Decompiled source of Archipelago Randomizer for REPO v0.4.0

RepoAP.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.WebSockets;
using System.Numerics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Archipelago.MultiClient.Net;
using Archipelago.MultiClient.Net.BounceFeatures.DeathLink;
using Archipelago.MultiClient.Net.Colors;
using Archipelago.MultiClient.Net.ConcurrentCollection;
using Archipelago.MultiClient.Net.Converters;
using Archipelago.MultiClient.Net.DataPackage;
using Archipelago.MultiClient.Net.Enums;
using Archipelago.MultiClient.Net.Exceptions;
using Archipelago.MultiClient.Net.Extensions;
using Archipelago.MultiClient.Net.Helpers;
using Archipelago.MultiClient.Net.MessageLog.Messages;
using Archipelago.MultiClient.Net.MessageLog.Parts;
using Archipelago.MultiClient.Net.Models;
using Archipelago.MultiClient.Net.Packets;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using MenuLib;
using MenuLib.MonoBehaviors;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using Photon.Pun;
using REPOLib.Modules;
using RepoAP.Core;
using UnityEngine;
using UnityEngine.Events;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("RepoAP")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.4.0.0")]
[assembly: AssemblyInformationalVersion("0.4.0+2bb3b0b2691b1d1e54686193fd3850ce9f105f71")]
[assembly: AssemblyProduct("Archipelago Randomizer")]
[assembly: AssemblyTitle("RepoAP")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.4.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 RepoAP
{
	[HarmonyPatch(typeof(MainMenuOpen), "Start")]
	internal class APConnectMenu
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static Action <>9__0_1;

			public static BuilderDelegate <>9__0_0;

			internal void <Prefix>b__0_0(Transform parent)
			{
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				MenuAPI.CreateREPOButton("Archipelago", (Action)delegate
				{
					MenuBuilder.BuildPopup();
				}, parent, new Vector2(145f, 27f));
			}

			internal void <Prefix>b__0_1()
			{
				MenuBuilder.BuildPopup();
			}
		}

		[HarmonyPrefix]
		private static void Prefix()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			object obj = <>c.<>9__0_0;
			if (obj == null)
			{
				BuilderDelegate val = delegate(Transform parent)
				{
					//IL_002f: Unknown result type (might be due to invalid IL or missing references)
					MenuAPI.CreateREPOButton("Archipelago", (Action)delegate
					{
						MenuBuilder.BuildPopup();
					}, parent, new Vector2(145f, 27f));
				};
				<>c.<>9__0_0 = val;
				obj = (object)val;
			}
			MenuAPI.AddElementToMainMenu((BuilderDelegate)obj);
		}
	}
	public static class MenuBuilder
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static BuilderDelegate <>9__0_0;

			public static BuilderDelegate <>9__0_1;

			public static Action<string> <>9__0_8;

			public static BuilderDelegate <>9__0_2;

			public static Action<string> <>9__0_9;

			public static BuilderDelegate <>9__0_3;

			public static Action<string> <>9__0_10;

			public static BuilderDelegate <>9__0_4;

			public static Action<string> <>9__0_11;

			public static BuilderDelegate <>9__0_5;

			internal void <BuildPopup>b__0_0(Transform parent)
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				MenuAPI.CreateREPOLabel("<size=12>Only host player must be connected to AP Server.", parent, new Vector2(380f, 275f));
			}

			internal void <BuildPopup>b__0_1(Transform parent)
			{
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				MenuAPI.CreateREPOLabel(Plugin.connection.connected ? "<size=12><color=#00ad2e>Connected" : "<size=12><color=#7a000e>Not Connected", parent, new Vector2(400f, 225f));
			}

			internal void <BuildPopup>b__0_2(Transform parent)
			{
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				MenuAPI.CreateREPOInputField("Address", (Action<string>)delegate(string input)
				{
					Plugin.apAddress = input;
				}, parent, new Vector2(400f, 200f), false, Plugin.apAddress, "");
			}

			internal void <BuildPopup>b__0_8(string input)
			{
				Plugin.apAddress = input;
			}

			internal void <BuildPopup>b__0_3(Transform parent)
			{
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				MenuAPI.CreateREPOInputField("Port", (Action<string>)delegate(string input)
				{
					Plugin.apPort = input;
				}, parent, new Vector2(400f, 175f), false, Plugin.apPort, "");
			}

			internal void <BuildPopup>b__0_9(string input)
			{
				Plugin.apPort = input;
			}

			internal void <BuildPopup>b__0_4(Transform parent)
			{
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				MenuAPI.CreateREPOInputField("Password", (Action<string>)delegate(string input)
				{
					Plugin.apPassword = input;
				}, parent, new Vector2(400f, 150f), false, Plugin.apPassword, "");
			}

			internal void <BuildPopup>b__0_10(string input)
			{
				Plugin.apPassword = input;
			}

			internal void <BuildPopup>b__0_5(Transform parent)
			{
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				MenuAPI.CreateREPOInputField("Player Slot", (Action<string>)delegate(string input)
				{
					Plugin.apSlot = input;
				}, parent, new Vector2(400f, 125f), false, Plugin.apSlot, "");
			}

			internal void <BuildPopup>b__0_11(string input)
			{
				Plugin.apSlot = input;
			}
		}

		public static void BuildPopup()
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Expected O, but got Unknown
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Expected O, but got Unknown
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Expected O, but got Unknown
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Expected O, but got Unknown
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Expected O, but got Unknown
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Expected O, but got Unknown
			Plugin.Logger.LogInfo((object)"Building Popup");
			REPOPopupPage repoPage = MenuAPI.CreateREPOPopupPage("Archipelago", (PresetSide)1, false, true, 1.5f);
			REPOPopupPage obj = repoPage;
			object obj2 = <>c.<>9__0_0;
			if (obj2 == null)
			{
				BuilderDelegate val = delegate(Transform parent)
				{
					//IL_0010: Unknown result type (might be due to invalid IL or missing references)
					MenuAPI.CreateREPOLabel("<size=12>Only host player must be connected to AP Server.", parent, new Vector2(380f, 275f));
				};
				<>c.<>9__0_0 = val;
				obj2 = (object)val;
			}
			obj.AddElement((BuilderDelegate)obj2);
			REPOPopupPage obj3 = repoPage;
			object obj4 = <>c.<>9__0_1;
			if (obj4 == null)
			{
				BuilderDelegate val2 = delegate(Transform parent)
				{
					//IL_0023: Unknown result type (might be due to invalid IL or missing references)
					MenuAPI.CreateREPOLabel(Plugin.connection.connected ? "<size=12><color=#00ad2e>Connected" : "<size=12><color=#7a000e>Not Connected", parent, new Vector2(400f, 225f));
				};
				<>c.<>9__0_1 = val2;
				obj4 = (object)val2;
			}
			obj3.AddElement((BuilderDelegate)obj4);
			REPOPopupPage obj5 = repoPage;
			object obj6 = <>c.<>9__0_2;
			if (obj6 == null)
			{
				BuilderDelegate val3 = delegate(Transform parent)
				{
					//IL_002f: Unknown result type (might be due to invalid IL or missing references)
					MenuAPI.CreateREPOInputField("Address", (Action<string>)delegate(string input)
					{
						Plugin.apAddress = input;
					}, parent, new Vector2(400f, 200f), false, Plugin.apAddress, "");
				};
				<>c.<>9__0_2 = val3;
				obj6 = (object)val3;
			}
			obj5.AddElement((BuilderDelegate)obj6);
			REPOPopupPage obj7 = repoPage;
			object obj8 = <>c.<>9__0_3;
			if (obj8 == null)
			{
				BuilderDelegate val4 = delegate(Transform parent)
				{
					//IL_002f: Unknown result type (might be due to invalid IL or missing references)
					MenuAPI.CreateREPOInputField("Port", (Action<string>)delegate(string input)
					{
						Plugin.apPort = input;
					}, parent, new Vector2(400f, 175f), false, Plugin.apPort, "");
				};
				<>c.<>9__0_3 = val4;
				obj8 = (object)val4;
			}
			obj7.AddElement((BuilderDelegate)obj8);
			REPOPopupPage obj9 = repoPage;
			object obj10 = <>c.<>9__0_4;
			if (obj10 == null)
			{
				BuilderDelegate val5 = delegate(Transform parent)
				{
					//IL_002f: Unknown result type (might be due to invalid IL or missing references)
					MenuAPI.CreateREPOInputField("Password", (Action<string>)delegate(string input)
					{
						Plugin.apPassword = input;
					}, parent, new Vector2(400f, 150f), false, Plugin.apPassword, "");
				};
				<>c.<>9__0_4 = val5;
				obj10 = (object)val5;
			}
			obj9.AddElement((BuilderDelegate)obj10);
			REPOPopupPage obj11 = repoPage;
			object obj12 = <>c.<>9__0_5;
			if (obj12 == null)
			{
				BuilderDelegate val6 = delegate(Transform parent)
				{
					//IL_002f: Unknown result type (might be due to invalid IL or missing references)
					MenuAPI.CreateREPOInputField("Player Slot", (Action<string>)delegate(string input)
					{
						Plugin.apSlot = input;
					}, parent, new Vector2(400f, 125f), false, Plugin.apSlot, "");
				};
				<>c.<>9__0_5 = val6;
				obj12 = (object)val6;
			}
			obj11.AddElement((BuilderDelegate)obj12);
			repoPage.AddElement((BuilderDelegate)delegate(Transform parent)
			{
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				MenuAPI.CreateREPOButton("Connect", (Action)delegate
				{
					Plugin.connection.TryConnect(Plugin.apAddress, int.Parse(Plugin.apPort), Plugin.apPassword, Plugin.apSlot);
					repoPage.ClosePage(false);
					BuildConnectingPopUp();
				}, parent, new Vector2(378f, 25f));
			});
			repoPage.AddElement((BuilderDelegate)delegate(Transform parent)
			{
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				MenuAPI.CreateREPOButton("Close", (Action)delegate
				{
					repoPage.ClosePage(true);
				}, parent, new Vector2(590f, 25f));
			});
			repoPage.OpenPage(true);
		}

		public static void BuildConnectingPopUp()
		{
			REPOPopupPage val = MenuAPI.CreateREPOPopupPage("Connecting to Server...", (PresetSide)1, false, true, 0f);
			Plugin.connection.connectingPage = val;
			val.OpenPage(true);
		}
	}
	internal class APSaveData
	{
		public List<long> locationsChecked = new List<long>();

		public List<string> pellysGathered = new List<string>();

		public List<string> valuablesGathered = new List<string>();

		public List<string> monsterSoulsGathered = new List<string>();

		public long shopStockSlotData;

		public int shopStockReceived;

		public Dictionary<long, int> itemsReceived = new Dictionary<long, int>();

		public Dictionary<string, bool> levelsUnlocked = new Dictionary<string, bool>();

		public int itemReceivedIndex;

		public Dictionary<long, SerializableItemInfo> locationsScouted = new Dictionary<long, SerializableItemInfo>();

		public long pellysRequired;

		public bool pellySpawning;

		public long levelQuota;

		public long levelsCompleted;

		public long upgradeLocations;

		public bool valuableHunt;

		public bool monsterHunt;

		public Dictionary<string, int> trapsUsed = new Dictionary<string, int>();
	}
	internal static class APSave
	{
		public static ES3Settings es3Settings;

		public static APSaveData saveData;

		public static string fileName;

		private static string saveKey = "archipelago";

		public static void Init()
		{
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			if (SemiFunc.IsMasterClientOrSingleplayer())
			{
				string text = Application.persistentDataPath + "/archipelago";
				fileName = BuildFileName();
				if (!Directory.Exists(text))
				{
					Directory.CreateDirectory(text);
				}
				text += "/saves";
				if (!Directory.Exists(text))
				{
					Directory.CreateDirectory(text);
				}
				text += fileName;
				if (!File.Exists(text))
				{
					es3Settings = new ES3Settings(text, new Enum[1] { (Enum)(object)(EncryptionType)0 });
					saveData = new APSaveData();
					SaveSlotDataToFile();
					ES3.Save<APSaveData>(saveKey, saveData, es3Settings);
				}
				else
				{
					es3Settings = new ES3Settings(text, new Enum[1] { (Enum)(object)(EncryptionType)0 });
					Plugin.Logger.LogInfo((object)("Loading save data from " + text));
					saveData = ES3.Load<APSaveData>(saveKey, saveData, es3Settings);
					SaveSlotDataToFile();
					ES3.Save<APSaveData>(saveKey, saveData, es3Settings);
				}
			}
		}

		private static string BuildFileName()
		{
			if (Plugin.connection.session == null)
			{
				return null;
			}
			return "/" + Plugin.connection.session.Players.ActivePlayer.Name + "___" + Plugin.connection.session.RoomState.Seed + ".es3";
		}

		private static void SaveSlotDataToFile()
		{
			if (Plugin.connection.session == null)
			{
				Plugin.Logger.LogWarning((object)"Not connected. Cannot save slot data.");
				return;
			}
			saveData.levelQuota = (long)Plugin.connection.slotData["level_quota"];
			saveData.pellysRequired = (long)Plugin.connection.slotData["pellys_required"];
			saveData.pellySpawning = saveData.pellysRequired > 0;
			saveData.upgradeLocations = (long)Plugin.connection.slotData["upgrade_locations"];
			saveData.shopStockSlotData = (long)Plugin.connection.slotData["shop_stock"];
			saveData.valuableHunt = (bool)Plugin.connection.slotData["valuable_hunt"];
			saveData.monsterHunt = (bool)Plugin.connection.slotData["monster_hunt"];
		}

		public static void SyncServerLocationsToSave()
		{
			if (!Plugin.connection.connected)
			{
				return;
			}
			ArchipelagoSession session = Plugin.connection.session;
			foreach (long item in session.Locations.AllLocationsChecked)
			{
				if (!GetLocationsChecked().Contains(item))
				{
					AddLocationChecked(item);
				}
				string locationNameFromId = session.Locations.GetLocationNameFromId(item);
				if (locationNameFromId.Contains("Pelly"))
				{
					AddPellyGathered(locationNameFromId);
				}
				if (locationNameFromId.Contains("Valuable"))
				{
					AddValuableGathered(LocationData.ValuableIDToName(item));
				}
				if (locationNameFromId.Contains("Soul"))
				{
					AddMonsterSoulGathered(LocationData.MonsterSoulIDToName(item));
				}
			}
		}

		public static void AddLocationChecked(long locToAdd)
		{
			if (Plugin.connection.session != null && SemiFunc.IsMasterClientOrSingleplayer())
			{
				saveData.locationsChecked.Add(locToAdd);
				ES3.Save<APSaveData>(saveKey, saveData, es3Settings);
			}
		}

		public static List<long> GetLocationsChecked()
		{
			if (Plugin.connection.session == null || !SemiFunc.IsMasterClientOrSingleplayer())
			{
				return null;
			}
			return ES3.Load<APSaveData>(saveKey, es3Settings).locationsChecked;
		}

		public static List<int> GetShopLocationsChecked()
		{
			if (Plugin.connection.session == null)
			{
				return null;
			}
			List<long> locationsChecked = GetLocationsChecked();
			List<int> list = new List<int>();
			foreach (long item in locationsChecked)
			{
				if (LocationData.RemoveBaseId(item) <= 100)
				{
					list.Add((int)LocationData.RemoveBaseId(item));
				}
			}
			return list;
		}

		public static void AddItemReceived(long itemId)
		{
			if (Plugin.connection.session != null && SemiFunc.IsMasterClientOrSingleplayer())
			{
				if (saveData.itemsReceived.ContainsKey(itemId))
				{
					saveData.itemsReceived[itemId]++;
				}
				else
				{
					saveData.itemsReceived.Add(itemId, 1);
				}
				saveData.itemReceivedIndex++;
				ES3.Save<APSaveData>(saveKey, saveData, es3Settings);
			}
		}

		public static int GetItemReceivedIndex()
		{
			if (Plugin.connection.session == null || !SemiFunc.IsMasterClientOrSingleplayer())
			{
				return 0;
			}
			return ES3.Load<APSaveData>(saveKey, es3Settings).itemReceivedIndex;
		}

		public static void AddStockReceived()
		{
			if (Plugin.connection.session != null && SemiFunc.IsMasterClientOrSingleplayer())
			{
				if (saveData.itemsReceived.ContainsKey(ItemData.AddBaseId(10L)))
				{
					saveData.shopStockReceived = saveData.itemsReceived[ItemData.AddBaseId(10L)];
				}
				else
				{
					saveData.shopStockReceived = 0;
				}
				ES3.Save<APSaveData>(saveKey, saveData, es3Settings);
			}
		}

		public static void UpdateAvailableItems()
		{
			if (Plugin.connection.session == null)
			{
				return;
			}
			Plugin.ShopItemsAvailable = new List<int>();
			Plugin.ShopItemsBought = GetShopLocationsChecked();
			for (int i = 1; i <= saveData.shopStockSlotData * (saveData.shopStockReceived + 1); i++)
			{
				if (!Plugin.ShopItemsBought.Contains(i) && Plugin.connection.session.Locations.AllMissingLocations.Contains(ItemData.AddBaseId(i)))
				{
					Plugin.ShopItemsAvailable.Add(i);
				}
			}
		}

		public static Dictionary<long, int> GetItemsReceived()
		{
			if (Plugin.connection.session == null || !SemiFunc.IsMasterClientOrSingleplayer())
			{
				return null;
			}
			return ES3.Load<APSaveData>(saveKey, es3Settings).itemsReceived;
		}

		public static bool IsItemReceived(long id, int count = 1)
		{
			if (!Plugin.connection.connected || !SemiFunc.IsMasterClientOrSingleplayer())
			{
				return false;
			}
			Dictionary<long, int> itemsReceived = ES3.Load<APSaveData>(saveKey, es3Settings).itemsReceived;
			bool result = false;
			if (itemsReceived.ContainsKey(id) && itemsReceived[id] >= count)
			{
				result = true;
			}
			return result;
		}

		public static void AddLevelReceived(string levelName)
		{
			if (Plugin.connection.session != null && SemiFunc.IsMasterClientOrSingleplayer())
			{
				if (!saveData.levelsUnlocked.ContainsKey(levelName) || !saveData.levelsUnlocked[levelName])
				{
					saveData.levelsUnlocked.Add(levelName, value: true);
				}
				else
				{
					Plugin.Logger.LogDebug((object)(levelName + " has already been received!"));
				}
				ES3.Save<APSaveData>(saveKey, saveData, es3Settings);
			}
		}

		public static Dictionary<string, bool> GetLevelsReceived()
		{
			if (Plugin.connection.session == null || !SemiFunc.IsMasterClientOrSingleplayer())
			{
				return null;
			}
			return ES3.Load<APSaveData>(saveKey, es3Settings).levelsUnlocked;
		}

		public static async void ScoutLocations()
		{
			if (Plugin.connection.session == null || !SemiFunc.IsMasterClientOrSingleplayer())
			{
				return;
			}
			Plugin.Logger.LogInfo((object)"Scouting Locations...");
			int num = 100;
			int num2 = LocationNames.all_pellys.Count * LocationNames.all_levels.Count;
			int count = LocationNames.all_valuables.Count;
			int count2 = LocationNames.all_monster_souls.Count;
			Plugin.Logger.LogInfo((object)$"Checking {num} shop items...");
			Plugin.Logger.LogInfo((object)$"Checking {num2} pelly statues...");
			Plugin.Logger.LogInfo((object)$"Checking {count} valuables...");
			Plugin.Logger.LogInfo((object)$"Checking {count2} monster souls...");
			long[] array = new long[num + num2 + count + count2];
			int num3 = 0;
			for (int i = 1; i <= num; i++)
			{
				array[num3++] = LocationData.AddBaseId(i);
			}
			for (int j = 1; j <= num2; j++)
			{
				array[num3++] = LocationData.AddBaseId(100 + j);
			}
			for (int k = 0; k < count; k++)
			{
				array[num3++] = LocationData.AddBaseId(200 + k);
			}
			for (int l = 0; l < count2; l++)
			{
				array[num3++] = LocationData.AddBaseId(500 + l);
			}
			try
			{
				Dictionary<long, ScoutedItemInfo> obj = await Plugin.connection.session.Locations.ScoutLocationsAsync(array);
				saveData.locationsScouted = new Dictionary<long, SerializableItemInfo>();
				foreach (ScoutedItemInfo value in obj.Values)
				{
					saveData.locationsScouted.Add(value.LocationId, value.ToSerializable());
				}
			}
			catch (Exception ex)
			{
				Debug.LogError((object)ex);
			}
			ES3.Save<APSaveData>(saveKey, saveData, es3Settings);
		}

		public static SerializableItemInfo GetScoutedLocation(long id)
		{
			if ((Plugin.connection.session != null || !SemiFunc.IsMasterClientOrSingleplayer()) && saveData.locationsScouted.ContainsKey(id))
			{
				return saveData.locationsScouted[id];
			}
			return null;
		}

		public static SerializableItemInfo GetScoutedShopItem(long id)
		{
			return GetScoutedLocation(id);
		}

		public static void AddPellyGathered(string name)
		{
			if (Plugin.connection.session == null || !SemiFunc.IsMasterClientOrSingleplayer())
			{
				return;
			}
			if (LocationNames.all_levels.Any((string x) => name.Contains(x)))
			{
				string text = LocationNames.all_levels.FirstOrDefault((string x) => name.Contains(x));
				int index = LocationNames.all_levels.IndexOf(text);
				name.Replace(text, LocationNames.all_levels_short[index]);
			}
			name = name.Replace("Valuable", "").Replace("(Clone)", "");
			if (!saveData.pellysGathered.Contains(name))
			{
				saveData.pellysGathered.Add(name);
			}
			ES3.Save<APSaveData>(saveKey, saveData, es3Settings);
		}

		public static void AddValuableGathered(string name)
		{
			name = LocationData.GetBaseName(name);
			if (Plugin.connection.session != null && SemiFunc.IsMasterClientOrSingleplayer())
			{
				if (!saveData.valuablesGathered.Contains(name))
				{
					saveData.valuablesGathered.Add(name);
				}
				ES3.Save<APSaveData>(saveKey, saveData, es3Settings);
			}
		}

		public static void AddMonsterSoulGathered(string name)
		{
			name = LocationData.GetBaseName(name);
			if (Plugin.connection.session != null && SemiFunc.IsMasterClientOrSingleplayer())
			{
				if (!saveData.monsterSoulsGathered.Contains(name))
				{
					saveData.monsterSoulsGathered.Add(name);
				}
				ES3.Save<APSaveData>(saveKey, saveData, es3Settings);
			}
		}

		public static bool WasValuableGathered(string name)
		{
			name = LocationData.GetBaseName(name);
			return saveData.valuablesGathered.Contains(name);
		}

		public static bool WasMonsterSoulGathered(string name)
		{
			name = LocationData.GetBaseName(name);
			return saveData.monsterSoulsGathered.Contains(name);
		}

		public static bool WasPellyGathered(string pelly, string level)
		{
			pelly = LocationData.GetBaseName(pelly);
			return saveData.pellysGathered.Exists((string x) => x.Contains(level) && x.Contains(pelly));
		}

		public static bool CheckCompletion(out string status)
		{
			if (Plugin.connection?.session == null)
			{
				status = string.Empty;
				return false;
			}
			_ = Plugin.connection.session.Locations.AllLocationsChecked;
			ReadOnlyCollection<long> allMissingLocations = Plugin.connection.session.Locations.AllMissingLocations;
			bool flag = true;
			long num = Math.Max(StatsManager.instance.GetRunStatLevel(), saveData.levelsCompleted);
			saveData.levelsCompleted = num;
			status = "";
			Plugin.Logger.LogInfo((object)"CheckComplete");
			Plugin.Logger.LogInfo((object)$"Current Level: {num}\nQuota: {saveData.levelQuota}");
			if (num < saveData.levelQuota)
			{
				Plugin.Logger.LogInfo((object)"Level Quota not met");
				flag = false;
			}
			status = string.Format("{{truck}} Levels - {0}/{1}{2}", num, saveData.levelQuota, (num >= saveData.levelQuota) ? " {check}" : " {X}");
			long pellysRequired = saveData.pellysRequired;
			int num2 = 0;
			Plugin.Logger.LogInfo((object)$"Pellys Required: {saveData.pellysRequired}");
			if (saveData.pellySpawning)
			{
				Plugin.Logger.LogInfo((object)"Pellys Gathered:");
				foreach (string item in saveData.pellysGathered)
				{
					Plugin.Logger.LogInfo((object)("-" + item));
					num2++;
				}
				Plugin.Logger.LogInfo((object)$"Pellys Collected: {num2}/{pellysRequired}");
				if (num2 < pellysRequired)
				{
					Plugin.Logger.LogInfo((object)"Pelly hunt not complete.");
					flag = false;
				}
				foreach (long item2 in allMissingLocations)
				{
					string locationNameFromId = Plugin.connection.session.Locations.GetLocationNameFromId(item2);
					if (locationNameFromId.Contains("Pelly"))
					{
						Plugin.Logger.LogInfo((object)("Missing " + locationNameFromId));
					}
				}
				if (RunManager.instance.levels.Contains(RunManager.instance.levelCurrent))
				{
					status = status + "<br>{?} " + RunManager.instance.levelCurrent.NarrativeName + " Pellys:<br><indent=10%>";
					string[] pellys = LocationNames.pellys;
					foreach (string pelly in pellys)
					{
						status += (saveData.pellysGathered.Any((string x) => x.Contains(pelly.ToString()) && x.Contains(((Object)RunManager.instance.levelCurrent).name)) ? (pelly.ToString().Replace(" Pelly", "") + " {check} | ") : (pelly.ToString().Replace(" Pelly", "") + " {X} | "));
					}
					status += "</indent>";
				}
				else
				{
					status += string.Format("<br>{{?}} Pellys - {0}/{1}{2}", num2, pellysRequired, (num2 == pellysRequired) ? " {check}" : " {X}");
				}
			}
			if (saveData.monsterHunt)
			{
				pellysRequired = LocationNames.all_monster_souls.Count;
				num2 = 0;
				Plugin.Logger.LogDebug((object)"Monster Hunt");
				foreach (string all_monster_soul in LocationNames.all_monster_souls)
				{
					if (!saveData.monsterSoulsGathered.Contains(all_monster_soul))
					{
						Plugin.Logger.LogDebug((object)(all_monster_soul + " has not been extracted"));
						flag = false;
					}
					else
					{
						Plugin.Logger.LogDebug((object)(all_monster_soul + " hunted"));
						num2++;
					}
				}
				status += string.Format("<br>{{ghost}} Souls - {0}/{1}{2}", num2, pellysRequired, (num2 == pellysRequired) ? " {check}" : " {X}");
			}
			if (saveData.valuableHunt)
			{
				pellysRequired = LocationNames.all_valuables.Count;
				num2 = 0;
				Plugin.Logger.LogDebug((object)"Valuable Hunt");
				foreach (string all_valuable in LocationNames.all_valuables)
				{
					if (!saveData.valuablesGathered.Contains(all_valuable))
					{
						Plugin.Logger.LogDebug((object)(all_valuable + " has not been extracted"));
						flag = false;
					}
					else
					{
						Plugin.Logger.LogDebug((object)(all_valuable + " extracted"));
						num2++;
					}
				}
				if (RunManager.instance.levels.Contains(RunManager.instance.levelCurrent))
				{
					List<string> list = new List<string>();
					foreach (LevelValuables valuablePreset in RunManager.instance.levelCurrent.ValuablePresets)
					{
						List<PrefabRef> list2 = new List<PrefabRef>();
						list2.AddRange(valuablePreset.tiny);
						list2.AddRange(valuablePreset.small);
						list2.AddRange(valuablePreset.medium);
						list2.AddRange(valuablePreset.big);
						list2.AddRange(valuablePreset.wide);
						list2.AddRange(valuablePreset.tall);
						list2.AddRange(valuablePreset.veryTall);
						List<PrefabRef> source = list2;
						list = list.Union(source.Select((PrefabRef prefab) => LocationData.GetBaseName(prefab.PrefabName))).ToList();
					}
					num2 = 0;
					pellysRequired = list.Intersect(LocationNames.all_valuables).Count();
					foreach (string item3 in list)
					{
						if (saveData.valuablesGathered.Contains(item3))
						{
							num2++;
						}
					}
					status += string.Format("<br>{{$$$}} {0} Valuables - {1}/{2}{3}", RunManager.instance.levelCurrent.NarrativeName, num2, pellysRequired, (num2 == pellysRequired) ? " {check}" : " {X}");
				}
				else
				{
					status += string.Format("<br>{{$$$}} Valuables - {0}/{1}{2}", num2, pellysRequired, (num2 == pellysRequired) ? " {check}" : " {X}");
				}
			}
			if (flag)
			{
				Plugin.Logger.LogInfo((object)"All Goals Complete.");
			}
			Plugin.connection.SyncCompletionProgress(num, saveData.pellysGathered, saveData.valuablesGathered, saveData.monsterSoulsGathered);
			return flag;
		}
	}
	public class ArchipelagoConnection
	{
		private struct messageData
		{
			public string message { get; }

			public Color flashCol { get; }

			public Color mainCol { get; }

			public float time { get; }

			public messageData(string m, Color fc, Color mc, float t)
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				message = m;
				flashCol = fc;
				mainCol = mc;
				time = t;
			}
		}

		[CompilerGenerated]
		private sealed class <CheckItemsReceived>d__33 : IEnumerator<bool>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private bool <>2__current;

			public ArchipelagoConnection <>4__this;

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

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

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

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

			private bool MoveNext()
			{
				int num = <>1__state;
				ArchipelagoConnection archipelagoConnection = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					break;
				case 1:
					<>1__state = -1;
					break;
				case 2:
					<>1__state = -1;
					break;
				}
				if (archipelagoConnection.connected)
				{
					if (archipelagoConnection.session.Items.AllItemsReceived.Count > archipelagoConnection.ItemIndex)
					{
						ItemInfo itemInfo = archipelagoConnection.session.Items.AllItemsReceived[archipelagoConnection.ItemIndex];
						string itemName = itemInfo.ItemName;
						Plugin.Logger.LogDebug((object)("Placing item " + itemName + " with index " + archipelagoConnection.ItemIndex + " in queue."));
						archipelagoConnection.incomingItems.Enqueue((itemInfo, archipelagoConnection.ItemIndex));
						archipelagoConnection.ItemIndex++;
						<>2__current = true;
						<>1__state = 1;
						return true;
					}
					<>2__current = true;
					<>1__state = 2;
					return true;
				}
				return false;
			}

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

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

		[CompilerGenerated]
		private sealed class <IncomingItemHandler>d__36 : IEnumerator<bool>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private bool <>2__current;

			public ArchipelagoConnection <>4__this;

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

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

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

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

			private bool MoveNext()
			{
				//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
				//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
				int num = <>1__state;
				ArchipelagoConnection archipelagoConnection = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					break;
				case 1:
					<>1__state = -1;
					break;
				case 2:
					<>1__state = -1;
					break;
				case 3:
					<>1__state = -1;
					break;
				}
				if (archipelagoConnection.connected)
				{
					if (!archipelagoConnection.incomingItems.TryPeek(out (ItemInfo, int) result))
					{
						<>2__current = true;
						<>1__state = 1;
						return true;
					}
					ItemInfo item = result.Item1;
					string itemName = item.ItemName;
					_ = itemName + " (" + item.ItemName + ") at index " + result.Item2;
					(ItemInfo, int) result2;
					if (APSave.GetItemReceivedIndex() > result.Item2)
					{
						archipelagoConnection.incomingItems.TryDequeue(out result2);
						Plugin.Logger.LogDebug((object)("Skipping item " + itemName + " at index " + result.Item2 + " as it has already been processed."));
						<>2__current = true;
						<>1__state = 2;
						return true;
					}
					Plugin.Logger.LogInfo((object)("ItemHandler " + item.ItemId));
					APSave.AddItemReceived(item.ItemId);
					if (!new List<Level>
					{
						RunManager.instance.levelMainMenu,
						RunManager.instance.levelLobby,
						RunManager.instance.levelLobbyMenu
					}.Contains(RunManager.instance.levelCurrent))
					{
						ItemData.AddItemToInventory(item.ItemId, repeatedAdditions: false);
						messageData item2 = new messageData("Received " + itemName, Color.green, Color.white, 3f);
						archipelagoConnection.messageItems.Enqueue(item2);
					}
					archipelagoConnection.incomingItems.TryDequeue(out result2);
					<>2__current = true;
					<>1__state = 3;
					return true;
				}
				return false;
			}

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

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

		[CompilerGenerated]
		private sealed class <MessageHandler>d__34 : IEnumerator<bool>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private bool <>2__current;

			public ArchipelagoConnection <>4__this;

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

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

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

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

			private bool MoveNext()
			{
				//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
				int num = <>1__state;
				ArchipelagoConnection archipelagoConnection = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					break;
				case 1:
					<>1__state = -1;
					break;
				case 2:
					<>1__state = -1;
					break;
				case 3:
					<>1__state = -1;
					break;
				}
				if (!SemiFunc.MenuLevel())
				{
					archipelagoConnection.messageDelay -= Time.deltaTime;
					if (archipelagoConnection.messageDelay > 0f)
					{
						<>2__current = true;
						<>1__state = 1;
						return true;
					}
					if (!archipelagoConnection.messageItems.TryDequeue(out var result))
					{
						<>2__current = true;
						<>1__state = 2;
						return true;
					}
					archipelagoConnection.messageDelay = 3.5f;
					Plugin.customRPCManager.CallFocusTextRPC(result.message, result.mainCol, result.flashCol, result.time, Plugin.customRPCManagerObject);
					<>2__current = true;
					<>1__state = 3;
					return true;
				}
				return false;
			}

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

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

		[CompilerGenerated]
		private sealed class <OutgoingItemHandler>d__35 : IEnumerator<bool>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private bool <>2__current;

			public ArchipelagoConnection <>4__this;

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

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

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

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

			private bool MoveNext()
			{
				int num = <>1__state;
				ArchipelagoConnection archipelagoConnection = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					break;
				case 1:
					<>1__state = -1;
					break;
				case 2:
					<>1__state = -1;
					break;
				}
				if (archipelagoConnection.connected)
				{
					if (!archipelagoConnection.outgoingItems.TryDequeue(out var result))
					{
						<>2__current = true;
						<>1__state = 1;
						return true;
					}
					string itemName = result.ItemName;
					string locationName = result.LocationName;
					_ = result.LocationId;
					string playerName = archipelagoConnection.session.Players.GetPlayerName(result.Player);
					Plugin.Logger.LogInfo((object)("Sent " + itemName + " at " + locationName + " for " + playerName));
					_ = (int)result.Player;
					_ = archipelagoConnection.session.ConnectionInfo.Slot;
					<>2__current = true;
					<>1__state = 2;
					return true;
				}
				return false;
			}

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

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

		public REPOPopupPage connectingPage;

		public ArchipelagoSession session;

		public IEnumerator<bool> incomingItemHandler;

		public IEnumerator<bool> outgoingItemHandler;

		public IEnumerator<bool> checkItemsReceived;

		public IEnumerator<bool> messageHandler;

		private float messageDelay;

		public bool sentCompletion;

		public bool sentRelease;

		public bool sentCollect;

		public Dictionary<string, object> slotData;

		public DeathLinkService deathLinkService;

		public int ItemIndex;

		private ConcurrentQueue<(ItemInfo NetworkItem, int index)> incomingItems;

		private ConcurrentQueue<SerializableItemInfo> outgoingItems;

		private ConcurrentQueue<messageData> messageItems;

		public bool connected
		{
			get
			{
				if (session == null)
				{
					return false;
				}
				return session.Socket.Connected;
			}
		}

		public event TickEventHandler TickInLevel;

		public async Task TryConnect(string address, int port, string pass, string player)
		{
			Plugin.Logger.LogDebug((object)"TryConnect");
			if (connected)
			{
				Plugin.Logger.LogDebug((object)"Already connected. Returning");
				return;
			}
			TryDisconnect();
			if (session == null)
			{
				try
				{
					session = ArchipelagoSessionFactory.CreateSession(address, port);
					Plugin.Logger.LogInfo((object)("Session at " + session.ToString()));
					if (Plugin.BoundConfig.DisplayAPMessagesOnTruckScreen.Value)
					{
						session.MessageLog.OnMessageReceived += MessageLog_OnMessageReceived;
					}
				}
				catch
				{
					Plugin.Logger.LogError((object)"Failed to create archipelago session!");
				}
			}
			messageHandler = MessageHandler();
			incomingItems = new ConcurrentQueue<(ItemInfo, int)>();
			outgoingItems = new ConcurrentQueue<SerializableItemInfo>();
			messageItems = new ConcurrentQueue<messageData>();
			LoginResult loginResult;
			try
			{
				await session.ConnectAsync();
				loginResult = await session.LoginAsync("R.E.P.O", player, ItemsHandlingFlags.AllItems, null, null, null, pass);
			}
			catch (Exception ex)
			{
				loginResult = new LoginFailure(ex.GetBaseException().Message);
			}
			if (loginResult is LoginSuccessful loginSuccessful)
			{
				slotData = loginSuccessful.SlotData;
				Plugin.Logger.LogInfo((object)"Successfully connected to Archipelago Multiworld server!");
				APSave.Init();
				APSave.ScoutLocations();
				if (!SemiFunc.MenuLevel())
				{
					messageData item = new messageData("Successfully Connected!", Color.white, Color.green, 3f);
					messageItems.Enqueue(item);
				}
				deathLinkService = session.CreateDeathLinkService();
				deathLinkService.OnDeathLinkReceived += HandleIncomingDeathlink;
				TickInLevel += DeathLinkPatch.ReceiveDeathLinkPatch;
				TickInLevel += TrapHandler.UseTrapPatch;
				if (DeathLinkEnabled())
				{
					deathLinkService.EnableDeathLink();
				}
				session.DataStorage["REPO-" + session.Players.GetPlayerName(session.ConnectionInfo.Slot) + "-levelsCompleted"].Initialize(JToken.op_Implicit(0));
				session.DataStorage["REPO-" + session.Players.GetPlayerName(session.ConnectionInfo.Slot) + "-pellysGathered"].Initialize((IEnumerable)new List<string>());
				session.DataStorage["REPO-" + session.Players.GetPlayerName(session.ConnectionInfo.Slot) + "-valuablesGathered"].Initialize((IEnumerable)new List<string>());
				session.DataStorage["REPO-" + session.Players.GetPlayerName(session.ConnectionInfo.Slot) + "-monsterSoulsGathered"].Initialize((IEnumerable)new List<string>());
				APSave.saveData.trapsUsed[ItemNames.monster_trap] = 0;
				APSave.saveData.trapsUsed[ItemNames.audit_trap] = 0;
				APSave.saveData.trapsUsed[ItemNames.lure_trap] = 0;
				APSave.saveData.trapsUsed[ItemNames.moon_phase_trap] = 0;
				session.DataStorage["REPO-" + Plugin.connection.session.Players.GetPlayerName(Plugin.connection.session.ConnectionInfo.Slot) + "-trapsUsed"].Initialize((JToken)(object)JObject.FromObject((object)APSave.saveData.trapsUsed));
				Plugin.connection.SyncCompletionProgress(APSave.saveData.levelsCompleted, APSave.saveData.pellysGathered, APSave.saveData.valuablesGathered, APSave.saveData.monsterSoulsGathered);
			}
			else
			{
				LoginFailure loginFailure = (LoginFailure)loginResult;
				string text = "Unable to connect to Archipelago Multiworld server:\n";
				string[] errors = loginFailure.Errors;
				foreach (string text2 in errors)
				{
					text = text + text2 + "\n";
				}
				text += "\n";
				ConnectionRefusedError[] errorCodes = loginFailure.ErrorCodes;
				for (int i = 0; i < errorCodes.Length; i++)
				{
					ConnectionRefusedError connectionRefusedError = errorCodes[i];
					text = text + connectionRefusedError.ToString() + "\n";
				}
				Plugin.Logger.LogWarning((object)text);
				TryDisconnect();
			}
			incomingItemHandler = IncomingItemHandler();
			outgoingItemHandler = OutgoingItemHandler();
			checkItemsReceived = CheckItemsReceived();
			if (SemiFunc.MenuLevel())
			{
				if (loginResult is LoginSuccessful)
				{
					Plugin.BoundConfig.APServerAddress.Value = Plugin.apAddress;
					Plugin.BoundConfig.APServerPort.Value = Plugin.apPort;
					Plugin.BoundConfig.APPassword.Value = Plugin.apPassword;
					Plugin.BoundConfig.APSlotName.Value = Plugin.apSlot;
				}
				connectingPage.ClosePage(false);
				MenuBuilder.BuildPopup();
			}
		}

		private string RGBtoHtmlStr(Color col)
		{
			return BitConverter.ToString(new byte[3] { col.R, col.G, col.B }).Replace("-", string.Empty);
		}

		private void MessageLog_OnMessageReceived(LogMessage message)
		{
			string text = string.Empty;
			MessagePart[] parts = message.Parts;
			foreach (MessagePart messagePart in parts)
			{
				_ = string.Empty;
				string empty = string.Empty;
				empty = RGBtoHtmlStr(messagePart.Color);
				text = ((!(empty != string.Empty)) ? (text + messagePart.Text) : (text + "<color=#" + empty + "><b>" + messagePart.Text + "</b></color>"));
			}
			HandleAPTruckScreenMessages.TruckScreenChatPatch.AddMessage("AP", text);
		}

		private void OnItemReceived(ReceivedItemsHelper helper)
		{
			ItemInfo itemInfo = helper.DequeueItem();
			Plugin.Logger.LogInfo((object)("OnItemReceived: " + itemInfo.ToString()));
		}

		public void TryDisconnect()
		{
			try
			{
				if (session != null)
				{
					session.Socket.DisconnectAsync();
					session = null;
				}
				incomingItems = new ConcurrentQueue<(ItemInfo, int)>();
				outgoingItems = new ConcurrentQueue<SerializableItemInfo>();
				deathLinkService = null;
				slotData = null;
				ItemIndex = 0;
				TickInLevel -= DeathLinkPatch.ReceiveDeathLinkPatch;
				TickInLevel -= TrapHandler.UseTrapPatch;
				Plugin.Logger.LogInfo((object)"Disconnected from Archipelago");
			}
			catch
			{
				Plugin.Logger.LogError((object)"Encountered an error disconnecting from Archipelago!");
			}
		}

		public async Task ClientDisconnected()
		{
			try
			{
				messageData item = new messageData("Client Disconnected! Trying to Reconnect...", Color.white, Color.red, 4f);
				messageItems.Enqueue(item);
				await TryConnect(Plugin.apAddress, int.Parse(Plugin.apPort), Plugin.apPassword, Plugin.apSlot);
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("Failure in reconnecting: " + ex.Message));
			}
		}

		public void ActivateCheck(long locationID)
		{
			if (APSave.saveData.locationsChecked.Contains(locationID))
			{
				return;
			}
			Plugin.Logger.LogInfo((object)("Checked Location " + locationID));
			session.Locations.CompleteLocationChecksAsync(locationID);
			APSave.AddLocationChecked(locationID);
			if (APSave.saveData.locationsScouted.ContainsKey(locationID))
			{
				outgoingItems.Enqueue(APSave.saveData.locationsScouted[locationID]);
				return;
			}
			session.Locations.ScoutLocationsAsync(locationID).ContinueWith(delegate(Task<Dictionary<long, ScoutedItemInfo>> locationInfoPacket)
			{
				foreach (ScoutedItemInfo value in locationInfoPacket.Result.Values)
				{
					outgoingItems.Enqueue(value.ToSerializable());
				}
			});
		}

		public void SyncLocations()
		{
			int count = session.Locations.AllLocationsChecked.Count;
			Dictionary<string, int> dictionary = StatsManager.instance.dictionaryOfDictionaries["archipelago items sent to other players"];
			if (count != dictionary.Count)
			{
				Plugin.Logger.LogWarning((object)"Locations Unsynced, resyncing...");
				Dictionary<string, int> dictionary2 = StatsManager.instance.dictionaryOfDictionaries["Locations Obtained"];
				Plugin.Logger.LogInfo((object)("Server: " + count + "\nClient Count: " + dictionary?.ToString() + "\nClient Raw: " + dictionary2.Count));
			}
		}

		public string GetLocationName(long id)
		{
			return session.Locations.GetLocationNameFromId(id);
		}

		public long GetLocationID(string name)
		{
			return session.Locations.GetLocationIdFromName("R.E.P.O", name);
		}

		public string GetItemName(long id)
		{
			return session.Items.GetItemName(id) ?? $"Item: {id}";
		}

		[IteratorStateMachine(typeof(<CheckItemsReceived>d__33))]
		private IEnumerator<bool> CheckItemsReceived()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <CheckItemsReceived>d__33(0)
			{
				<>4__this = this
			};
		}

		[IteratorStateMachine(typeof(<MessageHandler>d__34))]
		private IEnumerator<bool> MessageHandler()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <MessageHandler>d__34(0)
			{
				<>4__this = this
			};
		}

		[IteratorStateMachine(typeof(<OutgoingItemHandler>d__35))]
		private IEnumerator<bool> OutgoingItemHandler()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <OutgoingItemHandler>d__35(0)
			{
				<>4__this = this
			};
		}

		[IteratorStateMachine(typeof(<IncomingItemHandler>d__36))]
		private IEnumerator<bool> IncomingItemHandler()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <IncomingItemHandler>d__36(0)
			{
				<>4__this = this
			};
		}

		public void SendCompletion()
		{
			StatusUpdatePacket statusUpdatePacket = new StatusUpdatePacket();
			statusUpdatePacket.Status = ArchipelagoClientState.ClientGoal;
			session.Socket.SendPacket(statusUpdatePacket);
		}

		public void Release()
		{
			if (connected && sentCompletion && !sentRelease)
			{
				session.Socket.SendPacket(new SayPacket
				{
					Text = "!release"
				});
				sentRelease = true;
				Plugin.Logger.LogInfo((object)"Released remaining checks.");
			}
		}

		public void Collect()
		{
			if (connected && sentCompletion && !sentCollect)
			{
				session.Socket.SendPacket(new SayPacket
				{
					Text = "!collect"
				});
				sentCollect = true;
				Plugin.Logger.LogInfo((object)"Collected remaining items.");
			}
		}

		public async Task SyncCompletionProgress(long levels_completed, List<string> pellys_gathered, List<string> valuables_gathered, List<string> monster_souls_gathered)
		{
			if (connected)
			{
				Plugin.Logger.LogInfo((object)"Syncing completion progress to Archipelago data storage...");
				Task<long> getLevelsCompleted = SyncAPClientServerData("REPO-" + session.Players.GetPlayerName(session.ConnectionInfo.Slot) + "-levelsCompleted", levels_completed);
				Task<List<string>> getPellysGathered = SyncAPClientServerData("REPO-" + session.Players.GetPlayerName(session.ConnectionInfo.Slot) + "-pellysGathered", pellys_gathered);
				Task<List<string>> getValuablesGathered = SyncAPClientServerData("REPO-" + session.Players.GetPlayerName(session.ConnectionInfo.Slot) + "-valuablesGathered", valuables_gathered);
				Task<List<string>> getMonsterSoulsGathered = SyncAPClientServerData("REPO-" + session.Players.GetPlayerName(session.ConnectionInfo.Slot) + "-monsterSoulsGathered", monster_souls_gathered);
				APSaveData saveData = APSave.saveData;
				saveData.trapsUsed = await Plugin.connection.session.DataStorage["REPO-" + Plugin.connection.session.Players.GetPlayerName(Plugin.connection.session.ConnectionInfo.Slot) + "-trapsUsed"].GetAsync<Dictionary<string, int>>();
				saveData = APSave.saveData;
				saveData.levelsCompleted = await getLevelsCompleted;
				saveData = APSave.saveData;
				saveData.pellysGathered = await getPellysGathered;
				saveData = APSave.saveData;
				saveData.valuablesGathered = await getValuablesGathered;
				saveData = APSave.saveData;
				saveData.monsterSoulsGathered = await getMonsterSoulsGathered;
				Plugin.Logger.LogInfo((object)"Data storage sync complete");
			}
		}

		private async Task<long> SyncAPClientServerData(string serverDataKey, long localData)
		{
			long num = Math.Max(localData, await session.DataStorage[serverDataKey].GetAsync<long>());
			session.DataStorage[serverDataKey] = num;
			return num;
		}

		private async Task<List<string>> SyncAPClientServerData(string serverDataKey, List<string> localData)
		{
			List<string> serverData = await session.DataStorage[serverDataKey].GetAsync<List<string>>();
			foreach (string item in localData.Where((string element) => !serverData.Contains(element)))
			{
				serverData.Add(item);
			}
			session.DataStorage[serverDataKey] = serverData;
			return serverData;
		}

		public void SendDeathLink()
		{
			if (connected && SemiFunc.IsMasterClientOrSingleplayer() && DeathLinkEnabled())
			{
				deathLinkService.SendDeathLink(new DeathLink(session.Players.ActivePlayer.Name, session.Players.ActivePlayer.Name + " got scrapped by the Taxman."));
			}
		}

		public void HandleIncomingDeathlink(DeathLink deathLinkObject)
		{
			if (SemiFunc.IsMasterClientOrSingleplayer() && !SemiFunc.MenuLevel() && !DeathLinkPatch.awaitingDeathLink)
			{
				Plugin.Logger.LogInfo((object)"Received death link");
				DeathLinkPatch.playerWhoDied = deathLinkObject.Source;
				DeathLinkPatch.awaitingDeathLink = true;
			}
		}

		internal bool DeathLinkEnabled()
		{
			if (!Plugin.BoundConfig.OverrideMWDeathlink.Value || !Plugin.BoundConfig.Deathlink.Value)
			{
				if (!Plugin.BoundConfig.OverrideMWDeathlink.Value)
				{
					return (bool)Plugin.connection.slotData["death_link"];
				}
				return false;
			}
			return true;
		}

		internal void TickUpdate(RunManager __instance)
		{
			if (connected)
			{
				this.TickInLevel(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(PlayerController), "Update")]
	internal class CheckForDisconnect
	{
		private static double timeSinceLastCheck = 5.0;

		[HarmonyPostfix]
		private static void CheckDC()
		{
			if (SemiFunc.IsMasterClientOrSingleplayer() && !((Object)RunManager.instance.levelCurrent).name.Contains("Menu") && !((Object)RunManager.instance.levelCurrent).name.Contains("Splash") && !Plugin.connection.connected)
			{
				if (Plugin.reconnectTask == null)
				{
					Plugin.Logger.LogInfo((object)"Disconnected from AP Server");
					Plugin.reconnectTask = Plugin.connection.ClientDisconnected();
				}
				else if (Plugin.reconnectTask.Status == TaskStatus.RanToCompletion && timeSinceLastCheck >= 5.0)
				{
					Plugin.reconnectTask = null;
					timeSinceLastCheck = 0.0;
				}
				else
				{
					timeSinceLastCheck += Time.deltaTime;
				}
			}
		}
	}
	public class PluginConfig
	{
		public ConfigEntry<bool> DisplayAPMessagesOnTruckScreen;

		public ConfigEntry<uint> EnemyWeightIncrease;

		public ConfigEntry<uint> ValuableSubstitutionChance;

		public ConfigEntry<bool> Deathlink;

		public ConfigEntry<bool> OverrideMWDeathlink;

		public ConfigEntry<string> APServerAddress;

		public ConfigEntry<string> APServerPort;

		public ConfigEntry<string> APPassword;

		public ConfigEntry<string> APSlotName;

		public PluginConfig(ConfigFile cfg)
		{
			DisplayAPMessagesOnTruckScreen = cfg.Bind<bool>("General", "Display Archipelago messages on truck screen", true, "If true, the truck screen will display messages from the multiworld chat. Not recommended for large multiworlds due to the sheer volume of items being sent/received.");
			EnemyWeightIncrease = cfg.Bind<uint>("Bad Luck Protection", "Spawn weight increase for unextracted enemy souls", 50u, "Once half of all souls have been extracted, the spawn weight of enemies whose souls haven't been extracted is raised by this amount. Every enemy has a default spawn weight of 100. Remember that weights are NOT percentages, so a weight of 50 doesn't mean that a monster has a 50% chance to spawn. Minimum value is 0.");
			ValuableSubstitutionChance = cfg.Bind<uint>("Bad Luck Protection", "Chance to replace previously extracted valuables", 40u, "The chance to replace previously extracted valuables with undiscovered ones in the same size group, if possible. 0 means no valuables will be replaced, 50 means roughly half of all valuables will be replaced, 100 means all valuables will be replaced when possible. Minimum value is 0, maximum is 100.");
			Deathlink = cfg.Bind<bool>("General", "Enable death link", false, "When you die, everyone who enabled death link dies. Of course, the reverse is true too.");
			OverrideMWDeathlink = cfg.Bind<bool>("General", "Override yaml death link option", false, "If true, the mod config will be used to turn death link on/off instead of the yaml option.");
			APServerAddress = cfg.Bind<string>("Connection", "Address", "archipelago.gg", "The address of the multiworld server (usually archipelago.gg).");
			APServerPort = cfg.Bind<string>("Connection", "Port", "", "The port that the multiworld is hosted on.");
			APPassword = cfg.Bind<string>("Connection", "Password", "", "The password for the multiworld, if it has one.");
			APSlotName = cfg.Bind<string>("Connection", "Slot Name", "", "Your slot name in the multiworld.");
			ClearUnusedEntries(cfg);
		}

		private void ClearUnusedEntries(ConfigFile cfg)
		{
			((Dictionary<ConfigDefinition, string>)((object)cfg).GetType().GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(cfg, null)).Clear();
			cfg.Save();
		}
	}
	public class CustomRPCs : MonoBehaviour
	{
		public void CallUpdateItemNameRPC(string name, GameObject inst)
		{
			Plugin.Logger.LogInfo((object)"Calling UpdateItemNameRPC");
			PhotonView component = inst.GetComponent<PhotonView>();
			object[] array = new object[1] { name };
			component.RPC("UpdateItemNameRPC", (RpcTarget)3, array);
		}

		public void CallFocusTextRPC(string message, Color mainCol, Color flashCol, float lingerTime, GameObject inst)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (GameManager.instance.gameMode == 1)
			{
				PhotonView component = inst.GetComponent<PhotonView>();
				object[] array = new object[4] { message, mainCol, flashCol, lingerTime };
				component.RPC("FocusTextRPC", (RpcTarget)0, array);
			}
			else
			{
				FocusTextOffline(message, mainCol, flashCol, lingerTime);
			}
		}

		public void CallSyncSlotDataWithClientsRpc(GameObject inst)
		{
			if (GameManager.instance.gameMode == 1 && PhotonNetwork.IsMasterClient)
			{
				Plugin.Logger.LogInfo((object)"Syncing ap data with clients");
				PhotonView component = inst.GetComponent<PhotonView>();
				object[] array = new object[8]
				{
					Enumerable.ToArray(APSave.saveData.pellysGathered),
					Enumerable.ToArray(APSave.saveData.valuablesGathered),
					Enumerable.ToArray(APSave.saveData.monsterSoulsGathered),
					APSave.saveData.locationsScouted.ToDictionary((KeyValuePair<long, SerializableItemInfo> kvp) => kvp.Key, (KeyValuePair<long, SerializableItemInfo> kvp) => kvp.Value.ToJson(full: true)),
					APSave.saveData.pellysRequired,
					APSave.saveData.valuableHunt,
					APSave.saveData.monsterHunt,
					APSave.saveData.trapsUsed
				};
				component.RPC("SyncSlotDataWithClientsRpc", (RpcTarget)1, array);
			}
		}

		public void CallClientChangeMonsterOrbName(GameObject inst, string enemyName)
		{
			Plugin.Logger.LogInfo((object)"Calling ClientChangeMonsterOrbName");
			PhotonView component = inst.GetComponent<PhotonView>();
			object[] array = new object[1] { enemyName };
			component.RPC("ClientChangeMonsterOrbName", (RpcTarget)0, array);
		}

		public void CallSendClientDeathLink(GameObject inst, string playerWhoDied, string playerSteamID)
		{
			if (GameManager.instance.gameMode == 1 && PhotonNetwork.IsMasterClient)
			{
				Plugin.Logger.LogInfo((object)"Sending death link notification to clients");
				PhotonView component = inst.GetComponent<PhotonView>();
				object[] array = new object[2] { playerWhoDied, playerSteamID };
				component.RPC("SendClientDeathLink", (RpcTarget)0, array);
			}
		}

		public void CallClientDeathLinkFinished(GameObject inst, string playerSteamIdWhoWasPosessed)
		{
			Plugin.Logger.LogInfo((object)"Notifying clients that death link processing is finished");
			PhotonView component = inst.GetComponent<PhotonView>();
			object[] array = new object[1] { playerSteamIdWhoWasPosessed };
			component.RPC("ClientDeathLinkFinished", (RpcTarget)2, array);
		}

		public void CallPingClientsWithNoise(GameObject inst, string fieldName, Vector3 position)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			Plugin.Logger.LogInfo((object)"Playing lure trap sound for clients");
			PhotonView component = inst.GetComponent<PhotonView>();
			object[] array = new object[2] { fieldName, position };
			component.RPC("PingClientsWithNoise", (RpcTarget)0, array);
		}

		[PunRPC]
		public void UpdateItemNameRPC(string name, PhotonMessageInfo info)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			Plugin.Logger.LogInfo((object)"UpdateItemNameRPC Called");
			ItemAttributes component = ((Component)info.photonView).gameObject.GetComponent<ItemAttributes>();
			AccessTools.Field(typeof(ItemAttributes), "itemName").SetValue(component, name.Replace("_", " "));
		}

		[PunRPC]
		public void FocusTextRPC(string message, Color mainCol, Color flashCol, float lingerTime)
		{
			//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)
			SemiFunc.UIFocusText(message, mainCol, flashCol, lingerTime);
		}

		public void FocusTextOffline(string message, Color mainCol, Color flashCol, float lingerTime)
		{
			//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)
			SemiFunc.UIFocusText(message, mainCol, flashCol, lingerTime);
		}

		[PunRPC]
		public void SyncSlotDataWithClientsRpc(string[] pellys_gathered, string[] valuables_gathered, string[] monster_souls_gathered, Dictionary<long, string> locations_scouted, long pellys_required, bool valuable_hunt, bool monster_hunt, Dictionary<string, int> trapsUsed)
		{
			if (APSave.saveData == null)
			{
				APSave.saveData = new APSaveData();
			}
			APSave.saveData.pellysGathered = pellys_gathered.ToList();
			APSave.saveData.valuablesGathered = valuables_gathered.ToList();
			APSave.saveData.monsterSoulsGathered = monster_souls_gathered.ToList();
			APSave.saveData.locationsScouted = locations_scouted.ToDictionary((KeyValuePair<long, string> kvp) => kvp.Key, (KeyValuePair<long, string> kvp) => SerializableItemInfo.FromJson(kvp.Value));
			APSave.saveData.pellysRequired = pellys_required;
			APSave.saveData.valuableHunt = valuable_hunt;
			APSave.saveData.monsterHunt = monster_hunt;
			APSave.saveData.trapsUsed = trapsUsed;
			Plugin.Logger.LogInfo((object)"Ap data synced with host");
		}

		[PunRPC]
		public void ClientChangeMonsterOrbName(string enemyName)
		{
			EnemyDespawnPatch.ChangeEnemyOrbNames(enemyName);
		}

		[PunRPC]
		public void SendClientDeathLink(string apPlayerWhoDied, string chosenPlayerSteamID)
		{
			DeathLinkPatch.PosessDeathlink(apPlayerWhoDied, chosenPlayerSteamID);
		}

		[PunRPC]
		public void ClientDeathLinkFinished(string playerSteamIdWhoWasPosessed)
		{
			DeathLinkPatch.DeathLinkFinished(playerSteamIdWhoWasPosessed);
		}

		[PunRPC]
		public void PingClientsWithNoise(string soundFieldName, Vector3 position)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			Sound val = (Sound)(AccessTools.Field(typeof(PlayerAvatar), soundFieldName)?.GetValue(PlayerAvatar.instance));
			if (val == null)
			{
				Plugin.Logger.LogError((object)("Unable to play sound. No field found with the name '" + soundFieldName + "'"));
			}
			else
			{
				val.Play(position, 1f, 2f, 1f, 1f);
			}
		}
	}
	[HarmonyPatch(typeof(TruckScreenText), "GotoNextLevel")]
	internal class NextLevelCheckCompletePatch
	{
		[HarmonyPostfix]
		private static void CheckComplete()
		{
			Plugin.Logger.LogInfo((object)"Truck Go To Next");
			if (APSave.CheckCompletion(out var _))
			{
				Plugin.connection.SendCompletion();
			}
		}
	}
	[BepInPlugin("Automagic.ArchipelagoREPO", "Archipelago Randomizer", "0.4.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Logger = null;

		public static ArchipelagoConnection connection;

		public static Task reconnectTask = null;

		public static PlayerController _player;

		public static CustomRPCs customRPCManager;

		public static GameObject customRPCManagerObject;

		public static bool showMenu = true;

		public static string apAddress;

		public static string apPort;

		public static string apPassword;

		public static string apSlot;

		public static int LastShopItemChecked = 0;

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

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

		internal static PluginConfig BoundConfig { get; private set; } = null;


		private void Awake()
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			Logger = ((BaseUnityPlugin)this).Logger;
			_player = PlayerController.instance;
			BoundConfig = new PluginConfig(((BaseUnityPlugin)this).Config);
			apAddress = BoundConfig.APServerAddress.Value;
			apPort = BoundConfig.APServerPort.Value;
			apPassword = BoundConfig.APPassword.Value;
			apSlot = BoundConfig.APSlotName.Value;
			Logger.LogInfo((object)"Plugin RepoAP is loaded!");
			Harmony val = new Harmony("RepoAP");
			val.PatchAll();
			val.PatchAll(typeof(DeathLinkPatch));
			val.PatchAll(typeof(ShopPopulateItemVolumesPatch));
			val.PatchAll(typeof(UpgradeSpawningPatch));
			val.PatchAll(typeof(APItemNamePatch));
			val.PatchAll(typeof(EnemyDespawnPatch));
			val.PatchAll(typeof(TrapHandler));
			val.PatchAll(typeof(Events));
		}

		internal static void Initialize()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			Logger.LogDebug((object)"In Initialize");
			connection = new ArchipelagoConnection();
			customRPCManagerObject = new GameObject("RepoAPCustomRPCManager")
			{
				hideFlags = (HideFlags)61
			};
			customRPCManagerObject.SetActive(false);
			customRPCManager = customRPCManagerObject.AddComponent<CustomRPCs>();
			customRPCManagerObject.AddComponent<PhotonView>();
			Object.DontDestroyOnLoad((Object)(object)customRPCManager);
			string text = "RepoAP/" + ((Object)customRPCManagerObject).name;
			PrefabRef val = NetworkPrefabs.RegisterNetworkPrefab(text, customRPCManagerObject);
			if (val != null)
			{
				NetworkPrefabs.SpawnNetworkPrefab(val, Vector3.zero, Quaternion.identity, (byte)0, (object[])null);
				Logger.LogInfo((object)"Registered customRPCManagerObject for multiplayer RPCs.");
			}
			else
			{
				Logger.LogError((object)"Failed to register customRPCManagerObject. Multiplayer may be borked.");
			}
			customRPCManagerObject.GetComponent<PhotonView>().ViewID = text.GetHashCode();
			Logger.LogDebug((object)$"customRPCManagerObject has ViewID {customRPCManagerObject.GetComponent<PhotonView>().ViewID}");
			ItemData.CreateItemDataTable();
		}

		public static ArchipelagoConnection GetConnection()
		{
			return connection;
		}

		public void CheckLocation(long locID)
		{
			connection.ActivateCheck(locID);
		}

		public static void ProcessItems()
		{
			if (connection.connected)
			{
				connection.checkItemsReceived?.MoveNext();
				connection.incomingItemHandler?.MoveNext();
				connection.outgoingItemHandler?.MoveNext();
				connection.messageHandler?.MoveNext();
			}
		}

		public static void UpdateAPAddress(string input)
		{
			apAddress = input;
		}
	}
	[HarmonyPatch(typeof(GameManager))]
	internal static class GameManagerPatch
	{
		[HarmonyPatch("Awake")]
		[HarmonyPostfix]
		public static void AwakePatch(GameManager __instance)
		{
			if (!((Object)(object)__instance != (Object)(object)GameManager.instance))
			{
				Plugin.Initialize();
			}
		}
	}
	[HarmonyPatch(typeof(RunManager))]
	internal static class RunManagerPatch
	{
		[HarmonyPatch("Update")]
		[HarmonyPostfix]
		public static void UpdatePatch()
		{
			Plugin.ProcessItems();
		}
	}
	[HarmonyPatch(typeof(MenuPageSaves), "OnLoadGame")]
	internal class PreventLoadingRunWhenNotConnectedPatch
	{
		[HarmonyPrefix]
		private static bool OnLoadGamePatch()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.connection.session == null || !Plugin.connection.connected)
			{
				MenuManager.instance.PageCloseAllAddedOnTop();
				MenuManager.instance.PagePopUp("Not Connected", Color.red, "Not connected to AP server. Please connect before loading a save.", "OK", true);
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(MenuPageSaves), "OnNewGame")]
	internal class PreventNewRunWhenNotConnectedPatch
	{
		[HarmonyPrefix]
		private static bool OnNewGamePatch()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.connection.session == null || !Plugin.connection.connected)
			{
				MenuManager.instance.PageCloseAllAddedOnTop();
				MenuManager.instance.PagePopUp("Not Connected", Color.red, "Not connected to AP server. Please connect before creating a save.", "OK", true);
				return false;
			}
			return true;
		}
	}
	internal class ItemData
	{
		private const int baseID = 75912022;

		public const int shopStockID = 10;

		public static Dictionary<long, string> itemIDToName;

		public static Dictionary<string, long> itemNameToID;

		public static void CreateItemDataTable()
		{
			itemIDToName = new Dictionary<long, string>();
			itemNameToID = new Dictionary<string, long>();
			List<string> list = new List<string>();
			List<long> list2 = new List<long>();
			int num = 10;
			list2.Add(0L);
			list.Add(LocationNames.swiftbroom_academy);
			list2.Add(1L);
			list.Add(LocationNames.headman_manor);
			list2.Add(2L);
			list.Add(LocationNames.mcjannek_station);
			list2.Add(3L);
			list.Add(LocationNames.museum_of_human_art);
			list2.Add(num++);
			list.Add(ItemNames.shop_stock);
			list2.Add(num++);
			list.Add(ItemNames.upgrade_health);
			list2.Add(num++);
			list.Add(ItemNames.upgrade_strength);
			list2.Add(num++);
			list.Add(ItemNames.upgrade_range);
			list2.Add(num++);
			list.Add(ItemNames.upgrade_sprint_speed);
			list2.Add(num++);
			list.Add(ItemNames.upgrade_stamina);
			list2.Add(num++);
			list.Add(ItemNames.upgrade_player_count);
			list2.Add(num++);
			list.Add(ItemNames.upgrade_double_jump);
			list2.Add(num++);
			list.Add(ItemNames.upgrade_tumble_launch);
			list2.Add(num++);
			list.Add(ItemNames.upgrade_crouch_rest);
			list2.Add(num++);
			list.Add(ItemNames.upgrade_tumble_wings);
			list2.Add(num++);
			list.Add(ItemNames.upgrade_tumble_climb);
			list2.Add(num++);
			list.Add(ItemNames.upgrade_death_head_battery);
			list2.Add(num++);
			list.Add(ItemNames.small_health);
			list2.Add(num++);
			list.Add(ItemNames.progressive_health);
			list2.Add(num++);
			list.Add(ItemNames.baseball_bat);
			list2.Add(num++);
			list.Add(ItemNames.frying_pan);
			list2.Add(num++);
			list.Add(ItemNames.sledge_hammer);
			list2.Add(num++);
			list.Add(ItemNames.sword);
			list2.Add(num++);
			list.Add(ItemNames.inflatable_hammer);
			list2.Add(num++);
			list.Add(ItemNames.prodzap);
			list2.Add(num++);
			list.Add(ItemNames.gun);
			list2.Add(num++);
			list.Add(ItemNames.shotgun);
			list2.Add(num++);
			list.Add(ItemNames.tranq_gun);
			list2.Add(num++);
			list.Add(ItemNames.pulse_pistol);
			list2.Add(num++);
			list.Add(ItemNames.photon_blaster);
			list2.Add(num++);
			list.Add(ItemNames.boltzap);
			list2.Add(num++);
			list.Add(ItemNames.cart_cannon);
			list2.Add(num++);
			list.Add(ItemNames.cart_laser);
			list2.Add(num++);
			list.Add(ItemNames.grenade);
			list2.Add(num++);
			list.Add(ItemNames.shock_grenade);
			list2.Add(num++);
			list.Add(ItemNames.human_grenade);
			list2.Add(num++);
			list.Add(ItemNames.stun_grenade);
			list2.Add(num++);
			list.Add(ItemNames.duct_taped_grenade);
			list2.Add(num++);
			list.Add(ItemNames.shockwave_mine);
			list2.Add(num++);
			list.Add(ItemNames.stun_mine);
			list2.Add(num++);
			list.Add(ItemNames.explosive_mine);
			list2.Add(num++);
			list.Add(ItemNames.rubber_duck);
			list2.Add(num++);
			list.Add(ItemNames.recharge_drone);
			list2.Add(num++);
			list.Add(ItemNames.indestructible_drone);
			list2.Add(num++);
			list.Add(ItemNames.roll_drone);
			list2.Add(num++);
			list.Add(ItemNames.feather_drone);
			list2.Add(num++);
			list.Add(ItemNames.zero_grav_drone);
			list2.Add(num++);
			list.Add(ItemNames.pocket_cart);
			list2.Add(num++);
			list.Add(ItemNames.cart);
			list2.Add(num++);
			list.Add(ItemNames.valuable_detector);
			list2.Add(num++);
			list.Add(ItemNames.extraction_detector);
			list2.Add(num++);
			list.Add(ItemNames.energy_crystal);
			list2.Add(num++);
			list.Add(ItemNames.zero_grav_orb);
			list2.Add(num++);
			list.Add(ItemNames.duck_bucket);
			list2.Add(num++);
			list.Add(ItemNames.phase_bridge);
			list2.Add(num++);
			list.Add(ItemNames.monster_trap);
			list2.Add(num++);
			list.Add(ItemNames.audit_trap);
			list2.Add(num++);
			list.Add(ItemNames.lure_trap);
			list2.Add(num++);
			list.Add(ItemNames.moon_phase_trap);
			for (int i = 0; i < list2.Count; i++)
			{
				itemIDToName.Add(list2[i], list[i]);
				itemNameToID.Add(list[i], list2[i]);
			}
		}

		public static void AddItemToInventory(long itemId, bool repeatedAdditions)
		{
			string text = IdToItemName(RemoveBaseId(itemId));
			Plugin.Logger.LogDebug((object)("Attempting to add item to inventory: " + RemoveBaseId(itemId) + " : " + text));
			if (LocationNames.all_levels.Contains(text))
			{
				APSave.AddLevelReceived(text);
			}
			else if (text == ItemNames.shop_stock)
			{
				APSave.AddStockReceived();
				APSave.UpdateAvailableItems();
			}
			else if (text.Contains("Upgrade") || text.Contains("Item Health Pack"))
			{
				if (!StatsManager.instance.runStats.TryGetValue(text + " ReceivedFromAP", out var value))
				{
					PunManager.instance.SetRunStatSet(text + " ReceivedFromAP", 0);
					value = 0;
				}
				if (APSave.GetItemsReceived()[itemId] > value)
				{
					StatsManager.instance.ItemPurchase(text);
					PunManager.instance.SetRunStatSet(text + " ReceivedFromAP", value + 1);
				}
				else
				{
					Plugin.Logger.LogDebug((object)("Item " + text + " has already been received. Skipping..."));
				}
			}
		}

		public static string IdToItemName(long itemId)
		{
			return itemIDToName[itemId];
		}

		public static long RemoveBaseId(long id)
		{
			return id - 75912022;
		}

		public static long AddBaseId(long id)
		{
			return id + 75912022;
		}
	}
	public static class ItemNames
	{
		public static string shop_stock = "Progressive Shop Stock";

		public static string upgrade_player_count = "Item Upgrade Map Player Count";

		public static string upgrade_crouch_rest = "Item Upgrade Player Crouch Rest";

		public static string upgrade_stamina = "Item Upgrade Player Energy";

		public static string upgrade_double_jump = "Item Upgrade Player Extra Jump";

		public static string upgrade_range = "Item Upgrade Player Grab Range";

		public static string upgrade_strength = "Item Upgrade Player Grab Strength";

		public static string upgrade_health = "Item Upgrade Player Health";

		public static string upgrade_sprint_speed = "Item Upgrade Player Sprint Speed";

		public static string upgrade_tumble_launch = "Item Upgrade Player Tumble Launch";

		public static string upgrade_tumble_wings = "Item Upgrade Player Tumble Wings";

		public static string upgrade_tumble_climb = "Item Upgrade Player Tumble Climb";

		public static string upgrade_death_head_battery = "Item Upgrade Death Head Battery";

		public static string valuable_tracker = "Item Valuable Tracker";

		public static string ap_item = "Item Upgrade AP Item";

		public static string progressive_health = "Progressive Health Pack Unlock";

		public static string small_health = "Item Health Pack Small";

		public static string baseball_bat = "Baseball Bat Unlock";

		public static string frying_pan = "Frying Pan Unlock";

		public static string sledge_hammer = "Sledge Hammer Unlock";

		public static string sword = "Sword Unlock";

		public static string inflatable_hammer = "Inflatable Hammer Unlock";

		public static string prodzap = "Prodzap Unlock";

		public static string gun = "Gun Unlock";

		public static string shotgun = "Shotgun Unlock";

		public static string tranq_gun = "Tranq Gun Unlock";

		public static string pulse_pistol = "Pulse Pistol Unlock";

		public static string photon_blaster = "Photon Blaster Unlock";

		public static string boltzap = "Boltzap Unlock";

		public static string cart_cannon = "C.A.R.T. Cannon Unlock";

		public static string cart_laser = "C.A.R.T. Laser Unlock";

		public static string grenade = "Grenade Unlock";

		public static string shock_grenade = "Shockwave Grenade Unlock";

		public static string stun_grenade = "Stun Grenade Unlock";

		public static string human_grenade = "Human Grenade Unlock";

		public static string duct_taped_grenade = "Duct Taped Grenades Unlock";

		public static string shockwave_mine = "Shockwave Mine Unlock";

		public static string stun_mine = "Trapzap Unlock";

		public static string explosive_mine = "Explosive Mine Unlock";

		public static string rubber_duck = "Rubber Duck Unlock";

		public static string recharge_drone = "Recharge Drone Unlock";

		public static string indestructible_drone = "Indestructible Drone Unlock";

		public static string roll_drone = "Roll Drone Unlock";

		public static string feather_drone = "Feather Drone Unlock";

		public static string zero_grav_drone = "Zero Gravity Drone Unlock";

		public static string pocket_cart = "POCKET C.A.R.T. Unlock";

		public static string cart = "C.A.R.T. Unlock";

		public static string valuable_detector = "Valuable Tracker Unlock";

		public static string extraction_detector = "Extraction Tracker Unlock";

		public static string energy_crystal = "Energy Crystal Unlock";

		public static string zero_grav_orb = "Zero Gravity Orb Unlock";

		public static string duck_bucket = "Duck Bucket Unlock";

		public static string phase_bridge = "Phase Bridge Unlock";

		public static string monster_trap = "Extra Monster Trap";

		public static string audit_trap = "Audit Trap";

		public static string lure_trap = "Monster Lure Trap";

		public static string moon_phase_trap = "Progressive Moon Phase Trap";
	}
	[HarmonyPatch(typeof(RunManager), "SetRunLevel")]
	internal class LevelLockPatch
	{
		internal static int levelIndex = -1;

		[HarmonyPostfix]
		private static void SetRunLevelPre(RunManager __instance)
		{
			Dictionary<string, bool> levelsReceived = APSave.GetLevelsReceived();
			if ((levelsReceived != null && levelsReceived.Count == 0) || Plugin.connection.session == null)
			{
				Plugin.Logger.LogError((object)"No Levels found in Save!");
				return;
			}
			Dictionary<string, bool> levelsReceived2 = APSave.GetLevelsReceived();
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, bool> item in levelsReceived2)
			{
				Plugin.Logger.LogDebug((object)("Player has " + item.Key));
				list.Add(item.Key);
			}
			int[] array = new int[list.Count];
			int num = 0;
			Plugin.Logger.LogDebug((object)"Calculating level weights based on valuables gathered...");
			foreach (string levelName in list)
			{
				Level val2 = ((IEnumerable<Level>)__instance.levels).FirstOrDefault((Func<Level, bool>)((Level lev) => levelName.Contains(lev.NarrativeName)));
				if ((Object)(object)val2 == (Object)null)
				{
					Plugin.Logger.LogWarning((object)("Level " + levelName + " not found in RunManager levels when selecting a weight!"));
					array[num] = 0;
					num++;
					continue;
				}
				List<PrefabRef> list2 = new List<PrefabRef>();
				foreach (LevelValuables valuablePreset in val2.ValuablePresets)
				{
					list2.AddRange(valuablePreset.tiny);
					list2.AddRange(valuablePreset.small);
					list2.AddRange(valuablePreset.medium);
					list2.AddRange(valuablePreset.big);
					list2.AddRange(valuablePreset.wide);
					list2.AddRange(valuablePreset.tall);
					list2.AddRange(valuablePreset.veryTall);
				}
				int count = list2.Count;
				int num2 = list2.Count((PrefabRef val) => !val.PrefabName.Contains("Pelly") && !APSave.WasValuableGathered(val.PrefabName));
				Plugin.Logger.LogDebug((object)$"Level {val2.NarrativeName} has {num2}/{count} valuables left to collect (besides pellys).");
				int num3 = (int)(100f * (float)num2 / (float)count);
				foreach (PrefabRef item2 in list2.Where((PrefabRef val) => val.PrefabName.Contains("Pelly")))
				{
					num3 += ((!APSave.WasPellyGathered(item2.PrefabName, ((Object)val2).name)) ? 5 : 0);
				}
				Plugin.Logger.LogDebug((object)$"Assigned level {val2.NarrativeName} a weight of {num3}");
				array[num] = num3;
				num++;
			}
			if (array.Sum() == 0)
			{
				Plugin.Logger.LogInfo((object)"All valuables collected! Defaulting to random level selection.");
				levelIndex = Random.RandomRangeInt(0, list.Count);
			}
			else
			{
				int num4 = Random.RandomRangeInt(0, array.Sum());
				int num5 = 0;
				for (int i = 0; i < array.Length; i++)
				{
					num5 += array[i];
					if (num4 < num5)
					{
						levelIndex = i;
						Plugin.Logger.LogInfo((object)$"Selected {list[levelIndex]} ({(float)array[levelIndex] * 100f / (float)array.Sum()}% chance)");
						break;
					}
				}
			}
			string text = list[levelIndex];
			Level levelCurrent = null;
			Plugin.Logger.LogInfo((object)("Setting level to " + text));
			foreach (Level level in __instance.levels)
			{
				if (text.Contains(level.NarrativeName))
				{
					levelCurrent = level;
				}
				else
				{
					Plugin.Logger.LogDebug((object)(level.NarrativeName + " != " + text));
				}
			}
			__instance.levelCurrent = levelCurrent;
			Plugin.Logger.LogDebug((object)("Returning " + ((Object)__instance.levelCurrent).name));
			Plugin.customRPCManager.CallSyncSlotDataWithClientsRpc(Plugin.customRPCManagerObject);
		}
	}
	[HarmonyPatch(typeof(PunManager), "Start")]
	internal class DisplayCompletionStatusPatch
	{
		private static void Postfix()
		{
			if (!((Object)RunManager.instance.levelCurrent).name.Contains("Menu"))
			{
				APSave.CheckCompletion(out var status);
				HandleAPTruckScreenMessages.TruckScreenChatPatch.AddMessage("AP", status);
			}
		}
	}
	internal class EnemyDespawnPatch
	{
		[HarmonyPatch(typeof(EnemyParent), "Despawn")]
		[HarmonyPostfix]
		private static void OrbNaming(ref string ___enemyName, ref Enemy ___Enemy)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			bool num = (bool)AccessTools.Field(typeof(Enemy), "HasHealth").GetValue(___Enemy);
			EnemyHealth val = (EnemyHealth)AccessTools.Field(typeof(Enemy), "Health").GetValue(___Enemy);
			int num2 = (int)AccessTools.Field(typeof(EnemyHealth), "healthCurrent").GetValue(val);
			if (num && val.spawnValuable && num2 <= 0)
			{
				if (!SemiFunc.IsMultiplayer())
				{
					ChangeEnemyOrbNames(___enemyName);
				}
				else
				{
					Plugin.customRPCManager.CallClientChangeMonsterOrbName(Plugin.customRPCManagerObject, ___enemyName);
				}
			}
		}

		internal static void ChangeEnemyOrbNames(string enemyName)
		{
			EnemyValuable[] array = (EnemyValuable[])(object)Object.FindObjectsByType(typeof(EnemyValuable), (FindObjectsSortMode)0);
			foreach (EnemyValuable val in array)
			{
				if (((Object)val).name.Contains("Enemy Valuable"))
				{
					((Object)val).name = enemyName + " Soul";
				}
			}
		}
	}
	internal class ExtractSendCheck
	{
		private static void CheckValuable(GameObject valuableObject)
		{
			Plugin.Logger.LogInfo((object)("Extracting " + ((Object)valuableObject).name));
			if (!Object.op_Implicit((Object)(object)valuableObject) || !Object.op_Implicit((Object)(object)valuableObject.GetComponent<PhysGrabObject>()))
			{
				return;
			}
			if (((Object)valuableObject).name.Contains("Pelly"))
			{
				Plugin.connection.ActivateCheck(LocationData.PellyNameToID(((Object)valuableObject).name + ((Object)RunManager.instance.levelCurrent).name));
				APSave.AddPellyGathered(((Object)RunManager.instance.levelCurrent).name + ((Object)valuableObject).name);
			}
			else if (((Object)valuableObject).name.Contains("Soul"))
			{
				long num = LocationData.MonsterSoulNameToID(((Object)valuableObject).name);
				if (LocationData.RemoveBaseId(num) != 0L)
				{
					Plugin.connection.ActivateCheck(num);
					APSave.AddMonsterSoulGathered(((Object)valuableObject).name);
				}
			}
			else if (((Object)valuableObject).name.Contains("Valuable"))
			{
				long num2 = LocationData.ValuableNameToID(((Object)valuableObject).name);
				if (LocationData.RemoveBaseId(num2) != 0L)
				{
					Plugin.connection.ActivateCheck(num2);
					APSave.AddValuableGathered(((Object)valuableObject).name);
				}
			}
		}

		public static void Send(FieldInfo totalHaulField)
		{
			if (!SemiFunc.IsMasterClientOrSingleplayer() || RoundDirector.instance.dollarHaulList.Count <= 0)
			{
				return;
			}
			foreach (GameObject dollarHaul in RoundDirector.instance.dollarHaulList)
			{
				CheckValuable(dollarHaul);
			}
		}

		public static void SendFirst(FieldInfo totalHaulField)
		{
			if (SemiFunc.IsMasterClientOrSingleplayer() && RoundDirector.instance.dollarHaulList.Count > 0)
			{
				CheckValuable(RoundDirector.instance.dollarHaulList[0]);
			}
		}
	}
	[HarmonyPatch(typeof(ExtractionPoint))]
	internal class ExtractionSendCheckPatch
	{
		private static FieldInfo field = AccessTools.Field(typeof(RoundDirector), "totalHaul");

		[HarmonyPrefix]
		[HarmonyPatch("DestroyAllPhysObjectsInHaulList")]
		private static void ExtractAllPatch()
		{
			if (Plugin.connection != null)
			{
				ExtractSendCheck.Send(field);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch("DestroyTheFirstPhysObjectsInHaulList")]
		private static void ExtractFirstPatch()
		{
			if (Plugin.connection != null)
			{
				ExtractSendCheck.SendFirst(field);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("DestroyAllPhysObjectsInHaulList")]
		private static void ExtractAllSyncWithClientsPatch()
		{
			if (Plugin.connection != null)
			{
				Plugin.customRPCManager.CallSyncSlotDataWithClientsRpc(Plugin.customRPCManagerObject);
			}
		}
	}
	internal static class LocationData
	{
		private const int baseID = 75912022;

		public const int pellyOffset = 100;

		public const int valuableOffset = 200;

		public const int monsterOffset = 500;

		public static void CreateLocationTables()
		{
			for (int i = 0; i < 100; i++)
			{
			}
		}

		public static string GetBaseName(string name)
		{
			name = name.Replace("Valuable ", "").Replace("(Clone)", "");
			foreach (string item in LocationNames.all_levels_short)
			{
				name = name.Replace(item + " ", "");
			}
			return name;
		}

		public static long MonsterSoulNameToID(string name)
		{
			long num = 0L;
			name = GetBaseName(name);
			num = LocationNames.all_monster_souls.IndexOf(name);
			if (num == -1)
			{
				Plugin.Logger.LogWarning((object)(name + "'s id not found"));
				num = 0L;
			}
			else
			{
				num += 500;
			}
			return 75912022 + num;
		}

		public static string MonsterSoulIDToName(long id)
		{
			id -= 75912022;
			id -= 500;
			return LocationNames.all_monster_souls[(int)id];
		}

		public static long ValuableNameToID(string name)
		{
			long num = 0L;
			name = GetBaseName(name);
			num = LocationNames.all_valuables.IndexOf(name);
			if (num == -1)
			{
				Plugin.Logger.LogWarning((object)(name + "'s id not found"));
				num = 0L;
			}
			else
			{
				num += 200;
			}
			return 75912022 + num;
		}

		public static string ValuableIDToName(long id)
		{
			id -= 75912022;
			id -= 200;
			return LocationNames.all_valuables[(int)id];
		}

		public static long PellyNameToID(string name)
		{
			int num = 100;
			int num2 = 1;
			foreach (string item in LocationNames.all_levels_short)
			{
				if (name.Contains(item))
				{
					num += num2;
					break;
				}
				num2 += 3;
			}
			num2 = 0;
			foreach (string all_pelly in LocationNames.all_pellys)
			{
				if (name.Contains(all_pelly))
				{
					num += num2;
					break;
				}
				num2++;
			}
			return 75912022 + num;
		}

		public static long ShopItemToID(string name)
		{
			if (name.Any(char.IsDigit))
			{
				name = new string(name.Where((char x) => char.IsDigit(x)).ToArray());
				int num = int.Parse(name);
				return 75912022 + num;
			}
			return 0L;
		}

		public static long RemoveBaseId(long id)
		{
			return id - 75912022;
		}

		public static long AddBaseId(long id)
		{
			return id + 75912022;
		}
	}
	internal class LocationNames
	{
		public static string standard_pelly = "Standard Pelly";

		public static string glass_pelly = "Glass Pelly";

		public static string gold_pelly = "Gold Pelly";

		public static string[] pellys = new string[3] { standard_pelly, glass_pelly, gold_pelly };

		public static string upgrade_pur = "Upgrade Purchase";

		public static string swiftbroom_academy = "Swiftbroom Academy ";

		public static string headman_manor = "Headman Manor ";

		public static string mcjannek_station = "McJannek Station ";

		public static string museum_of_human_art = "Museum of Human Art ";

		public const string goblet = "Goblet";

		public const string uranium_mug = "Uranium Mug";

		public const string emerald_bracelet = "Emerald Bracelet";

		public const string ocarina = "Ocarina";

		public const string pocket_watch = "Pocket Watch";

		public const string music_box = "Music Box";

		public const string instrument = "Instrument";

		public const string doll = "Doll";

		public const string uranium_plate = "Uranium Plate";

		public const string globe = "Globe";

		public const string frog = "Frog";

		public const string toy_monkey = "Toy Monkey";

		public const string money = "Money";

		public const string small_vase = "Vase Small";

		public const string radio = "Radio";

		public const string gramophone = "Gramophone";

		public const string ship_in_a_bottle = "Ship in a bottle";

		public const string kettle = "Kettle";

		public const string old_camera = "Old Camera";

		public const string magnifying_glass = "Magnifying Glass";

		public const string map = "Map";

		public const string vase = "Vase";

		public const string bottle = "Bottle";

		public const string clown_doll = "Clown";

		public const string trophy = "Trophy";

		public const string television = "Television";

		public const string diamond_display = "Diamond Display";

		public const string scream_doll = "Scream Doll";

		public const string telescope = "Telescope";

		public const string chunky_vase = "Vase Chunky";

		public const string big_vase = "Vase Big";

		public const string piano = "Piano";

		public const string animal_crate = "Animal Crate";

		public const string harp = "Harp";

		public const string painting = "Painting";

		public const string grandfather_clock = "Grandfather Clock";

		public const string dinosaur = "Dinosaur";

		public const string golden_statue = "Golden Statue";

		public const string coffin = "Coffin";

		public const string keycard = "Keycard";

		public const string uranium_petri_dish = "Uranium Petri Dish";

		public const string eraser = "Eraser";

		public const string pills = "Pills";

		public const string stapler = "Stapler";

		public const string usb_stick = "Usb stick";

		public const string coffee_cup = "Coffee Cup";

		public const string smartwatch = "Smartwatch";

		public const string phone = "Phone";

		public const string bonsai = "Bonsai";

		public const string hdd = "HDD";

		public const string calculator = "Calculator";

		public const string vhs = "VHS";

		public const string camera = "Camera";

		public const string laptop = "Laptop";

		public const string sample = "Sample";

		public const string sample_pack = "Sample Six Pack";

		public const string fan = "Fan";

		public const string computer = "Computer";

		public const string printer_3d = "3D Printer";

		public const string propane_tank = "Propane Tank";

		public const string scale = "Scale";

		public const string flashlight = "Flashlight";

		public const string fire_extinguisher = "Fire Extinguisher";

		public const string icepick = "Icepick";

		public const string barrel = "Barrel";

		public const string sample_cooler = "Sample Cooler";

		public const string big_sample = "Big Sample";

		public const string creature_leg = "Creature Leg";

		public const string guitar = "Guitar";

		public const string ice_saw = "Ice Saw";

		public const string flamethrower = "Flamethrower";

		public const string ice_block = "Ice Block";

		public const string snow_bike = "Snow Bike";

		public const string centrifuge = "Centrifuge";

		public const string sample_cooler_wide = "Sample Cooler Wide";

		public const string science_station = "Science Station";

		public const string heavy_water = "Heavy Water";

		public const string jackhammer = "Jackhammer";

		public const string server_rack = "Server Rack";

		public const string cryo_pod = "Cryo Pod";

		public const string eye_ball = "Eye Ball";

		public const string diamond = "Diamond";

		public const string bird_skull = "Bird Skull";

		public const string bug = "Bug";

		public const string glowing_jar = "Glowing Jar";

		public const string small_gem = "Small Gem";

		public const string small_potion = "Small Potion";

		public const string chomp_book = "Chomp Book";

		public const string love_potion = "Love Potion";

		public const string red_mushroom = "Red Mushroom";

		public const string pendant = "Pendant";

		public const string fortune_card = "Fortune Card";

		public const string levitation_potion = "Levitation Potion";

		public const string gem_box = "Gem Box";

		public const string crown = "Crown";

		public const string power_crystal = "Power Crystal";

		public const string time_glass = "Time Glass";

		public const string goblin_head = "Goblin Head";

		public const string tentacle = "Tentacle";

		public const string star_wand = "Star Wand";

		public const string poison_chalice = "Poison Chalice";

		public const string crystal = "Crystal";

		public const string crystal_ball = "Crystal Ball";

		public const string eye_of_orpigox = "Eye of Orpigox";

		public const string cube_of_knowledge = "Cube of Knowledge";

		public const string master_potion = "Master Potion";

		public const string unicorn_horn = "Unicorn Horn";

		public const string forever_candle = "Forever Candle";

		public const string cauldron_box = "Cauldron Box";

		public const string spider_potion = "Spider Potion";

		public const string griffin_statue = "Griffin Statue";

		public const string dragon_skull = "Dragon Skull";

		public const string alchemy_staion = "Alchemy Station";

		public const string goblin_arm = "Goblin Arm";

		public const string dumgolfs_staff = "Dumgolfs Staff";

		public const string sword = "Sword";

		public const string broom = "Broom";

		public const string troll_finger = "Troll Finger";

		public const string tooth = "Tooth";

		public const string silverfish = "SilverFish";

		public const string rubendoll = "RubenDoll";

		public const string goldfish = "GoldFish";

		public const string fish = "Fish";

		public const string cool_brain = "Cool brain";

		public const string toast = "Toast";

		public const string goldtooth = "GoldTooth";

		public const string wire_figure = "Wire Figure";

		public const string flesh_blob = "Flesh Blob";

		public const string banana_bow = "Banana Bow";

		public const string cubic_tower = "Cubic Tower";

		public const string car = "Car";

		public const string ladybug = "ladybug";

		public const string duck_man = "duck man";

		public const string cube_ball = "Cube ball";

		public const string cocktail = "Cocktail";

		public const string pimpleguy = "PimpleGuy";

		public const string plane = "Plane";

		public const string pacifier = "Pacifier";

		public const string monkeybox = "MonkeyBox";

		public const string gumball = "Gumball";

		public const string handface = "Handface";

		public const string cubic_sculpture = "Cubic Sculpture";

		public const string teeth_bot = "Teeth Bot";

		public const string uranium_mug_deluxe = "Uranium Mug Deluxe";

		public const string golden_swirl = "Golden Swirl";

		public const string boombox = "Boombox";

		public const string gem_burger = "Gem Burger";

		public const string baby_head = "Baby Head";

		public const string egg = "Egg";

		public const string horse = "Horse";

		public const string worm = "Worm";

		public const string vinyl = "Vinyl";

		public const string tray = "Tray";

		public const string milk = "Milk";

		public const string tall_guy = "Tall Guy";

		public const string blender = "Blender";

		public const string traffic_light = "Traffic Light";

		public static readonly ReadOnlyCollection<string> all_pellys = new ReadOnlyCollection<string>(new List<string> { standard_pelly, glass_pelly, gold_pelly });

		public static readonly ReadOnlyCollection<string> all_levels_short = new ReadOnlyCollection<string>(new List<string> { "Wizard", "Manor", "Arctic", "Museum" });

		public static readonly ReadOnlyCollection<string> all_levels = new ReadOnlyCollection<string>(new List<string> { swiftbroom_academy, headman_manor, mcjannek_station, museum_of_human_art });

		public static readonly ReadOnlyCollection<string> all_valuables = new ReadOnlyCollection<string>(new List<string>
		{
			"Goblet", "Uranium Mug", "Emerald Bracelet", "Ocarina", "Pocket Watch", "Music Box", "Instrument", "Doll", "Uranium Plate", "Globe",
			"Frog", "Toy Monkey", "Money", "Vase Small", "Radio", "Gramophone", "Ship in a bottle", "Kettle", "Old Camera", "Magnifying Glass",
			"Map", "Vase", "Bottle", "Clown", "Trophy", "Television", "Diamond Display", "Scream Doll", "Telescope", "Vase Chunky",
			"Vase Big", "Piano", "Animal Crate", "Harp", "Painting", "Grandfather Clock", "Dinosaur", "Golden Statue", "Coffin", "Keycard",
			"Uranium Petri Dish", "Eraser", "Pills", "Stapler", "Usb stick", "Coffee Cup", "Smartwatch", "Phone", "Bonsai", "HDD",
			"Calculator", "VHS", "Camera", "Laptop", "Sample", "Sample Six Pack", "Fan", "Computer", "3D Printer", "Propane Tank",
			"Scale", "Flashlight", "Fire Extinguisher", "Icepick", "Barrel", "Sample Cooler", "Big Sample", "Creature Leg", "Guitar", "Ice Saw",
			"Flamethrower", "Ice Block", "Snow Bike", "Centrifuge", "Sample Cooler Wide", "Science Station", "Heavy Water", "Jackhammer", "Server Rack", "Cryo Pod",
			"Eye Ball", "Diamond", "Bird Skull", "Bug", "Glowing Jar", "Small Gem", "Small Potion", "Chomp Book", "Love Potion", "Red Mushroom",
			"Pendant", "Fortune Card", "Levitation Potion", "Gem Box", "Crown", "Power Crystal", "Time Glass", "Goblin Head", "Tentacle", "Star Wand",
			"Poison Chalice", "Crystal", "Crystal Ball", "Eye of Orpigox", "Cube of Knowledge", "Master Potion", "Unicorn Horn", "Forever Candle", "Cauldron Box", "Spider Potion",
			"Griffin Statue", "Dragon Skull", "Alchemy Station", "Goblin Arm", "Dumgolfs Staff", "Sword", "Broom", "Troll Finger", "Tooth", "SilverFish",
			"RubenDoll", "GoldFish", "Fish", "Cool brain", "Toast", "GoldTooth", "Wire Figure", "Flesh Blob", "Banana Bow", "Cubic Tower",
			"Car", "ladybug", "duck man", "Cube ball", "Cocktail", "PimpleGuy", "Plane", "Pacifier", "MonkeyBox", "Gumball",
			"Handface", "Cubic Sculpture", "Teeth Bot", "Uranium Mug Deluxe", "Golden Swirl", "Boombox", "Gem Burger", "Baby Head", "Egg", "Horse",
			"Worm", "Vinyl", "Tray", "Milk", "Tall Guy", "Blender", "Traffic Light"
		});

		public const string animal_soul = "Animal Soul";

		public const string apex_predator_soul = "Apex Predator Soul";

		public const string bella_soul = "Bella Soul";

		public const string birthday_boy_soul = "Birthday Boy Soul";

		public const string bowtie_soul = "Bowtie Soul";

		public const string chef_soul = "Chef Soul";

		public const string cleanup_crew_soul = "Cleanup Crew Soul";

		public const string clown_soul = "Clown Soul";

		public const string elsa_soul = "Elsa Soul";

		public const string gambit_soul = "Gambit Soul";

		public const string headgrab_soul = "Headgrab Soul";

		public const string headman_soul = "Headman Soul";

		public const string heart_hugger_soul = "Heart Hugger Soul";

		public const string hidden_soul = "Hidden Soul";

		public const st