Decompiled source of AtlyssArchipelago v1.3.4

AtlyssArchipelagoWIP.dll

Decompiled 17 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Threading.Tasks;
using Archipelago.MultiClient.Net;
using Archipelago.MultiClient.Net.BounceFeatures.DeathLink;
using Archipelago.MultiClient.Net.Enums;
using Archipelago.MultiClient.Net.Helpers;
using Archipelago.MultiClient.Net.Models;
using Archipelago.MultiClient.Net.Packets;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace AtlyssArchipelagoWIP;

[HarmonyPatch(typeof(SettingsManager), "Close_SettingsMenu")]
internal class SettingsMenuClosePatch
{
	private static void Prefix(SettingsManager __instance)
	{
		if (Object.op_Implicit((Object)(object)GameObject.Find("_SettingsManager/Canvas_SettingsMenu/_dolly_settingsMenu/_dolly_apSettingsTab")))
		{
			AtlyssArchipelagoPlugin instance = AtlyssArchipelagoPlugin.Instance;
			Toggle component = GameObject.Find("_SettingsManager/Canvas_SettingsMenu/_dolly_settingsMenu/_dolly_apSettingsTab/_backdrop_gameTab/Scroll View_gameTab/Viewport_gameTab/Content_gameTab/_cell_fadeGameFeed/Toggle_fadeGameFeed").GetComponent<Toggle>();
			if (component.isOn != instance.cfgDeathlink.Value)
			{
				instance.ToggleDeathLink(component.isOn);
			}
			instance.cfgDeathlink.Value = component.isOn;
		}
	}
}
[HarmonyPatch(typeof(SettingsManager), "Open_SettingsMenu")]
internal class SettingsMenuOpenPatch
{
	private static void Prefix(SettingsManager __instance)
	{
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_0362: Unknown result type (might be due to invalid IL or missing references)
		//IL_0383: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0407: Unknown result type (might be due to invalid IL or missing references)
		//IL_0423: Unknown result type (might be due to invalid IL or missing references)
		//IL_043f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0557: Unknown result type (might be due to invalid IL or missing references)
		//IL_0561: Expected O, but got Unknown
		if (Object.op_Implicit((Object)(object)GameObject.Find("_SettingsManager/Canvas_SettingsMenu/_dolly_settingsMenu/_dolly_apSettingsTab")))
		{
			return;
		}
		Scene sceneByName = SceneManager.GetSceneByName("01_rootScene");
		if (((Scene)(ref sceneByName)).isLoaded)
		{
			bool flag = false;
			if (!Object.op_Implicit((Object)(object)GameObject.Find("_GameUI_MainMenu")))
			{
				flag = true;
				((Component)((Component)MainMenuManager._current).gameObject.transform.parent).gameObject.SetActive(true);
			}
			AtlyssArchipelagoPlugin instance = AtlyssArchipelagoPlugin.Instance;
			GameObject val = Object.Instantiate<GameObject>(GameObject.Find("_SettingsManager/Canvas_SettingsMenu/_dolly_settingsMenu/_dolly_gameSettings"));
			((Object)val).name = "_dolly_apSettingsTab";
			val.transform.SetParent(GameObject.Find("_SettingsManager/Canvas_SettingsMenu/_dolly_settingsMenu").transform, false);
			Transform val2 = val.transform.Find("_backdrop_gameTab/Scroll View_gameTab/Viewport_gameTab/Content_gameTab");
			((Component)((Component)val2).transform.Find("_header_gameSettings/Text")).GetComponent<Text>().text = "Archipelago Settings";
			Transform child = ((Component)val2).transform.GetChild(1);
			Transform child2 = ((Component)val2).transform.GetChild(2);
			Transform child3 = ((Component)val2).transform.GetChild(3);
			Transform child4 = ((Component)val2).transform.GetChild(21);
			((Component)child4).GetComponentInChildren<Text>().text = "DeathLink";
			((Component)child4).GetComponent<SettingsCell>()._setToggle = null;
			Object.Destroy((Object)(object)((Component)child).transform.GetChild(1));
			Object.Destroy((Object)(object)((Component)child2).transform.GetChild(1));
			Object.Destroy((Object)(object)((Component)child3).transform.GetChild(1));
			((Component)child).GetComponentInChildren<Text>().text = "Archipelago Server";
			((Component)child2).GetComponentInChildren<Text>().text = "Slot Name";
			((Component)child3).GetComponentInChildren<Text>().text = "Password";
			((Component)((Component)val2).transform.Find("_header_nametagSettings/Text")).GetComponent<Text>().text = "Press F5 at any time to connect!";
			for (int num = val2.childCount - 3; num >= 5; num--)
			{
				GameObject gameObject = ((Component)val2.GetChild(num)).gameObject;
				Object.Destroy((Object)(object)gameObject);
			}
			Transform val3 = Object.Instantiate<Transform>(GameObject.Find("_GameUI_MainMenu").transform.Find("_characterSelectMenu/Canvas_characterSelect/_dolly_characterManagement/_input_@nickname"));
			((Object)val3).name = "Input_apServer";
			Transform val4 = Object.Instantiate<Transform>(GameObject.Find("_GameUI_MainMenu").transform.Find("_characterSelectMenu/Canvas_characterSelect/_dolly_characterManagement/_input_@nickname"));
			((Object)val4).name = "Input_apSlot";
			Transform val5 = Object.Instantiate<Transform>(GameObject.Find("_GameUI_MainMenu").transform.Find("_characterSelectMenu/Canvas_characterSelect/_dolly_characterManagement/_input_@nickname"));
			((Object)val5).name = "Input_apPassword";
			((Component)val3).gameObject.SetActive(true);
			((Component)val4).gameObject.SetActive(true);
			((Component)val5).gameObject.SetActive(true);
			Object.Destroy((Object)(object)((Component)val3).transform.Find("_backdrop_globalNicknameTooltip"));
			Object.Destroy((Object)(object)((Component)val4).transform.Find("_backdrop_globalNicknameTooltip"));
			Object.Destroy((Object)(object)((Component)val5).transform.Find("_backdrop_globalNicknameTooltip"));
			((Component)val3).transform.SetParent(((Component)child).transform, false);
			((Component)val4).transform.SetParent(((Component)child2).transform, false);
			((Component)val5).transform.SetParent(((Component)child3).transform, false);
			((Component)val3).transform.localPosition = new Vector3(180f, 0f, 0f);
			((Component)val4).transform.localPosition = new Vector3(180f, 0f, 0f);
			((Component)val5).transform.localPosition = new Vector3(180f, 0f, 0f);
			instance.apServer = ((Component)val3).GetComponent<InputField>();
			instance.apSlot = ((Component)val4).GetComponent<InputField>();
			instance.apPassword = ((Component)val5).GetComponent<InputField>();
			instance.apDeathlink = ((Component)((Component)child4).transform.Find("Toggle_fadeGameFeed")).gameObject.GetComponent<Toggle>();
			((Text)instance.apServer.placeholder).text = "archipelago.gg:38281";
			((Text)instance.apSlot.placeholder).text = "ATLYSSPlayer";
			((Text)instance.apPassword.placeholder).text = "supersecret";
			instance.apServer.text = instance.cfgServer.Value;
			instance.apSlot.text = instance.cfgSlot.Value;
			instance.apPassword.text = instance.cfgPassword.Value;
			instance.apDeathlink.isOn = instance.cfgDeathlink.Value;
			GameObject val6 = Object.Instantiate<GameObject>(GameObject.Find("_SettingsManager/Canvas_SettingsMenu/_dolly_settingsMenu/_dolly_tabButtons/Button_gameTab"));
			((Object)val6).name = "Button_apTab";
			val6.GetComponentInChildren<Text>().text = "Archipelago";
			GameObject val7 = GameObject.Find("_SettingsManager/Canvas_SettingsMenu/_dolly_settingsMenu/_dolly_tabButtons");
			val6.transform.SetParent(val7.transform, false);
			((HorizontalOrVerticalLayoutGroup)val7.GetComponent<HorizontalLayoutGroup>()).childScaleWidth = true;
			((HorizontalOrVerticalLayoutGroup)val7.GetComponent<HorizontalLayoutGroup>()).childControlWidth = true;
			((LayoutGroup)val7.GetComponent<HorizontalLayoutGroup>()).padding.right = 8;
			val7.SetActive(false);
			instance.ReenableSettingsTabs();
			((UnityEvent)val6.GetComponent<Button>().onClick).AddListener((UnityAction)delegate
			{
				__instance.Set_SettingMenuSelectionIndex(4);
			});
			if (flag)
			{
				((Component)((Component)MainMenuManager._current).gameObject.transform.parent).gameObject.SetActive(false);
			}
		}
	}
}
[HarmonyPatch(typeof(SettingsManager), "Set_SettingMenuSelectionIndex")]
internal class SettingsMenuTabsPatch
{
	private static void Postfix(SettingsManager __instance, int _index)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		Scene sceneByName = SceneManager.GetSceneByName("01_rootScene");
		if (((Scene)(ref sceneByName)).isLoaded)
		{
			if (_index == 4)
			{
				MenuElement component = GameObject.Find("_SettingsManager/Canvas_SettingsMenu/_dolly_settingsMenu/_dolly_apSettingsTab").GetComponent<MenuElement>();
				RectTransform component2 = GameObject.Find("_SettingsManager/Canvas_SettingsMenu/_dolly_settingsMenu/_dolly_apSettingsTab/_backdrop_gameTab/Scroll View_gameTab/Viewport_gameTab/Content_gameTab").GetComponent<RectTransform>();
				GameObject val = GameObject.Find("_SettingsManager/Canvas_SettingsMenu/_dolly_settingsMenu/_selectHighlight_tabButtons");
				component.isEnabled = true;
				component2.anchoredPosition = Vector2.zero;
				val.transform.position = GameObject.Find("_SettingsManager/Canvas_SettingsMenu/_dolly_settingsMenu/_dolly_tabButtons/Button_apTab").transform.position;
			}
			else
			{
				MenuElement component3 = GameObject.Find("_SettingsManager/Canvas_SettingsMenu/_dolly_settingsMenu/_dolly_apSettingsTab").GetComponent<MenuElement>();
				component3.isEnabled = false;
			}
		}
	}
}
[HarmonyPatch(typeof(Player), "Player_OnDeath")]
internal class PlayerDeathPatch
{
	private static void Postfix(Player __instance)
	{
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: Expected O, but got Unknown
		AtlyssArchipelagoPlugin instance = AtlyssArchipelagoPlugin.Instance;
		if (instance._dlService != null && instance.cfgDeathlink.Value)
		{
			if (AtlyssArchipelagoPlugin.reactingToDeathLink > 0)
			{
				AtlyssArchipelagoPlugin.reactingToDeathLink--;
				return;
			}
			DeathLink val = new DeathLink(__instance._nickname, __instance._nickname + " was defeated.");
			instance._dlService.SendDeathLink(val);
		}
	}
}
[HarmonyPatch(typeof(ChatBehaviour), "Send_ChatMessage")]
public static class ChatBehaviourPatch
{
	private static bool Prefix(ChatBehaviour __instance, string _message)
	{
		try
		{
			if (!string.IsNullOrEmpty(_message) && _message.StartsWith("/"))
			{
				string[] array = new string[6] { "/release", "/collect", "/hint", "/help", "/players", "/status" };
				bool flag = false;
				string[] array2 = array;
				foreach (string value in array2)
				{
					if (_message.StartsWith(value, StringComparison.OrdinalIgnoreCase))
					{
						flag = true;
						break;
					}
				}
				if (flag)
				{
					if ((Object)(object)AtlyssArchipelagoPlugin.Instance != (Object)null)
					{
						AtlyssArchipelagoPlugin.Instance.HandleArchipelagoCommand(_message);
					}
					__instance._focusedInChat = false;
					return false;
				}
			}
			return true;
		}
		catch (Exception ex)
		{
			ManualLogSource staticLogger = AtlyssArchipelagoPlugin.StaticLogger;
			if (staticLogger != null)
			{
				staticLogger.LogError((object)("[AtlyssAP] Chat patch error: " + ex.Message));
			}
			return true;
		}
	}
}
[HarmonyPatch(typeof(GameManager), "Locate_Item")]
public static class LocateItemPatch
{
	private static ScriptableItem _fallbackDummyItem = null;

	private static Sprite _customAPSprite = null;

	private static Dictionary<string, ScriptableItem> _apItemCache = new Dictionary<string, ScriptableItem>();

	private static void Postfix(string _tag, ref ScriptableItem __result)
	{
		try
		{
			if ((Object)(object)__result != (Object)null || string.IsNullOrEmpty(_tag) || !_tag.StartsWith("[AP]"))
			{
				return;
			}
			if (_apItemCache.TryGetValue(_tag, out var value))
			{
				__result = value;
				return;
			}
			string text = ExtractItemName(_tag);
			if (string.IsNullOrEmpty(text))
			{
				AtlyssArchipelagoPlugin.StaticLogger.LogWarning((object)("[AtlyssAP] Could not extract item name from: " + _tag));
				__result = GetCustomAPItem("Unknown Item");
				_apItemCache[_tag] = __result;
				return;
			}
			ScriptableItem val = FindRealItem(text);
			if ((Object)(object)val != (Object)null)
			{
				_apItemCache[_tag] = val;
				__result = val;
				AtlyssArchipelagoPlugin.StaticLogger.LogInfo((object)("[AtlyssAP] Using real item '" + val._itemName + "' icon for: " + _tag));
			}
			else
			{
				__result = GetCustomAPItem(text);
				_apItemCache[_tag] = __result;
				AtlyssArchipelagoPlugin.StaticLogger.LogInfo((object)("[AtlyssAP] Using custom AP icon for non-ATLYSS item: " + _tag));
			}
		}
		catch (Exception ex)
		{
			AtlyssArchipelagoPlugin.StaticLogger.LogError((object)("[AtlyssAP] Locate_Item patch error: " + ex.Message));
			__result = GetCustomAPItem("Unknown Item");
		}
	}

	public static string ExtractItemName(string apItemName)
	{
		string text = apItemName.Replace("[AP] ", "");
		int num = text.LastIndexOf(" (");
		if (num > 0)
		{
			return text.Substring(0, num);
		}
		return text;
	}

	private static ScriptableItem FindRealItem(string itemName)
	{
		if (!AtlyssArchipelagoPlugin.ItemNameMapping.TryGetValue(itemName, out var value))
		{
			return null;
		}
		string text = value;
		int num = value.LastIndexOf('_');
		if (num >= 0 && num < value.Length - 1)
		{
			text = value.Substring(num + 1);
		}
		ScriptableItem val = GameManager._current.Locate_Item(text);
		if ((Object)(object)val != (Object)null)
		{
			return val;
		}
		if (text.Contains(" (") && text.EndsWith(")"))
		{
			string text2 = text[..text.LastIndexOf(" (")];
			val = GameManager._current.Locate_Item(text2);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
		}
		string text3 = text.Replace(" ", "");
		val = GameManager._current.Locate_Item(text3);
		if ((Object)(object)val != (Object)null)
		{
			return val;
		}
		return null;
	}

	private static ScriptableItem GetCustomAPItem(string itemName = "Archipelago Item")
	{
		ScriptableItem fallbackDummy = GetFallbackDummy();
		if ((Object)(object)fallbackDummy != (Object)null)
		{
			ScriptableItem val = Object.Instantiate<ScriptableItem>(fallbackDummy);
			val._itemName = itemName;
			Sprite val2 = LoadCustomAPSprite();
			if ((Object)(object)val2 != (Object)null)
			{
				TrySetItemIcon(val, val2);
				if ((Object)(object)_customAPSprite == (Object)null)
				{
					AtlyssArchipelagoPlugin.StaticLogger.LogInfo((object)"[AtlyssAP] Loaded custom Archipelago icon successfully!");
				}
				_customAPSprite = val2;
			}
			else
			{
				AtlyssArchipelagoPlugin.StaticLogger.LogWarning((object)"[AtlyssAP] Failed to load custom icon, using base item icon");
			}
			return val;
		}
		AtlyssArchipelagoPlugin.StaticLogger.LogError((object)"[AtlyssAP] Could not create custom AP item - no base item available");
		return null;
	}

	private static Sprite LoadCustomAPSprite()
	{
		//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0100: Expected O, but got Unknown
		//IL_0146: Unknown result type (might be due to invalid IL or missing references)
		//IL_0155: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_customAPSprite != (Object)null)
		{
			return _customAPSprite;
		}
		try
		{
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			string[] manifestResourceNames = executingAssembly.GetManifestResourceNames();
			string text = null;
			string[] array = manifestResourceNames;
			foreach (string text2 in array)
			{
				if (text2.EndsWith("Archipelago.png-256x256_q95.png"))
				{
					text = text2;
					break;
				}
			}
			if (string.IsNullOrEmpty(text))
			{
				AtlyssArchipelagoPlugin.StaticLogger.LogError((object)"[AtlyssAP] Could not find Archipelago.png-256x256_q95.png in embedded resources");
				AtlyssArchipelagoPlugin.StaticLogger.LogError((object)("[AtlyssAP] Available resources: " + string.Join(", ", manifestResourceNames)));
				return null;
			}
			using Stream stream = executingAssembly.GetManifestResourceStream(text);
			if (stream == null)
			{
				AtlyssArchipelagoPlugin.StaticLogger.LogError((object)"[AtlyssAP] Failed to open embedded resource stream");
				return null;
			}
			byte[] array2 = new byte[stream.Length];
			stream.Read(array2, 0, array2.Length);
			Texture2D val = new Texture2D(2, 2);
			if (!ImageConversion.LoadImage(val, array2))
			{
				AtlyssArchipelagoPlugin.StaticLogger.LogError((object)"[AtlyssAP] Failed to load image data into texture");
				return null;
			}
			Sprite result = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
			AtlyssArchipelagoPlugin.StaticLogger.LogInfo((object)$"[AtlyssAP] Successfully loaded custom AP sprite: {((Texture)val).width}x{((Texture)val).height}");
			return result;
		}
		catch (Exception ex)
		{
			AtlyssArchipelagoPlugin.StaticLogger.LogError((object)("[AtlyssAP] Error loading custom sprite: " + ex.Message));
			return null;
		}
	}

	private static void TrySetItemIcon(ScriptableItem item, Sprite sprite)
	{
		try
		{
			string[] array = new string[6] { "_icon", "_itemIcon", "_sprite", "_itemSprite", "icon", "sprite" };
			Type type = ((object)item).GetType();
			string[] array2 = array;
			foreach (string text in array2)
			{
				FieldInfo field = type.GetField(text, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null && field.FieldType == typeof(Sprite))
				{
					field.SetValue(item, sprite);
					AtlyssArchipelagoPlugin.StaticLogger.LogInfo((object)("[AtlyssAP] Set item icon using field: " + text));
					return;
				}
			}
			AtlyssArchipelagoPlugin.StaticLogger.LogWarning((object)"[AtlyssAP] Could not find icon field on ScriptableItem");
		}
		catch (Exception ex)
		{
			AtlyssArchipelagoPlugin.StaticLogger.LogError((object)("[AtlyssAP] Error setting item icon: " + ex.Message));
		}
	}

	private static ScriptableItem GetFallbackDummy()
	{
		if ((Object)(object)_fallbackDummyItem == (Object)null)
		{
			_fallbackDummyItem = GameManager._current.Locate_Item("Bunbag");
			if ((Object)(object)_fallbackDummyItem == (Object)null)
			{
				_fallbackDummyItem = GameManager._current.Locate_Item("Wood Sword");
			}
			if ((Object)(object)_fallbackDummyItem == (Object)null)
			{
				_fallbackDummyItem = GameManager._current.Locate_Item("Leather Top");
			}
		}
		return _fallbackDummyItem;
	}
}
[HarmonyPatch(typeof(NetNPC), "Init_ShopkeepListing")]
public static class ShopInventoryPatch
{
	private static void Postfix(NetNPC __instance)
	{
		try
		{
			if (!AtlyssArchipelagoPlugin.Instance.connected || AtlyssArchipelagoPlugin.Instance._shopSanity == null || !AtlyssArchipelagoPlugin.Instance._shopSanity.IsInitialized)
			{
				return;
			}
			string name = ((Object)((Component)__instance).gameObject).name;
			string[] array = new string[10] { "_npc_Sally", "_npc_Skrit", "_npc_sallyWorker_frankie_01", "_npc_Ruka", "_npc_fisher", "_npc_dyeMerchant", "_npc_Tesh", "_npc_Nesh", "_npc_Cotoo", "_npc_Rikko" };
			bool flag = false;
			string[] array2 = array;
			foreach (string text in array2)
			{
				if (name == text)
				{
					flag = true;
					break;
				}
			}
			if (flag)
			{
				AtlyssArchipelagoPlugin.StaticLogger.LogInfo((object)("[AtlyssAP] AP merchant shop opened: " + name + " - injecting items"));
				AtlyssArchipelagoPlugin.Instance._shopSanity.InjectAPShopItems(__instance);
			}
		}
		catch (Exception ex)
		{
			AtlyssArchipelagoPlugin.StaticLogger.LogError((object)("[AtlyssAP] Shop patch error: " + ex.Message));
			AtlyssArchipelagoPlugin.StaticLogger.LogError((object)("[AtlyssAP] Stack trace: " + ex.StackTrace));
		}
	}
}
[HarmonyPatch(typeof(ShopkeepManager), "Init_PurchaseItem")]
public static class ShopPurchasePatch
{
	private static bool Prefix(ScriptableItem _scriptableItem, int _quantity, string _key, ShopListDataEntry _setEntry)
	{
		try
		{
			if (!AtlyssArchipelagoPlugin.Instance.connected)
			{
				return true;
			}
			if (AtlyssArchipelagoPlugin.Instance._shopSanity == null)
			{
				return true;
			}
			if (!AtlyssArchipelagoPlugin.Instance._shopSanity.IsInitialized)
			{
				return true;
			}
			string itemName = _setEntry._shopStruct._itemName;
			if (!itemName.StartsWith("[AP]"))
			{
				return true;
			}
			AtlyssArchipelagoPlugin.StaticLogger.LogInfo((object)("[AtlyssAP] Intercepting purchase of: " + itemName));
			Player mainPlayer = Player._mainPlayer;
			if ((Object)(object)mainPlayer == (Object)null)
			{
				AtlyssArchipelagoPlugin.StaticLogger.LogError((object)"[AtlyssAP] Player not found for purchase!");
				return false;
			}
			PlayerInventory component = ((Component)mainPlayer).GetComponent<PlayerInventory>();
			if ((Object)(object)component == (Object)null)
			{
				AtlyssArchipelagoPlugin.StaticLogger.LogError((object)"[AtlyssAP] PlayerInventory not found!");
				return false;
			}
			int num = _setEntry._shopStruct._dedicatedValue;
			if (_setEntry._shopStruct._useDedicatedValue)
			{
				num = _setEntry._shopStruct._dedicatedValue;
			}
			else if ((Object)(object)_scriptableItem != (Object)null)
			{
				num = _scriptableItem._vendorCost;
			}
			if (component._heldCurrency < num)
			{
				ErrorPromptTextManager.current.Init_ErrorPrompt("Not enough Crowns");
				AtlyssArchipelagoPlugin.StaticLogger.LogInfo((object)"[AtlyssAP] Player cannot afford AP item");
				return false;
			}
			component.Network_heldCurrency -= num;
			AtlyssArchipelagoPlugin.StaticLogger.LogInfo((object)$"[AtlyssAP] Deducted {num} crowns from player");
			component.Play_PurchaseSound();
			AtlyssArchipelagoPlugin.Instance._shopSanity.HandleAPItemPurchase(itemName, _key);
			return false;
		}
		catch (Exception ex)
		{
			AtlyssArchipelagoPlugin.StaticLogger.LogError((object)("[AtlyssAP] Shop purchase patch error: " + ex.Message));
			return true;
		}
	}
}
public class SpikePatch
{
	[HarmonyPatch(typeof(File), "ReadAllText", new Type[] { typeof(string) })]
	public static class File_ReadAllText_Patch
	{
		private static bool Prefix(ref string path, ref string __result)
		{
			try
			{
				if ((Object)(object)AtlyssArchipelagoPlugin.Instance == (Object)null || !AtlyssArchipelagoPlugin.Instance.connected)
				{
					return true;
				}
				if (path.EndsWith("atl_itemBank") && !path.Contains("_ap"))
				{
					string aPMasterBankPath = ArchipelagoSpikeStorage.GetAPMasterBankPath();
					if (File.Exists(aPMasterBankPath))
					{
						__result = File.ReadAllText(aPMasterBankPath);
						ManualLogSource staticLogger = AtlyssArchipelagoPlugin.StaticLogger;
						if (staticLogger != null)
						{
							staticLogger.LogInfo((object)"[AtlyssAP] Redirected Spike load: MASTER bank -> AP MASTER bank");
						}
						return false;
					}
					__result = "{ \"_heldItemStorage\": [] }";
					return false;
				}
				if (path.Contains("atl_itemBank_") && !path.Contains("_ap_"))
				{
					string fileName = Path.GetFileName(path);
					for (int i = 1; i <= 7; i++)
					{
						if (!(fileName == $"atl_itemBank_{i:D2}"))
						{
							continue;
						}
						string aPBankPath = ArchipelagoSpikeStorage.GetAPBankPath(i);
						if (File.Exists(aPBankPath))
						{
							__result = File.ReadAllText(aPBankPath);
							ManualLogSource staticLogger2 = AtlyssArchipelagoPlugin.StaticLogger;
							if (staticLogger2 != null)
							{
								staticLogger2.LogInfo((object)$"[AtlyssAP] Redirected Spike load: bank {i} -> AP bank {i}");
							}
							return false;
						}
						__result = "{ \"_heldItemStorage\": [] }";
						return false;
					}
				}
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource staticLogger3 = AtlyssArchipelagoPlugin.StaticLogger;
				if (staticLogger3 != null)
				{
					staticLogger3.LogError((object)("[AtlyssAP] Error in File.ReadAllText patch: " + ex.Message));
				}
				return true;
			}
		}
	}

	[HarmonyPatch(typeof(File), "WriteAllText", new Type[]
	{
		typeof(string),
		typeof(string)
	})]
	public static class File_WriteAllText_Patch
	{
		private static bool Prefix(ref string path, string contents)
		{
			try
			{
				if ((Object)(object)AtlyssArchipelagoPlugin.Instance == (Object)null || !AtlyssArchipelagoPlugin.Instance.connected)
				{
					return true;
				}
				if (path.EndsWith("atl_itemBank") && !path.Contains("_ap"))
				{
					string aPMasterBankPath = ArchipelagoSpikeStorage.GetAPMasterBankPath();
					string directoryName = Path.GetDirectoryName(aPMasterBankPath);
					if (!Directory.Exists(directoryName))
					{
						Directory.CreateDirectory(directoryName);
					}
					File.WriteAllText(aPMasterBankPath, contents);
					ManualLogSource staticLogger = AtlyssArchipelagoPlugin.StaticLogger;
					if (staticLogger != null)
					{
						staticLogger.LogInfo((object)"[AtlyssAP] Redirected Spike save: MASTER bank -> AP MASTER bank");
					}
					return false;
				}
				if (path.Contains("atl_itemBank_") && !path.Contains("_ap_"))
				{
					string fileName = Path.GetFileName(path);
					for (int i = 1; i <= 7; i++)
					{
						if (fileName == $"atl_itemBank_{i:D2}")
						{
							string aPBankPath = ArchipelagoSpikeStorage.GetAPBankPath(i);
							File.WriteAllText(aPBankPath, contents);
							ManualLogSource staticLogger2 = AtlyssArchipelagoPlugin.StaticLogger;
							if (staticLogger2 != null)
							{
								staticLogger2.LogInfo((object)$"[AtlyssAP] Redirected Spike save: bank {i} -> AP bank {i}");
							}
							return false;
						}
					}
				}
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource staticLogger3 = AtlyssArchipelagoPlugin.StaticLogger;
				if (staticLogger3 != null)
				{
					staticLogger3.LogError((object)("[AtlyssAP] Error in File.WriteAllText patch: " + ex.Message));
				}
				return true;
			}
		}
	}

	public static void InitializeAPStorage()
	{
		try
		{
			if (!ArchipelagoSpikeStorage.AreAPBanksInitialized())
			{
				ArchipelagoSpikeStorage.InitializeAPBanks();
				ManualLogSource staticLogger = AtlyssArchipelagoPlugin.StaticLogger;
				if (staticLogger != null)
				{
					staticLogger.LogInfo((object)"[AtlyssAP] Initialized AP Spike storage (separate from vanilla)");
				}
			}
			else
			{
				int totalItemCount = ArchipelagoSpikeStorage.GetTotalItemCount();
				ManualLogSource staticLogger2 = AtlyssArchipelagoPlugin.StaticLogger;
				if (staticLogger2 != null)
				{
					staticLogger2.LogInfo((object)$"[AtlyssAP] AP Spike storage loaded ({totalItemCount} items stored)");
				}
			}
		}
		catch (Exception ex)
		{
			ManualLogSource staticLogger3 = AtlyssArchipelagoPlugin.StaticLogger;
			if (staticLogger3 != null)
			{
				staticLogger3.LogError((object)("[AtlyssAP] Failed to initialize AP storage: " + ex.Message));
			}
		}
	}
}
public class ArchipelagoShopSanity
{
	private class ShopAPItemInfo
	{
		public string ItemName;

		public string FromPlayer;

		public long LocationId;

		public int Price;

		public int SlotNumber;
	}

	private readonly AtlyssArchipelagoPlugin _plugin;

	private readonly ManualLogSource _logger;

	private static readonly long[] SHOP_LOCATION_IDS = new long[50]
	{
		591300L, 591301L, 591302L, 591303L, 591304L, 591305L, 591306L, 591307L, 591308L, 591309L,
		591310L, 591311L, 591312L, 591313L, 591314L, 591315L, 591316L, 591317L, 591318L, 591319L,
		591320L, 591321L, 591322L, 591323L, 591324L, 591325L, 591326L, 591327L, 591328L, 591329L,
		591330L, 591331L, 591332L, 591333L, 591334L, 591335L, 591336L, 591337L, 591338L, 591339L,
		591340L, 591341L, 591342L, 591343L, 591344L, 591345L, 591346L, 591347L, 591348L, 591349L
	};

	private static readonly Dictionary<string, (long start, long end)> MERCHANT_LOCATION_RANGES = new Dictionary<string, (long, long)>
	{
		{
			"Sally",
			(591300L, 591304L)
		},
		{
			"Skrit",
			(591305L, 591309L)
		},
		{
			"sallyWorker_frankie_01",
			(591310L, 591314L)
		},
		{
			"Ruka",
			(591315L, 591319L)
		},
		{
			"fisher",
			(591320L, 591324L)
		},
		{
			"dyeMerchant",
			(591325L, 591329L)
		},
		{
			"Tesh",
			(591330L, 591334L)
		},
		{
			"Nesh",
			(591335L, 591339L)
		},
		{
			"Cotoo",
			(591340L, 591344L)
		},
		{
			"Rikko",
			(591345L, 591349L)
		}
	};

	private const int SHOP_PRICE_MIN = 15;

	private const int SHOP_PRICE_MAX = 3000;

	private Dictionary<long, ShopAPItemInfo> _scoutedShopItems = new Dictionary<long, ShopAPItemInfo>();

	private HashSet<long> _purchasedShopItems = new HashSet<long>();

	private bool _shopItemsInitialized = false;

	public bool IsInitialized => _shopItemsInitialized;

	public ArchipelagoShopSanity(AtlyssArchipelagoPlugin plugin, ManualLogSource logger)
	{
		_plugin = plugin;
		_logger = logger;
	}

	public void SendLocationScouts(ArchipelagoSession session)
	{
		try
		{
			if (session == null)
			{
				_logger.LogError((object)"[AtlyssAP] Cannot scout - no session");
				return;
			}
			_logger.LogInfo((object)$"[AtlyssAP] Scouting {SHOP_LOCATION_IDS.Length} shop locations...");
			session.Locations.ScoutLocationsAsync(SHOP_LOCATION_IDS).ContinueWith(delegate(Task<Dictionary<long, ScoutedItemInfo>> task)
			{
				if (task.IsFaulted)
				{
					_logger.LogError((object)("[AtlyssAP] Scout failed: " + task.Exception?.GetBaseException().Message));
				}
				else if (task.Status == TaskStatus.RanToCompletion)
				{
					ProcessScoutedLocations(session, task.Result);
				}
			});
		}
		catch (Exception ex)
		{
			_logger.LogError((object)("[AtlyssAP] Error sending shop scouts: " + ex.Message));
		}
	}

	private void ProcessScoutedLocations(ArchipelagoSession session, Dictionary<long, ScoutedItemInfo> scoutedLocations)
	{
		try
		{
			_scoutedShopItems.Clear();
			_logger.LogInfo((object)$"[AtlyssAP] Processing {scoutedLocations.Count} scouted shop items");
			int num = 0;
			foreach (KeyValuePair<long, ScoutedItemInfo> scoutedLocation in scoutedLocations)
			{
				long key = scoutedLocation.Key;
				ScoutedItemInfo value = scoutedLocation.Value;
				string text = session.Items.GetItemName(((ItemInfo)value).ItemId, ((ItemInfo)value).ItemGame) ?? $"Item {((ItemInfo)value).ItemId}";
				string text2 = session.Players.GetPlayerName(PlayerInfo.op_Implicit(value.Player)) ?? $"Player {value.Player}";
				int num2 = Random.Range(15, 3001);
				_scoutedShopItems[key] = new ShopAPItemInfo
				{
					ItemName = text,
					FromPlayer = text2,
					LocationId = key,
					Price = num2,
					SlotNumber = -1
				};
				_logger.LogInfo((object)$"[AtlyssAP] Scouted shop #{num + 1}: {text} from {text2} ({num2} crowns)");
				num++;
			}
			_shopItemsInitialized = true;
			_logger.LogInfo((object)$"[AtlyssAP] Shop items initialized! {_scoutedShopItems.Count} items ready.");
		}
		catch (Exception ex)
		{
			_logger.LogError((object)("[AtlyssAP] Error processing scouted locations: " + ex.Message));
		}
	}

	public void InjectAPShopItems(NetNPC npc)
	{
		//IL_0107: Unknown result type (might be due to invalid IL or missing references)
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0110: 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_02a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b9: 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_02c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d8: Expected O, but got Unknown
		//IL_02da: Unknown result type (might be due to invalid IL or missing references)
		//IL_034c: Unknown result type (might be due to invalid IL or missing references)
		//IL_034e: Unknown result type (might be due to invalid IL or missing references)
		//IL_036f: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			string name = ((Object)((Component)npc).gameObject).name;
			_logger.LogInfo((object)("[AtlyssAP] Found NPC GameObject: '" + name + "'"));
			string text = null;
			(long, long) tuple = (0L, 0L);
			foreach (KeyValuePair<string, (long, long)> mERCHANT_LOCATION_RANGE in MERCHANT_LOCATION_RANGES)
			{
				if (name.Contains(mERCHANT_LOCATION_RANGE.Key))
				{
					text = mERCHANT_LOCATION_RANGE.Key;
					tuple = mERCHANT_LOCATION_RANGE.Value;
					break;
				}
			}
			if (text == null)
			{
				_logger.LogWarning((object)("[AtlyssAP] Unknown merchant NPC: '" + name + "' - skipping AP injection"));
				return;
			}
			_logger.LogInfo((object)$"[AtlyssAP] Matched to merchant: {text} (locations {tuple.Item1}-{tuple.Item2})");
			HashSet<int> hashSet = new HashSet<int>();
			foreach (ShopkeepItemStruct value3 in npc._vendorItems.Values)
			{
				hashSet.Add(value3._itemData._slotNumber);
			}
			List<int> list = new List<int>();
			int num = 0;
			while (list.Count < 5 && num < 100)
			{
				if (!hashSet.Contains(num))
				{
					list.Add(num);
				}
				num++;
			}
			if (list.Count < 5)
			{
				_logger.LogWarning((object)$"[AtlyssAP] Only found {list.Count} available slots for {text}");
			}
			int num2 = 0;
			var (num3, _) = tuple;
			for (; num3 <= tuple.Item2; num3++)
			{
				if (!_scoutedShopItems.TryGetValue(num3, out var value))
				{
					_logger.LogWarning((object)$"[AtlyssAP] Missing scouted data for location {num3}");
				}
				else if (!_purchasedShopItems.Contains(num3))
				{
					if (num2 >= list.Count)
					{
						_logger.LogWarning((object)("[AtlyssAP] Ran out of slots for " + text));
						break;
					}
					int num4 = (value.SlotNumber = list[num2]);
					string text2 = "[AP] " + value.ItemName + " (" + value.FromPlayer + ")";
					ItemData itemData = new ItemData
					{
						_itemName = text2,
						_quantity = 0,
						_maxQuantity = 1,
						_slotNumber = num4,
						_modifierID = 0,
						_isEquipped = false,
						_isAltWeapon = false
					};
					ShopkeepItemStruct val = default(ShopkeepItemStruct);
					val._itemName = text2;
					val._dedicatedValue = value.Price;
					val._useDedicatedValue = true;
					val._itemData = itemData;
					val._stockQuantity = 1;
					val._removeAtEmptyStock = true;
					val._isbuybackItem = false;
					val._isGambleItem = false;
					val._equipModifierID = 0;
					val._specialItemCostName = string.Empty;
					val._specialItemCostQuantity = 0;
					val._gambleValue = 0;
					ShopkeepItemStruct value2 = val;
					if (!npc._vendorItems.ContainsKey(text2))
					{
						npc._vendorItems.Add(text2, value2);
						_logger.LogInfo((object)$"[AtlyssAP] Injected: {text2} in slot {num4} for {value.Price} crowns");
					}
					num2++;
				}
			}
			_logger.LogInfo((object)$"[AtlyssAP] Successfully injected {num2} AP items into {text}!");
		}
		catch (Exception ex)
		{
			_logger.LogError((object)("[AtlyssAP] Error injecting shop items: " + ex.Message));
		}
	}

	public void HandleAPItemPurchase(string displayName, string key)
	{
		try
		{
			string text = LocateItemPatch.ExtractItemName(displayName);
			_logger.LogInfo((object)("[AtlyssAP] Looking for purchased item: " + text));
			ShopAPItemInfo shopAPItemInfo = null;
			foreach (ShopAPItemInfo value in _scoutedShopItems.Values)
			{
				if (value.ItemName == text && !_purchasedShopItems.Contains(value.LocationId))
				{
					shopAPItemInfo = value;
					break;
				}
			}
			if (shopAPItemInfo == null)
			{
				_logger.LogWarning((object)("[AtlyssAP] No unpurchased AP item found for: " + text + " (all copies may already be bought)"));
			}
			else if (_plugin._session != null && _plugin._session.Socket.Connected)
			{
				_plugin._session.Locations.CompleteLocationChecks(new long[1] { shopAPItemInfo.LocationId });
				_purchasedShopItems.Add(shopAPItemInfo.LocationId);
				_plugin.SendAPChatMessage("<color=yellow>Purchased " + text + "!</color> Item sent to Spike storage!");
				_logger.LogInfo((object)$"[AtlyssAP] Shop purchase completed: {displayName} (Location {shopAPItemInfo.LocationId})");
			}
			else
			{
				_logger.LogError((object)"[AtlyssAP] Not connected to Archipelago server!");
			}
		}
		catch (Exception ex)
		{
			_logger.LogError((object)("[AtlyssAP] Error handling AP purchase: " + ex.Message));
		}
	}

	public void Reset()
	{
		_scoutedShopItems.Clear();
		_purchasedShopItems.Clear();
		_shopItemsInitialized = false;
		_logger.LogInfo((object)"[AtlyssAP] Shop sanity state reset");
	}
}
public class ArchipelagoSpikeStorage
{
	[Serializable]
	public class ItemBankData
	{
		public List<ItemData> _heldItemStorage = new List<ItemData>();
	}

	private const int NUM_BANKS = 7;

	public static string GetAPMasterBankPath()
	{
		string path = Path.Combine(Application.dataPath, "profileCollections");
		return Path.Combine(path, "atl_itemBank_ap");
	}

	public static string GetAPBankPath(int bankNumber)
	{
		if (bankNumber < 1 || bankNumber > 7)
		{
			throw new ArgumentException($"Bank number must be between 1 and {7}");
		}
		string path = Path.Combine(Application.dataPath, "profileCollections");
		return Path.Combine(path, $"atl_itemBank_ap_{bankNumber:D2}");
	}

	public static void InitializeAPBanks()
	{
		try
		{
			string aPMasterBankPath = GetAPMasterBankPath();
			string directoryName = Path.GetDirectoryName(aPMasterBankPath);
			if (!Directory.Exists(directoryName))
			{
				Directory.CreateDirectory(directoryName);
			}
			if (!File.Exists(aPMasterBankPath))
			{
				ItemBankData itemBankData = new ItemBankData();
				string contents = JsonConvert.SerializeObject((object)itemBankData, (Formatting)1);
				File.WriteAllText(aPMasterBankPath, contents);
				ManualLogSource staticLogger = AtlyssArchipelagoPlugin.StaticLogger;
				if (staticLogger != null)
				{
					staticLogger.LogInfo((object)"[AtlyssAP] Created AP master item bank");
				}
			}
			for (int i = 1; i <= 7; i++)
			{
				string aPBankPath = GetAPBankPath(i);
				if (!File.Exists(aPBankPath))
				{
					ItemBankData itemBankData2 = new ItemBankData();
					string contents2 = JsonConvert.SerializeObject((object)itemBankData2, (Formatting)1);
					File.WriteAllText(aPBankPath, contents2);
					ManualLogSource staticLogger2 = AtlyssArchipelagoPlugin.StaticLogger;
					if (staticLogger2 != null)
					{
						staticLogger2.LogInfo((object)$"[AtlyssAP] Created AP item bank {i}");
					}
				}
			}
			ManualLogSource staticLogger3 = AtlyssArchipelagoPlugin.StaticLogger;
			if (staticLogger3 != null)
			{
				staticLogger3.LogInfo((object)"[AtlyssAP] Archipelago item banks initialized");
			}
		}
		catch (Exception ex)
		{
			ManualLogSource staticLogger4 = AtlyssArchipelagoPlugin.StaticLogger;
			if (staticLogger4 != null)
			{
				staticLogger4.LogError((object)("[AtlyssAP] Failed to initialize AP banks: " + ex.Message));
			}
		}
	}

	public static ItemBankData LoadAPBank(int bankNumber)
	{
		try
		{
			string aPBankPath = GetAPBankPath(bankNumber);
			if (!File.Exists(aPBankPath))
			{
				return new ItemBankData();
			}
			string text = File.ReadAllText(aPBankPath);
			ItemBankData itemBankData = JsonConvert.DeserializeObject<ItemBankData>(text);
			return itemBankData ?? new ItemBankData();
		}
		catch (Exception ex)
		{
			ManualLogSource staticLogger = AtlyssArchipelagoPlugin.StaticLogger;
			if (staticLogger != null)
			{
				staticLogger.LogError((object)$"[AtlyssAP] Failed to load AP bank {bankNumber}: {ex.Message}");
			}
			return new ItemBankData();
		}
	}

	public static void SaveAPBank(int bankNumber, ItemBankData data)
	{
		try
		{
			string aPBankPath = GetAPBankPath(bankNumber);
			string contents = JsonConvert.SerializeObject((object)data, (Formatting)1);
			File.WriteAllText(aPBankPath, contents);
		}
		catch (Exception ex)
		{
			ManualLogSource staticLogger = AtlyssArchipelagoPlugin.StaticLogger;
			if (staticLogger != null)
			{
				staticLogger.LogError((object)$"[AtlyssAP] Failed to save AP bank {bankNumber}: {ex.Message}");
			}
		}
	}

	public static ItemBankData LoadAPMasterBank()
	{
		try
		{
			string aPMasterBankPath = GetAPMasterBankPath();
			if (!File.Exists(aPMasterBankPath))
			{
				return new ItemBankData();
			}
			string text = File.ReadAllText(aPMasterBankPath);
			ItemBankData itemBankData = JsonConvert.DeserializeObject<ItemBankData>(text);
			return itemBankData ?? new ItemBankData();
		}
		catch (Exception ex)
		{
			ManualLogSource staticLogger = AtlyssArchipelagoPlugin.StaticLogger;
			if (staticLogger != null)
			{
				staticLogger.LogError((object)("[AtlyssAP] Failed to load AP master bank: " + ex.Message));
			}
			return new ItemBankData();
		}
	}

	public static void SaveAPMasterBank(ItemBankData data)
	{
		try
		{
			string aPMasterBankPath = GetAPMasterBankPath();
			string contents = JsonConvert.SerializeObject((object)data, (Formatting)1);
			File.WriteAllText(aPMasterBankPath, contents);
		}
		catch (Exception ex)
		{
			ManualLogSource staticLogger = AtlyssArchipelagoPlugin.StaticLogger;
			if (staticLogger != null)
			{
				staticLogger.LogError((object)("[AtlyssAP] Failed to save AP master bank: " + ex.Message));
			}
		}
	}

	public static bool AddItemToAPSpike(ItemData itemToAdd)
	{
		try
		{
			if (itemToAdd._maxQuantity > 1)
			{
				ItemBankData itemBankData = LoadAPMasterBank();
				foreach (ItemData item in itemBankData._heldItemStorage)
				{
					if (!(item._itemName == itemToAdd._itemName) || item._quantity >= item._maxQuantity)
					{
						continue;
					}
					int val = item._maxQuantity - item._quantity;
					int num = Math.Min(val, itemToAdd._quantity);
					item._quantity += num;
					itemToAdd._quantity -= num;
					SaveAPMasterBank(itemBankData);
					if (itemToAdd._quantity == 0)
					{
						ManualLogSource staticLogger = AtlyssArchipelagoPlugin.StaticLogger;
						if (staticLogger != null)
						{
							staticLogger.LogInfo((object)("[AtlyssAP] Added " + itemToAdd._itemName + " to AP Spike MASTER bank (stacked)"));
						}
						return true;
					}
				}
				for (int i = 1; i <= 7; i++)
				{
					ItemBankData itemBankData2 = LoadAPBank(i);
					foreach (ItemData item2 in itemBankData2._heldItemStorage)
					{
						if (!(item2._itemName == itemToAdd._itemName) || item2._quantity >= item2._maxQuantity)
						{
							continue;
						}
						int val2 = item2._maxQuantity - item2._quantity;
						int num2 = Math.Min(val2, itemToAdd._quantity);
						item2._quantity += num2;
						itemToAdd._quantity -= num2;
						SaveAPBank(i, itemBankData2);
						if (itemToAdd._quantity == 0)
						{
							ManualLogSource staticLogger2 = AtlyssArchipelagoPlugin.StaticLogger;
							if (staticLogger2 != null)
							{
								staticLogger2.LogInfo((object)$"[AtlyssAP] Added {itemToAdd._itemName} to AP Spike bank {i} (stacked)");
							}
							return true;
						}
					}
				}
			}
			ItemBankData itemBankData3 = LoadAPMasterBank();
			int num3 = FindNextOpenSlot(itemBankData3, 100);
			if (num3 >= 0)
			{
				itemToAdd._slotNumber = num3;
				itemToAdd._isEquipped = false;
				itemBankData3._heldItemStorage.Add(itemToAdd);
				SaveAPMasterBank(itemBankData3);
				ManualLogSource staticLogger3 = AtlyssArchipelagoPlugin.StaticLogger;
				if (staticLogger3 != null)
				{
					staticLogger3.LogInfo((object)$"[AtlyssAP] Added {itemToAdd._itemName} to AP Spike MASTER bank slot {num3}");
				}
				return true;
			}
			for (int j = 1; j <= 7; j++)
			{
				ItemBankData itemBankData4 = LoadAPBank(j);
				int num4 = FindNextOpenSlot(itemBankData4, 40);
				if (num4 >= 0)
				{
					itemToAdd._slotNumber = num4;
					itemToAdd._isEquipped = false;
					itemBankData4._heldItemStorage.Add(itemToAdd);
					SaveAPBank(j, itemBankData4);
					ManualLogSource staticLogger4 = AtlyssArchipelagoPlugin.StaticLogger;
					if (staticLogger4 != null)
					{
						staticLogger4.LogInfo((object)$"[AtlyssAP] Added {itemToAdd._itemName} to AP Spike bank {j} slot {num4}");
					}
					return true;
				}
			}
			ManualLogSource staticLogger5 = AtlyssArchipelagoPlugin.StaticLogger;
			if (staticLogger5 != null)
			{
				staticLogger5.LogWarning((object)("[AtlyssAP] All AP Spike banks are full! Cannot add " + itemToAdd._itemName));
			}
			return false;
		}
		catch (Exception ex)
		{
			ManualLogSource staticLogger6 = AtlyssArchipelagoPlugin.StaticLogger;
			if (staticLogger6 != null)
			{
				staticLogger6.LogError((object)("[AtlyssAP] Failed to add item to AP Spike: " + ex.Message));
			}
			return false;
		}
	}

	private static int FindNextOpenSlot(ItemBankData bank, int maxSlots)
	{
		HashSet<int> hashSet = new HashSet<int>();
		foreach (ItemData item in bank._heldItemStorage)
		{
			hashSet.Add(item._slotNumber);
		}
		int i;
		for (i = 0; hashSet.Contains(i); i++)
		{
		}
		return (i < maxSlots) ? i : (-1);
	}

	private static bool TryAddToMasterBank(ItemData itemToAdd)
	{
		try
		{
			ItemBankData itemBankData = LoadAPMasterBank();
			if (itemToAdd._maxQuantity > 1)
			{
				foreach (ItemData item in itemBankData._heldItemStorage)
				{
					if (!(item._itemName == itemToAdd._itemName) || item._quantity >= item._maxQuantity)
					{
						continue;
					}
					int val = item._maxQuantity - item._quantity;
					int num = Math.Min(val, itemToAdd._quantity);
					item._quantity += num;
					itemToAdd._quantity -= num;
					SaveAPMasterBank(itemBankData);
					if (itemToAdd._quantity == 0)
					{
						ManualLogSource staticLogger = AtlyssArchipelagoPlugin.StaticLogger;
						if (staticLogger != null)
						{
							staticLogger.LogInfo((object)("[AtlyssAP] Added " + itemToAdd._itemName + " to AP Spike MASTER bank (stacked)"));
						}
						return true;
					}
				}
			}
			int i = 0;
			HashSet<int> hashSet = new HashSet<int>();
			foreach (ItemData item2 in itemBankData._heldItemStorage)
			{
				hashSet.Add(item2._slotNumber);
			}
			for (; hashSet.Contains(i); i++)
			{
			}
			if (i < 100)
			{
				itemToAdd._slotNumber = i;
				itemToAdd._isEquipped = false;
				itemBankData._heldItemStorage.Add(itemToAdd);
				SaveAPMasterBank(itemBankData);
				ManualLogSource staticLogger2 = AtlyssArchipelagoPlugin.StaticLogger;
				if (staticLogger2 != null)
				{
					staticLogger2.LogInfo((object)$"[AtlyssAP] Added {itemToAdd._itemName} to AP Spike MASTER bank slot {i}");
				}
				return true;
			}
			return false;
		}
		catch (Exception ex)
		{
			ManualLogSource staticLogger3 = AtlyssArchipelagoPlugin.StaticLogger;
			if (staticLogger3 != null)
			{
				staticLogger3.LogError((object)("[AtlyssAP] Failed to add to master bank: " + ex.Message));
			}
			return false;
		}
	}

	public static int GetTotalItemCount()
	{
		int num = 0;
		ItemBankData itemBankData = LoadAPMasterBank();
		num += itemBankData._heldItemStorage.Count;
		for (int i = 1; i <= 7; i++)
		{
			ItemBankData itemBankData2 = LoadAPBank(i);
			num += itemBankData2._heldItemStorage.Count;
		}
		return num;
	}

	public static bool AreAPBanksInitialized()
	{
		if (!File.Exists(GetAPMasterBankPath()))
		{
			return false;
		}
		for (int i = 1; i <= 7; i++)
		{
			if (!File.Exists(GetAPBankPath(i)))
			{
				return false;
			}
		}
		return true;
	}

	public static void ClearAllAPBanks()
	{
		try
		{
			ItemBankData data = new ItemBankData();
			SaveAPMasterBank(data);
			for (int i = 1; i <= 7; i++)
			{
				SaveAPBank(i, data);
			}
			ManualLogSource staticLogger = AtlyssArchipelagoPlugin.StaticLogger;
			if (staticLogger != null)
			{
				staticLogger.LogInfo((object)"[AtlyssAP] Cleared all AP item banks (master + numbered)");
			}
		}
		catch (Exception ex)
		{
			ManualLogSource staticLogger2 = AtlyssArchipelagoPlugin.StaticLogger;
			if (staticLogger2 != null)
			{
				staticLogger2.LogError((object)("[AtlyssAP] Failed to clear AP banks: " + ex.Message));
			}
		}
	}
}
[BepInPlugin("com.azrael.atlyss.ap", "Atlyss Archipelago", "1.3.1")]
public class AtlyssArchipelagoPlugin : BaseUnityPlugin
{
	[CompilerGenerated]
	private sealed class <EnableSettingsTabs>d__90 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public AtlyssArchipelagoPlugin <>4__this;

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

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

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

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

		private bool MoveNext()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>2__current = (object)new WaitForEndOfFrame();
				<>1__state = 1;
				return true;
			case 1:
				<>1__state = -1;
				GameObject.Find("_SettingsManager/Canvas_SettingsMenu/_dolly_settingsMenu/_dolly_tabButtons").SetActive(true);
				return false;
			}
		}

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

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

	private static Harmony _harmony;

	private static GameObject scriptHolder;

	private static PortalUnlocks portalLocker;

	private static readonly FieldInfo maxOnscreenMessages = AccessTools.Field(typeof(ChatBehaviour), "_maxGameLogicLines");

	public ConfigEntry<string> cfgServer;

	public ConfigEntry<string> cfgSlot;

	public ConfigEntry<string> cfgPassword;

	public ConfigEntry<bool> cfgDeathlink;

	private ConfigEntry<bool> cfgAutoConnect;

	public InputField apServer;

	public InputField apSlot;

	public InputField apPassword;

	public Toggle apDeathlink;

	public ArchipelagoSession _session;

	public bool connected;

	private bool connecting;

	private Dictionary<string, object> slotData = new Dictionary<string, object>();

	public DeathLinkService _dlService;

	public static int reactingToDeathLink;

	private int goalOption = 3;

	public bool randomPortalsEnabled = false;

	private int equipmentProgressionOption = 0;

	private bool shopSanityEnabled = false;

	private int progressivePortalCount = 0;

	private int progressiveEquipmentTier = 0;

	private Dictionary<string, bool> _portalItemsReceived = new Dictionary<string, bool>
	{
		{ "Outer Sanctum Portal", false },
		{ "Effold Terrace Portal", false },
		{ "Arcwood Pass Portal", false },
		{ "Tull Valley Portal", false },
		{ "Crescent Road Portal", false },
		{ "Catacombs Portal", false },
		{ "Luvora Garden Portal", false },
		{ "Crescent Keep Portal", false },
		{ "Tull Enclave Portal", false },
		{ "Bularr Fortress Portal", false },
		{ "Grove Portal", false }
	};

	private Dictionary<string, string> _portalScenes = new Dictionary<string, string>
	{
		{ "Outer Sanctum Portal", "Assets/Scenes/00_zone_forest/_zone00_outerSanctum.unity" },
		{ "Effold Terrace Portal", "Assets/Scenes/00_zone_forest/_zone00_effoldTerrace.unity" },
		{ "Arcwood Pass Portal", "Assets/Scenes/00_zone_forest/_zone00_arcwoodPass.unity" },
		{ "Tull Valley Portal", "Assets/Scenes/00_zone_forest/_zone00_tuulValley.unity" },
		{ "Crescent Road Portal", "Assets/Scenes/00_zone_forest/_zone00_crescentRoad.unity" },
		{ "Catacombs Portal", "Assets/Scenes/map_dungeon00_sanctumCatacombs.unity" },
		{ "Luvora Garden Portal", "Assets/Scenes/00_zone_forest/_zone00_luvoraGarden.unity" },
		{ "Crescent Keep Portal", "Assets/Scenes/00_zone_forest/_zone00_crescentKeep.unity" },
		{ "Tull Enclave Portal", "Assets/Scenes/00_zone_forest/_zone00_tuulEnclave.unity" },
		{ "Bularr Fortress Portal", "Assets/Scenes/00_zone_forest/_zone00_bularFortress.unity" },
		{ "Grove Portal", "Assets/Scenes/map_dungeon01_crescentGrove.unity" }
	};

	private List<string> _progressivePortalOrder = new List<string>
	{
		"Outer Sanctum Portal", "Arcwood Pass Portal", "Catacombs Portal", "Effold Terrace Portal", "Tull Valley Portal", "Crescent Road Portal", "Luvora Garden Portal", "Crescent Keep Portal", "Tull Enclave Portal", "Grove Portal",
		"Bularr Fortress Portal"
	};

	public ArchipelagoShopSanity _shopSanity;

	private readonly HashSet<long> _reportedChecks = new HashSet<long>();

	private int _lastLevel = 0;

	private int _previousFishingLevel = 1;

	private int _previousMiningLevel = 1;

	private HashSet<string> _completedQuests = new HashSet<string>();

	private bool _questDebugLogged = false;

	private string currentSessionId = "";

	private const string SESSION_FILE = "ap_session.json";

	private const long BASE_LOCATION_ID = 591000L;

	private const long DEFEAT_SLIME_DIVA = 591001L;

	private const long DEFEAT_LORD_ZUULNERUDA = 591002L;

	private const long DEFEAT_GALIUS = 591003L;

	private const long DEFEAT_COLOSSUS = 591004L;

	private const long DEFEAT_LORD_KALUUZ = 591005L;

	private const long DEFEAT_VALDUR = 591006L;

	private const long REACH_LEVEL_2 = 591010L;

	private static readonly Dictionary<string, long> AllQuestToLocation = new Dictionary<string, long>
	{
		{ "Diva Must Die", 591001L },
		{ "The Voice of Zuulneruda", 591002L },
		{ "Gatling Galius", 591003L },
		{ "The Colossus", 591004L },
		{ "A Warm Welcome", 591030L },
		{ "Communing Catacombs", 591031L },
		{ "Dense Ingots", 591100L },
		{ "Ghostly Goods", 591101L },
		{ "Killing Tomb", 591102L },
		{ "Night Spirits", 591103L },
		{ "Ridding Slimes", 591104L },
		{ "Summore' Spectral Powder!", 591105L },
		{ "Call of Fury", 591110L },
		{ "Cold Shoulder", 591111L },
		{ "Focusin' in", 591112L },
		{ "Cleaning Terrace", 591115L },
		{ "Huntin' Hogs", 591116L },
		{ "Amberite Ingots", 591120L },
		{ "Makin' a Mekspear", 591121L },
		{ "Makin' More Mekspears", 591122L },
		{ "Purging the Undead", 591123L },
		{ "Rattlecage Rage", 591124L },
		{ "Ancient Beings", 591125L },
		{ "Makin' a Vile Blade", 591130L },
		{ "Makin' a Wizwand", 591131L },
		{ "Makin' More Vile Blades", 591132L },
		{ "Makin' More Wizwands", 591133L },
		{ "Sapphite Ingots", 591134L },
		{ "Devious Pact", 591140L },
		{ "Disciple of Magic", 591141L },
		{ "Mastery of Dexterity", 591142L },
		{ "Mastery of Mind", 591143L },
		{ "Mastery of Strength", 591144L },
		{ "Strength and Honor", 591145L },
		{ "Wicked Wizboars", 591146L },
		{ "Beckoning Foes", 591150L },
		{ "Blossom of Life", 591151L },
		{ "Consumed Madness", 591152L },
		{ "Eradicating the Undead", 591153L },
		{ "Makin' a Golem Chestpiece", 591154L },
		{ "Summore' Golem Chestpieces", 591155L },
		{ "Whatta' Rush!", 591156L },
		{ "Finding Ammagon", 591160L },
		{ "Reviling the Rageboars", 591161L },
		{ "Reviling More Rageboars", 591162L },
		{ "Makin' a Ragespear", 591165L },
		{ "Makin' More Ragespears", 591166L },
		{ "Purging the Grove", 591167L },
		{ "Searching for the Grove", 591168L },
		{ "Tethering Grove", 591169L },
		{ "Up and Over It", 591170L },
		{ "Makin' a Monolith Chestpiece", 591175L },
		{ "Summore' Monolith Chestpieces", 591176L },
		{ "Facing Foes", 591180L },
		{ "Cleansing the Grove", 591200L },
		{ "Spiraling In The Grove", 591201L },
		{ "Hell In The Grove", 591202L },
		{ "Makin' a Firebreath Blade", 591203L },
		{ "Nulversa Magica", 591204L },
		{ "Nulversa Viscera", 591205L },
		{ "Nulversa, Greenveras!", 591206L },
		{ "Summore' Firebreath Blades", 591207L },
		{ "The Gall of Galius", 591220L },
		{ "Makin' a Follycannon", 591240L },
		{ "Makin' More Follycannons", 591241L },
		{ "The Glyphik Booklet", 591242L }
	};

	private static readonly Dictionary<long, string> LocationIdToName = new Dictionary<long, string>
	{
		{ 591010L, "Reach Level 2" },
		{ 591011L, "Reach Level 4" },
		{ 591012L, "Reach Level 6" },
		{ 591013L, "Reach Level 8" },
		{ 591014L, "Reach Level 10" },
		{ 591015L, "Reach Level 12" },
		{ 591016L, "Reach Level 14" },
		{ 591017L, "Reach Level 16" },
		{ 591018L, "Reach Level 18" },
		{ 591019L, "Reach Level 20" },
		{ 591020L, "Reach Level 22" },
		{ 591021L, "Reach Level 24" },
		{ 591022L, "Reach Level 26" },
		{ 591023L, "Reach Level 28" },
		{ 591024L, "Reach Level 30" },
		{ 591025L, "Reach Level 32" },
		{ 591001L, "Defeat Slime Diva" },
		{ 591002L, "Defeat Lord Zuulneruda" },
		{ 591003L, "Defeat Galius" }
	};

	private static readonly Dictionary<int, long> FishingLevelLocations = new Dictionary<int, long>
	{
		{ 2, 591400L },
		{ 3, 591401L },
		{ 4, 591402L },
		{ 5, 591403L },
		{ 6, 591404L },
		{ 7, 591405L },
		{ 8, 591406L },
		{ 9, 591407L },
		{ 10, 591408L }
	};

	private static readonly Dictionary<int, long> MiningLevelLocations = new Dictionary<int, long>
	{
		{ 2, 591409L },
		{ 3, 591410L },
		{ 4, 591411L },
		{ 5, 591412L },
		{ 6, 591413L },
		{ 7, 591414L },
		{ 8, 591415L },
		{ 9, 591416L },
		{ 10, 591417L }
	};

	public static readonly Dictionary<string, string> ItemNameMapping = new Dictionary<string, string>
	{
		{ "Bunbag Pack", "(lv-0) STATUSCONSUMABLE_Bunbag" },
		{ "Bunjar Pack", "(lv-0) STATUSCONSUMABLE_Bunjar" },
		{ "Bunpot Pack", "(lv-0) STATUSCONSUMABLE_Bunpot" },
		{ "Regen Potion Pack", "(lv-10) STATUSCONSUMABLE_Regen Potion" },
		{ "Regen Vial Pack", "(lv-0) STATUSCONSUMABLE_Regen Vial" },
		{ "Magiclove Pack", "(lv-0) STATUSCONSUMABLE_Magiclove" },
		{ "Magiflower Pack", "(lv-0) STATUSCONSUMABLE_Magiflower" },
		{ "Magileaf Pack", "(lv-0) STATUSCONSUMABLE_Magileaf" },
		{ "Stamstar Pack", "(lv-0) STATUSCONSUMABLE_Stamstar" },
		{ "Agility Potion Pack", "(lv-10) STATUSCONSUMABLE_Agility Potion" },
		{ "Agility Vial Pack", "(lv-0) STATUSCONSUMABLE_Agility Vial" },
		{ "Bolster Potion Pack", "(lv-10) STATUSCONSUMABLE_Bolster Potion" },
		{ "Bolster Vial Pack", "(lv-0) STATUSCONSUMABLE_Bolster Vial" },
		{ "Wisdom Potion Pack", "(lv-10) STATUSCONSUMABLE_Wisdom Potion" },
		{ "Wisdom Vial Pack", "(lv-0) STATUSCONSUMABLE_Wisdom Vial" },
		{ "Tome of Greater Experience", "(lv-0) STATUSCONSUMABLE_Tome of Greater Experience" },
		{ "Tome of Experience", "(lv-0) STATUSCONSUMABLE_Tome of Experience" },
		{ "Tome of Lesser Experience", "(lv-0) STATUSCONSUMABLE_Tome of Lesser Experience" },
		{ "Carrot Cake Pack", "(lv-0) STATUSCONSUMABLE_Carrot Cake" },
		{ "Minchroom Juice Pack", "(lv-0) STATUSCONSUMABLE_Minchroom Juice" },
		{ "Spectral Powder Pack", "(lv-0) STATUSCONSUMABLE_Spectral Powder" },
		{ "Geistlord Badge Pack", "TRADEITEM_Geistlord Badge" },
		{ "Coldgeist Badge Pack", "TRADEITEM_Coldgeist Badge" },
		{ "Earthcore Badge Pack", "TRADEITEM_Earthcore Badge" },
		{ "Windcore Badge Pack", "TRADEITEM_Windcore Badge" },
		{ "Iron Cluster Pack", "TRADEITEM_Iron Cluster" },
		{ "Copper Cluster Pack", "TRADEITEM_Copper Cluster" },
		{ "Mithril Cluster Pack", "TRADEITEM_Mithril Cluster" },
		{ "Dense Ingot Pack", "TRADEITEM_Dense Ingot" },
		{ "Sapphite Ingot Pack", "TRADEITEM_Sapphite Ingot" },
		{ "Amberite Ingot Pack", "TRADEITEM_Amberite Ingot" },
		{ "Soul Pearl", "TRADEITEM_Soul Pearl" },
		{ "Experience Bond Pack", "TRADEITEM_Experience Bond" },
		{ "Wood Sword", "(lv-1) WEAPON_Wood Sword (Sword, Strength)" },
		{ "Wooden Bow", "(lv-1) WEAPON_Wooden Bow (Bow, Dexterity)" },
		{ "Wood Scepter", "(lv-1) WEAPON_Wood Scepter (Scepter, Mind)" },
		{ "Crypt Blade", "(lv-2) WEAPON_Crypt Blade (Sword, Strength)" },
		{ "Slimecrust Blade", "(lv-2) WEAPON_Slimecrust Blade (Sword, Strength)" },
		{ "Gilded Sword", "(lv-4) WEAPON_Gilded Sword (Sword, Strength)" },
		{ "Mini Geist Scythe", "(lv-4) WEAPON_Mini Geist Scythe (Greatblade, Strength)" },
		{ "Iron Sword", "(lv-6) WEAPON_Iron Sword (Sword, Strength)" },
		{ "Iron Bow", "(lv-6) WEAPON_Iron Bow (Bow, Dexterity)" },
		{ "Dense Hammer", "(lv-6) WEAPON_Dense Hammer (Hammer, Strength)" },
		{ "Dense Katars", "(lv-6) WEAPON_Dense Katars (Katars, Dexterity)" },
		{ "Vile Blade", "(lv-8) WEAPON_Vile Blade (Sword, Strength)" },
		{ "Mekspear", "(lv-8) WEAPON_Mekspear (Polearm, Strength)" },
		{ "Menace Bow", "(lv-8) WEAPON_Menace Bow (Bow, Dexterity)" },
		{ "Cryptcall Bell", "(lv-8) WEAPON_Cryptcall Bell (Magic Bell, Mind)" },
		{ "Wizwand", "(lv-12) WEAPON_Wizwand (Scepter, Mind)" },
		{ "Amberite Sword", "(lv-12) WEAPON_Amberite Sword (Sword, Strength)" },
		{ "Geistlord Claws", "(lv-12) WEAPON_Geistlord Claws (Katars, Dexterity)" },
		{ "Petrified Bow", "(lv-12) WEAPON_Petrified Bow (Bow, Dexterity)" },
		{ "Mithril Sword", "(lv-16) WEAPON_Mithril Sword (Sword, Strength)" },
		{ "Mithril Bow", "(lv-14) WEAPON_Mithril Bow (Bow, Dexterity)" },
		{ "Ragespear", "(lv-16) WEAPON_Ragespear (Polearm, Strength)" },
		{ "Coldgeist Blade", "(lv-16) WEAPON_Coldgeist Blade (Sword, Strength)" },
		{ "Sapphite Spear", "(lv-18) WEAPON_Sapphite Spear (Polearm, Strength)" },
		{ "Colossus Tone", "(lv-18) WEAPON_Colossus Tone (Magic Bell, Mind)" },
		{ "Magitek Burstgun", "(lv-20) WEAPON_Magitek Burstgun (Shotgun, Dexterity)" },
		{ "Firebreath Blade", "(lv-22) WEAPON_Firebreath Blade (Sword, Strength)" },
		{ "Valdur Blade", "(lv-24) WEAPON_Valdur Blade (Sword, Strength)" },
		{ "Torrentius Longbow", "(lv-24) WEAPON_Torrentius Longbow (Bow, Dexterity)" },
		{ "Follycannon", "(lv-26) WEAPON_Follycannon (Shotgun, Dexterity)" },
		{ "Fier Blade", "(lv-26) WEAPON_Fier Blade (Sword, Strength)" },
		{ "Leather Cap", "(lv-1) HELM_Leather Cap" },
		{ "Fishin Hat", "(lv-1) HELM_Fishin Hat" },
		{ "Iron Halo", "(lv-6) HELM_Iron Halo" },
		{ "Dense Helm", "(lv-6) HELM_Dense Helm" },
		{ "Diva Crown", "(lv-6) HELM_Diva Crown" },
		{ "Geistlord Crown", "(lv-10) HELM_Geistlord Crown" },
		{ "Amberite Helm", "(lv-12) HELM_Amberite Helm" },
		{ "Mithril Halo", "(lv-16) HELM_Mithril Halo" },
		{ "Sapphite Mindhat", "(lv-18) HELM_Sapphite Mindhat" },
		{ "Wizlad Hood", "(lv-24) HELM_Wizlad Hood" },
		{ "Deathknight Helm", "(lv-24) HELM_Deathknight Helm" },
		{ "Leather Top", "(lv-1) CHESTPIECE_Leather Top" },
		{ "Noble Shirt", "(lv-1) CHESTPIECE_Noble Shirt" },
		{ "Iron Chestpiece", "(lv-6) CHESTPIECE_Iron Chestpiece" },
		{ "Dense Chestpiece", "(lv-6) CHESTPIECE_Dense Chestpiece" },
		{ "Golem Chestpiece", "(lv-12) CHESTPIECE_Golem Chestpiece" },
		{ "Amberite Breastplate", "(lv-12) CHESTPIECE_Amberite Breastplate" },
		{ "Mithril Chestpiece", "(lv-16) CHESTPIECE_Mithril Chestpiece" },
		{ "King Breastplate", "(lv-16) CHESTPIECE_King Breastplate" },
		{ "Monolith Chestpiece", "(lv-18) CHESTPIECE_Monolith Chestpiece" },
		{ "Sapphite Guard", "(lv-18) CHESTPIECE_Sapphite Guard" },
		{ "Wizlad Robe", "(lv-24) CHESTPIECE_Wizlad Robe" },
		{ "Executioner Vestment", "(lv-24) CHESTPIECE_Executioner Vestment" },
		{ "Leather Britches", "(lv-1) LEGGINGS_Leather Britches" },
		{ "Dense Leggings", "(lv-6) LEGGINGS_Dense Leggings" },
		{ "Amberite Leggings", "(lv-12) LEGGINGS_Amberite Leggings" },
		{ "Lord Greaves", "(lv-12) LEGGINGS_Lord Greaves" },
		{ "King Greaves", "(lv-16) LEGGINGS_King Greaves" },
		{ "Sapphite Leggings", "(lv-18) LEGGINGS_Sapphite Leggings" },
		{ "Berserker Leggings", "(lv-18) LEGGINGS_Berserker Leggings" },
		{ "Executioner Leggings", "(lv-24) LEGGINGS_Executioner Leggings" },
		{ "Initiate Cloak", "(lv-4) CAPE_Initiate Cloak" },
		{ "Nokket Cloak", "(lv-6) CAPE_Nokket Cloak" },
		{ "Regazuul Cape", "(lv-10) CAPE_Regazuul Cape" },
		{ "Flux Cloak", "(lv-12) CAPE_Flux Cloak" },
		{ "Nulversa Cape", "(lv-20) CAPE_Nulversa Cape" },
		{ "Windgolem Cloak", "(lv-22) CAPE_Windgolem Cloak" },
		{ "Wooden Shield", "(lv-1) SHIELD_Wooden Shield" },
		{ "Iron Shield", "(lv-6) SHIELD_Iron Shield" },
		{ "Dense Shield", "(lv-6) SHIELD_Dense Shield" },
		{ "Amberite Shield", "(lv-12) SHIELD_Amberite Shield" },
		{ "Sapphite Shield", "(lv-18) SHIELD_Sapphite Shield" },
		{ "Old Ring", "(lv-1) RING_Old Ring" },
		{ "Ring Of Ambition", "(lv-1) RING_Ring Of Ambition" },
		{ "Sapphireweave Ring", "(lv-6) RING_Sapphireweave Ring" },
		{ "Emeraldfocus Ring", "(lv-6) RING_Emeraldfocus Ring" },
		{ "Ambersquire Ring", "(lv-6) RING_Ambersquire Ring" },
		{ "Geistlord Ring", "(lv-12) RING_Geistlord Ring" },
		{ "Geistlord Band", "(lv-16) RING_Geistlord Band" },
		{ "Valor Ring", "(lv-16) RING_Valor Ring" },
		{ "Valdur Effigy", "(lv-24) RING_Valdur Effigy" },
		{ "Aqua Muchroom Cap", "TRADEITEM_Aqua Muchroom Cap" },
		{ "Barknaught Face", "TRADEITEM_Barknaught Face" },
		{ "Blightwood Log", "TRADEITEM_Blightwood Log" },
		{ "Blightwood Stick", "TRADEITEM_Blightwood Stick" },
		{ "Blue Minchroom Cap", "TRADEITEM_Blue Minchroom Cap" },
		{ "Boomboar Gear", "TRADEITEM_Boomboar Gear" },
		{ "Boomboar Head", "TRADEITEM_Boomboar Head" },
		{ "Boomboar Pouch", "TRADEITEM_Boomboar Pouch" },
		{ "Burnrose", "TRADEITEM_Burnrose" },
		{ "Carbuncle Foot", "TRADEITEM_Carbuncle Foot" },
		{ "Cursed Note", "TRADEITEM_Cursed Note" },
		{ "Deadwood Log", "TRADEITEM_Deadwood Log" },
		{ "Deathgel Core", "TRADEITEM_Deathgel Core" },
		{ "Deathknight Gauntlet", "TRADEITEM_Deathknight Gauntlet" },
		{ "Demigolem Core", "TRADEITEM_Demigolem Core" },
		{ "Demigolem Gem", "TRADEITEM_Demigolem Gem" },
		{ "Diva Necklace", "TRADEITEM_Diva Necklace" },
		{ "Firebreath Gland", "TRADEITEM_Firebreath Gland" },
		{ "Fluxfern", "TRADEITEM_Fluxfern" },
		{ "Gale Muchroom Cap", "TRADEITEM_Gale Muchroom Cap" },
		{ "Geist Collar", "TRADEITEM_Geist Collar" },
		{ "Ghostdust", "TRADEITEM_Ghostdust" },
		{ "Golem Core", "TRADEITEM_Golem Core" },
		{ "Golem Gem", "TRADEITEM_Golem Gem" },
		{ "Green Lipstick", "TRADEITEM_Green Lipstick" },
		{ "Hellsludge Core", "TRADEITEM_Hellsludge Core" },
		{ "Maw Eye", "TRADEITEM_Maw Eye" },
		{ "Mekboar Head", "TRADEITEM_Mekboar Head" },
		{ "Mekboar Spear", "TRADEITEM_Mekboar Spear" },
		{ "Mekboar Nail", "TRADEITEM_Mekboar Nail" },
		{ "Mekboar Nosering", "TRADEITEM_Mekboar Nosering" },
		{ "Mekboar Spine", "TRADEITEM_Mekboar Spine" },
		{ "Monolith Core", "TRADEITEM_Monolith Core" },
		{ "Monolith Gem", "TRADEITEM_Monolith Gem" },
		{ "Mouth Bittertooth", "TRADEITEM_Mouth Bittertooth" },
		{ "Mouth Eye", "TRADEITEM_Mouth Eye" },
		{ "Rageboar Head", "TRADEITEM_Rageboar Head" },
		{ "Rageboar Spear", "TRADEITEM_Rageboar Spear" },
		{ "Red Minchroom Cap", "TRADEITEM_Red Minchroom Cap" },
		{ "Rock", "TRADEITEM_Rock" },
		{ "Slime Core", "TRADEITEM_Slime Core" },
		{ "Slime Diva Ears", "TRADEITEM_Slime Diva Ears" },
		{ "Slime Ears", "TRADEITEM_Slime Ears" },
		{ "Slimek Core", "TRADEITEM_Slimek Core" },
		{ "Slimek Ears", "TRADEITEM_Slimek Ears" },
		{ "Slimek Eye", "TRADEITEM_Slimek Eye" },
		{ "Vinethorn", "TRADEITEM_Vinethorn" },
		{ "Vout Antennae", "TRADEITEM_Vout Antennae" },
		{ "Vout Wing", "TRADEITEM_Vout Wing" },
		{ "Warboar Axe", "TRADEITEM_Warboar Axe" },
		{ "Warboar Head", "TRADEITEM_Warboar Head" },
		{ "Wizboar Head", "TRADEITEM_Wizboar Head" },
		{ "Wizboar Scepter", "TRADEITEM_Wizboar Scepter" },
		{ "Geistlord Nails", "TRADEITEM_Geistlord Nails" },
		{ "Amberite Ingot", "TRADEITEM_Amberite Ingot" },
		{ "Amberite Ore", "TRADEITEM_Amberite Ore" },
		{ "Dense Ingot", "TRADEITEM_Dense Ingot" },
		{ "Dense Ore", "TRADEITEM_Dense Ore" },
		{ "Copper Cluster", "TRADEITEM_Copper Cluster" },
		{ "Iron Cluster", "TRADEITEM_Iron Cluster" },
		{ "Mithril Cluster", "TRADEITEM_Mithril Cluster" },
		{ "Sapphite Ingot", "TRADEITEM_Sapphite Ingot" },
		{ "Sapphite Ore", "TRADEITEM_Sapphite Ore" },
		{ "Coal", "TRADEITEM_Coal" },
		{ "Big Wan", "TRADEITEM_Big Wan" },
		{ "Bittering Katfish", "TRADEITEM_Bittering Katfish" },
		{ "Bonefish", "TRADEITEM_Bonefish" },
		{ "Smiling Wrellfish", "TRADEITEM_Smiling Wrellfish" },
		{ "Squangfish", "TRADEITEM_Squangfish" },
		{ "Sugeel", "TRADEITEM_Sugeel" },
		{ "Sugshrimp", "TRADEITEM_Sugshrimp" },
		{ "Windtail Fish", "TRADEITEM_Windtail Fish" },
		{ "Old Boot", "TRADEITEM_Old Boot" },
		{ "Bronze Arrows", "TRADEITEM_Bronze Arrows" },
		{ "Agility Stone", "TRADEITEM_Agility Stone" },
		{ "Angela's Tear", "TRADEITEM_Angela's Tear" },
		{ "Epic Carrot", "TRADEITEM_Epic Carrot" },
		{ "Experience Bond", "TRADEITEM_Experience Bond" },
		{ "Flux Stone", "TRADEITEM_Flux Stone" },
		{ "Illusion Stone", "TRADEITEM_Illusion Stone" },
		{ "Might Stone", "TRADEITEM_Might Stone" },
		{ "Starlight Gem", "TRADEITEM_Starlight Gem" }
	};

	public static AtlyssArchipelagoPlugin Instance { get; private set; }

	public static ManualLogSource StaticLogger { get; private set; }

	private string GetLocationName(long locationId)
	{
		if (LocationIdToName.TryGetValue(locationId, out var value))
		{
			return value;
		}
		return $"Location {locationId}";
	}

	private void Awake()
	{
		//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0107: Expected O, but got Unknown
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0116: Expected O, but got Unknown
		Instance = this;
		StaticLogger = ((BaseUnityPlugin)this).Logger;
		cfgServer = ((BaseUnityPlugin)this).Config.Bind<string>("Connection", "Server", "localhost", "Archipelago host. You can also put host:port here.");
		cfgSlot = ((BaseUnityPlugin)this).Config.Bind<string>("Connection", "Slot", "Player", "Your Archipelago slot name.");
		cfgPassword = ((BaseUnityPlugin)this).Config.Bind<string>("Connection", "Password", "", "Room password (optional).");
		cfgAutoConnect = ((BaseUnityPlugin)this).Config.Bind<bool>("Connection", "AutoConnect", false, "Auto-connect on game start.");
		cfgDeathlink = ((BaseUnityPlugin)this).Config.Bind<bool>("Connection", "DeathLink", false, "If DeathLink should be enabled (can be changed ingame).");
		((BaseUnityPlugin)this).Logger.LogInfo((object)"=== [AtlyssAP] Plugin loaded! Version 1.3.1 ===");
		((BaseUnityPlugin)this).Logger.LogInfo((object)"[AtlyssAP] ALL QUESTS + Commands + Item Drops + 261 ITEMS + 50 Shop Locations!");
		((BaseUnityPlugin)this).Logger.LogInfo((object)"[AtlyssAP] Press F5 to connect to Archipelago");
		_harmony = new Harmony("com.azrael.atlyss.ap.harmony");
		scriptHolder = new GameObject("Archipelago Script Holder");
		Object.DontDestroyOnLoad((Object)(object)scriptHolder);
		portalLocker = scriptHolder.AddComponent<PortalUnlocks>();
		_shopSanity = new ArchipelagoShopSanity(this, ((BaseUnityPlugin)this).Logger);
		try
		{
			_harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[AtlyssAP] Harmony patches applied successfully");
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[AtlyssAP] Failed to apply Harmony patches: " + ex.Message));
		}
	}

	private void Start()
	{
		if (cfgAutoConnect.Value)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[AtlyssAP] Auto-connecting...");
			TryConnect();
		}
	}

	private void OnDestroy()
	{
		Disconnect();
	}

	private void Update()
	{
		if (Input.GetKeyDown((KeyCode)286))
		{
			TryConnect();
		}
		if (connected)
		{
			PollForLevelChanges();
			PollForQuestCompletions();
			PollForSkillLevelChanges();
		}
	}

	private void PollForLevelChanges()
	{
		try
		{
			Player mainPlayer = Player._mainPlayer;
			if ((Object)(object)mainPlayer == (Object)null)
			{
				return;
			}
			PlayerStats component = ((Component)mainPlayer).GetComponent<PlayerStats>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			int network_currentLevel = component.Network_currentLevel;
			if (network_currentLevel == _lastLevel)
			{
				return;
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"[AtlyssAP] Level changed: {_lastLevel} -> {network_currentLevel}");
			if (network_currentLevel >= 2 && network_currentLevel <= 32 && network_currentLevel % 2 == 0)
			{
				long num = 591010L + (long)((network_currentLevel - 2) / 2);
				if (!_reportedChecks.Contains(num))
				{
					SendCheckById(num);
					SendAPChatMessage($"Found <color=yellow>Reach Level {network_currentLevel}</color>! " + "Sent item to another player!");
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"[AtlyssAP] Reached Level {network_currentLevel} milestone!");
				}
			}
			_lastLevel = network_currentLevel;
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[AtlyssAP] Error polling level: " + ex.Message));
		}
	}

	private void PollForSkillLevelChanges()
	{
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_0194: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			Player mainPlayer = Player._mainPlayer;
			if ((Object)(object)mainPlayer == (Object)null)
			{
				return;
			}
			PlayerStats pStats = mainPlayer._pStats;
			if ((Object)(object)pStats == (Object)null)
			{
				return;
			}
			for (int i = 0; i < pStats._syncProfessions.Count; i++)
			{
				ProfessionStruct val = pStats._syncProfessions[i];
				ScriptableProfession val2 = null;
				if ((Object)(object)GameManager._current != (Object)null && (Object)(object)GameManager._current._statLogics != (Object)null && i < GameManager._current._statLogics._scriptableProfessions.Length)
				{
					val2 = GameManager._current._statLogics._scriptableProfessions[i];
				}
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				if (val2._professionName == "Fishing")
				{
					int professionLvl = val._professionLvl;
					if (professionLvl > _previousFishingLevel)
					{
						for (int j = _previousFishingLevel + 1; j <= professionLvl; j++)
						{
							if (FishingLevelLocations.TryGetValue(j, out var value))
							{
								SendCheckById(value);
								SendAPChatMessage($"Found <color=yellow>Fishing Level {j}</color>! " + "Sent item to another player!");
								((BaseUnityPlugin)this).Logger.LogInfo((object)$"[AtlyssAP] Fishing level {j} reached!");
							}
						}
						_previousFishingLevel = professionLvl;
					}
				}
				if (!(val2._professionName == "Mining"))
				{
					continue;
				}
				int professionLvl2 = val._professionLvl;
				if (professionLvl2 <= _previousMiningLevel)
				{
					continue;
				}
				for (int k = _previousMiningLevel + 1; k <= professionLvl2; k++)
				{
					if (MiningLevelLocations.TryGetValue(k, out var value2))
					{
						SendCheckById(value2);
						SendAPChatMessage($"Found <color=yellow>Mining Level {k}</color>! " + "Sent item to another player!");
						((BaseUnityPlugin)this).Logger.LogInfo((object)$"[AtlyssAP] Mining level {k} reached!");
					}
				}
				_previousMiningLevel = professionLvl2;
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[AtlyssAP] Error checking skill levels: " + ex.Message));
		}
	}

	private void PollForQuestCompletions()
	{
		try
		{
			Player mainPlayer = Player._mainPlayer;
			if ((Object)(object)mainPlayer == (Object)null)
			{
				return;
			}
			PlayerQuesting component = ((Component)mainPlayer).GetComponent<PlayerQuesting>();
			if ((Object)(object)component == (Object)null || component._finishedQuests == null)
			{
				return;
			}
			if (!_questDebugLogged && component._finishedQuests.Count > 0)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"[AtlyssAP] DEBUG: Found {component._finishedQuests.Count} completed quests");
				foreach (string key2 in component._finishedQuests.Keys)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("[AtlyssAP] DEBUG: Completed quest: '" + key2 + "'"));
				}
				_questDebugLogged = true;
			}
			foreach (KeyValuePair<string, long> item in AllQuestToLocation)
			{
				string key = item.Key;
				long value = item.Value;
				if (component._finishedQuests.ContainsKey(key) && !_completedQuests.Contains(key))
				{
					SendCheckById(value);
					_completedQuests.Add(key);
					SendAPChatMessage("Found <color=yellow>" + key + "</color>! Sent item to another player!");
					((BaseUnityPlugin)this).Logger.LogInfo((object)("[AtlyssAP] Quest completed: " + key));
					if (key == "Gatling Galius")
					{
						SendAPChatMessage("<color=gold>VICTORY!</color> <color=yellow>You completed your goal!</color>");
						((BaseUnityPlugin)this).Logger.LogInfo((object)"[AtlyssAP] VICTORY! Defeated final boss Galius!");
					}
				}
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[AtlyssAP] Error polling quests: " + ex.Message));
		}
	}

	private bool IsNewSession(string sessionId)
	{
		try
		{
			string path = Path.Combine(Application.persistentDataPath, "ap_session.json");
			if (!File.Exists(path))
			{
				return true;
			}
			string text = File.ReadAllText(path);
			return text != sessionId;
		}
		catch
		{
			return true;
		}
	}

	private void SaveSessionId(string sessionId)
	{
		try
		{
			string path = Path.Combine(Application.persistentDataPath, "ap_session.json");
			File.WriteAllText(path, sessionId);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Saved session ID: " + sessionId));
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Failed to save session ID: " + ex.Message));
		}
	}

	private void TryConnect()
	{
		//IL_065b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0665: Expected O, but got Unknown
		//IL_0678: Unknown result type (might be due to invalid IL or missing references)
		//IL_0682: Expected O, but got Unknown
		//IL_0690: Unknown result type (might be due to invalid IL or missing references)
		//IL_069a: Expected O, but got Unknown
		//IL_06ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_06b7: Expected O, but got Unknown
		//IL_0607: Unknown result type (might be due to invalid IL or missing references)
		//IL_0611: Expected O, but got Unknown
		//IL_059e: Unknown result type (might be due to invalid IL or missing references)
		//IL_05a5: Expected O, but got Unknown
		if (connected)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"[AtlyssAP] Already connected.");
			return;
		}
		if (connecting)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"[AtlyssAP] Connection in progress...");
			return;
		}
		connecting = true;
		try
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[AtlyssAP] === CONNECTING TO ARCHIPELAGO ===");
			((BaseUnityPlugin)this).Logger.LogInfo((object)("[AtlyssAP] Server: " + apServer.text));
			((BaseUnityPlugin)this).Logger.LogInfo((object)("[AtlyssAP] Slot: " + apSlot.text));
			_session = ArchipelagoSessionFactory.CreateSession(apServer.text, 38281);
			_dlService = DeathLinkProvider.CreateDeathLinkService(_session);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[AtlyssAP] Session and DeathLink service created");
			string text = (string.IsNullOrWhiteSpace(apPassword.text) ? null : apPassword.text);
			LoginResult val = _session.TryConnectAndLogin("ATLYSS", apSlot.text, (ItemsHandlingFlags)7, (Version)null, (!Object.op_Implicit((Object)(object)apDeathlink)) ? Array.Empty<string>() : new string[1] { "DeathLink" }, (string)null, text, true);
			if (!val.Successful)
			{
				LoginFailure val2 = (LoginFailure)(object)((val is LoginFailure) ? val : null);
				if (val2 != null && val2.Errors != null && val2.Errors.Length != 0)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("[AtlyssAP] Login failed: " + string.Join(", ", val2.Errors)));
				}
				else
				{
					((BaseUnityPlugin)this).Logger.LogError((object)"[AtlyssAP] Login failed.");
				}
				Disconnect();
				connecting = false;
				return;
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[AtlyssAP] Login successful!");
			cfgServer.Value = apServer.text;
			cfgSlot.Value = apSlot.text;
			cfgPassword.Value = apPassword.text;
			try
			{
				LoginSuccessful val3 = (LoginSuccessful)(object)((val is LoginSuccessful) ? val : null);
				if (val3 != null && val3.SlotData != null)
				{
					slotData = val3.SlotData;
					if (slotData.ContainsKey("goal"))
					{
						goalOption = Convert.ToInt32(slotData["goal"]);
						string[] array = new string[9] { "Slime Diva", "Lord Zuulneruda", "Colossus", "Galius", "Lord Kaluuz", "Valdur", "All Bosses", "All Quests", "Level 32" };
						((BaseUnityPlugin)this).Logger.LogInfo((object)("[AtlyssAP] Goal: " + array[goalOption]));
					}
					if (slotData.ContainsKey("random_portals"))
					{
						randomPortalsEnabled = Convert.ToInt32(slotData["random_portals"]) == 1;
						((BaseUnityPlugin)this).Logger.LogInfo((object)("[AtlyssAP] Portal Mode: " + (randomPortalsEnabled ? "Random Portals" : "Progressive Portals")));
					}
					if (slotData.ContainsKey("equipment_progression"))
					{
						equipmentProgressionOption = Convert.ToInt32(slotData["equipment_progression"]);
						((BaseUnityPlugin)this).Logger.LogInfo((object)("[AtlyssAP] Equipment: " + ((equipmentProgressionOption == 1) ? "Progressive" : "Random")));
					}
					if (slotData.ContainsKey("shop_sanity"))
					{
						shopSanityEnabled = Convert.ToInt32(slotData["shop_sanity"]) == 1;
						((BaseUnityPlugin)this).Logger.LogInfo((object)("[AtlyssAP] Shop Sanity: " + (shopSanityEnabled ? "Enabled" : "Disabled")));
					}
				}
				else
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"[AtlyssAP] Login successful but slot data is null - using default options");
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[AtlyssAP] Could not read slot data: " + ex.Message));
			}
			SendAPChatMessage("<color=yellow>Connected to multiworld!</color>");
			string[] array2 = new string[9] { "Your goal: <color=red>Defeat Slime Diva</color>", "Your goal: <color=red>Defeat Lord Zuulneruda</color>", "Your goal: <color=red>Defeat Colossus</color>", "Your goal: <color=red>Defeat Galius</color>", "Your goal: <color=red>Defeat Lord Kaluuz</color>", "Your goal: <color=red>Defeat Valdur</color>", "Your goal: <color=red>Defeat All Bosses</color>", "Your goal: <color=yellow>Complete All Quests</color>", "Your goal: <color=#00FFFF>Reach Level 32</color>" };
			if (goalOption >= 0 && goalOption < array2.Length)
			{
				SendAPChatMessage(array2[goalOption]);
			}
			portalLocker.ApplyAreaAccessMode();
			if (shopSanityEnabled)
			{
				_shopSanity.SendLocationScouts(_session);
			}
			string sessionId = apServer.text + "_" + apSlot.text + "_" + _session.RoomState.Seed;
			if (IsNewSession(sessionId))
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[AtlyssAP] New AP session detected - clearing storage");
				ArchipelagoSpikeStorage.ClearAllAPBanks();
				SaveSessionId(sessionId);
			}
			currentSessionId = sessionId;
			SpikePatch.InitializeAPStorage();
			try
			{
				IArchipelagoSocketHelper socket = _session.Socket;
				GetDataPackagePacket val4 = new GetDataPackagePacket();
				val4.Games = new string[1] { "ATLYSS" };
				socket.SendPacket((ArchipelagoPacketBase)(object)val4);
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[AtlyssAP] Data package requested.");
			}
			catch (Exception ex2)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[AtlyssAP] Data package warning: " + ex2.Message));
			}
			try
			{
				_session.Socket.SendPacket((ArchipelagoPacketBase)new SyncPacket());
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[AtlyssAP] Sync packet sent.");
			}
			catch (Exception ex3)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[AtlyssAP] Sync packet warning: " + ex3.Message));
			}
			_session.Items.ItemReceived += new ItemReceivedHandler(OnItemReceived);
			_session.Socket.PacketReceived += new PacketReceivedHandler(OnPacketReceived);
			_dlService.OnDeathLinkReceived += new DeathLinkReceivedHandler(OnDeathLinkReceived);
			_session.Locations.CheckedLocationsUpdated += (CheckedLocationsUpdatedHandler)delegate(ReadOnlyCollection<long> locations)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"[AtlyssAP] Server confirmed {locations.Count} checked location(s)");
			};
			Player mainPlayer = Player._mainPlayer;
			if ((Object)(object)mainPlayer != (Object)null)
			{
				PlayerStats component = ((Component)mainPlayer).GetComponent<PlayerStats>();
				if ((Object)(object)component != (Object)null)
				{
					_lastLevel = component.Network_currentLevel;
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"[AtlyssAP] Starting at level {_lastLevel}");
					_previousFishingLevel = 1;
					_previousMiningLevel = 1;
				}
			}
			connected = true;
			connecting = false;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"=== [AtlyssAP] Connected and ready! ===");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[AtlyssAP] Automatic detection active - level-ups and quests will be tracked!");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[AtlyssAP] Items will be sent to Spike storage!");
		}
		catch (Exception ex4)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[AtlyssAP] Connection failed: " + ex4.Message));
			((BaseUnityPlugin)this).Logger.LogError((object)("[AtlyssAP] Stack: " + ex4.StackTrace));
			Disconnect();
			connecting = false;
			connected = false;
		}
	}

	private void Disconnect()
	{
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Expected O, but got Unknown
		try
		{
			if (_session == null)
			{
				return;
			}
			try
			{
				_session.Items.ItemReceived -= new ItemReceivedHandler(OnItemReceived);
			}
			catch
			{
			}
			try
			{
				if (_session.Socket != null)
				{
					_session.Socket.DisconnectAsync();
				}
			}
			catch
			{
			}
		}
		finally
		{
			_session = null;
			connected = false;
			connecting = false;
			_reportedChecks.Clear();
			_completedQuests.Clear();
			_lastLevel = 0;
			_previousFishingLevel = 1;
			_previousMiningLevel = 1;
			_questDebugLogged = false;
			foreach (string item in _portalItemsReceived.Keys.ToList())
			{
				_portalItemsReceived[item] = false;
			}
			progressivePortalCount = 0;
			progressiveEquipmentTier = 0;
			_shopSanity.Reset();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[AtlyssAP] Disconnected.");
		}
	}

	private void SendCheckById(long locationId)
	{
		if (!connected || _session == null)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)"[AtlyssAP] Not connected; cannot send check.");
		}
		else
		{
			if (_reportedChecks.Contains(locationId))
			{
				return;
			}
			try
			{
				if (_session != null && _session.Socket != null && _session.Socket.Connected)
				{
					_session.Locations.CompleteLocationChecks(new long[1] { locationId });
					_reportedChecks.Add(locationId);
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"[AtlyssAP] Sent check ID: {locationId}");
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("[AtlyssAP] Failed to send check: " + ex.Message));
			}
		}
	}

	private void OnDeathLinkReceived(DeathLink dl)
	{
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		reactingToDeathLink = 2;
		try
		{
			Player mainPlayer = Player._mainPlayer;
			if ((Object)(object)mainPlayer == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"[AtlyssAP] Player not found for DeathLink! Possibly on Main Menu?");
				reactingToDeathLink = 0;
				return;
			}
			mainPlayer._playerZoneType = (ZoneType)1;
			mainPlayer._statusEntity.Subtract_Health(10000);
			((BaseUnityPlugin)this).Logger.LogMessage((object)"[AtlyssAP] DeathLink Received!");
			string text = ((!Utility.IsNullOrWhiteSpace(dl.Cause)) ? (dl.Cause + ".") : ("Killed by " + dl.Source + " on Archipelago."));
			try
			{
				GameObject.Find("_GameUI_InGame").GetComponent<ErrorPromptTextManager>().Init_ErrorPrompt(text);
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("[AtlyssAP] Failed to display DeathLink message: " + ex.Message));
			}
		}
		catch (Exception ex2)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[AtlyssAP] Failed to process DeathLink: " + ex2.Message));
			reactingToDeathLink = 0;
		}
	}

	private void OnItemReceived(ReceivedItemsHelper helper)
	{
		try
		{
			ItemInfo val = helper.DequeueItem();
			string text = helper.GetItemName(val.ItemId, val.ItemGame) ?? $"Item {val.ItemId}";
			string text2 = _session.Players.GetPlayerName(PlayerInfo.op_Implicit(val.Player)) ?? $"Player {val.Player}";
			((BaseUnityPlugin)this).Logger.LogInfo((object)("[AtlyssAP] Received: " + text + " from " + text2));
			SendAPChatMessage("Received <color=yellow>" + text + "</color> from <color=#00FFFF>" + text2 + "</color>!");
			HandleReceivedItem(text);
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[AtlyssAP] Error receiving item: " + ex.Message));
		}
	}

	private void HandleReceivedItem(string itemName)
	{
		try
		{
			if (itemName == "Progressive Portal")
			{
				progressivePortalCount++;
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"[AtlyssAP] Progressive Portal #{progressivePortalCount}");
				if (progressivePortalCount <= _progressivePortalOrder.Count)
				{
					string text = _progressivePortalOrder[progressivePortalCount - 1];
					if (_portalScenes.ContainsKey(text))
					{
						string sceneName = _portalScenes[text];
						portalLocker.UnblockAccessToScene(sceneName);
						SendAPChatMessage("<color=#00FFFF>" + text.Replace(" Portal", "") + " unlocked!</color>");
					}
				}
				return;
			}
			if (itemName == "Progressive Equipment")
			{
				progressiveEquipmentTier++;
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"[AtlyssAP] Progressive Equipment received (#{progressiveEquipmentTier})");
				try
				{
					int num = 1;
					Player mainPlayer = Player._mainPlayer;
					if ((Object)(object)mainPlayer != (Object)null)
					{
						PlayerStats component = ((Component)mainPlayer).GetComponent<PlayerStats>();
						if ((Object)(object)component != (Object)null)
						{
							num = component.Network_currentLevel;
						}
					}
					List<KeyValuePair<string, string>> equipmentForLevel = GetEquipmentForLevel(num);
					if (equipmentForLevel.Count > 0)
					{
						int index = Random.Range(0, equipmentForLevel.Count);
						KeyValuePair<string, string> keyValuePair = equipmentForLevel[index];
						string key = keyValuePair.Key;
						string value = keyValuePair.Value;
						((BaseUnityPlugin)this).Logger.LogInfo((object)$"[AtlyssAP] Progressive Equipment chose: {key} (player level {num})");
						ItemData val = CreateItemData(value, 1);
						if (val != null)
						{
							if (ArchipelagoSpikeStorage.AddItemToAPSpike(val))
							{
								SendAPChatMessage("<color=#FFD700>Progressive Equipment: " + key + "!</color> Check Spike's storage!");
								((BaseUnityPlugin)this).Logger.LogInfo((object)("[AtlyssAP] Added " + key + " to Spike storage"));
							}
							else
							{
								((BaseUnityPlugin)this).Logger.LogWarning((object)("[AtlyssAP] Failed to add " + key + " to storage - banks full!"));
								SendAPChatMessage("<color=red>Storage full! Could not store " + key + "</color>");
							}
						}
						else
						{
							((BaseUnityPlugin)this).Logger.LogWarning((object)("[AtlyssAP] Could not create ItemData for: " + key));
						}
					}
					else
					{
						((BaseUnityPlugin)this).Logger.LogWarning((object)$"[AtlyssAP] No eligible equipment found for level {num}!");
						SendAPChatMessage($"<color=red>Progressive Equipment: No gear available for level {num}!</color>");
					}
					return;
				}
				catch (Exception ex)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("[AtlyssAP] Error processing Progressive Equipment: " + ex.Message));
					return;
				}
			}
			if (_portalItemsReceived.ContainsKey(itemName))
			{
				_portalItemsReceived[itemName] = true;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("[AtlyssAP] Received " + itemName + "!"));
				if (_portalScenes.ContainsKey(itemName))
				{
					string sceneName2 = _portalScenes[itemName];
					portalLocker.UnblockAccessToScene(sceneName2);
					SendAPChatMessage("<color=#00FFFF>" + itemName.Replace(" Portal", "") + " unlocked!</color>");
				}
				return;
			}
			if (itemName.StartsWith("Crowns ("))
			{
				int currencyAmount = GetCurrencyAmount(itemName);
				if (currencyAmount > 0)
				{
					GiveCurrency(currencyAmount);
					SendAPChatMessage($"<color=yellow>Received {currencyAmount} Crowns!</color>");
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"[AtlyssAP] Gave {currencyAmount} crowns to player");
				}
				return;
			}
			if (ItemNameMapping.TryGetValue(itemName, out var value2))
			{
				int quantity = DetermineItemQuantity(itemName);
				try
				{
					ItemData val2 = CreateItemData(value2, quantity);
					if (val2 != null)
					{
						if (ArchipelagoSpikeStorage.AddItemToAPSpike(val2))
						{
							SendAPChatMessage("<color=yellow>Received " + itemName + "!</color> Check Spike's storage!");
							((BaseUnityPlugin)this).Logger.LogInfo((object)("[AtlyssAP] Added " + itemName + " to Spike storage"));
						}
						else
						{
							((BaseUnityPlugin)this).Logger.LogWarning((object)("[AtlyssAP] Failed to add " + itemName + " to storage - banks full!"));
							SendAPChatMessage("<color=red>Storage full! Could not store " + itemName + "</color>");
						}
					}
					return;
				}
				catch (Exception ex2)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("[AtlyssAP] Failed to process item " + itemName + ": " + ex2.Message));
					return;
				}
			}
			((BaseUnityPlugin)this).Logger.LogWarning((object)("[AtlyssAP] Unknown item: " + itemName));
		}
		catch (Exception ex3)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[AtlyssAP] Error handling item '" + itemName + "': " + ex3.Message));
		}
	}

	private ItemData CreateItemData(string gameItemName, int quantity)
	{
		//IL_0341: Unknown result type (might be due to invalid IL or missing references)
		//IL_0346: Unknown result type (might be due to invalid IL or missing references)
		//IL_0352: Unknown result type (might be due to invalid IL or missing references)
		//IL_0359: Unknown result type (might be due to invalid IL or missing references)
		//IL_0361: Unknown result type (might be due to invalid IL or missing references)
		//IL_0368: Unknown result type (might be due to invalid IL or missing references)
		//IL_036f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0378: Expected O, but got Unknown
		string text = gameItemName;
		int num = gameItemName.LastIndexOf('_');
		if (num >= 0 && num < gameItemName.Length - 1)
		{
			text = gameItemName.Substring(num + 1);
		}
		((BaseUnityPlugin)this).Logger.LogInfo((object)("[AtlyssAP] DEBUG: Looking up item: '" + text + "'"));
		ScriptableItem val = null;
		List<string> list = new List<string>();
		val = GameManager._current.Locate_Item(text);
		list.Add("1. '" + text + "'");
		if ((Object)(object)val == (Object)null && text.Contains(" (") && text.EndsWith(")"))
		{
			string text2 = text[..text.LastIndexOf(" (")];
			((BaseUnityPlugin)this).Logger.LogInfo((object)("[AtlyssAP] DEBUG: Attempt 2 - base name: '" + text2 + "'"));
			val = GameManager._current.Locate_Item(text2);
			list.Add("2. '" + text2 + "'");
		}
		if ((Object)(object)val == (Object)null && text != gameItemName)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)("[AtlyssAP] DEBUG: Attempt 3 - full Unity name: '" + gameItemName + "'"));
			val = GameManager._current.Locate_Item(gameItemName);
			list.Add("3. '" + gameItemName + "'");
		}
		if ((Object)(object)val == (Object)null)
		{
			string text3 = text.Replace(" ", "");
			((BaseUnityPlugin)this).Logger.LogInfo((object)("[AtlyssAP] DEBUG: Attempt 4 - no spaces: '" + text3 + "'"));
			val = GameManager._current.Locate_Item(text3);
			list.Add("4. '" + text3 + "'");
		}
		if ((Object)(object)val == (Object)null && gameItemName.Contains("WEAPON_"))
		{
			string text4 = gameItemName.Substring(gameItemName.IndexOf("WEAPON_") + 7);
			if (text4.Contains(" ("))
			{
				string text5 = text4.Substring(0, text4.IndexOf(" ("));
				((BaseUnityPlugin)this).Logger.LogInfo((object)("[AtlyssAP] DEBUG: Attempt 5 - weapon name only: '" + text5 + "'"));
				val = GameManager._current.Locate_Item(text5);
				list.Add("5. '" + text5 + "'");
			}
		}
		if ((Object)(object)val == (Object)null)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[AtlyssAP] Could not find ScriptableItem for: '" + text + "'"));
			((BaseUnityPlugin)this).Logger.LogError((object)("[AtlyssAP] Original Unity name: '" + gameItemName + "'"));
			((BaseUnityPlugin)this).Logger.LogError((object)$"[AtlyssAP] Tried {list.Count} variations:");
			foreach (string item in list)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("[AtlyssAP]   - " + item));
			}
			((BaseUnityPlugin)this).Logger.LogWarning((object)"[AtlyssAP] This item may not be available in the current game version or uses a different name format");
			return null;
		}
		((BaseUnityPlugin)this).Logger.LogInfo((object)("[AtlyssAP] DEBUG: Found ScriptableItem: " + val._itemName));
		ItemData result = new ItemData
		{
			_itemName = val._itemName,
			_quantity = quantity,
			_maxQuantity = 99,
			_modifierID = 0,
			_isEquipped = false,
			_slotNumber = 0
		};
		((BaseUnityPlugin)this).Logger.LogInfo((object)("[AtlyssAP] Successfully created ItemData for: " + val._itemName));
		return result;
	}

	private int GetCurrencyAmount(string itemName)
	{
		return itemName switch
		{
			"Crowns (Small)" => 100, 
			"Crowns (Medium)" => 500, 
			"Crowns (Large)" => 2000, 
			"Crowns (Huge)" => 5000, 
			_ => 100, 
		};
	}

	private int DetermineItemQuantity(string itemName)
	{
		if (ItemNameMapping.TryGetValue(itemName, out var value))
		{
			string[] array = new string[7] { "WEAPON_", "HELM_", "CHESTPIECE_", "LEGGINGS_", "CAPE_", "SHIELD_", "RING_" };
			string[] array2 = array;
			foreach (string value2 in array2)
			{
				if (value.Contains(value2))
				{
					return 1;
				}
			}
		}
		return 10;
	}

	private List<KeyValuePair<string, string>> GetEquipmentForLevel(int playerLevel)
	{
		List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
		string[] array = new string[7] { "WEAPON_", "HELM_", "CHESTPIECE_", "LEGGINGS_", "CAPE_", "SHIELD_", "RING_" };
		foreach (KeyValuePair<string, string> item in ItemNameMapping)
		{
			string value = item.Value;
			bool flag = false;
			string[] array2 = array;
			foreach (string value2 in array2)
			{
				if (value.Contains(value2))
				{
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				continue;
			}
			int result = 0;
			if (value.StartsWith("(lv-"))
			{
				int num = value.IndexOf(')');
				if (num > 4)
				{
					string s = value.Substring(4, num - 4);
					int.TryParse(s, out result);
				}
			}
			if (result <= playerLevel)
			{
				list.Add(item);
			}
		}
		((BaseUnityPlugin)this).Logger.LogInfo((object)$"[AtlyssAP] Found {list.Count} eligible equipment pieces for level {playerLevel}");
		return list;
	}

	private void GiveCurrency(int amount)
	{
		try
		{
			Player mainPlayer = Player._mainPlayer;
			if ((Object)(object)mainPlayer == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"[AtlyssAP] Player not found!");
				return;
			}
			PlayerInventory component = ((Component)mainPlayer).GetComponent<PlayerInventory>();
			if ((Object)(object)component == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"[AtlyssAP] PlayerInventory not found!");
				return;
			}
			component.Network_heldCurrency += amount;
			SendAPChatMessage($"<color=yellow>+{amount} Crowns</color> added to wallet!");
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"[AtlyssAP] Gave {amount} Crowns! New total: {component.Network_heldCurrency}");
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[AtlyssAP] Failed to give currency: " + ex.Message));
		}
	}

	public void SendAPChatMessage(string message)
	{
		try
		{
			Player mainPlayer = Player._mainPlayer;
			if (!((Object)(object)mainPlayer == (Object)null))
			{
				ChatBehaviour chatBehaviour = mainPlayer._chatBehaviour;
				maxOnscreenMessages.SetValue(chatBehaviour, 50);
				if (!((Object)(object)chatBehaviour == (Object)null))
				{
					chatBehaviour.Init_GameLogicMessage("<color=#00ff00>[Archipelago]</color> " + message);
				}
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[AtlyssAP] Failed to send chat message: " + ex.Message));
		}
	}

	public void HandleArchipelagoCommand(string message)
	{
		//IL_013b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0140: Unknown result type (might be due to invalid IL or missing references)
		//IL_014d: Expected O, but got Unknown
		if (!connected || _session == null)
		{
			SendAPChatMessage("<color=red>Not connected to Archipelago!</color>");
			return;
		}
		string text = message.TrimStart(new char[1] { '/' }).Trim();
		string[] array = text.Split(new char[1] { ' ' }, 2);
		string text2 = array[0].ToLower();
		string text3 = ((array.Length > 1) ? array[1] : "");
		((BaseUnityPlugin)this).Logger.LogInfo((object)("[AtlyssAP] Command received: " + text2 + " " + text3));
		switch (text2)
		{
		case "release":
			HandleReleaseCommand();
			return;
		case "collect":
			HandleCollectCommand();
			return;
		case "hint":
			HandleHintCommand(text3);
			return;
		case "help":
			HandleHelpCommand();

Newtonsoft.Json.dll

Decompiled 17 hours ago
#define DEBUG
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data;
using System.Data.SqlTypes;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Dynamic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Numerics;
using System.Reflection;
using System.Reflection.Emit;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json.Bson;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Linq.JsonPath;
using Newtonsoft.Json.Schema;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Utilities;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AllowPartiallyTrustedCallers]
[assembly: InternalsVisibleTo("Newtonsoft.Json.Schema")]
[assembly: InternalsVisibleTo("Newtonsoft.Json.Tests")]
[assembly: InternalsVisibleTo("Newtonsoft.Json.Dynamic, PublicKey=0024000004800000940000000602000000240000525341310004000001000100cbd8d53b9d7de30f1f1278f636ec462cf9c254991291e66ebb157a885638a517887633b898ccbcf0d5c5ff7be85a6abe9e765d0ac7cd33c68dac67e7e64530e8222101109f154ab14a941c490ac155cd1d4fcba0fabb49016b4ef28593b015cab5937da31172f03f67d09edda404b88a60023f062ae71d0b2e4438b74cc11dc9")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("9ca358aa-317b-4925-8ada-4a29e943a363")]
[assembly: CLSCompliant(true)]
[assembly: TargetFramework(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")]
[assembly: AssemblyCompany("Newtonsoft")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyCopyright("Copyright © James Newton-King 2008")]
[assembly: AssemblyDescription("Json.NET is a popular high-performance JSON framework for .NET")]
[assembly: AssemblyFileVersion("11.0.1")]
[assembly: AssemblyInformationalVersion("11.0.1-beta2+0eb477a285cdf06aa7bf5e103583768eba37fed6")]
[assembly: AssemblyProduct("Json.NET")]
[assembly: AssemblyTitle("Json.NET")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/ArchipelagoMW/Archipelago.MultiClient.Net.git")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyVersion("11.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

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

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

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

			internal readonly int HashCode;

			internal Entry Next;

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

		private static readonly int HashCodeRandomizer;

		private int _count;

		private Entry[] _entries;

		private int _mask = 31;

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

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

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

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

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

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

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

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

		int LinePosition { get; }

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

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

		public JsonArrayAttribute()
		{
		}

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

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

		internal bool? _itemIsReference;

		internal ReferenceLoopHandling? _itemReferenceLoopHandling;

		internal TypeNameHandling? _itemTypeNameHandling;

		private Type? _namingStrategyType;

		private object[]? _namingStrategyParameters;

		public string? Id { get; set; }

		public string? Title { get; set; }

		public string? Description { get; set; }

		public Type? ItemConverterType { get; set; }

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

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

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

		internal NamingStrategy? NamingStrategyInstance { get; set; }

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

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

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

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

		protected JsonContainerAttribute()
		{
		}

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

		public static readonly string False = "false";

		public static readonly string Null = "null";

		public static readonly string Undefined = "undefined";

		public static readonly string PositiveInfinity = "Infinity";

		public static readonly string NegativeInfinity = "-Infinity";

		public static readonly string NaN = "NaN";

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

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

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

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

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

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

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

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

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

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

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

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

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

		private static string ToStringInternal(BigInteger value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		public static string SerializeXmlNode(XmlNode? node)
		{
			return SerializeXmlNode(node, Formatting.None);
		}

		public static string SerializeXmlNode(XmlNode? node, Formatting formatting)
		{
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter();
			return SerializeObject(node, formatting, xmlNodeConverter);
		}

		public static string SerializeXmlNode(XmlNode? node, Formatting formatting, bool omitRootObject)
		{
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter
			{
				OmitRootObject = omitRootObject
			};
			return SerializeObject(node, formatting, xmlNodeConverter);
		}

		public static XmlDocument? DeserializeXmlNode(string value)
		{
			return DeserializeXmlNode(value, null);
		}

		public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName)
		{
			return DeserializeXmlNode(value, deserializeRootElementName, writeArrayAttribute: false);
		}

		public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName, bool writeArrayAttribute)
		{
			return DeserializeXmlNode(value, deserializeRootElementName, writeArrayAttribute, encodeSpecialCharacters: false);
		}

		public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName, bool writeArrayAttribute, bool encodeSpecialCharacters)
		{
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter();
			xmlNodeConverter.DeserializeRootElementName = deserializeRootElementName;
			xmlNodeConverter.WriteArrayAttribute = writeArrayAttribute;
			xmlNodeConverter.EncodeSpecialCharacters = encodeSpecialCharacters;
			return (XmlDocument)DeserializeObject(value, typeof(XmlDocument), xmlNodeConverter);
		}

		public static string SerializeXNode(XObject? node)
		{
			return SerializeXNode(node, Formatting.None);
		}

		public static string SerializeXNode(XObject? node, Formatting formatting)
		{
			return SerializeXNode(node, formatting, omitRootObject: false);
		}

		public static string SerializeXNode(XObject? node, Formatting formatting, bool omitRootObject)
		{
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter
			{
				OmitRootObject = omitRootObject
			};
			return SerializeObject(node, formatting, xmlNodeConverter);
		}

		public static XDocument? DeserializeXNode(string value)
		{
			return DeserializeXNode(value, null);
		}

		public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName)
		{
			return DeserializeXNode(value, deserializeRootElementName, writeArrayAttribute: false);
		}

		public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName, bool writeArrayAttribute)
		{
			return DeserializeXNode(value, deserializeRootElementName, writeArrayAttribute, encodeSpecialCharacters: false);
		}

		public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName, bool writeArrayAttribute, bool encodeSpecialCharacters)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			XmlNodeConverter xmlNodeConverter = new XmlNodeConverter();
			xmlNodeConverter.DeserializeRootElementName = deserializeRootElementName;
			xmlNodeConverter.WriteArrayAttribute = writeArrayAttribute;
			xmlNodeConverter.EncodeSpecialCharacters = encodeSpecialCharacters;
			return (XDocument)DeserializeObject(value, typeof(XDocument), xmlNodeConverter);
		}
	}
	public abstract class JsonConverter
	{
		public virtual bool CanRead => true;

		public virtual bool CanWrite => true;

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

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

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

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

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

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

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

		public Type ConverterType => _converterType;

		public object[]? ConverterParameters { get; }

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

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

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

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

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

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

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

		public bool ReadData { get; set; }

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

		internal MissingMemberHandling? _missingMemberHandling;

		internal Required? _itemRequired;

		internal NullValueHandling? _itemNullValueHandling;

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

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

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

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

		public JsonObjectAttribute()
		{
		}

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

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

		internal JsonContainerType Type;

		internal int Position;

		internal string? PropertyName;

		internal bool HasIndex;

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

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

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

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

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

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

		internal DefaultValueHandling? _defaultValueHandling;

		internal ReferenceLoopHandling? _referenceLoopHandling;

		internal ObjectCreationHandling? _objectCreationHandling;

		internal TypeNameHandling? _typeNameHandling;

		internal bool? _isReference;

		internal int? _order;

		internal Required? _required;

		internal bool? _itemIsReference;

		internal ReferenceLoopHandling? _itemReferenceLoopHandling;

		internal TypeNameHandling? _itemTypeNameHandling;

		public Type? ItemConverterType { get; set; }

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

		public Type? NamingStrategyType { get; set; }

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

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

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

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

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

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

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

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

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

		public string? PropertyName { get; set; }

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

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

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

		public JsonPropertyAttribute()
		{
		}

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

		private JsonToken _tokenType;

		private object? _value;

		internal char _quoteChar;

		internal State _currentState;

		private JsonPosition _currentPosition;

		private CultureInfo? _culture;

		private DateTimeZoneHandling _dateTimeZoneHandling;

		private int? _maxDepth;

		private bool _hasExceededMaxDepth;

		internal DateParseHandling _dateParseHandling;

		internal FloatParseHandling _floatParseHandling;

		private string? _dateFormatString;

		private List<JsonPosition>? _stack;

		protected State CurrentState => _currentState;

		public bool CloseInput { get; set; }

		public bool SupportMultipleContent { get; set; }

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

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

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

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

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

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

		public virtual JsonToken TokenType => _tokenType;

		public virtual object? Value => _value;

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

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

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

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

		public virtual Task<bool> ReadAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<bool>() ?? Read().ToAsync();
		}

		public async Task SkipAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			if (TokenType == JsonToken.PropertyName)
			{
				await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			}
			if (JsonTokenUtils.IsStartToken(TokenType))
			{
				int depth = Depth;
				while (await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false) && depth < Depth)
				{
				}
			}
		}

		internal async Task ReaderReadAndAssertAsync(CancellationToken cancellationToken)
		{
			if (!(await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false)))
			{
				throw CreateUnexpectedEndException();
			}
		}

		public virtual Task<bool?> ReadAsBooleanAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<bool?>() ?? Task.FromResult(ReadAsBoolean());
		}

		public virtual Task<byte[]?> ReadAsBytesAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<byte[]>() ?? Task.FromResult(ReadAsBytes());
		}

		internal async Task<byte[]?> ReadArrayIntoByteArrayAsync(CancellationToken cancellationToken)
		{
			List<byte> buffer = new List<byte>();
			do
			{
				if (!(await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false)))
				{
					SetToken(JsonToken.None);
				}
			}
			while (!ReadArrayElementIntoByteArrayReportDone(buffer));
			byte[] d = buffer.ToArray();
			SetToken(JsonToken.Bytes, d, updateIndex: false);
			return d;
		}

		public virtual Task<DateTime?> ReadAsDateTimeAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<DateTime?>() ?? Task.FromResult(ReadAsDateTime());
		}

		public virtual Task<DateTimeOffset?> ReadAsDateTimeOffsetAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<DateTimeOffset?>() ?? Task.FromResult(ReadAsDateTimeOffset());
		}

		public virtual Task<decimal?> ReadAsDecimalAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<decimal?>() ?? Task.FromResult(ReadAsDecimal());
		}

		public virtual Task<double?> ReadAsDoubleAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return Task.FromResult(ReadAsDouble());
		}

		public virtual Task<int?> ReadAsInt32Async(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<int?>() ?? Task.FromResult(ReadAsInt32());
		}

		public virtual Task<string?> ReadAsStringAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			return cancellationToken.CancelIfRequestedAsync<string>() ?? Task.FromResult(ReadAsString());
		}

		internal async Task<bool> ReadAndMoveToContentAsync(CancellationToken cancellationToken)
		{
			bool flag = await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			if (flag)
			{
				flag = await MoveToContentAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			}
			return flag;
		}

		internal Task<bool> MoveToContentAsync(CancellationToken cancellationToken)
		{
			JsonToken tokenType = TokenType;
			JsonToken jsonToken = tokenType;
			if (jsonToken == JsonToken.None || jsonToken == JsonToken.Comment)
			{
				return MoveToContentFromNonContentAsync(cancellationToken);
			}
			return AsyncUtils.True;
		}

		private async Task<bool> MoveToContentFromNonContentAsync(CancellationToken cancellationToken)
		{
			JsonToken jsonToken2;
			do
			{
				if (!(await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false)))
				{
					return false;
				}
				JsonToken tokenType = TokenType;
				JsonToken jsonToken = tokenType;
				jsonToken2 = jsonToken;
			}
			while (jsonToken2 == JsonToken.None || jsonToken2 == JsonToken.Comment);
			return true;
		}

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

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

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

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

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

		public abstract bool Read();

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		public int LinePosition { get; }

		public string? Path { get; }

		public JsonReaderException()
		{
		}

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

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

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

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

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

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

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

		public int LinePosition { get; }

		public string? Path { get; }

		public JsonSerializationException()
		{
		}

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

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

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

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

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

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

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

		internal TypeNameAssemblyFormatHandling _typeNameAssemblyFormatHandling;

		internal PreserveReferencesHandling _preserveReferencesHandling;

		internal ReferenceLoopHandling _referenceLoopHandling;

		internal MissingMemberHandling _missingMemberHandling;

		internal ObjectCreationHandling _objectCreationHandling;

		internal NullValueHandling _nullValueHandling;

		internal DefaultValueHandling _defaultValueHandling;

		internal ConstructorHandling _constructorHandling;

		internal MetadataPropertyHandling _metadataPropertyHandling;

		internal JsonConverterCollection? _converters;

		internal IContractResolver _contractResolver;

		internal ITraceWriter? _traceWriter;

		internal IEqualityComparer? _equalityComparer;

		internal ISerializationBinder _serializationBinder;

		internal StreamingContext _context;

		private IReferenceResolver? _referenceResolver;

		private Formatting? _formatting;

		private DateFormatHandling? _dateFormatHandling;

		private DateTimeZoneHandling? _dateTimeZoneHandling;

		private DateParseHandling? _dateParseHandling;

		private FloatFormatHandling? _floatFormatHandling;

		private FloatParseHandling? _floatParseHandling;

		private StringEscapeHandling? _stringEscapeHandling;

		private CultureInfo _culture;

		private int? _maxDepth;

		private bool _maxDepthSet;

		private bool? _checkAdditionalContent;

		private string? _dateFormatString;

		private bool _dateFormatStringSet;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		internal const MissingMemberHandling DefaultMissingMemberHandling = MissingMemberHandling.Ignore;

		internal const NullValueHandling DefaultNullValueHandling = NullValueHandling.Include;

		internal const DefaultValueHandling DefaultDefaultValueHandling = DefaultValueHandling.Include;

		internal const ObjectCreationHandling DefaultObjectCreationHandling = ObjectCreationHandling.Auto;

		internal const PreserveReferencesHandling DefaultPreserveReferencesHandling = PreserveReferencesHandling.None;

		internal const ConstructorHandling DefaultConstructorHandling = ConstructorHandling.Default;

		internal const TypeNameHandling DefaultTypeNameHandling = TypeNameHandling.None;

		internal const MetadataPropertyHandling DefaultMetadataPropertyHandling = MetadataPropertyHandling.Default;

		internal static readonly StreamingContext DefaultContext;

		internal const Formatting DefaultFormatting = Formatting.None;

		internal const DateFormatHandling DefaultDateFormatHandling = DateFormatHandling.IsoDateFormat;

		internal const DateTimeZoneHandling DefaultDateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;

		internal const DateParseHandling DefaultDateParseHandling = DateParseHandling.DateTime;

		internal const FloatParseHandling DefaultFloatParseHandling = FloatParseHandling.Double;

		internal const FloatFormatHandling DefaultFloatFormatHandling = FloatFormatHandling.String;

		internal const StringEscapeHandling DefaultStringEscapeHandling = StringEscapeHandling.Default;

		internal const TypeNameAssemblyFormatHandling DefaultTypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple;

		internal static readonly CultureInfo DefaultCulture;

		internal const bool DefaultCheckAdditionalContent = false;

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

		internal const int DefaultMaxDepth = 64;

		internal Formatting? _formatting;

		internal DateFormatHandling? _dateFormatHandling;

		internal DateTimeZoneHandling? _dateTimeZoneHandling;

		internal DateParseHandling? _dateParseHandling;

		internal FloatFormatHandling? _floatFormatHandling;

		internal FloatParseHandling? _floatParseHandling;

		internal StringEscapeHandling? _stringEscapeHandling;

		internal CultureInfo? _culture;

		internal bool? _checkAdditionalContent;

		internal int? _maxDepth;

		internal bool _maxDepthSet;

		internal string? _dateFormatString;

		internal bool _dateFormatStringSet;

		internal TypeNameAssemblyFormatHandling? _typeNameAssemblyFormatHandling;

		internal DefaultValueHandling? _defaultValueHandling;

		internal PreserveReferencesHandling? _preserveReferencesHandling;

		internal NullValueHandling? _nullValueHandling;

		internal ObjectCreationHandling? _objectCreationHandling;

		internal MissingMemberHandling? _missingMemberHandling;

		internal ReferenceLoopHandling? _referenceLoopHandling;

		internal StreamingContext? _context;

		internal ConstructorHandling? _constructorHandling;

		internal TypeNameHandling? _typeNameHandling;

		internal MetadataPropertyHandling? _metadataPropertyHandling;

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

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

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

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

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

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

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

		public TypeNameHandling TypeName

Archipelago.MultiClient.Net.dll

Decompiled 17 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;
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(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")]
[assembly: AssemblyCompany("Jarno Westhof, Hussein Farran, Zach Parks")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyDescription("A client library for use with .NET based prog-langs for interfacing with Archipelago hosts.")]
[assembly: AssemblyFileVersion("6.7.0.0")]
[assembly: AssemblyInformationalVersion("6.7.0+c807746b6f1774cf1afe12af819acb078b55a333")]
[assembly: AssemblyProduct("Archipelago.MultiClient.Net")]
[assembly: AssemblyTitle("Archipelago.MultiClient.Net")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/ArchipelagoMW/Archipelago.MultiClient.Net")]
[assembly: AssemblyVersion("6.7.0.0")]
internal interface IConcurrentHashSet<T>
{
	bool TryAdd(T item);

	bool Contains(T item);

	void UnionWith(T[] otherSet);

	T[] ToArray();

	ReadOnlyCollection<T> AsToReadOnlyCollection();

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

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

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

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

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

		IReceivedItemsHelper Items { get; }

		ILocationCheckHelper Locations { get; }

		IPlayerHelper Players { get; }

		IDataStorageHelper DataStorage { get; }

		IConnectionInfoProvider ConnectionInfo { get; }

		IRoomStateHelper RoomState { get; }

		IMessageLogHelper MessageLog { get; }

		IHintsHelper Hints { get; }

		Task<RoomInfoPacket> ConnectAsync();

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

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

		private ConnectionInfoHelper connectionInfo;

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

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

		public IArchipelagoSocketHelper Socket { get; }

		public IReceivedItemsHelper Items { get; }

		public ILocationCheckHelper Locations { get; }

		public IPlayerHelper Players { get; }

		public IDataStorageHelper DataStorage { get; }

		public IConnectionInfoProvider ConnectionInfo => connectionInfo;

		public IRoomStateHelper RoomState { get; }

		public IMessageLogHelper MessageLog { get; }

		public IHintsHelper Hints { get; }

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

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

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

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

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

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

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

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

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

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

		void SetClientState(ArchipelagoClientState state);

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

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

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

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

		public int Team { get; }

		public int Slot { get; }

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

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

		public ConnectionRefusedError[] ErrorCodes { get; }

		public string[] Errors { get; }

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

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

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

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

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

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

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

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

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

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

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

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

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


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


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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		public byte R { get; set; }

		public byte G { get; set; }

		public byte B { get; set; }

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

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

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

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

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

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

	}
	public class DataStorageElement
	{
		internal DataStorageElementContext Context;

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

		internal DataStorageHelper.DataStorageUpdatedHandler Callbacks;

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

		private JToken cachedValue;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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


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

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

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

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

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

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

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

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

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

		public long ItemId { get; }

		public long LocationId { get; }

		public PlayerInfo Player { get; }

		public ItemFlags Flags { get; }

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

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

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

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

		public string ItemGame { get; }

		public string LocationGame { get; }

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

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

		public bool IsReceiverRelatedToActivePlayer { get; }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		public NetworkVersion()
		{
		}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		private Callback()
		{
		}

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

		internal JToken Value { get; set; }

		private AdditionalArgument()
		{
		}

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

		public long LocationId { get; set; }

		public int PlayerSlot { get; set; }

		public ItemFlags Flags { get; set; }

		public string ItemGame { get; set; }

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

		public PlayerInfo Player { get; set; }

		public string ItemName { get; set; }

		public string LocationName { get; set; }

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

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

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

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

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

		public ILocationCheckHelper Locations { get; set; }

		public IPlayerHelper PlayerHelper { get; set; }

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

		public long ItemId { get; }

		public int Player { get; }

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

		public int Player { get; }

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

		public MessagePartType Type { get; internal set; }

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

		public PaletteColor? PaletteColor { get; protected set; }

		public bool IsBackgroundColor { get; internal set; }

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

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

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

		public int SlotId { get; }

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

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

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

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

		public PlayerInfo Receiver { get; }

		public PlayerInfo Sender { get; }

		public bool IsReceiverTheActivePlayer => Receiver == ActivePlayer;

		public bool IsSenderTheActivePlayer => Sender == ActivePlayer;

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

		public ItemInfo Item { get; }

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

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

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

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

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

		public PlayerInfo Player { get; }

		public bool IsActivePlayer => Player == ActivePlayer;

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

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

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

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

		internal ArchipelagoSocketHelper(Uri hostUri)
			: base(CreateWebSocket(), 1024)
		{
			Uri = hostUri;
			SecurityProtocolType securityProtocolType = SecurityProtocolType.Tls13;
			ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | securityProtocolType;
		}

		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)
		{
			Get