Decompiled source of Archipelago Randomizer for REPO v0.3.0
RepoAP.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Net; using System.Net.WebSockets; using System.Numerics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.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; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("RepoAP")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("0.3.0.0")] [assembly: AssemblyInformationalVersion("0.3.0")] [assembly: AssemblyProduct("Archipelago Randomizer")] [assembly: AssemblyTitle("RepoAP")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.3.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_0030: 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_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown object obj = <>c.<>9__0_0; if (obj == null) { BuilderDelegate val = delegate(Transform parent) { //IL_0030: 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.apAdress = input; }, parent, new Vector2(400f, 200f), false, Plugin.apAdress, ""); } internal void <BuildPopup>b__0_8(string input) { Plugin.apAdress = 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_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown //IL_009f: 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_00aa: Expected O, but got Unknown //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Expected O, but got Unknown //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Expected O, but got Unknown //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Expected O, but got Unknown //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Expected O, but got Unknown //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012b: 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.apAdress = input; }, parent, new Vector2(400f, 200f), false, Plugin.apAdress, ""); }; <>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.apAdress, 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 = 0; public Dictionary<long, SerializableItemInfo> locationsScouted = new Dictionary<long, SerializableItemInfo>(); public JArray pellysRequired = new JArray(); public bool pellySpawning; public long levelQuota; public long levelsCompleted; public long upgradeLocations; public bool valuableHunt; public bool monsterHunt; } 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_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Expected O, but got Unknown //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009a: 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() { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown 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 = (JArray)Plugin.connection.slotData["pellys_required"]; saveData.pellySpawning = (bool)Plugin.connection.slotData["pelly_spawning"]; 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; ReadOnlyCollection<long> allLocationsChecked = session.Locations.AllLocationsChecked; foreach (long item in 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 shop_item_count = 100; int pelly_count = LocationNames.all_pellys.Count * LocationNames.all_levels.Count; int valuable_count = LocationNames.all_valuables.Count; int monster_count = LocationNames.all_monster_souls.Count; Plugin.Logger.LogInfo((object)$"Checking {shop_item_count} shop items..."); Plugin.Logger.LogInfo((object)$"Checking {pelly_count} pelly statues..."); Plugin.Logger.LogInfo((object)$"Checking {valuable_count} valuables..."); Plugin.Logger.LogInfo((object)$"Checking {monster_count} monster souls..."); long[] idsToScout = new long[shop_item_count + pelly_count + valuable_count + monster_count]; int p = 0; for (int i = 1; i <= shop_item_count; i++) { idsToScout[p++] = LocationData.AddBaseId(i); } for (int j = 1; j <= pelly_count; j++) { idsToScout[p++] = LocationData.AddBaseId(100 + j); } for (int k = 0; k < valuable_count; k++) { idsToScout[p++] = LocationData.AddBaseId(200 + k); } for (int l = 0; l < monster_count; l++) { idsToScout[p++] = LocationData.AddBaseId(500 + l); } try { Dictionary<long, ScoutedItemInfo> scout = await Plugin.connection.session.Locations.ScoutLocationsAsync(idsToScout); saveData.locationsScouted = new Dictionary<long, SerializableItemInfo>(); foreach (ScoutedItemInfo item in scout.Values) { saveData.locationsScouted.Add(item.LocationId, item.ToSerializable()); } } catch (Exception e) { Debug.LogError((object)e); } 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 IsPellyRequired(string pelly) { pelly = LocationData.GetBaseName(pelly); return ((IEnumerable<JToken>)saveData.pellysRequired).Any((JToken x) => pelly.Contains(((object)x).ToString())); } public static bool CheckCompletion(out string status) { if (Plugin.connection.session == null) { status = string.Empty; return false; } ReadOnlyCollection<long> allLocationsChecked = 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}"); JArray pellysRequired = saveData.pellysRequired; int num2 = ((JContainer)saveData.pellysRequired).Count * LocationNames.all_levels_short.Count; int num3 = 0; Plugin.Logger.LogInfo((object)"Pellys Required:"); foreach (JToken item in saveData.pellysRequired) { Plugin.Logger.LogInfo((object)$"-{item} {((JContainer)saveData.pellysRequired).Count}"); } Plugin.Logger.LogInfo((object)"Pellys Gathered:"); foreach (string pellyName in saveData.pellysGathered) { Plugin.Logger.LogInfo((object)("-" + pellyName)); if (((IEnumerable<JToken>)saveData.pellysRequired).Any((JToken x) => pellyName.Contains(((object)x).ToString()))) { num3++; } } Plugin.Logger.LogInfo((object)$"Pellys Collected: {num3}/{num2}"); if (num3 < num2) { 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)); } } status += string.Format("<br>{{?}} Pelly - {0}/{1}{2}", num3, num2, (num3 == num2) ? " {check}" : " {X}"); if (saveData.monsterHunt) { num2 = LocationNames.all_monster_souls.Count; num3 = 0; Plugin.Logger.LogInfo((object)"Monster Hunt"); foreach (string all_monster_soul in LocationNames.all_monster_souls) { if (!saveData.monsterSoulsGathered.Contains(all_monster_soul)) { Plugin.Logger.LogInfo((object)(all_monster_soul + " has not been extracted")); flag = false; } else { Plugin.Logger.LogInfo((object)(all_monster_soul + " hunted")); num3++; } } status += string.Format("<br>{{ghost}} Souls - {0}/{1}{2}", num3, num2, (num3 == num2) ? " {check}" : " {X}"); } if (saveData.valuableHunt) { num2 = LocationNames.all_valuables.Count; num3 = 0; Plugin.Logger.LogInfo((object)"Valuable Hunt"); foreach (string all_valuable in LocationNames.all_valuables) { if (!saveData.valuablesGathered.Contains(all_valuable)) { Plugin.Logger.LogInfo((object)(all_valuable + " has not been extracted")); flag = false; } else { Debug.Log((object)(all_valuable + " extracted")); num3++; } } status += string.Format("<br>{{$$$}} Valuables - {0}/{1}{2}", num3, num2, (num3 == num2) ? " {check}" : " {X}"); } if (flag) { Plugin.Logger.LogInfo((object)"All Goals Complete."); } Plugin.connection.SyncCompletionProgress(num, saveData.pellysGathered, saveData.valuablesGathered, saveData.monsterSoulsGathered, saveData.shopStockReceived); 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_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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) //IL_0011: 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__30 : IEnumerator<bool>, IDisposable, IEnumerator { private int <>1__state; private bool <>2__current; public ArchipelagoConnection <>4__this; private ItemInfo <Item>5__1; private string <ItemReceivedName>5__2; bool IEnumerator<bool>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <CheckItemsReceived>d__30(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <Item>5__1 = null; <ItemReceivedName>5__2 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; <Item>5__1 = null; <ItemReceivedName>5__2 = null; break; case 2: <>1__state = -1; break; } if (<>4__this.connected) { if (<>4__this.session.Items.AllItemsReceived.Count > <>4__this.ItemIndex) { <Item>5__1 = <>4__this.session.Items.AllItemsReceived[<>4__this.ItemIndex]; <ItemReceivedName>5__2 = <Item>5__1.ItemName; Plugin.Logger.LogDebug((object)("Placing item " + <ItemReceivedName>5__2 + " with index " + <>4__this.ItemIndex + " in queue.")); <>4__this.incomingItems.Enqueue((<Item>5__1, <>4__this.ItemIndex)); <>4__this.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__33 : IEnumerator<bool>, IDisposable, IEnumerator { private int <>1__state; private bool <>2__current; public ArchipelagoConnection <>4__this; private (ItemInfo NetworkItem, int index) <pendingItem>5__1; private ItemInfo <networkItem>5__2; private string <itemName>5__3; private string <itemDisplayName>5__4; private List<Level> <nonGameLevels>5__5; private messageData <md>5__6; bool IEnumerator<bool>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <IncomingItemHandler>d__33(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <pendingItem>5__1 = default((ItemInfo, int)); <networkItem>5__2 = null; <itemName>5__3 = null; <itemDisplayName>5__4 = null; <nonGameLevels>5__5 = null; <md>5__6 = default(messageData); <>1__state = -2; } private bool MoveNext() { //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { 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; <pendingItem>5__1 = default((ItemInfo, int)); <networkItem>5__2 = null; <itemName>5__3 = null; <itemDisplayName>5__4 = null; <nonGameLevels>5__5 = null; break; } if (<>4__this.connected) { if (!<>4__this.incomingItems.TryPeek(out <pendingItem>5__1)) { <>2__current = true; <>1__state = 1; return true; } <networkItem>5__2 = <pendingItem>5__1.NetworkItem; <itemName>5__3 = <networkItem>5__2.ItemName; <itemDisplayName>5__4 = <itemName>5__3 + " (" + <networkItem>5__2.ItemName + ") at index " + <pendingItem>5__1.index; (ItemInfo, int) result; if (APSave.GetItemReceivedIndex() > <pendingItem>5__1.index) { <>4__this.incomingItems.TryDequeue(out result); Plugin.Logger.LogDebug((object)("Skipping item " + <itemName>5__3 + " at index " + <pendingItem>5__1.index + " as it has already been processed.")); <>2__current = true; <>1__state = 2; return true; } Plugin.Logger.LogInfo((object)("ItemHandler " + <networkItem>5__2.ItemId)); APSave.AddItemReceived(<networkItem>5__2.ItemId); <nonGameLevels>5__5 = new List<Level> { RunManager.instance.levelMainMenu, RunManager.instance.levelLobby, RunManager.instance.levelLobbyMenu }; if (!<nonGameLevels>5__5.Contains(RunManager.instance.levelCurrent)) { ItemData.AddItemToInventory(<networkItem>5__2.ItemId, repeatedAdditions: false); <md>5__6 = new messageData("Received " + <itemName>5__3, Color.green, Color.white, 3f); <>4__this.messageItems.Enqueue(<md>5__6); <md>5__6 = default(messageData); } <>4__this.incomingItems.TryDequeue(out result); <>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__31 : IEnumerator<bool>, IDisposable, IEnumerator { private int <>1__state; private bool <>2__current; public ArchipelagoConnection <>4__this; private messageData <messageData>5__1; bool IEnumerator<bool>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <MessageHandler>d__31(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <messageData>5__1 = default(messageData); <>1__state = -2; } private bool MoveNext() { //IL_00e9: 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) switch (<>1__state) { 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; <messageData>5__1 = default(messageData); break; } if (!SemiFunc.MenuLevel()) { <>4__this.messageDelay -= Time.deltaTime; if (<>4__this.messageDelay > 0f) { <>2__current = true; <>1__state = 1; return true; } if (!<>4__this.messageItems.TryDequeue(out <messageData>5__1)) { <>2__current = true; <>1__state = 2; return true; } <>4__this.messageDelay = 3.5f; Plugin.customRPCManager.CallFocusTextRPC(<messageData>5__1.message, <messageData>5__1.mainCol, <messageData>5__1.flashCol, <messageData>5__1.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__32 : IEnumerator<bool>, IDisposable, IEnumerator { private int <>1__state; private bool <>2__current; public ArchipelagoConnection <>4__this; private SerializableItemInfo <networkItem>5__1; private string <itemName>5__2; private string <location>5__3; private long <locID>5__4; private string <receiver>5__5; bool IEnumerator<bool>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <OutgoingItemHandler>d__32(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <networkItem>5__1 = null; <itemName>5__2 = null; <location>5__3 = null; <receiver>5__5 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; break; case 2: <>1__state = -1; <networkItem>5__1 = null; <itemName>5__2 = null; <location>5__3 = null; <receiver>5__5 = null; break; } if (<>4__this.connected) { if (!<>4__this.outgoingItems.TryDequeue(out <networkItem>5__1)) { <>2__current = true; <>1__state = 1; return true; } <itemName>5__2 = <networkItem>5__1.ItemName; <location>5__3 = <networkItem>5__1.LocationName; <locID>5__4 = <networkItem>5__1.LocationId; <receiver>5__5 = <>4__this.session.Players.GetPlayerName(<networkItem>5__1.Player); Plugin.Logger.LogInfo((object)("Sent " + <itemName>5__2 + " at " + <location>5__3 + " for " + <receiver>5__5)); if ((int)<networkItem>5__1.Player != <>4__this.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 = 0f; public bool sentCompletion = false; public bool sentRelease = false; public bool sentCollect = false; public Dictionary<string, object> slotData; public DeathLinkService deathLinkService; public int ItemIndex = 0; private ConcurrentQueue<(ItemInfo NetworkItem, int index)> incomingItems; private ConcurrentQueue<SerializableItemInfo> outgoingItems; private ConcurrentQueue<messageData> messageItems; public bool connected => session != null && session.Socket.Connected; 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 result; try { await session.ConnectAsync(); result = await session.LoginAsync("R.E.P.O", player, ItemsHandlingFlags.AllItems, null, null, null, pass); } catch (Exception e) { result = new LoginFailure(e.GetBaseException().Message); } if (result is LoginSuccessful LoginSuccess) { slotData = LoginSuccess.SlotData; Plugin.Logger.LogInfo((object)"Successfully connected to Archipelago Multiworld server!"); APSave.Init(); APSave.ScoutLocations(); if (!SemiFunc.MenuLevel()) { messageData md = new messageData("Successfully Connected!", Color.white, Color.green, 3f); messageItems.Enqueue(md); } deathLinkService = session.CreateDeathLinkService(); } else { LoginFailure loginFailure = (LoginFailure)result; string connectFailureMessage2 = "Unable to connect to Archipelago Multiworld server:\n"; string[] errors = loginFailure.Errors; foreach (string Error in errors) { connectFailureMessage2 = connectFailureMessage2 + Error + "\n"; } connectFailureMessage2 += "\n"; ConnectionRefusedError[] errorCodes = loginFailure.ErrorCodes; for (int j = 0; j < errorCodes.Length; j++) { ConnectionRefusedError Error2 = errorCodes[j]; connectFailureMessage2 = connectFailureMessage2 + Error2.ToString() + "\n"; } Plugin.Logger.LogWarning((object)connectFailureMessage2); TryDisconnect(); } incomingItemHandler = IncomingItemHandler(); outgoingItemHandler = OutgoingItemHandler(); checkItemsReceived = CheckItemsReceived(); if (SemiFunc.MenuLevel()) { connectingPage.ClosePage(false); MenuBuilder.BuildPopup(); } } private string RGBtoHtmlStr(Color col) { byte[] array = new byte[3] { col.R, col.G, col.B }; return BitConverter.ToString(array).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 empty2 = string.Empty; empty2 = RGBtoHtmlStr(messagePart.Color); text = ((!(empty2 != string.Empty)) ? (text + messagePart.Text) : (text + "<color=#" + empty2 + "><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; Plugin.Logger.LogInfo((object)"Disconnected from Archipelago"); } catch { Plugin.Logger.LogError((object)"Encountered an error disconnecting from Archipelago!"); } } public async Task ClientDisconnected() { try { messageData md = new messageData("Client Disconnected! Trying to Reconnect...", Color.white, Color.red, 4f); messageItems.Enqueue(md); await TryConnect(Plugin.apAdress, int.Parse(Plugin.apPort), Plugin.apPassword, Plugin.apSlot); } catch (Exception ex) { Exception e = ex; Plugin.Logger.LogWarning((object)("Failure in reconnecting: " + e.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__30))] private IEnumerator<bool> CheckItemsReceived() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <CheckItemsReceived>d__30(0) { <>4__this = this }; } [IteratorStateMachine(typeof(<MessageHandler>d__31))] private IEnumerator<bool> MessageHandler() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <MessageHandler>d__31(0) { <>4__this = this }; } [IteratorStateMachine(typeof(<OutgoingItemHandler>d__32))] private IEnumerator<bool> OutgoingItemHandler() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <OutgoingItemHandler>d__32(0) { <>4__this = this }; } [IteratorStateMachine(typeof(<IncomingItemHandler>d__33))] private IEnumerator<bool> IncomingItemHandler() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <IncomingItemHandler>d__33(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, int shop_stock_received) { if (!connected) { return; } long tempLevels = await session.DataStorage["REPO-" + session.Players.GetPlayerName(session.ConnectionInfo.Slot) + "-levelsCompleted"].GetAsync<long>(); APSave.saveData.levelsCompleted = Math.Max(levels_completed, tempLevels); session.DataStorage["REPO-" + session.Players.GetPlayerName(session.ConnectionInfo.Slot) + "-levelsCompleted"] = APSave.saveData.levelsCompleted; List<string> pellyData = await session.DataStorage["REPO-" + session.Players.GetPlayerName(session.ConnectionInfo.Slot) + "-pellysGathered"].GetAsync<List<string>>(); foreach (string item3 in pellys_gathered.Where((string pelly) => !pellyData.Contains(pelly))) { pellyData.Add(item3); } session.DataStorage["REPO-" + session.Players.GetPlayerName(session.ConnectionInfo.Slot) + "-pellysGathered"] = pellyData; APSave.saveData.pellysGathered = pellyData; List<string> valuableData = await session.DataStorage["REPO-" + session.Players.GetPlayerName(session.ConnectionInfo.Slot) + "-valuablesGathered"].GetAsync<List<string>>(); foreach (string item2 in valuables_gathered.Where((string valuable) => !valuableData.Contains(valuable))) { valuableData.Add(item2); } session.DataStorage["REPO-" + session.Players.GetPlayerName(session.ConnectionInfo.Slot) + "-valuablesGathered"] = valuableData; APSave.saveData.valuablesGathered = valuableData; List<string> monsterData = await session.DataStorage["REPO-" + session.Players.GetPlayerName(session.ConnectionInfo.Slot) + "-monsterSoulsGathered"].GetAsync<List<string>>(); foreach (string item in monster_souls_gathered.Where((string soul) => !monsterData.Contains(soul))) { monsterData.Add(item); } session.DataStorage["REPO-" + session.Players.GetPlayerName(session.ConnectionInfo.Slot) + "-monsterSoulsGathered"] = monsterData; APSave.saveData.monsterSoulsGathered = monsterData; } public void SendDeathLink() { if (connected) { deathLinkService.SendDeathLink(new DeathLink(session.Players.ActivePlayer.Name)); } } } [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<int> EnemyWeightIncrease; public ConfigEntry<int> ValuableSubstitutionChance; 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<int>("Bad Luck Protection", "Spawn weight increase for unextracted enemy souls", 50, "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<int>("Bad Luck Protection", "Chance to replace previously extracted valuables", 40, "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."); ClearUnusedEntries(cfg); } private void ClearUnusedEntries(ConfigFile cfg) { PropertyInfo property = ((object)cfg).GetType().GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.NonPublic); Dictionary<ConfigDefinition, string> dictionary = (Dictionary<ConfigDefinition, string>)property.GetValue(cfg, null); dictionary.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)1, array); } public void CallFocusTextRPC(string message, Color mainCol, Color flashCol, float lingerTime, GameObject inst) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0030: 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[7] { 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)), ((object)APSave.saveData.pellysRequired).ToString(), APSave.saveData.valuableHunt, APSave.saveData.monsterHunt }; component.RPC("SyncSlotDataWithClientsRpc", (RpcTarget)0, array); } } [PunRPC] public void UpdateItemNameRPC(string name, PhotonMessageInfo info) { //IL_0011: 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>(); FieldInfo fieldInfo = AccessTools.Field(typeof(ItemAttributes), "itemName"); fieldInfo.SetValue(component, name.Replace("_", " ")); } [PunRPC] public void FocusTextRPC(string message, Color mainCol, Color flashCol, float lingerTime) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) SemiFunc.UIFocusText(message, mainCol, flashCol, lingerTime); } public void FocusTextOffline(string message, Color mainCol, Color flashCol, float lingerTime) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) 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, string pellys_required, bool valuable_hunt, bool monster_hunt) { 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 = JArray.Parse(pellys_required); APSave.saveData.valuableHunt = valuable_hunt; APSave.saveData.monsterHunt = monster_hunt; Plugin.Logger.LogInfo((object)"Ap data synced with host"); } } [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.3.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 apAdress = "archipelago.gg"; 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_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown Logger = ((BaseUnityPlugin)this).Logger; _player = PlayerController.instance; BoundConfig = new PluginConfig(((BaseUnityPlugin)this).Config); Logger.LogInfo((object)"Plugin RepoAP is loaded!"); Harmony val = new Harmony("com.example.patch"); val.PatchAll(); } private void Start() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_008f: 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) Logger.LogDebug((object)"In Start"); 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(); ItemData.CreateItemDataTable(); } public static ArchipelagoConnection GetConnection() { return connection; } public void CheckLocation(long locID) { connection.ActivateCheck(locID); } public void Update() { if (connection.connected) { if (connection.checkItemsReceived != null) { connection.checkItemsReceived.MoveNext(); } if (connection.incomingItemHandler != null) { connection.incomingItemHandler.MoveNext(); } if (connection.outgoingItemHandler != null) { connection.outgoingItemHandler.MoveNext(); } if (connection.messageHandler != null) { connection.messageHandler.MoveNext(); } } } public static void UpdateAPAddress(string input) { apAdress = input; } } [HarmonyPatch(typeof(MenuPageSaves), "OnLoadGame")] internal class PreventLoadingRunWhenNotConnectedPatch { [HarmonyPrefix] private static bool OnLoadGamePatch() { //IL_0037: 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_0037: 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.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); 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")) { int num = StatsManager.instance.itemsPurchasedTotal[text] - StatsManager.instance.itemsUpgradesPurchased[text]; if (APSave.GetItemsReceived()[itemId] > num) { StatsManager.instance.ItemPurchase(text); } 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 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 = "Shock 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 Grenade 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 Detector Unlock"; public static string extraction_detector = "Extraction Detector 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"; } [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.LogInfo((object)("Player has " + item.Key)); list.Add(item.Key); } if (levelIndex < 0) { levelIndex = Random.RandomRangeInt(0, list.Count); } else { levelIndex = (levelIndex + 1) % list.Count; } 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.LogInfo((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")) { string status; bool flag = APSave.CheckCompletion(out status); HandleAPTruckScreenMessages.TruckScreenChatPatch.AddMessage("AP", status); } } } [HarmonyPatch(typeof(EnemyParent))] internal class EnemyDespawnPatch { [HarmonyPatch("Despawn")] [HarmonyPostfix] private static void OrbNaming(ref string ___enemyName, ref Enemy ___Enemy) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown FieldInfo fieldInfo = AccessTools.Field(typeof(Enemy), "HasHealth"); bool flag = (bool)fieldInfo.GetValue(___Enemy); FieldInfo fieldInfo2 = AccessTools.Field(typeof(Enemy), "Health"); EnemyHealth val = (EnemyHealth)fieldInfo2.GetValue(___Enemy); FieldInfo fieldInfo3 = AccessTools.Field(typeof(EnemyHealth), "healthCurrent"); int num = (int)fieldInfo3.GetValue(val); if (!flag || !val.spawnValuable || num > 0) { return; } EnemyValuable[] array = (EnemyValuable[])(object)Object.FindObjectsByType(typeof(EnemyValuable), (FindObjectsSortMode)0); EnemyValuable[] array2 = array; foreach (EnemyValuable val2 in array2) { if (((Object)val2).name.Contains("Enemy Valuable")) { ((Object)val2).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) != 0) { 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) != 0) { 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 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 string huntsman_soul = "Huntsman Soul"; public const string loom_soul = "Loom Soul"; public const string mentalist_soul = "Mentalist Soul"; public const string oogly_soul = "Oogly Soul"; public const string peeper_soul = "Peeper Soul"; public const string reaper_soul = "Reaper Soul"; public const string robe_soul = "Robe Soul"; public const string rugrat_soul = "Rugrat Soul"; public const string shadow_child_soul = "Shadow Child Soul"; public const string spewer_soul = "Spewer Soul"; public const string tick_soul = "Tick Soul"; public const string trudge_soul = "Trudge Soul"; public const string upscream_soul = "Upscream Soul"; public static readonly ReadOnlyCollection<string> all_monster_souls = new ReadOnlyCollection<string>(new List<string> { "Animal Soul", "Apex Predator Soul", "Bella Soul", "Birthday Boy Soul", "Bowtie Soul", "Chef Soul", "Cleanup Crew Soul", "Clown Soul", "Elsa Soul", "Gambit Soul", "Headgrab Soul", "Headman Soul", "Heart Hugger Soul", "Hidden Soul", "Huntsman Soul", "Loom Soul", "Mentalist Soul", "Oogly Soul", "Peeper Soul", "Reaper Soul", "Robe Soul", "Rugrat Soul", "Shadow Child Soul", "Spewer Soul", "Tick Soul", "Trudge Soul", "Upscream Soul" }); } [HarmonyPatch(typeof(ValuableDirector), "Start")] internal class PellySpawingPatch { [HarmonyPrefix] private static void RemovePellysFromList(ValuableDirector __instance) { if (Plugin.connection.session == null || APSave.saveData.pellySpawning) { return; } Plugin.Logger.LogDebug((object)"InValuableDirector"); FieldInfo fieldInfo = AccessTools.Field(typeof(ValuableDirector), "mediumValuables"); List<GameObject> list = (List<GameObject>)fieldInfo.GetValue(__instance); foreach (LevelValuables valuablePreset in LevelGenerator.Instance.Level.ValuablePresets) { foreach (PrefabRef pelly in valuablePreset.medium.Where((PrefabRef x) => x.PrefabName.Contains("Pelly")).ToList()) { Plugin.Logger.LogInfo((object)("Pelly Found: " + pelly.PrefabName)); if (((IEnumerable<JToken>)APSave.saveData.pellysRequired).All((JToken x) => !pelly.PrefabName.Contains(((object)x).ToString()))) { Plugin.Logger.LogInfo((object)("Removing: " + pelly.PrefabName)); valuablePreset.medium.Remove(pelly); } } } } } [HarmonyPatch(typeof(PhysGrabObject))] internal class PhysGrabObjectPatch { [HarmonyPatch("GrabStarted")] [HarmonyPostfix] private static void OrbInfoTextEnabler(PhysGrabObject __instance) { string name = ((Object)((Component)__instance).gameObject).name; bool flag = name.Contains("Soul"); bool flag2 = name.Contains("Valuable"); bool flag3 = name.Contains("Pelly"); if (name.Contains("Surplus") || !(flag || flag2 || flag3)) { return; } string text = ""; if (Plugin.connection.session != null || !SemiFunc.IsMasterClientOrSingleplayer()) { long id = -1L; bool flag4 = false; bool flag5 = false; if (flag) { id = LocationData.MonsterSoulNameToID(name); flag4 = APSave.WasMonsterSoulGathered(name); flag5 = APSave.saveData.monsterHunt; } else if (flag3) { id = LocationData.PellyNameToID(name + ((Object)RunManager.instance.levelCurrent).name); flag4 = APSave.WasPellyGathered(name, ((Object)RunManager.instance.levelCurrent).name); flag5 = APSave.IsPellyRequired(name); } else if (flag2) { id = LocationData.ValuableNameToID(name); flag4 = APSave.WasValuableGathered(name); flag5 = APSave.saveData.valuableHunt; } SerializableItemInfo scoutedLocation = APSave.GetScoutedLocation(id); if (flag5 && flag4) { text = "<br><color=#67a9cf>extracted"; } else if (flag5 && scoutedLocation == null) { text = "<br><color=#ef8a62>not extracted"; } else if (flag4 && scoutedLocation != null) { text = "<br><color=#67a9cf>found"; } else if (!flag4 && scoutedLocation != null) { try { text = string.Format("<br><color={0}>{1}'s {2}", "#ef8a62", scoutedLocation.Player, scoutedLocation.ItemName); } catch (Exception ex) { Plugin.Logger.LogWarning((object)("OrbInfoTextEnabler: " + ex.Message)); text = "<br><color=#9c9c9c>unknown"; } } } name = LocationData.GetBaseName(name); SemiFunc.UIItemInfoText((ItemAttributes)null, name + text); } } [HarmonyPatch(typeof(ExtractionPoint), "DestroyAllPhysObjectsInShoppingList")] internal class ShopSendCheckPatch { private static FieldInfo field = AccessTools.Field(typeof(ShopManager), "shoppingList"); private static List<ItemAttributes> shoppingList; private static FieldInfo field2 = AccessTools.Field(typeof(ItemAttributes), "value"); private static int value; [HarmonyPrefix] private static bool ShopCheckPatch(ExtractionPoint __instance) { //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Invalid comparison between Unknown and I4 //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Invalid comparison between Unknown and I4 shoppingList = (List<ItemAttributes>)field.GetValue(ShopManager.instance); Plugin.Logger.LogInfo((object)"Connected in shop check"); if (SemiFunc.IsMasterClientOrSingleplayer()) { if (Plugin.connection == null) { Plugin.Logger.LogInfo((object)"Connection Null"); return true; } foreach (PlayerAvatar player in GameDirector.instance.PlayerList) { player.playerDeathHead.Revive(); } List<ItemAttributes> list = new List<ItemAttributes>(); foreach (ItemAttributes shopping in shoppingList) { value = (int)field2.GetValue(shopping); if (!Object.op_Implicit((Object)(object)shopping) || !Object.op_Implicit((Object)(object)((Component)shopping).GetComponent<PhysGrabObject>()) || SemiFunc.StatGetRunCurrency() - value < 0) { continue; } SemiFunc.StatSetRunCurrency(SemiFunc.StatGetRunCurrency() - value); if (((Object)shopping.item).name == ItemNames.ap_item) { Plugin.Logger.LogInfo((object)("AP ITEM PURCHASED " + ((Object)shopping).name)); long num = LocationData.ShopItemToID(((Object)shopping).name); if (num != 0) { Plugin.connection.ActivateCheck(num); } } else { Plugin.Logger.LogInfo((object)("Not AP Item\n" + ((Object)shopping.item).name + " != " + ItemNames.ap_item)); StatsManager.instance.ItemPurchase(((Object)shopping.item).name); } if ((int)shopping.item.itemType == 3 && ((Object)shopping.item).name != ItemNames.ap_item) { StatsManager.instance.AddItemsUpgradesPurchased(((Object)shopping.item).name); } if ((int)shopping.item.itemType == 5) { StatsManager.instance.runStats["chargingStationChargeTotal"] += 17; if (StatsManager.instance.runStats["chargingStationChargeTotal"] > 100) { StatsManager.instance.runStats["chargingStationChargeTotal"] = 100; } } ((Component)shopping).GetComponent<PhysGrabObject>().DestroyPhysGrabObject(); list.Add(shopping); } foreach (ItemAttributes item in list) { List<ItemAttributes> list2 = (List<ItemAttributes>)field.GetValue(ShopManager.instance); list2.Remove(item); field.SetValue(ShopManager.instance, list2); } SemiFunc.ShopUpdateCost(); } return false; } } [HarmonyPatch(typeof(PunManager), "Start")] internal class ItemNumberTracker { [HarmonyPostfix] private static void SetNumber() { Plugin.Logger.LogInfo((object)("Current Level: " + ((Object)RunManager.instance.levelCurrent).name)); if (!((Object)RunManager.instance.levelCurrent).name.Contains("Menu") && !((Object)RunManager.instance.levelCurrent).name.Contains("Splash")) { Plugin.LastShopItemChecked = 0; APSave.UpdateAvailableItems(); } } } [HarmonyPatch(typeof(PunManager), "SpawnShopItem")] internal class SpawnShopItemPatch { [HarmonyPrefix] private static bool ReplaceItemPatch(ref bool __result, ref ItemVolume itemVolume, ref List<Item> itemList, ref int spawnCount, bool isSecret = false) { //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_1102: Unknown result type (might be due to invalid IL or missing references) //IL_111c: Unknown result type (might be due to invalid IL or missing references) //IL_1121: Unknown result type (might be due to invalid IL or missing references) //IL_1210: Unknown result type (might be due to invalid IL or missing references) //IL_1215: Unknown result type (might be due to invalid IL or missing references) //IL_122b: Unknown result type (might be due to invalid IL or missing references) //IL_1231: Invalid comparison between Unknown and I4 //IL_1163: Unknown result type (might be due to invalid IL or missing references) //IL_1168: Unknown result type (might be due to invalid IL or missing references) //IL_1180: Unknown result type (might be due to invalid IL or missing references) //IL_1186: Invalid comparison between Unknown and I4 FieldInfo fieldInfo = AccessTools.Field(typeof(ItemAttributes), "itemName"); for (int num = itemList.Count - 1; num >= 0; num--) { Item val; if (itemList[num].itemName.Contains("Upgrade") && !((Object)itemList[num]).name.Contains("Counted") && Plugin.ShopItemsAvailable.Count > 0) { Plugin.Logger.LogInfo((object)("Replacing " + itemList[num].itemName)); val = StatsManager.instance.itemDictionary[ItemNames.ap_item]; } else { val = itemList[num]; } if (val.itemVolume == itemVolume.itemVolume) { if (((Object)itemList[num]).name.Contains("Item Cart Cannon") && !APSave.IsItemReceived(ItemData.AddBaseId(ItemData.itemNameToID[ItemNames.cart_cannon]))) { Plugin.Logger.LogInfo((object)(ItemNames.cart_cannon + " Not Unlocked")); itemList.RemoveAt(num); } else if (((Object)itemList[num]).name.Contains("Item Cart Laser") && !APSave.IsItemReceived(ItemData.AddBaseId(ItemData.itemNameToID[ItemNames.cart_laser]))) { Plugin.Logger.LogInfo((object)(ItemNames.cart_laser + " Not Unlocked")); itemList.RemoveAt(num); } else if (((Object)itemList[num]).name.Contains("Item Cart Medium") && !APSave.IsItemReceived(ItemData.AddBaseId(ItemData.itemNameToID[ItemNames.cart]))) { Plugin.Logger.LogInfo((object)(ItemNames.cart + " Not Unlocked")); itemList.RemoveAt(num); } else if (((Object)itemList[num]).name.Contains("Item Cart Small") && !APSave.IsItemReceived(ItemData.AddBaseId(ItemData.itemNameToID[ItemNames.pocket_cart]))) { Plugin.Logger.LogInfo((object)(ItemNames.pocket_cart + " Not Unlocked")); itemList.RemoveAt(num); } else if (((Object)itemList[num]).name.Contains("Item Drone Battery") && !APSave.IsItemReceived(ItemData.AddBaseId(ItemData.itemNameT