using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using Archipelago.MultiClient.Net; 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 Microsoft.CodeAnalysis; using NodeCanvas.Framework; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("BurglinGnomesArchipelago")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("BurglinGnomesArchipelago")] [assembly: AssemblyTitle("BurglinGnomesArchipelago")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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 BurglinGnomesArchipelago { public class ArchipelagoManager { private const string GameName = "Burglin' Gnomes"; private readonly ManualLogSource _log; private ArchipelagoSession _session; public bool Connected { get; private set; } public ArchipelagoManager(ManualLogSource log) { _log = log; } public void Connect(string address, int port, string slotName, string password) { //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Expected O, but got Unknown //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Expected O, but got Unknown //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown try { _session = ArchipelagoSessionFactory.CreateSession(address, port); LoginResult val = _session.TryConnectAndLogin("Burglin' Gnomes", slotName, (ItemsHandlingFlags)7, new Version(0, 5, 0), (string[])null, (string)null, string.IsNullOrEmpty(password) ? null : password, true); if (!val.Successful) { LoginFailure val2 = (LoginFailure)val; _log.LogError((object)("[Archipelago] Connection failed: " + string.Join(", ", val2.Errors))); Connected = false; return; } Connected = true; _log.LogInfo((object)("[Archipelago] Connected to " + address + ":" + port)); _session.Items.ItemReceived += new ItemReceivedHandler(OnItemReceived); _session.Socket.SocketClosed += (SocketClosedHandler)delegate(string reason) { Connected = false; _log.LogWarning((object)("[Archipelago] Disconnected: " + reason)); }; } catch (Exception arg) { _log.LogError((object)$"[Archipelago] Exception while connecting: {arg}"); Connected = false; } } public void Disconnect() { try { ArchipelagoSession session = _session; if (session != null) { IArchipelagoSocketHelper socket = session.Socket; if (socket != null) { socket.DisconnectAsync(); } } } catch (Exception arg) { _log.LogWarning((object)$"[Archipelago] Error during disconnect: {arg}"); } Connected = false; } private void OnItemReceived(IReceivedItemsHelper helper) { ItemInfo val = helper.DequeueItem(); _log.LogInfo((object)("[Archipelago] Received '" + val.ItemName + "' from " + val.Player.Name + " (location: " + val.LocationName + ")")); GameHooks.ApplyReceivedItem(val.ItemName); } public void SendLocationCheck(long locationId) { if (!Connected) { _log.LogWarning((object)"[Archipelago] Tried to send a location check while disconnected."); return; } _session.Locations.CompleteLocationChecks(new long[1] { locationId }); } public long? LocationIdByName(string name) { if (!Connected) { return null; } return _session.Locations.GetLocationIdFromName("Burglin' Gnomes", name); } } public static class GameHooks { [CompilerGenerated] private static class <>O { public static Action <0>__OnGameStarted; public static Action <1>__OnGameEnded; public static OnTaskUpdatedDelegate <2>__OnTaskCompleted; } private static PlayerTaskManager _taskManager; private static bool _subscribedToGameStart; public static void TryHook() { if (!_subscribedToGameStart) { GameProgressionManager instance = GameProgressionManager.Instance; if (!((Object)(object)instance == (Object)null)) { instance.onGameStarted += OnGameStarted; instance.onGameEnded += OnGameEnded; _subscribedToGameStart = true; TryHookTaskManager(); } } } private static void OnGameStarted() { TryHookTaskManager(); } private static void OnGameEnded(GameEndedReason reason) { UnhookTaskManager(); } private static void TryHookTaskManager() { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown if ((Object)(object)_taskManager != (Object)null) { return; } GlobalBlackboard val = GlobalBlackboard.Find("Global"); if ((Object)(object)val == (Object)null) { return; } PlayerTaskManager variableValue = ((Blackboard)val).GetVariableValue("taskManager"); if (!((Object)(object)variableValue == (Object)null)) { _taskManager = variableValue; PlayerTaskManager taskManager = _taskManager; object obj = <>O.<2>__OnTaskCompleted; if (obj == null) { OnTaskUpdatedDelegate val2 = OnTaskCompleted; <>O.<2>__OnTaskCompleted = val2; obj = (object)val2; } taskManager.OnTaskCompleted += (OnTaskUpdatedDelegate)obj; Plugin.Log.LogInfo((object)"[GameHooks] Hooked PlayerTaskManager.OnTaskCompleted."); } } private static void UnhookTaskManager() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown if ((Object)(object)_taskManager != (Object)null) { PlayerTaskManager taskManager = _taskManager; object obj = <>O.<2>__OnTaskCompleted; if (obj == null) { OnTaskUpdatedDelegate val = OnTaskCompleted; <>O.<2>__OnTaskCompleted = val; obj = (object)val; } taskManager.OnTaskCompleted -= (OnTaskUpdatedDelegate)obj; _taskManager = null; } } private static void OnTaskCompleted(TaskEventData eventData) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) string text = (((Object)(object)eventData.taskRef != (Object)null) ? ((Object)eventData.taskRef).name : "Unknown Task"); string text2 = "Task: " + text; long? num = Plugin.Archipelago.LocationIdByName(text2); if (num.HasValue) { Plugin.Archipelago.SendLocationCheck(num.Value); Plugin.Log.LogInfo((object)("[GameHooks] Task completed -> location check '" + text2 + "'.")); } else { Plugin.Log.LogInfo((object)("[GameHooks] Task '" + text2 + "' completed but no matching AP location found (name mismatch or apworld not loaded).")); } } public static void ApplyReceivedItem(string itemName) { PendingRewards.Enqueue(itemName); } } public static class PendingRewards { private const string PrefsKey = "APMod_PendingRewards"; private static List _queue; private static List Queue { get { if (_queue == null) { Load(); } return _queue; } } public static int Count => Queue.Count; public static IReadOnlyList All => Queue.AsReadOnly(); public static void Enqueue(string itemName) { Queue.Add(itemName); Save(); Plugin.Log.LogInfo((object)$"[PendingRewards] Queued '{itemName}'. Total pending: {Queue.Count}"); } public static string TryClaim() { if (Queue.Count == 0) { return null; } PlayerNetworking localPlayer = ServerManager.GetLocalPlayer(); if ((Object)(object)localPlayer == (Object)null) { Plugin.Log.LogWarning((object)"[PendingRewards] Cannot claim: not spawned into a game yet."); return null; } string text = Queue[0]; string text2 = ((text == "Gnomium Payout") ? "gnomium" : text); if (!((InventoryBase)localPlayer.Inventory).TryAddItem(text2, 1)) { Plugin.Log.LogWarning((object)("[PendingRewards] Could not claim '" + text2 + "' -- inventory full or item name mismatch. Item stays queued.")); return null; } Queue.RemoveAt(0); Save(); Plugin.Log.LogInfo((object)$"[PendingRewards] Claimed '{text2}' (AP item: '{text}'). Remaining: {Queue.Count}"); return text2; } public static List TryClaimAll() { List list = new List(); while (Queue.Count > 0) { string text = TryClaim(); if (text == null) { break; } list.Add(text); } return list; } private static void Save() { PlayerPrefs.SetString("APMod_PendingRewards", string.Join("\n", Queue)); PlayerPrefs.Save(); } private static void Load() { _queue = new List(); string text = PlayerPrefs.GetString("APMod_PendingRewards", ""); if (string.IsNullOrEmpty(text)) { return; } string[] array = text.Split(new char[1] { '\n' }); foreach (string text2 in array) { if (!string.IsNullOrWhiteSpace(text2)) { _queue.Add(text2.Trim()); } } if (_queue.Count > 0) { Plugin.Log.LogInfo((object)$"[PendingRewards] Loaded {_queue.Count} unclaimed item(s) from previous session."); } } } [BepInPlugin("yourname.burglingnomes.archipelago", "Burglin' Gnomes Archipelago Client", "0.1.1")] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "yourname.burglingnomes.archipelago"; public const string PluginName = "Burglin' Gnomes Archipelago Client"; public const string PluginVersion = "0.1.1"; internal static ManualLogSource Log; internal static ArchipelagoManager Archipelago; public static ConfigEntry ServerAddress; public static ConfigEntry ServerPort; public static ConfigEntry SlotName; public static ConfigEntry Password; public static ConfigEntry AutoConnectOnLaunch; public static ConfigEntry ToggleGuiKey; private Harmony _harmony; private bool _guiVisible; private string _addressField; private string _portField; private string _slotField; private string _passwordField; private Vector2 _pendingScrollPos; private string _lastClaimMessage = ""; private float _lastClaimMessageTimer; private void Awake() { //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Expected O, but got Unknown //IL_016c: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; ServerAddress = ((BaseUnityPlugin)this).Config.Bind("Archipelago", "ServerAddress", "archipelago.gg", "Hostname (no port)."); ServerPort = ((BaseUnityPlugin)this).Config.Bind("Archipelago", "ServerPort", 38281, "Port."); SlotName = ((BaseUnityPlugin)this).Config.Bind("Archipelago", "SlotName", "Player1", "Your slot name."); Password = ((BaseUnityPlugin)this).Config.Bind("Archipelago", "Password", "", "Room password (blank if none)."); AutoConnectOnLaunch = ((BaseUnityPlugin)this).Config.Bind("Archipelago", "AutoConnectOnLaunch", false, "Connect automatically on launch."); ToggleGuiKey = ((BaseUnityPlugin)this).Config.Bind("Debug", "ToggleGuiKey", (KeyCode)287, "Toggle the AP overlay."); _addressField = ServerAddress.Value; _portField = ServerPort.Value.ToString(); _slotField = SlotName.Value; _passwordField = Password.Value; Archipelago = new ArchipelagoManager(Log); _harmony = new Harmony("yourname.burglingnomes.archipelago"); _harmony.PatchAll(); Log.LogInfo((object)string.Format("{0} v{1} loaded. Press {2} for the AP overlay.", "Burglin' Gnomes Archipelago Client", "0.1.1", ToggleGuiKey.Value)); if (AutoConnectOnLaunch.Value) { Archipelago.Connect(ServerAddress.Value, ServerPort.Value, SlotName.Value, Password.Value); } } private void Update() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) if (Input.GetKeyDown(ToggleGuiKey.Value)) { _guiVisible = !_guiVisible; } GameHooks.TryHook(); if (_lastClaimMessageTimer > 0f) { _lastClaimMessageTimer -= Time.deltaTime; } } private void OnGUI() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_02ce: Unknown result type (might be due to invalid IL or missing references) //IL_030f: Unknown result type (might be due to invalid IL or missing references) //IL_03a5: Unknown result type (might be due to invalid IL or missing references) //IL_03ab: Unknown result type (might be due to invalid IL or missing references) //IL_03c3: Unknown result type (might be due to invalid IL or missing references) //IL_03c8: Unknown result type (might be due to invalid IL or missing references) //IL_03cd: Unknown result type (might be due to invalid IL or missing references) //IL_0351: Unknown result type (might be due to invalid IL or missing references) //IL_047b: Unknown result type (might be due to invalid IL or missing references) //IL_0431: Unknown result type (might be due to invalid IL or missing references) //IL_04d4: Unknown result type (might be due to invalid IL or missing references) //IL_055a: Unknown result type (might be due to invalid IL or missing references) if (!_guiVisible) { return; } GUI.Box(new Rect(20f, 20f, 320f, 230f), "Archipelago Connection"); GUI.Label(new Rect(30f, 48f, 100f, 20f), "Server"); _addressField = GUI.TextField(new Rect(120f, 48f, 210f, 20f), _addressField); GUI.Label(new Rect(30f, 73f, 100f, 20f), "Port"); _portField = GUI.TextField(new Rect(120f, 73f, 210f, 20f), _portField); GUI.Label(new Rect(30f, 98f, 100f, 20f), "Slot name"); _slotField = GUI.TextField(new Rect(120f, 98f, 210f, 20f), _slotField); GUI.Label(new Rect(30f, 123f, 100f, 20f), "Password"); _passwordField = GUI.PasswordField(new Rect(120f, 123f, 210f, 20f), _passwordField, '*'); string text = (Archipelago.Connected ? "Connected" : "Disconnected"); GUI.Label(new Rect(30f, 150f, 300f, 20f), "Status: " + text); if (!Archipelago.Connected) { if (GUI.Button(new Rect(30f, 175f, 130f, 30f), "Connect")) { if (int.TryParse(_portField, out var result)) { ServerAddress.Value = _addressField; ServerPort.Value = result; SlotName.Value = _slotField; Password.Value = _passwordField; Archipelago.Connect(_addressField, result, _slotField, _passwordField); } else { Log.LogWarning((object)"[AP] Port must be a number."); } } } else if (GUI.Button(new Rect(30f, 175f, 130f, 30f), "Disconnect")) { Archipelago.Disconnect(); } GUI.Label(new Rect(30f, 210f, 300f, 20f), "Pending rewards: " + PendingRewards.Count); float num = 360f; float num2 = 20f; float num3 = 340f; float num4 = 360f; GUI.Box(new Rect(num, num2, num3, num4), "Pending Rewards (Unclaimed AP Items)"); IReadOnlyList all = PendingRewards.All; if (all.Count == 0) { GUI.Label(new Rect(num + 10f, num2 + 30f, num3 - 20f, 30f), "Nothing pending."); return; } float num5 = num4 - 110f; float num6 = 22f; float num7 = Mathf.Max((float)all.Count * num6, num5); _pendingScrollPos = GUI.BeginScrollView(new Rect(num + 10f, num2 + 30f, num3 - 20f, num5), _pendingScrollPos, new Rect(0f, 0f, num3 - 40f, num7)); for (int i = 0; i < all.Count; i++) { string text2 = $"{i + 1}. {all[i]}"; if (all[i] == "Gnomium Payout") { text2 += " (grants gnomium)"; } GUI.Label(new Rect(4f, (float)i * num6, num3 - 50f, num6), text2); } GUI.EndScrollView(); float num8 = num2 + num4 - 72f; if (GUI.Button(new Rect(num + 10f, num8, 150f, 30f), "Claim Next Item")) { string text3 = PendingRewards.TryClaim(); _lastClaimMessage = ((text3 != null) ? ("Claimed: " + text3) : "Could not claim (full / not in game)"); _lastClaimMessageTimer = 3f; } if (GUI.Button(new Rect(num + 170f, num8, 160f, 30f), "Claim All")) { List list = PendingRewards.TryClaimAll(); _lastClaimMessage = ((list.Count > 0) ? $"Claimed {list.Count} item(s)" : "Could not claim (full / not in game)"); _lastClaimMessageTimer = 3f; } if (_lastClaimMessageTimer > 0f) { GUI.Label(new Rect(num + 10f, num2 + num4 - 30f, num3 - 20f, 24f), _lastClaimMessage); } } private void OnDestroy() { Archipelago?.Disconnect(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } }