Decompiled source of VeinMining v0.3.4

BepInEx/plugins/VeinMining/VeinMining.dll

Decompiled 4 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("SharedMining.RuntimeTests")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("VeinMining")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.3.4.0")]
[assembly: AssemblyInformationalVersion("0.3.4")]
[assembly: AssemblyProduct("VeinMining")]
[assembly: AssemblyTitle("VeinMining")]
[assembly: AssemblyVersion("0.3.4.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 SharedMining
{
	internal static class Catalog
	{
		private static readonly HashSet<string> Ores = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "CopperOre", "TinOre", "IronScrap", "SilverOre", "FlametalOre", "FlametalOreNew", "CopperScrap", "BlackMetalScrap", "Obsidian", "Chitin" };

		internal static string PrefabName(GameObject go)
		{
			ZNetView component = go.GetComponent<ZNetView>();
			GameObject val = ((Object.op_Implicit((Object)(object)component) && component.IsValid() && Object.op_Implicit((Object)(object)ZNetScene.instance)) ? ZNetScene.instance.GetPrefab(component.GetZDO().GetPrefab()) : null);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return Utils.GetPrefabName(go);
			}
			return ((Object)val).name;
		}

		internal static IEnumerable<string> Drops(GameObject go, int depth = 0)
		{
			IEnumerable<string> enumerable = (from d in (go.GetComponent<MineRock5>()?.m_dropItems ?? go.GetComponent<MineRock>()?.m_dropItems ?? go.GetComponent<DropOnDestroyed>()?.m_dropWhenDestroyed)?.m_drops
				where Object.op_Implicit((Object)(object)d.m_item)
				select Utils.GetPrefabName(d.m_item)) ?? Enumerable.Empty<string>();
			GameObject val = go.GetComponent<Destructible>()?.m_spawnWhenDestroyed;
			if (!Object.op_Implicit((Object)(object)val) || depth >= 4)
			{
				return enumerable;
			}
			return enumerable.Concat(Drops(val, depth + 1)).Distinct();
		}

		internal static bool Supported(GameObject go)
		{
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Invalid comparison between Unknown and I4
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Invalid comparison between Unknown and I4
			if (!Object.op_Implicit((Object)(object)Deposit.ComponentOn(go)) || Object.op_Implicit((Object)(object)go.GetComponent<Piece>()))
			{
				return false;
			}
			Destructible component = go.GetComponent<Destructible>();
			if (Object.op_Implicit((Object)(object)component) && (Object.op_Implicit((Object)(object)component.m_spawnWhenDamaged) || (Object.op_Implicit((Object)(object)component.m_spawnWhenDestroyed) && !Object.op_Implicit((Object)(object)component.m_spawnWhenDestroyed.GetComponent<MineRock5>()))))
			{
				return false;
			}
			string name = PrefabName(go);
			if (Plugin.Instance.Excluded.Value.Split(new char[1] { ',' }).Any((string x) => x.Trim() == name))
			{
				return false;
			}
			if (Plugin.Instance.Included.Value.Split(new char[1] { ',' }).Any((string x) => x.Trim() == name))
			{
				return true;
			}
			if (Object.op_Implicit((Object)(object)component) && ((int)component.m_damages.m_pickaxe == 3 || (int)component.m_damages.m_chop != 3 || Object.op_Implicit((Object)(object)go.GetComponent<Character>())))
			{
				return false;
			}
			return Drops(go).Any((string d) => Ores.Contains(d) || d.EndsWith("Ore", StringComparison.OrdinalIgnoreCase));
		}

		internal static int RequiredTier(GameObject go)
		{
			Destructible component = go.GetComponent<Destructible>();
			int num = go.GetComponent<MineRock5>()?.m_minToolTier ?? go.GetComponent<MineRock>()?.m_minToolTier ?? component?.m_minToolTier ?? 0;
			if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component.m_spawnWhenDestroyed))
			{
				return num;
			}
			return Math.Max(num, RequiredTier(component.m_spawnWhenDestroyed));
		}

		internal static void Audit()
		{
			if (!Object.op_Implicit((Object)(object)ZNetScene.instance))
			{
				return;
			}
			List<string> list = new List<string> { "prefab\tadapter\tenabled\tdrops\tstaged\tonDamaged\tonDestroyed\thealth\tpickaxe\tchop" };
			foreach (GameObject item in from g in ZNetScene.instance.m_prefabs
				where Object.op_Implicit((Object)(object)g) && Object.op_Implicit((Object)(object)Deposit.ComponentOn(g))
				orderby ((Object)g).name
				select g)
			{
				Destructible component = item.GetComponent<Destructible>();
				list.Add(string.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}\t{9}", ((Object)item).name, ((object)Deposit.ComponentOn(item)).GetType().Name, Supported(item), string.Join(",", Drops(item)), Object.op_Implicit((Object)(object)component) && (Object.op_Implicit((Object)(object)component.m_spawnWhenDestroyed) || Object.op_Implicit((Object)(object)component.m_spawnWhenDamaged)), (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.m_spawnWhenDamaged)) ? ((Object)component.m_spawnWhenDamaged).name : "", (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.m_spawnWhenDestroyed)) ? ((Object)component.m_spawnWhenDestroyed).name : "", Object.op_Implicit((Object)(object)component) ? component.m_health : 0f, Object.op_Implicit((Object)(object)component) ? ((object)Unsafe.As<DamageModifier, DamageModifier>(ref component.m_damages.m_pickaxe)/*cast due to .constrained prefix*/).ToString() : "", Object.op_Implicit((Object)(object)component) ? ((object)Unsafe.As<DamageModifier, DamageModifier>(ref component.m_damages.m_chop)/*cast due to .constrained prefix*/).ToString() : ""));
			}
			string text = Path.Combine(Paths.ConfigPath, "SharedMining.prefabs.tsv");
			File.WriteAllLines(text, list);
			Plugin.Instance.Log.LogInfo((object)$"Prefab audit written: {text}; {list.Count - 1} destructible prefabs examined.");
		}
	}
	internal static class Client
	{
		internal static ZDOID Target = ZDOID.None;

		private static long token;

		private static int sequence;

		private static float requestAt;

		private static float heartbeatAt;

		private static float missingSince;

		private static bool pending;

		private static ItemData? tool;

		private static Attack? attack;

		private static readonly List<(int index, HitData hit)> Batch = new List<(int, HitData)>();

		private static readonly MiningInput InputState = new MiningInput();

		internal static bool Running => token != 0;

		[MethodImpl(MethodImplOptions.NoInlining)]
		internal static bool IsHolding()
		{
			//IL_001d: 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)
			if (Application.isFocused)
			{
				if (!InputState.Latched)
				{
					KeyboardShortcut value = Plugin.Instance.HoldKey.Value;
					return ((KeyboardShortcut)(ref value)).IsPressed();
				}
				return true;
			}
			return false;
		}

		internal static void Reset(bool keepTap = false)
		{
			//IL_000b: 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)
			InputState.Clear(keepTap);
			Target = ZDOID.None;
			token = 0L;
			sequence = 0;
			pending = false;
			tool = null;
			attack = null;
			missingSince = 0f;
			Batch.Clear();
		}

		private static void Message(string text)
		{
			if (Object.op_Implicit((Object)(object)MessageHud.instance))
			{
				MessageHud.instance.ShowMessage((MessageType)2, text, 0, (Sprite)null, false, true);
			}
		}

		internal static void Stop(string message, bool keepTap = false)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			if (token != 0L && ZRoutedRpc.instance != null)
			{
				ZPackage val = new ZPackage();
				val.Write(token);
				ZRoutedRpc.instance.InvokeRoutedRPC("SharedMining.Stop.v1", new object[1] { val });
			}
			Reset(keepTap);
			if (message.Length > 0)
			{
				Message(message);
			}
		}

		internal static void Update()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Expected O, but got Unknown
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Invalid comparison between Unknown and I4
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_031f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Unknown result type (might be due to invalid IL or missing references)
			//IL_0349: Unknown result type (might be due to invalid IL or missing references)
			//IL_034e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0363: Unknown result type (might be due to invalid IL or missing references)
			//IL_036a: Expected O, but got Unknown
			//IL_0374: Unknown result type (might be due to invalid IL or missing references)
			//IL_0381: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer) || ZRoutedRpc.instance == null)
			{
				Reset();
				return;
			}
			int num;
			if (Application.isFocused)
			{
				KeyboardShortcut value = Plugin.Instance.HoldKey.Value;
				num = (((KeyboardShortcut)(ref value)).IsDown() ? 1 : 0);
			}
			else
			{
				num = 0;
			}
			bool flag = (byte)num != 0;
			if (!Application.isFocused || InputBlocked())
			{
				InputState.Clear();
			}
			else if (flag && InputState.Press(Time.unscaledTime))
			{
				Stop("Mining paused.");
				return;
			}
			if ((Running || pending) && !IsHolding())
			{
				Stop("", Application.isFocused && !InputBlocked());
				return;
			}
			if (pending && Time.time - requestAt > 8f)
			{
				Stop("The server did not respond. Check that Vein Mining is installed on it.");
			}
			if (Running && (!ValidPlayer(localPlayer) || ((Humanoid)localPlayer).GetCurrentWeapon() != tool || (tool.m_shared.m_useDurability && tool.m_durability <= 0f)))
			{
				Stop("Mining stopped. Shared progress has been saved.");
			}
			if (Running && (Object)(object)TargetView() == (Object)null)
			{
				if (missingSince == 0f)
				{
					missingSince = Time.time;
				}
				if (Time.time - missingSince > 2f)
				{
					Stop("");
				}
			}
			else
			{
				missingSince = 0f;
			}
			if (Running && Time.time >= heartbeatAt)
			{
				heartbeatAt = Time.time + 3f;
				ZPackage val = new ZPackage();
				val.Write(token);
				ZRoutedRpc.instance.InvokeRoutedRPC("SharedMining.Keep.v1", new object[1] { val });
			}
			if (!flag || !IsHolding() || InputBlocked() || Running || pending)
			{
				return;
			}
			if (!MiningCompatibility.Ready)
			{
				Message("This version of Smoothbrain Mining is not supported.");
				return;
			}
			tool = ((Humanoid)localPlayer).GetCurrentWeapon();
			if (!ValidPlayer(localPlayer) || tool == null || (int)tool.m_shared.m_skillType != 12 || (tool.m_shared.m_useDurability && tool.m_durability <= 0f))
			{
				Message("Equip a usable pickaxe first.");
				return;
			}
			Camera mainCamera = Utils.GetMainCamera();
			RaycastHit val2 = default(RaycastHit);
			if (!Object.op_Implicit((Object)(object)mainCamera) || !Physics.Raycast(((Component)mainCamera).transform.position, ((Component)mainCamera).transform.forward, ref val2, 50f, LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "terrain" }), (QueryTriggerInteraction)1))
			{
				return;
			}
			ZNetView componentInParent = ((Component)((RaycastHit)(ref val2)).collider).GetComponentInParent<ZNetView>();
			if (!Object.op_Implicit((Object)(object)componentInParent) || !componentInParent.IsValid() || !Object.op_Implicit((Object)(object)Deposit.ComponentOn(((Component)componentInParent).gameObject)))
			{
				Message("Aim at an ore deposit.");
				return;
			}
			int num2 = Catalog.RequiredTier(((Component)componentInParent).gameObject);
			if (tool.m_shared.m_toolTier < num2)
			{
				Message("Your pickaxe is too weak for this deposit.");
				return;
			}
			if (Vector3.Distance(((Component)localPlayer).transform.position, ((RaycastHit)(ref val2)).point) > 6f)
			{
				Message("Move closer to the deposit.");
				return;
			}
			Target = componentInParent.GetZDO().m_uid;
			pending = true;
			requestAt = Time.time;
			ZPackage val3 = new ZPackage();
			val3.Write(1);
			val3.Write(Target);
			val3.Write(((Character)localPlayer).GetZDOID());
			ZRoutedRpc.instance.InvokeRoutedRPC("SharedMining.Start.v1", new object[1] { val3 });
		}

		private static bool ValidPlayer(Player player)
		{
			if (!((Character)player).IsDead() && !((Character)player).IsTeleporting() && !((Character)player).InCutscene())
			{
				return !((Character)player).InPlaceMode();
			}
			return false;
		}

		private static bool InputBlocked()
		{
			if ((!Object.op_Implicit((Object)(object)Chat.instance) || !Chat.instance.HasFocus()) && !Console.IsVisible() && !TextInput.IsVisible() && !InventoryGui.IsVisible())
			{
				return Menu.IsVisible();
			}
			return true;
		}

		private static ZNetView? TargetView()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.FindInstance(Target) : null);
			ZNetView val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<ZNetView>() : null);
			if (!Object.op_Implicit((Object)(object)val2) || !val2.IsValid())
			{
				return null;
			}
			return val2;
		}

		internal static void Reply(long sender, ZPackage pkg)
		{
			//IL_001c: 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)
			if (sender != Server.ServerId)
			{
				return;
			}
			try
			{
				if (pkg.GetArray().Length > 2048)
				{
					return;
				}
				ZDOID val = pkg.ReadZDOID();
				long num = pkg.ReadLong();
				string text = pkg.ReadString();
				if (!(val != Target) && (pending || Running))
				{
					pending = false;
					if (num == 0L)
					{
						Reset();
					}
					else
					{
						token = num;
						sequence = 0;
					}
					Message(text);
				}
			}
			catch (Exception ex)
			{
				Plugin.Instance.Log.LogWarning((object)ex.Message);
			}
		}

		internal static void Retarget(long sender, ZPackage pkg)
		{
			//IL_000b: 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)
			//IL_0012: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: 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)
			if (sender != Server.ServerId)
			{
				return;
			}
			try
			{
				ZDOID val = pkg.ReadZDOID();
				ZDOID target = pkg.ReadZDOID();
				long num = pkg.ReadLong();
				if (Running && Target == val && token == num)
				{
					Target = target;
					missingSince = 0f;
				}
			}
			catch (Exception ex)
			{
				Plugin.Instance.Log.LogDebug((object)ex.Message);
			}
		}

		internal static void Controls(Player player, Vector3 movedir, ref bool primary, ref bool hold, bool cancel)
		{
			if ((Object)(object)player != (Object)(object)Player.m_localPlayer || !Running)
			{
				return;
			}
			if (cancel || ((Vector3)(ref movedir)).sqrMagnitude > 0.01f || InputBlocked())
			{
				Stop("Mining paused.");
			}
			else if (!IsHolding())
			{
				Stop("Mining paused.", Application.isFocused);
			}
			else if (Object.op_Implicit((Object)(object)TargetView()))
			{
				if (((Humanoid)player).GetCurrentWeapon() != tool || tool == null || (tool.m_shared.m_useDurability && tool.m_durability <= 0f))
				{
					Stop("");
					return;
				}
				primary = true;
				hold = true;
			}
		}

		internal static void Begin(Attack current, Humanoid character)
		{
			if (Running && !((Object)(object)character != (Object)(object)Player.m_localPlayer))
			{
				attack = current;
				Batch.Clear();
			}
		}

		internal static bool Capture(Component rock, HitData hit)
		{
			//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_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Expected O, but got Unknown
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			ZNetView component = rock.GetComponent<ZNetView>();
			if (!Object.op_Implicit((Object)(object)component) || !component.IsValid())
			{
				return true;
			}
			if (attack != null && Running && component.GetZDO().m_uid == Target && (Object)(object)hit.GetAttacker() == (Object)(object)Player.m_localPlayer)
			{
				MineRock5 val = (MineRock5)(object)((rock is MineRock5) ? rock : null);
				int num;
				if (val != null)
				{
					num = (int)AccessTools.Method(typeof(MineRock5), "GetAreaIndex", (Type[])null, (Type[])null).Invoke(val, new object[1] { hit.m_hitCollider });
				}
				else
				{
					MineRock val2 = (MineRock)(object)((rock is MineRock) ? rock : null);
					num = ((val2 != null) ? Array.IndexOf((Collider[])AccessTools.Field(typeof(MineRock), "m_hitAreas").GetValue(val2), hit.m_hitCollider) : 0);
				}
				if (num >= 0 && Batch.Count < 64)
				{
					Batch.Add((num, hit.Clone()));
				}
				return false;
			}
			if (component.GetZDO().GetBool("SharedMining.active.v1", false) && (Object)(object)hit.GetAttacker() == (Object)(object)Player.m_localPlayer && hit.m_damage.m_pickaxe > 0f)
			{
				MineRock5 val3 = (MineRock5)(object)((rock is MineRock5) ? rock : null);
				int num2;
				if (val3 == null)
				{
					MineRock val4 = (MineRock)(object)((rock is MineRock) ? rock : null);
					num2 = ((val4 != null) ? Array.IndexOf((Collider[])AccessTools.Field(typeof(MineRock), "m_hitAreas").GetValue(val4), hit.m_hitCollider) : 0);
				}
				else
				{
					num2 = (int)AccessTools.Method(typeof(MineRock5), "GetAreaIndex", (Type[])null, (Type[])null).Invoke(val3, new object[1] { hit.m_hitCollider });
				}
				int num3 = num2;
				if (num3 < 0)
				{
					return true;
				}
				ZPackage val5 = new ZPackage();
				val5.Write(component.GetZDO().m_uid);
				val5.Write(num3);
				hit.Serialize(ref val5);
				ZRoutedRpc.instance.InvokeRoutedRPC("SharedMining.Manual.v1", new object[1] { val5 });
				return false;
			}
			return true;
		}

		internal static void End(Attack current, Exception? error)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			if (attack != current)
			{
				return;
			}
			attack = null;
			if (error != null)
			{
				Batch.Clear();
				Stop("Mining stopped because of an error.");
				return;
			}
			if (Batch.Count == 0)
			{
				Stop("Your pickaxe missed the deposit. Adjust your aim, then hold Alt again.");
				return;
			}
			if (Running)
			{
				ZPackage val = new ZPackage();
				val.Write(token);
				val.Write(++sequence);
				val.Write(Batch.Count);
				foreach (var item in Batch)
				{
					val.Write(item.index);
					item.hit.Serialize(ref val);
				}
				ZRoutedRpc.instance.InvokeRoutedRPC("SharedMining.Hit.v1", new object[1] { val });
			}
			Batch.Clear();
		}

		internal static void Draw()
		{
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer))
			{
				MiningHud.Hide();
				return;
			}
			ZNetView val = TargetView();
			if (!Object.op_Implicit((Object)(object)val))
			{
				GameObject hoverObject = ((Humanoid)localPlayer).GetHoverObject();
				val = (Object.op_Implicit((Object)(object)hoverObject) ? hoverObject.GetComponentInParent<ZNetView>() : null);
			}
			if (!Object.op_Implicit((Object)(object)val) || !val.IsValid() || !val.GetZDO().GetBool("SharedMining.active.v1", false))
			{
				MiningHud.Hide();
				return;
			}
			float progress = Mathf.Clamp01(val.GetZDO().GetFloat("SharedMining.progress.v1", 0f));
			ZDO zDO = val.GetZDO();
			int miners = ((Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.GetTimeSeconds() - (double)zDO.GetLong("VeinMining.activityTime", 0L) < 6.0) ? zDO.GetInt("VeinMining.miners", 0) : 0);
			float num = zDO.GetFloat("VeinMining.speed", 0f);
			if (Server.IsServer)
			{
				num = Plugin.Instance.OreWorkMultiplier.Value;
			}
			else if (num <= 0f)
			{
				num = 3f;
			}
			MiningHud.Draw(progress, miners, num, InputState.Latched && Running);
		}
	}
	[HarmonyPatch(typeof(Player), "SetControls")]
	internal static class AutoSwing
	{
		private static void Prefix(Player __instance, Vector3 movedir, ref bool attack, ref bool attackHold, bool secondaryAttack, bool secondaryAttackHold, bool block, bool blockHold, bool jump, bool dodge)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			Client.Controls(__instance, movedir, ref attack, ref attackHold, secondaryAttack || secondaryAttackHold || block || blockHold || jump || dodge);
		}
	}
	[HarmonyPatch(typeof(Attack), "DoMeleeAttack")]
	internal static class SwingBatch
	{
		private static void Prefix(Attack __instance, Humanoid ___m_character)
		{
			Client.Begin(__instance, ___m_character);
		}

		private static void Finalizer(Attack __instance, Exception __exception)
		{
			Client.End(__instance, __exception);
		}
	}
	[HarmonyPatch]
	internal static class CaptureHit
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			yield return AccessTools.Method(typeof(MineRock5), "Damage", (Type[])null, (Type[])null);
			yield return AccessTools.Method(typeof(MineRock), "Damage", (Type[])null, (Type[])null);
			yield return AccessTools.Method(typeof(Destructible), "Damage", (Type[])null, (Type[])null);
		}

		[HarmonyPriority(800)]
		private static bool Prefix(Component __instance, HitData hit)
		{
			if (!Plugin.Completing)
			{
				return Client.Capture(__instance, hit);
			}
			return true;
		}
	}
	internal sealed class Deposit
	{
		internal const string ActiveKey = "SharedMining.active.v1";

		internal const string DataKey = "SharedMining.ledger.v1";

		internal const string ProgressKey = "SharedMining.progress.v1";

		internal readonly Component Rock;

		internal readonly ZNetView View;

		internal readonly Collider[] Parts;

		internal readonly float[] Health;

		internal readonly int Tier;

		internal readonly DamageModifiers Resistance;

		internal readonly MineRock5? nextStage;

		internal static readonly List<ZNetView> Spawned = new List<ZNetView>();

		internal ZDO Data => View.GetZDO();

		internal string Name => Catalog.PrefabName(Rock.gameObject);

		internal float WorkMultiplier => Plugin.Instance.OreWorkMultiplier.Value;

		internal Deposit(Component rock)
		{
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Expected O, but got Unknown
			//IL_0215: 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_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			Deposit deposit = this;
			Rock = rock;
			View = rock.GetComponent<ZNetView>();
			if (!Object.op_Implicit((Object)(object)View) || !View.IsValid())
			{
				throw new InvalidOperationException("Deposit is not networked");
			}
			MineRock5 val = (MineRock5)(object)((rock is MineRock5) ? rock : null);
			if (val != null)
			{
				AccessTools.Method(typeof(MineRock5), "LoadHealth", (Type[])null, (Type[])null).Invoke(val, null);
				IList source = (IList)AccessTools.Field(typeof(MineRock5), "m_hitAreas").GetValue(val);
				Parts = source.Cast<object>().Select((Func<object, Collider>)((object a) => (Collider)AccessTools.Field(a.GetType(), "m_collider").GetValue(a))).ToArray();
				Health = (from object a in source
					select Math.Max(0f, (float)AccessTools.Field(a.GetType(), "m_health").GetValue(a))).ToArray();
				Tier = val.m_minToolTier;
				Resistance = val.m_damageModifiers;
				return;
			}
			MineRock old = (MineRock)(object)((rock is MineRock) ? rock : null);
			if (old != null)
			{
				Parts = (Collider[])AccessTools.Field(typeof(MineRock), "m_hitAreas").GetValue(old);
				Health = (from i in Enumerable.Range(0, Parts.Length)
					select Math.Max(0f, deposit.Data.GetFloat("Health" + i, old.GetHealth()))).ToArray();
				Tier = old.m_minToolTier;
				Resistance = old.m_damageModifiers;
				return;
			}
			Destructible val2 = (Destructible)rock;
			Parts = (Collider[])(object)new Collider[1] { rock.GetComponentInChildren<Collider>() };
			Health = new float[1] { Math.Max(0f, Data.GetFloat(ZDOVars.s_health, val2.m_health * (1f + (float)Game.m_worldLevel * Game.instance.m_worldLevelMineHPMultiplier))) };
			Tier = val2.m_minToolTier;
			Resistance = val2.m_damages;
			nextStage = (Object.op_Implicit((Object)(object)val2.m_spawnWhenDestroyed) ? val2.m_spawnWhenDestroyed.GetComponent<MineRock5>() : null);
			if (Object.op_Implicit((Object)(object)nextStage))
			{
				int count = ((Component)nextStage).GetComponentsInChildren<Collider>().Length;
				float element = nextStage.m_health * (1f + (float)Game.m_worldLevel * Game.instance.m_worldLevelMineHPMultiplier);
				Health = Health.Concat(Enumerable.Repeat(element, count)).ToArray();
				Tier = Math.Max(Tier, nextStage.m_minToolTier);
			}
		}

		internal static Component? ComponentOn(GameObject go)
		{
			return (Component?)(go.GetComponent<MineRock5>() ?? ((object)go.GetComponent<MineRock>()) ?? ((object)go.GetComponent<Destructible>()));
		}

		internal static Deposit? Find(ZDOID id)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.FindInstance(id) : null);
			if (!Object.op_Implicit((Object)(object)val) || !Catalog.Supported(val))
			{
				return null;
			}
			Component val2 = ComponentOn(val);
			if (!Object.op_Implicit((Object)(object)val2))
			{
				return null;
			}
			return new Deposit(val2);
		}

		internal int Index(Collider collider)
		{
			if (!(Rock is Destructible))
			{
				return Array.IndexOf(Parts, collider);
			}
			return 0;
		}

		internal DamageModifiers ResistanceAt(int index)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)nextStage) || index <= 0)
			{
				return Resistance;
			}
			return nextStage.m_damageModifiers;
		}

		internal float Distance(Vector3 position)
		{
			//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)
			return Parts.Where((Collider c) => Object.op_Implicit((Object)(object)c) && c.enabled).Select(delegate(Collider c)
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: 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_0026: 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_002f: Unknown result type (might be due to invalid IL or missing references)
				MeshCollider val = (MeshCollider)(object)((c is MeshCollider) ? c : null);
				Vector3 val2;
				if (val == null || val.convex)
				{
					val2 = c.ClosestPoint(position);
				}
				else
				{
					Bounds bounds = c.bounds;
					val2 = ((Bounds)(ref bounds)).ClosestPoint(position);
				}
				return Vector3.Distance(val2, position);
			}).DefaultIfEmpty(float.MaxValue)
				.Min();
		}

		internal WorkLedger Load()
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			byte[] byteArray = Data.GetByteArray("SharedMining.ledger.v1", (byte[])null);
			if (byteArray == null || byteArray.Length == 0)
			{
				return new WorkLedger(Health, Health.Sum());
			}
			ZPackage val = new ZPackage(byteArray);
			if (val.ReadInt() != 1 || val.ReadInt() != Health.Length)
			{
				throw new InvalidOperationException("Deposit layout changed; refusing stale progress");
			}
			float total = val.ReadSingle();
			float[] array = new float[Health.Length];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = val.ReadSingle();
			}
			return new WorkLedger(array, total);
		}

		internal void Save(WorkLedger ledger)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write(1);
			val.Write(ledger.Remaining.Length);
			val.Write(ledger.Total);
			float[] remaining = ledger.Remaining;
			foreach (float num in remaining)
			{
				val.Write(num);
			}
			Data.Set("SharedMining.ledger.v1", val.GetArray());
			Data.Set("SharedMining.progress.v1", ledger.Progress);
		}

		internal void Finish(HitData source)
		{
			//IL_00b7: 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_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			bool completing = Plugin.Completing;
			Plugin.Completing = true;
			try
			{
				string expectedStage = (Object.op_Implicit((Object)(object)nextStage) ? Utils.GetPrefabName(((Component)nextStage).gameObject) : null);
				float[] array = (from i in Enumerable.Range(0, Health.Length)
					select Data.GetFloat("SharedMining.factor." + i, 0f)).ToArray();
				int count = Spawned.Count;
				for (int num = 0; num < Parts.Length; num++)
				{
					if (!Object.op_Implicit((Object)(object)Rock))
					{
						break;
					}
					if (!View.IsValid())
					{
						break;
					}
					if (Health[num] <= 0f)
					{
						continue;
					}
					using (MiningCompatibility.Scope(Data.GetFloat("SharedMining.factor." + num, 0f)))
					{
						HitData val = source.Clone();
						val.m_damage = new DamageTypes
						{
							m_damage = Health[num] + 1f
						};
						val.m_toolTier = short.MaxValue;
						Vector3 point;
						if (!Object.op_Implicit((Object)(object)Parts[num]))
						{
							point = Rock.transform.position;
						}
						else
						{
							Bounds bounds = Parts[num].bounds;
							point = ((Bounds)(ref bounds)).center;
						}
						val.m_point = point;
						val.m_hitCollider = Parts[num];
						Component rock = Rock;
						MineRock5 val2 = (MineRock5)(object)((rock is MineRock5) ? rock : null);
						if (val2 != null)
						{
							AccessTools.Method(typeof(MineRock5), "DamageArea", (Type[])null, (Type[])null).Invoke(val2, new object[2] { num, val });
							continue;
						}
						Component rock2 = Rock;
						MineRock val3 = (MineRock)(object)((rock2 is MineRock) ? rock2 : null);
						if (val3 != null)
						{
							AccessTools.Method(typeof(MineRock), "RPC_Hit", (Type[])null, (Type[])null).Invoke(val3, new object[3] { 0L, val, num });
						}
						else
						{
							AccessTools.Method(typeof(Destructible), "RPC_Damage", (Type[])null, (Type[])null).Invoke(Rock, new object[2] { 0L, val });
						}
					}
				}
				if (expectedStage != null)
				{
					ZNetView? obj = Spawned.Skip(count).FirstOrDefault((Func<ZNetView, bool>)((ZNetView v) => Object.op_Implicit((Object)(object)v) && v.IsValid() && v.GetZDO().GetPrefab() == StringExtensionMethods.GetStableHashCode(expectedStage)));
					if (!Object.op_Implicit((Object)(object)obj))
					{
						throw new InvalidOperationException("Native ore transition did not create " + expectedStage);
					}
					Deposit deposit = new Deposit((Component)(object)((Component)obj).GetComponent<MineRock5>());
					for (int num2 = 0; num2 < deposit.Health.Length; num2++)
					{
						deposit.Data.Set("SharedMining.factor." + num2, array[num2 + 1]);
					}
					deposit.Finish(source);
				}
				if (Object.op_Implicit((Object)(object)Rock) && View.IsValid())
				{
					Data.Set("SharedMining.active.v1", false);
				}
			}
			finally
			{
				Plugin.Completing = completing;
				if (!completing)
				{
					Spawned.Clear();
				}
			}
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "AddInstance")]
	internal static class CaptureNativeStage
	{
		private static void Postfix(ZNetView nview)
		{
			if (Plugin.Completing)
			{
				Deposit.Spawned.Add(nview);
			}
			ManualMining.RecordSpawn(nview);
		}
	}
	internal static class ManualMining
	{
		internal sealed class Snapshot
		{
			internal Deposit Deposit;

			internal ZDOID Id;

			internal WorkLedger Ledger;

			internal HitData Hit;

			internal float[] Factors = Array.Empty<float>();

			internal readonly List<(ZDOID id, int prefab)> Spawned = new List<(ZDOID, int)>();
		}

		private static readonly List<Snapshot> Active = new List<Snapshot>();

		internal static void Reset()
		{
			Active.Clear();
		}

		internal static Snapshot? Begin(Component rock, HitData hit)
		{
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.Completing || !Server.IsServer || Active.Any((Snapshot s) => (Object)(object)s.Deposit.Rock == (Object)(object)rock))
			{
				return null;
			}
			ZNetView component = rock.GetComponent<ZNetView>();
			if (!Object.op_Implicit((Object)(object)component) || !component.IsValid() || !component.IsOwner() || !component.GetZDO().GetBool("SharedMining.active.v1", false))
			{
				return null;
			}
			Deposit d = new Deposit(rock);
			Snapshot snapshot = new Snapshot
			{
				Deposit = d,
				Id = d.Data.m_uid,
				Ledger = d.Load(),
				Hit = hit.Clone(),
				Factors = (from i in Enumerable.Range(0, d.Health.Length)
					select d.Data.GetFloat("SharedMining.factor." + i, 0f)).ToArray()
			};
			Active.Add(snapshot);
			return snapshot;
		}

		internal static void RecordSpawn(ZNetView view)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.Completing || Active.Count == 0 || !Object.op_Implicit((Object)(object)view) || !view.IsValid())
			{
				return;
			}
			foreach (Snapshot item in Active)
			{
				item.Spawned.Add((view.GetZDO().m_uid, view.GetZDO().GetPrefab()));
			}
		}

		internal static void End(Snapshot? s)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			if (s == null)
			{
				return;
			}
			Active.Remove(s);
			try
			{
				Deposit deposit = Deposit.Find(s.Id);
				WorkLedger workLedger = s.Ledger;
				float[] array = s.Deposit.Health;
				int num = 0;
				if (deposit == null && Object.op_Implicit((Object)(object)s.Deposit.nextStage))
				{
					int expected = StringExtensionMethods.GetStableHashCode(((Object)((Component)s.Deposit.nextStage).gameObject).name);
					(ZDOID id, int prefab) tuple = s.Spawned.FirstOrDefault(((ZDOID id, int prefab) x) => x.prefab == expected);
					if (tuple.id == ZDOID.None)
					{
						throw new InvalidOperationException("Native shell transition was not captured");
					}
					deposit = Deposit.Find(tuple.id);
					if (deposit == null)
					{
						Server.Completed(s.Id);
						return;
					}
					workLedger = new WorkLedger(workLedger.Remaining.Skip(1).ToArray(), workLedger.Total);
					array = array.Skip(1).ToArray();
					num = 1;
					deposit.Data.SetOwner(Server.ServerId);
					deposit.Data.Set("SharedMining.active.v1", true);
					for (int num2 = 0; num2 < deposit.Health.Length; num2++)
					{
						deposit.Data.Set("SharedMining.factor." + num2, s.Factors[num2 + num]);
					}
					Server.Retarget(s.Id, deposit.Data.m_uid);
				}
				if (deposit == null)
				{
					Server.Completed(s.Id);
					return;
				}
				workLedger.ReconcileNative(array, deposit.Health);
				Character attacker = s.Hit.GetAttacker();
				Player val = (Player)(object)((attacker is Player) ? attacker : null);
				if (Object.op_Implicit((Object)(object)val))
				{
					for (int num3 = 0; num3 < deposit.Health.Length; num3++)
					{
						if (deposit.Health[num3] < array[num3])
						{
							deposit.Data.Set("SharedMining.factor." + num3, MiningCompatibility.Factor(val));
						}
					}
				}
				deposit.Save(workLedger);
				if (workLedger.Complete)
				{
					ZDOID uid = deposit.Data.m_uid;
					if (deposit.Health.Any((float h) => h > 0f))
					{
						deposit.Finish(s.Hit);
					}
					else
					{
						deposit.Data.Set("SharedMining.active.v1", false);
					}
					Server.Completed(uid);
				}
			}
			catch (Exception ex)
			{
				Plugin.Instance.Log.LogError((object)("Could not reconcile ordinary mining: " + ex));
			}
		}
	}
	[HarmonyPatch]
	internal static class ObserveNativeMining
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			yield return AccessTools.Method(typeof(MineRock5), "RPC_Damage", (Type[])null, (Type[])null);
			yield return AccessTools.Method(typeof(MineRock), "RPC_Hit", (Type[])null, (Type[])null);
			yield return AccessTools.Method(typeof(Destructible), "RPC_Damage", (Type[])null, (Type[])null);
		}

		[HarmonyPriority(800)]
		private static void Prefix(Component __instance, HitData hit, out ManualMining.Snapshot? __state)
		{
			__state = null;
			try
			{
				__state = ManualMining.Begin(__instance, hit);
			}
			catch (Exception ex)
			{
				Plugin.Instance.Log.LogError((object)("Could not snapshot ordinary mining: " + ex));
			}
		}

		private static void Finalizer(ManualMining.Snapshot? __state)
		{
			ManualMining.End(__state);
		}
	}
	internal static class MiningCompatibility
	{
		private sealed class MiningScope : IDisposable
		{
			private readonly object? oldMining;

			private readonly object? oldFactor;

			internal MiningScope(float value)
			{
				oldMining = mining?.GetValue(null);
				oldFactor = factor?.GetValue(null);
				mining?.SetValue(null, true);
				factor?.SetValue(null, value);
			}

			public void Dispose()
			{
				mining?.SetValue(null, oldMining);
				factor?.SetValue(null, oldFactor);
			}
		}

		private static Type? flag;

		private static MethodInfo? handle;

		private static FieldInfo? mining;

		private static FieldInfo? factor;

		internal static bool Ready { get; private set; } = true;

		internal static void Initialize(Harmony harmony)
		{
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Expected O, but got Unknown
			if (Chainloader.PluginInfos.TryGetValue("org.bepinex.plugins.mining", out var value))
			{
				flag = ((object)value.Instance).GetType().GetNestedType("SetMiningFlag", BindingFlags.Public);
				handle = ((flag == null) ? null : AccessTools.Method(flag, "HandleMining", (Type[])null, (Type[])null));
				mining = ((flag == null) ? null : AccessTools.Field(flag, "IsMining"));
				factor = ((flag == null) ? null : AccessTools.Field(flag, "MiningFactor"));
				Ready = handle != null && mining != null && factor != null && value.Metadata.Version.ToString() == "1.1.6";
				if (!Ready)
				{
					Plugin.Instance.Log.LogError((object)"Unknown Smoothbrain Mining API/version. Shared mining is disabled to protect compatibility.");
				}
				else
				{
					harmony.Patch((MethodBase)handle, new HarmonyMethod(typeof(MiningCompatibility), "BeforeHandle", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
		}

		private static bool BeforeHandle(ref bool __result)
		{
			if (!Plugin.Completing)
			{
				return true;
			}
			__result = true;
			return false;
		}

		internal static float Factor(Player player)
		{
			return ((Component)player).GetComponent<ZNetView>().GetZDO().GetFloat("Mining Skill Factor", 0f);
		}

		internal static void Contribute(HitData hit, Deposit deposit)
		{
			if (!(handle == null))
			{
				Character attacker = hit.GetAttacker();
				Player val = (Player)(object)((attacker is Player) ? attacker : null);
				if (Object.op_Implicit((Object)(object)val))
				{
					((Component)val).GetComponent<ZNetView>().InvokeRPC("Mining IncreaseSkill", new object[1] { 1 });
				}
			}
		}

		internal static IDisposable Scope(float value)
		{
			return new MiningScope(value);
		}
	}
	internal static class MiningHud
	{
		private static GameObject? root;

		private static Text? heading;

		private static Text? percent;

		private static Text? activity;

		private static RectTransform? fill;

		private static Texture2D? leatherTexture;

		private static Sprite? leatherSprite;

		private static RectTransform Rect(string name, Transform parent, float x, float y, float w, float h)
		{
			//IL_0014: 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_003f: 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_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			RectTransform component = new GameObject(name, new Type[1] { typeof(RectTransform) }).GetComponent<RectTransform>();
			((Transform)component).SetParent(parent, false);
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0f, 1f);
			component.anchorMax = val;
			component.anchorMin = val;
			component.pivot = new Vector2(0f, 1f);
			component.anchoredPosition = new Vector2(x, 0f - y);
			component.sizeDelta = new Vector2(w, h);
			return component;
		}

		private static Image Image(RectTransform rect, Color color, Sprite? sprite = null)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			Image val = ((Component)rect).gameObject.AddComponent<Image>();
			((Graphic)val).raycastTarget = false;
			((Graphic)val).color = color;
			val.sprite = sprite;
			if (Object.op_Implicit((Object)(object)sprite))
			{
				val.type = (Type)1;
			}
			return val;
		}

		private static Text Text(RectTransform rect, int size, TextAnchor alignment, bool bold = false)
		{
			//IL_0032: 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)
			Text obj = ((Component)rect).gameObject.AddComponent<Text>();
			obj.font = (bold ? GUIManager.Instance.AveriaSerifBold : GUIManager.Instance.AveriaSerif);
			obj.fontSize = size;
			obj.alignment = alignment;
			((Graphic)obj).color = new Color(0.97f, 0.9f, 0.72f);
			obj.supportRichText = false;
			((Graphic)obj).raycastTarget = false;
			obj.horizontalOverflow = (HorizontalWrapMode)1;
			return obj;
		}

		private static Sprite PanelSprite()
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)leatherSprite))
			{
				return leatherSprite;
			}
			using Stream stream = typeof(MiningHud).Assembly.GetManifestResourceStream("VeinMining.HudLeather.png") ?? throw new InvalidOperationException("HUD leather resource missing");
			using MemoryStream memoryStream = new MemoryStream();
			stream.CopyTo(memoryStream);
			leatherTexture = new Texture2D(2, 2, (TextureFormat)4, false);
			if (!AssetUtils.LoadImage(leatherTexture, memoryStream.ToArray()))
			{
				throw new InvalidOperationException("HUD texture failed to load");
			}
			((Texture)leatherTexture).wrapMode = (TextureWrapMode)1;
			((Texture)leatherTexture).filterMode = (FilterMode)1;
			Color32[] pixels = leatherTexture.GetPixels32();
			int width = ((Texture)leatherTexture).width;
			int height = ((Texture)leatherTexture).height;
			int num = width;
			int num2 = height;
			int num3 = -1;
			int num4 = -1;
			for (int i = 0; i < height; i++)
			{
				for (int j = 0; j < width; j++)
				{
					if (pixels[i * width + j].a >= 64)
					{
						num = Math.Min(num, j);
						num2 = Math.Min(num2, i);
						num3 = Math.Max(num3, j);
						num4 = Math.Max(num4, i);
					}
				}
			}
			if (num3 < 0)
			{
				throw new InvalidOperationException("HUD texture is empty");
			}
			leatherSprite = Sprite.Create(leatherTexture, new Rect((float)num, (float)num2, (float)(num3 - num + 1), (float)(num4 - num2 + 1)), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0);
			return leatherSprite;
		}

		private static void Create()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			root = new GameObject("VeinMiningHud", new Type[3]
			{
				typeof(RectTransform),
				typeof(Canvas),
				typeof(CanvasScaler)
			});
			Canvas component = root.GetComponent<Canvas>();
			component.renderMode = (RenderMode)0;
			component.sortingOrder = 20;
			RectTransform val = Rect("MiningPanel", root.transform, 0f, 0f, 360f, 84f);
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(0.5f, 0.29f);
			val.anchorMax = val2;
			val.anchorMin = val2;
			val.pivot = new Vector2(0.5f, 0.5f);
			val.anchoredPosition = Vector2.zero;
			Image(val, Color.white, PanelSprite()).type = (Type)0;
			heading = Text(Rect("Title", (Transform)(object)val, 18f, 11f, 230f, 22f), 16, (TextAnchor)3, bold: true);
			percent = Text(Rect("Percent", (Transform)(object)val, 264f, 11f, 78f, 22f), 16, (TextAnchor)5, bold: true);
			Image(Rect("BarBorder", (Transform)(object)val, 18f, 37f, 324f, 13f), new Color(0.65f, 0.43f, 0.17f), GUIManager.Instance.GetSprite("UISprite"));
			Image(Rect("BarTrack", (Transform)(object)val, 19f, 38f, 322f, 11f), new Color(0.05f, 0.05f, 0.035f), GUIManager.Instance.GetSprite("UISprite"));
			RectTransform val3 = Rect("ProgressClip", (Transform)(object)val, 20f, 39f, 320f, 9f);
			((Component)val3).gameObject.AddComponent<RectMask2D>();
			fill = Rect("Progress", (Transform)(object)val3, 0f, 0f, 320f, 9f);
			Image(fill, new Color(0.93f, 0.58f, 0.12f), GUIManager.Instance.GetSprite("UISprite"));
			Image(Rect("Highlight", (Transform)(object)fill, 0f, 0f, 320f, 2f), new Color(0.98f, 0.76f, 0.36f));
			activity = Text(Rect("Activity", (Transform)(object)val, 18f, 54f, 324f, 20f), 13, (TextAnchor)4);
		}

		internal static void Draw(float progress, int miners, float oreSpeed, bool automatic)
		{
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)Hud.instance) && Object.op_Implicit((Object)(object)GUIManager.Instance.AveriaSerif))
			{
				if (!Object.op_Implicit((Object)(object)root))
				{
					Create();
				}
				root.SetActive(true);
				root.GetComponent<CanvasScaler>().scaleFactor = Mathf.Clamp((float)Screen.width / 1280f, 0.85f, 1f);
				heading.text = "Vein Mining";
				percent.text = $"{Mathf.RoundToInt(Mathf.Clamp01(progress) * 100f)}%";
				fill.sizeDelta = new Vector2(320f * Mathf.Clamp01(progress), 9f);
				((Component)((Transform)fill).GetChild(0)).GetComponent<RectTransform>().sizeDelta = new Vector2(fill.sizeDelta.x, 2f);
				string arg = ((miners == 1) ? "1 miner" : $"{Mathf.Max(0, miners)} miners");
				activity.text = $"{oreSpeed:0.##}× · {arg}";
			}
		}

		internal static void Hide()
		{
			if (Object.op_Implicit((Object)(object)root))
			{
				root.SetActive(false);
			}
		}

		internal static void Destroy()
		{
			if (Object.op_Implicit((Object)(object)root))
			{
				Object.Destroy((Object)(object)root);
			}
			root = null;
		}
	}
	internal sealed class MiningInput
	{
		private float lastPress = float.NegativeInfinity;

		internal bool Latched { get; private set; }

		internal bool Press(float now)
		{
			if (Latched)
			{
				Clear();
				return true;
			}
			if (now >= lastPress && now - lastPress <= 0.35f)
			{
				Latched = true;
				lastPress = float.NegativeInfinity;
			}
			else
			{
				lastPress = now;
			}
			return false;
		}

		internal void Clear(bool keepTap = false)
		{
			Latched = false;
			if (!keepTap)
			{
				lastPress = float.NegativeInfinity;
			}
		}
	}
	[BepInPlugin("local.valheim.sharedmining", "Vein Mining", "0.3.4")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		private sealed class ConfigurationManagerAttributes
		{
			public bool? Browsable = false;
		}

		public const string Id = "local.valheim.sharedmining";

		public const string Version = "0.3.4";

		internal static Plugin Instance;

		internal static bool Completing;

		internal ConfigEntry<KeyboardShortcut> HoldKey;

		internal ConfigEntry<string> Included;

		internal ConfigEntry<string> Excluded;

		internal ConfigEntry<float> Range;

		internal ConfigEntry<float> OreWorkMultiplier;

		private Harmony harmony;

		private ZRoutedRpc? bound;

		private ZNetScene? audited;

		private float auditAt;

		internal ManualLogSource Log => ((BaseUnityPlugin)this).Logger;

		private void Awake()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Expected O, but got Unknown
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Expected O, but got Unknown
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Expected O, but got Unknown
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Expected O, but got Unknown
			Instance = this;
			HoldKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Client", "HoldKey", new KeyboardShortcut((KeyCode)308, Array.Empty<KeyCode>()), new ConfigDescription("Hold Alt or double-tap for automatic mining.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes()
			}));
			Included = ((BaseUnityPlugin)this).Config.Bind<string>("Server", "AdditionalPrefabs", "", new ConfigDescription("Additional ore prefabs.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes()
			}));
			Excluded = ((BaseUnityPlugin)this).Config.Bind<string>("Server", "ExcludedPrefabs", "", new ConfigDescription("Excluded ore prefabs.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes()
			}));
			Range = ((BaseUnityPlugin)this).Config.Bind<float>("Server", "MaximumDistance", 6f, new ConfigDescription("Maximum contributor distance to an exposed deposit collider.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 12f), new object[1]
			{
				new ConfigurationManagerAttributes()
			}));
			OreWorkMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Multiplayer", "Ore Mining Multiplayer", 3f, new ConfigDescription("Applies to all supported ore deposits. 3 is the default; 1 is normal work per hit; 10 is the maximum. Only the host/server value is used. Team speed: 1 miner = 1x, 2 = 2x, 3 = 2.5x, then +0.5x per miner. Does not change loot or per-hit durability; fewer hits means less total wear. This is a speed adjustment, not simulated structural collapse.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>()));
			harmony = new Harmony("local.valheim.sharedmining");
			harmony.PatchAll();
			MiningCompatibility.Initialize(harmony);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Vein Mining 0.3.4 experimental build loaded; hold Left Alt to mine.");
		}

		private void Update()
		{
			if (ZRoutedRpc.instance != bound)
			{
				bound = ZRoutedRpc.instance;
				Server.Reset();
				Client.Reset();
				if (bound != null)
				{
					Server.Register(bound);
				}
			}
			if ((Object)(object)ZNetScene.instance != (Object)(object)audited)
			{
				audited = ZNetScene.instance;
				auditAt = Time.time + 8f;
			}
			if (Object.op_Implicit((Object)(object)audited) && auditAt > 0f && Time.time >= auditAt)
			{
				auditAt = 0f;
				try
				{
					Catalog.Audit();
				}
				catch (Exception ex)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)ex);
				}
			}
			Server.UpdateActivity();
			Client.Update();
			Client.Draw();
		}

		private void OnDestroy()
		{
			MiningHud.Destroy();
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			Client.Reset();
			Server.Reset();
		}
	}
	internal static class Server
	{
		private sealed class Session
		{
			internal ZDOID Target;

			internal ZDOID Player;

			internal long Token;

			internal int Sequence;

			internal float LastHit = -10f;

			internal float LastSeen;
		}

		internal const string StartRpc = "SharedMining.Start.v1";

		internal const string StopRpc = "SharedMining.Stop.v1";

		internal const string HitRpc = "SharedMining.Hit.v1";

		internal const string ReplyRpc = "SharedMining.Reply.v1";

		internal const string KeepRpc = "SharedMining.Keep.v1";

		internal const string ManualRpc = "SharedMining.Manual.v1";

		internal const string MoveRpc = "SharedMining.Move.v1";

		private static readonly Dictionary<long, Session> Sessions = new Dictionary<long, Session>();

		private static long nextToken;

		internal const string MinersKey = "VeinMining.miners";

		internal const string NamesKey = "VeinMining.names";

		internal const string SpeedKey = "VeinMining.speed";

		internal const string ActivityTimeKey = "VeinMining.activityTime";

		private static readonly HashSet<ZDOID> ActivityTargets = new HashSet<ZDOID>();

		private static float nextActivity;

		private static readonly Dictionary<ZDOID, float> Pins = new Dictionary<ZDOID, float>();

		internal static bool IsServer
		{
			get
			{
				if (Object.op_Implicit((Object)(object)ZNet.instance))
				{
					return ZNet.instance.IsServer();
				}
				return false;
			}
		}

		internal static long ServerId
		{
			get
			{
				if (ZRoutedRpc.instance != null)
				{
					return (long)AccessTools.Method(typeof(ZRoutedRpc), "GetServerPeerID", (Type[])null, (Type[])null).Invoke(ZRoutedRpc.instance, null);
				}
				return 0L;
			}
		}

		internal static void Reset()
		{
			Sessions.Clear();
			Pins.Clear();
			ActivityTargets.Clear();
			nextActivity = 0f;
			ManualMining.Reset();
		}

		private static Session[] ActiveMiners(ZDOID id)
		{
			//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)
			return Sessions.Values.Where((Session s) => s.Target == id && Time.time - s.LastHit <= 4f && Time.time - s.LastSeen <= 15f).ToArray();
		}

		internal static void UpdateActivity()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			if (!IsServer || Time.time < nextActivity)
			{
				return;
			}
			nextActivity = Time.time + 0.5f;
			foreach (Session value in Sessions.Values)
			{
				ActivityTargets.Add(value.Target);
			}
			ZDOID[] array = ActivityTargets.ToArray();
			foreach (ZDOID id in array)
			{
				ZDO zDO = ZDOMan.instance.GetZDO(id);
				if (zDO == null)
				{
					ActivityTargets.Remove(id);
					continue;
				}
				Session[] array2 = ActiveMiners(id);
				zDO.Set("VeinMining.miners", array2.Length);
				zDO.Set("VeinMining.speed", Plugin.Instance.OreWorkMultiplier.Value);
				zDO.Set("VeinMining.activityTime", (long)ZNet.instance.GetTimeSeconds());
				zDO.Set("VeinMining.names", string.Join(", ", array2.Select(delegate(Session s)
				{
					//IL_0006: Unknown result type (might be due to invalid IL or missing references)
					GameObject val = ZNetScene.instance.FindInstance(s.Player);
					Player val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<Player>() : null);
					string text = (Object.op_Implicit((Object)(object)val2) ? val2.GetPlayerName() : "Miner");
					return (text.Length <= 24) ? text : text.Substring(0, 24);
				}).Take(6)));
				if (array2.Length == 0 && !Sessions.Values.Any((Session s) => s.Target == id))
				{
					ActivityTargets.Remove(id);
				}
			}
		}

		internal static void Register(ZRoutedRpc rpc)
		{
			rpc.Register<ZPackage>("SharedMining.Start.v1", (Action<long, ZPackage>)Start);
			rpc.Register<ZPackage>("SharedMining.Stop.v1", (Action<long, ZPackage>)Stop);
			rpc.Register<ZPackage>("SharedMining.Hit.v1", (Action<long, ZPackage>)Hit);
			rpc.Register<ZPackage>("SharedMining.Reply.v1", (Action<long, ZPackage>)Client.Reply);
			rpc.Register<ZPackage>("SharedMining.Keep.v1", (Action<long, ZPackage>)Keep);
			rpc.Register<ZPackage>("SharedMining.Manual.v1", (Action<long, ZPackage>)Manual);
			rpc.Register<ZPackage>("SharedMining.Move.v1", (Action<long, ZPackage>)Client.Retarget);
		}

		private static void Manual(long sender, ZPackage pkg)
		{
			//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_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: 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_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			if (!IsServer)
			{
				return;
			}
			try
			{
				if (pkg.GetArray().Length <= 2048)
				{
					ZDOID val = pkg.ReadZDOID();
					int index = pkg.ReadInt();
					HitData val2 = new HitData();
					val2.Deserialize(ref pkg);
					ZDO zDO = ZDOMan.instance.GetZDO(val2.m_attacker);
					ZDO zDO2 = ZDOMan.instance.GetZDO(val);
					if (zDO != null && zDO2 != null && zDO.GetOwner() == sender && zDO2.GetBool("SharedMining.active.v1", false) && !(Vector3.Distance(zDO.GetPosition(), zDO2.GetPosition()) > 80f) && WorkLedger.Finite(val2.GetTotalDamage()) && !(val2.GetTotalDamage() <= 0f) && !(val2.GetTotalDamage() > 100000f) && WorkLedger.Finite(val2.m_damage.m_pickaxe) && !(val2.m_damage.m_pickaxe <= 0f) && EnsureLoaded(val2.m_attacker, player: true, sender) && EnsureLoaded(val, player: false, sender))
					{
						((MonoBehaviour)Plugin.Instance).StartCoroutine(ManualAfterLoad(sender, val, index, val2));
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Instance.Log.LogWarning((object)("Manual mining request failed: " + ex.Message));
			}
		}

		private static IEnumerator ManualAfterLoad(long sender, ZDOID id, int index, HitData hit)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			yield return null;
			try
			{
				Player val = PlayerFor(sender, hit.m_attacker);
				Deposit deposit = Deposit.Find(id);
				if (Object.op_Implicit((Object)(object)val) && deposit != null && index >= 0 && index < deposit.Parts.Length && !(deposit.Distance(((Component)val).transform.position) > Plugin.Instance.Range.Value))
				{
					deposit.Data.SetOwner(ServerId);
					if (deposit.Rock is MineRock5)
					{
						AccessTools.Method(typeof(MineRock5), "RPC_Damage", (Type[])null, (Type[])null).Invoke(deposit.Rock, new object[3] { sender, hit, index });
					}
					else if (deposit.Rock is MineRock)
					{
						AccessTools.Method(typeof(MineRock), "RPC_Hit", (Type[])null, (Type[])null).Invoke(deposit.Rock, new object[3] { sender, hit, index });
					}
					else
					{
						AccessTools.Method(typeof(Destructible), "RPC_Damage", (Type[])null, (Type[])null).Invoke(deposit.Rock, new object[2] { sender, hit });
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Instance.Log.LogError((object)("Manual mining failed: " + ex));
			}
		}

		internal static void Retarget(ZDOID previous, ZDOID next)
		{
			//IL_0005: 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_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			ActivityTargets.Add(previous);
			ActivityTargets.Add(next);
			Pins[next] = Time.time + 15f;
			foreach (KeyValuePair<long, Session> session in Sessions)
			{
				if (!(session.Value.Target != previous))
				{
					session.Value.Target = next;
					ZPackage val = new ZPackage();
					val.Write(previous);
					val.Write(next);
					val.Write(session.Value.Token);
					ZRoutedRpc.instance.InvokeRoutedRPC(session.Key, "SharedMining.Move.v1", new object[1] { val });
				}
			}
		}

		internal static void Completed(ZDOID id)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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)
			List<long> list = new List<long>();
			foreach (KeyValuePair<long, Session> session in Sessions)
			{
				if (session.Value.Target == id)
				{
					list.Add(session.Key);
				}
			}
			foreach (long item in list)
			{
				Sessions.Remove(item);
				Reply(item, id, 0L, "Deposit fully mined.");
			}
		}

		private static bool EnsureLoaded(ZDOID id, bool player, long sender)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			ZDO zDO = ZDOMan.instance.GetZDO(id);
			if (zDO == null)
			{
				return false;
			}
			GameObject prefab = ZNetScene.instance.GetPrefab(zDO.GetPrefab());
			if (Object.op_Implicit((Object)(object)prefab))
			{
				bool num;
				if (!player)
				{
					num = !Catalog.Supported(prefab);
				}
				else
				{
					if (!Object.op_Implicit((Object)(object)prefab.GetComponent<Player>()))
					{
						goto IL_0056;
					}
					num = zDO.GetOwner() != sender;
				}
				if (!num)
				{
					Pins[id] = Time.time + 15f;
					if (!Object.op_Implicit((Object)(object)ZNetScene.instance.FindInstance(id)))
					{
						AccessTools.Method(typeof(ZNetScene), "CreateObject", (Type[])null, (Type[])null).Invoke(ZNetScene.instance, new object[1] { zDO });
					}
					return true;
				}
			}
			goto IL_0056;
			IL_0056:
			return false;
		}

		internal static void KeepInstances(List<ZDO> currentNearObjects)
		{
			//IL_0057: 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_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			if (!IsServer)
			{
				return;
			}
			List<long> list = new List<long>();
			foreach (KeyValuePair<long, Session> session in Sessions)
			{
				if (Time.time - session.Value.LastSeen > 15f)
				{
					list.Add(session.Key);
					continue;
				}
				Pins[session.Value.Target] = Time.time + 1f;
				Pins[session.Value.Player] = Time.time + 1f;
			}
			foreach (long item in list)
			{
				Sessions.Remove(item);
			}
			List<ZDOID> list2 = new List<ZDOID>();
			foreach (KeyValuePair<ZDOID, float> pin in Pins)
			{
				ZDO zDO = ZDOMan.instance.GetZDO(pin.Key);
				if (Time.time > pin.Value || zDO == null)
				{
					list2.Add(pin.Key);
				}
				else if (!currentNearObjects.Contains(zDO))
				{
					currentNearObjects.Add(zDO);
				}
			}
			foreach (ZDOID item2 in list2)
			{
				Pins.Remove(item2);
			}
		}

		private static void Keep(long sender, ZPackage pkg)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			if (!IsServer)
			{
				return;
			}
			try
			{
				if (pkg.GetArray().Length <= 16 && Sessions.TryGetValue(sender, out Session value) && pkg.ReadLong() == value.Token)
				{
					Player val = PlayerFor(sender, value.Player);
					Deposit deposit = Deposit.Find(value.Target);
					if (!Object.op_Implicit((Object)(object)val) || deposit == null || deposit.Distance(((Component)val).transform.position) > Plugin.Instance.Range.Value)
					{
						Sessions.Remove(sender);
						Reply(sender, value.Target, 0L, "Mining stopped. Shared progress has been saved.");
					}
					else
					{
						value.LastSeen = Time.time;
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Instance.Log.LogDebug((object)ex.Message);
			}
		}

		private static Player? PlayerFor(long sender, ZDOID id)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.FindInstance(id) : null);
			Player val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<Player>() : null);
			ZNetView val3 = (Object.op_Implicit((Object)(object)val2) ? ((Component)val2).GetComponent<ZNetView>() : null);
			if (!Object.op_Implicit((Object)(object)val3) || !val3.IsValid() || val3.GetZDO().GetOwner() != sender || ((Character)val2).IsDead() || ((Character)val2).IsTeleporting())
			{
				return null;
			}
			return val2;
		}

		private static void Reply(long sender, ZDOID id, long token, string message)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			ZPackage val = new ZPackage();
			val.Write(id);
			val.Write(token);
			val.Write(message);
			ZRoutedRpc.instance.InvokeRoutedRPC(sender, "SharedMining.Reply.v1", new object[1] { val });
		}

		private static void Start(long sender, ZPackage pkg)
		{
			//IL_00e0: 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_000d: 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_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: 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)
			if (!IsServer)
			{
				return;
			}
			ZDOID val = ZDOID.None;
			try
			{
				if (pkg.GetArray().Length <= 256 && pkg.ReadInt() == 1 && MiningCompatibility.Ready)
				{
					val = pkg.ReadZDOID();
					ZDOID val2 = pkg.ReadZDOID();
					ZDO zDO = ZDOMan.instance.GetZDO(val2);
					ZDO zDO2 = ZDOMan.instance.GetZDO(val);
					if (zDO == null || zDO2 == null || zDO.GetOwner() != sender || Vector3.Distance(zDO.GetPosition(), zDO2.GetPosition()) > 80f || !EnsureLoaded(val2, player: true, sender) || !EnsureLoaded(val, player: false, sender))
					{
						Reply(sender, val, 0L, "This deposit is not supported or is too far away.");
					}
					else
					{
						((MonoBehaviour)Plugin.Instance).StartCoroutine(StartAfterLoad(sender, val, val2));
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Instance.Log.LogWarning((object)("Cannot load shared mining: " + ex.Message));
				Reply(sender, val, 0L, "Could not load the deposit. Check the server log.");
			}
		}

		private static IEnumerator StartAfterLoad(long sender, ZDOID id, ZDOID playerId)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			yield return null;
			try
			{
				Player val = PlayerFor(sender, playerId);
				Deposit deposit = Deposit.Find(id);
				if (!Object.op_Implicit((Object)(object)val) || deposit == null || deposit.Distance(((Component)val).transform.position) > Plugin.Instance.Range.Value)
				{
					Reply(sender, id, 0L, "This deposit is unavailable or is not supported.");
					yield break;
				}
				WorkLedger ledger = deposit.Load();
				deposit.Data.SetOwner(ServerId);
				deposit.Data.Set("SharedMining.active.v1", true);
				deposit.Data.Set("VeinMining.speed", Plugin.Instance.OreWorkMultiplier.Value);
				deposit.Save(ledger);
				Sessions[sender] = new Session
				{
					Target = id,
					Player = playerId,
					Token = ++nextToken,
					LastSeen = Time.time
				};
				Reply(sender, id, nextToken, "Vein Mining started. Hold Alt, or double-tap Alt for automatic mining.");
			}
			catch (Exception ex)
			{
				Plugin.Instance.Log.LogWarning((object)("Cannot start shared mining: " + ex.Message));
				Reply(sender, id, 0L, "Could not start mining. Check the server log.");
			}
		}

		private static void Stop(long sender, ZPackage pkg)
		{
			if (!IsServer)
			{
				return;
			}
			try
			{
				if (pkg.GetArray().Length <= 32)
				{
					long num = pkg.ReadLong();
					if (Sessions.TryGetValue(sender, out Session value) && value.Token == num)
					{
						Sessions.Remove(sender);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Instance.Log.LogDebug((object)ex.Message);
			}
		}

		private static void Hit(long sender, ZPackage pkg)
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: 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_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Expected O, but got Unknown
			//IL_01df: 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_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			//IL_0323: Unknown result type (might be due to invalid IL or missing references)
			if (!IsServer)
			{
				return;
			}
			try
			{
				if (pkg.GetArray().Length > 32768 || !Sessions.TryGetValue(sender, out Session value))
				{
					return;
				}
				long num = pkg.ReadLong();
				int num2 = pkg.ReadInt();
				int num3 = pkg.ReadInt();
				if (num != value.Token || num2 <= value.Sequence || num3 < 1 || num3 > 64 || Time.time - value.LastHit < 0.15f)
				{
					return;
				}
				Player val = PlayerFor(sender, value.Player);
				Deposit deposit = Deposit.Find(value.Target);
				if (!Object.op_Implicit((Object)(object)val) || deposit == null || deposit.Distance(((Component)val).transform.position) > Plugin.Instance.Range.Value)
				{
					Sessions.Remove(sender);
					Reply(sender, value.Target, 0L, "Mining stopped. Shared progress has been saved.");
					return;
				}
				List<(int, HitData, float)> list = new List<(int, HitData, float)>();
				for (int i = 0; i < num3; i++)
				{
					int num4 = pkg.ReadInt();
					HitData val2 = new HitData();
					val2.Deserialize(ref pkg);
					if (num4 < 0 || num4 >= deposit.Health.Length || val2.m_attacker != value.Player || val2.m_toolTier < deposit.Tier || !WorkLedger.Finite(val2.m_damage.m_pickaxe) || val2.m_damage.m_pickaxe <= 0f || !WorkLedger.Finite(val2.GetTotalDamage()) || val2.GetTotalDamage() <= 0f || val2.GetTotalDamage() > 100000f)
					{
						return;
					}
					list.Add((num4, val2, 0f));
				}
				value.Sequence = num2;
				value.LastHit = (value.LastSeen = Time.time);
				ActivityTargets.Add(value.Target);
				float num5 = TeamScaling.PerMiner(ActiveMiners(value.Target).Length);
				deposit.Data.SetOwner(ServerId);
				WorkLedger workLedger = deposit.Load();
				float num6 = MiningCompatibility.Factor(val);
				DamageModifier val3 = default(DamageModifier);
				foreach (var item in list)
				{
					if (workLedger.Complete)
					{
						break;
					}
					int index = workLedger.Next(item.Item1);
					HitData obj = item.Item2.Clone();
					obj.ApplyResistance(deposit.ResistanceAt(index), ref val3);
					float num7 = obj.GetTotalDamage() * deposit.WorkMultiplier * num5;
					if (WorkLedger.Finite(num7) && !(num7 <= 0f))
					{
						MiningCompatibility.Contribute(item.Item2, deposit);
						int num8 = workLedger.Apply(num7, item.Item1);
						if (num8 >= 0)
						{
							deposit.Data.Set("SharedMining.factor." + num8, num6);
						}
					}
				}
				deposit.Save(workLedger);
				if (workLedger.Complete)
				{
					deposit.Finish(list[list.Count - 1].Item2);
					Completed(value.Target);
				}
			}
			catch (Exception ex)
			{
				Plugin.Instance.Log.LogError((object)("Shared mining hit failed: " + ex));
			}
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "RemoveObjects")]
	internal static class ServerInstances
	{
		private static void Prefix(List<ZDO> currentNearObjects)
		{
			Server.KeepInstances(currentNearObjects);
		}
	}
	[HarmonyPatch(typeof(ZDO), "SetOwner")]
	internal static class KeepServerOwnership
	{
		private static void Prefix(ZDO __instance, ref long uid)
		{
			if (__instance.GetBool("SharedMining.active.v1", false) && Server.ServerId != 0L)
			{
				uid = Server.ServerId;
			}
		}
	}
	internal static class TeamScaling
	{
		internal static float Total(int miners)
		{
			if (miners > 0)
			{
				if (miners > 2)
				{
					return 2f + (float)(miners - 2) * 0.5f;
				}
				return miners;
			}
			return 0f;
		}

		internal static float PerMiner(int miners)
		{
			if (miners > 0)
			{
				return Total(miners) / (float)miners;
			}
			return 1f;
		}
	}
	public sealed class WorkLedger
	{
		public float[] Remaining { get; }

		public float Total { get; }

		public bool Complete => Remaining.All((float x) => x <= 0f);

		public float Progress
		{
			get
			{
				if (!(Total > 0f))
				{
					return 1f;
				}
				return Math.Max(0f, Math.Min(1f, 1f - Remaining.Sum() / Total));
			}
		}

		public WorkLedger(float[] remaining, float total)
		{
			if (remaining.Length == 0 || remaining.Length > 4096 || remaining.Any((float x) => !Finite(x) || x < 0f) || !Finite(total) || total <= 0f || remaining.Sum() > total + 0.1f)
			{
				throw new ArgumentException("Invalid deposit state");
			}
			Remaining = (float[])remaining.Clone();
			Total = total;
		}

		public int Apply(float damage, int preferred)
		{
			if (!Finite(damage) || damage <= 0f || Complete)
			{
				return -1;
			}
			int num = Next(preferred);
			Remaining[num] = Math.Max(0f, Remaining[num] - damage);
			return num;
		}

		public int Next(int preferred)
		{
			if (preferred < 0 || preferred >= Remaining.Length || !(Remaining[preferred] > 0f))
			{
				return Array.FindIndex(Remaining, (float x) => x > 0f);
			}
			return preferred;
		}

		public void ReconcileNative(float[] before, float[] after)
		{
			if (before.Length != Remaining.Length || after.Length != Remaining.Length || before.Any((float x) => !Finite(x) || x < 0f) || after.Any((float x) => !Finite(x) || x < 0f))
			{
				throw new ArgumentException("Invalid native health snapshot");
			}
			for (int num = 0; num < Remaining.Length; num++)
			{
				Remaining[num] = ((after[num] <= 0f) ? 0f : Math.Max(0f, Remaining[num] - Math.Max(0f, before[num] - after[num])));
			}
		}

		public void Explode()
		{
			Array.Clear(Remaining, 0, Remaining.Length);
		}

		public static bool Finite(float value)
		{
			if (!float.IsNaN(value))
			{
				return !float.IsInfinity(value);
			}
			return false;
		}
	}
}