Decompiled source of Archipelago Randomizer for REPO v0.1.5
RepoAP.dll
Decompiled a week 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 HarmonyLib; using MenuLib; using MenuLib.MonoBehaviors; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; using Photon.Pun; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("RepoAP")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("Archipelago Randomizer")] [assembly: AssemblyTitle("RepoAP")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace RepoAP { [HarmonyPatch(typeof(MainMenuOpen), "Start")] internal class APConnectMenu { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static Action <>9__0_1; public static BuilderDelegate <>9__0_0; internal void <Prefix>b__0_0(Transform parent) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) MenuAPI.CreateREPOButton("Archipelago", (Action)delegate { MenuBuilder.BuildPopup(); }, parent, new Vector2(145f, 27f)); } internal void <Prefix>b__0_1() { MenuBuilder.BuildPopup(); } } [HarmonyPrefix] private static void Prefix() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown object obj = <>c.<>9__0_0; if (obj == null) { BuilderDelegate val = delegate(Transform parent) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) MenuAPI.CreateREPOButton("Archipelago", (Action)delegate { MenuBuilder.BuildPopup(); }, parent, new Vector2(145f, 27f)); }; <>c.<>9__0_0 = val; obj = (object)val; } MenuAPI.AddElementToMainMenu((BuilderDelegate)obj); } } public static class MenuBuilder { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static BuilderDelegate <>9__0_0; public static BuilderDelegate <>9__0_1; public static Action<string> <>9__0_8; public static BuilderDelegate <>9__0_2; public static Action<string> <>9__0_9; public static BuilderDelegate <>9__0_3; public static Action<string> <>9__0_10; public static BuilderDelegate <>9__0_4; public static Action<string> <>9__0_11; public static BuilderDelegate <>9__0_5; internal void <BuildPopup>b__0_0(Transform parent) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) MenuAPI.CreateREPOLabel("<size=12>Only host player must be connected to AP Server.", parent, new Vector2(380f, 275f)); } internal void <BuildPopup>b__0_1(Transform parent) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) MenuAPI.CreateREPOLabel((Plugin.connection.session != null) ? "<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_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Expected O, but got Unknown //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Expected O, but got Unknown //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Expected O, but got Unknown //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Expected O, but got Unknown //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Expected O, but got Unknown Debug.LogWarning((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.session != null) ? "<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); BuildPopup(); }, 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); } } internal class APSaveData { public APConnectionData connectionData = new APConnectionData(); 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 List<int> shopItemsPurchased = new List<int>(); public long shopStockSlotData; public int shopStockRecieved; public Dictionary<long, int> itemsRecieved = new Dictionary<long, int>(); public Dictionary<string, bool> levelsUnlocked = new Dictionary<string, bool>(); public int itemRecievedIndex; public Dictionary<long, ItemInfo> shopItemsScouted = new Dictionary<long, ItemInfo>(); public JArray pellysRequired = new JArray(); public bool pellySpawning; public long levelQuota; 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_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown 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 }); 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_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown if (Plugin.connection.session != null) { 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 AddLocationChecked(long locToAdd) { if (Plugin.connection.session != null) { saveData.locationsChecked.Add(locToAdd); ES3.Save<APSaveData>(saveKey, saveData, es3Settings); } } public static List<long> GetLocationsChecked() { if (Plugin.connection.session == null) { 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 AddItemRecieved(long itemId) { if (Plugin.connection.session != null) { if (saveData.itemsRecieved.ContainsKey(itemId)) { saveData.itemsRecieved[itemId]++; } else { saveData.itemsRecieved.Add(itemId, 1); } saveData.itemRecievedIndex++; ES3.Save<APSaveData>(saveKey, saveData, es3Settings); } } public static int GetItemRecievedIndex() { if (Plugin.connection.session == null) { return 0; } return ES3.Load<APSaveData>(saveKey, es3Settings).itemRecievedIndex; } public static void AddStockRecieved() { if (Plugin.connection.session != null) { if (saveData.itemsRecieved.ContainsKey(ItemData.AddBaseId(18L))) { saveData.shopStockRecieved = saveData.itemsRecieved[ItemData.AddBaseId(18L)]; } else { saveData.shopStockRecieved = 0; } ES3.Save<APSaveData>(saveKey, saveData, es3Settings); } } public static void UpdateAvailableItems() { Plugin.ShopItemsAvailable = new List<int>(); Plugin.ShopItemsBought = GetShopLocationsChecked(); for (int i = 1; i <= saveData.shopStockSlotData * (saveData.shopStockRecieved + 1); i++) { if (!Plugin.ShopItemsBought.Contains(i)) { Plugin.ShopItemsAvailable.Add(i); } } } public static Dictionary<long, int> GetItemsRecieved() { if (Plugin.connection.session == null) { return null; } return ES3.Load<APSaveData>(saveKey, es3Settings).itemsRecieved; } public static void AddLevelRecieved(string levelName) { if (Plugin.connection.session != null) { if (!saveData.levelsUnlocked.ContainsKey(levelName) || !saveData.levelsUnlocked[levelName]) { saveData.levelsUnlocked.Add(levelName, value: true); } else { Debug.LogError((object)(levelName + " has already been recieved!")); } ES3.Save<APSaveData>(saveKey, saveData, es3Settings); } } public static Dictionary<string, bool> GetLevelsRecieved() { if (Plugin.connection.session == null) { return null; } return ES3.Load<APSaveData>(saveKey, es3Settings).levelsUnlocked; } public static async void ScoutShopItems() { if (Plugin.connection.session == null) { return; } long[] array = new long[100]; for (int i = 1; i <= 100; i++) { array[i - 1] = LocationData.AddBaseId(i); } try { Dictionary<long, ScoutedItemInfo> obj = await Plugin.connection.session.Locations.ScoutLocationsAsync(array); saveData.shopItemsScouted = new Dictionary<long, ItemInfo>(); foreach (ScoutedItemInfo value in obj.Values) { saveData.shopItemsScouted.Add(value.LocationId, value); } } catch (Exception ex) { Debug.LogError((object)ex); } ES3.Save<APSaveData>(saveKey, saveData, es3Settings); } public static ItemInfo GetScoutedShopItem(long id) { if (Plugin.connection.session == null) { return null; } return saveData.shopItemsScouted[id]; } public static void AddPellyGathered(string name) { if (Plugin.connection.session != null) { if (!saveData.pellysGathered.Contains(name)) { saveData.pellysGathered.Add(name); } ES3.Save<APSaveData>(saveKey, saveData, es3Settings); } } public static void AddValuableGathered(string name) { name = name.Replace("Arctic ", "").Replace("Wizard ", "").Replace("Valuable ", "") .Replace("(Clone)", ""); if (Plugin.connection.session != null) { if (!saveData.valuablesGathered.Contains(name)) { saveData.valuablesGathered.Add(name); } ES3.Save<APSaveData>(saveKey, saveData, es3Settings); } } public static void AddMonsterSoulGathered(string name) { name = name.Replace("(Clone)", ""); if (Plugin.connection.session != null) { if (!saveData.monsterSoulsGathered.Contains(name)) { saveData.monsterSoulsGathered.Add(name); } ES3.Save<APSaveData>(saveKey, saveData, es3Settings); } } public static bool CheckCompletion() { if (Plugin.connection.session == null) { return false; } Debug.Log((object)"CheckComplete"); Debug.Log((object)$"Current Level: {StatsManager.instance.GetRunStatLevel()}\nQuota: {saveData.levelQuota}"); if (StatsManager.instance.GetRunStatLevel() < saveData.levelQuota) { Debug.Log((object)"Level Quota not met"); return false; } JArray pellysRequired = saveData.pellysRequired; List<string> list = new List<string> { "Manor", "Arctic", "Wizard" }; Debug.Log((object)"Pellys Required:"); foreach (JToken item in saveData.pellysRequired) { Debug.Log((object)$"-{((object)item).ToString()} {((JContainer)saveData.pellysRequired).Count}"); } Debug.Log((object)"Pellys Gathered:"); foreach (string item2 in saveData.pellysGathered) { Debug.Log((object)("-" + item2)); } foreach (JToken item3 in pellysRequired) { string pelly = (string)item3; foreach (string level in list) { if (!saveData.pellysGathered.Exists((string x) => x.Contains(level) && x.Contains(pelly))) { Debug.Log((object)"Pelly hunt not complete."); return false; } } } if (saveData.monsterHunt) { bool flag = true; Debug.Log((object)"Monster Hunt"); foreach (string all_monster_soul in LocationNames.all_monster_souls) { if (!saveData.monsterSoulsGathered.Contains(all_monster_soul)) { Debug.Log((object)(all_monster_soul + " has not been extracted")); flag = false; } else { Debug.Log((object)(all_monster_soul + " hunted")); } } if (!flag) { return false; } } if (saveData.valuableHunt) { bool flag2 = true; Debug.Log((object)"Valuable Hunt"); foreach (string all_valuable in LocationNames.all_valuables) { if (!saveData.valuablesGathered.Contains(all_valuable)) { Debug.Log((object)(all_valuable + " has not been extracted")); flag2 = false; } else { Debug.Log((object)(all_valuable + " extracted")); } } if (!flag2) { return false; } } Debug.Log((object)"All Goals Complete."); return true; } } internal class APConnectionData { private string address = "archipelago.gg"; private string port = ""; private string password = ""; private string slot = ""; } public class ArchipelagoConnection { public ArchipelagoSession session; public IEnumerator<bool> incomingItemHandler; public IEnumerator<bool> outgoingItemHandler; public IEnumerator<bool> checkItemsReceived; public bool sentCompletion; public bool sentRelease; public bool sentCollect; public Dictionary<string, object> slotData; public DeathLinkService deathLinkService; public int ItemIndex; private ConcurrentQueue<(ItemInfo NetworkItem, int index)> incomingItems; private ConcurrentQueue<ItemInfo> outgoingItems; public bool connected { get { if (session == null) { return false; } return session.Socket.Connected; } } public void TryConnect(string adress, int port, string pass, string player) { Debug.Log((object)"TryConnect"); if (connected) { Debug.Log((object)"Returning"); return; } TryDisconnect(); if (session == null) { try { session = ArchipelagoSessionFactory.CreateSession(adress, port); Debug.Log((object)("Session at " + session.ToString())); } catch { Debug.Log((object)"Failed to create archipelago session!"); } } incomingItemHandler = IncomingItemHandler(); outgoingItemHandler = OutgoingItemHandler(); checkItemsReceived = CheckItemsReceived(); incomingItems = new ConcurrentQueue<(ItemInfo, int)>(); outgoingItems = new ConcurrentQueue<ItemInfo>(); LoginResult loginResult; try { loginResult = session.TryConnectAndLogin("R.E.P.O", player, ItemsHandlingFlags.AllItems, null, null, null, pass); } catch (Exception ex) { loginResult = new LoginFailure(ex.GetBaseException().Message); } if (loginResult is LoginSuccessful loginSuccessful) { slotData = loginSuccessful.SlotData; Debug.Log((object)"Successfully connected to Archipelago Multiworld server!"); APSave.Init(); APSave.ScoutShopItems(); deathLinkService = session.CreateDeathLinkService(); return; } LoginFailure loginFailure = (LoginFailure)loginResult; Debug.Log((object)"Error connecting to Archipelago:"); string[] errors = loginFailure.Errors; for (int i = 0; i < errors.Length; i++) { Debug.Log((object)errors[i]); } ConnectionRefusedError[] errorCodes = loginFailure.ErrorCodes; for (int i = 0; i < errorCodes.Length; i++) { ConnectionRefusedError connectionRefusedError = errorCodes[i]; Debug.Log((object)connectionRefusedError.ToString()); } TryDisconnect(); } public void TryDisconnect() { try { if (session != null) { session.Socket.DisconnectAsync(); session = null; } incomingItems = new ConcurrentQueue<(ItemInfo, int)>(); outgoingItems = new ConcurrentQueue<ItemInfo>(); deathLinkService = null; slotData = null; ItemIndex = 0; Debug.Log((object)"Disconnected from Archipelago"); } catch { Debug.Log((object)"Encountered an error disconnecting from Archipelago!"); } } public void ActivateCheck(long locationID) { Debug.Log((object)("Checked Location " + locationID)); session.Locations.CompleteLocationChecks(locationID); Debug.Log((object)"TrySave"); APSave.AddLocationChecked(locationID); Debug.Log((object)"TrySync"); session.Locations.ScoutLocationsAsync(locationID).ContinueWith(delegate(Task<Dictionary<long, ScoutedItemInfo>> locationInfoPacket) { foreach (ScoutedItemInfo value in locationInfoPacket.Result.Values) { outgoingItems.Enqueue(value); } }); } 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) { Debug.Log((object)"Locations Unsynced, resyncing..."); Dictionary<string, int> dictionary2 = StatsManager.instance.dictionaryOfDictionaries["Locations Obtained"]; Debug.Log((object)("Server: " + count + "\nClient Count: " + dictionary?.ToString() + "\nClient Raw: " + dictionary2.Count)); } } public void ScoutLocation(long id) { if (session != null) { session.Locations.ScoutLocationsAsync(id); } } public string GetLocationName(long id) { return session.Locations.GetLocationNameFromId(id); } public long GetLocationID(string name) { return session.Locations.GetLocationIdFromName("Another Crabs Treasure", name); } public string GetItemName(long id) { return session.Items.GetItemName(id) ?? $"Item: {id}"; } private IEnumerator<bool> CheckItemsReceived() { while (connected) { if (session.Items.AllItemsReceived.Count > ItemIndex) { ItemInfo itemInfo = session.Items.AllItemsReceived[ItemIndex]; string itemName = itemInfo.ItemName; Debug.Log((object)("Placing item " + itemName + " with index " + ItemIndex + " in queue.")); incomingItems.Enqueue((itemInfo, ItemIndex)); ItemIndex++; yield return true; } else { yield return true; } } } private IEnumerator<bool> OutgoingItemHandler() { while (connected) { if (!outgoingItems.TryDequeue(out var result)) { yield return true; continue; } string itemName = result.ItemName; string locationName = result.LocationName; _ = result.LocationId; string playerName = session.Players.GetPlayerName(result.Player); Debug.Log((object)("Sent " + itemName + " at " + locationName + " for " + playerName)); _ = (int)result.Player; _ = session.ConnectionInfo.Slot; yield return true; } } private IEnumerator<bool> IncomingItemHandler() { while (connected) { if (!incomingItems.TryPeek(out (ItemInfo, int) result)) { yield return true; continue; } ItemInfo item = result.Item1; string itemName = item.ItemName; _ = itemName + " (" + item.ItemName + ") at index " + result.Item2; (ItemInfo, int) result2; if (APSave.GetItemRecievedIndex() > result.Item2) { incomingItems.TryDequeue(out result2); Debug.Log((object)("Skipping item " + itemName + " at index " + result.Item2 + " as it has already been processed.")); yield return true; } else { Debug.Log((object)("ItemHandler " + item.ItemId)); APSave.AddItemRecieved(item.ItemId); if (!new List<Level> { RunManager.instance.levelMainMenu, RunManager.instance.levelLobby, RunManager.instance.levelLobbyMenu }.Contains(RunManager.instance.levelCurrent)) { ItemData.AddItemToInventory(item.ItemId, repeatedAdditions: false); Plugin.customRPCManager.CallFocusTextRPC("Recieved " + itemName, Plugin.customRPCManagerObject); } incomingItems.TryDequeue(out result2); yield return true; } } } 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; Debug.Log((object)"Released remaining checks."); } } public void Collect() { if (connected && sentCompletion && !sentCollect) { session.Socket.SendPacket(new SayPacket { Text = "!collect" }); sentCollect = true; Debug.Log((object)"Collected remaining items."); } } public void SendDeathLink() { if (connected) { deathLinkService.SendDeathLink(new DeathLink(session.Players.ActivePlayer.Name)); } } } public class CustomRPCs : MonoBehaviour { public void CallUpdateItemNameRPC(string name, GameObject inst) { Debug.Log((object)"Calling RPC"); PhotonView component = inst.GetComponent<PhotonView>(); object[] array = new object[1] { name }; component.RPC("UpdateItemNameRPC", (RpcTarget)0, array); } public void CallFocusTextRPC(string message, GameObject inst) { if (GameManager.instance.gameMode == 1) { PhotonView component = inst.GetComponent<PhotonView>(); object[] array = new object[1] { message }; component.RPC("FocusTextRPC", (RpcTarget)0, array); } else { FocusTextOffline(message); } } [PunRPC] public void UpdateItemNameRPC(string name, PhotonMessageInfo info) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) Debug.Log((object)"RPC Called"); ItemAttributes component = ((Component)info.photonView).gameObject.GetComponent<ItemAttributes>(); AccessTools.Field(typeof(ItemAttributes), "itemName").SetValue(component, name.Replace("_", " ")); } [PunRPC] public void FocusTextRPC(string message) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) SemiFunc.UIFocusText(message, Color.white, Color.green, 3f); } public void FocusTextOffline(string message) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) SemiFunc.UIFocusText(message, Color.white, Color.green, 3f); } } [HarmonyPatch(typeof(TruckScreenText), "GotoNextLevel")] internal class NextLevelCheckCompletePatch { [HarmonyPostfix] private static void CheckComplete() { Debug.Log((object)"Truck Go To Next"); if (APSave.CheckCompletion()) { Plugin.connection.SendCompletion(); } } } [BepInPlugin("Automagic.ArchipelagoREPO", "Archipelago Randomizer", "0.1.5")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public static ArchipelagoConnection connection; 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>(); private void Awake() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) _player = PlayerController.instance; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin RepoAP is loaded!"); new Harmony("com.example.patch").PatchAll(); } private void Start() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown Debug.Log((object)"In Start"); connection = new ArchipelagoConnection(); customRPCManagerObject = new GameObject(); customRPCManager = customRPCManagerObject.AddComponent<CustomRPCs>(); customRPCManagerObject.AddComponent<PhotonView>(); Object.DontDestroyOnLoad((Object)(object)customRPCManager); } 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(); } } } public static void UpdateAPAddress(string input) { apAdress = input; } } internal class ItemData { private static int baseID = 75912022; public static void AddItemToInventory(long itemId, bool repeatedAdditions) { string text = IdToItemName(RemoveBaseId(itemId)); Debug.Log((object)("Adding Item To Inventory: " + RemoveBaseId(itemId) + " : " + text)); if (new List<string> { LocationNames.mcjannek, LocationNames.headman_manor, LocationNames.swiftbroom }.Contains(text)) { APSave.AddLevelRecieved(text); } else if (text == ItemNames.shopStock) { APSave.AddStockRecieved(); APSave.UpdateAvailableItems(); } else { StatsManager.instance.itemsPurchased[text]++; } } private static string IdToItemName(long itemId) { string result = ""; if ((ulong)itemId <= 18uL) { switch (itemId) { case 0L: result = LocationNames.swiftbroom; break; case 1L: result = LocationNames.headman_manor; break; case 2L: result = LocationNames.mcjannek; break; case 10L: result = ItemNames.upgreadHealth; break; case 11L: result = ItemNames.upgradeStrength; break; case 12L: result = ItemNames.upgradeRange; break; case 13L: result = ItemNames.upgradeSprintSpeed; break; case 14L: result = ItemNames.upgradeStamina; break; case 15L: result = ItemNames.upgradePlayerCount; break; case 16L: result = ItemNames.upgradeDoubleJump; break; case 17L: result = ItemNames.upgradeTumbleLaunch; break; case 18L: result = ItemNames.shopStock; break; } } return result; } public static long RemoveBaseId(long id) { return id - baseID; } public static long AddBaseId(long id) { return id + baseID; } } public static class ItemNames { public static string cartMed = "Item Cart Medium"; public static string cartSmall = "Item Cart Small"; public static string droneBattery = "Item Drone Battery"; public static string droneFeather = "Item Drone Feather"; public static string droneIndestructible = "Item Drone Indestructible"; public static string droneRoll = "Item Drone Torque"; public static string droneZeroGrav = "Item Drone Zero Gravity"; public static string extractTracker = "Item Extraction Tracker"; public static string grenadeDuctTape = "Item Grenade Duct Taped"; public static string grenade = "Item Grenade Explosive"; public static string grenadeHuman = "Item Grenade Human"; public static string grenadeShockwave = "Item Grenade Shockwave"; public static string grenadeStun = "Item Grenade Stun"; public static string gunPistol = "Item Gun Handgun"; public static string gunShotgun = "Item Gun Shotgun"; public static string gunTranq = "Item Gun Tranq"; public static string healthPackLarge = "Item Health Pack Large"; public static string healthPackMed = "Item Health Pack Medium"; public static string healthPackSmall = "Item Health Pack Small"; public static string baseballBat = "Item Melee Baseball Bat"; public static string fryingPan = "Item Melee Frying Pan"; public static string inflatableHammer = "Item Melee Inflatable Hammer"; public static string sledgeHammer = "Item Melee Sledge Hammer"; public static string sword = "Item Melee Sword"; public static string mineExplosive = "Item Mine Explosive"; public static string mineShockwave = "Item Mine Shockwave"; public static string mineStun = "Item Mine Stun"; public static string zeroGravOrb = "Item Orb Zero Gravity"; public static string powerCrystal = "Item Power Crystal"; public static string rubberDuck = "Item Rubber Duck"; public static string upgradePlayerCount = "Item Upgrade Map Player Count"; public static string upgradeStamina = "Item Upgrade Player Energy"; public static string upgradeDoubleJump = "Item Upgrade Player Extra Jump"; public static string upgradeRange = "Item Upgrade Player Grab Range"; public static string upgradeStrength = "Item Upgrade Player Grab Strength"; public static string upgreadHealth = "Item Upgrade Player Health"; public static string upgradeSprintSpeed = "Item Upgrade Player Sprint Speed"; public static string upgradeTumbleLaunch = "Item Upgrade Player Tumble Launch"; public static string valuableTracker = "Item Valuable Tracker"; public static string apItem = "Item Upgrade AP Item"; public static string shopStock = "Progressive Shop Stock"; } [HarmonyPatch(typeof(RunManager), "SetRunLevel")] internal class LevelLockPatch { [HarmonyPostfix] private static void SetRunLevelPre(RunManager __instance) { if (APSave.GetLevelsRecieved().Count == 0 || Plugin.connection.session == null) { Debug.LogError((object)"No Levels found in Save!"); return; } Dictionary<string, bool> levelsRecieved = APSave.GetLevelsRecieved(); List<string> list = new List<string>(); foreach (KeyValuePair<string, bool> item in levelsRecieved) { Debug.Log((object)("Player has " + item.Key)); list.Add(item.Key); } string text = list[Random.RandomRangeInt(0, list.Count)]; Level levelCurrent = null; Debug.Log((object)("Setting level to " + text)); foreach (Level level in __instance.levels) { if (text.Contains(level.NarrativeName)) { levelCurrent = level; } else { Debug.Log((object)(level.NarrativeName + " != " + text)); } } __instance.levelCurrent = levelCurrent; Debug.Log((object)("Returning " + ((Object)__instance.levelCurrent).name)); } } [HarmonyPatch(typeof(EnemyParent))] internal class EnemyDespawnPatch { [HarmonyPatch("Despawn")] [HarmonyPostfix] private static void OrbNaming(ref string ___enemyName, ref Enemy ___Enemy) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown bool num = (bool)AccessTools.Field(typeof(Enemy), "HasHealth").GetValue(___Enemy); EnemyHealth val = (EnemyHealth)AccessTools.Field(typeof(Enemy), "Health").GetValue(___Enemy); int num2 = (int)AccessTools.Field(typeof(EnemyHealth), "healthCurrent").GetValue(val); if (!num || !val.spawnValuable || num2 > 0) { return; } EnemyValuable[] array = (EnemyValuable[])(object)Object.FindObjectsByType(typeof(EnemyValuable), (FindObjectsSortMode)0); foreach (EnemyValuable val2 in array) { if (((Object)val2).name.Contains("Enemy Valuable")) { ((Object)val2).name = ___enemyName + " Soul"; } } } } internal class ExtractSendCheck { private static int totalHaul; public static void Send(FieldInfo totalHaulField) { totalHaul = (int)totalHaulField.GetValue(RoundDirector.instance); if (!SemiFunc.IsMasterClientOrSingleplayer() || RoundDirector.instance.dollarHaulList.Count == 0) { return; } foreach (GameObject dollarHaul in RoundDirector.instance.dollarHaulList) { Debug.Log((object)("Extracting " + ((Object)dollarHaul).name)); if (!Object.op_Implicit((Object)(object)dollarHaul) || !Object.op_Implicit((Object)(object)dollarHaul.GetComponent<PhysGrabObject>())) { continue; } totalHaulField.SetValue(RoundDirector.instance, totalHaul + (int)dollarHaul.GetComponent<ValuableObject>().dollarValueCurrent); if (((Object)dollarHaul).name.Contains("Pelly")) { Plugin.connection.ActivateCheck(LocationData.PellyNameToID(((Object)dollarHaul).name + ((Object)RunManager.instance.levelCurrent).name)); APSave.AddPellyGathered(((Object)dollarHaul).name + ((Object)RunManager.instance.levelCurrent).name); } else if (((Object)dollarHaul).name.Contains("Soul")) { long num = LocationData.MonsterSoulNameToID(((Object)dollarHaul).name); if (LocationData.RemoveBaseId(num) != 0L) { Plugin.connection.ActivateCheck(num); APSave.AddMonsterSoulGathered(((Object)dollarHaul).name); } } else if (((Object)dollarHaul).name.Contains("Valuable")) { long num2 = LocationData.ValuableNameToID(((Object)dollarHaul).name); if (LocationData.RemoveBaseId(num2) != 0L) { Plugin.connection.ActivateCheck(num2); APSave.AddValuableGathered(((Object)dollarHaul).name); } } } } } [HarmonyPatch(typeof(ExtractionPoint))] internal class ExtractionSendCheckPatch { private static FieldInfo field = AccessTools.Field(typeof(RoundDirector), "totalHaul"); private static int 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.Send(field); } } } internal static class LocationData { private static int baseID = 75912022; private static Dictionary<long, string> idToName; private static Dictionary<string, long> nameToId; private static long[] ids; private static long[] names; public static void CreateLocationTables() { for (int i = 0; i < 100; i++) { } } public static long MonsterSoulNameToID(string name) { long num = 0L; name = name.Replace("(Clone)", ""); switch (name) { case "Animal Soul": num = 300L; break; case "Apex Predator Soul": num = 301L; break; case "Bowtie Soul": num = 302L; break; case "Chef Soul": num = 303L; break; case "Clown Soul": num = 304L; break; case "Headman Soul": num = 305L; break; case "Hidden Soul": num = 306L; break; case "Huntsman Soul": num = 307L; break; case "Mentalist Soul": num = 308L; break; case "Reaper Soul": num = 309L; break; case "Robe Soul": num = 310L; break; case "Rugrat Soul": num = 311L; break; case "Shadow Child Soul": num = 312L; break; case "Spewer Soul": num = 313L; break; case "Trudge Soul": num = 314L; break; case "Upscream Soul": num = 315L; break; } if (num == 0L) { Debug.Log((object)(name + "'s id not found")); } return baseID + num; } public static long ValuableNameToID(string name) { long num = 0L; name = name.Replace("Arctic ", "").Replace("Wizard ", "").Replace("Valuable ", "") .Replace("(Clone)", ""); switch (name) { case "Diamond": num = 200L; break; case "Emerald Bracelet": num = 201L; break; case "Goblet": num = 202L; break; case "Ocarina": num = 203L; break; case "Pocket Watch": num = 204L; break; case "Uranium Mug": num = 205L; break; case "Crown": num = 206L; break; case "Doll": num = 207L; break; case "Barrel": num = 208L; break; case "Frog": num = 209L; break; case "Gem Box": num = 210L; break; case "Globe": num = 211L; break; case "Money": num = 212L; break; case "Toy Monkey": num = 213L; break; case "Uranium Plate": num = 214L; break; case "Vase Small": num = 215L; break; case "Bottle": num = 216L; break; case "Clown": num = 217L; break; case "Radio": num = 218L; break; case "Ship in a bottle": num = 219L; break; case "Trophy": num = 220L; break; case "Vase": num = 221L; break; case "Television": num = 222L; break; case "Vase Big": num = 223L; break; case "Animal Crate": num = 224L; break; case "Bonsai": num = 225L; break; case "Music Box": num = 226L; break; case "Gramophone": num = 227L; break; case "Diamond Display": num = 228L; break; case "Scream Doll": num = 229L; break; case "Piano": num = 230L; break; case "Harp": num = 231L; break; case "Painting": num = 232L; break; case "Grandfather Clock": num = 233L; break; case "Dinosaur": num = 234L; break; case "Golden Statue": num = 235L; break; case "Computer": num = 236L; break; case "Fan": num = 237L; break; case "Sample": num = 238L; break; case "Big Sample": num = 239L; break; case "Flamethrower": num = 240L; break; case "Science Station": num = 241L; break; case "Server Rack": num = 242L; break; case "3D Printer": num = 243L; break; case "HDD": num = 244L; break; case "Ice Saw": num = 245L; break; case "Laptop": num = 246L; break; case "Propane Tank": num = 247L; break; case "Sample Six Pack": num = 248L; break; case "Guitar": num = 249L; break; case "Sample Cooler": num = 250L; break; case "Creature Leg": num = 251L; break; case "Ice Block": num = 252L; break; case "Chomp Book": num = 253L; break; case "Love Potion": num = 254L; break; case "Cube of Knowledge": num = 255L; break; case "Dumgolfs Staff": num = 256L; break; case "Sword": num = 257L; break; case "Broom": num = 258L; break; case "Time Glass": num = 259L; break; case "Master Potion": num = 260L; break; case "Goblin Head": num = 261L; break; case "Griffin Statue": num = 262L; break; case "Power Crystal": num = 263L; break; } if (num == 0L) { Debug.Log((object)(name + "'s id not found")); } return baseID + num; } public static long PellyNameToID(string name) { int num = 100; if (name.Contains("Wizard")) { num++; } else if (name.Contains("Manor")) { num += 4; } else if (name.Contains("Arctic")) { num += 7; } if (name.Contains("Standard")) { num = num; } else if (name.Contains("Glass")) { num++; } else if (name.Contains("Gold")) { num += 2; } return baseID + 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 baseID + num; } return 0L; } public static long RemoveBaseId(long id) { return id - baseID; } public static long AddBaseId(long id) { return id + baseID; } } 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 = "Swiftbroom Academy "; public static string headman_manor = "Headman Manor "; public static string mcjannek = "McJannek Station "; public const string diamond = "Diamond"; public const string ring = "Emerald Bracelet"; public const string goblet = "Goblet"; public const string ocarina = "Ocarina"; public const string pocket_watch = "Pocket Watch"; public const string uranium_mug = "Uranium Mug"; public const string crown = "Crown"; public const string doll = "Doll"; public const string frog_toy = "Frog"; public const string gem_box = "Gem Box"; public const string globe = "Globe"; public const string money = "Money"; public const string monkey = "Toy Monkey"; public const string uranium_plate = "Uranium Plate"; public const string small_vase = "Vase Small"; public const string champagne = "Bottle"; public const string clown_doll = "Clown"; public const string radio = "Radio"; public const string ship_in_a_bottle = "Ship in a bottle"; public const string trophy = "Trophy"; public const string vase = "Vase"; public const string tv = "Television"; public const string large_vase = "Vase Big"; public const string animal_crate = "Animal Crate"; public const string bonsai = "Bonsai"; public const string music_box = "Music Box"; public const string gramophone = "Gramophone"; public const string rhino = "Diamond Display"; public const string scream_doll = "Scream Doll"; public const string grand_piano = "Piano"; public const string harp = "Harp"; public const string painting = "Painting"; public const string grandfather_clock = "Grandfather Clock"; public const string dinosaur_skeleton = "Dinosaur"; public const string golden_statue = "Golden Statue"; public const string desktop_computer = "Computer"; public const string fan = "Fan"; public const string explosive_barrel = "Barrel"; public const string sample = "Sample"; public const string big_sample = "Big Sample"; public const string flamethrower = "Flamethrower"; public const string science_station = "Science Station"; public const string server = "Server Rack"; public const string printer = "3D Printer"; public const string hdd = "HDD"; public const string ice_saw = "Ice Saw"; public const string laptop = "Laptop"; public const string propane = "Propane Tank"; public const string sample_pack = "Sample Six Pack"; public const string guitar = "Guitar"; public const string sample_cooler = "Sample Cooler"; public const string leg_ice = "Creature Leg"; public const string skeleton_ice = "Ice Block"; public const string chomp_book = "Chomp Book"; public const string love_potion = "Love Potion"; public const string cube_of_knowledge = "Cube of Knowledge"; public const string staff = "Dumgolfs Staff"; public const string large_sword = "Sword"; public const string broom = "Broom"; public const string hourglass = "Time Glass"; public const string master_potion = "Master Potion"; public const string goblin_head = "Goblin Head"; public const string griffin = "Griffin Statue"; public const string power_crystal = "Power Crystal"; public static readonly ReadOnlyCollection<string> all_valuables = new ReadOnlyCollection<string>(new List<string> { "Diamond", "Emerald Bracelet", "Goblet", "Ocarina", "Pocket Watch", "Uranium Mug", "Crown", "Doll", "Frog", "Gem Box", "Globe", "Money", "Toy Monkey", "Uranium Plate", "Vase Small", "Bottle", "Clown", "Radio", "Ship in a bottle", "Trophy", "Vase", "Television", "Vase Big", "Animal Crate", "Bonsai", "Music Box", "Gramophone", "Diamond Display", "Scream Doll", "Piano", "Harp", "Painting", "Grandfather Clock", "Dinosaur", "Golden Statue", "Computer", "Fan", "Barrel", "Sample", "Big Sample", "Flamethrower", "Science Station", "Server Rack", "3D Printer", "HDD", "Ice Saw", "Laptop", "Propane Tank", "Sample Six Pack", "Guitar", "Sample Cooler", "Creature Leg", "Ice Block", "Chomp Book", "Love Potion", "Cube of Knowledge", "Dumgolfs Staff", "Sword", "Broom", "Time Glass", "Master Potion", "Goblin Head", "Griffin Statue", "Power Crystal" }); public const string animal_soul = "Animal Soul"; public const string duck_soul = "Apex Predator Soul"; public const string bowtie_soul = "Bowtie Soul"; public const string chef_soul = "Chef Soul"; public const string clown_soul = "Clown Soul"; public const string headman_soul = "Headman Soul"; public const string hidden_soul = "Hidden Soul"; public const string huntsman_soul = "Huntsman Soul"; public const string mentalist_soul = "Mentalist 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 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", "Bowtie Soul", "Chef Soul", "Clown Soul", "Headman Soul", "Hidden Soul", "Huntsman Soul", "Mentalist Soul", "Reaper Soul", "Robe Soul", "Rugrat Soul", "Shadow Child Soul", "Spewer 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; } Debug.Log((object)"InValuableDirector"); _ = (List<GameObject>)AccessTools.Field(typeof(ValuableDirector), "mediumValuables").GetValue(__instance); foreach (LevelValuables valuablePreset in LevelGenerator.Instance.Level.ValuablePresets) { foreach (GameObject pelly in valuablePreset.medium.Where((GameObject x) => ((Object)x).name.Contains("Pelly")).ToList()) { Debug.Log((object)("Pelly Found: " + ((Object)pelly).name)); if (((IEnumerable<JToken>)APSave.saveData.pellysRequired).All((JToken x) => !((Object)pelly).name.Contains(((object)x).ToString()))) { Debug.Log((object)("Removing: " + ((Object)pelly).name)); valuablePreset.medium.Remove(pelly); } } } } } [HarmonyPatch(typeof(PhysGrabObject))] internal class PhysGrabObjectPatch { [HarmonyPatch("GrabStarted")] [HarmonyPostfix] private static void OrbInfoTextEnabler(PhysGrabObject __instance) { if (((Object)((Component)__instance).gameObject).name.Contains("soul")) { SemiFunc.UIItemInfoText((ItemAttributes)null, ((Object)((Component)__instance).gameObject).name); } } } [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_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Invalid comparison between Unknown and I4 shoppingList = (List<ItemAttributes>)field.GetValue(ShopManager.instance); Debug.Log((object)"Connected in shop check"); if (SemiFunc.IsMasterClientOrSingleplayer()) { if (Plugin.connection == null) { Debug.Log((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 (shopping.item.itemAssetName == ItemNames.apItem) { Debug.Log((object)("AP ITEM PURCHASED " + ((Object)shopping).name)); long num = LocationData.ShopItemToID(((Object)shopping).name); if (num != 0L) { Plugin.connection.ActivateCheck(num); } } else { Debug.Log((object)("Not AP Item\n" + shopping.item.itemAssetName + " != " + ItemNames.apItem)); StatsManager.instance.ItemPurchase(shopping.item.itemAssetName); } if ((int)shopping.item.itemType == 3 && shopping.item.itemAssetName != ItemNames.apItem) { StatsManager.instance.AddItemsUpgradesPurchased(shopping.item.itemAssetName); } ((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() { if (!((Object)RunManager.instance.levelCurrent).name.Contains("Menu")) { 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_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) AccessTools.Field(typeof(ItemAttributes), "itemName"); int num = itemList.Count - 1; while (num >= 0) { Item val; if (itemList[num].itemName.Contains("Upgrade") && !((Object)itemList[num]).name.Contains("Counted") && Plugin.ShopItemsAvailable.Count > 0) { Debug.Log((object)("Replacing " + itemList[num].itemName)); val = StatsManager.instance.itemDictionary[ItemNames.apItem]; if (val.itemVolume == itemVolume.itemVolume) { ((Component)ShopManager.instance.itemRotateHelper).transform.parent = ((Component)itemVolume).transform; ((Component)ShopManager.instance.itemRotateHelper).transform.localRotation = val.spawnRotationOffset; Quaternion rotation = ((Component)ShopManager.instance.itemRotateHelper).transform.rotation; ((Component)ShopManager.instance.itemRotateHelper).transform.parent = ((Component)ShopManager.instance).transform; string text = "Items/" + ((Object)val.prefab).name; if (SemiFunc.IsMultiplayer()) { GameObject obj = PhotonNetwork.InstantiateRoomObject(text, ((Component)itemVolume).transform.position, rotation, (byte)0, (object[])null); Plugin.LastShopItemChecked++; int index = new Random().Next(Plugin.ShopItemsAvailable.Count); int num2 = Plugin.ShopItemsAvailable[index]; ((Object)obj).name = ((Object)obj).name + "_Counted_" + num2; Plugin.ShopItemsAvailable.RemoveAt(index); } else { GameObject obj2 = Object.Instantiate<GameObject>(val.prefab, ((Component)itemVolume).transform.position, rotation); Plugin.LastShopItemChecked++; int index2 = new Random().Next(Plugin.ShopItemsAvailable.Count); int num3 = Plugin.ShopItemsAvailable[index2]; ((Object)obj2).name = ((Object)obj2).name + "_Counted_" + num3; Plugin.ShopItemsAvailable.RemoveAt(index2); } itemList.RemoveAt(num); if (!isSecret) { spawnCount++; } __result = true; return false; } num--; continue; } val = itemList[num]; return true; } __result = false; return false; } } [HarmonyPatch(typeof(ItemAttributes), "Start")] internal class APItemNamePatch { [HarmonyPostfix] private static void NamePatch(ref string ___itemName, ItemAttributes __instance) { //IL_00f4: Unknown result type (might be due to invalid IL or missing references) if (!___itemName.Contains("Archipelago")) { return; } ((Component)__instance).gameObject.AddComponent<CustomRPCs>(); if (!SemiFunc.IsMasterClientOrSingleplayer() || !((Object)RunManager.instance.levelCurrent).name.Contains("Shop")) { return; } string text = ((Object)__instance).name; if (text.Any(char.IsDigit)) { text = new string(text.Where((char x) => char.IsDigit(x)).ToArray()); } ___itemName = ___itemName + " " + text; ItemInfo scoutedShopItem = APSave.GetScoutedShopItem(LocationData.AddBaseId(long.Parse(text))); ___itemName = $"{scoutedShopItem.Player}'s {scoutedShopItem.ItemName}"; if (GameManager.instance.gameMode == 1) { _ = (PhotonView)AccessTools.Field(typeof(ItemUpgrade), "photonView").GetValue(((Component)__instance).GetComponent<ItemUpgrade>()); Plugin.customRPCManager.CallUpdateItemNameRPC(___itemName, ((Component)__instance).gameObject); } } } [HarmonyPatch(typeof(PlayerController), "Update")] internal class DebugKeys { [HarmonyPrefix] private static void Prefix() { if (Input.GetKeyDown((KeyCode)277)) { Plugin.showMenu = !Plugin.showMenu; Debug.Log((object)"Toggle Menu"); } if (Input.GetKeyDown((KeyCode)282)) { Debug.Log((object)"F1 Pressed"); RunManager.instance.ChangeLevel(true, false, (ChangeLevelType)5); } if (Input.GetKeyDown((KeyCode)283)) { Debug.Log((object)"F2 Pressed"); SemiFunc.StatSetRunCurrency(100000); } if (Input.GetKeyDown((KeyCode)284)) { Debug.Log((object)"F3 Pressed"); foreach (string key in StatsManager.instance.itemDictionary.Keys) { Debug.Log((object)(key ?? "")); } } if (Input.GetKeyDown((KeyCode)285)) { Debug.Log((object)"F4 Pressed"); StatsManager.instance.itemsPurchased[ItemNames.upgradeStrength] = 15; } if (Input.GetKeyDown((KeyCode)286)) { Debug.Log((object)"Try Connect"); Plugin.connection.TryConnect(Plugin.apAdress, int.Parse(Plugin.apPort), Plugin.apPassword, Plugin.apSlot); } if (Input.GetKeyDown((KeyCode)287)) { string text = "-- Completetion Data --"; text += $"\nLevel Quota: {APSave.saveData.levelQuota}"; text += "\nPellys Required: "; foreach (JToken item in APSave.saveData.pellysRequired) { text = text + "\n- " + ((object)item).ToString(); } text += "\n\nPellys Gathered: "; foreach (string item2 in APSave.saveData.pellysGathered) { text = text + "\n- " + item2; } text += "\n\nValuables Gathered: "; foreach (string item3 in APSave.saveData.valuablesGathered) { text = text + "\n- " + item3; } text += "\n\nValuables Missing: "; foreach (string all_valuable in LocationNames.all_valuables) { if (!APSave.saveData.valuablesGathered.Contains(all_valuable)) { text = text + "\n- Missing " + all_valuable; } } text += "\n\nMonster Souls Missing: "; foreach (string all_monster_soul in LocationNames.all_monster_souls) { if (!APSave.saveData.monsterSoulsGathered.Contains(all_monster_soul)) { text = text + "\n- Missing " + all_monster_soul; } } text += "\n\nMonster Souls Gathered: "; foreach (string item4 in APSave.saveData.monsterSoulsGathered) { text = text + "\n- " + item4; } Debug.Log((object)text); } if (Input.GetKeyDown((KeyCode)289)) { Debug.Log((object)((Object)RunManager.instance.levelCurrent).name); } if (Input.GetKeyDown((KeyCode)290)) { Debug.Log((object)APSave.saveData.shopStockRecieved); } } } public static class MyPluginInfo { public const string PLUGIN_GUID = "RepoAP"; public const string PLUGIN_NAME = "Archipelago Randomizer"; public const string PLUGIN_VERSION = "1.0.0"; } } namespace RepoAP.Items { [HarmonyPatch(typeof(StatsManager), "RunStartStats")] internal class StartRunWithAPItemsPatch { [HarmonyPostfix] private static void RunStartStatsPatch() { if (Plugin.connection.session == null) { return; } Debug.Log((object)"Start Run With AP Items"); foreach (KeyValuePair<long, int> item in APSave.GetItemsRecieved()) { for (int i = 0; i < item.Value; i++) { ItemData.AddItemToInventory(item.Key, repeatedAdditions: true); } } } } } internal interface IConcurrentHashSet<T> { bool TryAdd(T item); bool Contains(T item); void UnionWith(T[] otherSet); T[] ToArray(); ReadOnlyCollection<T> AsToReadOnlyCollection(); ReadOnlyCollection<T> AsToReadOnlyCollectionExcept(IConcurrentHashSet<T> otherSet); } namespace Archipelago.MultiClient.Net { [Serializable] public abstract class ArchipelagoPacketBase { [JsonIgnore] internal JObject jobject; [JsonProperty("cmd")] [JsonConverter(typeof(StringEnumConverter))] public abstract ArchipelagoPacketType PacketType { get; } public JObject ToJObject() { return jobject; } } public interface IArchipelagoSession : IArchipelagoSessionActions { IArchipelagoSocketHelper Socket { get; } IReceivedItemsHelper Items { get; } ILocationCheckHelper Locations { get; } IPlayerHelper Players { get; } IDataStorageHelper DataStorage { get; } IConnectionInfoProvider ConnectionInfo { get; } IRoomStateHelper RoomState { get; } IMessageLogHelper MessageLog { get; } Task<RoomInfoPacket> ConnectAsync(); Task<LoginResult> LoginAsync(string game, string name, ItemsHandlingFlags itemsHandlingFlags, Version version = null, string[] tags = null, string uuid = null, string password = null, bool requestSlotData = true); LoginResult TryConnectAndLogin(string game, string name, ItemsHandlingFlags itemsHandlingFlags, Version version = null, string[] tags = null, string uuid = null, string password = null, bool requestSlotData = true); } public class ArchipelagoSession : IArchipelagoSession, IArchipelagoSessionActions { private const int ArchipelagoConnectionTimeoutInSeconds = 4; private ConnectionInfoHelper connectionInfo; private TaskCompletionSource<LoginResult> loginResultTask = new TaskCompletionSource<LoginResult>(); private TaskCompletionSource<RoomInfoPacket> roomInfoPacketTask = new TaskCompletionSource<RoomInfoPacket>(); public IArchipelagoSocketHelper Socket { get; } public IReceivedItemsHelper Items { get; } public ILocationCheckHelper Locations { get; } public IPlayerHelper Players { get; } public IDataStorageHelper DataStorage { get; } public IConnectionInfoProvider ConnectionInfo => connectionInfo; public IRoomStateHelper RoomState { get; } public IMessageLogHelper MessageLog { get; } internal ArchipelagoSession(IArchipelagoSocketHelper socket, IReceivedItemsHelper items, ILocationCheckHelper locations, IPlayerHelper players, IRoomStateHelper roomState, ConnectionInfoHelper connectionInfoHelper, IDataStorageHelper dataStorage, IMessageLogHelper messageLog) { Socket = socket; Items = items; Locations = locations; Players = players; RoomState = roomState; connectionInfo = connectionInfoHelper; DataStorage = dataStorage; MessageLog = messageLog; socket.PacketReceived += Socket_PacketReceived; } private void Socket_PacketReceived(ArchipelagoPacketBase packet) { if (!(packet is ConnectedPacket) && !(packet is ConnectionRefusedPacket)) { if (packet is RoomInfoPacket result) { roomInfoPacketTask.TrySetResult(result); } return; } if (packet is ConnectedPacket && RoomState.Version != null && RoomState.Version >= new Version(0, 3, 8)) { LogUsedVersion(); } loginResultTask.TrySetResult(LoginResult.FromPacket(packet)); } private void LogUsedVersion() { try { string fileVersion = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion; Socket.SendPacketAsync(new SetPacket { Key = ".NetUsedVersions", DefaultValue = (JToken)(object)JObject.FromObject((object)new Dictionary<string, bool>()), Operations = new OperationSpecification[1] { Operation.Update(new Dictionary<string, bool> { { ConnectionInfo.Game + ":" + fileVersion + ":NET45", true } }) } }); } catch { } } public Task<RoomInfoPacket> ConnectAsync() { roomInfoPacketTask = new TaskCompletionSource<RoomInfoPacket>(); Task.Factory.StartNew(delegate { try { Task task = Socket.ConnectAsync(); task.Wait(TimeSpan.FromSeconds(4.0)); if (!task.IsCompleted) { roomInfoPacketTask.TrySetCanceled(); } } catch (AggregateException) { roomInfoPacketTask.TrySetCanceled(); } }); return roomInfoPacketTask.Task; } public Task<LoginResult> LoginAsync(string game, string name, ItemsHandlingFlags itemsHandlingFlags, Version version = null, string[] tags = null, string uuid = null, string password = null, bool requestSlotData = true) { loginResultTask = new TaskCompletionSource<LoginResult>(); if (!roomInfoPacketTask.Task.IsCompleted) { loginResultTask.TrySetResult(new LoginFailure("You are not connected, run ConnectAsync() first")); return loginResultTask.Task; } connectionInfo.SetConnectionParameters(game, tags, itemsHandlingFlags, uuid); try { Socket.SendPacket(BuildConnectPacket(name, password, version, requestSlotData)); } catch (ArchipelagoSocketClosedException) { loginResultTask.TrySetResult(new LoginFailure("You are not connected, run ConnectAsync() first")); return loginResultTask.Task; } SetResultAfterTimeout(loginResultTask, 4, new LoginFailure("Connection timed out.")); return loginResultTask.Task; } private static void SetResultAfterTimeout<T>(TaskCompletionSource<T> task, int timeoutInSeconds, T result) { new CancellationTokenSource(TimeSpan.FromSeconds(timeoutInSeconds)).Token.Register(delegate { task.TrySetResult(result); }); } public LoginResult TryConnectAndLogin(string game, string name, ItemsHandlingFlags itemsHandlingFlags, Version version = null, string[] tags = null, string uuid = null, string password = null, bool requestSlotData = true) { Task<RoomInfoPacket> task = ConnectAsync(); try { task.Wait(TimeSpan.FromSeconds(4.0)); } catch (AggregateException ex) { if (ex.GetBaseException() is OperationCanceledException) { return new LoginFailure("Connection timed out."); } return new LoginFailure(ex.GetBaseException().Message); } if (!task.IsCompleted) { return new LoginFailure("Connection timed out."); } return LoginAsync(game, name, itemsHandlingFlags, version, tags, uuid, password, requestSlotData).Result; } private ConnectPacket BuildConnectPacket(string name, string password, Version version, bool requestSlotData) { return new ConnectPacket { Game = ConnectionInfo.Game, Name = name, Password = password, Tags = ConnectionInfo.Tags, Uuid = ConnectionInfo.Uuid, Version = ((version != null) ? new NetworkVersion(version) : new NetworkVersion(0, 6, 0)), ItemsHandling = ConnectionInfo.ItemsHandlingFlags, RequestSlotData = requestSlotData }; } public void Say(string message) { Socket.SendPacket(new SayPacket { Text = message }); } public void SetClientState(ArchipelagoClientState state) { Socket.SendPacket(new StatusUpdatePacket { Status = state }); } public void SetGoalAchieved() { SetClientState(ArchipelagoClientState.ClientGoal); } } public interface IArchipelagoSessionActions { void Say(string message); void SetClientState(ArchipelagoClientState state); void SetGoalAchieved(); } public static class ArchipelagoSessionFactory { public static ArchipelagoSession CreateSession(Uri uri) { ArchipelagoSocketHelper socket = new ArchipelagoSocketHelper(uri); DataPackageCache cache = new DataPackageCache(socket); ConnectionInfoHelper connectionInfoHelper = new ConnectionInfoHelper(socket); PlayerHelper playerHelper = new PlayerHelper(socket, connectionInfoHelper); ItemInfoResolver itemInfoResolver = new ItemInfoResolver(cache, connectionInfoHelper); LocationCheckHelper locationCheckHelper = new LocationCheckHelper(socket, itemInfoResolver, connectionInfoHelper, playerHelper); ReceivedItemsHelper items = new ReceivedItemsHelper(socket, locationCheckHelper, itemInfoResolver, connectionInfoHelper, playerHelper); RoomStateHelper roomState = new RoomStateHelper(socket, locationCheckHelper); DataStorageHelper dataStorage = new DataStorageHelper(socket, connectionInfoHelper); MessageLogHelper messageLog = new MessageLogHelper(socket, itemInfoResolver, playerHelper, connectionInfoHelper); return new ArchipelagoSession(socket, items, locationCheckHelper, playerHelper, roomState, connectionInfoHelper, dataStorage, messageLog); } public static ArchipelagoSession CreateSession(string hostname, int port = 38281) { return CreateSession(ParseUri(hostname, port)); } internal static Uri ParseUri(string hostname, int port) { string text = hostname; if (!text.StartsWith("ws://") && !text.StartsWith("wss://")) { text = "unspecified://" + text; } if (!text.Substring(text.IndexOf("://", StringComparison.Ordinal) + 3).Contains(":")) { text += $":{port}"; } if (text.EndsWith(":")) { text += port; } return new Uri(text); } } public abstract class LoginResult { public abstract bool Successful { get; } public static LoginResult FromPacket(ArchipelagoPacketBase packet) { if (!(packet is ConnectedPacket connectedPacket)) { if (packet is ConnectionRefusedPacket connectionRefusedPacket) { return new LoginFailure(connectionRefusedPacket); } throw new ArgumentOutOfRangeException("packet", "packet is not a connection result packet"); } return new LoginSuccessful(connectedPacket); } } public class LoginSuccessful : LoginResult { public override bool Successful => true; public int Team { get; } public int Slot { get; } public Dictionary<string, object> SlotData { get; } public LoginSuccessful(ConnectedPacket connectedPacket) { Team = connectedPacket.Team; Slot = connectedPacket.Slot; SlotData = connectedPacket.SlotData; } } public class LoginFailure : LoginResult { public override bool Successful => false; public ConnectionRefusedError[] ErrorCodes { get; } public string[] Errors { get; } public LoginFailure(ConnectionRefusedPacket connectionRefusedPacket) { if (connectionRefusedPacket.Errors != null) { ErrorCodes = connectionRefusedPacket.Errors.ToArray(); Errors = ErrorCodes.Select(GetErrorMessage).ToArray(); } else { ErrorCodes = new ConnectionRefusedError[0]; Errors = new string[0]; } } public LoginFailure(string message) { ErrorCodes = new ConnectionRefusedError[0]; Errors = new string[1] { message }; } private static string GetErrorMessage(ConnectionRefusedError errorCode) { return errorCode switch { ConnectionRefusedError.InvalidSlot => "The slot name did not match any slot on the server.", ConnectionRefusedError.InvalidGame => "The slot is set to a different game on the server.", ConnectionRefusedError.SlotAlreadyTaken => "The slot already has a connection with a different uuid established.", ConnectionRefusedError.IncompatibleVersion => "The client and server version mismatch.", ConnectionRefusedError.InvalidPassword => "The password is invalid.", ConnectionRefusedError.InvalidItemsHandling => "The item handling flags provided are invalid.", _ => $"Unknown error: {errorCode}.", }; } } internal class TwoWayLookup<TA, TB> : IEnumerable<KeyValuePair<TB, TA>>, IEnumerable { private readonly Dictionary<TA, TB> aToB = new Dictionary<TA, TB>(); private readonly Dictionary<TB, TA> bToA = new Dictionary<TB, TA>(); public TA this[TB b] => bToA[b]; public TB this[TA a] => aToB[a]; public void Add(TA a, TB b) { aToB[a] = b; bToA[b] = a; } public void Add(TB b, TA a) { Add(a, b); } public bool TryGetValue(TA a, out TB b) { return aToB.TryGetValue(a, out b); } public bool TryGetValue(TB b, out TA a) { return bToA.TryGetValue(b, out a); } public IEnumerator<KeyValuePair<TB, TA>> GetEnumerator() { return bToA.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } } namespace Archipelago.MultiClient.Net.Packets { public class BouncedPacket : BouncePacket { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Bounced; } public class BouncePacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Bounce; [JsonProperty("games")] public List<string> Games { get; set; } = new List<string>(); [JsonProperty("slots")] public List<int> Slots { get; set; } = new List<int>(); [JsonProperty("tags")] public List<string> Tags { get; set; } = new List<string>(); [JsonProperty("data")] public Dictionary<string, JToken> Data { get; set; } } public class ConnectedPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Connected; [JsonProperty("team")] public int Team { get; set; } [JsonProperty("slot")] public int Slot { get; set; } [JsonProperty("players")] public NetworkPlayer[] Players { get; set; } [JsonProperty("missing_locations")] public long[] MissingChecks { get; set; } [JsonProperty("checked_locations")] public long[] LocationsChecked { get; set; } [JsonProperty("slot_data")] public Dictionary<string, object> SlotData { get; set; } [JsonProperty("slot_info")] public Dictionary<int, NetworkSlot> SlotInfo { get; set; } [JsonProperty("hint_points")] public int? HintPoints { get; set; } } public class ConnectionRefusedPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.ConnectionRefused; [JsonProperty("errors", ItemConverterType = typeof(StringEnumConverter))] public ConnectionRefusedError[] Errors { get; set; } } public class ConnectPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Connect; [JsonProperty("password")] public string Password { get; set; } [JsonProperty("game")] public string Game { get; set; } [JsonProperty("name")] public string Name { get; set; } [JsonProperty("uuid")] public string Uuid { get; set; } [JsonProperty("version")] public NetworkVersion Version { get; set; } [JsonProperty("tags")] public string[] Tags { get; set; } [JsonProperty("items_handling")] public ItemsHandlingFlags ItemsHandling { get; set; } [JsonProperty("slot_data")] public bool RequestSlotData { get; set; } } public class ConnectUpdatePacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.ConnectUpdate; [JsonProperty("tags")] public string[] Tags { get; set; } [JsonProperty("items_handling")] public ItemsHandlingFlags? ItemsHandling { get; set; } } public class DataPackagePacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.DataPackage; [JsonProperty("data")] public Archipelago.MultiClient.Net.Models.DataPackage DataPackage { get; set; } } public class GetDataPackagePacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.GetDataPackage; [JsonProperty("games")] public string[] Games { get; set; } } public class GetPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Get; [JsonProperty("keys")] public string[] Keys { get; set; } } public class InvalidPacketPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.InvalidPacket; [JsonProperty("type")] public InvalidPacketErrorType ErrorType { get; set; } [JsonProperty("text")] public string ErrorText { get; set; } [JsonProperty("original_cmd")] public ArchipelagoPacketType OriginalCmd { get; set; } } public class LocationChecksPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.LocationChecks; [JsonProperty("locations")] public long[] Locations { get; set; } } public class LocationInfoPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.LocationInfo; [JsonProperty("locations")] public NetworkItem[] Locations { get; set; } } public class LocationScoutsPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.LocationScouts; [JsonProperty("locations")] public long[] Locations { get; set; } [JsonProperty("create_as_hint")] public int CreateAsHint { get; set; } } public class PrintJsonPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.PrintJSON; [JsonProperty("data")] public JsonMessagePart[] Data { get; set; } [JsonProperty("type")] [JsonConverter(typeof(StringEnumConverter))] public JsonMessageType? MessageType { get; set; } } public class ItemPrintJsonPacket : PrintJsonPacket { [JsonProperty("receiving")] public int ReceivingPlayer { get; set; } [JsonProperty("item")] public NetworkItem Item { get; set; } } public class ItemCheatPrintJsonPacket : PrintJsonPacket { [JsonProperty("receiving")] public int ReceivingPlayer { get; set; } [JsonProperty("item")] public NetworkItem Item { get; set; } [JsonProperty("team")] public int Team { get; set; } } public class HintPrintJsonPacket : PrintJsonPacket { [JsonProperty("receiving")] public int ReceivingPlayer { get; set; } [JsonProperty("item")] public NetworkItem Item { get; set; } [JsonProperty("found")] public bool? Found { get; set; } } public class JoinPrintJsonPacket : PrintJsonPacket { [JsonProperty("team")] public int Team { get; set; } [JsonProperty("slot")] public int Slot { get; set; } [JsonProperty("tags")] public string[] Tags { get; set; } } public class LeavePrintJsonPacket : PrintJsonPacket { [JsonProperty("team")] public int Team { get; set; } [JsonProperty("slot")] public int Slot { get; set; } } public class ChatPrintJsonPacket : PrintJsonPacket { [JsonProperty("team")] public int Team { get; set; } [JsonProperty("slot")] public int Slot { get; set; } [JsonProperty("message")] public string Message { get; set; } } public class ServerChatPrintJsonPacket : PrintJsonPacket { [JsonProperty("message")] public string Message { get; set; } } public class TutorialPrintJsonPacket : PrintJsonPacket { } public class TagsChangedPrintJsonPacket : PrintJsonPacket { [JsonProperty("team")] public int Team { get; set; } [JsonProperty("slot")] public int Slot { get; set; } [JsonProperty("tags")] public string[] Tags { get; set; } } public class CommandResultPrintJsonPacket : PrintJsonPacket { } public class AdminCommandResultPrintJsonPacket : PrintJsonPacket { } public class GoalPrintJsonPacket : PrintJsonPacket { [JsonProperty("team")] public int Team { get; set; } [JsonProperty("slot")] public int Slot { get; set; } } public class ReleasePrintJsonPacket : PrintJsonPacket { [JsonProperty("team")] public int Team { get; set; } [JsonProperty("slot")] public int Slot { get; set; } } public class CollectPrintJsonPacket : PrintJsonPacket { [JsonProperty("team")] public int Team { get; set; } [JsonProperty("slot")] public int Slot { get; set; } } public class CountdownPrintJsonPacket : PrintJsonPacket { [JsonProperty("countdown")] public int RemainingSeconds { get; set; } } public class ReceivedItemsPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.ReceivedItems; [JsonProperty("index")] public int Index { get; set; } [JsonProperty("items")] public NetworkItem[] Items { get; set; } } public class RetrievedPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Retrieved; [JsonProperty("keys")] public Dictionary<string, JToken> Data { get; set; } } public class RoomInfoPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.RoomInfo; [JsonProperty("version")] public NetworkVersion Version { get; set; } [JsonProperty("generator_version")] public NetworkVersion GeneratorVersion { get; set; } [JsonProperty("tags")] public string[] Tags { get; set; } [JsonProperty("password")] public bool Password { get; set; } [JsonProperty("permissions")] public Dictionary<string, Permissions> Permissions { get; set; } [JsonProperty("hint_cost")] public int HintCostPercentage { get; set; } [JsonProperty("location_check_points")] public int LocationCheckPoints { get; set; } [JsonProperty("players")] public NetworkPlayer[] Players { get; set; } [JsonProperty("games")] public string[] Games { get; set; } [JsonProperty("datapackage_checksums")] public Dictionary<string, string> DataPackageChecksums { get; set; } [JsonProperty("seed_name")] public string SeedName { get; set; } [JsonProperty("time")] public double Timestamp { get; set; } } public class RoomUpdatePacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.RoomUpdate; [JsonProperty("tags")] public string[] Tags { get; set; } [JsonProperty("password")] public bool? Password { get; set; } [JsonProperty("permissions")] public Dictionary<string, Permissions> Permissions { get; set; } = new Dictionary<string, Permissions>(); [JsonProperty("hint_cost")] public int? HintCostPercentage { get; set; } [JsonProperty("location_check_points")] public int? LocationCheckPoints { get; set; } [JsonProperty("players")] public NetworkPlayer[] Players { get; set; } [JsonProperty("hint_points")] public int? HintPoints { get; set; } [JsonProperty("checked_locations")] public long[] CheckedLocations { get; set; } } public class SayPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Say; [JsonProperty("text")] public string Text { get; set; } } public class SetNotifyPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.SetNotify; [JsonProperty("keys")] public string[] Keys { get; set; } } public class SetPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Set; [JsonProperty("key")] public string Key { get; set; } [JsonProperty("default")] public JToken DefaultValue { get; set; } [JsonProperty("operations")] public OperationSpecification[] Operations { get; set; } [JsonProperty("want_reply")] public bool WantReply { get; set; } [JsonExtensionData] public Dictionary<string, JToken> AdditionalArguments { get; set; } [OnDeserialized] internal void OnDeserializedMethod(StreamingContext context) { AdditionalArguments?.Remove("cmd"); } } public class SetReplyPacket : SetPacket { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.SetReply; [JsonProperty("value")] public JToken Value { get; set; } [JsonProperty("original_value")] public JToken OriginalValue { get; set; } } public class StatusUpdatePacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.StatusUpdate; [JsonProperty("status")] public ArchipelagoClientState Status { get; set; } } public class SyncPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Sync; } internal class UnknownPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Unknown; } public class UpdateHintPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.UpdateHint; [JsonProperty("player")] public int Player { get; set; } [JsonProperty("location")] public long Location { get; set; } [JsonProperty("status")] public HintStatus Status { get; set; } } } namespace Archipelago.MultiClient.Net.Models { public struct Color : IEquatable<Color> { public static Color Red = new Color(byte.MaxValue, 0, 0); public static Color Green = new Color(0, 128, 0); public static Color Yellow = new Color(byte.MaxValue, byte.MaxValue, 0); public static Color Blue = new Color(0, 0, byte.MaxValue); public static Color Magenta = new Color(byte.MaxValue, 0, byte.MaxValue); public static Color Cyan = new Color(0, byte.MaxValue, byte.MaxValue); public static Color Black = new Color(0, 0, 0); public static Color White = new Color(byte.MaxValue, byte.MaxValue, byte.MaxValue); public static Color SlateBlue = new Color(106, 90, 205); public static Color Salmon = new Color(250, 128, 114); public static Color Plum = new Color(221, 160, 221); public byte R { get; set; } public byte G { get; set; } public byte B { get; set; } public Color(byte r, byte g, byte b) { R = r; G = g; B = b; } public override bool Equals(object obj) { if (obj is Color color && R == color.R && G == color.G) { return B == color.B; } return false; } public bool Equals(Color other) { if (R == other.R && G == other.G) { return B == other.B; } return false; } public override int GetHashCode() { return ((-1520100960 * -1521134295 + R.GetHashCode()) * -1521134295 + G.GetHashCode()) * -1521134295 + B.GetHashCode(); } public static bool operator ==(Color left, Color right) { return left.Equals(right); } public static bool operator !=(Color left, Color right) { return !(left == right); } } public class DataPackage { [JsonProperty("games")] public Dictionary<string, GameData> Games { get; set; } = new Dictionary<string, GameData>(); } public class DataStorageElement { internal DataStorageElementContext Context; internal List<OperationSpecification> Operations = new List<OperationSpecification>(0); internal DataStorageHelper.DataStorageUpdatedHandler Callbacks; internal Dictionary<string, JToken> AdditionalArguments = new Dictionary<string, JToken>(0); private JToken cachedValue; public event DataStorageHelper.DataStorageUpdatedHandler OnValueChanged { add { Context.AddHandler(Context.Key, value); } remove { Context.RemoveHandler(Context.Key, value); } } internal DataStorageElement(DataStorageElementContext context) { Context = context; } internal DataStorageElement(OperationType operationType, JToken value) { Operations = new List<OperationSpecification>(1) { new OperationSpecification { OperationType = operationType, Value = value } }; } internal DataStorageElement(DataStorageElement source, OperationType operationType, JToken value) : this(source.Context) { Operations = source.Operations.ToList(); Callbacks = source.Callbacks; AdditionalArguments = source.AdditionalArguments; Operations.Add(new OperationSpecification { OperationType = operationType, Value = value }); } internal DataStorageElement(DataStorageElement source, Callback callback) : this(source.Context) { Operations = source.Operations.ToList(); Callbacks = source.Callbacks; AdditionalArguments = source.AdditionalArguments; Callbacks = (DataStorageHelper.DataStorageUpdatedHandler)Delegate.Combine(Callbacks, callback.Method); } internal DataStorageElement(DataStorageElement source, AdditionalArgument additionalArgument) : this(source.Context) { Operations = source.Operations.ToList(); Callbacks = source.Callbacks; AdditionalArguments = source.AdditionalArguments; AdditionalArguments[additionalArgument.Key] = additionalArgument.Value; } public static DataStorageElement operator ++(DataStorageElement a) { return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(1)); } public static DataStorageElement operator --(DataStorageElement a) { return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(-1)); } public static DataStorageElement operator +(DataStorageElement a, int b) { return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b)); } public static DataStorageElement operator +(DataStorageElement a, long b) { return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b)); } public static DataStorageElement operator +(DataStorageElement a, float b) { return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b)); } public static DataStorageElement operator +(DataStorageElement a, double b) { return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b)); } public static DataStorageElement operator +(DataStorageElement a, decimal b) { return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b)); } public static DataStorageElement operator +(DataStorageElement a, string b) { return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b)); } public static DataStorageElement operator +(DataStorageElement a, JToken b) { return new DataStorageElement(a, OperationType.Add, b); } public static DataStorageElement operator +(DataStorageElement a, IEnumerable b) { return new DataStorageElement(a, OperationType.Add, (JToken)(object)JArray.FromObject((object)b)); } public static DataStorageElement operator +(DataStorageElement a, OperationSpecification s) { return new DataStorageElement(a, s.OperationType, s.Value); } public static DataStorageElement operator +(DataStorageElement a, Callback c) { return new DataStorageElement(a, c); } public static DataStorageElement operator +(DataStorageElement a, AdditionalArgument arg) { return new DataStorageElement(a, arg); } public static DataStorageElement operator *(DataStorageElement a, int b) { return new DataStorageElement(a, OperationType.Mul, JToken.op_Implicit(b)); } public static DataStorageElement operator *(DataStorageElement a, long b) { return new DataStorageElement(a, OperationType.Mul, JToken.op_Implicit(b)); } public static DataStorageElement operator *(DataStorageElement a, float b) { return new DataStorageElement(a, OperationType.Mul, JToken.op_Implicit(b)); } public static DataStorageElement operator *(DataStorageElement a, double b) { return new DataStorageElement(a, OperationType.Mul, JToken.op_Implicit(b)); } public static DataStorageElement operator *(DataStorageElement a, decimal b) { return new DataStorageElement(a, OperationType.Mul, JToken.op_Implicit(b)); } public static DataStorageElement operator %(DataStorageElement a, int b) { return new DataStorageElement(a, OperationType.Mod, JToken.op_Implicit(b)); } public static DataStorageElement operator %(DataStorageElement a, long b) { return new DataStorageElement(a, OperationType.Mod, JToken.op_Implicit(b)); } public static DataStorageElement operator %(DataStorageElement a, float b) { return new DataStorageElement(a, OperationType.Mod, JToken.op_Implicit(b)); } public static DataStorageElement operator %(DataStorageElement a, double b) { return new DataStorageElement(a, OperationType.Mod, JToken.op_Implicit(b)); } public static DataStorageElement operator %(DataStorageElement a, decimal b) { return new DataStorageElement(a, OperationType.Mod, JToken.op_Implicit(b)); } public static DataStorageElement operator ^(DataStorageElement a, int b) { return new DataStorageElement(a, OperationType.Pow, JToken.op_Implicit(b)); } public static DataStorageElement operator ^(DataStorageElement a, long b) { return new DataStorageElement(a, OperationType.Pow, JToken.op_Implicit(b)); } public static DataStorageElement operator ^(DataStorageElement a, float b) { return new DataStorageElement(a, OperationType.Pow, JToken.op_Implicit(b)); } public static DataStorageElement operator ^(DataStorageElement a, double b) { return new DataStorageElement(a, OperationType.Pow, JToken.op_Implicit(b)); } public static DataStorageElement operator ^(DataStorageElement a, decimal b) { return new DataStorageElement(a, OperationType.Pow, JToken.op_Implicit(b)); } public static DataStorageElement operator -(DataStorageElement a, int b) { return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(-b))); } public static DataStorageElement operator -(DataStorageElement a, long b) { return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(-b))); } public static DataStorageElement operator -(DataStorageElement a, float b) { return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(0f - b))); } public static DataStorageElement operator -(DataStorageElement a, double b) { return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(0.0 - b))); } public static DataStorageElement operator -(DataStorageElement a, decimal b) { return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(-b))); } public static DataStorageElement operator /(DataStorageElement a, int b) { return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1m / (decimal)b))); } public static DataStorageElement operator /(DataStorageElement a, long b) { return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1m / (decimal)b))); } public static DataStorageElement operator /(DataStorageElement a, float b) { return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1.0 / (double)b))); } public static DataStorageElement operator /(DataStorageElement a, double b) { return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1.0 / b))); } public static DataStorageElement operator /(DataStorageElement a, decimal b) { return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1m / b))); } public static implicit operator DataStorageElement(bool b) { return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(b)); } public static implicit operator DataStorageElement(int i) { return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(i)); } public static implicit operator DataStorageElement(long l) { return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(l)); } public static implicit operator DataStorageElement(decimal m) { return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(m)); } public static implicit operator DataStorageElement(double d) { return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(d)); } public static implicit operator DataStorageElement(float f) { return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(f)); } public static implicit operator DataStorageElement(string s) { if (s != null) { return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(s)); } return new DataStorageElement(Opera