Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of CommandQueueAutoPickup v1.5.0
BepInEx/plugins/CommandQueue.AutoPickup.dll
Decompiled 14 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using CommandQueue; using On.RoR2; using RoR2; using RoR2.Artifacts; using RoR2.UI; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Networking; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("CommandQueue.AutoPickup")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("CommandQueue.AutoPickup")] [assembly: AssemblyTitle("CommandQueue.AutoPickup")] [assembly: AssemblyVersion("1.0.0.0")] namespace CommandQueueAutoPickup; [BepInPlugin("com.ror2modding.commandqueue-autopickup", "CommandQueue.AutoPickup", "1.5.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class AutoPickupPlugin : BaseUnityPlugin { private struct PendingGrab { public PickupIndex index; public float createdRealtime; } private struct LiveTierInfo { public ItemTier tier; public int count; public PickupIndex head; } public const string VERSION = "1.5.0"; private const string BUTTON_MARKER = "CQAutoPickupToggle"; private const float TRIGGER_COOLDOWN_SECONDS = 1f; private const float TRIGGER_RETRY_BACKOFF_SECONDS = 3f; private const float PENDING_GRAB_TIMEOUT_SECONDS = 10f; private static ManualLogSource s_logger; private static ConfigEntry<bool> s_enabled; private static ConfigEntry<float> s_rangeBonus; private static GameObject s_toggleButton; private static readonly Dictionary<GameObject, float> s_triggerCooldown = new Dictionary<GameObject, float>(); private static string s_lastStatus; private static bool s_scannerAnnounced; private const float IDLE_SCAN_INTERVAL = 0.05f; private const float ACTIVE_WINDOW_SECONDS = 2.5f; private static float s_activityUntil = 0f; private static readonly List<PendingGrab> s_pendingGrabs = new List<PendingGrab>(); private static readonly HashSet<GameObject> s_claimedPickups = new HashSet<GameObject>(); private static IDictionary s_liveMainQueues; private static Type s_liveQueueManagerType; private static string s_bridgeDescription = "not resolved"; private static readonly ItemTier[] ALL_TIERS = (ItemTier[])(object)new ItemTier[3] { default(ItemTier), (ItemTier)1, (ItemTier)2 }; private static bool s_gateRegistered; private unsafe static void TryGrabPending(Interactor interactor) { //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Invalid comparison between Unknown and I4 if ((Object)(object)interactor == (Object)null || (Object)(object)((Component)interactor).gameObject == (Object)null) { return; } float realtimeSinceStartup = Time.realtimeSinceStartup; for (int num = s_pendingGrabs.Count - 1; num >= 0; num--) { if (realtimeSinceStartup - s_pendingGrabs[num].createdRealtime > 10f) { s_pendingGrabs.RemoveAt(num); } } foreach (GameObject item in new List<GameObject>(s_claimedPickups)) { if ((Object)(object)item == (Object)null) { s_claimedPickups.Remove(item); } } if (s_pendingGrabs.Count == 0) { return; } GenericPickupController[] array; try { array = Object.FindObjectsOfType<GenericPickupController>(); } catch { return; } if (array.Length == 0) { return; } for (int num2 = s_pendingGrabs.Count - 1; num2 >= 0; num2--) { PickupIndex index = s_pendingGrabs[num2].index; GenericPickupController val = null; float num3 = float.MaxValue; GenericPickupController[] array2 = array; foreach (GenericPickupController val2 in array2) { if ((Object)(object)val2 == (Object)null || !((Component)val2).gameObject.activeInHierarchy || s_claimedPickups.Contains(((Component)val2).gameObject) || val2.pickupIndex != index) { continue; } bool flag = false; try { flag = (int)val2.GetInteractability(interactor) == 2; } catch { } if (flag) { float num4 = Vector3.Distance(((Component)interactor).transform.position, ((Component)val2).transform.position); if (num4 < num3) { num3 = num4; val = val2; } } } if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null)) { s_claimedPickups.Add(((Component)val).gameObject); s_pendingGrabs.RemoveAt(num2); try { interactor.AttemptInteraction(((Component)val).gameObject); LogInfo("force-picked up chosen item " + ((object)(*(PickupIndex*)(&index))/*cast due to .constrained prefix*/).ToString() + " (pending left: " + s_pendingGrabs.Count + ")"); } catch (Exception ex) { s_claimedPickups.Remove(((Component)val).gameObject); s_pendingGrabs.Insert(num2, new PendingGrab { index = index, createdRealtime = realtimeSinceStartup }); LogWarn("force-pickup of " + ((object)(*(PickupIndex*)(&index))/*cast due to .constrained prefix*/).ToString() + " failed: " + ex.Message + "\n" + (ex.StackTrace ?? "(no stack trace)")); } } } } private static void ClearPendingGrabs() { s_pendingGrabs.Clear(); s_claimedPickups.Clear(); } private static string PendingSummary() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) if (s_pendingGrabs.Count == 0) { return null; } List<string> list = new List<string>(); foreach (IGrouping<PickupIndex, PendingGrab> item in from p in s_pendingGrabs group p by p.index) { list.Add(((object)item.Key/*cast due to .constrained prefix*/).ToString() + ((item.Count() > 1) ? (" x" + item.Count()) : "")); } return string.Join(", ", list); } public void Awake() { s_logger = ((BaseUnityPlugin)this).Logger; if (((BaseUnityPlugin)this).Config != null) { s_enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("AutoPickup", "Enabled", false, "While enabled: command essences («эссенция управления») you stand next to are picked up automatically when the queue for their tier has items"); s_rangeBonus = ((BaseUnityPlugin)this).Config.Bind<float>("AutoPickup", "RangeBonus", 0f, "Extra range added on top of the normal interact distance, in meters (0 = exactly like pressing E)"); LogInfo("Loaded v1.5.0"); } } public void OnEnable() { if (!IsCommandQueueLoaded()) { LogWarn("CommandQueue is not installed — the extension has nothing to extend and stays idle."); } ((MonoBehaviour)this).StartCoroutine(WatchForPanel()); ((MonoBehaviour)this).StartCoroutine(AutoPickupLoop()); ((MonoBehaviour)this).StartCoroutine(RegisterDisplayGate()); } private static void LogInfo(string msg) { ManualLogSource obj = s_logger; if (obj != null) { obj.LogInfo((object)("[CommandQueue.AutoPickup] " + msg)); } } private static void LogWarn(string msg) { ManualLogSource obj = s_logger; if (obj != null) { obj.LogWarning((object)("[CommandQueue.AutoPickup] " + msg)); } } private static void LogStatus(string status) { if (status != s_lastStatus) { s_lastStatus = status; LogInfo(status); } } private static bool IsCommandQueueLoaded() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { if (string.Equals(assemblies[i].GetName().Name, "CommandQueue", StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } private static IDictionary GetLiveMainQueues() { if (s_liveMainQueues != null) { return s_liveMainQueues; } List<Assembly> list = new List<Assembly>(); Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { if (string.Equals(assembly.GetName().Name, "CommandQueue", StringComparison.OrdinalIgnoreCase)) { list.Add(assembly); } } catch { } } Assembly assembly2 = null; if (list.Count == 1) { assembly2 = list[0]; } else if (list.Count > 1) { LogWarn(list.Count + " CommandQueue assemblies loaded — detecting the live one"); foreach (Assembly item in list) { Type type = null; try { Type[] source; try { source = item.GetTypes(); } catch (ReflectionTypeLoadException ex) { source = ex.Types.Where((Type t) => t != null).ToArray(); } type = source.FirstOrDefault((Type t) => t.IsSubclassOf(typeof(BaseUnityPlugin))); } catch { continue; } if (!(type == null)) { int num = 0; try { num = Resources.FindObjectsOfTypeAll(type).Length; } catch { } LogInfo(" candidate v" + item.GetName().Version?.ToString() + ": plugin " + type.FullName + ", instantiated objects: " + num); if (num > 0 && assembly2 == null) { assembly2 = item; } } } } if (assembly2 != null) { try { Type type2 = assembly2.GetType("CommandQueue.QueueManager"); IDictionary result = (s_liveMainQueues = ((type2?.GetField("mainQueues", BindingFlags.Static | BindingFlags.Public))?.GetValue(null) as IDictionary) ?? throw new MissingMemberException("mainQueues not found in " + assembly2.FullName)); s_liveQueueManagerType = type2; s_bridgeDescription = assembly2.GetName().Name + " v" + assembly2.GetName().Version; LogInfo("queue bridge attached to the RUNNING mod: " + s_bridgeDescription); return result; } catch (Exception ex2) { LogWarn("bridge failed (" + ex2.Message + ") — falling back to direct reference"); } } try { s_liveMainQueues = QueueManager.mainQueues; s_liveQueueManagerType = typeof(QueueManager); s_bridgeDescription = "direct reference"; if (list.Count > 1) { LogWarn("could not determine the live CommandQueue — remove duplicate CommandQueue plugin folders if queues look empty!"); } else { LogInfo("queue bridge attached (single instance): " + ((list.Count == 1) ? list[0].GetName().Version.ToString() : "none loaded yet")); } return s_liveMainQueues; } catch { s_bridgeDescription = "unresolved"; return null; } } private static List<LiveTierInfo> SnapshotQueues(IDictionary queues) { //IL_00a2: 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) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0020: 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_0090: Unknown result type (might be due to invalid IL or missing references) List<LiveTierInfo> list = new List<LiveTierInfo>(); if (queues == null) { return list; } ItemTier[] aLL_TIERS = ALL_TIERS; foreach (ItemTier val in aLL_TIERS) { object obj = null; try { obj = queues[val]; } catch { } IList list2 = obj as IList; int num = list2?.Count ?? 0; PickupIndex head = PickupIndex.none; if (num > 0) { try { object obj3 = list2[0]; if (obj3 != null) { FieldInfo field = obj3.GetType().GetField("pickupIndex"); if (field != null) { head = (PickupIndex)field.GetValue(obj3); } } } catch { } } list.Add(new LiveTierInfo { tier = val, count = num, head = head }); } return list; } private static string QueueSummary(List<LiveTierInfo> snapshot) { return "White=" + snapshot.FirstOrDefault((LiveTierInfo t) => (int)t.tier == 0).count + ", Green=" + snapshot.FirstOrDefault((LiveTierInfo t) => (int)t.tier == 1).count + ", Red=" + snapshot.FirstOrDefault((LiveTierInfo t) => (int)t.tier == 2).count; } private static ItemTier? DefTier(PickupIndex idx) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) try { return PickupCatalog.GetPickupDef(idx)?.itemTier; } catch { return null; } } private static List<ItemTier> GetCubeTiers(PickupPickerController picker) { //IL_001c: 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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) List<ItemTier> list = new List<ItemTier>(); try { Option[] array = picker.options ?? Array.Empty<Option>(); foreach (Option val in array) { if (val.available) { ItemTier? val2 = DefTier(val.pickup.pickupIndex); if (val2.HasValue && !list.Contains(val2.Value)) { list.Add(val2.Value); } } } } catch { } return list; } private static string DescribeCube(PickupPickerController picker, int maxSamples = 5) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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_0068: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_009e: 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) try { Option[] array = picker.options ?? Array.Empty<Option>(); if (array.Length == 0) { return "options not populated yet"; } int num = 0; StringBuilder stringBuilder = new StringBuilder(); Option[] array2 = array; foreach (Option val in array2) { if (val.available) { num++; if (stringBuilder.Length >= maxSamples) { break; } if (stringBuilder.Length > 0) { stringBuilder.Append(", "); } PickupIndex pickupIndex = val.pickup.pickupIndex; string value = "?"; ItemTier? val2 = DefTier(pickupIndex); if (val2.HasValue) { value = TierName(val2.Value); } stringBuilder.Append(pickupIndex).Append('(').Append(value) .Append(')'); } } return num + " of " + array.Length + " option(s) available" + ((stringBuilder.Length > 0) ? ("; first: " + stringBuilder) : ""); } catch { return "options unreadable"; } } private static GameObject GetCommandPanelPrefab() { try { GameObject commandCubePrefab = CommandArtifactManager.commandCubePrefab; if ((Object)(object)commandCubePrefab == (Object)null) { return null; } return commandCubePrefab.GetComponent<PickupPickerController>()?.panelPrefab; } catch { return null; } } private static IEnumerator RegisterDisplayGate() { yield return (object)new WaitForSeconds(2f); if (s_gateRegistered) { yield break; } try { PickupPickerController.OnDisplayBegin += new hook_OnDisplayBegin(HandleDisplayBeginGate); s_gateRegistered = true; LogInfo("display-pipeline gate is active — auto-submissions are now protected from crashes in other mods' OnDisplayBegin hooks (e.g. LookingGlass)"); } catch (Exception ex) { LogWarn("could not register the display-pipeline gate: " + ex.Message); } } private static void HandleDisplayBeginGate(orig_OnDisplayBegin orig, PickupPickerController self, NetworkUIPromptController nupc, LocalUser localUser, CameraRigController cam) { string text = QueueSignature(); Exception ex = null; try { orig.Invoke(self, nupc, localUser, cam); } catch (Exception ex2) { ex = ex2; LogWarn("OnDisplayBegin chain threw in a downstream hook - suppressed so the pipeline can continue. Fault: " + ex2.GetType().Name + ": " + ex2.Message + " | first frame: " + FirstFrame(ex2.StackTrace)); } if (ex == null) { return; } bool flag = false; try { flag = QueueSignature() != text; } catch { } if (flag) { LogInfo("gate: an auto-submission is in progress despite the downstream crash - nothing else to do"); return; } bool flag2 = false; try { FieldInfo field = typeof(PickupPickerController).GetField("panelInstance", BindingFlags.Instance | BindingFlags.NonPublic); flag2 = field != null && (bool)field.GetValue(self); } catch { } if (!flag2 && TryOpenPickerPanel(self, cam)) { LogInfo("gate: a downstream hook crashed before the picker could open - recreated the panel manually, manual selection restored"); } } private static string FirstFrame(string stack) { if (string.IsNullOrEmpty(stack)) { return "(no stack trace)"; } int num = stack.IndexOf('\n'); string text = ((num > 0) ? stack.Substring(0, num) : stack).Trim(); if (text.Length <= 220) { return text; } return text.Substring(0, 220) + "…"; } private unsafe static string QueueSignature() { //IL_0038: 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_006e: Unknown result type (might be due to invalid IL or missing references) List<LiveTierInfo> list = SnapshotQueues(GetLiveMainQueues()); if (list.Count == 0) { return "(empty)"; } List<string> list2 = new List<string>(list.Count); foreach (LiveTierInfo item in list) { string text = TierName(item.tier); string text2 = item.count.ToString(); object obj; if (item.count <= 0) { obj = ""; } else { PickupIndex head = item.head; obj = "@" + ((object)(*(PickupIndex*)(&head))/*cast due to .constrained prefix*/).ToString(); } list2.Add(text + "=" + text2 + (string?)obj); } return string.Join("|", list2); } private static bool TryOpenPickerPanel(PickupPickerController self, CameraRigController cam) { //IL_0065: 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) try { GameObject panelPrefab = self.panelPrefab; if ((Object)(object)panelPrefab == (Object)null) { LogWarn("gate: cannot open the picker - panelPrefab is null"); return false; } Transform val = null; try { val = (((Object)(object)cam != (Object)null) ? cam.hud.mainContainer.transform : null); } catch { } GameObject val2 = Object.Instantiate<GameObject>(panelPrefab, val); try { if (((Object)val2).name.ToLower().Contains("rebirthpickerpanel")) { Scene activeScene = SceneManager.GetActiveScene(); if (((Scene)(ref activeScene)).name == "meridian") { SettingsPanelController componentInChildren = val2.GetComponentInChildren<SettingsPanelController>(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.ToggleDialogBoxCreation(false); } } } } catch { } typeof(PickupPickerController).GetField("panelInstance", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(self, val2); PickupPickerPanel component = val2.GetComponent<PickupPickerPanel>(); if ((Object)(object)component != (Object)null) { typeof(PickupPickerController).GetField("panelInstanceController", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(self, component); component.pickerController = self; FieldInfo field = typeof(PickupPickerController).GetField("excludedItemsDropTable", BindingFlags.Instance | BindingFlags.NonPublic); if (field != null && field.GetValue(self) == null) { field.SetValue(self, component.excludedItemsDropTable); } component.SetPickupOptions(self.options); } MethodInfo method = typeof(PickupPickerController).GetMethod("OnPanelDestroyed", BindingFlags.Instance | BindingFlags.NonPublic); Action<OnDestroyCallback> action = null; if (method != null) { action = (Action<OnDestroyCallback>)method.CreateDelegate(typeof(Action<OnDestroyCallback>), self); } OnDestroyCallback.AddCallback(val2, action); return true; } catch (Exception ex) { LogWarn("gate: panel re-creation failed (" + ex.GetType().Name + ": " + ex.Message + ")"); return false; } } private IEnumerator WatchForPanel() { while (true) { if (IsCommandQueueLoaded()) { try { EnsureToggleButton(); } catch (Exception ex) { LogWarn("Button injection failed: " + ex.Message); } } yield return (object)new WaitForSeconds(2f); } } private static void EnsureToggleButton() { //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: Expected O, but got Unknown //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Expected O, but got Unknown //IL_02db: Unknown result type (might be due to invalid IL or missing references) //IL_02e5: Expected O, but got Unknown //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Expected O, but got Unknown //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)s_toggleButton != (Object)null) { UpdateButtonVisual(s_toggleButton); return; } try { GameObject val = null; HGButton[] array = Object.FindObjectsOfType<HGButton>(); foreach (HGButton val2 in array) { if (!((Object)(object)val2 == (Object)null) && !(((Object)((Component)val2).gameObject).name != "CQAutoPickupToggle")) { if ((Object)(object)val == (Object)null) { val = ((Component)val2).gameObject; } else { Object.Destroy((Object)(object)((Component)val2).gameObject); } } } if ((Object)(object)val != (Object)null) { s_toggleButton = val; UpdateButtonVisual(val); LogInfo("Adopted existing AutoPickup button"); return; } } catch { } GameObject val3 = null; try { val3 = GameObject.Find("CommandQueueContainer"); } catch { val3 = null; } if ((Object)(object)val3 == (Object)null) { HUD[] array2 = Object.FindObjectsOfType<HUD>(); for (int i = 0; i < array2.Length; i++) { GameObject val4 = array2[i]?.scoreboardPanel; if ((Object)(object)val4 != (Object)null) { Transform val5 = FindDescendantByName(val4.transform, "CommandQueueContainer"); if ((Object)(object)val5 != (Object)null) { val3 = ((Component)val5).gameObject; break; } } } } if ((Object)(object)val3 == (Object)null || (Object)(object)val3.transform.parent == (Object)null) { return; } Transform parent = val3.transform.parent; Transform[] componentsInChildren = ((Component)parent).GetComponentsInChildren<Transform>(true); foreach (Transform val6 in componentsInChildren) { if ((Object)(object)val6 != (Object)null && ((Object)val6).name == "CQAutoPickupToggle") { s_toggleButton = ((Component)val6).gameObject; UpdateButtonVisual(s_toggleButton); return; } } GameObject commandPanelPrefab = GetCommandPanelPrefab(); if ((Object)(object)commandPanelPrefab == (Object)null) { return; } try { HGButton[] componentsInChildren2 = commandPanelPrefab.GetComponentsInChildren<HGButton>(true); HGButton val7 = null; HGButton[] array = componentsInChildren2; foreach (HGButton val8 in array) { if ((Object)(object)val8 != (Object)null && ((Object)val8).name == "CancelButton") { val7 = val8; break; } } if ((Object)(object)val7 == (Object)null) { array = componentsInChildren2; foreach (HGButton val9 in array) { if ((Object)(object)val9 != (Object)null) { val7 = val9; break; } } } if ((Object)(object)val7 == (Object)null) { LogWarn("Could not find a prototype button in the command picker panel"); return; } GameObject obj3 = Object.Instantiate<GameObject>(((Component)val7).gameObject, parent); ((Object)obj3).name = "CQAutoPickupToggle"; RectTransform component = obj3.GetComponent<RectTransform>(); if ((Object)(object)component != (Object)null) { component.anchorMin = new Vector2(0.667f, 0.93f); component.anchorMax = new Vector2(1f, 1f); component.anchoredPosition = Vector2.zero; component.sizeDelta = Vector2.zero; } HGButton component2 = obj3.GetComponent<HGButton>(); ((MPButton)component2).onSelect = new UnityEvent(); ((MPButton)component2).onDeselect = new UnityEvent(); ((Button)component2).onClick = new ButtonClickedEvent(); ((UnityEvent)((Button)component2).onClick).AddListener(new UnityAction(ToggleAutoPickup)); UpdateButtonVisual(obj3); s_toggleButton = obj3; LogInfo("AutoPickup toggle button added to the CommandQueue panel (game button style)"); } catch (Exception ex) { LogWarn("Failed to create the toggle button: " + ex.Message); } } private static void SetButtonText(GameObject buttonGo, string text) { try { LanguageTextMeshController componentInChildren = buttonGo.GetComponentInChildren<LanguageTextMeshController>(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.token = text; return; } TextMeshProUGUI componentInChildren2 = buttonGo.GetComponentInChildren<TextMeshProUGUI>(); if ((Object)(object)componentInChildren2 != (Object)null) { ((TMP_Text)componentInChildren2).text = text; } } catch { } } private static void ToggleAutoPickup() { if (s_enabled == null) { return; } s_enabled.Value = !s_enabled.Value; UpdateButtonVisual(s_toggleButton); try { EventSystem current = EventSystem.current; if ((Object)(object)current != (Object)null) { current.SetSelectedGameObject((GameObject)null); } } catch { } LogInfo("AutoPickup " + (s_enabled.Value ? "ENABLED" : "disabled") + " by button"); } private static void UpdateButtonVisual(GameObject buttonGo) { if (!((Object)(object)buttonGo == (Object)null)) { SetButtonText(buttonGo, (s_enabled != null && s_enabled.Value) ? "AutoPickup ON" : "AutoPickup OFF"); } } private static Transform FindDescendantByName(Transform root, string name) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown foreach (Transform item in root) { Transform val = item; if (((Object)val).name == name) { return val; } Transform val2 = FindDescendantByName(val, name); if ((Object)(object)val2 != (Object)null) { return val2; } } return null; } private static bool PopLiveQueue(ItemTier tier) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) try { MethodInfo methodInfo = s_liveQueueManagerType?.GetMethod("Pop", BindingFlags.Static | BindingFlags.Public); if (methodInfo == null) { return false; } methodInfo.Invoke(null, new object[1] { tier }); return true; } catch (Exception ex) { LogWarn("live queue Pop failed: " + ex.Message); return false; } } private static void EnqueueLive(PickupIndex idx) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) try { (s_liveQueueManagerType?.GetMethod("Enqueue", BindingFlags.Static | BindingFlags.Public))?.Invoke(null, new object[1] { idx }); } catch (Exception ex) { LogWarn("live queue Enqueue failed: " + ex.Message); } } private unsafe static bool TryDirectGrant(GameObject cubeGO, CharacterBody body, ItemTier tier, PickupIndex head) { //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: 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) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)cubeGO == (Object)null || (Object)(object)body == (Object)null) { return false; } PickupDef pickupDef = PickupCatalog.GetPickupDef(head); if (pickupDef == null || pickupDef.attemptGrant == null) { LogWarn("direct grant: no valid PickupDef/attemptGrant for " + ((object)(*(PickupIndex*)(&head))/*cast due to .constrained prefix*/).ToString() + " — falling back to the classic path"); return false; } if (!PopLiveQueue(tier)) { LogWarn("direct grant: could not pop the live queue (" + TierName(tier) + ") — falling back to the classic path"); return false; } UniquePickup val = new UniquePickup { pickupIndex = head }; GrantContext val2 = new GrantContext { body = body, position = cubeGO.transform.position, rotation = Quaternion.identity, uniquePickup = val }; try { pickupDef.attemptGrant.Invoke(ref val2); if ((Object)(object)body.inventory != (Object)null) { body.OnPickup((PickupClass)3); } if (val2.shouldNotify && (Object)(object)body.master != (Object)null) { GenericPickupController.SendPickupMessage(body.master, val, 1); } Object.Destroy((Object)(object)cubeGO); } catch (Exception ex) { EnqueueLive(head); LogWarn("direct grant of " + ((object)(*(PickupIndex*)(&head))/*cast due to .constrained prefix*/).ToString() + " failed: " + ex.Message + " — rolled back to the queue, using the classic path"); return false; } LogInfo("direct-granted " + ((object)(*(PickupIndex*)(&head))/*cast due to .constrained prefix*/).ToString() + " (" + TierName(tier) + ") straight into the inventory; essence consumed, no ground item"); return true; } private IEnumerator AutoPickupLoop() { while (true) { yield return null; if (s_enabled == null || !s_enabled.Value) { s_scannerAnnounced = false; if (s_pendingGrabs.Count > 0) { ClearPendingGrabs(); } continue; } if (!IsCommandQueueLoaded()) { if (!s_scannerAnnounced) { s_scannerAnnounced = true; LogInfo("waiting — CommandQueue assembly not found yet"); } continue; } if (!s_scannerAnnounced) { s_scannerAnnounced = true; LogStatus("scanner active — looking for essences in range"); try { LogInfo("queue bridge → " + s_bridgeDescription + " | queues now: " + QueueSummary(SnapshotQueues(GetLiveMainQueues()))); } catch (Exception ex) { LogWarn("queue bridge announcement failed: " + ex.Message); } } try { TryAutoPickup(); } catch (Exception ex2) { LogWarn("AutoPickup tick failed: " + ex2.Message + "\n" + (ex2.StackTrace ?? "(no stack trace)")); } } } private unsafe static void TryAutoPickup() { //IL_062d: Unknown result type (might be due to invalid IL or missing references) //IL_063e: Unknown result type (might be due to invalid IL or missing references) //IL_0643: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0600: Unknown result type (might be due to invalid IL or missing references) //IL_0605: Unknown result type (might be due to invalid IL or missing references) //IL_0618: Unknown result type (might be due to invalid IL or missing references) //IL_0301: Unknown result type (might be due to invalid IL or missing references) //IL_0306: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_06e2: Unknown result type (might be due to invalid IL or missing references) //IL_0423: Unknown result type (might be due to invalid IL or missing references) //IL_0425: Unknown result type (might be due to invalid IL or missing references) //IL_0467: Unknown result type (might be due to invalid IL or missing references) //IL_04fe: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) if (!GetLocalInteractor(out var interactor, out var failReason)) { LogStatus("waiting — " + failReason); return; } if ((Object)(object)interactor == (Object)null || (Object)(object)((Component)interactor).gameObject == (Object)null) { LogStatus("waiting — Interactor reference is stale (respawn / scene change?)"); return; } CharacterBody val = ResolveLocalBody(); TryGrabPending(interactor); float num = Mathf.Max(interactor.maxInteractionDistance, 1f) + (s_rangeBonus?.Value ?? 0f) + 0.1f; Vector3 position = ((Component)interactor).transform.position; foreach (GameObject item in new List<GameObject>(s_triggerCooldown.Keys)) { if ((Object)(object)item == (Object)null) { s_triggerCooldown.Remove(item); } } GameObject commandPanelPrefab = GetCommandPanelPrefab(); if ((Object)(object)commandPanelPrefab == (Object)null) { LogStatus("enabled, but the command cube prefab is not loaded yet — nothing to do"); return; } PickupPickerController[] array; try { array = Object.FindObjectsOfType<PickupPickerController>(); } catch (Exception ex) { LogStatus("error while scanning for essences: " + ex.Message); return; } int num2 = 0; int num3 = 0; bool flag = false; PickupPickerController val2 = null; List<LiveTierInfo> list = SnapshotQueues(GetLiveMainQueues()); PickupPickerController[] array2 = array; foreach (PickupPickerController val3 in array2) { if ((Object)(object)val3 == (Object)null || !((Component)val3).gameObject.activeInHierarchy || val3.panelPrefab != commandPanelPrefab || Vector3.Distance(position, ((Component)val3).transform.position) > num) { continue; } num2++; if ((Object)(object)val2 == (Object)null) { val2 = val3; } if (s_triggerCooldown.TryGetValue(((Component)val3).gameObject, out var value) && Time.time < value) { continue; } ItemTier? val4 = null; PickupIndex val5 = PickupIndex.none; foreach (LiveTierInfo item2 in list) { if (item2.count != 0 && !(item2.head == PickupIndex.none)) { bool flag2 = false; try { flag2 = val3.IsChoiceAvailable(item2.head); } catch { } if (flag2) { val4 = item2.tier; val5 = item2.head; break; } } } if (!val4.HasValue) { num3++; continue; } if ((Object)(object)val3 == (Object)null || (Object)(object)((Component)val3).gameObject == (Object)null) { num3++; continue; } s_triggerCooldown[((Component)val3).gameObject] = Time.time + 1f; s_activityUntil = Time.time + 2.5f; bool flag3 = false; if (NetworkServer.active) { CharacterBody val6 = val ?? (((Object)(object)interactor != (Object)null) ? ((Component)interactor).GetComponent<CharacterBody>() : null); if ((Object)(object)val6 == (Object)null || (Object)(object)val6.inventory == (Object)null) { LogWarn("direct grant skipped (local CharacterBody not resolved) — falling back to the classic path"); } else { flag3 = TryDirectGrant(((Component)val3).gameObject, val6, val4.Value, val5); } } if (!flag3) { LogInfo("using classic path (reason: " + (NetworkServer.active ? "direct grant returned false" : "not hosting / client") + ")"); try { interactor.AttemptInteraction(((Component)val3).gameObject); } catch (Exception ex2) { s_triggerCooldown[((Component)val3).gameObject] = Time.time + 3f; string text = ""; string text2 = ex2.StackTrace ?? ""; int num4 = text2.IndexOf('\n'); if (num4 > 0) { text = text2.Substring(0, num4).Trim(); } LogWarn("trigger attempt on the essence threw (" + ex2.GetType().Name + ": " + ex2.Message + ") — a hook from another mod is likely crashing the display pipeline; retrying this cube in a few seconds." + ((text != "") ? (" Failing frame: " + text) : "")); num3++; continue; } s_pendingGrabs.Add(new PendingGrab { index = val5, createdRealtime = Time.realtimeSinceStartup }); LogInfo("Auto-picked up a command essence (classic path) — submitting queued item " + ((object)(*(PickupIndex*)(&val5))/*cast due to .constrained prefix*/).ToString() + " (" + TierName(val4.Value) + "); will force-grab it off the ground"); } flag = true; break; } if (flag) { return; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("waiting — ").Append(num2).Append(" essence(s) in interact range"); int num5 = 0; List<string> list2 = new List<string>(); foreach (LiveTierInfo item3 in list) { if (item3.count > 0) { num5 += item3.count; list2.Add(TierName(item3.tier) + "=" + item3.count); } } if (list2.Count == 0) { stringBuilder.Append("; QUEUES ARE EMPTY (bridge: ").Append(s_bridgeDescription).Append(" — add items first: Tab → Command Queue → click item buttons)"); } else { stringBuilder.Append(" [queues: ").Append(string.Join(", ", list2)).Append("] (bridge: ") .Append(s_bridgeDescription) .Append(')'); } if ((Object)(object)val2 != (Object)null && num5 > 0) { stringBuilder.Append(". cube: ").Append(DescribeCube(val2)); List<string> list3 = new List<string>(); foreach (LiveTierInfo item4 in list) { if (item4.count != 0 && !(item4.head == PickupIndex.none)) { bool flag4 = false; try { flag4 = val2.IsChoiceAvailable(item4.head); } catch { } string text3 = TierName(item4.tier); PickupIndex head = item4.head; list3.Add(text3 + " head=" + ((object)(*(PickupIndex*)(&head))/*cast due to .constrained prefix*/).ToString() + (flag4 ? " MATCH" : " not offered")); } } stringBuilder.Append("; your heads: ").Append(string.Join("; ", list3)); List<ItemTier> cubeTiers = GetCubeTiers(val2); HashSet<ItemTier> queuedTiers = new HashSet<ItemTier>(); foreach (LiveTierInfo item5 in list) { if (item5.count > 0) { queuedTiers.Add(item5.tier); } } if (!cubeTiers.Any((ItemTier t) => queuedTiers.Contains(t)) && cubeTiers.Count > 0) { stringBuilder.Append(". NOTE: this essence only offers ").Append(string.Join("/", cubeTiers.Select(TierName))).Append(" item(s), but you queued: ") .Append(string.Join("/", queuedTiers.Select(TierName))) .Append(" — queue an item of the essence's color (or wait for a matching essence)"); } } string text4 = PendingSummary(); if (text4 != null) { stringBuilder.Append("; awaiting ground item(s): ").Append(text4); } LogStatus(stringBuilder.ToString()); } private static string TierName(ItemTier tier) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected I4, but got Unknown return (int)tier switch { 0 => "White", 1 => "Green", 2 => "Red", _ => "?", }; } private static CharacterBody ResolveLocalBody() { try { LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser(); if (firstLocalUser != null) { if ((Object)(object)firstLocalUser.cachedBodyObject != (Object)null) { CharacterBody component = firstLocalUser.cachedBodyObject.GetComponent<CharacterBody>(); if ((Object)(object)component != (Object)null) { return component; } } if ((Object)(object)firstLocalUser.cachedMasterObject != (Object)null) { CharacterMaster component2 = firstLocalUser.cachedMasterObject.GetComponent<CharacterMaster>(); CharacterBody val = (((Object)(object)component2 != (Object)null) ? component2.GetBody() : null); if ((Object)(object)val != (Object)null) { return val; } } } } catch { } try { foreach (PlayerController localPlayer in ClientScene.localPlayers) { if (localPlayer != null && !((Object)(object)localPlayer.gameObject == (Object)null)) { CharacterBody component3 = localPlayer.gameObject.GetComponent<CharacterBody>(); if ((Object)(object)component3 != (Object)null) { return component3; } CharacterMaster component4 = localPlayer.gameObject.GetComponent<CharacterMaster>(); CharacterBody val2 = (((Object)(object)component4 != (Object)null) ? component4.GetBody() : null); if ((Object)(object)val2 != (Object)null) { return val2; } } } } catch { } return null; } private static bool GetLocalInteractor(out Interactor interactor, out string failReason) { interactor = null; failReason = "unknown"; try { LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser(); if (firstLocalUser != null) { GameObject[] array = (GameObject[])(object)new GameObject[2] { firstLocalUser.cachedBodyObject, firstLocalUser.cachedMasterObject }; foreach (GameObject val in array) { if (!((Object)(object)val == (Object)null)) { interactor = FindInteractor(val); if ((Object)(object)interactor != (Object)null) { return true; } } } } } catch { } try { List<PlayerController> localPlayers = ClientScene.localPlayers; if (localPlayers != null) { for (int j = 0; j < localPlayers.Count; j++) { PlayerController val2 = localPlayers[j]; if (val2 != null && !((Object)(object)val2.gameObject == (Object)null)) { interactor = FindInteractor(val2.gameObject); if ((Object)(object)interactor != (Object)null) { return true; } } } } } catch { } try { NetworkIdentity[] array2 = Object.FindObjectsOfType<NetworkIdentity>(); foreach (NetworkIdentity val3 in array2) { if (!((Object)(object)val3 == (Object)null) && val3.isLocalPlayer && !((Object)(object)((Component)val3).gameObject == (Object)null)) { interactor = FindInteractor(((Component)val3).gameObject); if ((Object)(object)interactor != (Object)null) { return true; } } } } catch { } failReason = "no local player found (tried LocalUserManager, ClientScene.localPlayers, NetworkIdentity scan) — not in a run yet?"; return false; } private static Interactor FindInteractor(GameObject masterGo) { try { Interactor component = masterGo.GetComponent<Interactor>(); if ((Object)(object)component != (Object)null) { return component; } CharacterMaster component2 = masterGo.GetComponent<CharacterMaster>(); CharacterBody val = (((Object)(object)component2 != (Object)null) ? component2.GetBody() : null); if ((Object)(object)val != (Object)null) { component = ((Component)val).GetComponent<Interactor>(); if ((Object)(object)component != (Object)null) { return component; } component = ((Component)val).GetComponentInChildren<Interactor>(); if ((Object)(object)component != (Object)null) { return component; } } return masterGo.GetComponentInChildren<Interactor>(); } catch { return null; } } }