Decompiled source of TCG AP Client v0.1.1

plugins/ApClient.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using ApClient;
using ApClient.data;
using ApClient.mapping;
using ApClient.patches;
using ApClientl;
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 BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using I2.Loc;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using TMPro;
using UnityEngine;
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(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: AssemblyCompany("ApClient")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+a9e83673d04db92b1b0a59e4e3c6006510262a1c")]
[assembly: AssemblyProduct("Ap Client For TCG Sim")]
[assembly: AssemblyTitle("ApClient")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ApClientl
{
	public class APGui : MonoBehaviour
	{
		public static bool showGUI = true;

		public static string ipporttext = Settings.Instance.LastUsedIP.Value;

		public static string password = Settings.Instance.LastUsedPassword.Value;

		public static string slot = Settings.Instance.LastUsedSlot.Value;

		public static string state = "Not Connected";

		private void OnGUI()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			if (showGUI)
			{
				GUI.Box(new Rect(10f, 10f, 200f, 300f), "AP Client");
				GUIStyle val = new GUIStyle();
				val.fontSize = 12;
				val.normal.textColor = Color.white;
				GUI.Label(new Rect(20f, 40f, 300f, 30f), "Address:port", val);
				ipporttext = GUI.TextField(new Rect(20f, 60f, 180f, 25f), ipporttext, 25);
				GUI.Label(new Rect(20f, 90f, 300f, 30f), "Password", val);
				password = GUI.TextField(new Rect(20f, 110f, 180f, 25f), password, 25);
				GUI.Label(new Rect(20f, 140f, 300f, 30f), "Slot", val);
				slot = GUI.TextField(new Rect(20f, 160f, 180f, 25f), slot, 25);
				if (GUI.Button(new Rect(20f, 210f, 180f, 30f), "Connect"))
				{
					Debug.Log((object)"Button Pressed!");
					Plugin.m_SessionHandler.connect(ipporttext, password, slot);
				}
				GUI.Label(new Rect(20f, 240f, 300f, 30f), state, val);
			}
		}

		private void Update()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKeyDown((KeyCode)104))
			{
				CSingleton<PriceChangeManager>.Instance.EvaluatePriceChange();
				CSingleton<PriceChangeManager>.Instance.EvaluatePriceCrash();
				CPlayerData.UpdateItemPricePercentChange();
				CPlayerData.UpdatePastCardPricePercentChange();
			}
			if (Input.GetKeyDown(Settings.Instance.MyHotkey.Value))
			{
				showGUI = !showGUI;
			}
		}
	}
}
namespace ApClient
{
	public class APClientSaveManager
	{
		private APSaveData aPSaveData;

		public APClientSaveManager()
		{
			aPSaveData = new APSaveData();
			Clear();
		}

		public void Clear()
		{
			aPSaveData.ProcessedIndex = 0;
			aPSaveData.MoneyMultiplier = 1f;
			aPSaveData.Luck = 0;
			aPSaveData.newCards = new List<int>();
			for (int i = 1; i < 122; i++)
			{
				aPSaveData.newCards.Add(i);
			}
		}

		public void setSeed(string seed)
		{
			aPSaveData.seed = seed;
		}

		public void setProcessedIndex(int index)
		{
			aPSaveData.ProcessedIndex = index;
		}

		public void IncreaseProcessedIndex()
		{
			aPSaveData.ProcessedIndex++;
		}

		public int GetProcessedIndex()
		{
			return aPSaveData.ProcessedIndex;
		}

		public void IncreaseMoneyMult()
		{
			aPSaveData.MoneyMultiplier = (aPSaveData.MoneyMultiplier += 1.025f);
		}

		public float GetMoneyMult()
		{
			return aPSaveData.MoneyMultiplier;
		}

		public int GetLuck()
		{
			return aPSaveData.Luck;
		}

		public void IncreaseLuck()
		{
			aPSaveData.Luck++;
		}

		public List<int> GetIncompleteCards()
		{
			return aPSaveData.newCards;
		}

		public void CompleteCardId(int id)
		{
			aPSaveData.newCards.Remove(id);
		}

		public void setIncompleteCards(List<int> list)
		{
			aPSaveData.newCards = list;
		}

		private string GetBaseDirectory()
		{
			return Path.GetDirectoryName(GetType().Assembly.Location);
		}

		private string getGdSavePath()
		{
			return GetBaseDirectory() + "/Saves/ApClient_" + aPSaveData.seed + ".gd";
		}

		private string getJsonSavePath()
		{
			return GetBaseDirectory() + "/Saves/ApClient_" + aPSaveData.seed + ".json";
		}

		public bool doesSaveExist()
		{
			return File.Exists(getJsonSavePath()) || File.Exists(getGdSavePath());
		}

		public void Save(int saveSlotIndex)
		{
			Directory.CreateDirectory(GetBaseDirectory() + "/Saves/");
			Plugin.Log("AP Save saveSlotIndex " + saveSlotIndex);
			CSaveLoad.m_SavedGame = CGameData.instance;
			try
			{
				string text = JsonUtility.ToJson((object)CSaveLoad.m_SavedGame);
				string text2 = JsonConvert.SerializeObject((object)aPSaveData.newCards);
				string contents = text.TrimEnd('}') + $", \"processedItems\": \"{aPSaveData.ProcessedIndex}\", \"newCardIds\": {text2} , \"maxMoney\": \"{aPSaveData.MoneyMultiplier}\", \"luck\": \"{aPSaveData.Luck}\"}}";
				File.WriteAllText(getJsonSavePath(), contents);
			}
			catch
			{
				Debug.Log((object)"Error saving JSON");
			}
		}

		public bool Load()
		{
			string gdSavePath = getGdSavePath();
			string jsonSavePath = getJsonSavePath();
			bool flag = false;
			if (File.Exists(jsonSavePath))
			{
				try
				{
					string text = File.ReadAllText(jsonSavePath);
					if (!(text == "") && text != null)
					{
						Match match = Regex.Match(text, "\"maxMoney\":\\s*\"([^\"]*)\"");
						if (match.Success)
						{
							string value = match.Groups[1].Value;
							int.TryParse(value, out var result);
							aPSaveData.MoneyMultiplier = result;
							Debug.Log((object)$"Extracted maxMoney: {result}");
						}
						text = Regex.Replace(text, ",\\s*\"maxMoney\":\\s*\"[^\"]*\"", "");
						match = Regex.Match(text, "\"luck\":\\s*\"([^\"]*)\"");
						if (match.Success)
						{
							string value2 = match.Groups[1].Value;
							int.TryParse(value2, out var result2);
							aPSaveData.Luck = result2;
							Debug.Log((object)$"Extracted luck: {result2}");
						}
						text = Regex.Replace(text, ",\\s*\"luck\":\\s*\"[^\"]*\"", "");
						Match match2 = Regex.Match(text, "\"newCardIds\"\\s*:\\s*\\{(.*?)\\}\\s*(,|})", RegexOptions.Singleline);
						if (match2.Success)
						{
							string text2 = "{" + match2.Groups[1].Value + "}";
							aPSaveData.newCards = JsonConvert.DeserializeObject<List<int>>(text2);
						}
						string text3 = Regex.Replace(text, "\"newCardIds\"\\s*:\\s*\\{(.*?)\\}\\s*(,|})", "", RegexOptions.Singleline);
						match = Regex.Match(text, "\"processedItems\":\\s*\"([^\"]*)\"");
						if (match.Success)
						{
							string value3 = match.Groups[1].Value;
							int.TryParse(value3, out var result3);
							aPSaveData.ProcessedIndex = result3;
							Debug.Log((object)$"Extracted processedItems: {result3}");
						}
						text = Regex.Replace(text, ",\\s*\"processedItems\":\\s*\"[^\"]*\"", "");
						Debug.Log((object)"Modified JSON before deserialization");
						CSaveLoad.m_SavedGame = JsonUtility.FromJson<CGameData>(text);
						return true;
					}
					flag = true;
				}
				catch
				{
					flag = true;
				}
			}
			return false;
		}
	}
	public class CoroutineRunner : MonoBehaviour
	{
		private static CoroutineRunner _instance;

		public static CoroutineRunner Instance
		{
			get
			{
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: Expected O, but got Unknown
				if ((Object)(object)_instance == (Object)null)
				{
					GameObject val = new GameObject("CoroutineRunner");
					Object.DontDestroyOnLoad((Object)(object)val);
					_instance = val.AddComponent<CoroutineRunner>();
				}
				return _instance;
			}
		}
	}
	public class ItemHandler
	{
		private Coroutine cashOnlyCoroutine;

		private float remainingTime = 0f;

		private bool timerRunning = false;

		public bool cashOnly = false;

		public void processNewItem(ItemInfo itemReceived)
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Expected O, but got Unknown
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Expected O, but got Unknown
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Expected O, but got Unknown
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Expected O, but got Unknown
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Expected O, but got Unknown
			//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Expected O, but got Unknown
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b13: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b18: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b20: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b28: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b2a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b2f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b34: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b39: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b3e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b40: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b45: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b4c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b59: Expected O, but got Unknown
			Plugin.Log(itemReceived.ItemName);
			if ((int)itemReceived.ItemId == ExpansionMapping.warehouseKey)
			{
				CSingleton<UnlockRoomManager>.Instance.SetUnlockWarehouseRoom(true);
				AchievementManager.OnShopLotBUnlocked();
				CPlayerData.m_GameReportDataCollect.upgradeCost -= 5000f;
				CPlayerData.m_GameReportDataCollectPermanent.upgradeCost -= 5000f;
				SoundManager.PlayAudio("SFX_CustomerBuy", 0.6f, 1f);
				PopupTextPatches.ShowCustomText("Warehouse Key Found");
			}
			else if ((int)itemReceived.ItemId == TrashMapping.smallMoney)
			{
				CEventManager.QueueEvent((CEvent)new CEventPlayer_AddCoin((float)(10 * Math.Min(CPlayerData.m_ShopLevel + 1, 25)), false));
			}
			else if ((int)itemReceived.ItemId == TrashMapping.mediumMoney)
			{
				CEventManager.QueueEvent((CEvent)new CEventPlayer_AddCoin((float)(20 * Math.Min(CPlayerData.m_ShopLevel + 1, 25)), false));
			}
			else if ((int)itemReceived.ItemId == TrashMapping.largeMoney)
			{
				CEventManager.QueueEvent((CEvent)new CEventPlayer_AddCoin((float)(40 * Math.Min(CPlayerData.m_ShopLevel + 1, 25)), false));
			}
			else if ((int)itemReceived.ItemId == TrashMapping.smallXp)
			{
				CEventManager.QueueEvent((CEvent)new CEventPlayer_AddShopExp(Math.Min((int)((double)CPlayerData.GetExpRequiredToLevelUp() * 0.1), (CPlayerData.m_ShopLevel + 1 > 20) ? ((int)((double)(300 * (CPlayerData.m_ShopLevel + 1)) * 0.2)) : 400), false));
			}
			else if ((int)itemReceived.ItemId == TrashMapping.mediumXp)
			{
				CEventManager.QueueEvent((CEvent)new CEventPlayer_AddShopExp(Math.Min((int)((double)CPlayerData.GetExpRequiredToLevelUp() * 0.17), (CPlayerData.m_ShopLevel + 1 > 20) ? ((int)((double)(600 * (CPlayerData.m_ShopLevel + 1)) * 0.2)) : 800), false));
			}
			else if ((int)itemReceived.ItemId == TrashMapping.largeXp)
			{
				CEventManager.QueueEvent((CEvent)new CEventPlayer_AddShopExp(Math.Min((int)((double)CPlayerData.GetExpRequiredToLevelUp() * 0.25), (CPlayerData.m_ShopLevel + 1 > 20) ? ((int)((double)(1000 * (CPlayerData.m_ShopLevel + 1)) * 0.2)) : 1500), false));
			}
			else if ((int)itemReceived.ItemId == TrashMapping.randomcard)
			{
				Array values = Enum.GetValues(typeof(ECollectionPackType));
				ECollectionPackType collectionPackType = (ECollectionPackType)values.GetValue(Random.Range(0, (Plugin.m_SessionHandler.GetSlotData().CardSanity == 0) ? 8 : Plugin.m_SessionHandler.GetSlotData().CardSanity));
				CPlayerData.AddCard(cardRoller(collectionPackType), 1);
			}
			else if ((int)itemReceived.ItemId == TrashMapping.randomNewCard)
			{
				CardData val = RandomNewCard();
				Plugin.Log($"Card is: {val.monsterType} and {val.expansionType}");
				CPlayerData.AddCard(val, 1);
			}
			else if ((int)itemReceived.ItemId == TrashMapping.ProgressiveCustomerMoney)
			{
				Plugin.m_SaveManager.IncreaseMoneyMult();
			}
			else if ((int)itemReceived.ItemId == TrashMapping.IncreaseCardLuck)
			{
				Plugin.m_SaveManager.IncreaseLuck();
			}
			else
			{
				if ((int)itemReceived.ItemId == TrashMapping.stinkTrap)
				{
					FieldInfo field = typeof(CustomerManager).GetField("m_CustomerList", BindingFlags.Instance | BindingFlags.NonPublic);
					if (field == null)
					{
						return;
					}
					List<Customer> list = (List<Customer>)field.GetValue(CSingleton<CustomerManager>.Instance);
					{
						foreach (Customer item in list)
						{
							item.SetSmelly();
						}
						return;
					}
				}
				if ((int)itemReceived.ItemId == TrashMapping.lightTrap)
				{
					((MonoBehaviour)CoroutineRunner.Instance).StartCoroutine(ToggleLightMultipleTimes());
				}
				else if ((int)itemReceived.ItemId == TrashMapping.CreditCardFailure)
				{
					remainingTime += 60f;
					if (!timerRunning)
					{
						cashOnlyCoroutine = ((MonoBehaviour)CoroutineRunner.Instance).StartCoroutine(CashOnlyTimerCoroutine());
					}
				}
				else
				{
					if ((int)itemReceived.ItemId == TrashMapping.MarketChangeTrap)
					{
						return;
					}
					if (LicenseMapping.getKeyValue((int)itemReceived.ItemId).Key != -1)
					{
						PopupTextPatches.ShowCustomText("New License Unlocked");
						KeyValuePair<int, (int, string, int, int, EItemType)> keyValue = LicenseMapping.getKeyValue((int)itemReceived.ItemId, Plugin.m_SessionHandler.itemCount((int)itemReceived.ItemId));
						RestockItemPanelUI val2 = null;
						RestockItemPanelUI[] array = Object.FindObjectsOfType<RestockItemPanelUI>();
						RestockItemPanelUI[] array2 = array;
						foreach (RestockItemPanelUI val3 in array2)
						{
							if (val3.GetIndex() == (float)keyValue.Key)
							{
								val2 = val3;
								break;
							}
						}
						if (!((Object)(object)val2 == (Object)null))
						{
							RestockItemPanelUIPatches.runLicenseBtnLogic(val2, hasItem: true, keyValue.Key);
							Plugin.Log($"Recieved Item While panel was open: {(int)itemReceived.ItemId} and {keyValue.Key}");
						}
					}
					else if ((int)itemReceived.ItemId == ExpansionMapping.progressiveA)
					{
						ExpansionShopUIScreen val4 = Object.FindObjectOfType<ExpansionShopUIScreen>();
						if ((Object)(object)val4 != (Object)null)
						{
							FieldInfo field2 = typeof(ExpansionShopUIScreen).GetField("m_IsShopB", BindingFlags.Instance | BindingFlags.NonPublic);
							if (!(bool)field2.GetValue(val4))
							{
								ExpansionShopPanelUI val5 = val4.m_ExpansionShopPanelUIList[Plugin.m_SessionHandler.itemCount((int)itemReceived.ItemId) - 1];
								val5.m_LockPurchaseBtn.gameObject.SetActive(false);
								val5.m_PurchasedBtn.gameObject.SetActive(false);
							}
						}
					}
					else if ((int)itemReceived.ItemId == ExpansionMapping.progressiveB)
					{
						ExpansionShopUIScreen val6 = Object.FindObjectOfType<ExpansionShopUIScreen>();
						if (!((Object)(object)val6 != (Object)null))
						{
							return;
						}
						FieldInfo field3 = typeof(ExpansionShopUIScreen).GetField("m_IsShopB", BindingFlags.Instance | BindingFlags.NonPublic);
						if (!(bool)field3.GetValue(val6))
						{
							return;
						}
						ExpansionShopPanelUI val7 = val6.m_ExpansionShopPanelUIList[Plugin.m_SessionHandler.itemCount((int)itemReceived.ItemId) - 1];
						FieldInfo field4 = typeof(ExpansionShopPanelUI).GetField("m_LevelRequired", BindingFlags.Instance | BindingFlags.NonPublic);
						if (!(field4 == null))
						{
							int num = (int)field4.GetValue(val7);
							if (CPlayerData.m_ShopLevel + 1 < num)
							{
								val7.m_LockPurchaseBtn.gameObject.SetActive(false);
								val7.m_PurchasedBtn.gameObject.SetActive(false);
								((Component)val7.m_LevelRequirementText).gameObject.SetActive(false);
							}
							else
							{
								((TMP_Text)val7.m_LevelRequirementText).text = $"Shop Level {val7.m_LevelRequired} Required";
							}
						}
					}
					else if (EmployeeMapping.getKeyValue((int)itemReceived.ItemId).Key != -1)
					{
						KeyValuePair<int, (int, string, int)> keyValue2 = EmployeeMapping.getKeyValue((int)itemReceived.ItemId);
						Plugin.Log($"worker recieved id: {EmployeeMapping.getKeyValue((int)itemReceived.ItemId).Key}");
						HireWorkerScreen val8 = Object.FindObjectOfType<HireWorkerScreen>();
						HireWorkerPanelUI[] array3 = Object.FindObjectsOfType<HireWorkerPanelUI>();
						HireWorkerPanelUI val9 = null;
						HireWorkerPanelUI[] array4 = array3;
						foreach (HireWorkerPanelUI val10 in array4)
						{
							FieldInfo field5 = typeof(HireWorkerPanelUI).GetField("m_Index", BindingFlags.Instance | BindingFlags.NonPublic);
							if (field5 == null)
							{
								return;
							}
							int num2 = (int)field5.GetValue(val10);
							if (num2 == keyValue2.Key)
							{
								val9 = val10;
								break;
							}
						}
						if (!((Object)(object)val9 == (Object)null))
						{
							Plugin.Log("detected Hire Worker Screen");
							Plugin.Log("Found Hire Worker Panel");
							val9.m_HiredText.SetActive(false);
							val9.m_PurchaseBtn.SetActive(true);
							Plugin.Log($"Recieved Worker While panel was open: {(int)itemReceived.ItemId}");
						}
					}
					else if (FurnatureMapping.getKeyValue((int)itemReceived.ItemId).Key != -1)
					{
						KeyValuePair<int, (int, string, int)> keyValue3 = FurnatureMapping.getKeyValue((int)itemReceived.ItemId, Plugin.m_SessionHandler.itemCount((int)itemReceived.ItemId));
						FurnitureShopPanelUI val11 = null;
						FurnitureShopPanelUI[] array5 = Object.FindObjectsOfType<FurnitureShopPanelUI>();
						FurnitureShopPanelUI[] array6 = array5;
						foreach (FurnitureShopPanelUI val12 in array6)
						{
							FieldInfo field6 = typeof(FurnitureShopPanelUI).GetField("m_Index", BindingFlags.Instance | BindingFlags.NonPublic);
							if (field6 == null)
							{
								return;
							}
							int num3 = (int)field6.GetValue(val12);
							if (num3 == keyValue3.Key)
							{
								val11 = val12;
								break;
							}
						}
						if (!((Object)(object)val11 == (Object)null))
						{
							FurnaturePatches.EnableFurnature(val11, keyValue3.Key);
						}
					}
					else
					{
						if ((int)itemReceived.ItemId != CardMapping.ghostProgressive)
						{
							return;
						}
						bool flag = false;
						int num4 = 0;
						List<bool> isCardCollectedList = CPlayerData.GetIsCardCollectedList((ECardExpansionType)2, flag);
						num4 = isCardCollectedList.FindAll((bool i) => i).Count;
						if (num4 >= 36)
						{
							flag = true;
							isCardCollectedList = CPlayerData.GetIsCardCollectedList((ECardExpansionType)2, flag);
							num4 += isCardCollectedList.FindAll((bool i) => i).Count;
						}
						if (Plugin.m_SessionHandler.GetSlotData().Goal == 2 && Plugin.m_SessionHandler.GetSlotData().GhostGoalAmount <= num4)
						{
							Plugin.m_SessionHandler.SendGoalCompletion();
							PopupTextPatches.ShowCustomText($"Congrats! You Collected {num4} Ghost Cards and Completed Your Goal!");
						}
						List<EMonsterType> shownMonsterList = InventoryBase.GetShownMonsterList((ECardExpansionType)2);
						bool isFoil = false;
						int index = 0;
						for (int m = 0; m < shownMonsterList.Count; m++)
						{
							int num5 = m * CPlayerData.GetCardAmountPerMonsterType((ECardExpansionType)2, true) + 5;
							if (isCardCollectedList[num5])
							{
								num5 += CPlayerData.GetCardAmountPerMonsterType((ECardExpansionType)2, false);
								if (!isCardCollectedList[num5])
								{
									isFoil = true;
									index = m;
									break;
								}
								continue;
							}
							index = m;
							break;
						}
						CPlayerData.AddCard(new CardData
						{
							isFoil = isFoil,
							isDestiny = flag,
							borderType = (ECardBorderType)5,
							monsterType = shownMonsterList[index],
							expansionType = (ECardExpansionType)2,
							isChampionCard = false,
							isNew = true
						}, 1);
					}
				}
			}
		}

		public CardData RandomNewCard()
		{
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b1: 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_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e9: Expected O, but got Unknown
			Plugin.Log("random new card");
			int border_sanity = 5;
			bool flag = true;
			if (Plugin.m_SessionHandler.GetSlotData().CardSanity != 0)
			{
				border_sanity = Plugin.m_SessionHandler.GetSlotData().BorderInSanity;
				flag = Plugin.m_SessionHandler.GetSlotData().FoilInSanity;
			}
			List<int> incompleteCards = Plugin.m_SaveManager.GetIncompleteCards();
			if (incompleteCards.Count == 0)
			{
				Plugin.m_SaveManager.setIncompleteCards(PlayerDataPatches.GetValidTypeIdsForSanity());
				incompleteCards = Plugin.m_SaveManager.GetIncompleteCards();
			}
			int num = incompleteCards[Random.Range(0, incompleteCards.Count)];
			int index = (num - 1) * CPlayerData.GetCardAmountPerMonsterType((ECardExpansionType)0, true);
			List<int> list = (from x in CPlayerData.GetIsCardCollectedList((ECardExpansionType)0, false).GetRange(index, flag ? 12 : 6).Select((bool val, int idx) => new { val, idx })
				where !x.val && x.idx % 6 <= border_sanity
				select x.idx).ToList();
			Plugin.Log($"border <= {border_sanity}");
			Plugin.Log(string.Join(", ", list));
			index = (num - 1) * CPlayerData.GetCardAmountPerMonsterType((ECardExpansionType)1, true);
			List<int> list2 = (from x in CPlayerData.GetIsCardCollectedList((ECardExpansionType)1, false).GetRange(index, flag ? 12 : 6).Select((bool val, int idx) => new { val, idx })
				where !x.val && x.idx % 6 <= border_sanity
				select x.idx).ToList();
			int num2 = 0;
			bool flag2 = false;
			if (list.Count > 0)
			{
				num2 = list[Random.Range(0, list.Count)];
			}
			else
			{
				if (list2.Count <= 0 || Plugin.m_SessionHandler.GetSlotData().CardSanity <= 4)
				{
					Plugin.Log($"You have collected all Cards for {(object)(EMonsterType)num}");
					Plugin.m_SaveManager.CompleteCardId(num);
					return cardRoller((ECollectionPackType)7);
				}
				num2 = list2[Random.Range(0, list2.Count)];
				flag2 = true;
				if (list2.Count == 1)
				{
					Plugin.m_SaveManager.CompleteCardId(num);
				}
			}
			ECardExpansionType val2 = (ECardExpansionType)(flag2 ? 1 : 0);
			return new CardData
			{
				isFoil = (num2 > 5),
				isDestiny = flag2,
				borderType = CPlayerData.GetCardBorderType(num2 % 6, val2),
				monsterType = (EMonsterType)num,
				expansionType = val2,
				isChampionCard = false,
				isNew = true
			};
		}

		private static CardData cardRoller(ECollectionPackType collectionPackType)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Invalid comparison between Unknown and I4
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected O, but got Unknown
			ECardExpansionType val = (ECardExpansionType)(!((double)Random.Range(0f, 1f) > 0.5));
			return new CardData
			{
				isFoil = ((double)Random.Range(0f, 1f) > 0.5),
				isDestiny = ((int)val == 1),
				borderType = (ECardBorderType)Random.Range(0, 7),
				monsterType = (EMonsterType)Random.Range(0, 122),
				expansionType = val,
				isChampionCard = false,
				isNew = true
			};
		}

		private IEnumerator ToggleLightMultipleTimes()
		{
			int repeats = Random.Range(1, 6) * 2 - 1;
			for (int i = 0; i < repeats; i++)
			{
				CSingleton<LightManager>.Instance.ToggleShopLight();
				SoundManager.PlayAudio("SFX_ButtonLightTap", 0.6f, 0.5f);
				float delay = Random.Range(0.5f, 2f);
				yield return (object)new WaitForSeconds(delay);
			}
		}

		private IEnumerator CashOnlyTimerCoroutine()
		{
			timerRunning = true;
			for (cashOnly = true; remainingTime > 0f; remainingTime -= Time.deltaTime)
			{
				yield return null;
			}
			cashOnly = false;
			timerRunning = false;
		}
	}
	[BepInPlugin("ApClient", "Ap Client For TCG Sim", "0.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Logger;

		private readonly Harmony m_Harmony = new Harmony("ApClient");

		public static APClientSaveManager m_SaveManager = new APClientSaveManager();

		public static ItemHandler m_ItemHandler = new ItemHandler();

		public static SessionHandler m_SessionHandler = new SessionHandler();

		private static bool SceneLoaded = false;

		private Plugin()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			m_Harmony.PatchAll();
		}

		private void Awake()
		{
			Logger = ((BaseUnityPlugin)this).Logger;
			Settings.Instance.Load(this);
			Logger.LogInfo((object)"Plugin ApClient is loaded!");
			SceneManager.sceneLoaded += OnSceneLoad;
		}

		private void Start()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			GameObject val = new GameObject("MyGUI");
			val.AddComponent<APGui>();
			Object.DontDestroyOnLoad((Object)(object)val);
		}

		private void OnDestroy()
		{
			m_Harmony.UnpatchSelf();
		}

		public static bool isSceneLoaded()
		{
			return SceneLoaded;
		}

		public static void onSceneLoadLogic()
		{
			SceneLoaded = true;
			m_SessionHandler.ProcessCachedItems();
		}

		public static bool OverrideTrades()
		{
			return m_SessionHandler.GetSlotData().TradesAreNew;
		}

		public static float getNumLuckItems()
		{
			Log($"Luck: {m_SaveManager.GetLuck()}");
			return m_SaveManager.GetLuck();
		}

		public static bool isCashOnly()
		{
			return m_ItemHandler.cashOnly;
		}

		public static CardData getNewCard()
		{
			return m_ItemHandler.RandomNewCard();
		}

		private void OnSceneLoad(Scene scene, LoadSceneMode mode)
		{
			Log(" Scene Load: " + ((Scene)(ref scene)).name);
			if (((Scene)(ref scene)).name == "Title")
			{
				m_SaveManager.Clear();
				setTitleInteractable(interactable: false);
				SceneLoaded = false;
			}
			if (((Scene)(ref scene)).name == "Start")
			{
				APGui.showGUI = false;
			}
		}

		public static void RunTitleInteractableSaveLogic()
		{
			TitleScreen val = Object.FindFirstObjectByType<TitleScreen>();
			GameObject val2 = GameObject.Find("NewGameBtn");
			Button val3 = null;
			if ((Object)(object)val2 != (Object)null)
			{
				val3 = val2.GetComponentInChildren<Button>();
			}
			if (m_SaveManager.doesSaveExist())
			{
				((Selectable)val.m_LoadGameButton).interactable = true;
				((Selectable)val3).interactable = false;
			}
			else
			{
				((Selectable)val.m_LoadGameButton).interactable = false;
				((Selectable)val3).interactable = true;
			}
		}

		public static void setTitleInteractable(bool interactable)
		{
			TitleScreen val = Object.FindFirstObjectByType<TitleScreen>();
			((Selectable)val.m_LoadGameButton).interactable = interactable;
			GameObject val2 = GameObject.Find("NewGameBtn");
			if ((Object)(object)val2 != (Object)null)
			{
				Button componentInChildren = val2.GetComponentInChildren<Button>();
				((Selectable)componentInChildren).interactable = interactable;
			}
		}

		public static void Log(string s)
		{
			Logger.LogInfo((object)s);
		}
	}
	public class SessionHandler
	{
		private class ItemCache
		{
			public ItemInfo info { get; set; }

			public int index { get; set; }
		}

		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static Func<string, string> <>9__13_0;

			public static Func<string, bool> <>9__13_1;

			public static Func<KeyValuePair<int, (int itemid, string name, int count, int locid, EItemType)>, int> <>9__19_0;

			public static SocketClosedHandler <>9__22_0;

			internal string <StrToList>b__13_0(string s)
			{
				return s.Trim();
			}

			internal bool <StrToList>b__13_1(string s)
			{
				int result;
				return int.TryParse(s, out result);
			}

			internal int <addStartingChecks>b__19_0(KeyValuePair<int, (int itemid, string name, int count, int locid, EItemType)> kvp)
			{
				return kvp.Value.count;
			}

			internal void <connect>b__22_0(string reason)
			{
				APGui.showGUI = true;
			}
		}

		private ArchipelagoSession session;

		private SlotData slotData = new SlotData();

		private Queue<ItemCache> cachedItems = new Queue<ItemCache>();

		private LoginResult result = null;

		private Coroutine autoSaveCoroutine;

		private float remainingTime = 0f;

		private bool timerRunning = false;

		private int startingCounter = 200;

		private DeathLinkService deathLinkService = null;

		public SlotData GetSlotData()
		{
			return slotData;
		}

		public int itemCount(long id)
		{
			return session.Items.AllItemsReceived.Where((ItemInfo i) => i.ItemId == id).Count();
		}

		public bool ControlTrades()
		{
			return slotData.TradesAreNew;
		}

		public bool hasItem(long id)
		{
			return itemCount(id) > 0;
		}

		public void SendGoalCompletion()
		{
			session.SetGoalAchieved();
		}

		public void CompleteLocationChecks(params long[] ids)
		{
			session.Locations.CompleteLocationChecks(ids);
		}

		public bool isStartingItem(int id)
		{
			return id == Plugin.m_SessionHandler.GetSlotData().pg1IndexMapping[0] || id == Plugin.m_SessionHandler.GetSlotData().pg2IndexMapping[0] || id == Plugin.m_SessionHandler.GetSlotData().pg3IndexMapping[0];
		}

		public int[] startingids()
		{
			return new int[3]
			{
				Plugin.m_SessionHandler.GetSlotData().pg1IndexMapping[0],
				Plugin.m_SessionHandler.GetSlotData().pg2IndexMapping[0],
				Plugin.m_SessionHandler.GetSlotData().pg3IndexMapping[0]
			};
		}

		private List<int> StrToList(string str)
		{
			int num;
			return (from s in str.Trim('[', ']').Split(',')
				select s.Trim() into s
				where int.TryParse(s, out num)
				select s).Select(int.Parse).ToList();
		}

		private IEnumerator AutoSaveTimerCoroutine()
		{
			for (timerRunning = true; remainingTime > 0f; remainingTime -= Time.deltaTime)
			{
				yield return null;
			}
			timerRunning = false;
		}

		private void addStartingChecks(List<int> mapping, int startingId)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			(int, string, int, int, EItemType) valueOrEmpty = LicenseMapping.getValueOrEmpty(mapping[0]);
			for (int i = 0; i < 8; i++)
			{
				int num = LicenseMapping.GetKeyValueFromType(valueOrEmpty.Item5).Min((KeyValuePair<int, (int itemid, string name, int count, int locid, EItemType)> kvp) => kvp.Value.count);
				LicenseMapping.mapping.Add(startingCounter + i, (-1, "Unknown", (i + 3) * num, startingId + i, valueOrEmpty.Item5));
			}
			startingCounter += 8;
			Plugin.Log($"Goal Amount for {valueOrEmpty.Item2} is {LicenseMapping.GetKeyValueFromType(valueOrEmpty.Item5).Count()}");
		}

		public void sendDeath()
		{
		}

		public void connect(string ip, string password, string slot)
		{
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Expected O, but got Unknown
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Expected O, but got Unknown
			APGui.state = "Connecting";
			session = ArchipelagoSessionFactory.CreateSession(ip, 38281);
			IArchipelagoSocketHelper socket = session.Socket;
			object obj = <>c.<>9__22_0;
			if (obj == null)
			{
				SocketClosedHandler val = delegate
				{
					APGui.showGUI = true;
				};
				<>c.<>9__22_0 = val;
				obj = (object)val;
			}
			socket.SocketClosed += (SocketClosedHandler)obj;
			session.Items.ItemReceived += (ItemReceivedHandler)delegate(ReceivedItemsHelper receivedItemsHelper)
			{
				if (!Plugin.isSceneLoaded())
				{
					Plugin.Log("Not In Scene");
					cachedItems.Enqueue(new ItemCache
					{
						info = receivedItemsHelper.DequeueItem(),
						index = receivedItemsHelper.Index
					});
				}
				else
				{
					Plugin.Log($"{receivedItemsHelper.Index} : {Plugin.m_SaveManager.GetProcessedIndex()}");
					if (Plugin.m_SaveManager.GetProcessedIndex() <= receivedItemsHelper.Index)
					{
						Plugin.m_SaveManager.IncreaseProcessedIndex();
						ItemInfo itemReceived = receivedItemsHelper.DequeueItem();
						Plugin.m_ItemHandler.processNewItem(itemReceived);
						if (receivedItemsHelper.Index % 25 == 0 && !timerRunning)
						{
							CSingleton<CGameManager>.Instance.SaveGameData(3);
							remainingTime += 60f;
							if (!timerRunning)
							{
								autoSaveCoroutine = ((MonoBehaviour)CoroutineRunner.Instance).StartCoroutine(AutoSaveTimerCoroutine());
							}
						}
					}
				}
			};
			try
			{
				result = session.TryConnectAndLogin("TCG Card Shop Simulator", slot, (ItemsHandlingFlags)7, (Version)null, (string[])null, (string)null, password, true);
			}
			catch (Exception ex)
			{
				APGui.state = "Connection Failed";
				result = (LoginResult)new LoginFailure(ex.GetBaseException().Message);
				Plugin.Log(ex.GetBaseException().Message);
			}
			if (result.Successful)
			{
				Plugin.m_SaveManager.setSeed(session.RoomState.Seed);
				LoginSuccessful val2 = (LoginSuccessful)result;
				string text = val2.SlotData.GetValueOrDefault("ModVersion").ToString();
				if (!text.Equals("0.1.0"))
				{
					APGui.state = "AP Expects Mod v" + text;
				}
				else
				{
					APGui.state = "Connected";
					Plugin.RunTitleInteractableSaveLogic();
				}
				slotData.CardSanity = int.Parse(val2.SlotData.GetValueOrDefault("CardSanity").ToString());
				slotData.Goal = int.Parse(val2.SlotData.GetValueOrDefault("Goal").ToString());
				slotData.ShopExpansionGoal = int.Parse(val2.SlotData.GetValueOrDefault("ShopExpansionGoal").ToString());
				slotData.ShopExpansionGoal = int.Parse(val2.SlotData.GetValueOrDefault("ShopExpansionGoal").ToString());
				slotData.LevelGoal = int.Parse(val2.SlotData.GetValueOrDefault("LevelGoal").ToString());
				slotData.GhostGoalAmount = int.Parse(val2.SlotData.GetValueOrDefault("GhostGoalAmount").ToString());
				slotData.TradesAreNew = val2.SlotData.GetValueOrDefault("BetterTrades").ToString() == "1";
				slotData.FoilInSanity = val2.SlotData.GetValueOrDefault("FoilInSanity").ToString() == "1";
				slotData.BorderInSanity = int.Parse(val2.SlotData.GetValueOrDefault("BorderInSanity").ToString());
				slotData.SellCheckAmount = int.Parse(val2.SlotData.GetValueOrDefault("SellCheckAmount").ToString());
				slotData.pg1IndexMapping = StrToList(val2.SlotData.GetValueOrDefault("ShopPg1Mapping").ToString());
				Plugin.Log(string.Join(", ", slotData.pg1IndexMapping));
				slotData.pg2IndexMapping = StrToList(val2.SlotData.GetValueOrDefault("ShopPg2Mapping").ToString());
				Plugin.Log(string.Join(", ", slotData.pg2IndexMapping));
				slotData.pg3IndexMapping = StrToList(val2.SlotData.GetValueOrDefault("ShopPg3Mapping").ToString());
				Plugin.Log(string.Join(", ", slotData.pg3IndexMapping));
				slotData.ttIndexMapping = StrToList(val2.SlotData.GetValueOrDefault("ShopTTMapping").ToString());
				Plugin.Log(string.Join(", ", slotData.ttIndexMapping));
				addStartingChecks(slotData.pg1IndexMapping, LicenseMapping.locs1Starting);
				Plugin.Log($"Mapping is {slotData.pg2IndexMapping.Count}");
				addStartingChecks(slotData.pg2IndexMapping, LicenseMapping.locs2Starting);
				addStartingChecks(slotData.pg3IndexMapping, LicenseMapping.locs3Starting);
				Settings.Instance.SaveNewConnectionInfo(ip, password, slot);
			}
		}

		public void ProcessCachedItems()
		{
			CPlayerData.SetUnlockItemLicense(slotData.pg1IndexMapping[0]);
			CPlayerData.SetUnlockItemLicense(slotData.pg2IndexMapping[0]);
			CPlayerData.SetUnlockItemLicense(slotData.pg3IndexMapping[0]);
			while (cachedItems.Any())
			{
				ItemCache itemCache = cachedItems.Dequeue();
				Plugin.Log($"{Plugin.m_SaveManager.GetProcessedIndex()} : {itemCache.index}");
				if (Plugin.m_SaveManager.GetProcessedIndex() > itemCache.index)
				{
					return;
				}
				Plugin.m_SaveManager.IncreaseProcessedIndex();
				Plugin.Log("Item on load " + itemCache.info.ItemName);
				Plugin.m_ItemHandler.processNewItem(itemCache.info);
			}
			cachedItems.Clear();
		}
	}
	public class Settings
	{
		private static Settings m_instance;

		private Plugin plugin;

		public ConfigEntry<int> StartingMoney;

		public ConfigEntry<int> XpMultiplier;

		public ConfigEntry<KeyCode> MyHotkey;

		public ConfigEntry<string> LastUsedIP;

		public ConfigEntry<string> LastUsedPassword;

		public ConfigEntry<string> LastUsedSlot;

		public static Settings Instance
		{
			get
			{
				if (m_instance == null)
				{
					m_instance = new Settings();
				}
				return m_instance;
			}
		}

		public void Load(Plugin plugin)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			this.plugin = plugin;
			StartingMoney = ((BaseUnityPlugin)plugin).Config.Bind<int>("1. GamePlay", "Starting Money", 1000, new ConfigDescription("The Amount of Money you Start With", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, int.MaxValue), Array.Empty<object>()));
			MyHotkey = ((BaseUnityPlugin)plugin).Config.Bind<KeyCode>("2. Hotkeys", "Toggle Connection Window", (KeyCode)289, "Press this key to op AP Connection GUI");
			LastUsedIP = ((BaseUnityPlugin)plugin).Config.Bind<string>("Connection", "LastUsedIP", "", "The last server IP entered.");
			LastUsedPassword = ((BaseUnityPlugin)plugin).Config.Bind<string>("Connection", "LastUsedPassword", "", "The last server password entered.");
			LastUsedSlot = ((BaseUnityPlugin)plugin).Config.Bind<string>("Connection", "LastUsedSlot", "", "The last player slot name entered.");
		}

		public void SaveNewConnectionInfo(string ip, string password, string slot)
		{
			LastUsedIP.Value = ip;
			LastUsedPassword.Value = password;
			LastUsedSlot.Value = slot;
			((BaseUnityPlugin)plugin).Config.Save();
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "ApClient";

		public const string PLUGIN_NAME = "Ap Client For TCG Sim";

		public const string PLUGIN_VERSION = "0.1.0";
	}
}
namespace ApClient.patches
{
	public class BillPatches
	{
		[HarmonyPatch(typeof(RentBillScreen))]
		public class NewDay
		{
			[HarmonyPatch("EvaluateNewDayBill")]
			[HarmonyPostfix]
			private static void PostFix(RentBillScreen __instance)
			{
				BillData bill = CPlayerData.GetBill((EBillType)1);
				BillData bill2 = CPlayerData.GetBill((EBillType)2);
				BillData bill3 = CPlayerData.GetBill((EBillType)3);
				bool flag = false;
				if (bill != null && __instance.m_DueDayMax - CPlayerData.GetBill((EBillType)1).billDayPassed <= 0)
				{
					flag = true;
				}
				if (bill2 != null && __instance.m_DueDayMax - CPlayerData.GetBill((EBillType)2).billDayPassed <= 0)
				{
					flag = true;
				}
				if (bill3 != null && __instance.m_DueDayMax - CPlayerData.GetBill((EBillType)3).billDayPassed <= 0)
				{
					flag = true;
				}
				if (flag)
				{
					Plugin.m_SessionHandler.sendDeath();
				}
			}
		}
	}
	public class CardOpeningPatches
	{
		[HarmonyPatch(typeof(CardOpeningSequence), "GetPackContent")]
		private class Patch_TargetMethod
		{
			private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
			{
				//IL_0146: Unknown result type (might be due to invalid IL or missing references)
				//IL_014c: Expected O, but got Unknown
				//IL_0154: Unknown result type (might be due to invalid IL or missing references)
				//IL_015a: Expected O, but got Unknown
				//IL_0168: Unknown result type (might be due to invalid IL or missing references)
				//IL_016e: Expected O, but got Unknown
				//IL_0176: Unknown result type (might be due to invalid IL or missing references)
				//IL_017c: Expected O, but got Unknown
				//IL_0184: Unknown result type (might be due to invalid IL or missing references)
				//IL_018a: Expected O, but got Unknown
				//IL_0193: Unknown result type (might be due to invalid IL or missing references)
				//IL_0199: Expected O, but got Unknown
				List<CodeInstruction> list = new List<CodeInstruction>(instructions);
				Dictionary<float, float> dictionary = new Dictionary<float, float>
				{
					{ 5f, 0.5f },
					{ 20f, 0.25f },
					{ 8f, 0.2f },
					{ 4f, 0.1f },
					{ 1f, 0.05f },
					{ 0.25f, 0.05f }
				};
				HashSet<float> hashSet = new HashSet<float>();
				MethodInfo methodInfo = AccessTools.Method(typeof(Plugin), "getNumLuckItems", (Type[])null, (Type[])null);
				for (int i = 0; i < list.Count - 1; i++)
				{
					CodeInstruction val = list[i];
					if (val.opcode == OpCodes.Ldc_R4 && dictionary.TryGetValue((float)val.operand, out var value))
					{
						float item = (float)val.operand;
						if (!hashSet.Contains(item) && list[i + 1].opcode.Name.StartsWith("stloc"))
						{
							object operand = list[i + 1].operand;
							list.InsertRange(i + 2, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[6]
							{
								new CodeInstruction(OpCodes.Ldloc, operand),
								new CodeInstruction(OpCodes.Call, (object)methodInfo),
								new CodeInstruction(OpCodes.Ldc_R4, (object)value),
								new CodeInstruction(OpCodes.Mul, (object)null),
								new CodeInstruction(OpCodes.Add, (object)null),
								new CodeInstruction(OpCodes.Stloc, operand)
							});
							hashSet.Add(item);
							i += 6;
						}
					}
				}
				return list;
			}
		}
	}
	public class CustomerPatches
	{
		[HarmonyPatch(typeof(Customer), "EvaluateFinishScanItem")]
		public static class FinishScan
		{
			[HarmonyPostfix]
			public static void Postfix(Customer __instance)
			{
				if (Plugin.isCashOnly())
				{
					__instance.m_CustomerCash.SetIsCard(false);
					CSingleton<CustomerManager>.Instance.ResetCustomerExactChangeChance();
					__instance.m_CurrentQueueCashierCounter.SetCustomerPaidAmount(false, __instance.GetRandomPayAmount(__instance.m_TotalScannedItemCost));
				}
			}
		}

		[HarmonyPatch(typeof(Customer), "OnItemScanned")]
		public static class OnScan
		{
			[HarmonyPostfix]
			public static void Postfix(Item item)
			{
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_001f: Expected I4, but got Unknown
				//IL_0047: Unknown result type (might be due to invalid IL or missing references)
				//IL_0051: Expected I4, but got Unknown
				//IL_0067: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
				CPlayerData.m_StockSoldList[(int)item.GetItemType()]++;
				Plugin.Log($"{item} has sold {CPlayerData.m_StockSoldList[(int)item.GetItemType()]} times");
				IEnumerable<KeyValuePair<int, (int, string, int, int, EItemType)>> enumerable = from i in LicenseMapping.GetKeyValueFromType(item.GetItemType())
					where i.Value.count <= CPlayerData.m_StockSoldList[(int)item.GetItemType()]
					select i;
				foreach (KeyValuePair<int, (int, string, int, int, EItemType)> item2 in enumerable)
				{
					Plugin.Log($"{item.GetItemType()} has {enumerable.Count()} goals left");
					Plugin.m_SessionHandler.CompleteLocationChecks(item2.Value.Item4);
				}
			}
		}

		[HarmonyPatch(typeof(Customer), "ActivateCustomer")]
		public static class Activate
		{
			[HarmonyPostfix]
			public static void Postfix(Customer __instance, bool canSpawnSmelly)
			{
				float maxMoney = __instance.m_MaxMoney;
				__instance.m_MaxMoney *= Plugin.m_SaveManager.GetMoneyMult();
				Plugin.Log($"Customer spawned with {__instance.m_MaxMoney} instead of {maxMoney}");
			}
		}

		[HarmonyPatch(typeof(CustomerTradeCardScreen), "SetCustomer")]
		public static class CustomerTradeScreen_SetCustomer_Transpiler
		{
			private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator il)
			{
				FieldInfo field_CardDataL = AccessTools.Field(typeof(CustomerTradeCardScreen), "m_CardData_L");
				MethodInfo originalGetCardData = AccessTools.Method(typeof(CPlayerData), "GetCardData", new Type[3]
				{
					typeof(int),
					typeof(ECardExpansionType),
					typeof(bool)
				}, (Type[])null);
				MethodInfo myCustomMethod = AccessTools.Method(typeof(Plugin), "getNewCard", (Type[])null, (Type[])null);
				MethodInfo controlTradesMethod = AccessTools.Method(typeof(Plugin), "OverrideTrades", (Type[])null, (Type[])null);
				List<CodeInstruction> codes = new List<CodeInstruction>(instructions);
				Label skipCustom = il.DefineLabel();
				Label endIf = il.DefineLabel();
				bool patchApplied = false;
				for (int i = 0; i < codes.Count; i++)
				{
					CodeInstruction code = codes[i];
					int num;
					if (!patchApplied && code.opcode == OpCodes.Call)
					{
						object operand = code.operand;
						if (operand is MethodInfo mi)
						{
							num = ((mi == originalGetCardData) ? 1 : 0);
							goto IL_0193;
						}
					}
					num = 0;
					goto IL_0193;
					IL_0193:
					if (num != 0)
					{
						List<CodeInstruction> newInstructions = new List<CodeInstruction>
						{
							new CodeInstruction(OpCodes.Ldarg_2, (object)null),
							new CodeInstruction(OpCodes.Ldnull, (object)null),
							new CodeInstruction(OpCodes.Ceq, (object)null),
							new CodeInstruction(OpCodes.Brfalse_S, (object)skipCustom),
							new CodeInstruction(OpCodes.Call, (object)controlTradesMethod),
							new CodeInstruction(OpCodes.Ldc_I4_0, (object)null),
							new CodeInstruction(OpCodes.Ceq, (object)null),
							new CodeInstruction(OpCodes.Brtrue_S, (object)skipCustom),
							new CodeInstruction(OpCodes.Pop, (object)null),
							new CodeInstruction(OpCodes.Pop, (object)null),
							new CodeInstruction(OpCodes.Pop, (object)null),
							new CodeInstruction(OpCodes.Call, (object)myCustomMethod),
							new CodeInstruction(OpCodes.Br_S, (object)endIf)
						};
						CodeInstruction labelOriginal = new CodeInstruction(OpCodes.Nop, (object)null)
						{
							labels = new List<Label> { skipCustom }
						};
						newInstructions.Add(labelOriginal);
						foreach (CodeInstruction item in newInstructions)
						{
							yield return item;
						}
						yield return code;
						patchApplied = true;
						continue;
					}
					int num2;
					if (patchApplied && code.opcode == OpCodes.Stfld)
					{
						object operand = code.operand;
						if (operand is FieldInfo field)
						{
							num2 = ((field == field_CardDataL) ? 1 : 0);
							goto IL_042c;
						}
					}
					num2 = 0;
					goto IL_042c;
					IL_042c:
					if (num2 != 0)
					{
						code.labels.Add(endIf);
						yield return code;
						patchApplied = false;
					}
					else
					{
						yield return code;
					}
				}
			}
		}
	}
	public class EmployeePatches
	{
		[HarmonyPatch(typeof(HireWorkerPanelUI), "Init")]
		public class Init
		{
			private static void Postfix(HireWorkerPanelUI __instance, HireWorkerScreen hireWorkerScreen, int index)
			{
				Plugin.Log($"Employee Index: {index}");
				(int, string, int) valueOrDefault = EmployeeMapping.mapping.GetValueOrDefault(index, (-1, "", -1));
				((TMP_Text)__instance.m_LevelRequirementText).text = "Requires AP Worker Unlock";
				if (valueOrDefault.Item3 != -1 && Plugin.m_SessionHandler.hasItem(valueOrDefault.Item1))
				{
					((Component)__instance.m_LevelRequirementText).gameObject.SetActive(false);
					((Component)__instance.m_HireFeeText).gameObject.SetActive(true);
					__instance.m_LockPurchaseBtn.SetActive(false);
				}
				else
				{
					((Component)__instance.m_LevelRequirementText).gameObject.SetActive(true);
					((Component)__instance.m_HireFeeText).gameObject.SetActive(false);
					__instance.m_LockPurchaseBtn.gameObject.SetActive(true);
				}
			}
		}

		[HarmonyPatch(typeof(HireWorkerPanelUI), "OnPressHireButton")]
		public class OnClick
		{
			private static bool Prefix(HireWorkerPanelUI __instance)
			{
				FieldInfo field = typeof(HireWorkerPanelUI).GetField("m_Index", BindingFlags.Instance | BindingFlags.NonPublic);
				if (field == null)
				{
					return false;
				}
				int num = (int)field.GetValue(__instance);
				(int, string, int) valueOrDefault = EmployeeMapping.mapping.GetValueOrDefault(num, (-1, "", -1));
				Plugin.Log($"at employee hire {valueOrDefault.Item2} {valueOrDefault.Item1} {valueOrDefault.Item3 != -1 && Plugin.m_SessionHandler.hasItem(valueOrDefault.Item1)}");
				if (valueOrDefault.Item3 != -1 && Plugin.m_SessionHandler.hasItem(valueOrDefault.Item1))
				{
					HireEmployee(__instance, num);
				}
				return true;
			}
		}

		public static void HireEmployee(HireWorkerPanelUI __instance, int index)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			if (CPlayerData.GetIsWorkerHired(index))
			{
				return;
			}
			FieldInfo field = typeof(HireWorkerPanelUI).GetField("m_TotalHireFee", BindingFlags.Instance | BindingFlags.NonPublic);
			if (field == null)
			{
				return;
			}
			float num = (float)field.GetValue(__instance);
			CEventManager.QueueEvent((CEvent)new CEventPlayer_ReduceCoin(num, false));
			CPlayerData.SetIsWorkerHired(index, true);
			CSingleton<WorkerManager>.Instance.ActivateWorker(index, true);
			CPlayerData.m_GameReportDataCollect.employeeCost -= num;
			CPlayerData.m_GameReportDataCollectPermanent.employeeCost -= num;
			int num2 = 0;
			for (int i = 0; i < CPlayerData.m_IsWorkerHired.Count; i++)
			{
				if (CPlayerData.m_IsWorkerHired[i])
				{
					num2++;
				}
			}
			FieldInfo field2 = typeof(HireWorkerPanelUI).GetField("m_IsHired", BindingFlags.Instance | BindingFlags.NonPublic);
			if (!(field2 == null))
			{
				AchievementManager.OnStaffHired(num2);
				SoundManager.PlayAudio("SFX_CustomerBuy", 0.6f, 1f);
				field2.SetValue(__instance, CPlayerData.GetIsWorkerHired(index));
				if (CPlayerData.GetIsWorkerHired(index))
				{
					__instance.m_HiredText.SetActive(true);
					__instance.m_PurchaseBtn.SetActive(false);
					((Component)__instance.m_HireFeeText).gameObject.SetActive(false);
				}
				else
				{
					__instance.m_HiredText.SetActive(false);
					__instance.m_PurchaseBtn.SetActive(true);
				}
			}
		}
	}
	public class ExpansionShopPatches
	{
		[HarmonyPatch(typeof(ExpansionShopPanelUI), "Init")]
		public class Init
		{
			[HarmonyPostfix]
			private static void Postfix(ExpansionShopPanelUI __instance, ExpansionShopUIScreen expansionShopUIScreen, int index, bool isShopB)
			{
				FieldInfo field = typeof(ExpansionShopPanelUI).GetField("m_LevelRequired", BindingFlags.Instance | BindingFlags.NonPublic);
				if (!(field == null))
				{
					int num = (int)field.GetValue(__instance);
					bool flag = false;
					flag = ((!isShopB) ? (Plugin.m_SessionHandler.itemCount(ExpansionMapping.progressiveA) > index) : (Plugin.m_SessionHandler.itemCount(ExpansionMapping.progressiveB) > index));
					bool flag2 = CPlayerData.m_ShopLevel + 1 >= num;
					if (!flag && flag2)
					{
						((Component)__instance.m_LevelRequirementText).gameObject.SetActive(true);
						((TMP_Text)__instance.m_LevelRequirementText).text = "Needs Progressive Shop Expansion " + (isShopB ? "B" : "A");
					}
					else if (!flag)
					{
						((TMP_Text)__instance.m_LevelRequirementText).text = ((TMP_Text)__instance.m_LevelRequirementText).text + " and AP Progressive " + (isShopB ? "B" : "A");
					}
					if (isShopB && CPlayerData.m_UnlockWarehouseRoomCount > index)
					{
						__instance.m_LockPurchaseBtn.gameObject.SetActive(false);
						__instance.m_PurchasedBtn.gameObject.SetActive(true);
					}
					else if (!isShopB && CPlayerData.m_UnlockRoomCount > index)
					{
						__instance.m_LockPurchaseBtn.gameObject.SetActive(false);
						__instance.m_PurchasedBtn.gameObject.SetActive(true);
					}
					else if (flag && flag2)
					{
						__instance.m_LockPurchaseBtn.gameObject.SetActive(false);
						__instance.m_PurchasedBtn.gameObject.SetActive(false);
					}
					else
					{
						__instance.m_LockPurchaseBtn.gameObject.SetActive(true);
						__instance.m_PurchasedBtn.gameObject.SetActive(false);
					}
				}
			}
		}

		[HarmonyPatch(typeof(ExpansionShopPanelUI), "OnPressButton")]
		public class OnClick
		{
			private static bool Prefix(ExpansionShopPanelUI __instance)
			{
				FieldInfo field = typeof(ExpansionShopPanelUI).GetField("m_Index", BindingFlags.Instance | BindingFlags.NonPublic);
				int num = (int)field.GetValue(__instance);
				FieldInfo field2 = typeof(ExpansionShopPanelUI).GetField("m_LevelRequired", BindingFlags.Instance | BindingFlags.NonPublic);
				int num2 = (int)field2.GetValue(__instance);
				FieldInfo fieldInfo = AccessTools.Field(typeof(ExpansionShopPanelUI), "m_IsShopB");
				bool flag = (bool)fieldInfo.GetValue(__instance);
				bool flag2 = false;
				flag2 = ((!flag) ? (Plugin.m_SessionHandler.itemCount(ExpansionMapping.progressiveA) > num) : (Plugin.m_SessionHandler.itemCount(ExpansionMapping.progressiveB) > num));
				bool flag3 = CPlayerData.m_ShopLevel + 1 >= num2;
				if (flag2 && flag3)
				{
					return true;
				}
				return false;
			}
		}

		[HarmonyPatch]
		private class CreateData
		{
			private static MethodBase TargetMethod()
			{
				return AccessTools.Method(typeof(ExpansionShopUIScreen), "EvaluateCartCheckout", (Type[])null, (Type[])null);
			}

			[HarmonyPrefix]
			public static void Prefix(float totalCost, int index, bool isShopB)
			{
				Plugin.m_SessionHandler.CompleteLocationChecks(ExpansionMapping.locstartval + index + (isShopB ? 30 : 0));
				if (!isShopB && Plugin.m_SessionHandler.GetSlotData().Goal == 0 && index + 1 >= Plugin.m_SessionHandler.GetSlotData().ShopExpansionGoal)
				{
					Plugin.m_SessionHandler.SendGoalCompletion();
					PopupTextPatches.ShowCustomText("Congrats! Your Shop Has Expanded To Your Goal!");
				}
				Plugin.Log("Prefix executed on EvaluateCartCheckout for Expansion");
			}
		}

		[HarmonyPatch]
		private class PanelUI
		{
			private static MethodBase TargetMethod()
			{
				return AccessTools.Method(typeof(ExpansionShopUIScreen), "EvaluateShopPanelUI", (Type[])null, (Type[])null);
			}

			[HarmonyPostfix]
			public static void Postfix(ExpansionShopUIScreen __instance)
			{
				if (__instance.m_IsShopB && !CPlayerData.m_IsWarehouseRoomUnlocked)
				{
					((Behaviour)__instance.m_ShopB_LevelRequirementText).enabled = true;
					((TMP_Text)__instance.m_ShopB_LevelRequirementText).text = "Needs AP Warehouse Key";
					__instance.m_ShopB_LockPurchaseBtn.SetActive(true);
				}
			}
		}
	}
	public class FurnaturePatches
	{
		[HarmonyPatch(typeof(FurnitureShopPanelUI), "Init")]
		public class Init
		{
			[HarmonyPrefix]
			private static void Prefix(FurnitureShopPanelUI __instance, FurnitureShopUIScreen furnitureShopUIScreen, int index)
			{
				__instance.m_Index = FurnatureMapping.reorder[index];
			}

			[HarmonyPostfix]
			private static void Postfix(FurnitureShopPanelUI __instance, FurnitureShopUIScreen furnitureShopUIScreen, int index)
			{
				if (index != 0)
				{
					(int, string, int) valueOrEmpty = FurnatureMapping.getValueOrEmpty(__instance.m_Index);
					if (valueOrEmpty.Item1 == -1)
					{
						Plugin.Log($"Failed to find index: {__instance.m_Index}");
						return;
					}
					bool hasItem = Plugin.m_SessionHandler.itemCount(valueOrEmpty.Item1) >= valueOrEmpty.Item3;
					runFurnatureBtnLogic(__instance, hasItem, __instance.m_Index);
				}
			}
		}

		[HarmonyPatch(typeof(FurnitureShopPanelUI), "OnPressButton")]
		public class OnClick
		{
			private static bool Prefix(FurnitureShopPanelUI __instance)
			{
				FieldInfo field = typeof(FurnitureShopPanelUI).GetField("m_Index", BindingFlags.Instance | BindingFlags.NonPublic);
				if (field == null)
				{
					return false;
				}
				int num = (int)field.GetValue(__instance);
				if (((TMP_Text)__instance.m_LevelRequirementText).text.Equals("License Locked by AP"))
				{
					return false;
				}
				return true;
			}
		}

		public static void runFurnatureBtnLogic(FurnitureShopPanelUI __instance, bool hasItem, int index)
		{
			if (!hasItem)
			{
				((TMP_Text)__instance.m_LevelRequirementText).text = "License Locked by AP";
				((Component)__instance.m_LevelRequirementText).gameObject.SetActive(true);
				__instance.m_CompanyTitle.gameObject.SetActive(false);
				__instance.m_LockPurchaseBtn.gameObject.SetActive(true);
			}
			else
			{
				EnableFurnature(__instance, index);
				((TMP_Text)__instance.m_LevelRequirementText).text = "";
			}
		}

		public static void EnableFurnature(FurnitureShopPanelUI __instance, int index)
		{
			FieldInfo field = typeof(FurnitureShopPanelUI).GetField("m_LevelRequired", BindingFlags.Instance | BindingFlags.NonPublic);
			if (!(field == null))
			{
				int num = (int)field.GetValue(__instance);
				field.SetValue(__instance, 1);
				((Component)__instance.m_LevelRequirementText).gameObject.SetActive(false);
				__instance.m_CompanyTitle.gameObject.SetActive(true);
				__instance.m_LockPurchaseBtn.gameObject.SetActive(false);
			}
		}
	}
	[HarmonyPatch(typeof(CGameManager))]
	public class CGameManagerPatches
	{
		[HarmonyPatch("LoadData")]
		[HarmonyPostfix]
		private static void PostFix()
		{
			CPlayerData.m_TutorialIndex = 16;
			if (CPlayerData.PlayerName != "My Card Shop" || CPlayerData.m_TutorialIndex > 0)
			{
				CSingleton<TutorialManager>.Instance.m_TutorialTargetIndicator.SetActive(false);
				((Component)CSingleton<TutorialManager>.Instance).gameObject.SetActive(false);
				CPlayerData.m_HasFinishedTutorial = true;
			}
			Plugin.Log("Processing cache Items");
			Plugin.onSceneLoadLogic();
		}
	}
	public class OpenCloseSignPatches
	{
		[HarmonyPatch(typeof(InteractableOpenCloseSign))]
		public class OverrideTutorialCheck
		{
			[HarmonyPatch("OnMouseButtonUp")]
			[HarmonyPrefix]
			private static bool Prefix(InteractableOpenCloseSign __instance)
			{
				if (!__instance.m_IsSwapping)
				{
					CPlayerData.m_IsShopOpen = !CPlayerData.m_IsShopOpen;
					if (!CPlayerData.m_IsShopOnceOpen && CPlayerData.m_IsShopOpen)
					{
						CPlayerData.m_IsShopOnceOpen = true;
					}
					__instance.m_IsSwapping = true;
					__instance.m_Anim.Play();
					((MonoBehaviour)__instance).StartCoroutine(__instance.DelaySwapMesh());
					SoundManager.GenericPop(1f, 1f);
				}
				return false;
			}
		}
	}
	[HarmonyPatch(typeof(PauseScreen))]
	public class PauseScreenPatches
	{
		[HarmonyPatch("OpenSaveGameSlotScreen")]
		[HarmonyPrefix]
		private static bool SavePrefix()
		{
			Plugin.Log("Start Saving");
			CSingleton<CGameManager>.Instance.m_CurrentSaveLoadSlotSelectedIndex = 3;
			CSingleton<CGameManager>.Instance.m_IsManualSaveLoad = true;
			CSingleton<ShelfManager>.Instance.SaveInteractableObjectData(false);
			CSingleton<CGameManager>.Instance.SaveGameData(3);
			SaveLoadGameSlotSelectScreen val = Object.FindObjectOfType<SaveLoadGameSlotSelectScreen>();
			if ((Object)(object)val != (Object)null)
			{
				Plugin.Log("Screen Saving");
				val.m_SavingGameScreen.SetActive(true);
				((MonoBehaviour)CSingleton<SaveLoadGameSlotSelectScreen>.Instance).StartCoroutine(DelaySavingGame(val));
			}
			return true;
		}

		private static IEnumerator DelaySavingGame(SaveLoadGameSlotSelectScreen saveScreen)
		{
			Plugin.Log("Delay Saving");
			yield return (object)new WaitForSecondsRealtime(2f);
			saveScreen.m_SavingGameScreen.SetActive(false);
			((Component)saveScreen).gameObject.SetActive(false);
		}
	}
	internal class PlayerDataPatches
	{
		[HarmonyPatch]
		private class CreateData
		{
			private static MethodBase TargetMethod()
			{
				return AccessTools.Method(typeof(CPlayerData), "CreateDefaultData", (Type[])null, (Type[])null);
			}

			[HarmonyPostfix]
			public static void Postfix(CPlayerData __instance)
			{
				Plugin.Log("Postfix executed on CreateDefaultData");
				CPlayerData.m_IsItemLicenseUnlocked[0] = false;
				Plugin.m_SaveManager.setIncompleteCards(GetValidTypeIdsForSanity());
			}
		}

		[HarmonyPatch]
		private class AddXp
		{
			private static int oldLevel;

			private static MethodBase TargetMethod()
			{
				return AccessTools.Method(typeof(CPlayerData), "CPlayer_OnAddShopExp", (Type[])null, (Type[])null);
			}

			[HarmonyPrefix]
			private static void Prefix(CEventPlayer_AddShopExp evt)
			{
				oldLevel = CPlayerData.m_ShopLevel;
			}

			[HarmonyPostfix]
			private static void Postfix(CEventPlayer_AddShopExp evt)
			{
				if (oldLevel < CPlayerData.m_ShopLevel && CPlayerData.m_ShopLevel + 1 >= 2)
				{
					Plugin.Log($"Level Up: {oldLevel + 1} -> {CPlayerData.m_ShopLevel + 1}");
					Plugin.m_SessionHandler.CompleteLocationChecks(LevelMapping.startValue + CPlayerData.m_ShopLevel);
					if (Plugin.m_SessionHandler.GetSlotData().Goal == 1 && CPlayerData.m_ShopLevel + 1 >= Plugin.m_SessionHandler.GetSlotData().LevelGoal)
					{
						Plugin.m_SessionHandler.SendGoalCompletion();
						PopupTextPatches.ShowCustomText("Congrats! Your Shop Has Leveled To Your Goal!");
					}
				}
			}
		}

		[HarmonyPatch]
		private class AddLicense
		{
			private static MethodBase TargetMethod()
			{
				Type typeFromHandle = typeof(CPlayerData);
				MethodInfo method = typeFromHandle.GetMethod("SetUnlockItemLicense", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (method == null)
				{
					Plugin.Log("Static method 'SetUnlockItemLicense' not found!");
				}
				return method;
			}

			private static void Prefix(int index)
			{
			}

			private static void Postfix(int index)
			{
			}
		}

		[HarmonyPatch]
		private class AddCard
		{
			private static MethodBase TargetMethod()
			{
				Type typeFromHandle = typeof(CPlayerData);
				MethodInfo method = typeFromHandle.GetMethod("AddCard", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (method == null)
				{
					Plugin.Log("Static method 'AddCard' not found!");
				}
				return method;
			}

			private static void Prefix(CardData cardData, int addAmount)
			{
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: Unknown result type (might be due to invalid IL or missing references)
				//IL_0041: Unknown result type (might be due to invalid IL or missing references)
				//IL_0051: Invalid comparison between Unknown and I4
				//IL_005c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0070: Invalid comparison between Unknown and I4
				if (Plugin.m_SessionHandler.GetSlotData().CardSanity != 0)
				{
					ECollectionPackType val = (ECollectionPackType)AccessTools.Field(typeof(CardOpeningSequence), "m_CollectionPackType").GetValue(CSingleton<CardOpeningSequence>.Instance);
					if ((int)val < Plugin.m_SessionHandler.GetSlotData().CardSanity && CPlayerData.GetCardAmount(cardData) == 0 && (int)cardData.borderType <= Plugin.m_SessionHandler.GetSlotData().BorderInSanity && (!cardData.isFoil || Plugin.m_SessionHandler.GetSlotData().FoilInSanity))
					{
						Plugin.m_SessionHandler.CompleteLocationChecks(CardMapping.getId(cardData));
					}
				}
			}

			private static void Postfix(CardData cardData, int addAmount)
			{
			}
		}

		public static List<int> GetValidTypeIdsForSanity()
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Expected I4, but got Unknown
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Invalid comparison between Unknown and I4
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Invalid comparison between Unknown and I4
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Invalid comparison between Unknown and I4
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Invalid comparison between Unknown and I4
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Invalid comparison between Unknown and I4
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Invalid comparison between Unknown and I4
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Invalid comparison between Unknown and I4
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Invalid comparison between Unknown and I4
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Expected I4, but got Unknown
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Expected I4, but got Unknown
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Expected I4, but got Unknown
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Expected I4, but got Unknown
			if (Plugin.m_SessionHandler.GetSlotData().CardSanity == 0)
			{
				return Enumerable.Range(1, 121).ToList();
			}
			HashSet<int> hashSet = new HashSet<int>();
			ECardExpansionType[] array = (ECardExpansionType[])(object)new ECardExpansionType[2]
			{
				default(ECardExpansionType),
				(ECardExpansionType)1
			};
			ECardExpansionType[] array2 = array;
			foreach (ECardExpansionType val in array2)
			{
				for (int j = 0; j < InventoryBase.GetShownMonsterList(val).Count; j++)
				{
					EMonsterType monsterType = InventoryBase.GetMonsterData(InventoryBase.GetShownMonsterList(val)[j]).MonsterType;
					ERarity rarity = InventoryBase.GetMonsterData(InventoryBase.GetShownMonsterList(val)[j]).Rarity;
					ERarity val2 = rarity;
					ERarity val3 = val2;
					switch (val3 - 1)
					{
					case 2:
						if ((Plugin.m_SessionHandler.GetSlotData().CardSanity >= 8 && (int)val == 1) || (Plugin.m_SessionHandler.GetSlotData().CardSanity >= 4 && (int)val == 0))
						{
							hashSet.Add((int)monsterType);
						}
						break;
					case 1:
						if ((Plugin.m_SessionHandler.GetSlotData().CardSanity >= 7 && (int)val == 1) || (Plugin.m_SessionHandler.GetSlotData().CardSanity >= 3 && (int)val == 0))
						{
							hashSet.Add((int)monsterType);
						}
						break;
					case 0:
						if ((Plugin.m_SessionHandler.GetSlotData().CardSanity >= 6 && (int)val == 1) || (Plugin.m_SessionHandler.GetSlotData().CardSanity >= 2 && (int)val == 0))
						{
							hashSet.Add((int)monsterType);
						}
						break;
					default:
						if ((Plugin.m_SessionHandler.GetSlotData().CardSanity >= 5 && (int)val == 1) || (Plugin.m_SessionHandler.GetSlotData().CardSanity >= 1 && (int)val == 0))
						{
							hashSet.Add((int)monsterType);
						}
						break;
					}
				}
			}
			return hashSet.ToList();
		}
	}
	public class PopupTextPatches
	{
		[HarmonyPatch]
		public class ShowText
		{
			private static MethodBase TargetMethod()
			{
				Type typeFromHandle = typeof(NotEnoughResourceTextPopup);
				MethodInfo method = typeFromHandle.GetMethod("ShowText", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (method == null)
				{
					Plugin.Log("Static method 'ShowText' not found!");
				}
				return method;
			}

			private static void Prefix(ENotEnoughResourceText notEnoughResourceText)
			{
				currentText = ((object)(ENotEnoughResourceText)(ref notEnoughResourceText)).ToString();
			}
		}

		private static string currentText;

		public static void ShowCustomText(string notEnoughResourceText)
		{
			if (currentText == notEnoughResourceText)
			{
				return;
			}
			CSingleton<NotEnoughResourceTextPopup>.Instance.m_ResetTimer = 0f;
			currentText = notEnoughResourceText;
			for (int i = 0; i < CSingleton<NotEnoughResourceTextPopup>.Instance.m_ShowTextGameObjectList.Count; i++)
			{
				if (!CSingleton<NotEnoughResourceTextPopup>.Instance.m_ShowTextGameObjectList[i].activeSelf)
				{
					((TMP_Text)CSingleton<NotEnoughResourceTextPopup>.Instance.m_ShowTextList[i]).text = notEnoughResourceText;
					CSingleton<NotEnoughResourceTextPopup>.Instance.m_ShowTextGameObjectList[i].gameObject.SetActive(true);
					break;
				}
			}
		}
	}
	public class RestockItemPanelUIPatches
	{
		[HarmonyPatch(typeof(RestockItemPanelUI), "Init")]
		public class Init
		{
			[HarmonyPrefix]
			private static void Prefix(RestockItemPanelUI __instance, RestockItemScreen restockItemScreen, ref int index)
			{
			}

			[HarmonyPostfix]
			private static void Postfix(RestockItemPanelUI __instance, RestockItemScreen restockItemScreen, int index)
			{
				List<EItemType> list = new List<EItemType>();
				List<int> list2 = new List<int>();
				int[] array = LicenseMapping.pg1_ids;
				switch (restockItemScreen.m_PageIndex)
				{
				case 0:
					list = CSingleton<InventoryBase>.Instance.m_StockItemData_SO.m_ShownItemType;
					list2 = Plugin.m_SessionHandler.GetSlotData().pg1IndexMapping;
					array = LicenseMapping.pg1_ids;
					break;
				case 1:
					list = CSingleton<InventoryBase>.Instance.m_StockItemData_SO.m_ShownAccessoryItemType;
					list2 = Plugin.m_SessionHandler.GetSlotData().pg2IndexMapping;
					array = LicenseMapping.pg2_ids;
					break;
				case 2:
					list = CSingleton<InventoryBase>.Instance.m_StockItemData_SO.m_ShownFigurineItemType;
					list2 = Plugin.m_SessionHandler.GetSlotData().pg3IndexMapping;
					array = LicenseMapping.pg3_ids;
					break;
				}
				if (restockItemScreen is RestockItemBoardGameScreen)
				{
					list = CSingleton<InventoryBase>.Instance.m_StockItemData_SO.m_ShownBoardGameItemType;
					list2 = Plugin.m_SessionHandler.GetSlotData().ttIndexMapping;
					array = LicenseMapping.tt_ids;
					if (index == -1)
					{
						return;
					}
				}
				else if (restockItemScreen.m_SortedRestockDataIndexList.IndexOf(index) == -1)
				{
					return;
				}
				RestockData restockData = InventoryBase.GetRestockData(array[list2.IndexOf(index)]);
				__instance.m_LevelRequired = restockData.licenseShopLevelRequired;
				((TMP_Text)__instance.m_LicensePriceText).text = GameInstance.GetPriceString(0f, false, true, false, "F2");
				if (index == Plugin.m_SessionHandler.GetSlotData().pg1IndexMapping[0])
				{
					__instance.m_LevelRequired = 0;
				}
				if (index == Plugin.m_SessionHandler.GetSlotData().pg2IndexMapping[0])
				{
					__instance.m_LevelRequired = 0;
				}
				if (index == Plugin.m_SessionHandler.GetSlotData().pg3IndexMapping[0])
				{
					__instance.m_LevelRequired = 0;
				}
				(int, string, int, int, EItemType) valueOrEmpty = LicenseMapping.getValueOrEmpty(index);
				if (valueOrEmpty.Item4 == -1)
				{
					Plugin.Log($"Failed to find index: {index}");
				}
				else
				{
					runLicenseBtnLogic(__instance, Plugin.m_SessionHandler.hasItem(valueOrEmpty.Item1), index);
				}
			}
		}

		[HarmonyPatch(typeof(RestockItemPanelUI), "OnPressPurchaseButton")]
		public class OnClick
		{
			private static bool Prefix(RestockItemPanelUI __instance)
			{
				if (Plugin.m_SessionHandler.hasItem(LicenseMapping.getValueOrEmpty(__instance.m_Index).itemid))
				{
					return true;
				}
				PopupTextPatches.ShowCustomText("License Unowned");
				return false;
			}
		}

		[HarmonyPatch(typeof(RestockItemScreen), "Init")]
		public class InitScreen
		{
			[HarmonyPrefix]
			public static void Prefix(RestockItemScreen __instance)
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				CPlayerData.m_RestockSortingType = (ERestockSortingType)0;
			}
		}

		[HarmonyPatch(typeof(RestockItemScreen), "OnPressChangePageButton")]
		public class OnPressChangePageButton
		{
			[HarmonyPrefix]
			public static void Prefix(RestockItemScreen __instance)
			{
				//IL_0003: Unknown result type (might be due to invalid IL or missing references)
				__instance.m_CurrentSortingMethod = (ERestockSortingType)0;
			}
		}

		[HarmonyPatch(typeof(RestockItemScreen), "EvaluateSorting")]
		public class Sorting
		{
			[HarmonyPrefix]
			public static void Prefix(RestockItemScreen __instance)
			{
				switch (__instance.m_PageIndex)
				{
				case 0:
					__instance.m_CurrentRestockDataIndexList.Clear();
					__instance.m_CurrentRestockDataIndexList.AddRange(Plugin.m_SessionHandler.GetSlotData().pg1IndexMapping);
					break;
				case 1:
					__instance.m_CurrentRestockDataIndexList.Clear();
					__instance.m_CurrentRestockDataIndexList.AddRange(Plugin.m_SessionHandler.GetSlotData().pg2IndexMapping);
					break;
				case 2:
					__instance.m_CurrentRestockDataIndexList.Clear();
					__instance.m_CurrentRestockDataIndexList.AddRange(Plugin.m_SessionHandler.GetSlotData().pg3IndexMapping);
					break;
				}
				Plugin.Log("new");
				Plugin.Log(string.Join(", ", __instance.m_CurrentRestockDataIndexList));
			}
		}

		public static void runLicenseBtnLogic(RestockItemPanelUI __instance, bool hasItem, int index)
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Expected I4, but got Unknown
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Expected I4, but got Unknown
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			Plugin.Log($"Item Data: {index} : {__instance.m_LevelRequired}");
			if (hasItem && CPlayerData.m_ShopLevel + 1 >= __instance.m_LevelRequired)
			{
				((UIElementBase)__instance).m_UIGrp.SetActive(true);
				__instance.m_LicenseUIGrp.SetActive(false);
				__instance.m_LockPurchaseBtn.gameObject.SetActive(false);
				EItemType type = InventoryBase.GetRestockData(index).itemType;
				IEnumerable<KeyValuePair<int, (int, string, int, int, EItemType)>> source = from i in LicenseMapping.GetKeyValueFromType(type)
					where i.Value.count > CPlayerData.m_StockSoldList[(int)type]
					select i;
				if (source.Any())
				{
					RectTransform val = ((IEnumerable<RectTransform>)((UIElementBase)__instance).m_UIGrp.GetComponentsInChildren<RectTransform>(true)).FirstOrDefault((Func<RectTransform, bool>)((RectTransform rt) => ((Object)rt).name == "UnitPriceText"));
					if ((Object)(object)val != (Object)null)
					{
						Localize component = ((Component)val).GetComponent<Localize>();
						if ((Object)(object)component != (Object)null)
						{
							component.SetTerm("Sold Check Progress");
						}
					}
					((TMP_Text)__instance.m_UnitPriceText).text = $"{CPlayerData.m_StockSoldList[(int)type]}/{source.OrderBy<KeyValuePair<int, (int, string, int, int, EItemType)>, int>((KeyValuePair<int, (int itemid, string name, int count, int locid, EItemType)> x) => x.Value.count).FirstOrDefault().Value.Item3}";
					((Graphic)__instance.m_UnitPriceText).color = Color.blue;
					return;
				}
				RectTransform val2 = ((IEnumerable<RectTransform>)((UIElementBase)__instance).m_UIGrp.GetComponentsInChildren<RectTransform>(true)).FirstOrDefault((Func<RectTransform, bool>)((RectTransform rt) => ((Object)rt).name == "UnitPriceText"));
				if ((Object)(object)val2 != (Object)null)
				{
					Localize component2 = ((Component)val2).GetComponent<Localize>();
					if ((Object)(object)component2 != (Object)null)
					{
						component2.SetTerm("Checks Completed. Total Sold:");
					}
				}
				((TMP_Text)__instance.m_UnitPriceText).text = $"{CPlayerData.m_StockSoldList[(int)type]}";
				((Graphic)__instance.m_UnitPriceText).color = Color.green;
			}
			else if (hasItem)
			{
				((UIElementBase)__instance).m_UIGrp.SetActive(false);
				__instance.m_LicenseUIGrp.SetActive(true);
				__instance.m_LockPurchaseBtn.gameObject.SetActive(true);
				((TMP_Text)__instance.m_LevelRequirementText).text = $"Level {__instance.m_LevelRequired} Required. License Found";
				((Component)__instance.m_LevelRequirementText).gameObject.SetActive(true);
			}
			else if (CPlayerData.m_ShopLevel + 1 >= __instance.m_LevelRequired)
			{
				((UIElementBase)__instance).m_UIGrp.SetActive(false);
				__instance.m_LockPurchaseBtn.gameObject.SetActive(true);
				__instance.m_LicenseUIGrp.SetActive(true);
				((Component)__instance.m_LevelRequirementText).gameObject.SetActive(true);
				((TMP_Text)__instance.m_LevelRequirementText).text = "Level Reached, License Locked by AP";
			}
			else
			{
				((UIElementBase)__instance).m_UIGrp.SetActive(false);
				__instance.m_LicenseUIGrp.SetActive(true);
				__instance.m_LockPurchaseBtn.gameObject.SetActive(true);
				((TMP_Text)__instance.m_LevelRequirementText).text = $"Level {__instance.m_LevelRequired} Required. License Locked by AP";
				((Component)__instance.m_LevelRequirementText).gameObject.SetActive(true);
			}
		}
	}
	public class SaveLoadPatches
	{
		[HarmonyPatch]
		public class SavePatch
		{
			private static MethodBase TargetMethod()
			{
				Type typeFromHandle = typeof(CSaveLoad);
				MethodInfo method = typeFromHandle.GetMethod("Save", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (method == null)
				{
					Plugin.Log("Static method 'Save' not found!");
				}
				return method;
			}

			[HarmonyPrefix]
			private static bool SavePrefix(int saveSlotIndex, bool skipJSONSave = false)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Expected O, but got Unknown
				Plugin.m_SaveManager.Save(saveSlotIndex);
				CEventManager.QueueEvent((CEvent)new CEventPlayer_OnSaveStatusUpdated(true, false));
				return false;
			}
		}

		[HarmonyPatch]
		public class LoadPatch
		{
			private static MethodBase TargetMethod()
			{
				Type typeFromHandle = typeof(CSaveLoad);
				MethodInfo method = typeFromHandle.GetMethod("Load", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (method == null)
				{
					Plugin.Log("Static method 'Load' not found!");
				}
				return method;
			}

			[HarmonyPrefix]
			private static bool LoadPrefix(ref bool __result, int slotIndex)
			{
				Plugin.Log("Loading AP save data");
				if (!Plugin.m_SaveManager.Load())
				{
					Plugin.Log("Cannot load Saves for AP Client");
					__result = false;
				}
				__result = true;
				return false;
			}
		}
	}
	[HarmonyPatch(typeof(RestockItemBoardGameScreen))]
	[HarmonyPatch("EvaluateRestockItemPanelUI")]
	public class TableTopPatches
	{
		[HarmonyPrefix]
		private static bool Prefix(RestockItemBoardGameScreen __instance, int pageIndex)
		{
			((RestockItemScreen)__instance).m_CurrentRestockDataIndexList.Clear();
			((RestockItemScreen)__instance).m_CurrentRestockDataIndexList.AddRange(Plugin.m_SessionHandler.GetSlotData().ttIndexMapping);
			((RestockItemScreen)__instance).m_CurrentRestockDataIndexList.AddRange(new <>z__ReadOnlyArray<int>(new int[3] { -1, -1, -1 }));
			for (int i = 0; i < ((RestockItemScreen)__instance).m_CurrentRestockDataIndexList.Count && i < ((RestockItemScreen)__instance).m_RestockItemPanelUIList.Count; i++)
			{
				((RestockItemScreen)__instance).m_RestockItemPanelUIList[i].Init((RestockItemScreen)(object)__instance, ((RestockItemScreen)__instance).m_CurrentRestockDataIndexList[i]);
				((UIElementBase)((RestockItemScreen)__instance).m_RestockItemPanelUIList[i]).SetActive(true);
				((GenericSliderScreen)__instance).m_ScrollEndPosParent = ((Component)((RestockItemScreen)__instance).m_RestockItemPanelUIList[i]).gameObject;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(TitleScreen))]
	public class TitleScreenPatches
	{
		[HarmonyPatch("OpenLoadGameSlotScreen")]
		[HarmonyPrefix]
		private static bool LoadPrefix(TitleScreen __instance)
		{
			FieldInfo field = typeof(TitleScreen).GetField("m_IsOpeningLevel", BindingFlags.Instance | BindingFlags.NonPublic);
			if (field == null)
			{
				return false;
			}
			if (!(bool)field.GetValue(__instance))
			{
				field.SetValue(__instance, true);
				CSingleton<CGameManager>.Instance.m_CurrentSaveLoadSlotSelectedIndex = 3;
				CSingleton<CGameManager>.Instance.m_IsManualSaveLoad = true;
				CSingleton<CGameManager>.Instance.LoadMainLevelAsync("Start", 3);
				ControllerScreenUIExtManager.OnCloseScreen(__instance.m_ControllerScreenUIExtension);
				return true;
			}
			return true;
		}

		[HarmonyPatch("OnPressStartGame")]
		[HarmonyPrefix]
		private static bool NewGamePrefix(TitleScreen __instance)
		{
			FieldInfo field = typeof(TitleScreen).GetField("m_IsOpeningLevel", BindingFlags.Instance | BindingFlags.NonPublic);
			if (field == null)
			{
				return false;
			}
			if (!(bool)field.GetValue(__instance))
			{
				bool flag = true;
				CSingleton<CGameManager>.Instance.LoadMainLevelAsync("Start", -1);
				ControllerScreenUIExtManager.OnCloseScreen(__instance.m_ControllerScreenUIExtension);
			}
			return false;
		}
	}
	public class TutorialPatches
	{
		[HarmonyPatch(typeof(ShopRenamer))]
		public class ShopRenamerPatches
		{
			[HarmonyPatch("OnPressConfirmShopName")]
			[HarmonyPostfix]
			private static void PostFix(ShopRenamer __instance)
			{
				//IL_0051: Unknown result type (might be due to invalid IL or missing references)
				//IL_005b: Expected O, but got Unknown
				CSingleton<TutorialManager>.Instance.m_TutorialTargetIndicator.SetActive(false);
				((Component)CSingleton<TutorialManager>.Instance).gameObject.SetActive(false);
				CPlayerData.m_TutorialIndex = 16;
				CPlayerData.m_HasFinishedTutorial = true;
				CPlayerData.m_TutorialDataList.Clear();
				Plugin.onSceneLoadLogic();
				CEventManager.QueueEvent((CEvent)new CEventPlayer_SetCoin((float)Settings.Instance.StartingMoney.Value));
			}
		}
	}
}
namespace ApClient.mapping
{
	public class CardMapping
	{
		public static int ghostProgressive = 522715351;

		public static int getId(CardData cardData)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Invalid comparison between Unknown and I4
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Expected I4, but got Unknown
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: 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_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Expected I4, but got Unknown
			if ((int)cardData.expansionType > 1 || (int)cardData.monsterType >= 122)
			{
				return -1;
			}
			Plugin.Log(string.Format("{0} : {1}", string.Format("{0} {1} {2} {3}", cardData.monsterType, cardData.borderType, cardData.isFoil ? "Foil" : "NonFoil", cardData.expansionType), 0x1F290000 | (cardData.expansionType << 12) | (cardData.borderType << 8) | ((cardData.isFoil ? 1 : 0) << 7) | cardData.monsterType));
			return 0x1F290000 | (cardData.expansionType << 12) | (cardData.borderType << 8) | ((cardData.isFoil ? 1 : 0) << 7) | cardData.monsterType;
		}
	}
	public class EmployeeMapping
	{
		public static Dictionary<int, (int itemid, string name, int locid)> mapping = new Dictionary<int, (int, string, int)>
		{
			{
				0,
				(522715318, "Zachery", 522715505)
			},
			{
				1,
				(522715319, "Terence", 522715506)
			},
			{
				2,
				(522715320, "Dennis", 522715507)
			},
			{
				3,
				(522715321, "Clark", 522715508)
			},
			{
				4,
				(522715322, "Angus", 522715509)
			},
			{
				5,
				(522715323, "Benji", 522715510)
			},
			{
				6,
				(522715324, "Lauren", 522715511)
			},
			{
				7,
				(522715325, "Axel", 522715512)
			}
		};

		public static KeyValuePair<int, (int itemid, string name, int locid)> getKeyValue(int itemid)
		{
			KeyValuePair<int, (int, string, int)> result = mapping.FirstOrDefault((KeyValuePair<int, (int itemid, string name, int locid)> pair) => pair.Value.itemid == itemid);
			KeyValuePair<int, (int, string, int)> keyValuePair = new KeyValuePair<int, (int, string, int)>(-1, (-1, "", -1));
			if (result.Equals(default(KeyValuePair<int, (int, string, int)>)))
			{
				result = keyValuePair;
			}
			return result;
		}

		public static (int itemid, string name, int locid) getValueOrEmpty(int key)
		{
			return mapping.GetValueOrDefault(key, (-1, "", -1));
		}
	}
	public class ExpansionMapping
	{
		public static int locstartval = 522715513;

		public static int progressiveA = 522715328;

		public static int progressiveB = 522715329;

		public static int warehouseKey = 522715381;
	}
	public class FurnatureMapping
	{
		public static int[] reorder = new int[22]
		{
			0, 5, 17, 4, 11, 18, 1, 6, 12, 2,
			10, 13, 8, 14, 20, 3, 12, 19, 7, 15,
			21, 9
		};

		public static Dictionary<int, (int itemid, string name, int count)> mapping = new Dictionary<int, (int, string, int)>
		{
			{
				0,
				(-1, "Small Cabinet", 1)
			},
			{
				1,
				(522715205, "Small Metal Rack", 1)
			},
			{
				2,
				(522715214, "Play Table", 1)
			},
			{
				3,
				(522715211, "Small Personal Shelf", 1)
			},
			{
				4,
				(522715206, "Single Sided Shelf", 1)
			},
			{
				5,
				(522715209, "Card Table", 1)
			},
			{
				6,
				(522715213, "Small Warehouse Shelf", 1)
			},
			{
				7,
				(522715210, "Small Card Display", 1)
			},
			{
				8,
				(522715212, "Auto Scent M100", 1)
			},
			{
				9,
				(522715215, "Workbench", 1)
			},
			{
				10,
				(522715216, "Trash Bin", 1)
			},
			{
				11,
				(522715207, "Double Sided Shelf", 1)
			},
			{
				12,
				(522715213, "Big Warehouse Shelf", 2)
			},
			{
				13,
				(522715217, "Checkout Counter", 1)
			},
			{
				14,
				(522715212, "Auto Scent G500", 2)
			},
			{
				15,
				(522715210, "Card Display Table", 2)
			},
			{
				16,
				(522715211, "Big Personal Shelf", 2)
			},
			{
				17,
				(522715209, "Vintage Card Table", 2)
			},
			{
				18,
				(522715208, "Wide Shelf", 1)
			},
			{
				19,
				(522715211, "Huge Personal Shelf", 3)
			},
			{
				20,
				(522715212, "Auto Scent T100", 3)
			},
			{
				21,
				(522715210, "Big Card Display", 3)
			}
		};

		public static KeyValuePair<int, (int itemid, string name, int count)> getKeyValue(int itemid, int count = 1)
		{
			KeyValuePair<int, (int, string, int)> result = mapping.FirstOrDefault((KeyValuePair<int, (int itemid, string name, int count)> pair) => pair.Value.itemid == itemid && count == pair.Value.count);
			KeyValuePair<int, (int, string, int)> keyValuePair = new KeyValuePair<int, (int, string, int)>(-1, (-1, "Unknown", 0));
			if (result.Equals(default(KeyValuePair<int, (int, string, int)>)))
			{
				result = keyValuePair;
			}
			return result;
		}

		public static (int itemid, string name, int count) getValueOrEmpty(int key)
		{
			return mapping.GetValueOrDefault(key, (-1, "", 0));
		}
	}
	public class LevelMapping
	{
		public static int startValue = 522715556;
	}
	public class LicenseMapping
	{
		public static SortedDictionary<int, (int itemid, string name, int count, int locid, EItemType type)> mapping = new SortedDictionary<int, (int, string, int, int, EItemType)>
		{
			{
				0,
				(522715137, "Basic Card Pack (32)", 32, 522715376, (EItemType)0)
			},
			{
				1,
				(522715352, "Basic Card Pack (64)", 32, 522715376, (EItemType)0)
			},
			{
				2,
				(522715353, "Progressive Basic Card Pack", 8, 522715377, (EItemType)1)
			},
			{
				3,
				(522715354, "Progressive Basic Card Pack", 8, 522715377, (EItemType)1)
			},
			{
				4,
				(522715138, "Progressive Rare Card Pack", 32, 522715378, (EItemType)2)
			},
			{
				5,
				(522715355, "Progressive Rare Card Pack", 32, 522715378, (EItemType)2)
			},
			{
				6,
				(522715356, "Progressive Rare Card Pack", 8, 522715379, (EItemType)3)
			},
			{
				7,
				(522715357, "Progressive Rare Card Pack", 8, 522715379, (EItemType)3)
			},
			{
				8,
				(522715139, "Progressive Epic Card Pack", 32, 522715380, (EItemType)4)
			},
			{
				9,
				(522715358, "Progressive Epic Card Pack", 32, 522715380, (EItemType)4)
			},
			{
				10,
				(522715359, "Progressive Epic Card Pack", 8, 522715381, (EItemType)5)
			},
			{
				11,
				(522715360, "Progressive Epic Card Pack", 8, 522715381, (EItemType)5)
			},
			{
				12,
				(522715140, "Progressive Legendary Card Pack", 32, 522715382, (EItemType)6)
			},
			{
				13,
				(522715361, "Progressive Legendary Card Pack", 32, 522715382, (EItemType)6)
			},
			{
				14,
				(522715362, "Progressive Legendary Card Pack", 8, 522715383, (EItemType)7)
			},
			{
				15,
				(522715363, "Progressive Legendary Card Pack", 8, 522715383, (EItemType)7)
			},
			{
				67,
				(522715141, "Fire Battle Deck", 9, 522715392, (EItemType)55)
			},
			{
				68,
				(522715142, "Earth Battle Deck", 9, 522715393, (EItemType)56)
			},
			{
				69,
				(522715143, "Water Battle Deck", 9, 522715394, (EItemType)57)
			},
			{
				70,
				(522715144, "Wind Battle Deck", 9, 522715395, (EItemType)58)
			},
			{
				24,
				(522715145, "Progressive Basic Destiny Pack", 32, 522715384, (EItemType)8)
			},
			{
				25,
				(522715364, "Progressive Basic Destiny Pack", 32, 522715384, (EItemType)8)
			},
			{
				26,
				(522715365, "Progressive Basic Destiny Pack", 8, 522715385, (EItemType)9)
			},
			{
				27,
				(522715366, "Progressive Basic Destiny Pack", 8, 522715385, (EItemType)9)
			},
			{
				28,
				(522715146, "Progressive Rare Destiny Pack", 32, 522715386, (EItemType)10)
			},
			{
				29,
				(522715367, "Progressive Rare Destiny Pack", 32, 522715386, (EItemType)10)
			},
			{
				30,
				(522715368, "Progressive Rare Destiny Pack", 8, 522715387, (EItemType)11)
			},
			{
				31,
				(522715369, "Progressive Rare Destiny Pack", 8, 522715387, (EItemType)11)
			},
			{
				32,
				(522715147, "Progressive Epic Destiny Pack", 32, 522715388, (EItemType)12)
			},
			{
				33,
				(522715370, "Progressive Epic Destiny Pack", 32, 522715388, (EItemType)12)
			},
			{
				34,
				(522715371, "Progressive Epic Destiny Pack", 8, 522715389, (EItemType)13)
			},
			{
				35,
				(522715372, "Progressive Epic Destiny Pack", 8, 522715389, (EItemType)13)
			},
			{
				36,
				(522715148, "Progressive Legendary Destiny Pack", 32, 522715390, (EItemType)14)
			},
			{
				37,
				(522715373, "Progressive Legendary Destiny Pack", 32, 522715390, (EItemType)14)
			},
			{
				38,
				(522715374, "Progressive Legendary Destiny Pack", 8, 522715391, (EItemType)15)
			},
			{
				39,
				(522715375, "Progressive Legendary Destiny Pack", 8, 522715391, (EItemType)15)
			},
			{
				71,
				(522715149, "Fire Destiny Deck", 9, 522715396, (EItemType)59)
			},
			{
				72,
				(522715150, "Earth Destiny Deck", 9, 522715397, (EItemType)60)
			},
			{
				73,
				(522715151, "Water Destiny Deck", 9, 522715398, (EItemType)61)
			},
			{
				74,
				(522715152, "Wind Destiny Deck", 9, 522715399, (EItemType)62)
			},
			{
				40,
				(522715153, "Cleanser (8)", 8, 522715400, (EItemType)23)
			},
			{
				41,
				(522715376, "Progressive Cleanser", 8, 522715400, (EItemType)23)
			},
			{
				75,
				(522715154, "Card Sleeves (Clear)", 32, 522715401, (EItemType)63)
			},
			{
				76,
				(522715155, "Card Sleeves (Tetramon)", 32, 522715402, (EItemType)64)
			},
			{
				43,
				(522715156, "D20 Dice Red (16)", 8, 522715403, (EItemType)29)
			},
			{
				44,
				(522715157, "D20 Dice Blue (16)", 8, 522715404, (EItemType)30)
			},
			{
				45,
				(522715158, "D20 Dice Black (16)", 8, 522715405, (EItemType)31)
			},
			{
				46,
				(522715159, "D20 Dice White (16)", 8, 522715406, (EItemType)32)
			},
			{
				77,
				(522715160, "Card Sleeves (Fire)", 32, 522715407, (EItemType)65)
			},
			{
				78,
				(522715161, "Card Sleeves (Earth)", 32, 522715408, (EItemType)66)
			},
			{
				79,
				(522715162, "Card Sleeves (Water)", 32, 522715409, (EItemType)67)
			},
			{
				80,
				(522715163, "Card Sleeves (Wind)", 32, 522715410, (EItemType)68)
			},
			{
				16,
				(522715164, "Progressive Deck Box Red", 8, 522715411, (EItemType)24)
			},
			{
				17,
				(522715377, "Progressive Deck Box Red", 8, 522715411, (EItemType)24)
			},
			{
				18,
				(522715165, "Progressive Deck Box Green", 8, 522715412, (EItemType)25)
			},
			{
				19,
				(522715378, "Progressive Deck Box Green", 8, 522715412, (EItemType)25)
			},
			{
				20,
				(522715166, "Progressive Deck Box Blue", 8, 522715413, (EItemType)26)
			},
			{
				21,
				(522715379, "Progressive Deck Box Blue", 8, 522715413, (EItemType)26)
			},
			{
				22,
				(522715167, "Progressive Deck Box Yellow", 8, 522715414, (EItemType)27)
			},
			{
				23,
				(522715380, "Progressive Deck Box Yellow", 8, 522715414, (EItemType)27)
			},
			{
				42,
				(522715168, "Collection Book ", 4, 522715415, (EItemType)28)
			},
			{
				66,
				(522715169, "Premium Collection Book", 4, 522715416, (EItemType)54)
			},
			{
				83,
				(522715170, "Playmat (Drilceros)", 8, 522715417, (EItemType)71)
			},
			{
				81,
				(522715171, "Playmat (Clamigo)", 8, 522715418, (EItemType)69)
			},
			{
				87,
				(522715172, "Playmat (Wispo)", 8, 522715419, (EItemType)75)
			},
			{
				95,
				(522715173, "Playmat (Lunight)", 8, 522715420, (EItemType)83)
			},
			{
				90,
				(522715174, "Playmat (Kyrone)", 8, 522715421, (EItemType)78)
			},
			{
				82,
				(522715175, "Playmat (Duel)", 8, 522715422, (EItemType)70)
			},
			{
				86,
				(522715176, "Playmat (Dracunix)", 8, 522715423, (EItemType)74)
			},
			{
				85,
				(522715177, "Playmat (The Four Dragons)", 8, 522715424, (EItemType)73)
			},
			{
				84,
				(522715178, "Playmat (Drakon)", 8, 522715425, (EItemType)72)
			},
			{
				88,
				(522715179, "Playmat (GigatronX Evo)", 8, 522715426, (EItemType)76)
			},
			{
				91,
				(522715180, "Playmat (Fire)", 8, 522715427, (EItemType)79)
			},
			{
				92,
				(522715181, "Playmat (Earth)

plugins/Archipelago.MultiClient.Net.dll

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

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: ComVisible(false)]
[assembly: Guid("35a803ad-85ed-42e9-b1e3-c6b72096f0c1")]
[assembly: InternalsVisibleTo("Archipelago.MultiClient.Net.Tests")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("Jarno Westhof, Hussein Farran, Zach Parks")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyDescription("A client library for use with .NET based prog-langs for interfacing with Archipelago hosts.")]
[assembly: AssemblyFileVersion("6.6.0.0")]
[assembly: AssemblyInformationalVersion("6.6.0+75d4c5e6a52bb0c8bb1d4bc368652613509c7acb")]
[assembly: AssemblyProduct("Archipelago.MultiClient.Net")]
[assembly: AssemblyTitle("Archipelago.MultiClient.Net")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/ArchipelagoMW/Archipelago.MultiClient.Net")]
[assembly: AssemblyVersion("6.6.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);
}
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; }

		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; }

		internal ArchipelagoSession(IArchipelagoSocketHelper socket, IReceivedItemsHelper items, ILocationCheckHelper locations, IPlayerHelper players, IRoomStateHelper roomState, ConnectionInfoHelper connectionInfoHelper, IDataStorageHelper dataStorage, IMessageLogHelper messageLog)
		{
			Socket = socket;
			Items = items;
			Locations = locations;
			Players = players;
			RoomState = roomState;
			connectionInfo = connectionInfoHelper;
			DataStorage = dataStorage;
			MessageLog = messageLog;
			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);
				}
				return;
			}
			if (packet is ConnectedPacket && RoomState.Version != null && RoomState.Version >= new Version(0, 3, 8))
			{
				LogUsedVersion();
			}
			loginResultTask.TrySetResult(LoginResult.FromPacket(packet));
		}

		private void LogUsedVersion()
		{
			try
			{
				string fileVersion = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion;
				Socket.SendPacketAsync(new SetPacket
				{
					Key = ".NetUsedVersions",
					DefaultValue = (JToken)(object)JObject.FromObject((object)new Dictionary<string, bool>()),
					Operations = new OperationSpecification[1] { Operation.Update(new Dictionary<string, bool> { 
					{
						ConnectionInfo.Game + ":" + fileVersion + ":NETSTANDARD2_0",
						true
					} }) }
				});
			}
			catch
			{
			}
		}

		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 roomState = new RoomStateHelper(socket, locationCheckHelper);
			DataStorageHelper dataStorage = new DataStorageHelper(socket, connectionInfoHelper);
			MessageLogHelper messageLog = new MessageLogHelper(socket, itemInfoResolver, playerHelper, connectionInfoHelper);
			return new ArchipelagoSession(socket, items, locationCheckHelper, playerHelper, roomState, connectionInfoHelper, dataStorage, messageLog);
		}

		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(StringEnumConverter))]
		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 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(StringEnumConverter))]
		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_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Invalid comparison between Unknown and I4
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Invalid comparison between Unknown and I4
			//IL_00d7: 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_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: 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(StringEnumConverter), new object[] { typeof(SnakeCaseNamingStrategy) })]
		public JsonMessagePartType? Type { get; set; }

		[JsonProperty("color")]
		[JsonConverter(typeof(StringEnumConverter), 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(StringEnumConverter), new object[] { typeof(SnakeCaseNamingStrategy) })]
		public OperationType OperationType;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		private Callback()
		{
		}

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

		internal JToken Value { get; set; }

		private AdditionalArgument()
		{
		}

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

		public long LocationId { get; set; }

		public int PlayerSlot { get; set; }

		public ItemFlags Flags { get; set; }

		public string ItemGame { get; set; }

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

		public PlayerInfo Player { get; set; }

		public string ItemName { get; set; }

		public string LocationName { get; set; }

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

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

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

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

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

		public ILocationCheckHelper Locations { get; set; }

		public IPlayerHelper PlayerHelper { get; set; }

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

		public long ItemId { get; }

		public int Player { get; }

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

		public int Player { get; }

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

		public MessagePartType Type { get; internal set; }

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

		public PaletteColor? PaletteColor { get; protected set; }

		public bool IsBackgroundColor { get; internal set; }

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

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

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

		public int SlotId { get; }

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

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

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

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

		public PlayerInfo Receiver { get; }

		public PlayerInfo Sender { get; }

		public bool IsReceiverTheActivePlayer => Receiver == ActivePlayer;

		public bool IsSenderTheActivePlayer => Sender == ActivePlayer;

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

		public ItemInfo Item { get; }

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

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

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

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

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

		public PlayerInfo Player { get; }

		public bool IsActivePlayer => Player == ActivePlayer;

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

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

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

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

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

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

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

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

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

		internal T Socket;

		private readonly int bufferSize;

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

		public event ArchipelagoSocketHelperDelagates.PacketReceivedHandler PacketReceived;

		public event ArchipelagoSocketHelperDelagates.PacketsSentHandler PacketsSent;

		public event ArchipelagoSocketHelperDelagates.ErrorReceivedHandler ErrorReceived;

		public event ArchipelagoSocketHelperDelagates.SocketClosedHandler SocketClosed;

		public event ArchipelagoSocketHelperDelagates.SocketOpenedHandler SocketOpened;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		int Team { get; }

		int Slot { get; }

		string[] Tags { get; }

		ItemsHandlingFlags ItemsHandlingFlags { get; }

		string Uuid { get; }

		void UpdateConnectionOptions(string[] tags);

		void UpdateConnectionOptions(ItemsHandlingFlags itemsHandlingFlags);

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

		public string Game { get; private set; }

		public int Team { get; private set; }

		public int Slot { get; private set; }

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

		public ItemsHandlingFlags ItemsHandlingFlags { get; internal set; }

		public string Uuid { get; private set; }

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

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

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

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

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

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

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

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

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

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

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

		private readonly IArchipelagoSocketHelper socket;

		private readonly IConnectionInfoProvider connectionInfoProvider;

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

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

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

		private void OnPacketReceived(ArchipelagoPacketBase packet)
		{
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: 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 == 15 && operationSpecificCallbacks.TryGetValue((Guid)setReplyPacket.AdditionalArguments["Reference"], out var value))
					{
						value(setReplyPacket.OriginalValue, setReplyPacket.Value, setReplyPacket.AdditionalArguments);
						operationSpecificCallbacks.Remove((Guid)setReplyPacket.AdditionalArguments["Reference"]);
					}
					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 guid = Guid.NewGuid();
				operationSpecificCallbacks[guid] = e.Callbacks;
				dictionary["Reference"] = JToken.FromObject((object)guid);
				socket.SendPacketAsync(new SetPacket
				{
					Key = key,
					Operations = e.Operations.ToArray(),
					WantReply = true,
					AdditionalArguments = dictionary
				});
			}
			else
			{
				socket.SendPacketAsync(new SetPacket
				{
					Key = key,
					Operations = e.Operations.ToArray(),
					AdditionalArguments = dictionary
				});
			}
		}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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