Decompiled source of DadsVeinmine v1.0.0

DadsVeinmine.dll

Decompiled 2 hours ago
using 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 BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("DadsVeinmine")]
[assembly: AssemblyDescription("Vein mining for Valheim 1.0.12")]
[assembly: AssemblyCompany("Dad_Is_Bored")]
[assembly: AssemblyProduct("DadsVeinmine")]
[assembly: AssemblyCopyright("Copyright 2026 Dad_Is_Bored")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.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 DadsVeinmine
{
	[BepInPlugin("com.dadisbored.dadsveinmine", "DadsVeinmine", "1.0.0")]
	[BepInProcess("valheim.exe")]
	public sealed class DadsVeinminePlugin : BaseUnityPlugin
	{
		internal enum ActivationModes
		{
			HoldKey,
			AlwaysOn,
			Off
		}

		public const string PluginGuid = "com.dadisbored.dadsveinmine";

		public const string PluginName = "DadsVeinmine";

		public const string PluginVersion = "1.0.0";

		internal static DadsVeinminePlugin Instance = null;

		internal static ConfigEntry<ActivationModes> ActivationMode = null;

		internal static ConfigEntry<KeyboardShortcut> ActivationKey = null;

		internal static ConfigEntry<int> SectionsPerFrame = null;

		internal static ConfigEntry<string> ExcludedPrefabFragments = null;

		internal static ConfigEntry<bool> ProgressiveMode = null;

		internal static ConfigEntry<float> ProgressiveRadiusMultiplier = null;

		internal static ConfigEntry<float> MinimumProgressiveRadius = null;

		internal static ConfigEntry<float> AdditionalStaminaPerSection = null;

		internal static ConfigEntry<float> ExtraSkillGainMultiplier = null;

		private readonly List<MiningJob> _jobs = new List<MiningJob>();

		private readonly HashSet<int> _activeTargets = new HashSet<int>();

		private Harmony? _harmony;

		private static readonly FieldInfo MineRockHitAreasField = AccessTools.Field(typeof(MineRock), "m_hitAreas");

		private static readonly FieldInfo MineRockViewField = AccessTools.Field(typeof(MineRock), "m_nview");

		private static readonly FieldInfo MineRock5HitAreasField = AccessTools.Field(typeof(MineRock5), "m_hitAreas");

		private static readonly FieldInfo MineRock5ViewField = AccessTools.Field(typeof(MineRock5), "m_nview");

		private static readonly MethodInfo MineRock5SetupCollidersMethod = AccessTools.Method(typeof(MineRock5), "SetupColliders", (Type[])null, (Type[])null);

		private static readonly MethodInfo MineRock5LoadHealthMethod = AccessTools.Method(typeof(MineRock5), "LoadHealth", (Type[])null, (Type[])null);

		private static readonly Type MineRock5HitAreaType = AccessTools.Inner(typeof(MineRock5), "HitArea");

		private static readonly FieldInfo MineRock5AreaColliderField = AccessTools.Field(MineRock5HitAreaType, "m_collider");

		private static readonly FieldInfo MineRock5AreaHealthField = AccessTools.Field(MineRock5HitAreaType, "m_health");

		private void Awake()
		{
			//IL_0040: 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_0081: Expected O, but got Unknown
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Expected O, but got Unknown
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Expected O, but got Unknown
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Expected O, but got Unknown
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Expected O, but got Unknown
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Expected O, but got Unknown
			Instance = this;
			ActivationMode = ((BaseUnityPlugin)this).Config.Bind<ActivationModes>("1 - Activation", "Mode", ActivationModes.HoldKey, "HoldKey requires the configured key, AlwaysOn activates on every valid pickaxe hit, and Off disables vein mining.");
			ActivationKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("1 - Activation", "Hold Key", new KeyboardShortcut((KeyCode)308, Array.Empty<KeyCode>()), "Key held while striking a mine rock or ore deposit in HoldKey mode.");
			SectionsPerFrame = ((BaseUnityPlugin)this).Config.Bind<int>("2 - Mining", "Sections Per Frame", 8, new ConfigDescription("Maximum sections sent through Valheim's native mining handler per frame.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 64), Array.Empty<object>()));
			ExcludedPrefabFragments = ((BaseUnityPlugin)this).Config.Bind<string>("2 - Mining", "Excluded Prefab Fragments", string.Empty, "Comma-separated prefab-name fragments that DadsVeinmine must ignore. Matching is case-insensitive.");
			ProgressiveMode = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Progressive Mining", "Enabled", false, "Limit vein mining to a radius derived from the player's Pickaxes skill.");
			ProgressiveRadiusMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Progressive Mining", "Skill Radius Multiplier", 0.1f, new ConfigDescription("Pickaxes skill is multiplied by this value to determine mining radius.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 10f), Array.Empty<object>()));
			MinimumProgressiveRadius = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Progressive Mining", "Minimum Radius", 1f, new ConfigDescription("Minimum radius used while progressive mining is enabled.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 100f), Array.Empty<object>()));
			AdditionalStaminaPerSection = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Costs", "Additional Stamina Per Section", 0f, new ConfigDescription("Stamina charged for every section after the first. Zero disables the additional stamina cost.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1000f), Array.Empty<object>()));
			ExtraSkillGainMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Costs", "Extra Pickaxes Skill Gain", 0.2f, new ConfigDescription("Pickaxes skill gain applied for every section after the first. Zero disables additional skill gain.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
			_harmony = new Harmony("com.dadisbored.dadsveinmine");
			_harmony.PatchAll(typeof(DadsVeinminePlugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"DadsVeinmine 1.0.0 loaded for Valheim 1.0.12.");
		}

		private void Update()
		{
			for (int num = _jobs.Count - 1; num >= 0; num--)
			{
				MiningJob miningJob = _jobs[num];
				int num2 = Mathf.Clamp(SectionsPerFrame.Value, 1, 64);
				while (num2-- > 0 && miningJob.NextTarget < miningJob.Targets.Count)
				{
					if (!ProcessNextTarget(miningJob))
					{
						miningJob.NextTarget = miningJob.Targets.Count;
						break;
					}
				}
				if (miningJob.NextTarget >= miningJob.Targets.Count)
				{
					_activeTargets.Remove(miningJob.TargetInstanceId);
					_jobs.RemoveAt(num);
				}
			}
		}

		private bool ProcessNextTarget(MiningJob job)
		{
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)job.View == (Object)null || !job.View.IsValid() || (Object)(object)job.Player == (Object)null || ((Character)job.Player).IsDead())
			{
				return false;
			}
			MiningTarget miningTarget = job.Targets[job.NextTarget];
			if (job.NextTarget > 0)
			{
				if (((Humanoid)job.Player).GetCurrentWeapon() != job.Weapon)
				{
					return false;
				}
				float num = Mathf.Max(0f, AdditionalStaminaPerSection.Value);
				if (num > 0f && !((Character)job.Player).HaveStamina(num))
				{
					return false;
				}
				if (job.Weapon.m_shared.m_useDurability)
				{
					if (job.Weapon.m_durability <= 0f)
					{
						return false;
					}
					float num2 = Mathf.Max(0f, job.Weapon.m_shared.m_useDurabilityDrain * Game.m_durabilityRate);
					job.Weapon.m_durability = Mathf.Max(0f, job.Weapon.m_durability - num2);
				}
				if (num > 0f)
				{
					((Character)job.Player).UseStamina(num);
				}
				float num3 = Mathf.Max(0f, ExtraSkillGainMultiplier.Value);
				if (num3 > 0f)
				{
					((Character)job.Player).RaiseSkill((SkillType)12, num3);
				}
			}
			HitData val = job.SourceHit.Clone();
			val.m_hitCollider = miningTarget.Collider;
			val.m_point = miningTarget.Point;
			val.m_damage.m_pickaxe = Mathf.Max(val.m_damage.m_pickaxe, 1000000f);
			job.View.InvokeRPC(job.RpcName, new object[2] { val, miningTarget.AreaIndex });
			job.NextTarget++;
			return true;
		}

		internal bool QueueMineRock(MineRock rock, HitData hit)
		{
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: 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)
			if (!TryGetMiningContext((Component)(object)rock, hit, rock.m_minToolTier, out Player player, out ItemData weapon))
			{
				return false;
			}
			object? value = MineRockViewField.GetValue(rock);
			ZNetView val = (ZNetView)((value is ZNetView) ? value : null);
			Collider[] array = MineRockHitAreasField.GetValue(rock) as Collider[];
			if ((Object)(object)val == (Object)null || !val.IsValid() || val.GetZDO() == null || array == null)
			{
				return false;
			}
			int instanceID = ((Object)rock).GetInstanceID();
			if (_activeTargets.Contains(instanceID))
			{
				return true;
			}
			List<MiningTarget> list = new List<MiningTarget>();
			float maximumDistance = GetMaximumDistance(player);
			for (int i = 0; i < array.Length; i++)
			{
				Collider val2 = array[i];
				if (!((Object)(object)val2 == (Object)null) && !(val.GetZDO().GetFloat("Health" + i, rock.GetHealth()) <= 0f))
				{
					Bounds bounds = val2.bounds;
					Vector3 center = ((Bounds)(ref bounds)).center;
					if (Vector3.Distance(hit.m_point, center) <= maximumDistance)
					{
						list.Add(new MiningTarget(i, val2, center));
					}
				}
			}
			return QueueJob(instanceID, val, "Hit", hit, player, weapon, list);
		}

		internal bool QueueMineRock5(MineRock5 rock, HitData hit)
		{
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: 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_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: 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)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			if (!TryGetMiningContext((Component)(object)rock, hit, rock.m_minToolTier, out Player player, out ItemData weapon))
			{
				return false;
			}
			MineRock5SetupCollidersMethod.Invoke(rock, null);
			MineRock5LoadHealthMethod.Invoke(rock, null);
			object? value = MineRock5ViewField.GetValue(rock);
			ZNetView val = (ZNetView)((value is ZNetView) ? value : null);
			IList list = MineRock5HitAreasField.GetValue(rock) as IList;
			if ((Object)(object)val == (Object)null || !val.IsValid() || list == null)
			{
				return false;
			}
			int instanceID = ((Object)rock).GetInstanceID();
			if (_activeTargets.Contains(instanceID))
			{
				return true;
			}
			List<MiningTarget> list2 = new List<MiningTarget>();
			float maximumDistance = GetMaximumDistance(player);
			for (int i = 0; i < list.Count; i++)
			{
				object obj = list[i];
				if (obj == null)
				{
					continue;
				}
				object? value2 = MineRock5AreaColliderField.GetValue(obj);
				Collider val2 = (Collider)((value2 is Collider) ? value2 : null);
				float num = (float)MineRock5AreaHealthField.GetValue(obj);
				if (!((Object)(object)val2 == (Object)null) && !(num <= 0f))
				{
					Bounds bounds = val2.bounds;
					Vector3 center = ((Bounds)(ref bounds)).center;
					if (Vector3.Distance(hit.m_point, center) <= maximumDistance)
					{
						list2.Add(new MiningTarget(i, val2, center));
					}
				}
			}
			return QueueJob(instanceID, val, "RPC_Damage", hit, player, weapon, list2);
		}

		private bool QueueJob(int instanceId, ZNetView view, string rpcName, HitData hit, Player player, ItemData weapon, List<MiningTarget> targets)
		{
			if ((Object)(object)view == (Object)null || !view.IsValid() || targets.Count == 0)
			{
				return false;
			}
			List<MiningTarget> targets2 = targets.OrderBy(delegate(MiningTarget target)
			{
				//IL_0001: 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_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)
				Vector3 val = target.Point - hit.m_point;
				return ((Vector3)(ref val)).sqrMagnitude;
			}).ToList();
			_activeTargets.Add(instanceId);
			_jobs.Add(new MiningJob(instanceId, view, rpcName, hit.Clone(), player, weapon, targets2));
			return true;
		}

		private static bool TryGetMiningContext(Component target, HitData hit, int minimumToolTier, out Player player, out ItemData weapon)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			player = null;
			weapon = null;
			if (!ActivationHeld() || hit == null || (Object)(object)target == (Object)null || IsExcluded(target))
			{
				return false;
			}
			Character attacker = hit.GetAttacker();
			Player val = (Player)(object)((attacker is Player) ? attacker : null);
			if ((Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)Player.m_localPlayer)
			{
				return false;
			}
			player = val;
			ItemData currentWeapon = ((Humanoid)player).GetCurrentWeapon();
			if (currentWeapon == null)
			{
				return false;
			}
			weapon = currentWeapon;
			if (weapon.GetDamage().m_pickaxe > 0f && hit.m_damage.m_pickaxe > 0f)
			{
				return hit.m_toolTier >= minimumToolTier;
			}
			return false;
		}

		private static bool ActivationHeld()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			switch (ActivationMode.Value)
			{
			case ActivationModes.AlwaysOn:
				return true;
			case ActivationModes.Off:
				return false;
			default:
			{
				KeyboardShortcut value = ActivationKey.Value;
				if ((int)((KeyboardShortcut)(ref value)).MainKey == 0 || !Input.GetKey(((KeyboardShortcut)(ref value)).MainKey))
				{
					return false;
				}
				return ((KeyboardShortcut)(ref value)).Modifiers.All((Func<KeyCode, bool>)Input.GetKey);
			}
			}
		}

		private static bool IsExcluded(Component target)
		{
			string prefabName = Utils.GetPrefabName(target.gameObject);
			return (from fragment in ExcludedPrefabFragments.Value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries)
				select fragment.Trim()).Any((string fragment) => fragment.Length > 0 && prefabName.IndexOf(fragment, StringComparison.OrdinalIgnoreCase) >= 0);
		}

		private static float GetMaximumDistance(Player player)
		{
			if (!ProgressiveMode.Value)
			{
				return float.PositiveInfinity;
			}
			float skillLevel = ((Character)player).GetSkills().GetSkillLevel((SkillType)12);
			return Mathf.Max(Mathf.Max(0.1f, MinimumProgressiveRadius.Value), skillLevel * Mathf.Max(0.01f, ProgressiveRadiusMultiplier.Value));
		}

		private void OnDestroy()
		{
			_jobs.Clear();
			_activeTargets.Clear();
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	internal sealed class MiningJob
	{
		internal readonly int TargetInstanceId;

		internal readonly ZNetView View;

		internal readonly string RpcName;

		internal readonly HitData SourceHit;

		internal readonly Player Player;

		internal readonly ItemData Weapon;

		internal readonly List<MiningTarget> Targets;

		internal int NextTarget;

		internal MiningJob(int targetInstanceId, ZNetView view, string rpcName, HitData sourceHit, Player player, ItemData weapon, List<MiningTarget> targets)
		{
			TargetInstanceId = targetInstanceId;
			View = view;
			RpcName = rpcName;
			SourceHit = sourceHit;
			Player = player;
			Weapon = weapon;
			Targets = targets;
		}
	}
	internal readonly struct MiningTarget
	{
		internal readonly int AreaIndex;

		internal readonly Collider Collider;

		internal readonly Vector3 Point;

		internal MiningTarget(int areaIndex, Collider collider, Vector3 point)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			AreaIndex = areaIndex;
			Collider = collider;
			Point = point;
		}
	}
	[HarmonyPatch(typeof(MineRock), "Damage")]
	internal static class MineRockDamagePatch
	{
		private static bool Prefix(MineRock __instance, HitData hit)
		{
			return !DadsVeinminePlugin.Instance.QueueMineRock(__instance, hit);
		}
	}
	[HarmonyPatch(typeof(MineRock5), "Damage")]
	internal static class MineRock5DamagePatch
	{
		private static bool Prefix(MineRock5 __instance, HitData hit)
		{
			return !DadsVeinminePlugin.Instance.QueueMineRock5(__instance, hit);
		}
	}
}