Decompiled source of TCG AP Client v0.1.1
plugins/ApClient.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.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text.RegularExpressions; using ApClient; using ApClient.data; using ApClient.mapping; using ApClient.patches; using ApClientl; using Archipelago.MultiClient.Net; using Archipelago.MultiClient.Net.BounceFeatures.DeathLink; using Archipelago.MultiClient.Net.Enums; using Archipelago.MultiClient.Net.Helpers; using Archipelago.MultiClient.Net.Models; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using I2.Loc; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: AssemblyCompany("ApClient")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0+a9e83673d04db92b1b0a59e4e3c6006510262a1c")] [assembly: AssemblyProduct("Ap Client For TCG Sim")] [assembly: AssemblyTitle("ApClient")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ApClientl { public class APGui : MonoBehaviour { public static bool showGUI = true; public static string ipporttext = Settings.Instance.LastUsedIP.Value; public static string password = Settings.Instance.LastUsedPassword.Value; public static string slot = Settings.Instance.LastUsedSlot.Value; public static string state = "Not Connected"; private void OnGUI() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) if (showGUI) { GUI.Box(new Rect(10f, 10f, 200f, 300f), "AP Client"); GUIStyle val = new GUIStyle(); val.fontSize = 12; val.normal.textColor = Color.white; GUI.Label(new Rect(20f, 40f, 300f, 30f), "Address:port", val); ipporttext = GUI.TextField(new Rect(20f, 60f, 180f, 25f), ipporttext, 25); GUI.Label(new Rect(20f, 90f, 300f, 30f), "Password", val); password = GUI.TextField(new Rect(20f, 110f, 180f, 25f), password, 25); GUI.Label(new Rect(20f, 140f, 300f, 30f), "Slot", val); slot = GUI.TextField(new Rect(20f, 160f, 180f, 25f), slot, 25); if (GUI.Button(new Rect(20f, 210f, 180f, 30f), "Connect")) { Debug.Log((object)"Button Pressed!"); Plugin.m_SessionHandler.connect(ipporttext, password, slot); } GUI.Label(new Rect(20f, 240f, 300f, 30f), state, val); } } private void Update() { //IL_003a: Unknown result type (might be due to invalid IL or missing references) if (Input.GetKeyDown((KeyCode)104)) { CSingleton<PriceChangeManager>.Instance.EvaluatePriceChange(); CSingleton<PriceChangeManager>.Instance.EvaluatePriceCrash(); CPlayerData.UpdateItemPricePercentChange(); CPlayerData.UpdatePastCardPricePercentChange(); } if (Input.GetKeyDown(Settings.Instance.MyHotkey.Value)) { showGUI = !showGUI; } } } } namespace ApClient { public class APClientSaveManager { private APSaveData aPSaveData; public APClientSaveManager() { aPSaveData = new APSaveData(); Clear(); } public void Clear() { aPSaveData.ProcessedIndex = 0; aPSaveData.MoneyMultiplier = 1f; aPSaveData.Luck = 0; aPSaveData.newCards = new List<int>(); for (int i = 1; i < 122; i++) { aPSaveData.newCards.Add(i); } } public void setSeed(string seed) { aPSaveData.seed = seed; } public void setProcessedIndex(int index) { aPSaveData.ProcessedIndex = index; } public void IncreaseProcessedIndex() { aPSaveData.ProcessedIndex++; } public int GetProcessedIndex() { return aPSaveData.ProcessedIndex; } public void IncreaseMoneyMult() { aPSaveData.MoneyMultiplier = (aPSaveData.MoneyMultiplier += 1.025f); } public float GetMoneyMult() { return aPSaveData.MoneyMultiplier; } public int GetLuck() { return aPSaveData.Luck; } public void IncreaseLuck() { aPSaveData.Luck++; } public List<int> GetIncompleteCards() { return aPSaveData.newCards; } public void CompleteCardId(int id) { aPSaveData.newCards.Remove(id); } public void setIncompleteCards(List<int> list) { aPSaveData.newCards = list; } private string GetBaseDirectory() { return Path.GetDirectoryName(GetType().Assembly.Location); } private string getGdSavePath() { return GetBaseDirectory() + "/Saves/ApClient_" + aPSaveData.seed + ".gd"; } private string getJsonSavePath() { return GetBaseDirectory() + "/Saves/ApClient_" + aPSaveData.seed + ".json"; } public bool doesSaveExist() { return File.Exists(getJsonSavePath()) || File.Exists(getGdSavePath()); } public void Save(int saveSlotIndex) { Directory.CreateDirectory(GetBaseDirectory() + "/Saves/"); Plugin.Log("AP Save saveSlotIndex " + saveSlotIndex); CSaveLoad.m_SavedGame = CGameData.instance; try { string text = JsonUtility.ToJson((object)CSaveLoad.m_SavedGame); string text2 = JsonConvert.SerializeObject((object)aPSaveData.newCards); string contents = text.TrimEnd('}') + $", \"processedItems\": \"{aPSaveData.ProcessedIndex}\", \"newCardIds\": {text2} , \"maxMoney\": \"{aPSaveData.MoneyMultiplier}\", \"luck\": \"{aPSaveData.Luck}\"}}"; File.WriteAllText(getJsonSavePath(), contents); } catch { Debug.Log((object)"Error saving JSON"); } } public bool Load() { string gdSavePath = getGdSavePath(); string jsonSavePath = getJsonSavePath(); bool flag = false; if (File.Exists(jsonSavePath)) { try { string text = File.ReadAllText(jsonSavePath); if (!(text == "") && text != null) { Match match = Regex.Match(text, "\"maxMoney\":\\s*\"([^\"]*)\""); if (match.Success) { string value = match.Groups[1].Value; int.TryParse(value, out var result); aPSaveData.MoneyMultiplier = result; Debug.Log((object)$"Extracted maxMoney: {result}"); } text = Regex.Replace(text, ",\\s*\"maxMoney\":\\s*\"[^\"]*\"", ""); match = Regex.Match(text, "\"luck\":\\s*\"([^\"]*)\""); if (match.Success) { string value2 = match.Groups[1].Value; int.TryParse(value2, out var result2); aPSaveData.Luck = result2; Debug.Log((object)$"Extracted luck: {result2}"); } text = Regex.Replace(text, ",\\s*\"luck\":\\s*\"[^\"]*\"", ""); Match match2 = Regex.Match(text, "\"newCardIds\"\\s*:\\s*\\{(.*?)\\}\\s*(,|})", RegexOptions.Singleline); if (match2.Success) { string text2 = "{" + match2.Groups[1].Value + "}"; aPSaveData.newCards = JsonConvert.DeserializeObject<List<int>>(text2); } string text3 = Regex.Replace(text, "\"newCardIds\"\\s*:\\s*\\{(.*?)\\}\\s*(,|})", "", RegexOptions.Singleline); match = Regex.Match(text, "\"processedItems\":\\s*\"([^\"]*)\""); if (match.Success) { string value3 = match.Groups[1].Value; int.TryParse(value3, out var result3); aPSaveData.ProcessedIndex = result3; Debug.Log((object)$"Extracted processedItems: {result3}"); } text = Regex.Replace(text, ",\\s*\"processedItems\":\\s*\"[^\"]*\"", ""); Debug.Log((object)"Modified JSON before deserialization"); CSaveLoad.m_SavedGame = JsonUtility.FromJson<CGameData>(text); return true; } flag = true; } catch { flag = true; } } return false; } } public class CoroutineRunner : MonoBehaviour { private static CoroutineRunner _instance; public static CoroutineRunner Instance { get { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown if ((Object)(object)_instance == (Object)null) { GameObject val = new GameObject("CoroutineRunner"); Object.DontDestroyOnLoad((Object)(object)val); _instance = val.AddComponent<CoroutineRunner>(); } return _instance; } } } public class ItemHandler { private Coroutine cashOnlyCoroutine; private float remainingTime = 0f; private bool timerRunning = false; public bool cashOnly = false; public void processNewItem(ItemInfo itemReceived) { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected O, but got Unknown //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Expected O, but got Unknown //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Expected O, but got Unknown //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Expected O, but got Unknown //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Expected O, but got Unknown //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Expected O, but got Unknown //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_0b13: Unknown result type (might be due to invalid IL or missing references) //IL_0b18: Unknown result type (might be due to invalid IL or missing references) //IL_0b20: Unknown result type (might be due to invalid IL or missing references) //IL_0b28: Unknown result type (might be due to invalid IL or missing references) //IL_0b2a: Unknown result type (might be due to invalid IL or missing references) //IL_0b2f: Unknown result type (might be due to invalid IL or missing references) //IL_0b34: Unknown result type (might be due to invalid IL or missing references) //IL_0b39: Unknown result type (might be due to invalid IL or missing references) //IL_0b3e: Unknown result type (might be due to invalid IL or missing references) //IL_0b40: Unknown result type (might be due to invalid IL or missing references) //IL_0b45: Unknown result type (might be due to invalid IL or missing references) //IL_0b4c: Unknown result type (might be due to invalid IL or missing references) //IL_0b59: Expected O, but got Unknown Plugin.Log(itemReceived.ItemName); if ((int)itemReceived.ItemId == ExpansionMapping.warehouseKey) { CSingleton<UnlockRoomManager>.Instance.SetUnlockWarehouseRoom(true); AchievementManager.OnShopLotBUnlocked(); CPlayerData.m_GameReportDataCollect.upgradeCost -= 5000f; CPlayerData.m_GameReportDataCollectPermanent.upgradeCost -= 5000f; SoundManager.PlayAudio("SFX_CustomerBuy", 0.6f, 1f); PopupTextPatches.ShowCustomText("Warehouse Key Found"); } else if ((int)itemReceived.ItemId == TrashMapping.smallMoney) { CEventManager.QueueEvent((CEvent)new CEventPlayer_AddCoin((float)(10 * Math.Min(CPlayerData.m_ShopLevel + 1, 25)), false)); } else if ((int)itemReceived.ItemId == TrashMapping.mediumMoney) { CEventManager.QueueEvent((CEvent)new CEventPlayer_AddCoin((float)(20 * Math.Min(CPlayerData.m_ShopLevel + 1, 25)), false)); } else if ((int)itemReceived.ItemId == TrashMapping.largeMoney) { CEventManager.QueueEvent((CEvent)new CEventPlayer_AddCoin((float)(40 * Math.Min(CPlayerData.m_ShopLevel + 1, 25)), false)); } else if ((int)itemReceived.ItemId == TrashMapping.smallXp) { CEventManager.QueueEvent((CEvent)new CEventPlayer_AddShopExp(Math.Min((int)((double)CPlayerData.GetExpRequiredToLevelUp() * 0.1), (CPlayerData.m_ShopLevel + 1 > 20) ? ((int)((double)(300 * (CPlayerData.m_ShopLevel + 1)) * 0.2)) : 400), false)); } else if ((int)itemReceived.ItemId == TrashMapping.mediumXp) { CEventManager.QueueEvent((CEvent)new CEventPlayer_AddShopExp(Math.Min((int)((double)CPlayerData.GetExpRequiredToLevelUp() * 0.17), (CPlayerData.m_ShopLevel + 1 > 20) ? ((int)((double)(600 * (CPlayerData.m_ShopLevel + 1)) * 0.2)) : 800), false)); } else if ((int)itemReceived.ItemId == TrashMapping.largeXp) { CEventManager.QueueEvent((CEvent)new CEventPlayer_AddShopExp(Math.Min((int)((double)CPlayerData.GetExpRequiredToLevelUp() * 0.25), (CPlayerData.m_ShopLevel + 1 > 20) ? ((int)((double)(1000 * (CPlayerData.m_ShopLevel + 1)) * 0.2)) : 1500), false)); } else if ((int)itemReceived.ItemId == TrashMapping.randomcard) { Array values = Enum.GetValues(typeof(ECollectionPackType)); ECollectionPackType collectionPackType = (ECollectionPackType)values.GetValue(Random.Range(0, (Plugin.m_SessionHandler.GetSlotData().CardSanity == 0) ? 8 : Plugin.m_SessionHandler.GetSlotData().CardSanity)); CPlayerData.AddCard(cardRoller(collectionPackType), 1); } else if ((int)itemReceived.ItemId == TrashMapping.randomNewCard) { CardData val = RandomNewCard(); Plugin.Log($"Card is: {val.monsterType} and {val.expansionType}"); CPlayerData.AddCard(val, 1); } else if ((int)itemReceived.ItemId == TrashMapping.ProgressiveCustomerMoney) { Plugin.m_SaveManager.IncreaseMoneyMult(); } else if ((int)itemReceived.ItemId == TrashMapping.IncreaseCardLuck) { Plugin.m_SaveManager.IncreaseLuck(); } else { if ((int)itemReceived.ItemId == TrashMapping.stinkTrap) { FieldInfo field = typeof(CustomerManager).GetField("m_CustomerList", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) { return; } List<Customer> list = (List<Customer>)field.GetValue(CSingleton<CustomerManager>.Instance); { foreach (Customer item in list) { item.SetSmelly(); } return; } } if ((int)itemReceived.ItemId == TrashMapping.lightTrap) { ((MonoBehaviour)CoroutineRunner.Instance).StartCoroutine(ToggleLightMultipleTimes()); } else if ((int)itemReceived.ItemId == TrashMapping.CreditCardFailure) { remainingTime += 60f; if (!timerRunning) { cashOnlyCoroutine = ((MonoBehaviour)CoroutineRunner.Instance).StartCoroutine(CashOnlyTimerCoroutine()); } } else { if ((int)itemReceived.ItemId == TrashMapping.MarketChangeTrap) { return; } if (LicenseMapping.getKeyValue((int)itemReceived.ItemId).Key != -1) { PopupTextPatches.ShowCustomText("New License Unlocked"); KeyValuePair<int, (int, string, int, int, EItemType)> keyValue = LicenseMapping.getKeyValue((int)itemReceived.ItemId, Plugin.m_SessionHandler.itemCount((int)itemReceived.ItemId)); RestockItemPanelUI val2 = null; RestockItemPanelUI[] array = Object.FindObjectsOfType<RestockItemPanelUI>(); RestockItemPanelUI[] array2 = array; foreach (RestockItemPanelUI val3 in array2) { if (val3.GetIndex() == (float)keyValue.Key) { val2 = val3; break; } } if (!((Object)(object)val2 == (Object)null)) { RestockItemPanelUIPatches.runLicenseBtnLogic(val2, hasItem: true, keyValue.Key); Plugin.Log($"Recieved Item While panel was open: {(int)itemReceived.ItemId} and {keyValue.Key}"); } } else if ((int)itemReceived.ItemId == ExpansionMapping.progressiveA) { ExpansionShopUIScreen val4 = Object.FindObjectOfType<ExpansionShopUIScreen>(); if ((Object)(object)val4 != (Object)null) { FieldInfo field2 = typeof(ExpansionShopUIScreen).GetField("m_IsShopB", BindingFlags.Instance | BindingFlags.NonPublic); if (!(bool)field2.GetValue(val4)) { ExpansionShopPanelUI val5 = val4.m_ExpansionShopPanelUIList[Plugin.m_SessionHandler.itemCount((int)itemReceived.ItemId) - 1]; val5.m_LockPurchaseBtn.gameObject.SetActive(false); val5.m_PurchasedBtn.gameObject.SetActive(false); } } } else if ((int)itemReceived.ItemId == ExpansionMapping.progressiveB) { ExpansionShopUIScreen val6 = Object.FindObjectOfType<ExpansionShopUIScreen>(); if (!((Object)(object)val6 != (Object)null)) { return; } FieldInfo field3 = typeof(ExpansionShopUIScreen).GetField("m_IsShopB", BindingFlags.Instance | BindingFlags.NonPublic); if (!(bool)field3.GetValue(val6)) { return; } ExpansionShopPanelUI val7 = val6.m_ExpansionShopPanelUIList[Plugin.m_SessionHandler.itemCount((int)itemReceived.ItemId) - 1]; FieldInfo field4 = typeof(ExpansionShopPanelUI).GetField("m_LevelRequired", BindingFlags.Instance | BindingFlags.NonPublic); if (!(field4 == null)) { int num = (int)field4.GetValue(val7); if (CPlayerData.m_ShopLevel + 1 < num) { val7.m_LockPurchaseBtn.gameObject.SetActive(false); val7.m_PurchasedBtn.gameObject.SetActive(false); ((Component)val7.m_LevelRequirementText).gameObject.SetActive(false); } else { ((TMP_Text)val7.m_LevelRequirementText).text = $"Shop Level {val7.m_LevelRequired} Required"; } } } else if (EmployeeMapping.getKeyValue((int)itemReceived.ItemId).Key != -1) { KeyValuePair<int, (int, string, int)> keyValue2 = EmployeeMapping.getKeyValue((int)itemReceived.ItemId); Plugin.Log($"worker recieved id: {EmployeeMapping.getKeyValue((int)itemReceived.ItemId).Key}"); HireWorkerScreen val8 = Object.FindObjectOfType<HireWorkerScreen>(); HireWorkerPanelUI[] array3 = Object.FindObjectsOfType<HireWorkerPanelUI>(); HireWorkerPanelUI val9 = null; HireWorkerPanelUI[] array4 = array3; foreach (HireWorkerPanelUI val10 in array4) { FieldInfo field5 = typeof(HireWorkerPanelUI).GetField("m_Index", BindingFlags.Instance | BindingFlags.NonPublic); if (field5 == null) { return; } int num2 = (int)field5.GetValue(val10); if (num2 == keyValue2.Key) { val9 = val10; break; } } if (!((Object)(object)val9 == (Object)null)) { Plugin.Log("detected Hire Worker Screen"); Plugin.Log("Found Hire Worker Panel"); val9.m_HiredText.SetActive(false); val9.m_PurchaseBtn.SetActive(true); Plugin.Log($"Recieved Worker While panel was open: {(int)itemReceived.ItemId}"); } } else if (FurnatureMapping.getKeyValue((int)itemReceived.ItemId).Key != -1) { KeyValuePair<int, (int, string, int)> keyValue3 = FurnatureMapping.getKeyValue((int)itemReceived.ItemId, Plugin.m_SessionHandler.itemCount((int)itemReceived.ItemId)); FurnitureShopPanelUI val11 = null; FurnitureShopPanelUI[] array5 = Object.FindObjectsOfType<FurnitureShopPanelUI>(); FurnitureShopPanelUI[] array6 = array5; foreach (FurnitureShopPanelUI val12 in array6) { FieldInfo field6 = typeof(FurnitureShopPanelUI).GetField("m_Index", BindingFlags.Instance | BindingFlags.NonPublic); if (field6 == null) { return; } int num3 = (int)field6.GetValue(val12); if (num3 == keyValue3.Key) { val11 = val12; break; } } if (!((Object)(object)val11 == (Object)null)) { FurnaturePatches.EnableFurnature(val11, keyValue3.Key); } } else { if ((int)itemReceived.ItemId != CardMapping.ghostProgressive) { return; } bool flag = false; int num4 = 0; List<bool> isCardCollectedList = CPlayerData.GetIsCardCollectedList((ECardExpansionType)2, flag); num4 = isCardCollectedList.FindAll((bool i) => i).Count; if (num4 >= 36) { flag = true; isCardCollectedList = CPlayerData.GetIsCardCollectedList((ECardExpansionType)2, flag); num4 += isCardCollectedList.FindAll((bool i) => i).Count; } if (Plugin.m_SessionHandler.GetSlotData().Goal == 2 && Plugin.m_SessionHandler.GetSlotData().GhostGoalAmount <= num4) { Plugin.m_SessionHandler.SendGoalCompletion(); PopupTextPatches.ShowCustomText($"Congrats! You Collected {num4} Ghost Cards and Completed Your Goal!"); } List<EMonsterType> shownMonsterList = InventoryBase.GetShownMonsterList((ECardExpansionType)2); bool isFoil = false; int index = 0; for (int m = 0; m < shownMonsterList.Count; m++) { int num5 = m * CPlayerData.GetCardAmountPerMonsterType((ECardExpansionType)2, true) + 5; if (isCardCollectedList[num5]) { num5 += CPlayerData.GetCardAmountPerMonsterType((ECardExpansionType)2, false); if (!isCardCollectedList[num5]) { isFoil = true; index = m; break; } continue; } index = m; break; } CPlayerData.AddCard(new CardData { isFoil = isFoil, isDestiny = flag, borderType = (ECardBorderType)5, monsterType = shownMonsterList[index], expansionType = (ECardExpansionType)2, isChampionCard = false, isNew = true }, 1); } } } } public CardData RandomNewCard() { //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02b9: Unknown result type (might be due to invalid IL or missing references) //IL_02be: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_02cc: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Unknown result type (might be due to invalid IL or missing references) //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Expected O, but got Unknown Plugin.Log("random new card"); int border_sanity = 5; bool flag = true; if (Plugin.m_SessionHandler.GetSlotData().CardSanity != 0) { border_sanity = Plugin.m_SessionHandler.GetSlotData().BorderInSanity; flag = Plugin.m_SessionHandler.GetSlotData().FoilInSanity; } List<int> incompleteCards = Plugin.m_SaveManager.GetIncompleteCards(); if (incompleteCards.Count == 0) { Plugin.m_SaveManager.setIncompleteCards(PlayerDataPatches.GetValidTypeIdsForSanity()); incompleteCards = Plugin.m_SaveManager.GetIncompleteCards(); } int num = incompleteCards[Random.Range(0, incompleteCards.Count)]; int index = (num - 1) * CPlayerData.GetCardAmountPerMonsterType((ECardExpansionType)0, true); List<int> list = (from x in CPlayerData.GetIsCardCollectedList((ECardExpansionType)0, false).GetRange(index, flag ? 12 : 6).Select((bool val, int idx) => new { val, idx }) where !x.val && x.idx % 6 <= border_sanity select x.idx).ToList(); Plugin.Log($"border <= {border_sanity}"); Plugin.Log(string.Join(", ", list)); index = (num - 1) * CPlayerData.GetCardAmountPerMonsterType((ECardExpansionType)1, true); List<int> list2 = (from x in CPlayerData.GetIsCardCollectedList((ECardExpansionType)1, false).GetRange(index, flag ? 12 : 6).Select((bool val, int idx) => new { val, idx }) where !x.val && x.idx % 6 <= border_sanity select x.idx).ToList(); int num2 = 0; bool flag2 = false; if (list.Count > 0) { num2 = list[Random.Range(0, list.Count)]; } else { if (list2.Count <= 0 || Plugin.m_SessionHandler.GetSlotData().CardSanity <= 4) { Plugin.Log($"You have collected all Cards for {(object)(EMonsterType)num}"); Plugin.m_SaveManager.CompleteCardId(num); return cardRoller((ECollectionPackType)7); } num2 = list2[Random.Range(0, list2.Count)]; flag2 = true; if (list2.Count == 1) { Plugin.m_SaveManager.CompleteCardId(num); } } ECardExpansionType val2 = (ECardExpansionType)(flag2 ? 1 : 0); return new CardData { isFoil = (num2 > 5), isDestiny = flag2, borderType = CPlayerData.GetCardBorderType(num2 % 6, val2), monsterType = (EMonsterType)num, expansionType = val2, isChampionCard = false, isNew = true }; } private static CardData cardRoller(ECollectionPackType collectionPackType) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Invalid comparison between Unknown and I4 //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Expected O, but got Unknown ECardExpansionType val = (ECardExpansionType)(!((double)Random.Range(0f, 1f) > 0.5)); return new CardData { isFoil = ((double)Random.Range(0f, 1f) > 0.5), isDestiny = ((int)val == 1), borderType = (ECardBorderType)Random.Range(0, 7), monsterType = (EMonsterType)Random.Range(0, 122), expansionType = val, isChampionCard = false, isNew = true }; } private IEnumerator ToggleLightMultipleTimes() { int repeats = Random.Range(1, 6) * 2 - 1; for (int i = 0; i < repeats; i++) { CSingleton<LightManager>.Instance.ToggleShopLight(); SoundManager.PlayAudio("SFX_ButtonLightTap", 0.6f, 0.5f); float delay = Random.Range(0.5f, 2f); yield return (object)new WaitForSeconds(delay); } } private IEnumerator CashOnlyTimerCoroutine() { timerRunning = true; for (cashOnly = true; remainingTime > 0f; remainingTime -= Time.deltaTime) { yield return null; } cashOnly = false; timerRunning = false; } } [BepInPlugin("ApClient", "Ap Client For TCG Sim", "0.1.0")] public class Plugin : BaseUnityPlugin { internal static ManualLogSource Logger; private readonly Harmony m_Harmony = new Harmony("ApClient"); public static APClientSaveManager m_SaveManager = new APClientSaveManager(); public static ItemHandler m_ItemHandler = new ItemHandler(); public static SessionHandler m_SessionHandler = new SessionHandler(); private static bool SceneLoaded = false; private Plugin() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown m_Harmony.PatchAll(); } private void Awake() { Logger = ((BaseUnityPlugin)this).Logger; Settings.Instance.Load(this); Logger.LogInfo((object)"Plugin ApClient is loaded!"); SceneManager.sceneLoaded += OnSceneLoad; } private void Start() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown GameObject val = new GameObject("MyGUI"); val.AddComponent<APGui>(); Object.DontDestroyOnLoad((Object)(object)val); } private void OnDestroy() { m_Harmony.UnpatchSelf(); } public static bool isSceneLoaded() { return SceneLoaded; } public static void onSceneLoadLogic() { SceneLoaded = true; m_SessionHandler.ProcessCachedItems(); } public static bool OverrideTrades() { return m_SessionHandler.GetSlotData().TradesAreNew; } public static float getNumLuckItems() { Log($"Luck: {m_SaveManager.GetLuck()}"); return m_SaveManager.GetLuck(); } public static bool isCashOnly() { return m_ItemHandler.cashOnly; } public static CardData getNewCard() { return m_ItemHandler.RandomNewCard(); } private void OnSceneLoad(Scene scene, LoadSceneMode mode) { Log(" Scene Load: " + ((Scene)(ref scene)).name); if (((Scene)(ref scene)).name == "Title") { m_SaveManager.Clear(); setTitleInteractable(interactable: false); SceneLoaded = false; } if (((Scene)(ref scene)).name == "Start") { APGui.showGUI = false; } } public static void RunTitleInteractableSaveLogic() { TitleScreen val = Object.FindFirstObjectByType<TitleScreen>(); GameObject val2 = GameObject.Find("NewGameBtn"); Button val3 = null; if ((Object)(object)val2 != (Object)null) { val3 = val2.GetComponentInChildren<Button>(); } if (m_SaveManager.doesSaveExist()) { ((Selectable)val.m_LoadGameButton).interactable = true; ((Selectable)val3).interactable = false; } else { ((Selectable)val.m_LoadGameButton).interactable = false; ((Selectable)val3).interactable = true; } } public static void setTitleInteractable(bool interactable) { TitleScreen val = Object.FindFirstObjectByType<TitleScreen>(); ((Selectable)val.m_LoadGameButton).interactable = interactable; GameObject val2 = GameObject.Find("NewGameBtn"); if ((Object)(object)val2 != (Object)null) { Button componentInChildren = val2.GetComponentInChildren<Button>(); ((Selectable)componentInChildren).interactable = interactable; } } public static void Log(string s) { Logger.LogInfo((object)s); } } public class SessionHandler { private class ItemCache { public ItemInfo info { get; set; } public int index { get; set; } } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static Func<string, string> <>9__13_0; public static Func<string, bool> <>9__13_1; public static Func<KeyValuePair<int, (int itemid, string name, int count, int locid, EItemType)>, int> <>9__19_0; public static SocketClosedHandler <>9__22_0; internal string <StrToList>b__13_0(string s) { return s.Trim(); } internal bool <StrToList>b__13_1(string s) { int result; return int.TryParse(s, out result); } internal int <addStartingChecks>b__19_0(KeyValuePair<int, (int itemid, string name, int count, int locid, EItemType)> kvp) { return kvp.Value.count; } internal void <connect>b__22_0(string reason) { APGui.showGUI = true; } } private ArchipelagoSession session; private SlotData slotData = new SlotData(); private Queue<ItemCache> cachedItems = new Queue<ItemCache>(); private LoginResult result = null; private Coroutine autoSaveCoroutine; private float remainingTime = 0f; private bool timerRunning = false; private int startingCounter = 200; private DeathLinkService deathLinkService = null; public SlotData GetSlotData() { return slotData; } public int itemCount(long id) { return session.Items.AllItemsReceived.Where((ItemInfo i) => i.ItemId == id).Count(); } public bool ControlTrades() { return slotData.TradesAreNew; } public bool hasItem(long id) { return itemCount(id) > 0; } public void SendGoalCompletion() { session.SetGoalAchieved(); } public void CompleteLocationChecks(params long[] ids) { session.Locations.CompleteLocationChecks(ids); } public bool isStartingItem(int id) { return id == Plugin.m_SessionHandler.GetSlotData().pg1IndexMapping[0] || id == Plugin.m_SessionHandler.GetSlotData().pg2IndexMapping[0] || id == Plugin.m_SessionHandler.GetSlotData().pg3IndexMapping[0]; } public int[] startingids() { return new int[3] { Plugin.m_SessionHandler.GetSlotData().pg1IndexMapping[0], Plugin.m_SessionHandler.GetSlotData().pg2IndexMapping[0], Plugin.m_SessionHandler.GetSlotData().pg3IndexMapping[0] }; } private List<int> StrToList(string str) { int num; return (from s in str.Trim('[', ']').Split(',') select s.Trim() into s where int.TryParse(s, out num) select s).Select(int.Parse).ToList(); } private IEnumerator AutoSaveTimerCoroutine() { for (timerRunning = true; remainingTime > 0f; remainingTime -= Time.deltaTime) { yield return null; } timerRunning = false; } private void addStartingChecks(List<int> mapping, int startingId) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) (int, string, int, int, EItemType) valueOrEmpty = LicenseMapping.getValueOrEmpty(mapping[0]); for (int i = 0; i < 8; i++) { int num = LicenseMapping.GetKeyValueFromType(valueOrEmpty.Item5).Min((KeyValuePair<int, (int itemid, string name, int count, int locid, EItemType)> kvp) => kvp.Value.count); LicenseMapping.mapping.Add(startingCounter + i, (-1, "Unknown", (i + 3) * num, startingId + i, valueOrEmpty.Item5)); } startingCounter += 8; Plugin.Log($"Goal Amount for {valueOrEmpty.Item2} is {LicenseMapping.GetKeyValueFromType(valueOrEmpty.Item5).Count()}"); } public void sendDeath() { } public void connect(string ip, string password, string slot) { //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Expected O, but got Unknown APGui.state = "Connecting"; session = ArchipelagoSessionFactory.CreateSession(ip, 38281); IArchipelagoSocketHelper socket = session.Socket; object obj = <>c.<>9__22_0; if (obj == null) { SocketClosedHandler val = delegate { APGui.showGUI = true; }; <>c.<>9__22_0 = val; obj = (object)val; } socket.SocketClosed += (SocketClosedHandler)obj; session.Items.ItemReceived += (ItemReceivedHandler)delegate(ReceivedItemsHelper receivedItemsHelper) { if (!Plugin.isSceneLoaded()) { Plugin.Log("Not In Scene"); cachedItems.Enqueue(new ItemCache { info = receivedItemsHelper.DequeueItem(), index = receivedItemsHelper.Index }); } else { Plugin.Log($"{receivedItemsHelper.Index} : {Plugin.m_SaveManager.GetProcessedIndex()}"); if (Plugin.m_SaveManager.GetProcessedIndex() <= receivedItemsHelper.Index) { Plugin.m_SaveManager.IncreaseProcessedIndex(); ItemInfo itemReceived = receivedItemsHelper.DequeueItem(); Plugin.m_ItemHandler.processNewItem(itemReceived); if (receivedItemsHelper.Index % 25 == 0 && !timerRunning) { CSingleton<CGameManager>.Instance.SaveGameData(3); remainingTime += 60f; if (!timerRunning) { autoSaveCoroutine = ((MonoBehaviour)CoroutineRunner.Instance).StartCoroutine(AutoSaveTimerCoroutine()); } } } } }; try { result = session.TryConnectAndLogin("TCG Card Shop Simulator", slot, (ItemsHandlingFlags)7, (Version)null, (string[])null, (string)null, password, true); } catch (Exception ex) { APGui.state = "Connection Failed"; result = (LoginResult)new LoginFailure(ex.GetBaseException().Message); Plugin.Log(ex.GetBaseException().Message); } if (result.Successful) { Plugin.m_SaveManager.setSeed(session.RoomState.Seed); LoginSuccessful val2 = (LoginSuccessful)result; string text = val2.SlotData.GetValueOrDefault("ModVersion").ToString(); if (!text.Equals("0.1.0")) { APGui.state = "AP Expects Mod v" + text; } else { APGui.state = "Connected"; Plugin.RunTitleInteractableSaveLogic(); } slotData.CardSanity = int.Parse(val2.SlotData.GetValueOrDefault("CardSanity").ToString()); slotData.Goal = int.Parse(val2.SlotData.GetValueOrDefault("Goal").ToString()); slotData.ShopExpansionGoal = int.Parse(val2.SlotData.GetValueOrDefault("ShopExpansionGoal").ToString()); slotData.ShopExpansionGoal = int.Parse(val2.SlotData.GetValueOrDefault("ShopExpansionGoal").ToString()); slotData.LevelGoal = int.Parse(val2.SlotData.GetValueOrDefault("LevelGoal").ToString()); slotData.GhostGoalAmount = int.Parse(val2.SlotData.GetValueOrDefault("GhostGoalAmount").ToString()); slotData.TradesAreNew = val2.SlotData.GetValueOrDefault("BetterTrades").ToString() == "1"; slotData.FoilInSanity = val2.SlotData.GetValueOrDefault("FoilInSanity").ToString() == "1"; slotData.BorderInSanity = int.Parse(val2.SlotData.GetValueOrDefault("BorderInSanity").ToString()); slotData.SellCheckAmount = int.Parse(val2.SlotData.GetValueOrDefault("SellCheckAmount").ToString()); slotData.pg1IndexMapping = StrToList(val2.SlotData.GetValueOrDefault("ShopPg1Mapping").ToString()); Plugin.Log(string.Join(", ", slotData.pg1IndexMapping)); slotData.pg2IndexMapping = StrToList(val2.SlotData.GetValueOrDefault("ShopPg2Mapping").ToString()); Plugin.Log(string.Join(", ", slotData.pg2IndexMapping)); slotData.pg3IndexMapping = StrToList(val2.SlotData.GetValueOrDefault("ShopPg3Mapping").ToString()); Plugin.Log(string.Join(", ", slotData.pg3IndexMapping)); slotData.ttIndexMapping = StrToList(val2.SlotData.GetValueOrDefault("ShopTTMapping").ToString()); Plugin.Log(string.Join(", ", slotData.ttIndexMapping)); addStartingChecks(slotData.pg1IndexMapping, LicenseMapping.locs1Starting); Plugin.Log($"Mapping is {slotData.pg2IndexMapping.Count}"); addStartingChecks(slotData.pg2IndexMapping, LicenseMapping.locs2Starting); addStartingChecks(slotData.pg3IndexMapping, LicenseMapping.locs3Starting); Settings.Instance.SaveNewConnectionInfo(ip, password, slot); } } public void ProcessCachedItems() { CPlayerData.SetUnlockItemLicense(slotData.pg1IndexMapping[0]); CPlayerData.SetUnlockItemLicense(slotData.pg2IndexMapping[0]); CPlayerData.SetUnlockItemLicense(slotData.pg3IndexMapping[0]); while (cachedItems.Any()) { ItemCache itemCache = cachedItems.Dequeue(); Plugin.Log($"{Plugin.m_SaveManager.GetProcessedIndex()} : {itemCache.index}"); if (Plugin.m_SaveManager.GetProcessedIndex() > itemCache.index) { return; } Plugin.m_SaveManager.IncreaseProcessedIndex(); Plugin.Log("Item on load " + itemCache.info.ItemName); Plugin.m_ItemHandler.processNewItem(itemCache.info); } cachedItems.Clear(); } } public class Settings { private static Settings m_instance; private Plugin plugin; public ConfigEntry<int> StartingMoney; public ConfigEntry<int> XpMultiplier; public ConfigEntry<KeyCode> MyHotkey; public ConfigEntry<string> LastUsedIP; public ConfigEntry<string> LastUsedPassword; public ConfigEntry<string> LastUsedSlot; public static Settings Instance { get { if (m_instance == null) { m_instance = new Settings(); } return m_instance; } } public void Load(Plugin plugin) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown this.plugin = plugin; StartingMoney = ((BaseUnityPlugin)plugin).Config.Bind<int>("1. GamePlay", "Starting Money", 1000, new ConfigDescription("The Amount of Money you Start With", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, int.MaxValue), Array.Empty<object>())); MyHotkey = ((BaseUnityPlugin)plugin).Config.Bind<KeyCode>("2. Hotkeys", "Toggle Connection Window", (KeyCode)289, "Press this key to op AP Connection GUI"); LastUsedIP = ((BaseUnityPlugin)plugin).Config.Bind<string>("Connection", "LastUsedIP", "", "The last server IP entered."); LastUsedPassword = ((BaseUnityPlugin)plugin).Config.Bind<string>("Connection", "LastUsedPassword", "", "The last server password entered."); LastUsedSlot = ((BaseUnityPlugin)plugin).Config.Bind<string>("Connection", "LastUsedSlot", "", "The last player slot name entered."); } public void SaveNewConnectionInfo(string ip, string password, string slot) { LastUsedIP.Value = ip; LastUsedPassword.Value = password; LastUsedSlot.Value = slot; ((BaseUnityPlugin)plugin).Config.Save(); } } public static class MyPluginInfo { public const string PLUGIN_GUID = "ApClient"; public const string PLUGIN_NAME = "Ap Client For TCG Sim"; public const string PLUGIN_VERSION = "0.1.0"; } } namespace ApClient.patches { public class BillPatches { [HarmonyPatch(typeof(RentBillScreen))] public class NewDay { [HarmonyPatch("EvaluateNewDayBill")] [HarmonyPostfix] private static void PostFix(RentBillScreen __instance) { BillData bill = CPlayerData.GetBill((EBillType)1); BillData bill2 = CPlayerData.GetBill((EBillType)2); BillData bill3 = CPlayerData.GetBill((EBillType)3); bool flag = false; if (bill != null && __instance.m_DueDayMax - CPlayerData.GetBill((EBillType)1).billDayPassed <= 0) { flag = true; } if (bill2 != null && __instance.m_DueDayMax - CPlayerData.GetBill((EBillType)2).billDayPassed <= 0) { flag = true; } if (bill3 != null && __instance.m_DueDayMax - CPlayerData.GetBill((EBillType)3).billDayPassed <= 0) { flag = true; } if (flag) { Plugin.m_SessionHandler.sendDeath(); } } } } public class CardOpeningPatches { [HarmonyPatch(typeof(CardOpeningSequence), "GetPackContent")] private class Patch_TargetMethod { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Expected O, but got Unknown //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Expected O, but got Unknown //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Expected O, but got Unknown //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Expected O, but got Unknown //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Expected O, but got Unknown //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); Dictionary<float, float> dictionary = new Dictionary<float, float> { { 5f, 0.5f }, { 20f, 0.25f }, { 8f, 0.2f }, { 4f, 0.1f }, { 1f, 0.05f }, { 0.25f, 0.05f } }; HashSet<float> hashSet = new HashSet<float>(); MethodInfo methodInfo = AccessTools.Method(typeof(Plugin), "getNumLuckItems", (Type[])null, (Type[])null); for (int i = 0; i < list.Count - 1; i++) { CodeInstruction val = list[i]; if (val.opcode == OpCodes.Ldc_R4 && dictionary.TryGetValue((float)val.operand, out var value)) { float item = (float)val.operand; if (!hashSet.Contains(item) && list[i + 1].opcode.Name.StartsWith("stloc")) { object operand = list[i + 1].operand; list.InsertRange(i + 2, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[6] { new CodeInstruction(OpCodes.Ldloc, operand), new CodeInstruction(OpCodes.Call, (object)methodInfo), new CodeInstruction(OpCodes.Ldc_R4, (object)value), new CodeInstruction(OpCodes.Mul, (object)null), new CodeInstruction(OpCodes.Add, (object)null), new CodeInstruction(OpCodes.Stloc, operand) }); hashSet.Add(item); i += 6; } } } return list; } } } public class CustomerPatches { [HarmonyPatch(typeof(Customer), "EvaluateFinishScanItem")] public static class FinishScan { [HarmonyPostfix] public static void Postfix(Customer __instance) { if (Plugin.isCashOnly()) { __instance.m_CustomerCash.SetIsCard(false); CSingleton<CustomerManager>.Instance.ResetCustomerExactChangeChance(); __instance.m_CurrentQueueCashierCounter.SetCustomerPaidAmount(false, __instance.GetRandomPayAmount(__instance.m_TotalScannedItemCost)); } } } [HarmonyPatch(typeof(Customer), "OnItemScanned")] public static class OnScan { [HarmonyPostfix] public static void Postfix(Item item) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected I4, but got Unknown //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected I4, but got Unknown //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) CPlayerData.m_StockSoldList[(int)item.GetItemType()]++; Plugin.Log($"{item} has sold {CPlayerData.m_StockSoldList[(int)item.GetItemType()]} times"); IEnumerable<KeyValuePair<int, (int, string, int, int, EItemType)>> enumerable = from i in LicenseMapping.GetKeyValueFromType(item.GetItemType()) where i.Value.count <= CPlayerData.m_StockSoldList[(int)item.GetItemType()] select i; foreach (KeyValuePair<int, (int, string, int, int, EItemType)> item2 in enumerable) { Plugin.Log($"{item.GetItemType()} has {enumerable.Count()} goals left"); Plugin.m_SessionHandler.CompleteLocationChecks(item2.Value.Item4); } } } [HarmonyPatch(typeof(Customer), "ActivateCustomer")] public static class Activate { [HarmonyPostfix] public static void Postfix(Customer __instance, bool canSpawnSmelly) { float maxMoney = __instance.m_MaxMoney; __instance.m_MaxMoney *= Plugin.m_SaveManager.GetMoneyMult(); Plugin.Log($"Customer spawned with {__instance.m_MaxMoney} instead of {maxMoney}"); } } [HarmonyPatch(typeof(CustomerTradeCardScreen), "SetCustomer")] public static class CustomerTradeScreen_SetCustomer_Transpiler { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator il) { FieldInfo field_CardDataL = AccessTools.Field(typeof(CustomerTradeCardScreen), "m_CardData_L"); MethodInfo originalGetCardData = AccessTools.Method(typeof(CPlayerData), "GetCardData", new Type[3] { typeof(int), typeof(ECardExpansionType), typeof(bool) }, (Type[])null); MethodInfo myCustomMethod = AccessTools.Method(typeof(Plugin), "getNewCard", (Type[])null, (Type[])null); MethodInfo controlTradesMethod = AccessTools.Method(typeof(Plugin), "OverrideTrades", (Type[])null, (Type[])null); List<CodeInstruction> codes = new List<CodeInstruction>(instructions); Label skipCustom = il.DefineLabel(); Label endIf = il.DefineLabel(); bool patchApplied = false; for (int i = 0; i < codes.Count; i++) { CodeInstruction code = codes[i]; int num; if (!patchApplied && code.opcode == OpCodes.Call) { object operand = code.operand; if (operand is MethodInfo mi) { num = ((mi == originalGetCardData) ? 1 : 0); goto IL_0193; } } num = 0; goto IL_0193; IL_0193: if (num != 0) { List<CodeInstruction> newInstructions = new List<CodeInstruction> { new CodeInstruction(OpCodes.Ldarg_2, (object)null), new CodeInstruction(OpCodes.Ldnull, (object)null), new CodeInstruction(OpCodes.Ceq, (object)null), new CodeInstruction(OpCodes.Brfalse_S, (object)skipCustom), new CodeInstruction(OpCodes.Call, (object)controlTradesMethod), new CodeInstruction(OpCodes.Ldc_I4_0, (object)null), new CodeInstruction(OpCodes.Ceq, (object)null), new CodeInstruction(OpCodes.Brtrue_S, (object)skipCustom), new CodeInstruction(OpCodes.Pop, (object)null), new CodeInstruction(OpCodes.Pop, (object)null), new CodeInstruction(OpCodes.Pop, (object)null), new CodeInstruction(OpCodes.Call, (object)myCustomMethod), new CodeInstruction(OpCodes.Br_S, (object)endIf) }; CodeInstruction labelOriginal = new CodeInstruction(OpCodes.Nop, (object)null) { labels = new List<Label> { skipCustom } }; newInstructions.Add(labelOriginal); foreach (CodeInstruction item in newInstructions) { yield return item; } yield return code; patchApplied = true; continue; } int num2; if (patchApplied && code.opcode == OpCodes.Stfld) { object operand = code.operand; if (operand is FieldInfo field) { num2 = ((field == field_CardDataL) ? 1 : 0); goto IL_042c; } } num2 = 0; goto IL_042c; IL_042c: if (num2 != 0) { code.labels.Add(endIf); yield return code; patchApplied = false; } else { yield return code; } } } } } public class EmployeePatches { [HarmonyPatch(typeof(HireWorkerPanelUI), "Init")] public class Init { private static void Postfix(HireWorkerPanelUI __instance, HireWorkerScreen hireWorkerScreen, int index) { Plugin.Log($"Employee Index: {index}"); (int, string, int) valueOrDefault = EmployeeMapping.mapping.GetValueOrDefault(index, (-1, "", -1)); ((TMP_Text)__instance.m_LevelRequirementText).text = "Requires AP Worker Unlock"; if (valueOrDefault.Item3 != -1 && Plugin.m_SessionHandler.hasItem(valueOrDefault.Item1)) { ((Component)__instance.m_LevelRequirementText).gameObject.SetActive(false); ((Component)__instance.m_HireFeeText).gameObject.SetActive(true); __instance.m_LockPurchaseBtn.SetActive(false); } else { ((Component)__instance.m_LevelRequirementText).gameObject.SetActive(true); ((Component)__instance.m_HireFeeText).gameObject.SetActive(false); __instance.m_LockPurchaseBtn.gameObject.SetActive(true); } } } [HarmonyPatch(typeof(HireWorkerPanelUI), "OnPressHireButton")] public class OnClick { private static bool Prefix(HireWorkerPanelUI __instance) { FieldInfo field = typeof(HireWorkerPanelUI).GetField("m_Index", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) { return false; } int num = (int)field.GetValue(__instance); (int, string, int) valueOrDefault = EmployeeMapping.mapping.GetValueOrDefault(num, (-1, "", -1)); Plugin.Log($"at employee hire {valueOrDefault.Item2} {valueOrDefault.Item1} {valueOrDefault.Item3 != -1 && Plugin.m_SessionHandler.hasItem(valueOrDefault.Item1)}"); if (valueOrDefault.Item3 != -1 && Plugin.m_SessionHandler.hasItem(valueOrDefault.Item1)) { HireEmployee(__instance, num); } return true; } } public static void HireEmployee(HireWorkerPanelUI __instance, int index) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown if (CPlayerData.GetIsWorkerHired(index)) { return; } FieldInfo field = typeof(HireWorkerPanelUI).GetField("m_TotalHireFee", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) { return; } float num = (float)field.GetValue(__instance); CEventManager.QueueEvent((CEvent)new CEventPlayer_ReduceCoin(num, false)); CPlayerData.SetIsWorkerHired(index, true); CSingleton<WorkerManager>.Instance.ActivateWorker(index, true); CPlayerData.m_GameReportDataCollect.employeeCost -= num; CPlayerData.m_GameReportDataCollectPermanent.employeeCost -= num; int num2 = 0; for (int i = 0; i < CPlayerData.m_IsWorkerHired.Count; i++) { if (CPlayerData.m_IsWorkerHired[i]) { num2++; } } FieldInfo field2 = typeof(HireWorkerPanelUI).GetField("m_IsHired", BindingFlags.Instance | BindingFlags.NonPublic); if (!(field2 == null)) { AchievementManager.OnStaffHired(num2); SoundManager.PlayAudio("SFX_CustomerBuy", 0.6f, 1f); field2.SetValue(__instance, CPlayerData.GetIsWorkerHired(index)); if (CPlayerData.GetIsWorkerHired(index)) { __instance.m_HiredText.SetActive(true); __instance.m_PurchaseBtn.SetActive(false); ((Component)__instance.m_HireFeeText).gameObject.SetActive(false); } else { __instance.m_HiredText.SetActive(false); __instance.m_PurchaseBtn.SetActive(true); } } } } public class ExpansionShopPatches { [HarmonyPatch(typeof(ExpansionShopPanelUI), "Init")] public class Init { [HarmonyPostfix] private static void Postfix(ExpansionShopPanelUI __instance, ExpansionShopUIScreen expansionShopUIScreen, int index, bool isShopB) { FieldInfo field = typeof(ExpansionShopPanelUI).GetField("m_LevelRequired", BindingFlags.Instance | BindingFlags.NonPublic); if (!(field == null)) { int num = (int)field.GetValue(__instance); bool flag = false; flag = ((!isShopB) ? (Plugin.m_SessionHandler.itemCount(ExpansionMapping.progressiveA) > index) : (Plugin.m_SessionHandler.itemCount(ExpansionMapping.progressiveB) > index)); bool flag2 = CPlayerData.m_ShopLevel + 1 >= num; if (!flag && flag2) { ((Component)__instance.m_LevelRequirementText).gameObject.SetActive(true); ((TMP_Text)__instance.m_LevelRequirementText).text = "Needs Progressive Shop Expansion " + (isShopB ? "B" : "A"); } else if (!flag) { ((TMP_Text)__instance.m_LevelRequirementText).text = ((TMP_Text)__instance.m_LevelRequirementText).text + " and AP Progressive " + (isShopB ? "B" : "A"); } if (isShopB && CPlayerData.m_UnlockWarehouseRoomCount > index) { __instance.m_LockPurchaseBtn.gameObject.SetActive(false); __instance.m_PurchasedBtn.gameObject.SetActive(true); } else if (!isShopB && CPlayerData.m_UnlockRoomCount > index) { __instance.m_LockPurchaseBtn.gameObject.SetActive(false); __instance.m_PurchasedBtn.gameObject.SetActive(true); } else if (flag && flag2) { __instance.m_LockPurchaseBtn.gameObject.SetActive(false); __instance.m_PurchasedBtn.gameObject.SetActive(false); } else { __instance.m_LockPurchaseBtn.gameObject.SetActive(true); __instance.m_PurchasedBtn.gameObject.SetActive(false); } } } } [HarmonyPatch(typeof(ExpansionShopPanelUI), "OnPressButton")] public class OnClick { private static bool Prefix(ExpansionShopPanelUI __instance) { FieldInfo field = typeof(ExpansionShopPanelUI).GetField("m_Index", BindingFlags.Instance | BindingFlags.NonPublic); int num = (int)field.GetValue(__instance); FieldInfo field2 = typeof(ExpansionShopPanelUI).GetField("m_LevelRequired", BindingFlags.Instance | BindingFlags.NonPublic); int num2 = (int)field2.GetValue(__instance); FieldInfo fieldInfo = AccessTools.Field(typeof(ExpansionShopPanelUI), "m_IsShopB"); bool flag = (bool)fieldInfo.GetValue(__instance); bool flag2 = false; flag2 = ((!flag) ? (Plugin.m_SessionHandler.itemCount(ExpansionMapping.progressiveA) > num) : (Plugin.m_SessionHandler.itemCount(ExpansionMapping.progressiveB) > num)); bool flag3 = CPlayerData.m_ShopLevel + 1 >= num2; if (flag2 && flag3) { return true; } return false; } } [HarmonyPatch] private class CreateData { private static MethodBase TargetMethod() { return AccessTools.Method(typeof(ExpansionShopUIScreen), "EvaluateCartCheckout", (Type[])null, (Type[])null); } [HarmonyPrefix] public static void Prefix(float totalCost, int index, bool isShopB) { Plugin.m_SessionHandler.CompleteLocationChecks(ExpansionMapping.locstartval + index + (isShopB ? 30 : 0)); if (!isShopB && Plugin.m_SessionHandler.GetSlotData().Goal == 0 && index + 1 >= Plugin.m_SessionHandler.GetSlotData().ShopExpansionGoal) { Plugin.m_SessionHandler.SendGoalCompletion(); PopupTextPatches.ShowCustomText("Congrats! Your Shop Has Expanded To Your Goal!"); } Plugin.Log("Prefix executed on EvaluateCartCheckout for Expansion"); } } [HarmonyPatch] private class PanelUI { private static MethodBase TargetMethod() { return AccessTools.Method(typeof(ExpansionShopUIScreen), "EvaluateShopPanelUI", (Type[])null, (Type[])null); } [HarmonyPostfix] public static void Postfix(ExpansionShopUIScreen __instance) { if (__instance.m_IsShopB && !CPlayerData.m_IsWarehouseRoomUnlocked) { ((Behaviour)__instance.m_ShopB_LevelRequirementText).enabled = true; ((TMP_Text)__instance.m_ShopB_LevelRequirementText).text = "Needs AP Warehouse Key"; __instance.m_ShopB_LockPurchaseBtn.SetActive(true); } } } } public class FurnaturePatches { [HarmonyPatch(typeof(FurnitureShopPanelUI), "Init")] public class Init { [HarmonyPrefix] private static void Prefix(FurnitureShopPanelUI __instance, FurnitureShopUIScreen furnitureShopUIScreen, int index) { __instance.m_Index = FurnatureMapping.reorder[index]; } [HarmonyPostfix] private static void Postfix(FurnitureShopPanelUI __instance, FurnitureShopUIScreen furnitureShopUIScreen, int index) { if (index != 0) { (int, string, int) valueOrEmpty = FurnatureMapping.getValueOrEmpty(__instance.m_Index); if (valueOrEmpty.Item1 == -1) { Plugin.Log($"Failed to find index: {__instance.m_Index}"); return; } bool hasItem = Plugin.m_SessionHandler.itemCount(valueOrEmpty.Item1) >= valueOrEmpty.Item3; runFurnatureBtnLogic(__instance, hasItem, __instance.m_Index); } } } [HarmonyPatch(typeof(FurnitureShopPanelUI), "OnPressButton")] public class OnClick { private static bool Prefix(FurnitureShopPanelUI __instance) { FieldInfo field = typeof(FurnitureShopPanelUI).GetField("m_Index", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) { return false; } int num = (int)field.GetValue(__instance); if (((TMP_Text)__instance.m_LevelRequirementText).text.Equals("License Locked by AP")) { return false; } return true; } } public static void runFurnatureBtnLogic(FurnitureShopPanelUI __instance, bool hasItem, int index) { if (!hasItem) { ((TMP_Text)__instance.m_LevelRequirementText).text = "License Locked by AP"; ((Component)__instance.m_LevelRequirementText).gameObject.SetActive(true); __instance.m_CompanyTitle.gameObject.SetActive(false); __instance.m_LockPurchaseBtn.gameObject.SetActive(true); } else { EnableFurnature(__instance, index); ((TMP_Text)__instance.m_LevelRequirementText).text = ""; } } public static void EnableFurnature(FurnitureShopPanelUI __instance, int index) { FieldInfo field = typeof(FurnitureShopPanelUI).GetField("m_LevelRequired", BindingFlags.Instance | BindingFlags.NonPublic); if (!(field == null)) { int num = (int)field.GetValue(__instance); field.SetValue(__instance, 1); ((Component)__instance.m_LevelRequirementText).gameObject.SetActive(false); __instance.m_CompanyTitle.gameObject.SetActive(true); __instance.m_LockPurchaseBtn.gameObject.SetActive(false); } } } [HarmonyPatch(typeof(CGameManager))] public class CGameManagerPatches { [HarmonyPatch("LoadData")] [HarmonyPostfix] private static void PostFix() { CPlayerData.m_TutorialIndex = 16; if (CPlayerData.PlayerName != "My Card Shop" || CPlayerData.m_TutorialIndex > 0) { CSingleton<TutorialManager>.Instance.m_TutorialTargetIndicator.SetActive(false); ((Component)CSingleton<TutorialManager>.Instance).gameObject.SetActive(false); CPlayerData.m_HasFinishedTutorial = true; } Plugin.Log("Processing cache Items"); Plugin.onSceneLoadLogic(); } } public class OpenCloseSignPatches { [HarmonyPatch(typeof(InteractableOpenCloseSign))] public class OverrideTutorialCheck { [HarmonyPatch("OnMouseButtonUp")] [HarmonyPrefix] private static bool Prefix(InteractableOpenCloseSign __instance) { if (!__instance.m_IsSwapping) { CPlayerData.m_IsShopOpen = !CPlayerData.m_IsShopOpen; if (!CPlayerData.m_IsShopOnceOpen && CPlayerData.m_IsShopOpen) { CPlayerData.m_IsShopOnceOpen = true; } __instance.m_IsSwapping = true; __instance.m_Anim.Play(); ((MonoBehaviour)__instance).StartCoroutine(__instance.DelaySwapMesh()); SoundManager.GenericPop(1f, 1f); } return false; } } } [HarmonyPatch(typeof(PauseScreen))] public class PauseScreenPatches { [HarmonyPatch("OpenSaveGameSlotScreen")] [HarmonyPrefix] private static bool SavePrefix() { Plugin.Log("Start Saving"); CSingleton<CGameManager>.Instance.m_CurrentSaveLoadSlotSelectedIndex = 3; CSingleton<CGameManager>.Instance.m_IsManualSaveLoad = true; CSingleton<ShelfManager>.Instance.SaveInteractableObjectData(false); CSingleton<CGameManager>.Instance.SaveGameData(3); SaveLoadGameSlotSelectScreen val = Object.FindObjectOfType<SaveLoadGameSlotSelectScreen>(); if ((Object)(object)val != (Object)null) { Plugin.Log("Screen Saving"); val.m_SavingGameScreen.SetActive(true); ((MonoBehaviour)CSingleton<SaveLoadGameSlotSelectScreen>.Instance).StartCoroutine(DelaySavingGame(val)); } return true; } private static IEnumerator DelaySavingGame(SaveLoadGameSlotSelectScreen saveScreen) { Plugin.Log("Delay Saving"); yield return (object)new WaitForSecondsRealtime(2f); saveScreen.m_SavingGameScreen.SetActive(false); ((Component)saveScreen).gameObject.SetActive(false); } } internal class PlayerDataPatches { [HarmonyPatch] private class CreateData { private static MethodBase TargetMethod() { return AccessTools.Method(typeof(CPlayerData), "CreateDefaultData", (Type[])null, (Type[])null); } [HarmonyPostfix] public static void Postfix(CPlayerData __instance) { Plugin.Log("Postfix executed on CreateDefaultData"); CPlayerData.m_IsItemLicenseUnlocked[0] = false; Plugin.m_SaveManager.setIncompleteCards(GetValidTypeIdsForSanity()); } } [HarmonyPatch] private class AddXp { private static int oldLevel; private static MethodBase TargetMethod() { return AccessTools.Method(typeof(CPlayerData), "CPlayer_OnAddShopExp", (Type[])null, (Type[])null); } [HarmonyPrefix] private static void Prefix(CEventPlayer_AddShopExp evt) { oldLevel = CPlayerData.m_ShopLevel; } [HarmonyPostfix] private static void Postfix(CEventPlayer_AddShopExp evt) { if (oldLevel < CPlayerData.m_ShopLevel && CPlayerData.m_ShopLevel + 1 >= 2) { Plugin.Log($"Level Up: {oldLevel + 1} -> {CPlayerData.m_ShopLevel + 1}"); Plugin.m_SessionHandler.CompleteLocationChecks(LevelMapping.startValue + CPlayerData.m_ShopLevel); if (Plugin.m_SessionHandler.GetSlotData().Goal == 1 && CPlayerData.m_ShopLevel + 1 >= Plugin.m_SessionHandler.GetSlotData().LevelGoal) { Plugin.m_SessionHandler.SendGoalCompletion(); PopupTextPatches.ShowCustomText("Congrats! Your Shop Has Leveled To Your Goal!"); } } } } [HarmonyPatch] private class AddLicense { private static MethodBase TargetMethod() { Type typeFromHandle = typeof(CPlayerData); MethodInfo method = typeFromHandle.GetMethod("SetUnlockItemLicense", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { Plugin.Log("Static method 'SetUnlockItemLicense' not found!"); } return method; } private static void Prefix(int index) { } private static void Postfix(int index) { } } [HarmonyPatch] private class AddCard { private static MethodBase TargetMethod() { Type typeFromHandle = typeof(CPlayerData); MethodInfo method = typeFromHandle.GetMethod("AddCard", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { Plugin.Log("Static method 'AddCard' not found!"); } return method; } private static void Prefix(CardData cardData, int addAmount) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Invalid comparison between Unknown and I4 //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Invalid comparison between Unknown and I4 if (Plugin.m_SessionHandler.GetSlotData().CardSanity != 0) { ECollectionPackType val = (ECollectionPackType)AccessTools.Field(typeof(CardOpeningSequence), "m_CollectionPackType").GetValue(CSingleton<CardOpeningSequence>.Instance); if ((int)val < Plugin.m_SessionHandler.GetSlotData().CardSanity && CPlayerData.GetCardAmount(cardData) == 0 && (int)cardData.borderType <= Plugin.m_SessionHandler.GetSlotData().BorderInSanity && (!cardData.isFoil || Plugin.m_SessionHandler.GetSlotData().FoilInSanity)) { Plugin.m_SessionHandler.CompleteLocationChecks(CardMapping.getId(cardData)); } } } private static void Postfix(CardData cardData, int addAmount) { } } public static List<int> GetValidTypeIdsForSanity() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected I4, but got Unknown //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Invalid comparison between Unknown and I4 //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Invalid comparison between Unknown and I4 //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Invalid comparison between Unknown and I4 //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Invalid comparison between Unknown and I4 //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Invalid comparison between Unknown and I4 //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Invalid comparison between Unknown and I4 //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Invalid comparison between Unknown and I4 //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Invalid comparison between Unknown and I4 //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Expected I4, but got Unknown //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Expected I4, but got Unknown //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Expected I4, but got Unknown //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Expected I4, but got Unknown if (Plugin.m_SessionHandler.GetSlotData().CardSanity == 0) { return Enumerable.Range(1, 121).ToList(); } HashSet<int> hashSet = new HashSet<int>(); ECardExpansionType[] array = (ECardExpansionType[])(object)new ECardExpansionType[2] { default(ECardExpansionType), (ECardExpansionType)1 }; ECardExpansionType[] array2 = array; foreach (ECardExpansionType val in array2) { for (int j = 0; j < InventoryBase.GetShownMonsterList(val).Count; j++) { EMonsterType monsterType = InventoryBase.GetMonsterData(InventoryBase.GetShownMonsterList(val)[j]).MonsterType; ERarity rarity = InventoryBase.GetMonsterData(InventoryBase.GetShownMonsterList(val)[j]).Rarity; ERarity val2 = rarity; ERarity val3 = val2; switch (val3 - 1) { case 2: if ((Plugin.m_SessionHandler.GetSlotData().CardSanity >= 8 && (int)val == 1) || (Plugin.m_SessionHandler.GetSlotData().CardSanity >= 4 && (int)val == 0)) { hashSet.Add((int)monsterType); } break; case 1: if ((Plugin.m_SessionHandler.GetSlotData().CardSanity >= 7 && (int)val == 1) || (Plugin.m_SessionHandler.GetSlotData().CardSanity >= 3 && (int)val == 0)) { hashSet.Add((int)monsterType); } break; case 0: if ((Plugin.m_SessionHandler.GetSlotData().CardSanity >= 6 && (int)val == 1) || (Plugin.m_SessionHandler.GetSlotData().CardSanity >= 2 && (int)val == 0)) { hashSet.Add((int)monsterType); } break; default: if ((Plugin.m_SessionHandler.GetSlotData().CardSanity >= 5 && (int)val == 1) || (Plugin.m_SessionHandler.GetSlotData().CardSanity >= 1 && (int)val == 0)) { hashSet.Add((int)monsterType); } break; } } } return hashSet.ToList(); } } public class PopupTextPatches { [HarmonyPatch] public class ShowText { private static MethodBase TargetMethod() { Type typeFromHandle = typeof(NotEnoughResourceTextPopup); MethodInfo method = typeFromHandle.GetMethod("ShowText", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { Plugin.Log("Static method 'ShowText' not found!"); } return method; } private static void Prefix(ENotEnoughResourceText notEnoughResourceText) { currentText = ((object)(ENotEnoughResourceText)(ref notEnoughResourceText)).ToString(); } } private static string currentText; public static void ShowCustomText(string notEnoughResourceText) { if (currentText == notEnoughResourceText) { return; } CSingleton<NotEnoughResourceTextPopup>.Instance.m_ResetTimer = 0f; currentText = notEnoughResourceText; for (int i = 0; i < CSingleton<NotEnoughResourceTextPopup>.Instance.m_ShowTextGameObjectList.Count; i++) { if (!CSingleton<NotEnoughResourceTextPopup>.Instance.m_ShowTextGameObjectList[i].activeSelf) { ((TMP_Text)CSingleton<NotEnoughResourceTextPopup>.Instance.m_ShowTextList[i]).text = notEnoughResourceText; CSingleton<NotEnoughResourceTextPopup>.Instance.m_ShowTextGameObjectList[i].gameObject.SetActive(true); break; } } } } public class RestockItemPanelUIPatches { [HarmonyPatch(typeof(RestockItemPanelUI), "Init")] public class Init { [HarmonyPrefix] private static void Prefix(RestockItemPanelUI __instance, RestockItemScreen restockItemScreen, ref int index) { } [HarmonyPostfix] private static void Postfix(RestockItemPanelUI __instance, RestockItemScreen restockItemScreen, int index) { List<EItemType> list = new List<EItemType>(); List<int> list2 = new List<int>(); int[] array = LicenseMapping.pg1_ids; switch (restockItemScreen.m_PageIndex) { case 0: list = CSingleton<InventoryBase>.Instance.m_StockItemData_SO.m_ShownItemType; list2 = Plugin.m_SessionHandler.GetSlotData().pg1IndexMapping; array = LicenseMapping.pg1_ids; break; case 1: list = CSingleton<InventoryBase>.Instance.m_StockItemData_SO.m_ShownAccessoryItemType; list2 = Plugin.m_SessionHandler.GetSlotData().pg2IndexMapping; array = LicenseMapping.pg2_ids; break; case 2: list = CSingleton<InventoryBase>.Instance.m_StockItemData_SO.m_ShownFigurineItemType; list2 = Plugin.m_SessionHandler.GetSlotData().pg3IndexMapping; array = LicenseMapping.pg3_ids; break; } if (restockItemScreen is RestockItemBoardGameScreen) { list = CSingleton<InventoryBase>.Instance.m_StockItemData_SO.m_ShownBoardGameItemType; list2 = Plugin.m_SessionHandler.GetSlotData().ttIndexMapping; array = LicenseMapping.tt_ids; if (index == -1) { return; } } else if (restockItemScreen.m_SortedRestockDataIndexList.IndexOf(index) == -1) { return; } RestockData restockData = InventoryBase.GetRestockData(array[list2.IndexOf(index)]); __instance.m_LevelRequired = restockData.licenseShopLevelRequired; ((TMP_Text)__instance.m_LicensePriceText).text = GameInstance.GetPriceString(0f, false, true, false, "F2"); if (index == Plugin.m_SessionHandler.GetSlotData().pg1IndexMapping[0]) { __instance.m_LevelRequired = 0; } if (index == Plugin.m_SessionHandler.GetSlotData().pg2IndexMapping[0]) { __instance.m_LevelRequired = 0; } if (index == Plugin.m_SessionHandler.GetSlotData().pg3IndexMapping[0]) { __instance.m_LevelRequired = 0; } (int, string, int, int, EItemType) valueOrEmpty = LicenseMapping.getValueOrEmpty(index); if (valueOrEmpty.Item4 == -1) { Plugin.Log($"Failed to find index: {index}"); } else { runLicenseBtnLogic(__instance, Plugin.m_SessionHandler.hasItem(valueOrEmpty.Item1), index); } } } [HarmonyPatch(typeof(RestockItemPanelUI), "OnPressPurchaseButton")] public class OnClick { private static bool Prefix(RestockItemPanelUI __instance) { if (Plugin.m_SessionHandler.hasItem(LicenseMapping.getValueOrEmpty(__instance.m_Index).itemid)) { return true; } PopupTextPatches.ShowCustomText("License Unowned"); return false; } } [HarmonyPatch(typeof(RestockItemScreen), "Init")] public class InitScreen { [HarmonyPrefix] public static void Prefix(RestockItemScreen __instance) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) CPlayerData.m_RestockSortingType = (ERestockSortingType)0; } } [HarmonyPatch(typeof(RestockItemScreen), "OnPressChangePageButton")] public class OnPressChangePageButton { [HarmonyPrefix] public static void Prefix(RestockItemScreen __instance) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) __instance.m_CurrentSortingMethod = (ERestockSortingType)0; } } [HarmonyPatch(typeof(RestockItemScreen), "EvaluateSorting")] public class Sorting { [HarmonyPrefix] public static void Prefix(RestockItemScreen __instance) { switch (__instance.m_PageIndex) { case 0: __instance.m_CurrentRestockDataIndexList.Clear(); __instance.m_CurrentRestockDataIndexList.AddRange(Plugin.m_SessionHandler.GetSlotData().pg1IndexMapping); break; case 1: __instance.m_CurrentRestockDataIndexList.Clear(); __instance.m_CurrentRestockDataIndexList.AddRange(Plugin.m_SessionHandler.GetSlotData().pg2IndexMapping); break; case 2: __instance.m_CurrentRestockDataIndexList.Clear(); __instance.m_CurrentRestockDataIndexList.AddRange(Plugin.m_SessionHandler.GetSlotData().pg3IndexMapping); break; } Plugin.Log("new"); Plugin.Log(string.Join(", ", __instance.m_CurrentRestockDataIndexList)); } } public static void runLicenseBtnLogic(RestockItemPanelUI __instance, bool hasItem, int index) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Expected I4, but got Unknown //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Expected I4, but got Unknown //IL_0186: Unknown result type (might be due to invalid IL or missing references) Plugin.Log($"Item Data: {index} : {__instance.m_LevelRequired}"); if (hasItem && CPlayerData.m_ShopLevel + 1 >= __instance.m_LevelRequired) { ((UIElementBase)__instance).m_UIGrp.SetActive(true); __instance.m_LicenseUIGrp.SetActive(false); __instance.m_LockPurchaseBtn.gameObject.SetActive(false); EItemType type = InventoryBase.GetRestockData(index).itemType; IEnumerable<KeyValuePair<int, (int, string, int, int, EItemType)>> source = from i in LicenseMapping.GetKeyValueFromType(type) where i.Value.count > CPlayerData.m_StockSoldList[(int)type] select i; if (source.Any()) { RectTransform val = ((IEnumerable<RectTransform>)((UIElementBase)__instance).m_UIGrp.GetComponentsInChildren<RectTransform>(true)).FirstOrDefault((Func<RectTransform, bool>)((RectTransform rt) => ((Object)rt).name == "UnitPriceText")); if ((Object)(object)val != (Object)null) { Localize component = ((Component)val).GetComponent<Localize>(); if ((Object)(object)component != (Object)null) { component.SetTerm("Sold Check Progress"); } } ((TMP_Text)__instance.m_UnitPriceText).text = $"{CPlayerData.m_StockSoldList[(int)type]}/{source.OrderBy<KeyValuePair<int, (int, string, int, int, EItemType)>, int>((KeyValuePair<int, (int itemid, string name, int count, int locid, EItemType)> x) => x.Value.count).FirstOrDefault().Value.Item3}"; ((Graphic)__instance.m_UnitPriceText).color = Color.blue; return; } RectTransform val2 = ((IEnumerable<RectTransform>)((UIElementBase)__instance).m_UIGrp.GetComponentsInChildren<RectTransform>(true)).FirstOrDefault((Func<RectTransform, bool>)((RectTransform rt) => ((Object)rt).name == "UnitPriceText")); if ((Object)(object)val2 != (Object)null) { Localize component2 = ((Component)val2).GetComponent<Localize>(); if ((Object)(object)component2 != (Object)null) { component2.SetTerm("Checks Completed. Total Sold:"); } } ((TMP_Text)__instance.m_UnitPriceText).text = $"{CPlayerData.m_StockSoldList[(int)type]}"; ((Graphic)__instance.m_UnitPriceText).color = Color.green; } else if (hasItem) { ((UIElementBase)__instance).m_UIGrp.SetActive(false); __instance.m_LicenseUIGrp.SetActive(true); __instance.m_LockPurchaseBtn.gameObject.SetActive(true); ((TMP_Text)__instance.m_LevelRequirementText).text = $"Level {__instance.m_LevelRequired} Required. License Found"; ((Component)__instance.m_LevelRequirementText).gameObject.SetActive(true); } else if (CPlayerData.m_ShopLevel + 1 >= __instance.m_LevelRequired) { ((UIElementBase)__instance).m_UIGrp.SetActive(false); __instance.m_LockPurchaseBtn.gameObject.SetActive(true); __instance.m_LicenseUIGrp.SetActive(true); ((Component)__instance.m_LevelRequirementText).gameObject.SetActive(true); ((TMP_Text)__instance.m_LevelRequirementText).text = "Level Reached, License Locked by AP"; } else { ((UIElementBase)__instance).m_UIGrp.SetActive(false); __instance.m_LicenseUIGrp.SetActive(true); __instance.m_LockPurchaseBtn.gameObject.SetActive(true); ((TMP_Text)__instance.m_LevelRequirementText).text = $"Level {__instance.m_LevelRequired} Required. License Locked by AP"; ((Component)__instance.m_LevelRequirementText).gameObject.SetActive(true); } } } public class SaveLoadPatches { [HarmonyPatch] public class SavePatch { private static MethodBase TargetMethod() { Type typeFromHandle = typeof(CSaveLoad); MethodInfo method = typeFromHandle.GetMethod("Save", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { Plugin.Log("Static method 'Save' not found!"); } return method; } [HarmonyPrefix] private static bool SavePrefix(int saveSlotIndex, bool skipJSONSave = false) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown Plugin.m_SaveManager.Save(saveSlotIndex); CEventManager.QueueEvent((CEvent)new CEventPlayer_OnSaveStatusUpdated(true, false)); return false; } } [HarmonyPatch] public class LoadPatch { private static MethodBase TargetMethod() { Type typeFromHandle = typeof(CSaveLoad); MethodInfo method = typeFromHandle.GetMethod("Load", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { Plugin.Log("Static method 'Load' not found!"); } return method; } [HarmonyPrefix] private static bool LoadPrefix(ref bool __result, int slotIndex) { Plugin.Log("Loading AP save data"); if (!Plugin.m_SaveManager.Load()) { Plugin.Log("Cannot load Saves for AP Client"); __result = false; } __result = true; return false; } } } [HarmonyPatch(typeof(RestockItemBoardGameScreen))] [HarmonyPatch("EvaluateRestockItemPanelUI")] public class TableTopPatches { [HarmonyPrefix] private static bool Prefix(RestockItemBoardGameScreen __instance, int pageIndex) { ((RestockItemScreen)__instance).m_CurrentRestockDataIndexList.Clear(); ((RestockItemScreen)__instance).m_CurrentRestockDataIndexList.AddRange(Plugin.m_SessionHandler.GetSlotData().ttIndexMapping); ((RestockItemScreen)__instance).m_CurrentRestockDataIndexList.AddRange(new <>z__ReadOnlyArray<int>(new int[3] { -1, -1, -1 })); for (int i = 0; i < ((RestockItemScreen)__instance).m_CurrentRestockDataIndexList.Count && i < ((RestockItemScreen)__instance).m_RestockItemPanelUIList.Count; i++) { ((RestockItemScreen)__instance).m_RestockItemPanelUIList[i].Init((RestockItemScreen)(object)__instance, ((RestockItemScreen)__instance).m_CurrentRestockDataIndexList[i]); ((UIElementBase)((RestockItemScreen)__instance).m_RestockItemPanelUIList[i]).SetActive(true); ((GenericSliderScreen)__instance).m_ScrollEndPosParent = ((Component)((RestockItemScreen)__instance).m_RestockItemPanelUIList[i]).gameObject; } return false; } } [HarmonyPatch(typeof(TitleScreen))] public class TitleScreenPatches { [HarmonyPatch("OpenLoadGameSlotScreen")] [HarmonyPrefix] private static bool LoadPrefix(TitleScreen __instance) { FieldInfo field = typeof(TitleScreen).GetField("m_IsOpeningLevel", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) { return false; } if (!(bool)field.GetValue(__instance)) { field.SetValue(__instance, true); CSingleton<CGameManager>.Instance.m_CurrentSaveLoadSlotSelectedIndex = 3; CSingleton<CGameManager>.Instance.m_IsManualSaveLoad = true; CSingleton<CGameManager>.Instance.LoadMainLevelAsync("Start", 3); ControllerScreenUIExtManager.OnCloseScreen(__instance.m_ControllerScreenUIExtension); return true; } return true; } [HarmonyPatch("OnPressStartGame")] [HarmonyPrefix] private static bool NewGamePrefix(TitleScreen __instance) { FieldInfo field = typeof(TitleScreen).GetField("m_IsOpeningLevel", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) { return false; } if (!(bool)field.GetValue(__instance)) { bool flag = true; CSingleton<CGameManager>.Instance.LoadMainLevelAsync("Start", -1); ControllerScreenUIExtManager.OnCloseScreen(__instance.m_ControllerScreenUIExtension); } return false; } } public class TutorialPatches { [HarmonyPatch(typeof(ShopRenamer))] public class ShopRenamerPatches { [HarmonyPatch("OnPressConfirmShopName")] [HarmonyPostfix] private static void PostFix(ShopRenamer __instance) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown CSingleton<TutorialManager>.Instance.m_TutorialTargetIndicator.SetActive(false); ((Component)CSingleton<TutorialManager>.Instance).gameObject.SetActive(false); CPlayerData.m_TutorialIndex = 16; CPlayerData.m_HasFinishedTutorial = true; CPlayerData.m_TutorialDataList.Clear(); Plugin.onSceneLoadLogic(); CEventManager.QueueEvent((CEvent)new CEventPlayer_SetCoin((float)Settings.Instance.StartingMoney.Value)); } } } } namespace ApClient.mapping { public class CardMapping { public static int ghostProgressive = 522715351; public static int getId(CardData cardData) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Expected I4, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Expected I4, but got Unknown if ((int)cardData.expansionType > 1 || (int)cardData.monsterType >= 122) { return -1; } Plugin.Log(string.Format("{0} : {1}", string.Format("{0} {1} {2} {3}", cardData.monsterType, cardData.borderType, cardData.isFoil ? "Foil" : "NonFoil", cardData.expansionType), 0x1F290000 | (cardData.expansionType << 12) | (cardData.borderType << 8) | ((cardData.isFoil ? 1 : 0) << 7) | cardData.monsterType)); return 0x1F290000 | (cardData.expansionType << 12) | (cardData.borderType << 8) | ((cardData.isFoil ? 1 : 0) << 7) | cardData.monsterType; } } public class EmployeeMapping { public static Dictionary<int, (int itemid, string name, int locid)> mapping = new Dictionary<int, (int, string, int)> { { 0, (522715318, "Zachery", 522715505) }, { 1, (522715319, "Terence", 522715506) }, { 2, (522715320, "Dennis", 522715507) }, { 3, (522715321, "Clark", 522715508) }, { 4, (522715322, "Angus", 522715509) }, { 5, (522715323, "Benji", 522715510) }, { 6, (522715324, "Lauren", 522715511) }, { 7, (522715325, "Axel", 522715512) } }; public static KeyValuePair<int, (int itemid, string name, int locid)> getKeyValue(int itemid) { KeyValuePair<int, (int, string, int)> result = mapping.FirstOrDefault((KeyValuePair<int, (int itemid, string name, int locid)> pair) => pair.Value.itemid == itemid); KeyValuePair<int, (int, string, int)> keyValuePair = new KeyValuePair<int, (int, string, int)>(-1, (-1, "", -1)); if (result.Equals(default(KeyValuePair<int, (int, string, int)>))) { result = keyValuePair; } return result; } public static (int itemid, string name, int locid) getValueOrEmpty(int key) { return mapping.GetValueOrDefault(key, (-1, "", -1)); } } public class ExpansionMapping { public static int locstartval = 522715513; public static int progressiveA = 522715328; public static int progressiveB = 522715329; public static int warehouseKey = 522715381; } public class FurnatureMapping { public static int[] reorder = new int[22] { 0, 5, 17, 4, 11, 18, 1, 6, 12, 2, 10, 13, 8, 14, 20, 3, 12, 19, 7, 15, 21, 9 }; public static Dictionary<int, (int itemid, string name, int count)> mapping = new Dictionary<int, (int, string, int)> { { 0, (-1, "Small Cabinet", 1) }, { 1, (522715205, "Small Metal Rack", 1) }, { 2, (522715214, "Play Table", 1) }, { 3, (522715211, "Small Personal Shelf", 1) }, { 4, (522715206, "Single Sided Shelf", 1) }, { 5, (522715209, "Card Table", 1) }, { 6, (522715213, "Small Warehouse Shelf", 1) }, { 7, (522715210, "Small Card Display", 1) }, { 8, (522715212, "Auto Scent M100", 1) }, { 9, (522715215, "Workbench", 1) }, { 10, (522715216, "Trash Bin", 1) }, { 11, (522715207, "Double Sided Shelf", 1) }, { 12, (522715213, "Big Warehouse Shelf", 2) }, { 13, (522715217, "Checkout Counter", 1) }, { 14, (522715212, "Auto Scent G500", 2) }, { 15, (522715210, "Card Display Table", 2) }, { 16, (522715211, "Big Personal Shelf", 2) }, { 17, (522715209, "Vintage Card Table", 2) }, { 18, (522715208, "Wide Shelf", 1) }, { 19, (522715211, "Huge Personal Shelf", 3) }, { 20, (522715212, "Auto Scent T100", 3) }, { 21, (522715210, "Big Card Display", 3) } }; public static KeyValuePair<int, (int itemid, string name, int count)> getKeyValue(int itemid, int count = 1) { KeyValuePair<int, (int, string, int)> result = mapping.FirstOrDefault((KeyValuePair<int, (int itemid, string name, int count)> pair) => pair.Value.itemid == itemid && count == pair.Value.count); KeyValuePair<int, (int, string, int)> keyValuePair = new KeyValuePair<int, (int, string, int)>(-1, (-1, "Unknown", 0)); if (result.Equals(default(KeyValuePair<int, (int, string, int)>))) { result = keyValuePair; } return result; } public static (int itemid, string name, int count) getValueOrEmpty(int key) { return mapping.GetValueOrDefault(key, (-1, "", 0)); } } public class LevelMapping { public static int startValue = 522715556; } public class LicenseMapping { public static SortedDictionary<int, (int itemid, string name, int count, int locid, EItemType type)> mapping = new SortedDictionary<int, (int, string, int, int, EItemType)> { { 0, (522715137, "Basic Card Pack (32)", 32, 522715376, (EItemType)0) }, { 1, (522715352, "Basic Card Pack (64)", 32, 522715376, (EItemType)0) }, { 2, (522715353, "Progressive Basic Card Pack", 8, 522715377, (EItemType)1) }, { 3, (522715354, "Progressive Basic Card Pack", 8, 522715377, (EItemType)1) }, { 4, (522715138, "Progressive Rare Card Pack", 32, 522715378, (EItemType)2) }, { 5, (522715355, "Progressive Rare Card Pack", 32, 522715378, (EItemType)2) }, { 6, (522715356, "Progressive Rare Card Pack", 8, 522715379, (EItemType)3) }, { 7, (522715357, "Progressive Rare Card Pack", 8, 522715379, (EItemType)3) }, { 8, (522715139, "Progressive Epic Card Pack", 32, 522715380, (EItemType)4) }, { 9, (522715358, "Progressive Epic Card Pack", 32, 522715380, (EItemType)4) }, { 10, (522715359, "Progressive Epic Card Pack", 8, 522715381, (EItemType)5) }, { 11, (522715360, "Progressive Epic Card Pack", 8, 522715381, (EItemType)5) }, { 12, (522715140, "Progressive Legendary Card Pack", 32, 522715382, (EItemType)6) }, { 13, (522715361, "Progressive Legendary Card Pack", 32, 522715382, (EItemType)6) }, { 14, (522715362, "Progressive Legendary Card Pack", 8, 522715383, (EItemType)7) }, { 15, (522715363, "Progressive Legendary Card Pack", 8, 522715383, (EItemType)7) }, { 67, (522715141, "Fire Battle Deck", 9, 522715392, (EItemType)55) }, { 68, (522715142, "Earth Battle Deck", 9, 522715393, (EItemType)56) }, { 69, (522715143, "Water Battle Deck", 9, 522715394, (EItemType)57) }, { 70, (522715144, "Wind Battle Deck", 9, 522715395, (EItemType)58) }, { 24, (522715145, "Progressive Basic Destiny Pack", 32, 522715384, (EItemType)8) }, { 25, (522715364, "Progressive Basic Destiny Pack", 32, 522715384, (EItemType)8) }, { 26, (522715365, "Progressive Basic Destiny Pack", 8, 522715385, (EItemType)9) }, { 27, (522715366, "Progressive Basic Destiny Pack", 8, 522715385, (EItemType)9) }, { 28, (522715146, "Progressive Rare Destiny Pack", 32, 522715386, (EItemType)10) }, { 29, (522715367, "Progressive Rare Destiny Pack", 32, 522715386, (EItemType)10) }, { 30, (522715368, "Progressive Rare Destiny Pack", 8, 522715387, (EItemType)11) }, { 31, (522715369, "Progressive Rare Destiny Pack", 8, 522715387, (EItemType)11) }, { 32, (522715147, "Progressive Epic Destiny Pack", 32, 522715388, (EItemType)12) }, { 33, (522715370, "Progressive Epic Destiny Pack", 32, 522715388, (EItemType)12) }, { 34, (522715371, "Progressive Epic Destiny Pack", 8, 522715389, (EItemType)13) }, { 35, (522715372, "Progressive Epic Destiny Pack", 8, 522715389, (EItemType)13) }, { 36, (522715148, "Progressive Legendary Destiny Pack", 32, 522715390, (EItemType)14) }, { 37, (522715373, "Progressive Legendary Destiny Pack", 32, 522715390, (EItemType)14) }, { 38, (522715374, "Progressive Legendary Destiny Pack", 8, 522715391, (EItemType)15) }, { 39, (522715375, "Progressive Legendary Destiny Pack", 8, 522715391, (EItemType)15) }, { 71, (522715149, "Fire Destiny Deck", 9, 522715396, (EItemType)59) }, { 72, (522715150, "Earth Destiny Deck", 9, 522715397, (EItemType)60) }, { 73, (522715151, "Water Destiny Deck", 9, 522715398, (EItemType)61) }, { 74, (522715152, "Wind Destiny Deck", 9, 522715399, (EItemType)62) }, { 40, (522715153, "Cleanser (8)", 8, 522715400, (EItemType)23) }, { 41, (522715376, "Progressive Cleanser", 8, 522715400, (EItemType)23) }, { 75, (522715154, "Card Sleeves (Clear)", 32, 522715401, (EItemType)63) }, { 76, (522715155, "Card Sleeves (Tetramon)", 32, 522715402, (EItemType)64) }, { 43, (522715156, "D20 Dice Red (16)", 8, 522715403, (EItemType)29) }, { 44, (522715157, "D20 Dice Blue (16)", 8, 522715404, (EItemType)30) }, { 45, (522715158, "D20 Dice Black (16)", 8, 522715405, (EItemType)31) }, { 46, (522715159, "D20 Dice White (16)", 8, 522715406, (EItemType)32) }, { 77, (522715160, "Card Sleeves (Fire)", 32, 522715407, (EItemType)65) }, { 78, (522715161, "Card Sleeves (Earth)", 32, 522715408, (EItemType)66) }, { 79, (522715162, "Card Sleeves (Water)", 32, 522715409, (EItemType)67) }, { 80, (522715163, "Card Sleeves (Wind)", 32, 522715410, (EItemType)68) }, { 16, (522715164, "Progressive Deck Box Red", 8, 522715411, (EItemType)24) }, { 17, (522715377, "Progressive Deck Box Red", 8, 522715411, (EItemType)24) }, { 18, (522715165, "Progressive Deck Box Green", 8, 522715412, (EItemType)25) }, { 19, (522715378, "Progressive Deck Box Green", 8, 522715412, (EItemType)25) }, { 20, (522715166, "Progressive Deck Box Blue", 8, 522715413, (EItemType)26) }, { 21, (522715379, "Progressive Deck Box Blue", 8, 522715413, (EItemType)26) }, { 22, (522715167, "Progressive Deck Box Yellow", 8, 522715414, (EItemType)27) }, { 23, (522715380, "Progressive Deck Box Yellow", 8, 522715414, (EItemType)27) }, { 42, (522715168, "Collection Book ", 4, 522715415, (EItemType)28) }, { 66, (522715169, "Premium Collection Book", 4, 522715416, (EItemType)54) }, { 83, (522715170, "Playmat (Drilceros)", 8, 522715417, (EItemType)71) }, { 81, (522715171, "Playmat (Clamigo)", 8, 522715418, (EItemType)69) }, { 87, (522715172, "Playmat (Wispo)", 8, 522715419, (EItemType)75) }, { 95, (522715173, "Playmat (Lunight)", 8, 522715420, (EItemType)83) }, { 90, (522715174, "Playmat (Kyrone)", 8, 522715421, (EItemType)78) }, { 82, (522715175, "Playmat (Duel)", 8, 522715422, (EItemType)70) }, { 86, (522715176, "Playmat (Dracunix)", 8, 522715423, (EItemType)74) }, { 85, (522715177, "Playmat (The Four Dragons)", 8, 522715424, (EItemType)73) }, { 84, (522715178, "Playmat (Drakon)", 8, 522715425, (EItemType)72) }, { 88, (522715179, "Playmat (GigatronX Evo)", 8, 522715426, (EItemType)76) }, { 91, (522715180, "Playmat (Fire)", 8, 522715427, (EItemType)79) }, { 92, (522715181, "Playmat (Earth)
plugins/Archipelago.MultiClient.Net.dll
Decompiled a week ago
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.WebSockets; using System.Numerics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Text; using System.Threading; using System.Threading.Tasks; using Archipelago.MultiClient.Net.Colors; using Archipelago.MultiClient.Net.ConcurrentCollection; using Archipelago.MultiClient.Net.Converters; using Archipelago.MultiClient.Net.DataPackage; using Archipelago.MultiClient.Net.Enums; using Archipelago.MultiClient.Net.Exceptions; using Archipelago.MultiClient.Net.Extensions; using Archipelago.MultiClient.Net.Helpers; using Archipelago.MultiClient.Net.MessageLog.Messages; using Archipelago.MultiClient.Net.MessageLog.Parts; using Archipelago.MultiClient.Net.Models; using Archipelago.MultiClient.Net.Packets; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: ComVisible(false)] [assembly: Guid("35a803ad-85ed-42e9-b1e3-c6b72096f0c1")] [assembly: InternalsVisibleTo("Archipelago.MultiClient.Net.Tests")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("Jarno Westhof, Hussein Farran, Zach Parks")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyDescription("A client library for use with .NET based prog-langs for interfacing with Archipelago hosts.")] [assembly: AssemblyFileVersion("6.6.0.0")] [assembly: AssemblyInformationalVersion("6.6.0+75d4c5e6a52bb0c8bb1d4bc368652613509c7acb")] [assembly: AssemblyProduct("Archipelago.MultiClient.Net")] [assembly: AssemblyTitle("Archipelago.MultiClient.Net")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/ArchipelagoMW/Archipelago.MultiClient.Net")] [assembly: AssemblyVersion("6.6.0.0")] internal interface IConcurrentHashSet<T> { bool TryAdd(T item); bool Contains(T item); void UnionWith(T[] otherSet); T[] ToArray(); ReadOnlyCollection<T> AsToReadOnlyCollection(); ReadOnlyCollection<T> AsToReadOnlyCollectionExcept(IConcurrentHashSet<T> otherSet); } namespace Archipelago.MultiClient.Net { [Serializable] public abstract class ArchipelagoPacketBase { [JsonIgnore] internal JObject jobject; [JsonProperty("cmd")] [JsonConverter(typeof(StringEnumConverter))] public abstract ArchipelagoPacketType PacketType { get; } public JObject ToJObject() { return jobject; } } public interface IArchipelagoSession : IArchipelagoSessionActions { IArchipelagoSocketHelper Socket { get; } IReceivedItemsHelper Items { get; } ILocationCheckHelper Locations { get; } IPlayerHelper Players { get; } IDataStorageHelper DataStorage { get; } IConnectionInfoProvider ConnectionInfo { get; } IRoomStateHelper RoomState { get; } IMessageLogHelper MessageLog { get; } Task<RoomInfoPacket> ConnectAsync(); Task<LoginResult> LoginAsync(string game, string name, ItemsHandlingFlags itemsHandlingFlags, Version version = null, string[] tags = null, string uuid = null, string password = null, bool requestSlotData = true); LoginResult TryConnectAndLogin(string game, string name, ItemsHandlingFlags itemsHandlingFlags, Version version = null, string[] tags = null, string uuid = null, string password = null, bool requestSlotData = true); } public class ArchipelagoSession : IArchipelagoSession, IArchipelagoSessionActions { private const int ArchipelagoConnectionTimeoutInSeconds = 4; private ConnectionInfoHelper connectionInfo; private TaskCompletionSource<LoginResult> loginResultTask = new TaskCompletionSource<LoginResult>(); private TaskCompletionSource<RoomInfoPacket> roomInfoPacketTask = new TaskCompletionSource<RoomInfoPacket>(); public IArchipelagoSocketHelper Socket { get; } public IReceivedItemsHelper Items { get; } public ILocationCheckHelper Locations { get; } public IPlayerHelper Players { get; } public IDataStorageHelper DataStorage { get; } public IConnectionInfoProvider ConnectionInfo => connectionInfo; public IRoomStateHelper RoomState { get; } public IMessageLogHelper MessageLog { get; } internal ArchipelagoSession(IArchipelagoSocketHelper socket, IReceivedItemsHelper items, ILocationCheckHelper locations, IPlayerHelper players, IRoomStateHelper roomState, ConnectionInfoHelper connectionInfoHelper, IDataStorageHelper dataStorage, IMessageLogHelper messageLog) { Socket = socket; Items = items; Locations = locations; Players = players; RoomState = roomState; connectionInfo = connectionInfoHelper; DataStorage = dataStorage; MessageLog = messageLog; socket.PacketReceived += Socket_PacketReceived; } private void Socket_PacketReceived(ArchipelagoPacketBase packet) { if (!(packet is ConnectedPacket) && !(packet is ConnectionRefusedPacket)) { if (packet is RoomInfoPacket result) { roomInfoPacketTask.TrySetResult(result); } return; } if (packet is ConnectedPacket && RoomState.Version != null && RoomState.Version >= new Version(0, 3, 8)) { LogUsedVersion(); } loginResultTask.TrySetResult(LoginResult.FromPacket(packet)); } private void LogUsedVersion() { try { string fileVersion = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion; Socket.SendPacketAsync(new SetPacket { Key = ".NetUsedVersions", DefaultValue = (JToken)(object)JObject.FromObject((object)new Dictionary<string, bool>()), Operations = new OperationSpecification[1] { Operation.Update(new Dictionary<string, bool> { { ConnectionInfo.Game + ":" + fileVersion + ":NETSTANDARD2_0", true } }) } }); } catch { } } public Task<RoomInfoPacket> ConnectAsync() { roomInfoPacketTask = new TaskCompletionSource<RoomInfoPacket>(); Task.Factory.StartNew(delegate { try { Task task = Socket.ConnectAsync(); task.Wait(TimeSpan.FromSeconds(4.0)); if (!task.IsCompleted) { roomInfoPacketTask.TrySetCanceled(); } } catch (AggregateException) { roomInfoPacketTask.TrySetCanceled(); } }); return roomInfoPacketTask.Task; } public Task<LoginResult> LoginAsync(string game, string name, ItemsHandlingFlags itemsHandlingFlags, Version version = null, string[] tags = null, string uuid = null, string password = null, bool requestSlotData = true) { loginResultTask = new TaskCompletionSource<LoginResult>(); if (!roomInfoPacketTask.Task.IsCompleted) { loginResultTask.TrySetResult(new LoginFailure("You are not connected, run ConnectAsync() first")); return loginResultTask.Task; } connectionInfo.SetConnectionParameters(game, tags, itemsHandlingFlags, uuid); try { Socket.SendPacket(BuildConnectPacket(name, password, version, requestSlotData)); } catch (ArchipelagoSocketClosedException) { loginResultTask.TrySetResult(new LoginFailure("You are not connected, run ConnectAsync() first")); return loginResultTask.Task; } SetResultAfterTimeout(loginResultTask, 4, new LoginFailure("Connection timed out.")); return loginResultTask.Task; } private static void SetResultAfterTimeout<T>(TaskCompletionSource<T> task, int timeoutInSeconds, T result) { new CancellationTokenSource(TimeSpan.FromSeconds(timeoutInSeconds)).Token.Register(delegate { task.TrySetResult(result); }); } public LoginResult TryConnectAndLogin(string game, string name, ItemsHandlingFlags itemsHandlingFlags, Version version = null, string[] tags = null, string uuid = null, string password = null, bool requestSlotData = true) { Task<RoomInfoPacket> task = ConnectAsync(); try { task.Wait(TimeSpan.FromSeconds(4.0)); } catch (AggregateException ex) { if (ex.GetBaseException() is OperationCanceledException) { return new LoginFailure("Connection timed out."); } return new LoginFailure(ex.GetBaseException().Message); } if (!task.IsCompleted) { return new LoginFailure("Connection timed out."); } return LoginAsync(game, name, itemsHandlingFlags, version, tags, uuid, password, requestSlotData).Result; } private ConnectPacket BuildConnectPacket(string name, string password, Version version, bool requestSlotData) { return new ConnectPacket { Game = ConnectionInfo.Game, Name = name, Password = password, Tags = ConnectionInfo.Tags, Uuid = ConnectionInfo.Uuid, Version = ((version != null) ? new NetworkVersion(version) : new NetworkVersion(0, 6, 0)), ItemsHandling = ConnectionInfo.ItemsHandlingFlags, RequestSlotData = requestSlotData }; } public void Say(string message) { Socket.SendPacket(new SayPacket { Text = message }); } public void SetClientState(ArchipelagoClientState state) { Socket.SendPacket(new StatusUpdatePacket { Status = state }); } public void SetGoalAchieved() { SetClientState(ArchipelagoClientState.ClientGoal); } } public interface IArchipelagoSessionActions { void Say(string message); void SetClientState(ArchipelagoClientState state); void SetGoalAchieved(); } public static class ArchipelagoSessionFactory { public static ArchipelagoSession CreateSession(Uri uri) { ArchipelagoSocketHelper socket = new ArchipelagoSocketHelper(uri); DataPackageCache cache = new DataPackageCache(socket); ConnectionInfoHelper connectionInfoHelper = new ConnectionInfoHelper(socket); PlayerHelper playerHelper = new PlayerHelper(socket, connectionInfoHelper); ItemInfoResolver itemInfoResolver = new ItemInfoResolver(cache, connectionInfoHelper); LocationCheckHelper locationCheckHelper = new LocationCheckHelper(socket, itemInfoResolver, connectionInfoHelper, playerHelper); ReceivedItemsHelper items = new ReceivedItemsHelper(socket, locationCheckHelper, itemInfoResolver, connectionInfoHelper, playerHelper); RoomStateHelper roomState = new RoomStateHelper(socket, locationCheckHelper); DataStorageHelper dataStorage = new DataStorageHelper(socket, connectionInfoHelper); MessageLogHelper messageLog = new MessageLogHelper(socket, itemInfoResolver, playerHelper, connectionInfoHelper); return new ArchipelagoSession(socket, items, locationCheckHelper, playerHelper, roomState, connectionInfoHelper, dataStorage, messageLog); } public static ArchipelagoSession CreateSession(string hostname, int port = 38281) { return CreateSession(ParseUri(hostname, port)); } internal static Uri ParseUri(string hostname, int port) { string text = hostname; if (!text.StartsWith("ws://") && !text.StartsWith("wss://")) { text = "unspecified://" + text; } if (!text.Substring(text.IndexOf("://", StringComparison.Ordinal) + 3).Contains(":")) { text += $":{port}"; } if (text.EndsWith(":")) { text += port; } return new Uri(text); } } public abstract class LoginResult { public abstract bool Successful { get; } public static LoginResult FromPacket(ArchipelagoPacketBase packet) { if (!(packet is ConnectedPacket connectedPacket)) { if (packet is ConnectionRefusedPacket connectionRefusedPacket) { return new LoginFailure(connectionRefusedPacket); } throw new ArgumentOutOfRangeException("packet", "packet is not a connection result packet"); } return new LoginSuccessful(connectedPacket); } } public class LoginSuccessful : LoginResult { public override bool Successful => true; public int Team { get; } public int Slot { get; } public Dictionary<string, object> SlotData { get; } public LoginSuccessful(ConnectedPacket connectedPacket) { Team = connectedPacket.Team; Slot = connectedPacket.Slot; SlotData = connectedPacket.SlotData; } } public class LoginFailure : LoginResult { public override bool Successful => false; public ConnectionRefusedError[] ErrorCodes { get; } public string[] Errors { get; } public LoginFailure(ConnectionRefusedPacket connectionRefusedPacket) { if (connectionRefusedPacket.Errors != null) { ErrorCodes = connectionRefusedPacket.Errors.ToArray(); Errors = ErrorCodes.Select(GetErrorMessage).ToArray(); } else { ErrorCodes = new ConnectionRefusedError[0]; Errors = new string[0]; } } public LoginFailure(string message) { ErrorCodes = new ConnectionRefusedError[0]; Errors = new string[1] { message }; } private static string GetErrorMessage(ConnectionRefusedError errorCode) { return errorCode switch { ConnectionRefusedError.InvalidSlot => "The slot name did not match any slot on the server.", ConnectionRefusedError.InvalidGame => "The slot is set to a different game on the server.", ConnectionRefusedError.SlotAlreadyTaken => "The slot already has a connection with a different uuid established.", ConnectionRefusedError.IncompatibleVersion => "The client and server version mismatch.", ConnectionRefusedError.InvalidPassword => "The password is invalid.", ConnectionRefusedError.InvalidItemsHandling => "The item handling flags provided are invalid.", _ => $"Unknown error: {errorCode}.", }; } } internal class TwoWayLookup<TA, TB> : IEnumerable<KeyValuePair<TB, TA>>, IEnumerable { private readonly Dictionary<TA, TB> aToB = new Dictionary<TA, TB>(); private readonly Dictionary<TB, TA> bToA = new Dictionary<TB, TA>(); public TA this[TB b] => bToA[b]; public TB this[TA a] => aToB[a]; public void Add(TA a, TB b) { aToB[a] = b; bToA[b] = a; } public void Add(TB b, TA a) { Add(a, b); } public bool TryGetValue(TA a, out TB b) { return aToB.TryGetValue(a, out b); } public bool TryGetValue(TB b, out TA a) { return bToA.TryGetValue(b, out a); } public IEnumerator<KeyValuePair<TB, TA>> GetEnumerator() { return bToA.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } } namespace Archipelago.MultiClient.Net.Packets { public class BouncedPacket : BouncePacket { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Bounced; } public class BouncePacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Bounce; [JsonProperty("games")] public List<string> Games { get; set; } = new List<string>(); [JsonProperty("slots")] public List<int> Slots { get; set; } = new List<int>(); [JsonProperty("tags")] public List<string> Tags { get; set; } = new List<string>(); [JsonProperty("data")] public Dictionary<string, JToken> Data { get; set; } } public class ConnectedPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Connected; [JsonProperty("team")] public int Team { get; set; } [JsonProperty("slot")] public int Slot { get; set; } [JsonProperty("players")] public NetworkPlayer[] Players { get; set; } [JsonProperty("missing_locations")] public long[] MissingChecks { get; set; } [JsonProperty("checked_locations")] public long[] LocationsChecked { get; set; } [JsonProperty("slot_data")] public Dictionary<string, object> SlotData { get; set; } [JsonProperty("slot_info")] public Dictionary<int, NetworkSlot> SlotInfo { get; set; } [JsonProperty("hint_points")] public int? HintPoints { get; set; } } public class ConnectionRefusedPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.ConnectionRefused; [JsonProperty("errors", ItemConverterType = typeof(StringEnumConverter))] public ConnectionRefusedError[] Errors { get; set; } } public class ConnectPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Connect; [JsonProperty("password")] public string Password { get; set; } [JsonProperty("game")] public string Game { get; set; } [JsonProperty("name")] public string Name { get; set; } [JsonProperty("uuid")] public string Uuid { get; set; } [JsonProperty("version")] public NetworkVersion Version { get; set; } [JsonProperty("tags")] public string[] Tags { get; set; } [JsonProperty("items_handling")] public ItemsHandlingFlags ItemsHandling { get; set; } [JsonProperty("slot_data")] public bool RequestSlotData { get; set; } } public class ConnectUpdatePacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.ConnectUpdate; [JsonProperty("tags")] public string[] Tags { get; set; } [JsonProperty("items_handling")] public ItemsHandlingFlags? ItemsHandling { get; set; } } public class DataPackagePacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.DataPackage; [JsonProperty("data")] public Archipelago.MultiClient.Net.Models.DataPackage DataPackage { get; set; } } public class GetDataPackagePacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.GetDataPackage; [JsonProperty("games")] public string[] Games { get; set; } } public class GetPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Get; [JsonProperty("keys")] public string[] Keys { get; set; } } public class InvalidPacketPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.InvalidPacket; [JsonProperty("type")] public InvalidPacketErrorType ErrorType { get; set; } [JsonProperty("text")] public string ErrorText { get; set; } [JsonProperty("original_cmd")] public ArchipelagoPacketType OriginalCmd { get; set; } } public class LocationChecksPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.LocationChecks; [JsonProperty("locations")] public long[] Locations { get; set; } } public class LocationInfoPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.LocationInfo; [JsonProperty("locations")] public NetworkItem[] Locations { get; set; } } public class LocationScoutsPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.LocationScouts; [JsonProperty("locations")] public long[] Locations { get; set; } [JsonProperty("create_as_hint")] public int CreateAsHint { get; set; } } public class PrintJsonPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.PrintJSON; [JsonProperty("data")] public JsonMessagePart[] Data { get; set; } [JsonProperty("type")] [JsonConverter(typeof(StringEnumConverter))] public JsonMessageType? MessageType { get; set; } } public class ItemPrintJsonPacket : PrintJsonPacket { [JsonProperty("receiving")] public int ReceivingPlayer { get; set; } [JsonProperty("item")] public NetworkItem Item { get; set; } } public class ItemCheatPrintJsonPacket : PrintJsonPacket { [JsonProperty("receiving")] public int ReceivingPlayer { get; set; } [JsonProperty("item")] public NetworkItem Item { get; set; } [JsonProperty("team")] public int Team { get; set; } } public class HintPrintJsonPacket : PrintJsonPacket { [JsonProperty("receiving")] public int ReceivingPlayer { get; set; } [JsonProperty("item")] public NetworkItem Item { get; set; } [JsonProperty("found")] public bool? Found { get; set; } } public class JoinPrintJsonPacket : PrintJsonPacket { [JsonProperty("team")] public int Team { get; set; } [JsonProperty("slot")] public int Slot { get; set; } [JsonProperty("tags")] public string[] Tags { get; set; } } public class LeavePrintJsonPacket : PrintJsonPacket { [JsonProperty("team")] public int Team { get; set; } [JsonProperty("slot")] public int Slot { get; set; } } public class ChatPrintJsonPacket : PrintJsonPacket { [JsonProperty("team")] public int Team { get; set; } [JsonProperty("slot")] public int Slot { get; set; } [JsonProperty("message")] public string Message { get; set; } } public class ServerChatPrintJsonPacket : PrintJsonPacket { [JsonProperty("message")] public string Message { get; set; } } public class TutorialPrintJsonPacket : PrintJsonPacket { } public class TagsChangedPrintJsonPacket : PrintJsonPacket { [JsonProperty("team")] public int Team { get; set; } [JsonProperty("slot")] public int Slot { get; set; } [JsonProperty("tags")] public string[] Tags { get; set; } } public class CommandResultPrintJsonPacket : PrintJsonPacket { } public class AdminCommandResultPrintJsonPacket : PrintJsonPacket { } public class GoalPrintJsonPacket : PrintJsonPacket { [JsonProperty("team")] public int Team { get; set; } [JsonProperty("slot")] public int Slot { get; set; } } public class ReleasePrintJsonPacket : PrintJsonPacket { [JsonProperty("team")] public int Team { get; set; } [JsonProperty("slot")] public int Slot { get; set; } } public class CollectPrintJsonPacket : PrintJsonPacket { [JsonProperty("team")] public int Team { get; set; } [JsonProperty("slot")] public int Slot { get; set; } } public class CountdownPrintJsonPacket : PrintJsonPacket { [JsonProperty("countdown")] public int RemainingSeconds { get; set; } } public class ReceivedItemsPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.ReceivedItems; [JsonProperty("index")] public int Index { get; set; } [JsonProperty("items")] public NetworkItem[] Items { get; set; } } public class RetrievedPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Retrieved; [JsonProperty("keys")] public Dictionary<string, JToken> Data { get; set; } } public class RoomInfoPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.RoomInfo; [JsonProperty("version")] public NetworkVersion Version { get; set; } [JsonProperty("generator_version")] public NetworkVersion GeneratorVersion { get; set; } [JsonProperty("tags")] public string[] Tags { get; set; } [JsonProperty("password")] public bool Password { get; set; } [JsonProperty("permissions")] public Dictionary<string, Permissions> Permissions { get; set; } [JsonProperty("hint_cost")] public int HintCostPercentage { get; set; } [JsonProperty("location_check_points")] public int LocationCheckPoints { get; set; } [JsonProperty("players")] public NetworkPlayer[] Players { get; set; } [JsonProperty("games")] public string[] Games { get; set; } [JsonProperty("datapackage_checksums")] public Dictionary<string, string> DataPackageChecksums { get; set; } [JsonProperty("seed_name")] public string SeedName { get; set; } [JsonProperty("time")] public double Timestamp { get; set; } } public class RoomUpdatePacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.RoomUpdate; [JsonProperty("tags")] public string[] Tags { get; set; } [JsonProperty("password")] public bool? Password { get; set; } [JsonProperty("permissions")] public Dictionary<string, Permissions> Permissions { get; set; } = new Dictionary<string, Permissions>(); [JsonProperty("hint_cost")] public int? HintCostPercentage { get; set; } [JsonProperty("location_check_points")] public int? LocationCheckPoints { get; set; } [JsonProperty("players")] public NetworkPlayer[] Players { get; set; } [JsonProperty("hint_points")] public int? HintPoints { get; set; } [JsonProperty("checked_locations")] public long[] CheckedLocations { get; set; } } public class SayPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Say; [JsonProperty("text")] public string Text { get; set; } } public class SetNotifyPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.SetNotify; [JsonProperty("keys")] public string[] Keys { get; set; } } public class SetPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Set; [JsonProperty("key")] public string Key { get; set; } [JsonProperty("default")] public JToken DefaultValue { get; set; } [JsonProperty("operations")] public OperationSpecification[] Operations { get; set; } [JsonProperty("want_reply")] public bool WantReply { get; set; } [JsonExtensionData] public Dictionary<string, JToken> AdditionalArguments { get; set; } [OnDeserialized] internal void OnDeserializedMethod(StreamingContext context) { AdditionalArguments?.Remove("cmd"); } } public class SetReplyPacket : SetPacket { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.SetReply; [JsonProperty("value")] public JToken Value { get; set; } [JsonProperty("original_value")] public JToken OriginalValue { get; set; } } public class StatusUpdatePacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.StatusUpdate; [JsonProperty("status")] public ArchipelagoClientState Status { get; set; } } public class SyncPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Sync; } internal class UnknownPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Unknown; } public class UpdateHintPacket : ArchipelagoPacketBase { public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.UpdateHint; [JsonProperty("player")] public int Player { get; set; } [JsonProperty("location")] public long Location { get; set; } [JsonProperty("status")] public HintStatus Status { get; set; } } } namespace Archipelago.MultiClient.Net.Models { public struct Color : IEquatable<Color> { public static Color Red = new Color(byte.MaxValue, 0, 0); public static Color Green = new Color(0, 128, 0); public static Color Yellow = new Color(byte.MaxValue, byte.MaxValue, 0); public static Color Blue = new Color(0, 0, byte.MaxValue); public static Color Magenta = new Color(byte.MaxValue, 0, byte.MaxValue); public static Color Cyan = new Color(0, byte.MaxValue, byte.MaxValue); public static Color Black = new Color(0, 0, 0); public static Color White = new Color(byte.MaxValue, byte.MaxValue, byte.MaxValue); public static Color SlateBlue = new Color(106, 90, 205); public static Color Salmon = new Color(250, 128, 114); public static Color Plum = new Color(221, 160, 221); public byte R { get; set; } public byte G { get; set; } public byte B { get; set; } public Color(byte r, byte g, byte b) { R = r; G = g; B = b; } public override bool Equals(object obj) { if (obj is Color color && R == color.R && G == color.G) { return B == color.B; } return false; } public bool Equals(Color other) { if (R == other.R && G == other.G) { return B == other.B; } return false; } public override int GetHashCode() { return ((-1520100960 * -1521134295 + R.GetHashCode()) * -1521134295 + G.GetHashCode()) * -1521134295 + B.GetHashCode(); } public static bool operator ==(Color left, Color right) { return left.Equals(right); } public static bool operator !=(Color left, Color right) { return !(left == right); } } public class DataPackage { [JsonProperty("games")] public Dictionary<string, GameData> Games { get; set; } = new Dictionary<string, GameData>(); } public class DataStorageElement { internal DataStorageElementContext Context; internal List<OperationSpecification> Operations = new List<OperationSpecification>(0); internal DataStorageHelper.DataStorageUpdatedHandler Callbacks; internal Dictionary<string, JToken> AdditionalArguments = new Dictionary<string, JToken>(0); private JToken cachedValue; public event DataStorageHelper.DataStorageUpdatedHandler OnValueChanged { add { Context.AddHandler(Context.Key, value); } remove { Context.RemoveHandler(Context.Key, value); } } internal DataStorageElement(DataStorageElementContext context) { Context = context; } internal DataStorageElement(OperationType operationType, JToken value) { Operations = new List<OperationSpecification>(1) { new OperationSpecification { OperationType = operationType, Value = value } }; } internal DataStorageElement(DataStorageElement source, OperationType operationType, JToken value) : this(source.Context) { Operations = source.Operations.ToList(); Callbacks = source.Callbacks; AdditionalArguments = source.AdditionalArguments; Operations.Add(new OperationSpecification { OperationType = operationType, Value = value }); } internal DataStorageElement(DataStorageElement source, Callback callback) : this(source.Context) { Operations = source.Operations.ToList(); Callbacks = source.Callbacks; AdditionalArguments = source.AdditionalArguments; Callbacks = (DataStorageHelper.DataStorageUpdatedHandler)Delegate.Combine(Callbacks, callback.Method); } internal DataStorageElement(DataStorageElement source, AdditionalArgument additionalArgument) : this(source.Context) { Operations = source.Operations.ToList(); Callbacks = source.Callbacks; AdditionalArguments = source.AdditionalArguments; AdditionalArguments[additionalArgument.Key] = additionalArgument.Value; } public static DataStorageElement operator ++(DataStorageElement a) { return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(1)); } public static DataStorageElement operator --(DataStorageElement a) { return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(-1)); } public static DataStorageElement operator +(DataStorageElement a, int b) { return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b)); } public static DataStorageElement operator +(DataStorageElement a, long b) { return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b)); } public static DataStorageElement operator +(DataStorageElement a, float b) { return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b)); } public static DataStorageElement operator +(DataStorageElement a, double b) { return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b)); } public static DataStorageElement operator +(DataStorageElement a, decimal b) { return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b)); } public static DataStorageElement operator +(DataStorageElement a, string b) { return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b)); } public static DataStorageElement operator +(DataStorageElement a, JToken b) { return new DataStorageElement(a, OperationType.Add, b); } public static DataStorageElement operator +(DataStorageElement a, IEnumerable b) { return new DataStorageElement(a, OperationType.Add, (JToken)(object)JArray.FromObject((object)b)); } public static DataStorageElement operator +(DataStorageElement a, OperationSpecification s) { return new DataStorageElement(a, s.OperationType, s.Value); } public static DataStorageElement operator +(DataStorageElement a, Callback c) { return new DataStorageElement(a, c); } public static DataStorageElement operator +(DataStorageElement a, AdditionalArgument arg) { return new DataStorageElement(a, arg); } public static DataStorageElement operator *(DataStorageElement a, int b) { return new DataStorageElement(a, OperationType.Mul, JToken.op_Implicit(b)); } public static DataStorageElement operator *(DataStorageElement a, long b) { return new DataStorageElement(a, OperationType.Mul, JToken.op_Implicit(b)); } public static DataStorageElement operator *(DataStorageElement a, float b) { return new DataStorageElement(a, OperationType.Mul, JToken.op_Implicit(b)); } public static DataStorageElement operator *(DataStorageElement a, double b) { return new DataStorageElement(a, OperationType.Mul, JToken.op_Implicit(b)); } public static DataStorageElement operator *(DataStorageElement a, decimal b) { return new DataStorageElement(a, OperationType.Mul, JToken.op_Implicit(b)); } public static DataStorageElement operator %(DataStorageElement a, int b) { return new DataStorageElement(a, OperationType.Mod, JToken.op_Implicit(b)); } public static DataStorageElement operator %(DataStorageElement a, long b) { return new DataStorageElement(a, OperationType.Mod, JToken.op_Implicit(b)); } public static DataStorageElement operator %(DataStorageElement a, float b) { return new DataStorageElement(a, OperationType.Mod, JToken.op_Implicit(b)); } public static DataStorageElement operator %(DataStorageElement a, double b) { return new DataStorageElement(a, OperationType.Mod, JToken.op_Implicit(b)); } public static DataStorageElement operator %(DataStorageElement a, decimal b) { return new DataStorageElement(a, OperationType.Mod, JToken.op_Implicit(b)); } public static DataStorageElement operator ^(DataStorageElement a, int b) { return new DataStorageElement(a, OperationType.Pow, JToken.op_Implicit(b)); } public static DataStorageElement operator ^(DataStorageElement a, long b) { return new DataStorageElement(a, OperationType.Pow, JToken.op_Implicit(b)); } public static DataStorageElement operator ^(DataStorageElement a, float b) { return new DataStorageElement(a, OperationType.Pow, JToken.op_Implicit(b)); } public static DataStorageElement operator ^(DataStorageElement a, double b) { return new DataStorageElement(a, OperationType.Pow, JToken.op_Implicit(b)); } public static DataStorageElement operator ^(DataStorageElement a, decimal b) { return new DataStorageElement(a, OperationType.Pow, JToken.op_Implicit(b)); } public static DataStorageElement operator -(DataStorageElement a, int b) { return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(-b))); } public static DataStorageElement operator -(DataStorageElement a, long b) { return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(-b))); } public static DataStorageElement operator -(DataStorageElement a, float b) { return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(0f - b))); } public static DataStorageElement operator -(DataStorageElement a, double b) { return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(0.0 - b))); } public static DataStorageElement operator -(DataStorageElement a, decimal b) { return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(-b))); } public static DataStorageElement operator /(DataStorageElement a, int b) { return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1m / (decimal)b))); } public static DataStorageElement operator /(DataStorageElement a, long b) { return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1m / (decimal)b))); } public static DataStorageElement operator /(DataStorageElement a, float b) { return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1.0 / (double)b))); } public static DataStorageElement operator /(DataStorageElement a, double b) { return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1.0 / b))); } public static DataStorageElement operator /(DataStorageElement a, decimal b) { return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1m / b))); } public static implicit operator DataStorageElement(bool b) { return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(b)); } public static implicit operator DataStorageElement(int i) { return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(i)); } public static implicit operator DataStorageElement(long l) { return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(l)); } public static implicit operator DataStorageElement(decimal m) { return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(m)); } public static implicit operator DataStorageElement(double d) { return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(d)); } public static implicit operator DataStorageElement(float f) { return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(f)); } public static implicit operator DataStorageElement(string s) { if (s != null) { return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(s)); } return new DataStorageElement(OperationType.Replace, (JToken)(object)JValue.CreateNull()); } public static implicit operator DataStorageElement(JToken o) { return new DataStorageElement(OperationType.Replace, o); } public static implicit operator DataStorageElement(Array a) { return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)a)); } public static implicit operator DataStorageElement(List<bool> l) { return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l)); } public static implicit operator DataStorageElement(List<int> l) { return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l)); } public static implicit operator DataStorageElement(List<long> l) { return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l)); } public static implicit operator DataStorageElement(List<decimal> l) { return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l)); } public static implicit operator DataStorageElement(List<double> l) { return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l)); } public static implicit operator DataStorageElement(List<float> l) { return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l)); } public static implicit operator DataStorageElement(List<string> l) { return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l)); } public static implicit operator DataStorageElement(List<object> l) { return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l)); } public static implicit operator bool(DataStorageElement e) { return RetrieveAndReturnBoolValue<bool>(e); } public static implicit operator bool?(DataStorageElement e) { return RetrieveAndReturnBoolValue<bool?>(e); } public static implicit operator int(DataStorageElement e) { return RetrieveAndReturnDecimalValue<int>(e); } public static implicit operator int?(DataStorageElement e) { return RetrieveAndReturnDecimalValue<int?>(e); } public static implicit operator long(DataStorageElement e) { return RetrieveAndReturnDecimalValue<long>(e); } public static implicit operator long?(DataStorageElement e) { return RetrieveAndReturnDecimalValue<long?>(e); } public static implicit operator float(DataStorageElement e) { return RetrieveAndReturnDecimalValue<float>(e); } public static implicit operator float?(DataStorageElement e) { return RetrieveAndReturnDecimalValue<float?>(e); } public static implicit operator double(DataStorageElement e) { return RetrieveAndReturnDecimalValue<double>(e); } public static implicit operator double?(DataStorageElement e) { return RetrieveAndReturnDecimalValue<double?>(e); } public static implicit operator decimal(DataStorageElement e) { return RetrieveAndReturnDecimalValue<decimal>(e); } public static implicit operator decimal?(DataStorageElement e) { return RetrieveAndReturnDecimalValue<decimal?>(e); } public static implicit operator string(DataStorageElement e) { return RetrieveAndReturnStringValue(e); } public static implicit operator bool[](DataStorageElement e) { return RetrieveAndReturnArrayValue<bool[]>(e); } public static implicit operator int[](DataStorageElement e) { return RetrieveAndReturnArrayValue<int[]>(e); } public static implicit operator long[](DataStorageElement e) { return RetrieveAndReturnArrayValue<long[]>(e); } public static implicit operator decimal[](DataStorageElement e) { return RetrieveAndReturnArrayValue<decimal[]>(e); } public static implicit operator double[](DataStorageElement e) { return RetrieveAndReturnArrayValue<double[]>(e); } public static implicit operator float[](DataStorageElement e) { return RetrieveAndReturnArrayValue<float[]>(e); } public static implicit operator string[](DataStorageElement e) { return RetrieveAndReturnArrayValue<string[]>(e); } public static implicit operator object[](DataStorageElement e) { return RetrieveAndReturnArrayValue<object[]>(e); } public static implicit operator List<bool>(DataStorageElement e) { return RetrieveAndReturnArrayValue<List<bool>>(e); } public static implicit operator List<int>(DataStorageElement e) { return RetrieveAndReturnArrayValue<List<int>>(e); } public static implicit operator List<long>(DataStorageElement e) { return RetrieveAndReturnArrayValue<List<long>>(e); } public static implicit operator List<decimal>(DataStorageElement e) { return RetrieveAndReturnArrayValue<List<decimal>>(e); } public static implicit operator List<double>(DataStorageElement e) { return RetrieveAndReturnArrayValue<List<double>>(e); } public static implicit operator List<float>(DataStorageElement e) { return RetrieveAndReturnArrayValue<List<float>>(e); } public static implicit operator List<string>(DataStorageElement e) { return RetrieveAndReturnArrayValue<List<string>>(e); } public static implicit operator List<object>(DataStorageElement e) { return RetrieveAndReturnArrayValue<List<object>>(e); } public static implicit operator Array(DataStorageElement e) { return RetrieveAndReturnArrayValue<Array>(e); } public static implicit operator JArray(DataStorageElement e) { return RetrieveAndReturnArrayValue<JArray>(e); } public static implicit operator JToken(DataStorageElement e) { return e.Context.GetData(e.Context.Key); } public static DataStorageElement operator +(DataStorageElement a, BigInteger b) { return new DataStorageElement(a, OperationType.Add, JToken.Parse(b.ToString())); } public static DataStorageElement operator *(DataStorageElement a, BigInteger b) { return new DataStorageElement(a, OperationType.Mul, JToken.Parse(b.ToString())); } public static DataStorageElement operator %(DataStorageElement a, BigInteger b) { return new DataStorageElement(a, OperationType.Mod, JToken.Parse(b.ToString())); } public static DataStorageElement operator ^(DataStorageElement a, BigInteger b) { return new DataStorageElement(a, OperationType.Pow, JToken.Parse(b.ToString())); } public static DataStorageElement operator -(DataStorageElement a, BigInteger b) { return new DataStorageElement(a, OperationType.Add, JToken.Parse((-b).ToString())); } public static DataStorageElement operator /(DataStorageElement a, BigInteger b) { throw new InvalidOperationException("DataStorage[Key] / BigInterger is not supported, due to loss of precision when using integer division"); } public static implicit operator DataStorageElement(BigInteger bi) { return new DataStorageElement(OperationType.Replace, JToken.Parse(bi.ToString())); } public static implicit operator BigInteger(DataStorageElement e) { return RetrieveAndReturnBigIntegerValue<BigInteger>(e); } public static implicit operator BigInteger?(DataStorageElement e) { return RetrieveAndReturnBigIntegerValue<BigInteger?>(e); } private static T RetrieveAndReturnBigIntegerValue<T>(DataStorageElement e) { if (e.cachedValue != null) { if (!BigInteger.TryParse(((object)e.cachedValue).ToString(), out var result)) { return default(T); } return (T)Convert.ChangeType(result, IsNullable<T>() ? Nullable.GetUnderlyingType(typeof(T)) : typeof(T)); } BigInteger result2; BigInteger? bigInteger = (BigInteger.TryParse(((object)e.Context.GetData(e.Context.Key)).ToString(), out result2) ? new BigInteger?(result2) : null); if (!bigInteger.HasValue && !IsNullable<T>()) { bigInteger = Activator.CreateInstance<BigInteger>(); } foreach (OperationSpecification operation in e.Operations) { if (operation.OperationType == OperationType.Floor || operation.OperationType == OperationType.Ceil) { continue; } if (!BigInteger.TryParse(((object)operation.Value).ToString(), NumberStyles.AllowLeadingSign, null, out var result3)) { throw new InvalidOperationException($"DataStorage[Key] cannot be converted to BigInterger as its value its not an integer number, value: {operation.Value}"); } switch (operation.OperationType) { case OperationType.Replace: bigInteger = result3; break; case OperationType.Add: bigInteger += result3; break; case OperationType.Mul: bigInteger *= result3; break; case OperationType.Mod: bigInteger %= result3; break; case OperationType.Pow: bigInteger = BigInteger.Pow(bigInteger.Value, (int)operation.Value); break; case OperationType.Max: { BigInteger value = result3; BigInteger? bigInteger2 = bigInteger; if (value > bigInteger2) { bigInteger = result3; } break; } case OperationType.Min: { BigInteger value = result3; BigInteger? bigInteger2 = bigInteger; if (value < bigInteger2) { bigInteger = result3; } break; } case OperationType.Xor: bigInteger ^= result3; break; case OperationType.Or: bigInteger |= result3; break; case OperationType.And: bigInteger &= result3; break; case OperationType.LeftShift: bigInteger <<= (int)operation.Value; break; case OperationType.RightShift: bigInteger >>= (int)operation.Value; break; } } e.cachedValue = JToken.Parse(bigInteger.ToString()); if (!bigInteger.HasValue) { return default(T); } return (T)Convert.ChangeType(bigInteger.Value, IsNullable<T>() ? Nullable.GetUnderlyingType(typeof(T)) : typeof(T)); } public void Initialize(JToken value) { Context.Initialize(Context.Key, value); } public void Initialize(IEnumerable value) { Context.Initialize(Context.Key, (JToken)(object)JArray.FromObject((object)value)); } public Task<T> GetAsync<T>() { return GetAsync().ContinueWith((Task<JToken> r) => r.Result.ToObject<T>()); } public Task<JToken> GetAsync() { return Context.GetAsync(Context.Key); } private static T RetrieveAndReturnArrayValue<T>(DataStorageElement e) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Invalid comparison between Unknown and I4 //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Invalid comparison between Unknown and I4 //IL_00d7: Unknown result type (might be due to invalid IL or missing references) if (e.cachedValue != null) { return ((JToken)(JArray)e.cachedValue).ToObject<T>(); } JArray val = (JArray)(((object)e.Context.GetData(e.Context.Key).ToObject<JArray>()) ?? ((object)new JArray())); foreach (OperationSpecification operation in e.Operations) { switch (operation.OperationType) { case OperationType.Add: if ((int)operation.Value.Type != 2) { throw new InvalidOperationException($"Cannot perform operation {OperationType.Add} on Array value, with a non Array value: {operation.Value}"); } ((JContainer)val).Merge((object)operation.Value); break; case OperationType.Replace: if ((int)operation.Value.Type != 2) { throw new InvalidOperationException($"Cannot replace Array value, with a non Array value: {operation.Value}"); } val = (JArray)(((object)operation.Value.ToObject<JArray>()) ?? ((object)new JArray())); break; default: throw new InvalidOperationException($"Cannot perform operation {operation.OperationType} on Array value"); } } e.cachedValue = (JToken)(object)val; return ((JToken)val).ToObject<T>(); } private static string RetrieveAndReturnStringValue(DataStorageElement e) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Invalid comparison between Unknown and I4 //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Invalid comparison between Unknown and I4 if (e.cachedValue != null) { return (string)e.cachedValue; } JToken val = e.Context.GetData(e.Context.Key); string text = (((int)val.Type == 10) ? null : ((object)val).ToString()); foreach (OperationSpecification operation in e.Operations) { switch (operation.OperationType) { case OperationType.Add: text += (string)operation.Value; break; case OperationType.Mul: if ((int)operation.Value.Type != 6) { throw new InvalidOperationException($"Cannot perform operation {OperationType.Mul} on string value, with a non interger value: {operation.Value}"); } text = string.Concat(Enumerable.Repeat(text, (int)operation.Value)); break; case OperationType.Replace: text = (string)operation.Value; break; default: throw new InvalidOperationException($"Cannot perform operation {operation.OperationType} on string value"); } } if (text == null) { e.cachedValue = (JToken)(object)JValue.CreateNull(); } else { e.cachedValue = JToken.op_Implicit(text); } return (string)e.cachedValue; } private static T RetrieveAndReturnBoolValue<T>(DataStorageElement e) { if (e.cachedValue != null) { return e.cachedValue.ToObject<T>(); } bool? flag = e.Context.GetData(e.Context.Key).ToObject<bool?>() ?? ((bool?)Activator.CreateInstance(typeof(T))); foreach (OperationSpecification operation in e.Operations) { if (operation.OperationType == OperationType.Replace) { flag = (bool?)operation.Value; continue; } throw new InvalidOperationException($"Cannot perform operation {operation.OperationType} on boolean value"); } e.cachedValue = JToken.op_Implicit(flag); if (!flag.HasValue) { return default(T); } return (T)Convert.ChangeType(flag.Value, IsNullable<T>() ? Nullable.GetUnderlyingType(typeof(T)) : typeof(T)); } private static T RetrieveAndReturnDecimalValue<T>(DataStorageElement e) { if (e.cachedValue != null) { return e.cachedValue.ToObject<T>(); } decimal? num = e.Context.GetData(e.Context.Key).ToObject<decimal?>(); if (!num.HasValue && !IsNullable<T>()) { num = Activator.CreateInstance<decimal>(); } foreach (OperationSpecification operation in e.Operations) { switch (operation.OperationType) { case OperationType.Replace: num = (decimal)operation.Value; break; case OperationType.Add: num += (decimal?)(decimal)operation.Value; break; case OperationType.Mul: num *= (decimal?)(decimal)operation.Value; break; case OperationType.Mod: num %= (decimal?)(decimal)operation.Value; break; case OperationType.Pow: num = (decimal)Math.Pow((double)num.Value, (double)operation.Value); break; case OperationType.Max: num = Math.Max(num.Value, (decimal)operation.Value); break; case OperationType.Min: num = Math.Min(num.Value, (decimal)operation.Value); break; case OperationType.Xor: num = (long)num.Value ^ (long)operation.Value; break; case OperationType.Or: num = (long)num.Value | (long)operation.Value; break; case OperationType.And: num = (long)num.Value & (long)operation.Value; break; case OperationType.LeftShift: num = (long)num.Value << (int)operation.Value; break; case OperationType.RightShift: num = (long)num.Value >> (int)operation.Value; break; case OperationType.Floor: num = Math.Floor(num.Value); break; case OperationType.Ceil: num = Math.Ceiling(num.Value); break; } } e.cachedValue = JToken.op_Implicit(num); if (!num.HasValue) { return default(T); } return (T)Convert.ChangeType(num.Value, IsNullable<T>() ? Nullable.GetUnderlyingType(typeof(T)) : typeof(T)); } private static bool IsNullable<T>() { if (typeof(T).IsGenericType) { return typeof(T).GetGenericTypeDefinition() == typeof(Nullable<>).GetGenericTypeDefinition(); } return false; } public T To<T>() { if (Operations.Count != 0) { throw new InvalidOperationException("DataStorageElement.To<T>() cannot be used together with other operations on the DataStorageElement"); } return Context.GetData(Context.Key).ToObject<T>(); } public override string ToString() { return (Context?.ToString() ?? "(null)") + ", (" + ListOperations() + ")"; } private string ListOperations() { if (Operations != null) { return string.Join(", ", Operations.Select((OperationSpecification o) => o.ToString()).ToArray()); } return "none"; } } internal class DataStorageElementContext { internal string Key { get; set; } internal Action<string, DataStorageHelper.DataStorageUpdatedHandler> AddHandler { get; set; } internal Action<string, DataStorageHelper.DataStorageUpdatedHandler> RemoveHandler { get; set; } internal Func<string, JToken> GetData { get; set; } internal Action<string, JToken> Initialize { get; set; } internal Func<string, Task<JToken>> GetAsync { get; set; } public override string ToString() { return "Key: " + Key; } } public class GameData { [JsonProperty("location_name_to_id")] public Dictionary<string, long> LocationLookup { get; set; } = new Dictionary<string, long>(); [JsonProperty("item_name_to_id")] public Dictionary<string, long> ItemLookup { get; set; } = new Dictionary<string, long>(); [Obsolete("use Checksum instead")] [JsonProperty("version")] public int Version { get; set; } [JsonProperty("checksum")] public string Checksum { get; set; } } public class Hint { [JsonProperty("receiving_player")] public int ReceivingPlayer { get; set; } [JsonProperty("finding_player")] public int FindingPlayer { get; set; } [JsonProperty("item")] public long ItemId { get; set; } [JsonProperty("location")] public long LocationId { get; set; } [JsonProperty("item_flags")] public ItemFlags ItemFlags { get; set; } [JsonProperty("found")] public bool Found { get; set; } [JsonProperty("entrance")] public string Entrance { get; set; } [JsonProperty("status")] public HintStatus Status { get; set; } } public class ItemInfo { private readonly IItemInfoResolver itemInfoResolver; public long ItemId { get; } public long LocationId { get; } public PlayerInfo Player { get; } public ItemFlags Flags { get; } public string ItemName => itemInfoResolver.GetItemName(ItemId, ItemGame); public string ItemDisplayName => ItemName ?? $"Item: {ItemId}"; public string LocationName => itemInfoResolver.GetLocationName(LocationId, LocationGame); public string LocationDisplayName => LocationName ?? $"Location: {LocationId}"; public string ItemGame { get; } public string LocationGame { get; } public ItemInfo(NetworkItem item, string receiverGame, string senderGame, IItemInfoResolver itemInfoResolver, PlayerInfo player) { this.itemInfoResolver = itemInfoResolver; ItemGame = receiverGame; LocationGame = senderGame; ItemId = item.Item; LocationId = item.Location; Flags = item.Flags; Player = player; } public SerializableItemInfo ToSerializable() { return new SerializableItemInfo { IsScout = (GetType() == typeof(ScoutedItemInfo)), ItemId = ItemId, LocationId = LocationId, PlayerSlot = Player, Player = Player, Flags = Flags, ItemGame = ItemGame, ItemName = ItemName, LocationGame = LocationGame, LocationName = LocationName }; } } public class ScoutedItemInfo : ItemInfo { public new PlayerInfo Player => base.Player; public bool IsReceiverRelatedToActivePlayer { get; } public ScoutedItemInfo(NetworkItem item, string receiverGame, string senderGame, IItemInfoResolver itemInfoResolver, IPlayerHelper players, PlayerInfo player) : base(item, receiverGame, senderGame, itemInfoResolver, player) { IsReceiverRelatedToActivePlayer = (players.ActivePlayer ?? new PlayerInfo()).IsRelatedTo(player); } } public class JsonMessagePart { [JsonProperty("type")] [JsonConverter(typeof(StringEnumConverter), new object[] { typeof(SnakeCaseNamingStrategy) })] public JsonMessagePartType? Type { get; set; } [JsonProperty("color")] [JsonConverter(typeof(StringEnumConverter), new object[] { typeof(SnakeCaseNamingStrategy) })] public JsonMessagePartColor? Color { get; set; } [JsonProperty("text")] public string Text { get; set; } [JsonProperty("player")] public int? Player { get; set; } [JsonProperty("flags")] public ItemFlags? Flags { get; set; } [JsonProperty("hint_status")] public HintStatus? HintStatus { get; set; } } public struct NetworkItem { [JsonProperty("item")] public long Item { get; set; } [JsonProperty("location")] public long Location { get; set; } [JsonProperty("player")] public int Player { get; set; } [JsonProperty("flags")] public ItemFlags Flags { get; set; } } public struct NetworkPlayer { [JsonProperty("team")] public int Team { get; set; } [JsonProperty("slot")] public int Slot { get; set; } [JsonProperty("alias")] public string Alias { get; set; } [JsonProperty("name")] public string Name { get; set; } } public struct NetworkSlot { [JsonProperty("name")] public string Name { get; set; } [JsonProperty("game")] public string Game { get; set; } [JsonProperty("type")] public SlotType Type { get; set; } [JsonProperty("group_members")] public int[] GroupMembers { get; set; } } public class NetworkVersion { [JsonProperty("major")] public int Major { get; set; } [JsonProperty("minor")] public int Minor { get; set; } [JsonProperty("build")] public int Build { get; set; } [JsonProperty("class")] public string Class => "Version"; public NetworkVersion() { } public NetworkVersion(int major, int minor, int build) { Major = major; Minor = minor; Build = build; } public NetworkVersion(Version version) { Major = version.Major; Minor = version.Minor; Build = version.Build; } public Version ToVersion() { return new Version(Major, Minor, Build); } } public class OperationSpecification { [JsonProperty("operation")] [JsonConverter(typeof(StringEnumConverter), new object[] { typeof(SnakeCaseNamingStrategy) })] public OperationType OperationType; [JsonProperty("value")] public JToken Value { get; set; } public override string ToString() { return $"{OperationType}: {Value}"; } } public static class Operation { public static OperationSpecification Min(int i) { return new OperationSpecification { OperationType = OperationType.Min, Value = JToken.op_Implicit(i) }; } public static OperationSpecification Min(long i) { return new OperationSpecification { OperationType = OperationType.Min, Value = JToken.op_Implicit(i) }; } public static OperationSpecification Min(float i) { return new OperationSpecification { OperationType = OperationType.Min, Value = JToken.op_Implicit(i) }; } public static OperationSpecification Min(double i) { return new OperationSpecification { OperationType = OperationType.Min, Value = JToken.op_Implicit(i) }; } public static OperationSpecification Min(decimal i) { return new OperationSpecification { OperationType = OperationType.Min, Value = JToken.op_Implicit(i) }; } public static OperationSpecification Min(JToken i) { return new OperationSpecification { OperationType = OperationType.Min, Value = i }; } public static OperationSpecification Min(BigInteger i) { return new OperationSpecification { OperationType = OperationType.Min, Value = JToken.Parse(i.ToString()) }; } public static OperationSpecification Max(int i) { return new OperationSpecification { OperationType = OperationType.Max, Value = JToken.op_Implicit(i) }; } public static OperationSpecification Max(long i) { return new OperationSpecification { OperationType = OperationType.Max, Value = JToken.op_Implicit(i) }; } public static OperationSpecification Max(float i) { return new OperationSpecification { OperationType = OperationType.Max, Value = JToken.op_Implicit(i) }; } public static OperationSpecification Max(double i) { return new OperationSpecification { OperationType = OperationType.Max, Value = JToken.op_Implicit(i) }; } public static OperationSpecification Max(decimal i) { return new OperationSpecification { OperationType = OperationType.Max, Value = JToken.op_Implicit(i) }; } public static OperationSpecification Max(JToken i) { return new OperationSpecification { OperationType = OperationType.Max, Value = i }; } public static OperationSpecification Max(BigInteger i) { return new OperationSpecification { OperationType = OperationType.Max, Value = JToken.Parse(i.ToString()) }; } public static OperationSpecification Remove(JToken value) { return new OperationSpecification { OperationType = OperationType.Remove, Value = value }; } public static OperationSpecification Pop(int value) { return new OperationSpecification { OperationType = OperationType.Pop, Value = JToken.op_Implicit(value) }; } public static OperationSpecification Pop(JToken value) { return new OperationSpecification { OperationType = OperationType.Pop, Value = value }; } public static OperationSpecification Update(IDictionary dictionary) { return new OperationSpecification { OperationType = OperationType.Update, Value = (JToken)(object)JObject.FromObject((object)dictionary) }; } public static OperationSpecification Floor() { return new OperationSpecification { OperationType = OperationType.Floor, Value = null }; } public static OperationSpecification Ceiling() { return new OperationSpecification { OperationType = OperationType.Ceil, Value = null }; } } public static class Bitwise { public static OperationSpecification Xor(long i) { return new OperationSpecification { OperationType = OperationType.Xor, Value = JToken.op_Implicit(i) }; } public static OperationSpecification Xor(BigInteger i) { return new OperationSpecification { OperationType = OperationType.Xor, Value = JToken.Parse(i.ToString()) }; } public static OperationSpecification Or(long i) { return new OperationSpecification { OperationType = OperationType.Or, Value = JToken.op_Implicit(i) }; } public static OperationSpecification Or(BigInteger i) { return new OperationSpecification { OperationType = OperationType.Or, Value = JToken.Parse(i.ToString()) }; } public static OperationSpecification And(long i) { return new OperationSpecification { OperationType = OperationType.And, Value = JToken.op_Implicit(i) }; } public static OperationSpecification And(BigInteger i) { return new OperationSpecification { OperationType = OperationType.And, Value = JToken.Parse(i.ToString()) }; } public static OperationSpecification LeftShift(long i) { return new OperationSpecification { OperationType = OperationType.LeftShift, Value = JToken.op_Implicit(i) }; } public static OperationSpecification RightShift(long i) { return new OperationSpecification { OperationType = OperationType.RightShift, Value = JToken.op_Implicit(i) }; } } public class Callback { internal DataStorageHelper.DataStorageUpdatedHandler Method { get; set; } private Callback() { } public static Callback Add(DataStorageHelper.DataStorageUpdatedHandler callback) { return new Callback { Method = callback }; } } public class AdditionalArgument { internal string Key { get; set; } internal JToken Value { get; set; } private AdditionalArgument() { } public static AdditionalArgument Add(string name, JToken value) { return new AdditionalArgument { Key = name, Value = value }; } } public class MinimalSerializableItemInfo { public long ItemId { get; set; } public long LocationId { get; set; } public int PlayerSlot { get; set; } public ItemFlags Flags { get; set; } public string ItemGame { get; set; } public string LocationGame { get; set; } } public class SerializableItemInfo : MinimalSerializableItemInfo { public bool IsScout { get; set; } public PlayerInfo Player { get; set; } public string ItemName { get; set; } public string LocationName { get; set; } [JsonIgnore] public string ItemDisplayName => ItemName ?? $"Item: {base.ItemId}"; [JsonIgnore] public string LocationDisplayName => LocationName ?? $"Location: {base.LocationId}"; public string ToJson(bool full = false) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown MinimalSerializableItemInfo minimalSerializableItemInfo = this; if (!full) { minimalSerializableItemInfo = new MinimalSerializableItemInfo { ItemId = base.ItemId, LocationId = base.LocationId, PlayerSlot = base.PlayerSlot, Flags = base.Flags }; if (IsScout) { minimalSerializableItemInfo.ItemGame = base.ItemGame; } else { minimalSerializableItemInfo.LocationGame = base.LocationGame; } } JsonSerializerSettings val = new JsonSerializerSettings { NullValueHandling = (NullValueHandling)1, Formatting = (Formatting)0 }; return JsonConvert.SerializeObject((object)minimalSerializableItemInfo, val); } public static SerializableItemInfo FromJson(string json, IArchipelagoSession session = null) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown ItemInfoStreamingContext additional = ((session != null) ? new ItemInfoStreamingContext { Items = session.Items, Locations = session.Locations, PlayerHelper = session.Players, ConnectionInfo = session.ConnectionInfo } : null); JsonSerializerSettings val = new JsonSerializerSettings { Context = new StreamingContext(StreamingContextStates.Other, additional) }; return JsonConvert.DeserializeObject<SerializableItemInfo>(json, val); } [OnDeserialized] internal void OnDeserializedMethod(StreamingContext streamingContext) { if (base.ItemGame == null && base.LocationGame != null) { IsScout = false; } else if (base.ItemGame != null && base.LocationGame == null) { IsScout = true; } if (streamingContext.Context is ItemInfoStreamingContext itemInfoStreamingContext) { if (IsScout && base.LocationGame == null) { base.LocationGame = itemInfoStreamingContext.ConnectionInfo.Game; } else if (!IsScout && base.ItemGame == null) { base.ItemGame = itemInfoStreamingContext.ConnectionInfo.Game; } if (ItemName == null) { ItemName = itemInfoStreamingContext.Items.GetItemName(base.ItemId, base.ItemGame); } if (LocationName == null) { LocationName = itemInfoStreamingContext.Locations.GetLocationNameFromId(base.LocationId, base.LocationGame); } if (Player == null) { Player = itemInfoStreamingContext.PlayerHelper.GetPlayerInfo(base.PlayerSlot); } } } } internal class ItemInfoStreamingContext { public IReceivedItemsHelper Items { get; set; } public ILocationCheckHelper Locations { get; set; } public IPlayerHelper PlayerHelper { get; set; } public IConnectionInfoProvider ConnectionInfo { get; set; } } } namespace Archipelago.MultiClient.Net.MessageLog.Parts { public class EntranceMessagePart : MessagePart { internal EntranceMessagePart(JsonMessagePart messagePart) : base(MessagePartType.Entrance, messagePart, Archipelago.MultiClient.Net.Colors.PaletteColor.Blue) { base.Text = messagePart.Text; } } public class HintStatusMessagePart : MessagePart { internal HintStatusMessagePart(JsonMessagePart messagePart) : base(MessagePartType.HintStatus, messagePart) { base.Text = messagePart.Text; if (messagePart.HintStatus.HasValue) { base.PaletteColor = ColorUtils.GetColor(messagePart.HintStatus.Value); } } } public class ItemMessagePart : MessagePart { public ItemFlags Flags { get; } public long ItemId { get; } public int Player { get; } internal ItemMessagePart(IPlayerHelper players, IItemInfoResolver items, JsonMessagePart part) : base(MessagePartType.Item, part) { Flags = part.Flags.GetValueOrDefault(); base.PaletteColor = ColorUtils.GetColor(Flags); Player = part.Player.GetValueOrDefault(); string game = (players.GetPlayerInfo(Player) ?? new PlayerInfo()).Game; JsonMessagePartType? type = part.Type; if (type.HasValue) { switch (type.GetValueOrDefault()) { case JsonMessagePartType.ItemId: ItemId = long.Parse(part.Text); base.Text = items.GetItemName(ItemId, game) ?? $"Item: {ItemId}"; break; case JsonMessagePartType.ItemName: ItemId = 0L; base.Text = part.Text; break; } } } } public class LocationMessagePart : MessagePart { public long LocationId { get; } public int Player { get; } internal LocationMessagePart(IPlayerHelper players, IItemInfoResolver itemInfoResolver, JsonMessagePart part) : base(MessagePartType.Location, part, Archipelago.MultiClient.Net.Colors.PaletteColor.Green) { Player = part.Player.GetValueOrDefault(); string game = (players.GetPlayerInfo(Player) ?? new PlayerInfo()).Game; JsonMessagePartType? type = part.Type; if (type.HasValue) { switch (type.GetValueOrDefault()) { case JsonMessagePartType.LocationId: LocationId = long.Parse(part.Text); base.Text = itemInfoResolver.GetLocationName(LocationId, game) ?? $"Location: {LocationId}"; break; case JsonMessagePartType.LocationName: LocationId = itemInfoResolver.GetLocationId(part.Text, game); base.Text = part.Text; break; } } } } public class MessagePart { public string Text { get; internal set; } public MessagePartType Type { get; internal set; } public Color Color => GetColor(BuiltInPalettes.Dark); public PaletteColor? PaletteColor { get; protected set; } public bool IsBackgroundColor { get; internal set; } internal MessagePart(MessagePartType type, JsonMessagePart messagePart, PaletteColor? color = null) { Type = type; Text = messagePart.Text; if (color.HasValue) { PaletteColor = color.Value; } else if (messagePart.Color.HasValue) { PaletteColor = ColorUtils.GetColor(messagePart.Color.Value); IsBackgroundColor = messagePart.Color.Value >= JsonMessagePartColor.BlackBg; } else { PaletteColor = null; } } public T GetColor<T>(Palette<T> palette) { return palette[PaletteColor]; } public override string ToString() { return Text; } } public enum MessagePartType { Text, Player, Item, Location, Entrance, HintStatus } public class PlayerMessagePart : MessagePart { public bool IsActivePlayer { get; } public int SlotId { get; } internal PlayerMessagePart(IPlayerHelper players, IConnectionInfoProvider connectionInfo, JsonMessagePart part) : base(MessagePartType.Player, part) { switch (part.Type) { case JsonMessagePartType.PlayerId: SlotId = int.Parse(part.Text); IsActivePlayer = SlotId == connectionInfo.Slot; base.Text = players.GetPlayerAlias(SlotId) ?? $"Player {SlotId}"; break; case JsonMessagePartType.PlayerName: SlotId = 0; IsActivePlayer = false; base.Text = part.Text; break; } base.PaletteColor = (IsActivePlayer ? Archipelago.MultiClient.Net.Colors.PaletteColor.Magenta : Archipelago.MultiClient.Net.Colors.PaletteColor.Yellow); } } } namespace Archipelago.MultiClient.Net.MessageLog.Messages { public class AdminCommandResultLogMessage : LogMessage { internal AdminCommandResultLogMessage(MessagePart[] parts) : base(parts) { } } public class ChatLogMessage : PlayerSpecificLogMessage { public string Message { get; } internal ChatLogMessage(MessagePart[] parts, IPlayerHelper players, int team, int slot, string message) : base(parts, players, team, slot) { Message = message; } } public class CollectLogMessage : PlayerSpecificLogMessage { internal CollectLogMessage(MessagePart[] parts, IPlayerHelper players, int team, int slot) : base(parts, players, team, slot) { } } public class CommandResultLogMessage : LogMessage { internal CommandResultLogMessage(MessagePart[] parts) : base(parts) { } } public class CountdownLogMessage : LogMessage { public int RemainingSeconds { get; } internal CountdownLogMessage(MessagePart[] parts, int remainingSeconds) : base(parts) { RemainingSeconds = remainingSeconds; } } public class GoalLogMessage : PlayerSpecificLogMessage { internal GoalLogMessage(MessagePart[] parts, IPlayerHelper players, int team, int slot) : base(parts, players, team, slot) { } } public class HintItemSendLogMessage : ItemSendLogMessage { public bool IsFound { get; } internal HintItemSendLogMessage(MessagePart[] parts, IPlayerHelper players, int receiver, int sender, NetworkItem item, bool found, IItemInfoResolver itemInfoResolver) : base(parts, players, receiver, sender, item, itemInfoResolver) { IsFound = found; } } public class ItemCheatLogMessage : ItemSendLogMessage { internal ItemCheatLogMessage(MessagePart[] parts, IPlayerHelper players, int team, int slot, NetworkItem item, IItemInfoResolver itemInfoResolver) : base(parts, players, slot, 0, item, team, itemInfoResolver) { } } public class ItemSendLogMessage : LogMessage { private PlayerInfo ActivePlayer { get; } public PlayerInfo Receiver { get; } public PlayerInfo Sender { get; } public bool IsReceiverTheActivePlayer => Receiver == ActivePlayer; public bool IsSenderTheActivePlayer => Sender == ActivePlayer; public bool IsRelatedToActivePlayer { get { if (!ActivePlayer.IsRelatedTo(Receiver)) { return ActivePlayer.IsRelatedTo(Sender); } return true; } } public ItemInfo Item { get; } internal ItemSendLogMessage(MessagePart[] parts, IPlayerHelper players, int receiver, int sender, NetworkItem item, IItemInfoResolver itemInfoResolver) : this(parts, players, receiver, sender, item, players.ActivePlayer.Team, itemInfoResolver) { } internal ItemSendLogMessage(MessagePart[] parts, IPlayerHelper players, int receiver, int sender, NetworkItem item, int team, IItemInfoResolver itemInfoResolver) : base(parts) { ActivePlayer = players.ActivePlayer ?? new PlayerInfo(); Receiver = players.GetPlayerInfo(team, receiver) ?? new PlayerInfo(); Sender = players.GetPlayerInfo(team, sender) ?? new PlayerInfo(); PlayerInfo player = players.GetPlayerInfo(team, item.Player) ?? new PlayerInfo(); Item = new ItemInfo(item, Receiver.Game, Sender.Game, itemInfoResolver, player); } } public class JoinLogMessage : PlayerSpecificLogMessage { public string[] Tags { get; } internal JoinLogMessage(MessagePart[] parts, IPlayerHelper players, int team, int slot, string[] tags) : base(parts, players, team, slot) { Tags = tags; } } public class LeaveLogMessage : PlayerSpecificLogMessage { internal LeaveLogMessage(MessagePart[] parts, IPlayerHelper players, int team, int slot) : base(parts, players, team, slot) { } } public class LogMessage { public MessagePart[] Parts { get; } internal LogMessage(MessagePart[] parts) { Parts = parts; } public override string ToString() { if (Parts.Length == 1) { return Parts[0].Text; } StringBuilder stringBuilder = new StringBuilder(); MessagePart[] parts = Parts; foreach (MessagePart messagePart in parts) { stringBuilder.Append(messagePart.Text); } return stringBuilder.ToString(); } } public abstract class PlayerSpecificLogMessage : LogMessage { private PlayerInfo ActivePlayer { get; } public PlayerInfo Player { get; } public bool IsActivePlayer => Player == ActivePlayer; public bool IsRelatedToActivePlayer => ActivePlayer.IsRelatedTo(Player); internal PlayerSpecificLogMessage(MessagePart[] parts, IPlayerHelper players, int team, int slot) : base(parts) { ActivePlayer = players.ActivePlayer ?? new PlayerInfo(); Player = players.GetPlayerInfo(team, slot) ?? new PlayerInfo(); } } public class ReleaseLogMessage : PlayerSpecificLogMessage { internal ReleaseLogMessage(MessagePart[] parts, IPlayerHelper players, int team, int slot) : base(parts, players, team, slot) { } } public class ServerChatLogMessage : LogMessage { public string Message { get; } internal ServerChatLogMessage(MessagePart[] parts, string message) : base(parts) { Message = message; } } public class TagsChangedLogMessage : PlayerSpecificLogMessage { public string[] Tags { get; } internal TagsChangedLogMessage(MessagePart[] parts, IPlayerHelper players, int team, int slot, string[] tags) : base(parts, players, team, slot) { Tags = tags; } } public class TutorialLogMessage : LogMessage { internal TutorialLogMessage(MessagePart[] parts) : base(parts) { } } } namespace Archipelago.MultiClient.Net.Helpers { public class ArchipelagoSocketHelper : BaseArchipelagoSocketHelper<ClientWebSocket>, IArchipelagoSocketHelper { public Uri Uri { get; } internal ArchipelagoSocketHelper(Uri hostUri) : base(CreateWebSocket(), 1024) { Uri = hostUri; } private static ClientWebSocket CreateWebSocket() { return new ClientWebSocket(); } public async Task ConnectAsync() { await ConnectToProvidedUri(Uri); StartPolling(); } private async Task ConnectToProvidedUri(Uri uri) { if (uri.Scheme != "unspecified") { try { await Socket.ConnectAsync(uri, CancellationToken.None); return; } catch (Exception e) { OnError(e); throw; } } List<Exception> errors = new List<Exception>(0); try { await Socket.ConnectAsync(uri.AsWss(), CancellationToken.None); if (Socket.State == WebSocketState.Open) { return; } } catch (Exception item) { errors.Add(item); Socket = CreateWebSocket(); } try { await Socket.ConnectAsync(uri.AsWs(), CancellationToken.None); } catch (Exception item2) { errors.Add(item2); OnError(new AggregateException(errors)); throw; } } } public class BaseArchipelagoSocketHelper<T> where T : WebSocket { private static readonly ArchipelagoPacketConverter Converter = new ArchipelagoPacketConverter(); private readonly BlockingCollection<Tuple<ArchipelagoPacketBase, TaskCompletionSource<bool>>> sendQueue = new BlockingCollection<Tuple<ArchipelagoPacketBase, TaskCompletionSource<bool>>>(); internal T Socket; private readonly int bufferSize; public bool Connected { get { if (Socket.State != WebSocketState.Open) { return Socket.State == WebSocketState.CloseReceived; } return true; } } public event ArchipelagoSocketHelperDelagates.PacketReceivedHandler PacketReceived; public event ArchipelagoSocketHelperDelagates.PacketsSentHandler PacketsSent; public event ArchipelagoSocketHelperDelagates.ErrorReceivedHandler ErrorReceived; public event ArchipelagoSocketHelperDelagates.SocketClosedHandler SocketClosed; public event ArchipelagoSocketHelperDelagates.SocketOpenedHandler SocketOpened; internal BaseArchipelagoSocketHelper(T socket, int bufferSize = 1024) { Socket = socket; this.bufferSize = bufferSize; } internal void StartPolling() { if (this.SocketOpened != null) { this.SocketOpened(); } Task.Run((Func<Task?>)PollingLoop); Task.Run((Func<Task?>)SendLoop); } private async Task PollingLoop() { byte[] buffer = new byte[bufferSize]; while (Socket.State == WebSocketState.Open) { string message = null; try { message = await ReadMessageAsync(buffer); } catch (Exception e) { OnError(e); } OnMessageReceived(message); } } private async Task SendLoop() { while (Socket.State == WebSocketState.Open) { try { await HandleSendBuffer(); } catch (Exception e) { OnError(e); } await Task.Delay(20); } } private async Task<string> ReadMessageAsync(byte[] buffer) { using MemoryStream readStream = new MemoryStream(buffer.Length); WebSocketReceiveResult result; do { result = await Socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None); if (result.MessageType == WebSocketMessageType.Close) { try { await Socket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); } catch { } OnSocketClosed(); } else { readStream.Write(buffer, 0, result.Count); } } while (!result.EndOfMessage); return Encoding.UTF8.GetString(readStream.ToArray()); } public async Task DisconnectAsync() { await Socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closure requested by client", CancellationToken.None); OnSocketClosed(); } public void SendPacket(ArchipelagoPacketBase packet) { SendMultiplePackets(new List<ArchipelagoPacketBase> { packet }); } public void SendMultiplePackets(List<ArchipelagoPacketBase> packets) { SendMultiplePackets(packets.ToArray()); } public void SendMultiplePackets(params ArchipelagoPacketBase[] packets) { SendMultiplePacketsAsync(packets).Wait(); } public Task SendPacketAsync(ArchipelagoPacketBase packet) { return SendMultiplePacketsAsync(new List<ArchipelagoPacketBase> { packet }); } public Task SendMultiplePacketsAsync(List<ArchipelagoPacketBase> packets) { return SendMultiplePacketsAsync(packets.ToArray()); } public Task SendMultiplePacketsAsync(params ArchipelagoPacketBase[] packets) { TaskCompletionSource<bool> taskCompletionSource = new TaskCompletionSource<bool>(); foreach (ArchipelagoPacketBase item in packets) { sendQueue.Add(new Tuple<ArchipelagoPacketBase, TaskCompletionSource<bool>>(item, taskCompletionSource)); } return taskCompletionSource.Task; } private async Task HandleSendBuffer() { List<ArchipelagoPacketBase> list = new List<ArchipelagoPacketBase>(); List<TaskCompletionSource<bool>> tasks = new List<TaskCompletionSource<bool>>(); Tuple<ArchipelagoPacketBase, TaskCompletionSource<bool>> tuple = sendQueue.Take(); list.Add(tuple.Item1); tasks.Add(tuple.Item2); Tuple<ArchipelagoPacketBase, TaskCompletionSource<bool>> item; while (sendQueue.TryTake(out item)) { list.Add(item.Item1); tasks.Add(item.Item2); } if (!list.Any()) { return; } if (Socket.State != WebSocketState.Open) { throw new ArchipelagoSocketClosedException(); } ArchipelagoPacketBase[] packets = list.ToArray(); string s = JsonConvert.SerializeObject((object)packets); byte[] messageBuffer = Encoding.UTF8.GetBytes(s); int messagesCount = (int)Math.Ceiling((double)messageBuffer.Length / (double)bufferSize); for (int i = 0; i < messagesCount; i++) { int num = bufferSize * i; int num2 = bufferSize; bool endOfMessage = i + 1 == messagesCount; if (num2 * (i + 1) > messageBuffer.Length) { num2 = messageBuffer.Length - num; } await Socket.SendAsync(new ArraySegment<byte>(messageBuffer, num, num2), WebSocketMessageType.Text, endOfMessage, CancellationToken.None); } foreach (TaskCompletionSource<bool> item2 in tasks) { item2.TrySetResult(result: true); } OnPacketSend(packets); } private void OnPacketSend(ArchipelagoPacketBase[] packets) { try { if (this.PacketsSent != null) { this.PacketsSent(packets); } } catch (Exception e) { OnError(e); } } private void OnSocketClosed() { try { if (this.SocketClosed != null) { this.SocketClosed(""); } } catch (Exception e) { OnError(e); } } private void OnMessageReceived(string message) { try { if (string.IsNullOrEmpty(message) || this.PacketReceived == null) { return; } List<ArchipelagoPacketBase> list = null; try { list = JsonConvert.DeserializeObject<List<ArchipelagoPacketBase>>(message, (JsonConverter[])(object)new JsonConverter[1] { Converter }); } catch (Exception e) { OnError(e); } if (list == null) { return; } foreach (ArchipelagoPacketBase item in list) { this.PacketReceived(item); } } catch (Exception e2) { OnError(e2); } } protected void OnError(Exception e) { try { if (this.ErrorReceived != null) { this.ErrorReceived(e, e.Message); } } catch (Exception ex) { Console.Out.WriteLine("Error occured during reporting of errorOuter Errror: " + e.Message + " " + e.StackTrace + "Inner Errror: " + ex.Message + " " + ex.StackTrace); } } } public interface IConnectionInfoProvider { string Game { get; } int Team { get; } int Slot { get; } string[] Tags { get; } ItemsHandlingFlags ItemsHandlingFlags { get; } string Uuid { get; } void UpdateConnectionOptions(string[] tags); void UpdateConnectionOptions(ItemsHandlingFlags itemsHandlingFlags); void UpdateConnectionOptions(string[] tags, ItemsHandlingFlags itemsHandlingFlags); } public class ConnectionInfoHelper : IConnectionInfoProvider { private readonly IArchipelagoSocketHelper socket; public string Game { get; private set; } public int Team { get; private set; } public int Slot { get; private set; } public string[] Tags { get; internal set; } public ItemsHandlingFlags ItemsHandlingFlags { get; internal set; } public string Uuid { get; private set; } internal ConnectionInfoHelper(IArchipelagoSocketHelper socket) { this.socket = socket; Reset(); socket.PacketReceived += PacketReceived; } private void PacketReceived(ArchipelagoPacketBase packet) { if (!(packet is ConnectedPacket connectedPacket)) { if (packet is ConnectionRefusedPacket) { Reset(); } return; } Team = connectedPacket.Team; Slot = connectedPacket.Slot; if (connectedPacket.SlotInfo != null && connectedPacket.SlotInfo.ContainsKey(Slot)) { Game = connectedPacket.SlotInfo[Slot].Game; } } internal void SetConnectionParameters(string game, string[] tags, ItemsHandlingFlags itemsHandlingFlags, string uuid) { Game = game; Tags = tags ?? new string[0]; ItemsHandlingFlags = itemsHandlingFlags; Uuid = uuid ?? Guid.NewGuid().ToString(); } private void Reset() { Game = null; Team = -1; Slot = -1; Tags = new string[0]; ItemsHandlingFlags = ItemsHandlingFlags.NoItems; Uuid = null; } public void UpdateConnectionOptions(string[] tags) { UpdateConnectionOptions(tags, ItemsHandlingFlags); } public void UpdateConnectionOptions(ItemsHandlingFlags itemsHandlingFlags) { UpdateConnectionOptions(Tags, ItemsHandlingFlags); } public void UpdateConnectionOptions(string[] tags, ItemsHandlingFlags itemsHandlingFlags) { SetConnectionParameters(Game, tags, itemsHandlingFlags, Uuid); socket.SendPacket(new ConnectUpdatePacket { Tags = Tags, ItemsHandling = ItemsHandlingFlags }); } } public interface IDataStorageHelper : IDataStorageWrapper { DataStorageElement this[Scope scope, string key] { get; set; } DataStorageElement this[string key] { get; set; } } public class DataStorageHelper : IDataStorageHelper, IDataStorageWrapper { public delegate void DataStorageUpdatedHandler(JToken originalValue, JToken newValue, Dictionary<string, JToken> additionalArguments); private readonly Dictionary<string, DataStorageUpdatedHandler> onValueChangedEventHandlers = new Dictionary<string, DataStorageUpdatedHandler>(); private readonly Dictionary<Guid, DataStorageUpdatedHandler> operationSpecificCallbacks = new Dictionary<Guid, DataStorageUpdatedHandler>(); private readonly Dictionary<string, TaskCompletionSource<JToken>> asyncRetrievalTasks = new Dictionary<string, TaskCompletionSource<JToken>>(); private readonly IArchipelagoSocketHelper socket; private readonly IConnectionInfoProvider connectionInfoProvider; public DataStorageElement this[Scope scope, string key] { get { return this[AddScope(scope, key)]; } set { this[AddScope(scope, key)] = value; } } public DataStorageElement this[string key] { get { return new DataStorageElement(GetContextForKey(key)); } set { SetValue(key, value); } } internal DataStorageHelper(IArchipelagoSocketHelper socket, IConnectionInfoProvider connectionInfoProvider) { this.socket = socket; this.connectionInfoProvider = connectionInfoProvider; socket.PacketReceived += OnPacketReceived; } private void OnPacketReceived(ArchipelagoPacketBase packet) { //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Invalid comparison between Unknown and I4 if (!(packet is RetrievedPacket retrievedPacket)) { if (packet is SetReplyPacket setReplyPacket) { if (setReplyPacket.AdditionalArguments != null && setReplyPacket.AdditionalArguments.ContainsKey("Reference") && (int)setReplyPacket.AdditionalArguments["Reference"].Type == 15 && operationSpecificCallbacks.TryGetValue((Guid)setReplyPacket.AdditionalArguments["Reference"], out var value)) { value(setReplyPacket.OriginalValue, setReplyPacket.Value, setReplyPacket.AdditionalArguments); operationSpecificCallbacks.Remove((Guid)setReplyPacket.AdditionalArguments["Reference"]); } if (onValueChangedEventHandlers.TryGetValue(setReplyPacket.Key, out var value2)) { value2(setReplyPacket.OriginalValue, setReplyPacket.Value, setReplyPacket.AdditionalArguments); } } return; } foreach (KeyValuePair<string, JToken> datum in retrievedPacket.Data) { if (asyncRetrievalTasks.TryGetValue(datum.Key, out var value3)) { value3.TrySetResult(datum.Value); asyncRetrievalTasks.Remove(datum.Key); } } } private Task<JToken> GetAsync(string key) { if (asyncRetrievalTasks.TryGetValue(key, out var value)) { return value.Task; } TaskCompletionSource<JToken> taskCompletionSource = new TaskCompletionSource<JToken>(); asyncRetrievalTasks[key] = taskCompletionSource; socket.SendPacketAsync(new GetPacket { Keys = new string[1] { key } }); return taskCompletionSource.Task; } private void Initialize(string key, JToken value) { socket.SendPacketAsync(new SetPacket { Key = key, DefaultValue = value, Operations = new OperationSpecification[1] { new OperationSpecification { OperationType = OperationType.Default } } }); } private JToken GetValue(string key) { Task<JToken> async = GetAsync(key); if (!async.Wait(TimeSpan.FromSeconds(2.0))) { throw new TimeoutException("Timed out retrieving data for key `" + key + "`. This may be due to an attempt to retrieve a value from the DataStorageHelper in a synchronous fashion from within a PacketReceived handler. When using the DataStorageHelper from within code which runs on the websocket thread then use the asynchronous getters. Ex: `DataStorageHelper[\"" + key + "\"].GetAsync().ContinueWith(x => {});`Be aware that DataStorageHelper calls tend to cause packet responses, so making a call from within a PacketReceived handler may cause an infinite loop."); } return async.Result; } private void SetValue(string key, DataStorageElement e) { if (key.StartsWith("_read_")) { throw new InvalidOperationException("DataStorage write operation on readonly key '" + key + "' is not allowed"); } if (e == null) { e = new DataStorageElement(OperationType.Replace, (JToken)(object)JValue.CreateNull()); } if (e.Context == null) { e.Context = GetContextForKey(key); } else if (e.Context.Key != key) { e.Operations.Insert(0, new OperationSpecification { OperationType = OperationType.Replace, Value = GetValue(e.Context.Key) }); } Dictionary<string, JToken> dictionary = e.AdditionalArguments ?? new Dictionary<string, JToken>(0); if (e.Callbacks != null) { Guid guid = Guid.NewGuid(); operationSpecificCallbacks[guid] = e.Callbacks; dictionary["Reference"] = JToken.FromObject((object)guid); socket.SendPacketAsync(new SetPacket { Key = key, Operations = e.Operations.ToArray(), WantReply = true, AdditionalArguments = dictionary }); } else { socket.SendPacketAsync(new SetPacket { Key = key, Operations = e.Operations.ToArray(), AdditionalArguments = dictionary }); } } private DataStorageElementContext GetContextForKey(string key) { return new DataStorageElementContext { Key = key, GetData = GetValue, GetAsync = GetAsync, Initialize = Initialize, AddHandler = AddHandler, RemoveHandler = RemoveHandler }; } private void AddHandler(string key, DataStorageUpdatedHandler handler) { if (onValueChangedEventHandlers.ContainsKey(key)) { Dictionary<string, DataStorageUpdatedHandler> dictionary = onValueChangedEventHandlers; dictionary[key] = (DataStorageUpdatedHandler)Delegate.Combine(dictionary[key], handler); } else { onValueChangedEventHandlers[key] = handler; } socket.SendPacketAsync(new SetNotifyPacket { Keys = new string[1] { key } }); } private void RemoveHandler(string key, DataStorageUpdatedHandler handler) { if (onValueChangedEventHandlers.ContainsKey(key)) { Dictionary<string, DataStorageUpdatedHandler> dictionary = onValueChangedEventHandlers; dictionary[key] = (DataStorageUpdatedHandler)Delegate.Remove(dictionary[key], handler); if (onValueChangedEventHandlers[key] == null) { onValueChangedEventHandlers.Remove(key); } } } private string AddScope(Scope scope, string key) { return scope switch { Scope.Global => key, Scope.Game => $"{scope}:{connectionInfoProvider.Game}:{key}", Scope.Team => $"{scope}:{connectionInfoProvider.Team}:{key}", Scope.Slot => $"{scope}:{connectionInfoProvider.Slot}:{key}", Scope.ReadOnly => "_read_" + key, _ => throw new ArgumentOutOfRangeException("scope", scope, "Invalid scope for key " + key), }; } private DataStorageElement GetHintsElement(int? slot = null, int? team = null) { return this[Scope.ReadOnly, $"hints_{team ?? connectionInfoProvider.Team}_{slot ?? connectionInfoProvider.Slot}"]; } private DataStorageElement GetSlotDataElement(int? slot = null) { return this[Scope.ReadOnly, $"slot_data_{slot ?? connectionInfoProvider.Slot}"]; } private DataStorageElement GetItemNameGroupsElement(string game = null) { return this[Scope.ReadOnly, "item_name_groups_" + (game ?? connectionInfoProvider.Game)]; } private DataStorageElement GetLocationNameGroupsElement(string game = null) { return this[Scope.ReadOnly, "location_name_groups_" + (game ?? connectionInfoProvider.Game)]; } private DataStorageElement GetClientStatusElement(int? slot = null, int? team = null) { return this[Scope.ReadOnly, $"client_status_{team ?? connectionInfoProvider.Team}_{slot ?? connectionInfoProvider.Slot}"]; } private DataStorageElement GetRaceModeElement() { return this[Scope.ReadOnly, "race_mode"]; } public Hint[] GetHints(int? slot = null, int? team = null) { return GetHintsElement(slot, team).To<Hint[]>(); } public Task<Hint[]> GetHintsAsync(int? slot = null, int? team = null) { return GetHintsElement(slot, team).GetAsync<Hint[]>(); } public void TrackHints(Action<Hint[]> onHintsUpdated, bool retrieveCurrentlyUnlockedHints = true, int? slot = null, int? team = null) { GetHintsElement(slot, team).OnValueChanged += delegate(JToken _, JToken newValue, Dictionary<string, JToken> x) { onHintsUpdated(newValue.ToObject<Hint[]>()); }; if (retrieveCurrentlyUnlockedHints) { GetHintsAsync(slot, team).ContinueWith(delegate(Task<Hint[]> t) { onHintsUpdated(t.Result); }); } } public Dictionary<string, object> GetSlotData(int? slot = null) { return GetSlotData<Dictionary<string, object>>(slot); } public T GetSlotData<T>(int? slot = null) where T : class { return GetSlotDataElement(slot).To<T>(); } public Task<Dictionary<string, object>> GetSlotDataAsync(int? slot = null) { return GetSlotDataAsync<Dictionary<string, object>>(slot); } public Task<T> GetSlotDataAsync<T>(int? slot = null) where T : class { return GetSlotDataElement(slot).GetAsync<T>(); } public Dictionary<string, string[]> GetItemNameGroups(string game = null) { return GetItemNameGroupsElement(game).To<Dictionary<string, string[]>>(); } public Task<Dictionary<string, string[]>> GetItemNameGroupsAsync(string game = null) { return GetItemNameGroupsElement(game).GetAsync<Dictionary<string, string[]>>(); } public Dictionary<string, string[]> GetLocationNameGroups(string game = null) { return GetLocationNameGroupsElement(game).To<Dictionary<string, string[]>>(); } public Task<Dictionary<string, string[]>> GetLocationNameGroupsAsync(string game = null) { return GetLocationNameGroupsElement(game).GetAsync<Dictionary<string, string[]>>(); } public ArchipelagoClientState GetClientStatus(int? slot = null, int? team = null) { return GetClientStatusElement(slot, team).To<ArchipelagoClientState?>().GetValueOrDefault(); } public Task<ArchipelagoClientState> GetClientStatusAsync(int? slot = null, int? team = null) { return GetClientStatusElement(slot, team).GetAsync<ArchipelagoClientState?>().ContinueWith((Task<ArchipelagoClientState?> r) => r.Result.GetValueOrDefault()); } public void TrackClientStatus(Action<ArchipelagoClientState> onStatusUpdated, bool retrieveCurrentClientStatus = true, int? slot = null, int? team = null) { GetClientStatusElement(slot, team).OnValueChanged += delegate(JToken _, JToken newValue, Dictionary<string, JToken> x) { onStatusUpdated(newValue.ToObject<ArchipelagoClientState>()); }; if (retrieveCurrentClientStatus) { GetClientStatusAsync(slot, team).ContinueWith(delegate(Task<ArchipelagoClientState> t) { onStatusUpdated(t.Result); }); } } public bool GetRaceMode() { return GetRaceModeElement().To<int?>().GetValueOrDefault() > 0; } public Task<bool> GetRaceModeAsync() { return GetRaceModeElement().GetAsync<int?>().ContinueWith((Task<int?> t) => t.Result.GetValueOrDefault() > 0); } } public interface IDataStorageWrapper { Hint[] GetHints(int? slot = null, int? tea