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 AreaPickup v1.0.1
AreaPickup.dll
Decompiled 2 days agousing System; using System.Collections; 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 BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn; using Jotunn.Configs; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("assembly_utils")] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("AreaPickup")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyInformationalVersion("1.0.1")] [assembly: AssemblyProduct("AreaPickup")] [assembly: AssemblyTitle("AreaPickup")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.1.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 AreaPickup { [BepInPlugin("dreamscapist.valheim.areapickup", "AreaPickup", "1.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] internal class AreaPickupPlugin : BaseUnityPlugin { private class SweepResult { public int Collected; public int Pending; public bool InventoryFull; } public const string PluginGUID = "dreamscapist.valheim.areapickup"; public const string PluginName = "AreaPickup"; public const string PluginVersion = "1.0.1"; private const float DefaultRange = 10f; private const float MinRange = 5f; private const float MaxRange = 100f; private const int OwnershipRetries = 4; private const float OwnershipRetryDelay = 0.3f; private const float PickableDropDelay = 0.6f; internal static bool SuppressTopLeftMessages; private ConfigEntry<float> _range; private ConfigEntry<KeyboardShortcut> _hotkey; private ConfigEntry<bool> _pickupGroundItems; private ConfigEntry<bool> _harvestPickables; private ConfigEntry<bool> _includeFish; private ConfigEntry<bool> _ignorePlacedItems; private ConfigEntry<bool> _debugLogging; private ConfigEntry<string> _blacklistEntry; private ConfigEntry<bool> _showPerItemMessages; private ConfigEntry<bool> _showSummary; private readonly HashSet<string> _blacklist = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private ButtonConfig _pickupButton; private Harmony _harmony; private bool _busy; private void Awake() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown BindConfig(); _pickupButton = new ButtonConfig { Name = "AreaPickup_Pickup", ShortcutConfig = _hotkey }; InputManager.Instance.AddButton("dreamscapist.valheim.areapickup", _pickupButton); _harmony = new Harmony("dreamscapist.valheim.areapickup"); _harmony.PatchAll(typeof(AreaPickupPlugin).Assembly); Logger.LogInfo((object)"AreaPickup v1.0.1 loaded"); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private void BindConfig() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_005f: Unknown result type (might be due to invalid IL or missing references) _range = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Range", 10f, new ConfigDescription("Pickup radius in meters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 100f), Array.Empty<object>())); _hotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "Hotkey", new KeyboardShortcut((KeyCode)101, (KeyCode[])(object)new KeyCode[1] { (KeyCode)304 }), "Key combination that picks up everything in range."); _pickupGroundItems = ((BaseUnityPlugin)this).Config.Bind<bool>("Filters", "PickupGroundItems", true, "Pick up dropped items lying on the ground."); _harvestPickables = ((BaseUnityPlugin)this).Config.Bind<bool>("Filters", "HarvestPickables", false, "Harvest pickables in range (berries, mushrooms, stones, flint, branches, grown crops, ...)."); _includeFish = ((BaseUnityPlugin)this).Config.Bind<bool>("Filters", "IncludeFish", false, "Also grab fish. Off by default so live fish can't be scooped out of the water."); _ignorePlacedItems = ((BaseUnityPlugin)this).Config.Bind<bool>("Filters", "IgnorePlacedItems", true, "Leave placed-down items alone (food set out on tables, decorative items). Only loose, dropped items get picked up."); _debugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "LogCandidates", false, "Log every item found in range and why it was picked up or skipped. Use this if something placed still gets grabbed, or a dropped item gets left behind."); _blacklistEntry = ((BaseUnityPlugin)this).Config.Bind<string>("Filters", "Blacklist", "", "Comma-separated prefab names to ignore, e.g. Pickable_Carrot,Wood,Resin"); _blacklistEntry.SettingChanged += delegate { ParseBlacklist(); }; ParseBlacklist(); _showPerItemMessages = ((BaseUnityPlugin)this).Config.Bind<bool>("Messages", "ShowPerItemMessages", false, "Show vanilla's top-left 'added X' message for every item picked up."); _showSummary = ((BaseUnityPlugin)this).Config.Bind<bool>("Messages", "ShowSummary", true, "Show one summary message after each sweep."); } private void ParseBlacklist() { _blacklist.Clear(); string[] array = _blacklistEntry.Value.Split(','); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length > 0) { _blacklist.Add(text); } } } private void Update() { if (!_busy && ZInput.instance != null && ZInput.GetButtonDown(_pickupButton.Name)) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && !((Character)localPlayer).IsDead() && !((Character)localPlayer).IsTeleporting() && !((Character)localPlayer).InCutscene() && ((Character)localPlayer).TakeInput()) { ((MonoBehaviour)this).StartCoroutine(PickupRoutine(localPlayer)); } } } private IEnumerator PickupRoutine(Player player) { _busy = true; try { float range = Mathf.Clamp(_range.Value, 5f, 100f); int harvested = 0; int collected = 0; bool inventoryFull = false; if (_harvestPickables.Value) { harvested = HarvestPickables(player, range); if (harvested > 0 && _pickupGroundItems.Value) { yield return (object)new WaitForSeconds(0.6f); } } if (_pickupGroundItems.Value) { for (int attempt = 0; attempt <= 4; attempt++) { if (!((Object)(object)player == (Object)null) && !((Character)player).IsDead()) { SweepResult sweepResult = SweepItemDrops(player, range); collected += sweepResult.Collected; inventoryFull |= sweepResult.InventoryFull; if (sweepResult.Pending == 0) { break; } yield return (object)new WaitForSeconds(0.3f); continue; } yield break; } } if (_showSummary.Value && (Object)(object)player != (Object)null) { ((Character)player).Message((MessageType)1, BuildSummary(collected, harvested, inventoryFull), 0, (Sprite)null, false); } } finally { AreaPickupPlugin areaPickupPlugin = this; SuppressTopLeftMessages = false; areaPickupPlugin._busy = false; } } private int HarvestPickables(Player player, float range) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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_007e: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)player).transform.position; int num = 0; SuppressTopLeftMessages = !_showPerItemMessages.Value; try { foreach (Pickable item in FindInRange<Pickable>(position, range)) { if (!item.m_picked && HasValidView((Component)(object)item) && !IsBlacklisted(((Component)item).gameObject) && item.Interact((Humanoid)(object)player, false, false)) { num++; } } foreach (PickableItem item2 in FindInRange<PickableItem>(position, range)) { if (HasValidView((Component)(object)item2) && !IsBlacklisted(((Component)item2).gameObject) && item2.Interact((Humanoid)(object)player, false, false)) { num++; } } return num; } finally { SuppressTopLeftMessages = false; } } private SweepResult SweepItemDrops(Player player, float range) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) SweepResult sweepResult = new SweepResult(); Inventory inventory = ((Humanoid)player).GetInventory(); SuppressTopLeftMessages = !_showPerItemMessages.Value; try { foreach (ItemDrop item in FindInRange<ItemDrop>(((Component)player).transform.position, range)) { if ((Object)(object)item == (Object)null) { continue; } ZNetView component = ((Component)item).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid() || IsBlacklisted(((Component)item).gameObject) || (!_includeFish.Value && (Object)(object)((Component)item).GetComponent<Fish>() != (Object)null)) { continue; } item.Load(); if (item.m_itemData == null) { continue; } if (_ignorePlacedItems.Value && IsPlaced(item, out var reason)) { if (_debugLogging.Value) { Logger.LogInfo((object)("[AreaPickup] skip placed " + PrefabName(((Component)item).gameObject) + " (" + reason + ")")); } continue; } if (_debugLogging.Value) { Logger.LogInfo((object)($"[AreaPickup] take {PrefabName(((Component)item).gameObject)} x{item.m_itemData.m_stack} " + $"(autoPickup={item.m_autoPickup}, kinematic={IsKinematic(item)}, " + $"food={item.m_itemData.m_shared.m_food})")); } if (!inventory.CanAddItem(item.m_itemData, -1)) { sweepResult.InventoryFull = true; continue; } if (!component.IsOwner()) { item.RequestOwn(); sweepResult.Pending++; continue; } int stack = item.m_itemData.m_stack; if (((Humanoid)player).Pickup(((Component)item).gameObject, false, false)) { sweepResult.Collected += stack; } } return sweepResult; } finally { SuppressTopLeftMessages = false; } } private static List<T> FindInRange<T>(Vector3 center, float range) where T : Component { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) HashSet<T> hashSet = new HashSet<T>(); List<T> list = new List<T>(); Collider[] array = Physics.OverlapSphere(center, range, -1, (QueryTriggerInteraction)2); for (int i = 0; i < array.Length; i++) { T componentInParent = ((Component)array[i]).GetComponentInParent<T>(); if ((Object)(object)componentInParent != (Object)null && hashSet.Add(componentInParent)) { list.Add(componentInParent); } } list.Sort(delegate(T a, T b) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //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) Vector3 val = ((Component)a).transform.position - center; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; val = ((Component)b).transform.position - center; return sqrMagnitude.CompareTo(((Vector3)(ref val)).sqrMagnitude); }); return list; } private static bool HasValidView(Component component) { ZNetView component2 = component.GetComponent<ZNetView>(); if ((Object)(object)component2 != (Object)null) { return component2.IsValid(); } return false; } private static bool IsPlaced(ItemDrop drop, out string reason) { if (!drop.m_autoPickup) { reason = "autoPickup=false"; return true; } if ((Object)(object)((Component)drop).GetComponentInParent<Piece>() != (Object)null) { reason = "part of a piece"; return true; } if (IsKinematic(drop)) { reason = "no free-moving rigidbody"; return true; } reason = null; return false; } private static bool IsKinematic(ItemDrop drop) { Rigidbody component = ((Component)drop).GetComponent<Rigidbody>(); if (!((Object)(object)component == (Object)null)) { return component.isKinematic; } return true; } private bool IsBlacklisted(GameObject go) { if (_blacklist.Count > 0) { return _blacklist.Contains(PrefabName(go)); } return false; } private static string PrefabName(GameObject go) { string text = ((Object)go).name; int num = text.IndexOf("(Clone)", StringComparison.Ordinal); if (num >= 0) { text = text.Substring(0, num); } return text.Trim(); } private static string BuildSummary(int collected, int harvested, bool inventoryFull) { string text = ((collected == 0 && harvested == 0) ? "Nothing to pick up" : ((harvested <= 0) ? $"Picked up {collected} item(s)" : $"Picked up {collected} item(s), harvested {harvested}")); if (inventoryFull) { text += " — inventory full, some left behind"; } return text; } } [HarmonyPatch(typeof(Player), "Message")] internal static class PlayerMessagePatch { private static bool Prefix(MessageType __0) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 if (AreaPickupPlugin.SuppressTopLeftMessages) { return (int)__0 != 1; } return true; } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }