Decompiled source of NoAutoPickup v0.1.2

NoAutoPickup.dll

Decompiled 2 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[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("NoAutoPickup")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.2.0")]
[assembly: AssemblyInformationalVersion("0.1.2+7b3884cc30328564314e91bb160e4939887cae56")]
[assembly: AssemblyProduct("NoAutoPickup")]
[assembly: AssemblyTitle("NoAutoPickup")]
[assembly: AssemblyVersion("0.1.2.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 NoAutoPickup
{
	internal static class DrawerApi
	{
		private static MethodInfo? _allDrawers;

		internal static void Init()
		{
			Type type = Type.GetType("API.ClientSideV2, kg_ItemDrawers");
			if (type == null)
			{
				Plugin.Log.LogInfo((object)"kg.ItemDrawers not found; drawer zones disabled until that mod is present.");
				return;
			}
			_allDrawers = type.GetMethod("AllDrawers", BindingFlags.Static | BindingFlags.Public);
			if (_allDrawers == null)
			{
				Plugin.Log.LogWarning((object)"kg.ItemDrawers loaded but API.ClientSideV2.AllDrawers was not found.");
			}
			else
			{
				Plugin.Log.LogInfo((object)"Using kg.ItemDrawers AllDrawers API for drawer exclusion zones.");
			}
		}

		internal static bool AnyInRange(Vector3 origin, float range)
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			if (_allDrawers == null)
			{
				return false;
			}
			float num = range * range;
			try
			{
				if (!(_allDrawers.Invoke(null, null) is IEnumerable enumerable))
				{
					return false;
				}
				foreach (object item in enumerable)
				{
					ZNetView val = (ZNetView)((item is ZNetView) ? item : null);
					if (val != null && Object.op_Implicit((Object)(object)val) && val.IsValid() && Object.op_Implicit((Object)(object)((Component)val).transform))
					{
						Vector3 val2 = ((Component)val).transform.position - origin;
						if (((Vector3)(ref val2)).sqrMagnitude <= num)
						{
							return true;
						}
					}
				}
			}
			catch (Exception ex)
			{
				if (ModConfig.DebugLogs.Value)
				{
					Plugin.Log.LogWarning((object)("ItemDrawers scan failed: " + ex.Message));
				}
			}
			return false;
		}
	}
	internal static class ModConfig
	{
		internal static ConfigEntry<bool> Enabled = null;

		internal static ConfigEntry<bool> DebugLogs = null;

		internal static ConfigEntry<float> RangePadding = null;

		internal static ConfigEntry<float> VanillaFloor = null;

		internal static ConfigEntry<bool> FiresEnabled = null;

		internal static ConfigEntry<bool> OnlyIfBurning = null;

		internal static ConfigEntry<string> FirePrefabs = null;

		internal static ConfigEntry<bool> TamesEnabled = null;

		internal static ConfigEntry<bool> DrawersEnabled = null;

		private static HashSet<string> _firePrefabNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		internal static void Bind(ConfigFile config)
		{
			Enabled = config.Bind<bool>("General", "Enabled", true, "If off, auto-pickup is never suppressed.");
			DebugLogs = config.Bind<bool>("General", "Debug Logs", false, "Log when auto-pickup is suppressed or restored, and the active exclusion range.");
			VanillaFloor = config.Bind<float>("Range", "Vanilla Floor", 2f, "Valheim's default auto-pickup range. Used as the minimum in the max() of all pickup radii.");
			RangePadding = config.Bind<float>("Range", "Range Padding", 0f, "Extra meters added after taking the largest pickup-related range.");
			FiresEnabled = config.Bind<bool>("Fires", "Enabled", true, "Suppress auto-pickup near campfires and hearths so tossed fuel/food is not vacuumed.");
			OnlyIfBurning = config.Bind<bool>("Fires", "Only If Burning", false, "If on, only lit fires count. Off = unlit campfires and hearths still suppress auto-pickup.");
			FirePrefabs = config.Bind<string>("Fires", "Prefab Names", "fire_pit,hearth", "Comma-separated prefab names (Clone suffix ignored). Add bonfire here if you want it.");
			TamesEnabled = config.Bind<bool>("Tames", "Enabled", true, "Suppress auto-pickup near tamed animals so tossed food stays on the ground for them.");
			DrawersEnabled = config.Bind<bool>("Drawers", "Enabled", true, "Suppress auto-pickup near Item Drawers so tossed items can be vacuumed by drawers instead of players.");
			FirePrefabs.SettingChanged += delegate
			{
				RebuildFirePrefabs();
			};
			RebuildFirePrefabs();
		}

		internal static bool IsWatchedFirePrefab(string prefabName)
		{
			return _firePrefabNames.Contains(prefabName);
		}

		private static void RebuildFirePrefabs()
		{
			_firePrefabNames = (from s in FirePrefabs.Value.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries)
				select s.Trim() into s
				where s.Length > 0
				select s).ToHashSet<string>(StringComparer.OrdinalIgnoreCase);
		}
	}
	internal static class FireplaceRegistry
	{
		private static readonly HashSet<Fireplace> Fires = new HashSet<Fireplace>();

		internal static IEnumerable<Fireplace> All
		{
			get
			{
				Fires.RemoveWhere((Fireplace f) => !Object.op_Implicit((Object)(object)f));
				return Fires;
			}
		}

		internal static void Add(Fireplace fire)
		{
			if (Object.op_Implicit((Object)(object)fire))
			{
				Fires.Add(fire);
			}
		}

		internal static void Remove(Fireplace fire)
		{
			if (Object.op_Implicit((Object)(object)fire))
			{
				Fires.Remove(fire);
			}
		}
	}
	[HarmonyPatch(typeof(Fireplace), "Awake")]
	internal static class FireplaceAwakePatch
	{
		private static void Postfix(Fireplace __instance)
		{
			FireplaceRegistry.Add(__instance);
		}
	}
	[HarmonyPatch(typeof(Player), "AutoPickup")]
	internal static class PlayerAutoPickupPatch
	{
		private static void Prefix(Player __instance)
		{
			try
			{
				PickupGuard.Tick(__instance);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"NoAutoPickup tick failed: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(Game), "Logout")]
	internal static class GameLogoutPatch
	{
		private static void Prefix()
		{
			PickupGuard.ForceRestore();
		}
	}
	[HarmonyPatch(typeof(Player), "OnDestroy")]
	internal static class PlayerDestroyPatch
	{
		private static void Prefix(Player __instance)
		{
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				PickupGuard.ForceRestore();
			}
		}
	}
	internal static class PlayerFields
	{
		private static readonly FieldRef<bool> EnableAutoPickup = AccessTools.StaticFieldRefAccess<bool>(AccessTools.DeclaredField(typeof(Player), "m_enableAutoPickup"));

		private static readonly FieldRef<Player, float> AutoPickupRange = AccessTools.FieldRefAccess<Player, float>(AccessTools.DeclaredField(typeof(Player), "m_autoPickupRange"));

		internal static bool GetEnabled()
		{
			return EnableAutoPickup.Invoke();
		}

		internal static void SetEnabled(bool value, bool announce)
		{
			if (GetEnabled() != value)
			{
				EnableAutoPickup.Invoke() = value;
				if (announce)
				{
					Announce();
				}
			}
		}

		internal static void Announce()
		{
			Player localPlayer = Player.m_localPlayer;
			if (Object.op_Implicit((Object)(object)localPlayer))
			{
				string text = (GetEnabled() ? "$hud_on" : "$hud_off");
				((Character)localPlayer).Message((MessageType)1, "$hud_autopickup:" + text, 0, (Sprite)null, false);
			}
		}

		internal static float GetRange(Player player)
		{
			if (!((Object)(object)player == (Object)null))
			{
				return AutoPickupRange.Invoke(player);
			}
			return 0f;
		}
	}
	internal static class PickupGuard
	{
		private static bool _inZone;

		private static bool _weSuppressed;

		private static bool _savedEnabled;

		private static string _lastReason = "none";

		private static readonly List<Character> _tameScratch = new List<Character>(32);

		internal static void Tick(Player player)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			if (!ModConfig.Enabled.Value)
			{
				ForceRestore();
				return;
			}
			float range = RangeSources.CurrentExclusionRange(player);
			if (IsInExclusionZone(((Component)player).transform.position, range, out string reason))
			{
				OnInsideZone(reason, range);
			}
			else
			{
				OnOutsideZone();
			}
		}

		internal static void ForceRestore()
		{
			_inZone = false;
			RestoreIfNeeded(announce: false);
		}

		private static void OnInsideZone(string reason, float range)
		{
			if (!_inZone)
			{
				_inZone = true;
				_lastReason = reason;
				if (PlayerFields.GetEnabled())
				{
					_savedEnabled = true;
					_weSuppressed = true;
					PlayerFields.SetEnabled(value: false, announce: true);
					if (ModConfig.DebugLogs.Value)
					{
						Plugin.Log.LogInfo((object)$"Auto-pickup off near {reason} (range {range:0.##}).");
					}
				}
				else if (ModConfig.DebugLogs.Value)
				{
					Plugin.Log.LogInfo((object)("Entered " + reason + " zone with auto-pickup already off."));
				}
				return;
			}
			if (_weSuppressed && PlayerFields.GetEnabled())
			{
				_weSuppressed = false;
				_savedEnabled = true;
				if (ModConfig.DebugLogs.Value)
				{
					Plugin.Log.LogInfo((object)"Auto-pickup hotkey turned it back on; leaving it on until you leave this zone.");
				}
			}
			if (ModConfig.DebugLogs.Value && reason != _lastReason)
			{
				Plugin.Log.LogInfo((object)("Zone is now " + reason + "."));
			}
			_lastReason = reason;
		}

		private static void OnOutsideZone()
		{
			if (_inZone || _weSuppressed)
			{
				_inZone = false;
				RestoreIfNeeded(announce: true);
			}
		}

		private static void RestoreIfNeeded(bool announce)
		{
			if (_weSuppressed)
			{
				PlayerFields.SetEnabled(_savedEnabled, announce);
				_weSuppressed = false;
				if (ModConfig.DebugLogs.Value)
				{
					Plugin.Log.LogInfo((object)("Auto-pickup restored to " + (_savedEnabled ? "on" : "off") + "."));
				}
				_lastReason = "none";
			}
		}

		private static bool IsInExclusionZone(Vector3 origin, float range, out string reason)
		{
			//IL_001d: 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_0059: Unknown result type (might be due to invalid IL or missing references)
			reason = "none";
			if (range <= 0f)
			{
				return false;
			}
			if (ModConfig.FiresEnabled.Value && AnyFireInRange(origin, range))
			{
				reason = "campfire/hearth";
				return true;
			}
			if (ModConfig.TamesEnabled.Value && AnyTameInRange(origin, range))
			{
				reason = "tamed animal";
				return true;
			}
			if (ModConfig.DrawersEnabled.Value && DrawerApi.AnyInRange(origin, range))
			{
				reason = "item drawer";
				return true;
			}
			return false;
		}

		private static bool AnyFireInRange(Vector3 origin, float range)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			float num = range * range;
			foreach (Fireplace item in FireplaceRegistry.All)
			{
				if (Object.op_Implicit((Object)(object)item) && Object.op_Implicit((Object)(object)((Component)item).transform))
				{
					Vector3 val = ((Component)item).transform.position - origin;
					if (!(((Vector3)(ref val)).sqrMagnitude > num) && (!ModConfig.OnlyIfBurning.Value || item.IsBurning()) && ModConfig.IsWatchedFirePrefab(PrefabName(((Component)item).gameObject)))
					{
						return true;
					}
				}
			}
			return false;
		}

		private static bool AnyTameInRange(Vector3 origin, float range)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			_tameScratch.Clear();
			Character.GetCharactersInRange(origin, range, _tameScratch);
			foreach (Character item in _tameScratch)
			{
				if (Object.op_Implicit((Object)(object)item) && !item.IsPlayer() && item.IsTamed())
				{
					return true;
				}
			}
			return false;
		}

		internal static string PrefabName(GameObject go)
		{
			if (!Object.op_Implicit((Object)(object)go))
			{
				return string.Empty;
			}
			string name = ((Object)go).name;
			int num = name.IndexOf("(Clone)", StringComparison.Ordinal);
			if (num < 0)
			{
				return name;
			}
			return name.Substring(0, num).Trim();
		}
	}
	[BepInPlugin("Ageous.NoAutoPickup", "NoAutoPickup", "0.1.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string ModGUID = "Ageous.NoAutoPickup";

		public const string ModName = "NoAutoPickup";

		public const string ModVersion = "0.1.2";

		internal static Plugin Instance;

		internal static ManualLogSource Log;

		internal static Harmony Harmony;

		private void Awake()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			ModConfig.Bind(((BaseUnityPlugin)this).Config);
			DrawerApi.Init();
			Harmony = new Harmony("Ageous.NoAutoPickup");
			Harmony.PatchAll();
			Log.LogInfo((object)"NoAutoPickup 0.1.2 loaded (client auto-pickup guard).");
		}

		private void OnDestroy()
		{
			PickupGuard.ForceRestore();
			Harmony harmony = Harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	internal static class RangeSources
	{
		private static readonly Regex DrawerRange = new Regex("^\\s*DrawerPickupRange\\s*=\\s*([0-9]+(?:\\.[0-9]+)?)\\s*$", RegexOptions.Multiline | RegexOptions.CultureInvariant);

		private static readonly Regex BiggerRadius = new Regex("^\\s*Radius\\s*=\\s*([0-9]+(?:\\.[0-9]+)?)\\s*$", RegexOptions.Multiline | RegexOptions.CultureInvariant);

		internal static float CurrentExclusionRange(Player player)
		{
			float val = Math.Max(0f, ModConfig.VanillaFloor.Value);
			float range = PlayerFields.GetRange(player);
			if (range > 0f)
			{
				val = Math.Max(val, range);
			}
			val = Math.Max(val, ReadConfigFloat("net.mtnewton.biggerpickupradius.cfg", BiggerRadius));
			val = Math.Max(val, ReadConfigFloat("kg.ItemDrawers.cfg", DrawerRange));
			float num = Math.Max(0f, ModConfig.RangePadding.Value);
			return val + num;
		}

		private static float ReadConfigFloat(string fileName, Regex pattern)
		{
			try
			{
				string path = Path.Combine(Paths.ConfigPath, fileName);
				if (!File.Exists(path))
				{
					return 0f;
				}
				Match match = pattern.Match(File.ReadAllText(path));
				if (!match.Success)
				{
					return 0f;
				}
				if (float.TryParse(match.Groups[1].Value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && result > 0f)
				{
					return result;
				}
			}
			catch (Exception ex)
			{
				if (ModConfig.DebugLogs.Value)
				{
					Plugin.Log.LogWarning((object)("Failed reading " + fileName + ": " + ex.Message));
				}
			}
			return 0f;
		}
	}
}