Decompiled source of BRC Archipelago v1.0.0

plugins/Archipelago.dll

Decompiled 11 hours ago
using System;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using Archipelago.BRC.Apps;
using Archipelago.BRC.Components;
using Archipelago.BRC.Patches;
using Archipelago.BRC.Properties;
using Archipelago.BRC.Stages;
using Archipelago.BRC.Structures;
using Archipelago.MultiClient.Net;
using Archipelago.MultiClient.Net.BounceFeatures.DeathLink;
using Archipelago.MultiClient.Net.Enums;
using Archipelago.MultiClient.Net.Helpers;
using Archipelago.MultiClient.Net.Models;
using Archipelago.MultiClient.Net.Packets;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using DG.Tweening;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using ModLocalizer;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Reptile;
using Reptile.Phone;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;
using brc_styleswapmod;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("Archipelago")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Connect to an Archipelago server to play Bomb Rush Cyberfunk randomizer.")]
[assembly: AssemblyFileVersion("0.9.0.0")]
[assembly: AssemblyInformationalVersion("0.9.0+3faf1d519f2ad53475056406b5b74ae730c9ed1d")]
[assembly: AssemblyProduct("Archipelago")]
[assembly: AssemblyTitle("Archipelago")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.9.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 Archipelago.BRC
{
	[BepInPlugin("trpg.brc.archipelago", "Archipelago", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Core : BaseUnityPlugin
	{
		public const string PluginGUID = "trpg.brc.archipelago";

		public const string PluginName = "Archipelago";

		public const string PluginVersion = "1.0.0";

		internal static GameVersion TargetGameVersion;

		public static Core Instance;

		public Data Data = new Data();

		public UIManager UIManager = new UIManager();

		public PhoneManager PhoneManager = new PhoneManager();

		public Multiworld Multiworld = new Multiworld();

		public LocationManager LocationManager = new LocationManager();

		public SaveManager SaveManager = new SaveManager();

		public StageManager stageManager = null;

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

		public static ConfigEntry<string> configDefaultName;

		public static ConfigEntry<string> configDefaultAddress;

		public static ConfigEntry<string> configDefaultPassword;

		public static ConfigEntry<Color> configColorPlayerSelf;

		public static ConfigEntry<Color> configColorPlayerOther;

		public static ConfigEntry<Color> configColorItemAdvancement;

		public static ConfigEntry<Color> configColorItemNeverExclude;

		public static ConfigEntry<Color> configColorItemFiller;

		public static ConfigEntry<Color> configColorItemTrap;

		public static ConfigEntry<Color> configColorLocation;

		public static ConfigEntry<bool> configPlayerOtherNotifs;

		public static ConfigEntry<bool> configDontSavePhotos;

		internal static bool isQuickStyleSwapLoaded = false;

		internal static bool isSlopCrewLoaded = false;

		internal static int forbiddenModsLoaded = 0;

		internal static string forbiddenGUIDs = string.Empty;

		private readonly List<string> forbiddenMods = new List<string> { "QuickGraffiti", "com.Dragsun.FastCypher", "dance.tari.bombrushcyberfunk.customgraffiti", "TombRush" };

		public PluginLocalizer Localizer { get; private set; }

		public static GameFontType MainFont { get; private set; }

		public static GameFontType MainFontEnglish { get; private set; }

		public static GameFontType PhoneFont { get; private set; }

		public static bool FailScoreEncounters { get; private set; } = false;


		private void CheckForbiddenMods()
		{
			forbiddenModsLoaded = 0;
			forbiddenGUIDs = string.Empty;
			foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos)
			{
				if (forbiddenMods.Contains(pluginInfo.Value.Metadata.GUID))
				{
					forbiddenModsLoaded++;
					Logger.LogWarning((object)("A forbidden mod is loaded. (\"" + pluginInfo.Value.Metadata.GUID + "\")"));
					if (forbiddenGUIDs == string.Empty)
					{
						forbiddenGUIDs = "\"" + pluginInfo.Value.Metadata.GUID + "\"";
					}
					else
					{
						forbiddenGUIDs = (forbiddenGUIDs = forbiddenGUIDs + ", \"" + pluginInfo.Value.Metadata.GUID + "\"");
					}
				}
			}
		}

		private void Awake()
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Expected O, but got Unknown
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Expected O, but got Unknown
			//IL_04b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ba: Expected O, but got Unknown
			//IL_04c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04cc: Expected O, but got Unknown
			//IL_0558: Unknown result type (might be due to invalid IL or missing references)
			//IL_058b: Unknown result type (might be due to invalid IL or missing references)
			//IL_05be: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0624: Unknown result type (might be due to invalid IL or missing references)
			//IL_0657: Unknown result type (might be due to invalid IL or missing references)
			//IL_068a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Instance != (Object)null)
			{
				Object.Destroy((Object)(object)this);
			}
			Instance = this;
			TargetGameVersion = ScriptableObject.CreateInstance<GameVersion>();
			TargetGameVersion.major = 1;
			TargetGameVersion.minor = 0;
			TargetGameVersion.repositoryRevision = 20381;
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			Localizer = new PluginLocalizer("Archipelago", Path.Combine(directoryName, "Languages"), (SystemLanguage)10);
			Localizer.OnLanguageChanged += new OnLanguageChangedDelegate(UIManager.UpdateLanguage);
			Localizer.OnInitializationFinished += (OnInitializationFinishedDelegate)delegate
			{
				MainFont = Localizer.LoadFontTypeAndRemoveUnusedFonts((GameFontTypes)3);
				MainFontEnglish = Localizer.LoadFontTypeEnglishOnly((GameFontTypes)3);
				PhoneFont = Localizer.LoadFontTypeAndRemoveUnusedFonts((GameFontTypes)30);
			};
			Harmony val = new Harmony("Archipelago");
			val.PatchAll(typeof(AppCamera_WaitForPhotoSavingComplete));
			val.PatchAll(typeof(AppGraffiti_OnHoldDown_Patch));
			val.PatchAll(typeof(AppGraffiti_OnHoldUp_Patch));
			val.PatchAll(typeof(AppGraffiti_OnPressDown_Patch));
			val.PatchAll(typeof(AppGraffiti_OnPressRight_Patch));
			val.PatchAll(typeof(AppGraffiti_OnPressUp_Patch));
			val.PatchAll(typeof(AppGraffiti_OnReleaseRight_Patch));
			val.PatchAll(typeof(AppGraffiti_OpenInfo_Patch));
			val.PatchAll(typeof(AppGraffiti_RefreshList_Patch));
			val.PatchAll(typeof(BaseModule_HandleStageFullyLoaded_Patch));
			val.PatchAll(typeof(BaseModule_SaveBeforeStageExit_Patch));
			val.PatchAll(typeof(BaseModule_QuitCurrentGameSession_Patch));
			val.PatchAll(typeof(BaseModule_StartNewGame_Patch));
			val.PatchAll(typeof(CharacterSelect_PopulateListOfSelectableCharacters_Patch));
			val.PatchAll(typeof(Collectable_PickupCollectable_Patch));
			val.PatchAll(typeof(DieAbility_OnStartAbility_Patch));
			val.PatchAll(typeof(DynamicPickup_PickupPickup_Patch));
			val.PatchAll(typeof(Encounter_SetEncounterState_Patch));
			val.PatchAll(typeof(GameplayEvent_UnlockCameraAppForPlayer_Patch));
			val.PatchAll(typeof(GameplayEvent_UnlockCharacterImpl_Patch));
			val.PatchAll(typeof(GraffitiGame_OnDestroy_Patch));
			val.PatchAll(typeof(GraffitiGame_SetState_Patch));
			val.PatchAll(typeof(GraffitiGame_SetStateVisual_Patch));
			val.PatchAll(typeof(GraffitiInfoPanel_Show_Patch));
			val.PatchAll(typeof(GraffitiScrollButton_SetContent_Patch));
			val.PatchAll(typeof(GraffitiSpot_GiveRep_Patch));
			val.PatchAll(typeof(GraffitiSpot_SpawnRep_Patch));
			val.PatchAll(typeof(HomescreenButton_SetContent_Patch));
			val.PatchAll(typeof(LocalizationLookupTable_GetLocalizationValueFromSubgroup_Patch));
			val.PatchAll(typeof(PhoneScrollUnlockableButton_SetContent_Patch));
			val.PatchAll(typeof(PhotoObjectiveProgressable_MadePhotograph_Patch));
			val.PatchAll(typeof(PhotosManager_SavePhoto_Patch));
			val.PatchAll(typeof(Player_ChangeHP_Patch));
			val.PatchAll(typeof(Player_CheckNPCTriggerForConversation_Patch));
			val.PatchAll(typeof(Player_OnTriggerEnter_Patch));
			val.PatchAll(typeof(Player_OnTriggerExit_Patch));
			val.PatchAll(typeof(Player_StartGraffitiMode_Patch));
			val.PatchAll(typeof(ScoreEncounter_StartMainEvent_Patch));
			val.PatchAll(typeof(SaveManager_SaveCurrentSaveSlot_Patch));
			val.PatchAll(typeof(SaveSlotData_UnlockCharacter_Patch));
			val.PatchAll(typeof(SaveSlotMenu_OnPressedPopupDeleteButton_Patch));
			val.PatchAll(typeof(SaveSlotMenu_ShowDeleteSaveSlotPopup_Patch));
			val.PatchAll(typeof(TextMeshProGameTextLocalizer_GetRawDialogueTextValue_Patch));
			val.PatchAll(typeof(Type_GetType_Patch));
			val.PatchAll(typeof(UIManager_InstantiateMainMenuSceneUI_Patch));
			val.PatchAll(typeof(UIManager_HideDieMenu_Patch));
			val.PatchAll(typeof(UIManager_ShowDieMenu_Patch));
			val.PatchAll(typeof(VendingMachine_RewardIsValid_Patch));
			val.PatchAll(typeof(VersionUIHandler_SetVersionText_Patch));
			foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos)
			{
				if (pluginInfo.Value.Metadata.GUID == "com.yuril.brc_styleswapmod")
				{
					isQuickStyleSwapLoaded = true;
					Logger.LogInfo((object)"QuickStyleSwap is loaded. Applying SwapStyle patch.");
					val.PatchAll(typeof(brc_styleswapmodPlugin_SwapStyle_Patch));
				}
				else if (pluginInfo.Value.Metadata.GUID == "SlopCrew.Plugin")
				{
					isSlopCrewLoaded = true;
				}
			}
			Core.OnCoreInitialized += new OnCoreInitializedHandler(SaveManager.GetSavePath);
			Core.OnCoreInitialized += new OnCoreInitializedHandler(CheckForbiddenMods);
			configDefaultName = ((BaseUnityPlugin)this).Config.Bind<string>("Defaults", "defaultName", "Red", "The default name used when opening the connection menu for a slate with no save data.");
			configDefaultAddress = ((BaseUnityPlugin)this).Config.Bind<string>("Defaults", "defaultAddress", "archipelago.gg", "The default address used when opening the connection menu for a slate with no save data.");
			configDefaultPassword = ((BaseUnityPlugin)this).Config.Bind<string>("Defaults", "defaultPassword", "", "The default password used when opening the connection menu for a slate with no save data.");
			configColorPlayerSelf = ((BaseUnityPlugin)this).Config.Bind<Color>("Colors", "colorPlayerSelf", new Color(0.93f, 0f, 0.93f), "The color used to represent you.");
			configColorPlayerOther = ((BaseUnityPlugin)this).Config.Bind<Color>("Colors", "colorPlayerOther", new Color(0.98f, 0.98f, 0.92f), "The color used to represent other players.");
			configColorItemAdvancement = ((BaseUnityPlugin)this).Config.Bind<Color>("Colors", "colorItemAdvancement", new Color(0.69f, 0.6f, 0.94f), "The color used to represent items that are important for progression.");
			configColorItemNeverExclude = ((BaseUnityPlugin)this).Config.Bind<Color>("Colors", "colorItemNeverExclude", new Color(0.43f, 0.55f, 0.91f), "The color used to represent items that are useful.");
			configColorItemFiller = ((BaseUnityPlugin)this).Config.Bind<Color>("Colors", "colorItemFiller", new Color(0f, 0.93f, 0.93f), "The color used to represent items that are not very important.");
			configColorItemTrap = ((BaseUnityPlugin)this).Config.Bind<Color>("Colors", "colorItemTrap", new Color(0.98f, 0.5f, 0.45f), "The color used to represent items that are traps.");
			configColorLocation = ((BaseUnityPlugin)this).Config.Bind<Color>("Colors", "colorLocation", new Color(0f, 1f, 0.5f), "The color used to represent locations.");
			configPlayerOtherNotifs = ((BaseUnityPlugin)this).Config.Bind<bool>("Notifications", "otherPlayerNotifs", true, "Get phone notifications when collecting items that belong to other players.");
			configDontSavePhotos = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera", "dontSavePhotos", false, "Don't save photos taken with the Camera app. Only takes effect when playing randomizer.");
		}
	}
	public class Data
	{
		public long index;

		public string host_name;

		public string slot_name;

		public string password;

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

		public Logic logic = Logic.Glitchless;

		public bool skipIntro = true;

		public bool skipDreams = false;

		public bool skipHands = false;

		public int totalRep = 1400;

		public bool endingRep = false;

		public ScoreDifficulty scoreDifficulty = ScoreDifficulty.Normal;

		public HashSet<string> to_lock = new HashSet<string> { "OVERWHELMME", "QUICK BING", "WHOLE SIXER", "Graffo Le Fou", "WILD STRUXXA", "Bombing by FireMan" };

		public bool limitedGraffiti = false;

		public SGraffiti sGraffiti = SGraffiti.Separate;

		public Dictionary<string, int> grafUses = new Dictionary<string, int>();

		public int sMax = 5;

		public bool junkPhotos = false;

		public int fakeRep = 0;

		public int sprayCount = 0;

		public MoveStyle startingMovestyle = (MoveStyle)2;

		public bool skateboardUnlocked = true;

		public bool inlineUnlocked = false;

		public bool bmxUnlocked = false;

		public Characters firstCharacter = (Characters)(-1);

		public bool dummyUnlocked = false;

		public int damageMultiplier = 1;

		public bool deathLink = false;
	}
	public class LocationManager
	{
		public Dictionary<string, long> locations = new Dictionary<string, long>();

		public List<AItem> itemQueue = new List<AItem>();

		public List<Notification> notifQueue = new List<Notification>();

		public void CheckLocation(string loc, bool playSound = true)
		{
			if (!Core.Instance.Data.@checked.Contains(loc))
			{
				Core.Instance.Data.@checked.Add(loc);
			}
			if (locations.ContainsKey(loc) && Core.Instance.Multiworld.Authenticated)
			{
				Core.Logger.LogInfo((object)$"Checking location \"{loc}\" | {locations[loc]}");
				Core.Instance.Multiworld.Session.Locations.CompleteLocationChecks(new long[1] { locations[loc] });
				if (playSound && !Core.Instance.Data.@checked.Contains(loc))
				{
					Core.Instance.UIManager.PlaySfxGameplay((SfxCollectionID)23, (AudioClipID)371);
				}
			}
			else
			{
				Core.Logger.LogWarning((object)("Location \"" + loc + "\" does not exist."));
			}
		}

		public void GetItem(AItem item, bool playSound = true)
		{
			//IL_061b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0620: Unknown result type (might be due to invalid IL or missing references)
			//IL_062c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0632: Invalid comparison between Unknown and I4
			//IL_0644: Unknown result type (might be due to invalid IL or missing references)
			//IL_0646: Unknown result type (might be due to invalid IL or missing references)
			//IL_06b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_06b9: Invalid comparison between Unknown and I4
			//IL_06db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0712: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			Core.Instance.PhoneManager.appArchipelago.UpdateText();
			if (playSound)
			{
				Core.Instance.UIManager.PlaySfxGameplay((SfxCollectionID)23, (AudioClipID)371);
			}
			if (item is BRCItem bRCItem && item.player_name == Core.Instance.Data.slot_name)
			{
				switch (bRCItem.type)
				{
				case BRCType.Music:
				{
					string name = bRCItem.item_name.Substring(7, bRCItem.item_name.Length - 8);
					MusicTrack musicTrack = GetMusicTrack(GetMusicAssetName(name));
					Core.Instance.SaveManager.CurrentSaveSlot.GetUnlockableDataByUid(((AUnlockable)musicTrack).Uid).IsUnlocked = true;
					Core.Instance.PhoneManager.Phone.GetAppInstance<AppMusicPlayer>().GameMusicPlayer.AddMusicTrack(musicTrack);
					notifQueue.Add(new Notification("AppMusicPlayer", Core.Instance.Localizer.GetRawTextValue((Subgroups)0, "COLLECTIBLE_MUSIC") + " (" + musicTrack.Title + ")", (AUnlockable)(object)musicTrack));
					break;
				}
				case BRCType.GraffitiM:
				case BRCType.GraffitiL:
				case BRCType.GraffitiXL:
				{
					string name = ((bRCItem.type != BRCType.GraffitiXL) ? bRCItem.item_name.Substring(14, bRCItem.item_name.Length - 15) : bRCItem.item_name.Substring(15, bRCItem.item_name.Length - 16));
					if (bRCItem.type == BRCType.GraffitiM)
					{
						Core.Instance.stageManager.YesGraffiti((GraffitiSize)1);
					}
					else if (bRCItem.type == BRCType.GraffitiL)
					{
						Core.Instance.stageManager.YesGraffiti((GraffitiSize)2);
					}
					else if (bRCItem.type == BRCType.GraffitiXL)
					{
						Core.Instance.stageManager.YesGraffiti((GraffitiSize)3);
					}
					if (Core.Instance.Data.to_lock.Contains(name))
					{
						Core.Instance.Data.to_lock.Remove(name);
					}
					GraffitiAppEntry unlockable = WorldHandler.instance.graffitiArtInfo.FindByTitle(name).unlockable;
					Core.Instance.SaveManager.CurrentSaveSlot.GetUnlockableDataByUid(((AUnlockable)unlockable).Uid).IsUnlocked = true;
					if (Core.Instance.Data.limitedGraffiti)
					{
						Core.Instance.Data.grafUses[((AUnlockable)unlockable).Uid] = 0;
					}
					notifQueue.Add(new Notification("AppGraffiti", string.Format("{0} ({1} - {2})", Core.Instance.Localizer.GetRawTextValue((Subgroups)0, "COLLECTIBLE_GRAFFITI"), unlockable.Size, unlockable.Title), (AUnlockable)(object)unlockable));
					break;
				}
				case BRCType.Skateboard:
				{
					string name = bRCItem.item_name.Substring(12, bRCItem.item_name.Length - 13);
					Core.Instance.Data.skateboardUnlocked = true;
					if (Core.Instance.stageManager is HideoutManager)
					{
						((HideoutManager)Core.Instance.stageManager).SetSkateboardGarage(open: true);
					}
					MoveStyleSkin skateboardSkin = GetSkateboardSkin(GetSkateboardAssetName(name));
					Core.Instance.SaveManager.CurrentSaveSlot.GetUnlockableDataByUid(((AUnlockable)skateboardSkin).Uid).IsUnlocked = true;
					notifQueue.Add(new Notification("AppArchipelago", Core.Instance.Localizer.GetRawTextValue((Subgroups)0, "VALUE_MOVESTYLE_SKATEBOARD") + " " + bRCItem.item_name.Substring(11), null));
					break;
				}
				case BRCType.InlineSkates:
				{
					string name = bRCItem.item_name.Substring(15, bRCItem.item_name.Length - 16);
					Core.Instance.Data.inlineUnlocked = true;
					if (Core.Instance.stageManager is HideoutManager)
					{
						((HideoutManager)Core.Instance.stageManager).SetInlineGarage(open: true);
					}
					MoveStyleSkin inlineSkin = GetInlineSkin(GetInlineAssetName(name));
					Core.Instance.SaveManager.CurrentSaveSlot.GetUnlockableDataByUid(((AUnlockable)inlineSkin).Uid).IsUnlocked = true;
					notifQueue.Add(new Notification("AppArchipelago", Core.Instance.Localizer.GetRawTextValue((Subgroups)0, "VALUE_MOVESTYLE_INLINE") + " " + bRCItem.item_name.Substring(14), null));
					break;
				}
				case BRCType.BMX:
				{
					string name = bRCItem.item_name.Substring(5, bRCItem.item_name.Length - 6);
					Core.Instance.Data.bmxUnlocked = true;
					if (Core.Instance.stageManager is HideoutManager)
					{
						((HideoutManager)Core.Instance.stageManager).SetBMXGarage(open: true);
					}
					MoveStyleSkin bMXSkin = GetBMXSkin(GetBMXAssetName(name));
					Core.Instance.SaveManager.CurrentSaveSlot.GetUnlockableDataByUid(((AUnlockable)bMXSkin).Uid).IsUnlocked = true;
					notifQueue.Add(new Notification("AppArchipelago", Core.Instance.Localizer.GetRawTextValue((Subgroups)0, "VALUE_MOVESTYLE_BMX") + " " + bRCItem.item_name.Substring(4), null));
					break;
				}
				case BRCType.Outfit:
				{
					string name = bRCItem.item_name.Substring(8, bRCItem.item_name.Length - 9);
					OutfitUnlockable outfitUnlockable = GetOutfitUnlockable(GetOutfitAssetName(name));
					Core.Instance.SaveManager.CurrentSaveSlot.GetUnlockableDataByUid(((AUnlockable)outfitUnlockable).Uid).IsUnlocked = true;
					notifQueue.Add(new Notification("AppArchipelago", Core.Instance.Localizer.GetRawTextValue((Subgroups)0, "COLLECTIBLE_OUTFIT") + " " + bRCItem.item_name.Substring(7), null));
					break;
				}
				case BRCType.Character:
				{
					Core.Instance.SaveManager.CurrentSaveSlot.characterSelectLocked = false;
					Characters val = NameToCharacter(bRCItem.item_name);
					if ((int)Core.Instance.Data.firstCharacter == -1)
					{
						Core.Instance.Data.firstCharacter = val;
					}
					if (Core.Instance.Data.limitedGraffiti)
					{
						if (Core.Instance.Data.sGraffiti == SGraffiti.Separate)
						{
							Core.Instance.Data.grafUses[((object)(Characters)(ref val)).ToString()] = 0;
						}
						else
						{
							Core.Instance.Data.sMax += 5;
						}
					}
					if ((int)val == 8)
					{
						Core.Instance.Data.dummyUnlocked = true;
					}
					Core.Instance.SaveManager.UnlockCharacter(val);
					((App)Core.Instance.PhoneManager.Phone.GetAppInstance<AppGraffiti>()).OnAppRefresh();
					notifQueue.Add(new Notification("AppArchipelago", Core.Instance.Localizer.GetCharacterName(val), null));
					break;
				}
				case BRCType.REP:
				{
					int num = int.Parse(bRCItem.item_name.Substring(0, bRCItem.item_name.Length - 4));
					Core.Instance.Data.fakeRep += num;
					if (Core.Instance.BaseModule.IsPlayingInStage)
					{
						Traverse.Create((object)WorldHandler.instance.GetCurrentPlayer()).Field<float>("rep").Value = Core.Instance.Data.fakeRep;
						Core.Instance.SaveManager.CurrentSaveSlot.GetCurrentStageProgress().reputation = Core.Instance.Data.fakeRep;
						foreach (RandoRequirement requirementCollider in Core.Instance.stageManager.requirementColliders)
						{
							if ((requirementCollider.Needs == RequirementNeeds.REP || requirementCollider.Needs == RequirementNeeds.Both) && Core.Instance.Data.fakeRep >= requirementCollider.Rep)
							{
								requirementCollider.EnableTrigger(RequirementNeeds.REP);
							}
						}
					}
					notifQueue.Add(new Notification("AppArchipelago", bRCItem.item_name, null));
					break;
				}
				case BRCType.Camera:
					WorldHandler.instance.GetCurrentPlayer().LockCameraApp(false);
					notifQueue.Add(new Notification("AppArchipelago", bRCItem.item_name, null));
					break;
				}
				Core.Instance.SaveManager.SaveCurrentSaveSlot();
			}
			else if (item is APItem aPItem)
			{
				notifQueue.Add(new Notification("AppArchipelago", aPItem.item_name + " (" + aPItem.player_name + ")", null));
			}
			else
			{
				notifQueue.Add(new Notification("AppArchipelago", item.item_name + " (" + item.player_name + ")", null));
			}
		}

		public void CountAndCheckSpray()
		{
			if (Core.Instance.Data.sprayCount < 389)
			{
				Core.Instance.Data.sprayCount++;
			}
			Core.Logger.LogInfo((object)$"Spray count is {Core.Instance.Data.sprayCount}");
			if (Core.Instance.Data.sprayCount == 389)
			{
				CheckLocation("graf389");
			}
			else if (Core.Instance.Data.sprayCount % 5 == 0)
			{
				CheckLocation($"graf{Core.Instance.Data.sprayCount}");
			}
		}

		public BRCType GetItemType(string name)
		{
			if (name.Contains("Music ("))
			{
				return BRCType.Music;
			}
			if (name.Contains("Graffiti (M"))
			{
				return BRCType.GraffitiM;
			}
			if (name.Contains("Graffiti (L"))
			{
				return BRCType.GraffitiL;
			}
			if (name.Contains("Graffiti (XL"))
			{
				return BRCType.GraffitiXL;
			}
			if (name.Contains("Skateboard ("))
			{
				return BRCType.Skateboard;
			}
			if (name.Contains("Inline Skates ("))
			{
				return BRCType.InlineSkates;
			}
			if (name.Contains("BMX ("))
			{
				return BRCType.BMX;
			}
			if (name.Contains("Outfit ("))
			{
				return BRCType.Outfit;
			}
			if (name.Contains(" REP"))
			{
				return BRCType.REP;
			}
			if (name.Contains("Camera"))
			{
				return BRCType.Camera;
			}
			return BRCType.Character;
		}

		public MusicTrack GetMusicTrack(string name)
		{
			return Core.Instance.Assets.LoadAssetFromBundle<MusicTrack>("coreassets", "assets/games/phone/appassets/musicplayer/musictrackunlocks/musictrack_" + name + ".asset");
		}

		public string GetMusicAssetName(string name)
		{
			return name switch
			{
				"GET ENUF" => "getenuf", 
				"Chuckin Up" => "chuckinup", 
				"Spectres" => "spectres", 
				"You Can Say Hi" => "youcansayhi", 
				"JACK DA FUNK" => "jackdafunk", 
				"Feel The Funk (Computer Love)" => "feelthefunk", 
				"Big City Life" => "bigcitylife", 
				"I Wanna Kno" => "wannakno", 
				"Plume" => "plume", 
				"Two Days Off" => "twodaysoff", 
				"Scraped On The Way Out" => "scrapedonthewayout", 
				"Last Hoorah" => "lasthoorah", 
				"State of Mind" => "stateofmind", 
				"AGUA" => "agua", 
				"Condensed milk" => "condensedmilk", 
				"Light Switch" => "lightswitch", 
				"Hair Dun Nails Dun" => "hairdunnailsdun", 
				"Precious Thing" => "preciousthing", 
				"Next To Me" => "nexttome", 
				"Refuse" => "refuse", 
				"Iridium" => "iridium", 
				"Funk Express" => "funkexpress", 
				"In The Pocket" => "inthepocket", 
				"Bounce Upon A Time" => "bounceuponatime", 
				"hwbouths" => "hwbouths", 
				"Morning Glow" => "morningglow", 
				"Chromebies" => "chromebies", 
				"watchyaback!" => "watchyaback", 
				"Anime Break" => "missingbreak", 
				"DA PEOPLE" => "dapeople", 
				"Trinitron" => "trinitron", 
				"Operator" => "operator", 
				"Sunshine Popping Mixtape" => "chapter1mixtape", 
				"House Cats Mixtape" => "chapter2mixtape", 
				"Breaking Machine Mixtape" => "chapter3mixtape", 
				"Beastmode Hip Hop Mixtape" => "chapter4mixtape", 
				_ => "?", 
			};
		}

		public MoveStyleSkin GetSkateboardSkin(string name)
		{
			return Core.Instance.Assets.LoadAssetFromBundle<MoveStyleSkin>("in_game_assets", "assets/common assets/vfx/unlockables/skateboardunlockables/" + name + ".asset");
		}

		public string GetSkateboardAssetName(string name)
		{
			return name switch
			{
				"Devon" => "SkateboardDeck2", 
				"Terrence" => "SkateboardDeck3", 
				"Maceo" => "SkateboardDeck4", 
				"Lazer Accuracy" => "SkateboardDeck5", 
				"Death Boogie" => "SkateboardDeck6", 
				"Sylk" => "SkateboardDeck7", 
				"Taiga" => "SkateboardDeck8", 
				"Just Swell" => "SkateboardDeck9", 
				"Mantra" => "SkateboardDeck10", 
				_ => "?", 
			};
		}

		public MoveStyleSkin GetInlineSkin(string name)
		{
			return Core.Instance.Assets.LoadAssetFromBundle<MoveStyleSkin>("in_game_assets", "assets/common assets/vfx/unlockables/inlineunlockables/" + name + ".asset");
		}

		public string GetInlineAssetName(string name)
		{
			return name switch
			{
				"Glaciers" => "InlineSkates2", 
				"Sweet Royale" => "InlineSkates3", 
				"Strawberry Missiles" => "InlineSkates4", 
				"Ice Cold Killers" => "InlineSkates5", 
				"Red Industry" => "InlineSkates6", 
				"Mech Adversary" => "InlineSkates7", 
				"Orange Blasters" => "InlineSkates8", 
				"ck" => "InlineSkates9", 
				"Sharpshooters" => "InlineSkates10", 
				_ => "?", 
			};
		}

		public MoveStyleSkin GetBMXSkin(string name)
		{
			return Core.Instance.Assets.LoadAssetFromBundle<MoveStyleSkin>("in_game_assets", "assets/common assets/vfx/unlockables/bmxunlockables/" + name + ".asset");
		}

		public string GetBMXAssetName(string name)
		{
			return name switch
			{
				"Mr. Taupe" => "BMXBike2", 
				"Gum" => "BMXBike3", 
				"Steel Wheeler" => "BMXBike4", 
				"oyo" => "BMXBike5", 
				"Rigid No.6" => "BMXBike6", 
				"Ceremony" => "BMXBike7", 
				"XXX" => "BMXBike8", 
				"Terrazza" => "BMXBike9", 
				"Dedication" => "BMXBike10", 
				_ => "?", 
			};
		}

		public OutfitUnlockable GetOutfitUnlockable(string name)
		{
			return Core.Instance.Assets.LoadAssetFromBundle<OutfitUnlockable>("in_game_assets", "assets/common assets/vfx/unlockables/playeroutfits/" + name + ".asset");
		}

		public string GetOutfitAssetName(string name)
		{
			return name switch
			{
				"Red - Autumn" => "MetalheadOutfit3", 
				"Red - Winter" => "MetalheadOutfit4", 
				"Tryce - Autumn" => "BlockGuyOutfit3", 
				"Tryce - Winter" => "BlockGuyOutfit4", 
				"Bel - Autumn" => "SpacegirlOutfit3", 
				"Bel - Winter" => "SpacegirlOutfit4", 
				"Vinyl - Autumn" => "VinylOutfit3", 
				"Vinyl - Winter" => "VinylOutfit4", 
				"Solace - Autumn" => "DummyOutfit3", 
				"Solace - Winter" => "DummyOutfit4", 
				"Felix - Autumn" => "LegendFaceOutfit3", 
				"Felix - Winter" => "LegendFaceOutfit4", 
				"Rave - Autumn" => "AngelOutfit3", 
				"Rave - Winter" => "AngelOutfit4", 
				"Mesh - Autumn" => "WideKidOutfit3", 
				"Mesh - Winter" => "WideKidOutfit4", 
				"Shine - Autumn" => "BunGirlOutfit3", 
				"Shine - Winter" => "BunGirlOutfit4", 
				"Rise - Autumn" => "PufferGirlOutfit3", 
				"Rise - Winter" => "PufferGirlOutfit4", 
				"Coil - Autumn" => "RingDudeOutfit3", 
				"Coil - Winter" => "RingDudeOutfit4", 
				_ => "?", 
			};
		}

		public Characters NameToCharacter(string name)
		{
			//IL_030f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0301: Unknown result type (might be due to invalid IL or missing references)
			//IL_030a: 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_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0325: Unknown result type (might be due to invalid IL or missing references)
			//IL_0322: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0306: Unknown result type (might be due to invalid IL or missing references)
			//IL_0314: Unknown result type (might be due to invalid IL or missing references)
			//IL_0319: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_031e: Unknown result type (might be due to invalid IL or missing references)
			return (Characters)(name switch
			{
				"Tryce" => 4, 
				"Bel" => 5, 
				"Vinyl" => 0, 
				"Solace" => 8, 
				"Felix" => 15, 
				"Rave" => 6, 
				"Mesh" => 19, 
				"Shine" => 22, 
				"Rise" => 21, 
				"Coil" => 2, 
				"Frank" => 1, 
				"Rietveld" => 14, 
				"DJ Cyber" => 9, 
				"Eclipse" => 10, 
				"DOT.EXE" => 7, 
				"Devil Theory" => 11, 
				"Flesh Prince" => 13, 
				"Futurism" => 20, 
				"Oldhead" => 16, 
				_ => 3, 
			});
		}

		public Color GetAPItemColor(ItemFlags flag)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected I4, but got Unknown
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			return (Color)((flag - 1) switch
			{
				0 => Core.configColorItemAdvancement.Value, 
				1 => Core.configColorItemNeverExclude.Value, 
				3 => Core.configColorItemTrap.Value, 
				_ => Core.configColorItemFiller.Value, 
			});
		}
	}
	public class Multiworld
	{
		public static int[] AP_VERSION = new int[3] { 0, 5, 0 };

		public bool Authenticated;

		public ArchipelagoSession Session;

		public static List<string> messages = new List<string>();

		public DeathLinkService DeathLinkService = null;

		public bool DeathLinkKilling = false;

		public string DeathLinkReason { get; private set; }

		public void TryGetSlotDataValue(ref int option, Dictionary<string, object> slotData, string key, int defaultValue)
		{
			try
			{
				option = int.Parse(slotData[key].ToString());
			}
			catch (KeyNotFoundException)
			{
				Core.Logger.LogWarning((object)$"No key found for option \"{key}\". Using default value ({defaultValue})");
				option = defaultValue;
			}
		}

		public void TryGetSlotDataValue(ref bool option, Dictionary<string, object> slotData, string key, bool defaultValue)
		{
			try
			{
				option = bool.Parse(slotData[key].ToString());
			}
			catch (KeyNotFoundException)
			{
				Core.Logger.LogWarning((object)$"No key found for option \"{key}\". Using default value ({defaultValue})");
				option = defaultValue;
			}
		}

		public void TryGetSlotDataValue(ref Logic option, Dictionary<string, object> slotData, string key, Logic defaultValue)
		{
			try
			{
				option = (Logic)int.Parse(slotData[key].ToString());
			}
			catch (KeyNotFoundException)
			{
				Core.Logger.LogWarning((object)$"No key found for option \"{key}\". Using default value ({defaultValue})");
				option = defaultValue;
			}
		}

		public void TryGetSlotDataValue(ref MoveStyle option, Dictionary<string, object> slotData, string key, MoveStyle defaultValue)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected I4, but got Unknown
			try
			{
				option = (MoveStyle)int.Parse(slotData[key].ToString());
			}
			catch (KeyNotFoundException)
			{
				Core.Logger.LogWarning((object)$"No key found for option \"{key}\". Using default value ({defaultValue})");
				option = (MoveStyle)(int)defaultValue;
			}
		}

		public void TryGetSlotDataValue(ref SGraffiti option, Dictionary<string, object> slotData, string key, SGraffiti defaultValue)
		{
			try
			{
				option = (SGraffiti)int.Parse(slotData[key].ToString());
			}
			catch (KeyNotFoundException)
			{
				Core.Logger.LogWarning((object)$"No key found for option \"{key}\". Using default value ({defaultValue})");
				option = defaultValue;
			}
		}

		public void TryGetSlotDataValue(ref ScoreDifficulty option, Dictionary<string, object> slotData, string key, ScoreDifficulty defaultValue)
		{
			try
			{
				option = (ScoreDifficulty)int.Parse(slotData[key].ToString());
			}
			catch (KeyNotFoundException)
			{
				Core.Logger.LogWarning((object)$"No key found for option \"{key}\". Using default value ({defaultValue})");
				option = defaultValue;
			}
		}

		public bool Connect(int slotId, string name, string address, string password = null)
		{
			//IL_0564: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Expected O, but got Unknown
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Expected O, but got Unknown
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: 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_0358: Unknown result type (might be due to invalid IL or missing references)
			//IL_035e: Invalid comparison between Unknown and I4
			//IL_03a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ad: Invalid comparison between Unknown and I4
			//IL_03f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f9: Invalid comparison between Unknown and I4
			//IL_0471: Unknown result type (might be due to invalid IL or missing references)
			if (Authenticated)
			{
				return true;
			}
			if (slotId == -1)
			{
				return false;
			}
			if (Core.forbiddenModsLoaded > 0)
			{
				if (Core.forbiddenModsLoaded == 1)
				{
					Core.Instance.UIManager.SetResult("A forbidden mod is loaded. (" + Core.forbiddenGUIDs + ")");
				}
				else
				{
					Core.Instance.UIManager.SetResult($"A forbidden mod is loaded. ({Core.forbiddenModsLoaded} mods)");
				}
				Core.Logger.LogWarning((object)("A forbidden mod is loaded. (" + Core.forbiddenGUIDs + ")"));
				Core.Instance.UIManager.slotButtons[slotId].ChangeState(APSlotButton.SlotState.Disconnected);
				Core.Instance.UIManager.SetStatus(APSlotButton.SlotState.Disconnected);
				return false;
			}
			Core.Logger.LogInfo((object)$"Attempting connection - Slot: {slotId} | Name: {name}");
			Session = ArchipelagoSessionFactory.CreateSession(address, 38281);
			Session.Socket.SocketClosed += new SocketClosedHandler(SocketClosed);
			Session.Socket.ErrorReceived += new ErrorReceivedHandler(ErrorReceived);
			Session.Socket.PacketReceived += new PacketReceivedHandler(PacketReceived);
			Session.Items.ItemReceived += new ItemReceivedHandler(ItemReceived);
			LoginResult val = Session.TryConnectAndLogin("Bomb Rush Cyberfunk", name, (ItemsHandlingFlags)7, new Version(AP_VERSION[0], AP_VERSION[1], AP_VERSION[2]), (string[])null, (string)null, (password == "") ? null : password, true);
			LoginSuccessful val2 = (LoginSuccessful)(object)((val is LoginSuccessful) ? val : null);
			if (val2 != null)
			{
				TryGetSlotDataValue(ref Core.Instance.Data.logic, val2.SlotData, "logic", Logic.Glitchless);
				TryGetSlotDataValue(ref Core.Instance.Data.skipIntro, val2.SlotData, "skip_intro", defaultValue: true);
				TryGetSlotDataValue(ref Core.Instance.Data.skipDreams, val2.SlotData, "skip_dreams", defaultValue: false);
				TryGetSlotDataValue(ref Core.Instance.Data.skipHands, val2.SlotData, "skip_statue_hands", defaultValue: false);
				TryGetSlotDataValue(ref Core.Instance.Data.totalRep, val2.SlotData, "total_rep", 1400);
				TryGetSlotDataValue(ref Core.Instance.Data.endingRep, val2.SlotData, "extra_rep_required", defaultValue: false);
				TryGetSlotDataValue(ref Core.Instance.Data.startingMovestyle, val2.SlotData, "starting_movestyle", (MoveStyle)2);
				TryGetSlotDataValue(ref Core.Instance.Data.junkPhotos, val2.SlotData, "skip_polo_photos", defaultValue: false);
				TryGetSlotDataValue(ref Core.Instance.Data.limitedGraffiti, val2.SlotData, "limited_graffiti", defaultValue: false);
				TryGetSlotDataValue(ref Core.Instance.Data.sGraffiti, val2.SlotData, "small_graffiti_uses", SGraffiti.Separate);
				if (!Core.Instance.SaveManager.DataExists(slotId))
				{
					if ((int)Core.Instance.Data.startingMovestyle == 2)
					{
						Core.Instance.Data.skateboardUnlocked = true;
						Core.Instance.Data.inlineUnlocked = false;
						Core.Instance.Data.bmxUnlocked = false;
					}
					else if ((int)Core.Instance.Data.startingMovestyle == 3)
					{
						Core.Instance.Data.skateboardUnlocked = false;
						Core.Instance.Data.inlineUnlocked = true;
						Core.Instance.Data.bmxUnlocked = false;
					}
					else if ((int)Core.Instance.Data.startingMovestyle == 1)
					{
						Core.Instance.Data.skateboardUnlocked = false;
						Core.Instance.Data.inlineUnlocked = false;
						Core.Instance.Data.bmxUnlocked = true;
					}
					if (Core.Instance.Data.limitedGraffiti)
					{
						if (Core.Instance.Data.sGraffiti == SGraffiti.Separate)
						{
							Dictionary<string, int> grafUses = Core.Instance.Data.grafUses;
							Characters val3 = (Characters)3;
							grafUses[((object)(Characters)(ref val3)).ToString()] = 0;
						}
						else
						{
							Core.Instance.Data.grafUses["S"] = 0;
						}
					}
					TryGetSlotDataValue(ref Core.Instance.Data.damageMultiplier, val2.SlotData, "damage_multiplier", 1);
					TryGetSlotDataValue(ref Core.Instance.Data.scoreDifficulty, val2.SlotData, "score_difficulty", ScoreDifficulty.Normal);
					try
					{
						Core.configDontSavePhotos.Value = bool.Parse(val2.SlotData["dont_save_photos"].ToString());
					}
					catch (KeyNotFoundException)
					{
						Core.Logger.LogWarning((object)"No key found for option \"dont_save_photos\". Ignored.");
					}
					TryGetSlotDataValue(ref Core.Instance.Data.deathLink, val2.SlotData, "death_link", defaultValue: false);
				}
				Core.Instance.LocationManager.locations = ((JToken)(JObject)val2.SlotData["locations"]).ToObject<Dictionary<string, long>>();
				Authenticated = true;
				if (Core.Instance.Data.deathLink)
				{
					EnableDeathLink();
				}
				messages.Clear();
				Core.Instance.Data.slot_name = name;
				Core.Instance.Data.host_name = address;
				Core.Instance.Data.password = password;
				Core.Instance.SaveManager.currentSlot = slotId;
				Core.Instance.SaveManager.SaveData();
				Core.Instance.UIManager.slotButtons[slotId].ChangeState(APSlotButton.SlotState.Connected);
				Core.Instance.UIManager.SetResult("Successfully connected to server as player \"" + name + "\".");
				Core.Instance.UIManager.SetStatus(APSlotButton.SlotState.Connected);
				((Component)Core.Instance.UIManager.APMenuChat).gameObject.SetActive(true);
				Core.Logger.LogInfo((object)("Successfully connected to server as player \"" + name + "\"."));
			}
			else
			{
				LoginFailure val4 = (LoginFailure)(object)((val is LoginFailure) ? val : null);
				if (val4 != null)
				{
					Authenticated = false;
					Core.Logger.LogError((object)string.Join("\n", val4.Errors));
					Core.Instance.UIManager.SetResult(string.Join("\n", val4.Errors));
					Session.Socket.DisconnectAsync();
					Session = null;
					DeathLinkService = null;
					Core.Instance.UIManager.slotButtons[slotId].ChangeState(APSlotButton.SlotState.Disconnected);
					Core.Instance.UIManager.SetStatus(APSlotButton.SlotState.Disconnected);
				}
			}
			return val.Successful;
		}

		public void Disconnect()
		{
			if (Session != null && Session.Socket != null)
			{
				Session.Socket.DisconnectAsync();
			}
			messages.Clear();
			((Component)Core.Instance.UIManager.APMenuChat).gameObject.SetActive(false);
			Session = null;
			DeathLinkService = null;
			Authenticated = false;
		}

		public void SocketClosed(string reason)
		{
			Core.Logger.LogError((object)("Lost connection to Archipelago server. " + reason));
			Disconnect();
		}

		public void ErrorReceived(Exception e, string message)
		{
			Core.Logger.LogError((object)message);
			if (e != null)
			{
				Core.Logger.LogError((object)e.ToString());
			}
		}

		public void PacketReceived(ArchipelagoPacketBase packet)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Expected I4, but got Unknown
			//IL_0416: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0367: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02df: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f8: Expected I4, but got Unknown
			//IL_0304: Unknown result type (might be due to invalid IL or missing references)
			//IL_0325: Unknown result type (might be due to invalid IL or missing references)
			//IL_0346: Unknown result type (might be due to invalid IL or missing references)
			if ((int)packet.PacketType != 6)
			{
				return;
			}
			if (messages.Count >= PhoneManager.maxMessages)
			{
				messages.RemoveAt(0);
			}
			PrintJsonPacket val = (PrintJsonPacket)(object)((packet is PrintJsonPacket) ? packet : null);
			string text = "";
			string text2 = "<color=#FFFFFFFF>";
			if (Core.configPlayerOtherNotifs.Value && val.Data[0].Type == (JsonMessagePartType?)1 && Session.Players.GetPlayerName(int.Parse(val.Data[0].Text)) == Core.Instance.Data.slot_name && val.Data[1].Text == " sent ")
			{
				string itemName = Session.Items.GetItemName(long.Parse(val.Data[2].Text), Session.Players.GetPlayerInfo(val.Data[2].Player.Value).Game);
				string playerAlias = Session.Players.GetPlayerAlias(int.Parse(val.Data[4].Text));
				Core.Instance.LocationManager.notifQueue.Add(new Notification("AppArchipelago", itemName + " (" + playerAlias + ")", null));
			}
			JsonMessagePart[] data = val.Data;
			foreach (JsonMessagePart val2 in data)
			{
				switch (val2.Type)
				{
				case 0L:
				{
					text2 = ((!(Session.Players.GetPlayerName(int.Parse(val2.Text)) == Core.Instance.Data.slot_name)) ? ("<color=#" + ColorUtility.ToHtmlStringRGBA(Core.configColorPlayerOther.Value) + ">") : ("<color=#" + ColorUtility.ToHtmlStringRGBA(Core.configColorPlayerSelf.Value) + ">"));
					if (int.TryParse(val2.Text, out var result3))
					{
						string text5 = Session.Players.GetPlayerAlias(result3) ?? $"Slot: {result3}";
						text = text + text2 + text5 + "</color>";
					}
					else
					{
						text = text + text2 + val2.Text + "</color>";
					}
					break;
				}
				case 2L:
				{
					text2 = val2.Flags switch
					{
						0L => "<color=#" + ColorUtility.ToHtmlStringRGBA(Core.configColorItemAdvancement.Value) + ">", 
						1L => "<color=#" + ColorUtility.ToHtmlStringRGBA(Core.configColorItemNeverExclude.Value) + ">", 
						3L => "<color=#" + ColorUtility.ToHtmlStringRGBA(Core.configColorItemTrap.Value) + ">", 
						_ => "<color=#" + ColorUtility.ToHtmlStringRGBA(Core.configColorItemFiller.Value) + ">", 
					};
					if (long.TryParse(val2.Text, out var result2))
					{
						string text4 = Session.Items.GetItemName(result2, Session.Players.GetPlayerInfo(val2.Player.Value).Game) ?? $"Item: {result2}";
						text = text + text2 + text4 + "</color>";
					}
					else
					{
						text = text + text2 + val2.Text + "</color>";
					}
					break;
				}
				case 4L:
				{
					text2 = "<color=#" + ColorUtility.ToHtmlStringRGBA(Core.configColorLocation.Value) + ">";
					if (long.TryParse(val2.Text, out var result))
					{
						string text3 = Session.Locations.GetLocationNameFromId(result, Session.Players.GetPlayerInfo(val2.Player.Value).Game) ?? $"Location: {result}";
						text = text + text2 + text3 + "</color>";
					}
					else
					{
						text = text + text2 + val2.Text + "</color>";
					}
					break;
				}
				default:
					text += val2.Text;
					break;
				}
			}
			messages.Add(text);
			((TMP_Text)Core.Instance.UIManager.APMenuChat).text = string.Join("\n", messages.ToArray());
			if ((Object)(object)Core.Instance.PhoneManager.appArchipelago != (Object)null)
			{
				Core.Instance.PhoneManager.appArchipelago.UpdateText();
			}
		}

		public void ItemReceived(ReceivedItemsHelper helper)
		{
			if (helper.Index > Core.Instance.Data.index)
			{
				ItemInfo val = helper.PeekItem();
				string text = ((Session.Players.GetPlayerAlias(PlayerInfo.op_Implicit(val.Player)) == "") ? "?" : Session.Players.GetPlayerAlias(PlayerInfo.op_Implicit(val.Player)));
				string text2 = $"Received item: {val.ItemName} | Type: {Core.Instance.LocationManager.GetItemType(val.ItemName)}";
				if (text != Core.Instance.Data.slot_name)
				{
					text2 = text2 + " | Player: " + text;
				}
				Core.Logger.LogInfo((object)text2);
				BRCItem item = new BRCItem
				{
					item_name = val.ItemName,
					type = Core.Instance.LocationManager.GetItemType(val.ItemName),
					player_name = Core.Instance.Data.slot_name
				};
				Core.Instance.LocationManager.itemQueue.Add(item);
				Core.Instance.Data.index++;
			}
			helper.DequeueItem();
		}

		public void GetRandomHint()
		{
			if (Authenticated)
			{
				ReadOnlyCollection<long> allMissingLocations = Session.Locations.AllMissingLocations;
				IEnumerable<long> second = from h in ((IDataStorageWrapper)Session.DataStorage).GetHints((int?)null, (int?)null)
					where h.FindingPlayer == Session.ConnectionInfo.Slot
					select h.LocationId;
				long[] array = allMissingLocations.Except(second).ToArray();
				if (array.Any())
				{
					long num = array[Random.Range(0, array.Length)];
					Session.Locations.ScoutLocationsAsync(true, new long[1] { num });
					Core.Instance.LocationManager.notifQueue.Add(new Notification("AppArchipelago", Core.Instance.Localizer.GetRawTextValue((Subgroups)0, "APP_HINT"), null));
				}
				else
				{
					Core.Logger.LogWarning((object)"No locations available to hint.");
				}
			}
		}

		public void EnableDeathLink()
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			if (Session != null)
			{
				if (DeathLinkService == null)
				{
					DeathLinkService = DeathLinkProvider.CreateDeathLinkService(Session);
					DeathLinkService.OnDeathLinkReceived += new DeathLinkReceivedHandler(DeathLinkReceived);
				}
				DeathLinkService.EnableDeathLink();
			}
		}

		public void DisableDeathLink()
		{
			if (DeathLinkService != null)
			{
				DeathLinkService.DisableDeathLink();
			}
		}

		public void DeathLinkReceived(DeathLink dl)
		{
			if (Core.Instance.BaseModule.IsPlayingInStage && !Core.Instance.BaseModule.IsLoading && !DeathLinkKilling)
			{
				DeathLinkKilling = true;
				string text = dl.Cause;
				if (text == null)
				{
					text = dl.Source + " has died.";
				}
				DeathLinkReason = text;
			}
			else
			{
				Core.Logger.LogWarning((object)"Received DeathLink, but player cannot be killed right now.");
			}
		}

		public void SendCompletion()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			if (Authenticated)
			{
				StatusUpdatePacket val = new StatusUpdatePacket
				{
					Status = (ArchipelagoClientState)30
				};
				Session.Socket.SendPacket((ArchipelagoPacketBase)(object)val);
			}
		}
	}
	public class PhoneManager
	{
		public static int maxMessages = 8;

		public AppArchipelago appArchipelago;

		public AppEncounter appEncounter;

		public Phone Phone
		{
			get
			{
				if (Core.Instance.BaseModule.IsPlayingInStage)
				{
					return Traverse.Create((object)WorldHandler.instance.GetCurrentPlayer()).Field<Phone>("phone").Value;
				}
				return null;
			}
		}

		public static Color PhoneBlue => new Color(0.224f, 0.302f, 0.624f);

		public static Color PhoneYellow => new Color(0.882f, 0.953f, 0.345f);

		public static Color PhoneOrange => new Color(0.978f, 0.424f, 0.216f);

		public void DoAppSetup()
		{
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Expected O, but got Unknown
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_05bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d3: Expected O, but got Unknown
			//IL_0601: Unknown result type (might be due to invalid IL or missing references)
			//IL_0622: Unknown result type (might be due to invalid IL or missing references)
			//IL_0650: Unknown result type (might be due to invalid IL or missing references)
			//IL_069b: Unknown result type (might be due to invalid IL or missing references)
			//IL_074c: Unknown result type (might be due to invalid IL or missing references)
			//IL_07c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_07f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_082f: Unknown result type (might be due to invalid IL or missing references)
			//IL_088b: Unknown result type (might be due to invalid IL or missing references)
			//IL_09e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a44: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b7f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bf7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c8f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d9b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0dea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ea0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0eca: Unknown result type (might be due to invalid IL or missing references)
			//IL_0f6c: Unknown result type (might be due to invalid IL or missing references)
			//IL_100a: Unknown result type (might be due to invalid IL or missing references)
			//IL_10a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_115b: Unknown result type (might be due to invalid IL or missing references)
			//IL_11fd: Unknown result type (might be due to invalid IL or missing references)
			if (Core.Instance.BaseModule.IsPlayingInStage && !((Object)(object)appArchipelago != (Object)null))
			{
				appArchipelago = Object.Instantiate<GameObject>(((Component)((Component)((Component)Phone).GetComponentInChildren<AppEmail>(true)).transform).gameObject, ((Component)((Component)Phone).GetComponentInChildren<AppEmail>(true)).transform.parent).AddComponent<AppArchipelago>();
				((Object)((Component)appArchipelago).gameObject).name = "AppArchipelago";
				Object.DestroyImmediate((Object)(object)((Component)appArchipelago).GetComponent<AppEmail>());
				Traverse val = Traverse.Create((object)appArchipelago);
				val.Method("Awake", Array.Empty<object>()).GetValue();
				val.Field<Phone>("<MyPhone>k__BackingField").Value = Phone;
				val.Field<AUnlockable[]>("m_Unlockables").Value = (AUnlockable[])(object)new AUnlockable[0];
				Object.DestroyImmediate((Object)(object)((Component)((Transform)((App)appArchipelago).Content).Find("EmailScroll")).gameObject);
				Object.DestroyImmediate((Object)(object)((Component)((Transform)((App)appArchipelago).Content).Find("MessagePanel")).gameObject);
				Object.Destroy((Object)(object)((Component)((Transform)((App)appArchipelago).Content).Find("Overlay")).GetComponentInChildren<TMProLocalizationAddOn>());
				appArchipelago.title = ((Component)((Transform)((App)appArchipelago).Content).Find("Overlay")).GetComponentInChildren<TextMeshProUGUI>();
				((TMP_Text)appArchipelago.title).text = Core.Instance.Localizer.GetRawTextValue((Subgroups)0, "APP_ARCHIPELAGO_HEADER_DEFAULT");
				Image componentInChildren = ((Component)((Transform)((App)appArchipelago).Content).Find("Overlay").Find("Icons").Find("AppIcon")).GetComponentInChildren<Image>();
				componentInChildren.sprite = UIManager.bundle.LoadAsset<Sprite>("assets/archipelago.png");
				GameObject val2 = new GameObject
				{
					name = "Messages",
					layer = 24
				};
				val2.transform.parent = ((Component)((App)appArchipelago).Content).transform;
				val2.transform.localPosition = Vector3.zero;
				val2.transform.SetAsFirstSibling();
				appArchipelago.text = val2.AddComponent<TextMeshProUGUI>();
				appArchipelago.UpdateText();
				((TMP_Text)appArchipelago.text).fontSize = 68f;
				((TMP_Text)appArchipelago.text).font = UIManager.font;
				((TMP_Text)appArchipelago.text).alignment = (TextAlignmentOptions)1025;
				((TMP_Text)appArchipelago.text).enableWordWrapping = true;
				((TMP_Text)appArchipelago.text).transform.localPosition = new Vector3(0f, 250f, 0f);
				((TMP_Text)appArchipelago.text).transform.localScale = Vector3.one;
				((Component)appArchipelago.text).GetComponent<RectTransform>().sizeDelta = new Vector2(1000f, 1560f);
				TMProFontLocalizer val3 = ((Component)appArchipelago.text).gameObject.AddComponent<TMProFontLocalizer>();
				Traverse val4 = Traverse.Create((object)val3);
				val4.Field<TextMeshProUGUI>("textMesh").Value = appArchipelago.text;
				val4.Field<GameFontType>("gameFontType").Value = Core.MainFont;
				appArchipelago.chatBackground = Object.Instantiate<GameObject>(((Component)((Transform)((App)Phone.GetAppInstance<AppHomeScreen>()).Content).Find("BottomView").Find("ButtonContainer").Find("Selector")
					.Find("Background")).gameObject, (Transform)(object)((App)appArchipelago).Content);
				appArchipelago.chatBackground.transform.localPosition = new Vector3(100f, -650f, 0f);
				((Object)appArchipelago.chatBackground).name = "Chat Bottom";
				appEncounter = Object.Instantiate<GameObject>(((Component)appArchipelago).gameObject, ((Component)appArchipelago).transform.parent).AddComponent<AppEncounter>();
				((Object)((Component)appEncounter).gameObject).name = "AppEncounter";
				Object.Destroy((Object)(object)((Component)appEncounter).GetComponent<AppArchipelago>());
				Traverse val5 = Traverse.Create((object)appEncounter);
				val5.Method("Awake", Array.Empty<object>()).GetValue();
				val5.Field<Phone>("<MyPhone>k__BackingField").Value = Phone;
				val5.Field<AUnlockable[]>("m_Unlockables").Value = (AUnlockable[])(object)new AUnlockable[0];
				((Component)((Transform)((App)appEncounter).Content).Find("Overlay").Find("Icons").Find("AppIcon")).GetComponent<Image>().sprite = UIManager.bundle.LoadAsset<Sprite>("assets/encounter.png");
				appEncounter.headerText = ((Component)((Transform)((App)appEncounter).Content).Find("Overlay")).GetComponentInChildren<TextMeshProUGUI>();
				((TMP_Text)appEncounter.headerText).text = Core.Instance.Localizer.GetRawTextValue((Subgroups)0, "APP_ENCOUNTER_HEADER");
				appEncounter.Init();
				Object.Destroy((Object)(object)((Component)((Transform)((App)appEncounter).Content).Find("Messages")).gameObject);
				GameObject gameObject = ((Component)((Transform)((App)appEncounter).Content).Find("Chat Bottom")).gameObject;
				((Object)gameObject).name = "Text Background";
				gameObject.transform.Rotate(0f, 0f, 180f);
				gameObject.transform.localPosition = new Vector3(-100f, 500f, 0f);
				GameObject val6 = new GameObject
				{
					name = "Background Image",
					layer = 24
				};
				val6.transform.SetParent((Transform)(object)((App)appEncounter).Content);
				val6.transform.localPosition = new Vector3(250f, -250f, 0f);
				val6.transform.localScale = new Vector3(12f, 12f, 12f);
				val6.AddComponent<Image>().sprite = UIManager.bundle.LoadAsset<Sprite>("assets/encounter_large.png");
				((Graphic)val6.GetComponent<Image>()).color = PhoneBlue;
				GameObject val7 = Object.Instantiate<GameObject>(appArchipelago.chatBackground, (Transform)(object)((App)appEncounter).Content);
				Object.DestroyImmediate((Object)(object)val7.GetComponent<Image>());
				val7.transform.localPosition = new Vector3(75f, 500f, 0f);
				((Object)val7).name = "Current Encounter";
				appEncounter.currentText = val7.AddComponent<TextMeshProUGUI>();
				Traverse val8 = Traverse.Create((object)((Component)appEncounter.currentText).gameObject.AddComponent<TMProFontLocalizer>());
				val8.Field<GameFontType>("gameFontType").Value = Core.PhoneFont;
				val8.Field<TextMeshProUGUI>("textMesh").Value = appEncounter.currentText;
				((TMP_Text)appEncounter.currentText).alignment = (TextAlignmentOptions)513;
				((TMP_Text)appEncounter.currentText).fontSize = 80f;
				((Graphic)appEncounter.currentText).color = PhoneYellow;
				((TMP_Text)appEncounter.currentText).text = Core.Instance.Localizer.GetRawTextValue((Subgroups)0, "APP_ENCOUNTER_TOP");
				appEncounter.messageText = Object.Instantiate<GameObject>(((Component)appEncounter.currentText).gameObject, (Transform)(object)((App)appEncounter).Content).GetComponent<TextMeshProUGUI>();
				((Component)appEncounter.messageText).GetComponent<RectTransform>().sizeDelta = new Vector2(-200f, 1f);
				((TMP_Text)appEncounter.messageText).alignment = (TextAlignmentOptions)257;
				((Graphic)appEncounter.messageText).color = Color.white;
				((TMP_Text)appEncounter.messageText).enableWordWrapping = true;
				((TMP_Text)appEncounter.messageText).transform.localPosition = new Vector3(0f, -550f, 0f);
				appEncounter.confirmText = Object.Instantiate<GameObject>(((Component)appEncounter.currentText).gameObject, (Transform)(object)((App)appEncounter).Content).GetComponent<TextMeshProUGUI>();
				((TMP_Text)appEncounter.confirmText).alignment = (TextAlignmentOptions)516;
				((Graphic)appEncounter.confirmText).color = PhoneOrange;
				((TMP_Text)appEncounter.confirmText).text = Core.Instance.Localizer.GetRawTextValue((Subgroups)0, "APP_ENCOUNTER_CONFIRM");
				appEncounter.confirmArrow = Object.Instantiate<GameObject>(((Component)((Transform)((App)appEncounter).Content).Find("Overlay").Find("Icons").Find("Arrow")).gameObject, (Transform)(object)((App)appEncounter).Content);
				appEncounter.confirmArrow.transform.Rotate(0f, 0f, 180f);
				((Object)appEncounter.confirmArrow).name = "Arrow Right";
				appArchipelago.headerArrow = ((Component)((Transform)((App)appArchipelago).Content).Find("Overlay").Find("Icons").Find("Arrow")).gameObject;
				appArchipelago.arrowRight = Object.Instantiate<GameObject>(appArchipelago.headerArrow, (Transform)(object)((App)appArchipelago).Content);
				appArchipelago.arrowRight.transform.Rotate(0f, 0f, 180f);
				appArchipelago.arrowRight.transform.localPosition = new Vector3(450f, -650f, 0f);
				((Object)appArchipelago.arrowRight).name = "Arrow Right";
				GameObject val9 = Object.Instantiate<GameObject>(appArchipelago.chatBackground, (Transform)(object)((App)appArchipelago).Content);
				Object.DestroyImmediate((Object)(object)val9.GetComponent<Image>());
				val9.transform.localPosition = new Vector3(-180f, -650f, 0f);
				((Object)val9).name = "Chat Swap Text";
				appArchipelago.chatSwap = val9.AddComponent<TextMeshProUGUI>();
				val8 = Traverse.Create((object)((Component)appArchipelago.chatSwap).gameObject.AddComponent<TMProFontLocalizer>());
				val8.Field<GameFontType>("gameFontType").Value = Core.PhoneFont;
				val8.Field<TextMeshProUGUI>("textMesh").Value = appArchipelago.chatSwap;
				((TMP_Text)appArchipelago.chatSwap).alignment = (TextAlignmentOptions)516;
				((TMP_Text)appArchipelago.chatSwap).fontSize = 70f;
				((TMP_Text)appArchipelago.chatSwap).text = Core.Instance.Localizer.GetRawTextValue((Subgroups)0, "APP_ARCHIPELAGO_NAVIGATION_OPTIONS");
				appArchipelago.optionsBackground = Object.Instantiate<GameObject>(appArchipelago.chatBackground.gameObject, (Transform)(object)((App)appArchipelago).Content);
				appArchipelago.optionsBackground.transform.Rotate(0f, 0f, 180f);
				appArchipelago.optionsBackground.transform.localPosition = new Vector3(-90f, -650f, 0f);
				((Object)appArchipelago.optionsBackground).name = "Options Bottom";
				appArchipelago.optionsBackground.SetActive(false);
				appArchipelago.arrowLeft = Object.Instantiate<GameObject>(appArchipelago.headerArrow, (Transform)(object)((App)appArchipelago).Content);
				appArchipelago.arrowLeft.transform.localPosition = new Vector3(-440f, -650f, 0f);
				((Object)appArchipelago.arrowLeft).name = "Arrow Left";
				appArchipelago.arrowLeft.SetActive(false);
				appArchipelago.optionsSwap = Object.Instantiate<GameObject>(((Component)appArchipelago.chatSwap).gameObject, (Transform)(object)((App)appArchipelago).Content).GetComponent<TextMeshProUGUI>();
				((TMP_Text)appArchipelago.optionsSwap).alignment = (TextAlignmentOptions)513;
				((TMP_Text)appArchipelago.optionsSwap).transform.localPosition = new Vector3(200f, -650f, 0f);
				((TMP_Text)appArchipelago.optionsSwap).text = "Chat";
				((Object)((Component)appArchipelago.optionsSwap).gameObject).name = "Options Swap Text";
				((Component)appArchipelago.optionsSwap).gameObject.SetActive(false);
				appArchipelago.optionCurrentText = Object.Instantiate<GameObject>(((Component)appArchipelago.text).gameObject, (Transform)(object)((App)appArchipelago).Content).GetComponent<TextMeshProUGUI>();
				((TMP_Text)appArchipelago.optionCurrentText).alignment = (TextAlignmentOptions)513;
				((TMP_Text)appArchipelago.optionCurrentText).enableAutoSizing = true;
				((TMP_Text)appArchipelago.optionCurrentText).fontSizeMax = 90f;
				((TMP_Text)appArchipelago.optionCurrentText).fontSizeMin = 70f;
				((TMP_Text)appArchipelago.optionCurrentText).lineSpacing = 24f;
				((TMP_Text)appArchipelago.optionCurrentText).transform.localPosition = new Vector3(0f, 50f, 0f);
				Traverse.Create((object)((Component)appArchipelago.optionCurrentText).GetComponent<TMProFontLocalizer>()).Field<GameFontType>("gameFontType").Value = Core.PhoneFont;
				((Component)appArchipelago.optionCurrentText).GetComponent<RectTransform>().sizeDelta = new Vector2(900f, 1560f);
				((Object)((Component)appArchipelago.optionCurrentText).gameObject).name = "Current Option";
				((Component)appArchipelago.optionCurrentText).gameObject.SetActive(false);
				appArchipelago.optionPrevText = Object.Instantiate<GameObject>(((Component)appArchipelago.optionCurrentText).gameObject, (Transform)(object)((App)appArchipelago).Content).GetComponent<TextMeshProUGUI>();
				((TMP_Text)appArchipelago.optionPrevText).alignment = (TextAlignmentOptions)8194;
				((TMP_Text)appArchipelago.optionPrevText).enableAutoSizing = false;
				((TMP_Text)appArchipelago.optionPrevText).fontSize = 60f;
				((Graphic)appArchipelago.optionPrevText).color = PhoneBlue;
				((TMP_Text)appArchipelago.optionPrevText).transform.localPosition = new Vector3(0f, 500f, 0f);
				((Object)((Component)appArchipelago.optionPrevText).gameObject).name = "Prev Option";
				((Component)appArchipelago.optionPrevText).gameObject.SetActive(false);
				appArchipelago.optionNextText = Object.Instantiate<GameObject>(((Component)appArchipelago.optionPrevText).gameObject, (Transform)(object)((App)appArchipelago).Content).GetComponent<TextMeshProUGUI>();
				((TMP_Text)appArchipelago.optionNextText).alignment = (TextAlignmentOptions)1026;
				((TMP_Text)appArchipelago.optionNextText).transform.localPosition = new Vector3(0f, 350f, 0f);
				((Object)((Component)appArchipelago.optionNextText).gameObject).name = "Next Option";
				((Component)appArchipelago.optionNextText).gameObject.SetActive(false);
				appArchipelago.optionChangeText = Object.Instantiate<GameObject>(((Component)appArchipelago.chatSwap).gameObject, (Transform)(object)((App)appArchipelago).Content).GetComponent<TextMeshProUGUI>();
				((TMP_Text)appArchipelago.optionChangeText).text = Core.Instance.Localizer.GetRawTextValue((Subgroups)0, "APP_ARCHIPELAGO_NAVIGATION_CHANGE");
				((Graphic)appArchipelago.optionChangeText).color = PhoneOrange;
				((TMP_Text)appArchipelago.optionChangeText).fontSize = 65f;
				((Object)((Component)appArchipelago.optionChangeText).gameObject).name = "Option Change Text";
				((Component)appArchipelago.optionChangeText).gameObject.SetActive(false);
				appArchipelago.optionChangeArrow = Object.Instantiate<GameObject>(appArchipelago.arrowRight.gameObject, (Transform)(object)((App)appArchipelago).Content);
				appArchipelago.optionChangeArrow.transform.localScale = new Vector3(0.75f, 0.75f, 0.75f);
				((Object)appArchipelago.optionChangeArrow.gameObject).name = "Option Change Arrow";
				appArchipelago.optionChangeArrow.gameObject.SetActive(false);
				appArchipelago.optionDownArrow = Object.Instantiate<GameObject>(((Component)((Transform)((App)Phone.GetAppInstance<AppHomeScreen>()).Content).Find("BottomView").Find("OtherElements").Find("ArrowsContainer")
					.Find("ArrowDown")).gameObject, (Transform)(object)((App)appArchipelago).Content);
				appArchipelago.optionDownArrow.transform.localPosition = new Vector3(0f, -500f, 0f);
				((Object)appArchipelago.optionDownArrow).name = "Arrow Down";
				appArchipelago.optionDownArrow.gameObject.SetActive(false);
				appArchipelago.optionUpArrow = Object.Instantiate<GameObject>(appArchipelago.optionDownArrow, (Transform)(object)((App)appArchipelago).Content);
				appArchipelago.optionUpArrow.transform.Rotate(0f, 0f, 180f);
				appArchipelago.optionUpArrow.transform.localPosition = new Vector3(0f, 600f, 0f);
				((Object)appArchipelago.optionUpArrow).name = "Arrow Up";
				appArchipelago.optionUpArrow.gameObject.SetActive(false);
				HomeScreenApp val10 = ScriptableObject.CreateInstance<HomeScreenApp>();
				((Object)val10).name = "AppEncounter";
				Traverse val11 = Traverse.Create((object)val10);
				val11.Field<HomeScreenAppType>("appType").Value = (HomeScreenAppType)0;
				val11.Field<string>("m_AppName").Value = "AppEncounter";
				val11.Field<string>("m_DisplayName").Value = "APP_ENCOUNTER_HEADER";
				val11.Field<Sprite>("m_AppIcon").Value = UIManager.bundle.LoadAsset<Sprite>("assets/encounter.png");
				HomeScreenApp val12 = ScriptableObject.CreateInstance<HomeScreenApp>();
				((Object)val12).name = "AppArchipelago";
				Traverse val13 = Traverse.Create((object)val12);
				val13.Field<HomeScreenAppType>("appType").Value = (HomeScreenAppType)0;
				val13.Field<string>("m_AppName").Value = "AppArchipelago";
				val13.Field<string>("m_DisplayName").Value = "APP_ARCHIPELAGO_HEADER_DEFAULT";
				val13.Field<Sprite>("m_AppIcon").Value = UIManager.bundle.LoadAsset<Sprite>("assets/archipelago.png");
				Traverse.Create((object)Phone).Field<Dictionary<string, App>>("<AppInstances>k__BackingField").Value.Add("AppEncounter", (App)(object)appEncounter);
				Traverse.Create((object)Phone.GetAppInstance<AppHomeScreen>()).Method("AddApp", new object[1] { val10 }).GetValue();
				Traverse.Create((object)Phone).Field<Dictionary<string, App>>("<AppInstances>k__BackingField").Value.Add("AppArchipelago", (App)(object)appArchipelago);
				Traverse.Create((object)Phone.GetAppInstance<AppHomeScreen>()).Method("AddApp", new object[1] { val12 }).GetValue();
				GameObject gameObject2 = ((Component)val.Property("Notification", (object[])null).Field<GameObject>("appNotificationPanel_Main").Value.transform.parent).gameObject;
				GameObject gameObject3 = ((Component)val.Property("Notification", (object[])null).Field<GameObject>("appNotificationPanel_Outside").Value.transform.parent).gameObject;
				GameObject val14 = Object.Instantiate<GameObject>(((Component)gameObject2.transform.Find("GraffitiNotification")).gameObject, gameObject2.transform);
				GameObject val15 = Object.Instantiate<GameObject>(((Component)gameObject3.transform.Find("GraffitiNotification")).gameObject, gameObject3.transform);
				val14.GetComponentInChildren<Image>().sprite = UIManager.bundle.LoadAsset<Sprite>("assets/notification.png");
				((Component)val15.transform.Find("ActionImage")).GetComponent<Image>().sprite = UIManager.bundle.LoadAsset<Sprite>("assets/notification.png");
				val.Property("Notification", (object[])null).Field<GameObject>("appNotificationPanel_Main").Value = val14;
				val.Property("Notification", (object[])null).Field<GameObject>("appNotificationPanel_Outside").Value = val15;
				val.Property("Notification", (object[])null).Field<TextMeshProUGUI>("topBarText_Main").Value = val14.GetComponentInChildren<TextMeshProUGUI>();
				val.Property("Notification", (object[])null).Field<TextMeshProUGUI>("topBarText_Outside").Value = val15.GetComponentInChildren<TextMeshProUGUI>();
			}
		}
	}
	internal static class Requirements
	{
		public const int grafSLimit = 5;

		public const int grafMLimit = 7;

		public const int grafLLimit = 6;

		public const int grafXLLimit = 4;

		public static RepValues HideoutStoryRep = new RepValues(20, 20);

		public static RepValues DownhillChallenge1Rep = new RepValues(30, 50);

		public static RepValues DownhillChallenge2Rep = new RepValues(38, 58);

		public static RepValues DownhillChallenge3Rep = new RepValues(45, 65);

		public static RepValues DownhillCrewWallRep = new RepValues(70, 90);

		public static ScoreValues DownhillCrewBattleScore = new ScoreValues(60000, 750000, 1500000, 2250000, 3000000);

		public static RepValues DownhillOldheadRep = new RepValues(100, 120);

		public static ScoreValues DownhillRaveScore = new ScoreValues(50000, 375000, 750000, 1500000, 3000000);

		public static RepValues SquareEclipseRep = new RepValues(60, 180);

		public static RepValues SquareOldheadRep = new RepValues(120, 380);

		public static RepValues TowerChallenge1Rep = new RepValues(8, 188);

		public static RepValues TowerChallenge2Rep = new RepValues(20, 200);

		public static ScoreValues TowerChallenge2Score = new ScoreValues(25000, 50000, 100000, 250000, 400000);

		public static RepValues TowerChallenge3Rep = new RepValues(40, 220);

		public static RepValues TowerEscherRep = new RepValues(80, 260);

		public static RepValues TowerCrewWallRep = new RepValues(100, 280);

		public static ScoreValues TowerCrewBattleScore = new ScoreValues(150000, 1250000, 2500000, 3500000, 5000000);

		public static RepValues TowerOldhead1Rep = new RepValues(70, 250);

		public static RepValues TowerOldhead2Rep = new RepValues(140, 320);

		public static ScoreValues TowerMeshScore = new ScoreValues(70000, 125000, 250000, 500000, 700000);

		public static RepValues MallChallenge1Rep = new RepValues(54, 434);

		public static RepValues MallChallenge2Rep = new RepValues(62, 442);

		public static RepValues MallChallenge3Rep = new RepValues(70, 450);

		public static RepValues MallChallenge4Rep = new RepValues(78, 458);

		public static ScoreValues MallChallenge4Score = new ScoreValues(100000, 375000, 750000, 1500000, 2500000);

		public static RepValues MallCrewWallRep = new RepValues(111, 491);

		public static ScoreValues MallCrewBattleScore = new ScoreValues(300000, 1500000, 3000000, 5000000, 6500000);

		public static RepValues MallOldhead1Rep = new RepValues(150, 530);

		public static RepValues MallOldhead2Rep = new RepValues(200, 580);

		public static RepValues PyramidGateRep = new RepValues(40, 620);

		public static RepValues PyramidChallenge1Rep = new RepValues(50, 630);

		public static ScoreValues PyramidChallenge1Score = new ScoreValues(70000, 200000, 400000, 700000, 900000);

		public static RepValues PyramidChallenge2Rep = new RepValues(60, 640);

		public static RepValues PyramidChallenge3Rep = new RepValues(70, 650);

		public static ScoreValues PyramidChallenge3Score = new ScoreValues(100000, 250000, 500000, 800000, 1100000);

		public static RepValues PyramidChallenge4Rep = new RepValues(80, 660);

		public static RepValues PyramidCrewRep = new RepValues(150, 730);

		public static ScoreValues PyramidCrewBattleScore = new ScoreValues(450000, 1500000, 3000000, 5000000, 7500000);

		public static RepValues PyramidOldheadRep = new RepValues(200, 780);

		public static RepValues OsakaSmokeRep = new RepValues(70, 850);

		public static RepValues OsakaChallenge1Rep = new RepValues(84, 864);

		public static RepValues OsakaChallenge2Rep = new RepValues(100, 880);

		public static RepValues OsakaChallenge3Rep = new RepValues(140, 920);

		public static ScoreValues OsakaChallenge3Score = new ScoreValues(60000, 100000, 200000, 350000, 500000);

		public static RepValues OsakaCrewRep = new RepValues(180, 960);

		public static ScoreValues OsakaCrewBattleScore = new ScoreValues(600000, 2000000, 4000000, 5500000, 7000000);

		public static RepValues OsakaOldheadRep = new RepValues(155, 935);

		public static void OverrideCharacterIfInvalid(ref Characters character)
		{
			List<Characters> list = new List<Characters>
			{
				(Characters)25,
				(Characters)15,
				(Characters)17,
				(Characters)18
			};
			if (!Enum.IsDefined(typeof(Characters), character))
			{
				character = (Characters)3;
			}
			else if (list.Contains(character))
			{
				character = (Characters)3;
			}
		}

		public static int? GetNPCNewRep(Stage stage, NPC npc)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected I4, but got Unknown
			switch (stage - 4)
			{
			case 0:
				return ((Object)((Component)npc).transform.parent).name switch
				{
					"WallrunsChallenge" => DownhillChallenge1Rep.newValue, 
					"ManualChallenge" => DownhillChallenge2Rep.newValue, 
					"CornersScoreChallenge" => DownhillChallenge3Rep.newValue, 
					"Crew_Wall" => DownhillCrewWallRep.newValue, 
					"OldHeadWall" => DownhillOldheadRep.newValue, 
					_ => null, 
				};
			case 7:
			{
				string name2 = ((Object)((Component)npc).transform).name;
				string text2 = name2;
				if (!(text2 == "NPC_EclipseCrew"))
				{
					if (text2 == "NPC_oldhead")
					{
						return SquareOldheadRep.newValue;
					}
					return null;
				}
				return SquareEclipseRep.newValue;
			}
			case 8:
				switch (((Object)((Component)npc).transform.parent).name)
				{
				case "UpsideGrind_Challenge":
					return TowerChallenge1Rep.newValue;
				case "Manual_Challenge ":
					return TowerChallenge2Rep.newValue;
				case "Score_Challenge":
					return TowerChallenge3Rep.newValue;
				case "Chapter2":
				{
					string name = ((Object)((Component)npc).transform).name;
					string text = name;
					if (!(text == "CombatEncounter_SniperCaptain"))
					{
						if (text == "NPC_TowerGuard")
						{
							return TowerCrewWallRep.newValue;
						}
						return null;
					}
					return TowerEscherRep.newValue;
				}
				case "OldHeadWall":
					return ((GameplayEvent)npc).requirement switch
					{
						70 => TowerOldhead1Rep.newValue, 
						140 => TowerOldhead2Rep.newValue, 
						_ => null, 
					};
				default:
					return null;
				}
			case 2:
				switch (((Object)((Component)npc).transform.parent).name)
				{
				case "Palms_Challenge":
					return MallChallenge1Rep.newValue;
				case "Slidepads_Challenge":
					return MallChallenge2Rep.newValue;
				case "Fish_Challenge ":
					return MallChallenge3Rep.newValue;
				case "Tricks_Challenge":
					return MallChallenge4Rep.newValue;
				case "Chapter3":
					if (((Object)((Component)npc).transform).name == "NPC_Crew_GUARDING")
					{
						return MallCrewWallRep.newValue;
					}
					return null;
				case "Oldhead1":
					return MallOldhead2Rep.newValue;
				case "Oldhead2":
					return MallOldhead1Rep.newValue;
				default:
					return null;
				}
			case 5:
				switch (((Object)((Component)npc).transform.parent).name)
				{
				case "Chapter4":
					if (((Object)((Component)npc).transform).name == "NPC_OnDoor")
					{
						return PyramidGateRep.newValue;
					}
					if (((Object)((Component)npc).transform).name == "NPC_Crew_CrewBattle_Starter")
					{
						return PyramidCrewRep.newValue;
					}
					return null;
				case "Tricks_ScoreChallenge":
					return PyramidChallenge1Rep.newValue;
				case "RaceChallenge":
					return PyramidChallenge2Rep.newValue;
				case "Tricks2_ScoreChallenge":
					return PyramidChallenge3Rep.newValue;
				case "Manual_Challenge":
					return PyramidChallenge4Rep.newValue;
				case "OldHeadWall":
					return PyramidOldheadRep.newValue;
				default:
					return null;
				}
			case 3:
				switch (((Object)((Component)npc).transform.parent).name)
				{
				case "Chapter5":
					if (((Object)((Component)npc).transform).name == "NPC_Crew_GateGuard")
					{
						return OsakaSmokeRep.newValue;
					}
					return null;
				case "Race_Challenge":
					return OsakaChallenge1Rep.newValue;
				case "WallrunsChallenge":
					return OsakaChallenge2Rep.newValue;
				case "ScoreChallenge":
					return OsakaChallenge3Rep.newValue;
				case "OldHeadWall":
				case "OldHeadWall2":
					return OsakaOldheadRep.newValue;
				case "CrewBattle":
					return OsakaCrewRep.newValue;
				default:
					return null;
				}
			default:
				return null;
			}
		}

		public static ScoreValues GetEncounterNewScore(Stage stage, ScoreEncounter encounter)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected I4, but got Unknown
			switch (stage - 4)
			{
			case 0:
			{
				string name2 = ((Object)encounter).name;
				string text2 = name2;
				if (!(text2 == "ScoreEncounterBazaar"))
				{
					if (text2 == "CrewBattle_ScoreEncounter")
					{
						return DownhillCrewBattleScore;
					}
					return null;
				}
				return DownhillRaveScore;
			}
			case 8:
				return ((Object)((Component)encounter).transform.parent).name switch
				{
					"Score_Challenge" => TowerChallenge2Score, 
					"Score_Challenge " => TowerMeshScore, 
					"Chapter2" => TowerCrewBattleScore, 
					_ => null, 
				};
			case 2:
			{
				string name3 = ((Object)encounter).name;
				string text3 = name3;
				if (!(text3 == "ScoreEncounter_Tricks"))
				{
					if (text3 == "CrewBattle_ScoreEncounter")
					{
						return MallCrewBattleScore;
					}
					return null;
				}
				return MallChallenge4Score;
			}
			case 5:
				return ((Object)encounter).name switch
				{
					"ScoreEncounter_Tricks1" => PyramidChallenge1Score, 
					"ScoreEncounter_Tricks2" => PyramidChallenge3Score, 
					"CrewBattle_ScoreEncounter" => PyramidCrewBattleScore, 
					_ => null, 
				};
			case 3:
			{
				string name = ((Object)encounter).name;
				string text = name;
				if (!(text == "ScoreEncounter"))
				{
					if (text == "ScoreEncounter_CrewBattle")
					{
						return OsakaCrewBattleScore;
					}
					return null;
				}
				return OsakaChallenge3Score;
			}
			default:
				return null;
			}
		}

		public static Values GetLocalizedTextRepValues(string key)
		{
			switch (key)
			{
			case "Dialogue_hideout_54":
			case "Dialogue_hideout_56":
				return HideoutStoryRep;
			case "Dialogue_downhill_8":
				return DownhillChallenge1Rep;
			case "Dialogue_downhill_21":
				return DownhillChallenge2Rep;
			case "Dialogue_downhill_33":
				return DownhillChallenge3Rep;
			case "Dialogue_downhill_45":
			case "Dialogue_downhill_49":
				return DownhillCrewWallRep;
			case "Dialogue_downhill_215":
				return DownhillRaveScore;
			case "Dialogue_downhill_254":
				return DownhillOldheadRep;
			case "Dialogue_tower_72A":
				return TowerChallenge2Score;
			case "Dialogue_tower_82":
				return TowerCrewWallRep;
			case "Dialogue_tower_205":
				return TowerOldhead1Rep;
			case "Dialogue_tower_245":
			case "Dialogue_tower_246":
				return TowerOldhead2Rep;
			case "Dialogue_square_51":
				return SquareOldheadRep;
			case "Dialogue_Mall_32":
				return MallChallenge1Rep;
			case "Dialogue_Mall_61":
				return MallChallenge3Rep;
			case "Dialogue_Mall_76":
			case "Dialogue_Mall_86":
			case "Dialogue_Mall_87":
			case "Dialogue_Mall_88":
			case "Dialogue_Mall_89":
			case "Dialogue_Mall_91":
			case "Dialogue_Mall_92":
				return MallChallenge4Score;
			case "Dialogue_Mall_96":
			case "Dialogue_Mall_103":
				return MallCrewWallRep;
			case "Dialogue_Mall_205":
				return MallOldhead2Rep;
			case "Dialogue_Mall_216":
				return MallOldhead1Rep;
			case "Dialogue_pyramid_5":
			case "Dialogue_pyramid_7":
				return PyramidGateRep;
			case "Dialogue_pyramid_71":
			case "Dialogue_pyramid_74":
			case "Dialogue_pyramid_75":
				return PyramidCrewRep;
			case "Dialogue_pyramid_209":
				return PyramidOldheadRep;
			case "Dialogue_osaka_57":
				return OsakaCrewRep;
			case "Dialogue_osaka_263":
			case "Dialogue_osaka_274":
				return OsakaOldheadRep;
			case "NOTIFICATION_DOWNHILL_REPFRANKSHIDEOUT":
				return DownhillCrewWallRep;
			case "NOTIFICATION_PYRAMID_REPCREWBATTLE":
				return PyramidCrewRep;
			case "NOTIFICATION_OSAKA_REPCREWBATTLE":
				return OsakaCrewRep;
			default:
				return null;
			}
		}
	}
	public class SaveManager
	{
		private string m_FolderPath;

		public int currentSlot = -1;

		public SaveSlotData CurrentSaveSlot => Core.Instance.SaveManager.CurrentSaveSlot;

		public string FolderPath => m_FolderPath;

		public void GetSavePath()
		{
			m_FolderPath = Traverse.Create((object)Core.Instance.BaseModule).Field("saveManager").Field("storage")
				.Field<string>("storageDirectory")
				.Value;
		}

		public bool DataExists(int slot = -1)
		{
			int num = slot;
			if (num == -1)
			{
				num = currentSlot;
			}
			string path = Path.Combine(FolderPath, $"archipelago{num}.json");
			return File.Exists(path);
		}

		public void SaveData(int slot = -1)
		{
			int num = slot;
			if (num == -1)
			{
				num = currentSlot;
			}
			string path = Path.Combine(FolderPath, $"archipelago{num}.json");
			byte[] bytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject((object)Core.Instance.Data));
			File.WriteAllBytes(path, bytes);
		}

		public void LoadData(int slot = -1)
		{
			int num = slot;
			if (num == -1)
			{
				num = currentSlot;
			}
			string text = Path.Combine(FolderPath, $"archipelago{num}.json");
			if (File.Exists(text))
			{
				using (StreamReader streamReader = new StreamReader(text))
				{
					Core.Instance.Data = JsonConvert.DeserializeObject<Data>(streamReader.ReadToEnd());
				}
				Core.Logger.LogInfo((object)("Loaded from " + text));
			}
			else
			{
				Core.Logger.LogWarning((object)("File at " + text + " doesn't exist. Resetting data."));
				Core.Instance.Data = new Data();
			}
		}

		public void DeleteData(int slot = -1)
		{
			int num = slot;
			if (num == -1)
			{
				num = currentSlot;
			}
			string text = Path.Combine(FolderPath, $"archipelago{num}.json");
			if (File.Exists(text))
			{
				File.Delete(text);
			}
			Core.Instance.Data = new Data();
			Core.Logger.LogInfo((object)("Deleted data at " + text));
		}

		public void UnlockCharacter(Characters character)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			CurrentSaveSlot.GetCharacterProgress(character).unlocked = true;
			Core.Instance.SaveManager.SaveCurrentSaveSlot();
		}

		public void UnlockMaps()
		{
			StageProgress[] allStageProgress = CurrentSaveSlot.GetAllStageProgress();
			foreach (StageProgress val in allStageProgress)
			{
				val.mapFound = true;
			}
		}

		public bool IsAnyGraffitiUnlocked(GraffitiSize size)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if ((int)size == 0)
			{
				return true;
			}
			bool result = false;
			foreach (GraffitiArt item in WorldHandler.instance.graffitiArtInfo.FindBySize(size))
			{
				if (CurrentSaveSlot.GetUnlockableDataByUid(((AUnlockable)item.unlockable).Uid).IsUnlocked)
				{
					result = true;
					break;
				}
			}
			return result;
		}
	}
	public class UIManager
	{
		public static AssetBundle bundle = AssetBundle.LoadFromMemory(Resources.archipelago);

		public TextMeshProMenuButton SaveSlotOneButton;

		public TextMeshProMenuButton SaveSlotTwoButton;

		public TextMeshProMenuButton SaveSlotThreeButton;

		public APSlotButton APSlotOneButton;

		public APSlotButton APSlotTwoButton;

		public APSlotButton APSlotThreeButton;

		public List<APSlotButton> slotButtons = new List<APSlotButton>();

		public SaveSlotMenu ssm;

		public UIAnimationController uiac;

		public GameObject SelectionBarImage;

		public TextMeshProUGUI APMenuHeaderText;

		public TextMeshProUGUI APMenuNameLabel;

		public TextMeshProUGUI APMenuAddressLabel;

		public TextMeshProUGUI APMenuPasswordLabel;

		public TMP_InputField APMenuNameInput;

		public TMP_InputField APMenuAddressInput;

		public TMP_InputField APMenuPasswordInput;

		public TextMeshProUGUI APMenuStatus;

		public TextMeshProUGUI APMenuLocations;

		public const int maxLocations = 247;

		public TextMeshProUGUI APMenuResult;

		public TextMeshProUGUI APMenuChat;

		public int connectingSlot = -1;

		public SelectEnlargeButton APMenuConnectButton;

		public SelectEnlargeButton APMenuCancelButton;

		public static TMP_FontAsset font;

		public static Color menuOrange => new Color(1f, 0.54f, 0f);

		public void FindSaveSlotMenu()
		{
			if (!((Object)(object)ssm != (Object)null))
			{
				ssm = Traverse.Create((object)Core.Instance.UIManager).Field<SaveSlotMenu>("saveSlotsMenu").Value;
			}
		}

		public void FindUIAnimController()
		{
			if (!((Object)(object)uiac != (Object)null))
			{
				uiac = Traverse.Create((object)ssm).Field<UIAnimationController[]>("menuAnimations").Value[0];
			}
		}

		public void CreateAPButtons()
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Expected O, but got Unknown
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Expected O, but got Unknown
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Expected O, but got Unknown
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_027a: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0292: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bf: 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_0345: Unknown result type (might be due to invalid IL or missing references)
			//IL_034a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0357: Unknown result type (might be due to invalid IL or missing references)
			//IL_035c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0370: Unknown result type (might be due to invalid IL or missing references)
			//IL_0375: Unknown result type (might be due to invalid IL or missing references)
			//IL_038f: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0435: Unknown result type (might be due to invalid IL or missing references)
			//IL_043a: Unknown result type (might be due to invalid IL or missing references)
			//IL_044e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0472: Unknown result type (might be due to invalid IL or missing references)
			//IL_0477: Unknown result type (might be due to invalid IL or missing references)
			//IL_047b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0495: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0508: Unknown result type (might be due to invalid IL or missing references)
			//IL_050d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0511: Unknown result type (might be due to invalid IL or missing references)
			//IL_0523: Unknown result type (might be due to invalid IL or missing references)
			//IL_0528: Unknown result type (might be due to invalid IL or missing references)
			//IL_053f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0551: Unknown result type (might be due to invalid IL or missing references)
			//IL_0556: Unknown result type (might be due to invalid IL or missing references)
			//IL_0576: Unknown result type (might be due to invalid IL or missing references)
			//IL_05cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_05eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_060b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0660: Unknown result type (might be due to invalid IL or missing references)
			//IL_0665: Unknown result type (might be due to invalid IL or missing references)
			//IL_0669: Unknown result type (might be due to invalid IL or missing references)
			//IL_067b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0680: Unknown result type (might be due to invalid IL or missing references)
			//IL_06a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_06fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0724: Unknown result type (might be due to invalid IL or missing references)
			//IL_0729: Unknown result type (might be due to invalid IL or missing references)
			//IL_072d: Unknown result type (might be due to invalid IL or missing references)
			//IL_073f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0744: Unknown result type (might be due to invalid IL or missing references)
			//IL_0764: Unknown result type (might be due to invalid IL or missing references)
			//IL_07a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_07ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_07bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_07d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_081c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0821: Unknown result type (might be due to invalid IL or missing references)
			//IL_0830: Unknown result type (might be due to invalid IL or missing references)
			//IL_084a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0886: Unknown result type (might be due to invalid IL or missing references)
			//IL_08ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_08b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_08b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_08c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_08cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_08ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0936: Unknown result type (might be due to invalid IL or missing references)
			//IL_095d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0962: Unknown result type (might be due to invalid IL or missing references)
			//IL_0966: Unknown result type (might be due to invalid IL or missing references)
			//IL_0978: Unknown result type (might be due to invalid IL or missing references)
			//IL_097d: Unknown result type (might be due to invalid IL or missing references)
			//IL_099d: Unknown result type (might be due to invalid IL or missing references)
			//IL_09f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a20: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a25: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a34: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a4e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ad4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0af9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b9b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ba0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ba4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bbe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0be5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c2f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c39: Expected O, but got Unknown
			//IL_0c66: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c6b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c6f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c89: Unknown result type (might be due to invalid IL or missing references)
			//IL_0cc4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0cf8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0cfa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d07: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d2e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d6f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d79: Expected O, but got Unknown
			if (!((Object)(object)APSlotThreeButton != (Object)null))
			{
				FindSaveSlotMenu();
				FindUIAnimController();
				GameObject gameObject = ((Component)((AMenuController)ssm).GetFi

plugins/Archipelago.MultiClient.Net.dll

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

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: ComVisible(false)]
[assembly: Guid("35a803ad-85ed-42e9-b1e3-c6b72096f0c1")]
[assembly: InternalsVisibleTo("Archipelago.MultiClient.Net.Tests")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
[assembly: TargetFramework(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")]
[assembly: AssemblyCompany("Jarno Westhof, Hussein Farran, Zach Parks")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © 2024")]
[assembly: AssemblyDescription("A client library for use with .NET based prog-langs for interfacing with Archipelago hosts.")]
[assembly: AssemblyFileVersion("6.0.0.0")]
[assembly: AssemblyInformationalVersion("6.0.0-rc5")]
[assembly: AssemblyProduct("Archipelago.MultiClient.Net")]
[assembly: AssemblyTitle("Archipelago.MultiClient.Net")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/ArchipelagoMW/Archipelago.MultiClient.Net")]
[assembly: AssemblyVersion("6.0.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 class ArchipelagoSession
	{
		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 + ":NET45",
						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 = new TaskCompletionSource<LoginResult>();
				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, 4, 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 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;
	}
}
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; }
	}
	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 class ScoutedItemInfo : ItemInfo
	{
		public new PlayerInfo Player => base.Player;

		public ScoutedItemInfo(NetworkItem item, string receiverGame, string senderGame, IItemInfoResolver itemInfoResolver, PlayerInfo player)
			: base(item, receiverGame, senderGame, itemInfoResolver, 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; }
	}
	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
			};
		}
	}
}
namespace Archipelago.MultiClient.Net.MessageLog.Parts
{
	public class EntranceMessagePart : MessagePart
	{
		internal EntranceMessagePart(JsonMessagePart messagePart)
			: base(MessagePartType.Entrance, messagePart, Color.Blue)
		{
			base.Text = messagePart.Text;
		}
	}
	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.Color = 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;
				}
			}
		}

		private static Color GetColor(ItemFlags flags)
		{
			if (HasFlag(flags, ItemFlags.Advancement))
			{
				return Color.Plum;
			}
			if (HasFlag(flags, ItemFlags.NeverExclude))
			{
				return Color.SlateBlue;
			}
			if (HasFlag(flags, ItemFlags.Trap))
			{
				return Color.Salmon;
			}
			return Color.Cyan;
		}

		private static bool HasFlag(ItemFlags flags, ItemFlags flag)
		{
			return flags.HasFlag(flag);
		}
	}
	public class LocationMessagePart : MessagePart
	{
		public long LocationId { get; }

		public int Player { get; }

		internal LocationMessagePart(IPlayerHelper players, IItemInfoResolver itemInfoResolver, JsonMessagePart part)
			: base(MessagePartType.Location, part, Color.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 { get; internal set; }

		public bool IsBackgroundColor { get; internal set; }

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

		private static Color GetColor(JsonMessagePartColor color)
		{
			switch (color)
			{
			case JsonMessagePartColor.Red:
			case JsonMessagePartColor.RedBg:
				return Color.Red;
			case JsonMessagePartColor.Green:
			case JsonMessagePartColor.GreenBg:
				return Color.Green;
			case JsonMessagePartColor.Yellow:
			case JsonMessagePartColor.YellowBg:
				return Color.Yellow;
			case JsonMessagePartColor.Blue:
			case JsonMessagePartColor.BlueBg:
				return Color.Blue;
			case JsonMessagePartColor.Magenta:
			case JsonMessagePartColor.MagentaBg:
				return Color.Magenta;
			case JsonMessagePartColor.Cyan:
			case JsonMessagePartColor.CyanBg:
				return Color.Cyan;
			case JsonMessagePartColor.Black:
			case JsonMessagePartColor.BlackBg:
				return Color.Black;
			case JsonMessagePartColor.White:
			case JsonMessagePartColor.WhiteBg:
				return Color.White;
			default:
				return Color.White;
			}
		}

		public override string ToString()
		{
			return Text;
		}
	}
	public enum MessagePartType
	{
		Text,
		Player,
		Item,
		Location,
		Entrance
	}
	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.Color = GetColor(IsActivePlayer);
		}

		private static Color GetColor(bool isActivePlayer)
		{
			if (isActivePlayer)
			{
				return Color.Magenta;
			}
			return Color.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, IConnectionInfoProvider connectionInfo, int team, int slot, string message)
			: base(parts, players, connectionInfo, team, slot)
		{
			Message = message;
		}
	}
	public class CollectLogMessage : PlayerSpecificLogMessage
	{
		internal CollectLogMessage(MessagePart[] parts, IPlayerHelper players, IConnectionInfoProvider connectionInfo, int team, int slot)
			: base(parts, players, connectionInfo, 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, IConnectionInfoProvider connectionInfo, int team, int slot)
			: base(parts, players, connectionInfo, team, slot)
		{
		}
	}
	public class HintItemSendLogMessage : ItemSendLogMessage
	{
		public bool IsFound { get; }

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

		public PlayerInfo Sender { get; }

		public bool IsReceiverTheActivePlayer { get; }

		public bool IsSenderTheActivePlayer { get; }

		public bool IsRelatedToActivePlayer { get; }

		public ItemInfo Item { get; }

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

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

		internal JoinLogMessage(MessagePart[] parts, IPlayerHelper players, IConnectionInfoProvider connectionInfo, int team, int slot, string[] tags)
			: base(parts, players, connectionInfo, team, slot)
		{
			Tags = tags;
		}
	}
	public class LeaveLogMessage : PlayerSpecificLogMessage
	{
		internal LeaveLogMessage(MessagePart[] parts, IPlayerHelper players, IConnectionInfoProvider connectionInfo, int team, int slot)
			: base(parts, players, connectionInfo, 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
	{
		public PlayerInfo Player { get; }

		public bool IsActivePlayer { get; }

		public bool IsRelatedToActivePlayer { get; }

		internal PlayerSpecificLogMessage(MessagePart[] parts, IPlayerHelper players, IConnectionInfoProvider connectionInfo, int team, int slot)
			: base(parts)
		{
			ReadOnlyDictionary<int, ReadOnlyCollection<PlayerInfo>> players2 = players.Players;
			IsActivePlayer = connectionInfo.Team == team && connectionInfo.Slot == slot;
			Player = ((players2.Count > team && players2[team].Count > slot) ? players2[team][slot] : new PlayerInfo());
			IsRelatedToActivePlayer = IsActivePlayer || Player.IsSharingGroupWith(connectionInfo.Team, connectionInfo.Slot);
		}
	}
	public class ReleaseLogMessage : PlayerSpecificLogMessage
	{
		internal ReleaseLogMessage(MessagePart[] parts, IPlayerHelper players, IConnectionInfoProvider connectionInfo, int team, int slot)
			: base(parts, players, connectionInfo, 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, IConnectionInfoProvider connectionInfo, int team, int slot, string[] tags)
			: base(parts, players, connectionInfo, team, slot)
		{
			Tags = tags;
		}
	}
	public class TutorialLogMessage : LogMessage
	{
		internal TutorialLogMessage(MessagePart[] parts)
			: base(parts)
		{
		}
	}
}
namespace Archipelago.MultiClient.Net.Helpers
{
	public class ArchipelagoSocketHelper : IArchipelagoSocketHelper
	{
		private static readonly ArchipelagoPacketConverter Converter = new ArchipelagoPacketConverter();

		private const int ReceiveChunkSize = 1024;

		private const int SendChunkSize = 1024;

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

		internal ClientWebSocket webSocket;

		public Uri Uri { get; }

		public bool Connected
		{
			get
			{
				if (webSocket.State != WebSocketState.Open)
				{
					return webSocket.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 ArchipelagoSocketHelper(Uri hostUri)
		{
			Uri = hostUri;
			webSocket = new ClientWebSocket();
			SecurityProtocolType securityProtocolType = SecurityProtocolType.Tls13;
			ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | securityProtocolType;
		}

		public async Task ConnectAsync()
		{
			await ConnectToProvidedUri(Uri);
			if (this.SocketOpened != null)
			{
				this.SocketOpened();
			}
			Task.Run((Func<Task?>)PollingLoop);
			Task.Run((Func<Task?>)SendLoop);
		}

		private async Task ConnectToProvidedUri(Uri uri)
		{
			if (uri.Scheme != "unspecified")
			{
				try
				{
					await webSocket.ConnectAsync(uri, CancellationToken.None);
					return;
				}
				catch (Exception e)
				{
					OnError(e);
					throw;
				}
			}
			List<Exception> errors = new List<Exception>(0);
			try
			{
				await webSocket.ConnectAsync(uri.AsWss(), CancellationToken.None);
				if (webSocket.State == WebSocketState.Open)
				{
					return;
				}
			}
			catch (Exception item)
			{
				errors.Add(item);
				webSocket = new ClientWebSocket();
			}
			try
			{
				await webSocket.ConnectAsync(uri.AsWs(), CancellationToken.None);
			}
			catch (Exception item2)
			{
				errors.Add(item2);
				OnError(new AggregateException(errors));
				throw;
			}
		}

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

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

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

		public async Task DisconnectAsync()
		{
			await webSocket.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 (webSocket.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 / 1024.0);
			for (int i = 0; i < messagesCount; i++)
			{
				int num = 1024 * i;
				int num2 = 1024;
				bool endOfMessage = i + 1 == messagesCount;
				if (num2 * (i + 1) > messageBuffer.Length)
				{
					num2 = messageBuffer.Length - num;
				}
				await webSocket.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 = JsonConvert.DeserializeObject<List<ArchipelagoPacketBase>>(message, (JsonConverter[])(object)new JsonConverter[1] { Converter });
				if (list == null)
				{
					return;
				}
				foreach (ArchipelagoPacketBase item in list)
				{
					this.PacketReceived(item);
				}
			}
			catch (Exception e)
			{
				OnError(e);
			}
		}

		private 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();
				}
			}
			else
			{
				Team = connectedPacket.Team;
				Slot = connectedPacket.Slot;
			}
		}

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

		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 GetSlotDataElement(slot).To<Dictionary<string, object>>();
		}

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

		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 interface IDataStorageWrapper
	{
		Hint[] GetHints(int? slot = null, int? team = null);

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

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

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

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

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

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

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

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

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

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

		void TrackClientStatus(Action<ArchipelagoClientState> onStatusUpdated, bool retrieveCurrentClientStatus = true, int? slot = null, int? team = null);
	}
	public class ArchipelagoSocketHelperDelagates
	{
		public delegate void PacketReceivedHandler(ArchipelagoPacketBase packet);

		public delegate void PacketsSentHandler(ArchipelagoPacketBase[] packets);

		public delegate void ErrorReceivedHandler(Exception e, string message);

		public delegate void SocketClosedHandler(string reason);

		public delegate void SocketOpenedHandler();
	}
	public interface IArchipelagoSocketHelper
	{
		Uri Uri { get; }

		bool Connected { get; }

		event ArchipelagoSocketHelperDelagates.PacketReceivedHandler PacketReceived;

		event ArchipelagoSocketHelperDelagates.PacketsSentHandler PacketsSent;

		event ArchipelagoSocketHelperDelagates.ErrorReceivedHandler ErrorReceived;

		event ArchipelagoSocketHelperDelagates.SocketClosedHandler SocketClosed;

		event ArchipelagoSocketHelperDelagates.SocketOpenedHandler SocketOpened;

		void SendPacket(ArchipelagoPacketBase packet);

		void SendMultiplePackets(List<ArchipelagoPacketBase> packets);

		void SendMultiplePackets(params ArchipelagoPacketBase[] packets);

		Task ConnectAsync();

		Task DisconnectAsync();

		Task SendPacketAsync(ArchipelagoPacketBase packet);

		Task SendMultiplePacketsAsync(List<ArchipelagoPacketBase> packets);

		Task SendMultiplePacketsAsync(params ArchipelagoPacketBase[] packets);
	}
	public interface ILocationCheckHelper
	{
		ReadOnlyCollection<long> AllLocations { get; }

		ReadOnlyCollection<long> AllLocationsChecked { get; }

		ReadOnlyCollection<long> AllMissingLocations { get; }

		event LocationCheckHelper.CheckedLocationsUpdatedHandler CheckedLocationsUpdated;

		void CompleteLocationChecks(params long[] ids);

		Task CompleteLocationChecksAsync(params long[] ids);

		Task<Dictionary<long, ScoutedItemInfo>> ScoutLocationsAsync(HintCreationPolicy hintCreationPolicy, params long[] ids);

		Task<Dictionary<long, ScoutedItemInfo>> ScoutLocationsAsync(bool createAsHint, params long[] ids);

		Task<Dictionary<long, ScoutedItemInfo>> ScoutLocationsAsync(params long[] ids);

		long GetLocationIdFromName(string game, string locationName);

		string GetLocationNameFromId(long locationId, string game = null);
	}
	public class LocationCheckHelper : ILocationCheckHelper
	{
		public delegate void CheckedLocationsUpdatedHandler(ReadOnlyCollection<long> newCheckedLocations);

		private readonly IConcurrentHashSet<long> allLocations = new ConcurrentHashSet<long>();

		private readonly IConcurrentHashSet<long> locationsChecked = new ConcurrentHashSet<long>();

		private readonly IConcurrentHashSet<long> serverConfirmedChecks = new ConcurrentHashSet<long>();

		private ReadOnlyCollection<long> missingLocations = new ReadOnlyCollection<long>(new long[0]);

		private readonly IArchipelagoSocketHelper socket;

		private readonly IItemInfoResolver itemInfoResolver;

		private readonly IConnectionInfoProvider connectionInfoProvider;

		private readonly IPlayerHelper players;

		private bool awaitingLocationInfoPacket;

		private TaskCompletionSource<Dictionary<long, ScoutedItemInfo>> locationInfoPacketCallbackTask;

		public ReadOnlyCollection<long> AllLocations => allLocations.AsToReadOnlyCollection();

		public ReadOnlyCollection<long> AllLocationsChecked => locationsChecked.AsToReadOnlyCollection();

		public ReadOnlyCollection<long> AllMissingLocations => missingLocations;

		public event CheckedLocationsUpdatedHandler CheckedLocationsUpdated;

		internal LocationCheckHelper(IArchipelagoSocketHelper socket, IItemInfoResolver itemInfoResolver, IConnectionInfoProvider connectionInfoProvider, IPlayerHelper players)
		{
			this.socket = socket;
			this.itemInfoResolver = itemInfoResolver;
			this.connectionInfoProvider = connectionInfoProvider;
			this.players = players;
			socket.PacketReceived += Socket_PacketReceived;
		}

		private void Socket_PacketReceived(ArchipelagoPacketBase packet)
		{
			if (!(packet is ConnectedPacket connectedPacket))
			{
				if (!(packet is RoomUpdatePacket roomUpdatePacket))
				{
					if (!(packet is LocationInfoPacket locationInfoPacket))
					{
						if (packet is InvalidPacketPacket invalidPacketPacket && awaitingLocationInfoPacket && invalidPacketPacket.OriginalCmd == ArchipelagoPacketType.LocationScouts)
						{
							locationInfoPacketCallbackTask.TrySetException(new ArchipelagoServerRejectedPacketException(invalidPacketPacket.OriginalCmd, invalidP