Decompiled source of Ore Excavation v1.0.1

BepInEx/plugins/OreExcavation.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;

[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: AssemblyTitle("OreExcavation")]
[assembly: AssemblyDescription("Terraria-style Ore Excavation for Valheim 1.0.20+: break one chunk of an ore vein to chain-excavate the entire deposit at pickaxe-dependent speed and bring all underground ore neatly to the surface.")]
[assembly: AssemblyProduct("OreExcavation")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.1.0")]
[module: UnverifiableCode]
[module: UnverifiableCode]
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public string AssemblyName { get; }

		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
			AssemblyName = assemblyName;
		}
	}
}
namespace OreExcavation
{
	[BepInPlugin("com.valheim.oreexcavation", "Ore Excavation", "1.0.1")]
	public class OreExcavationPlugin : BaseUnityPlugin
	{
		private struct ChunkTarget
		{
			public int Index;

			public Vector3 WorldPos;
		}

		private struct PickaxeProfile
		{
			public ItemData Weapon;

			public string LocalizedWeaponName;

			public int ToolTier;

			public float PickaxeDamage;

			public float SkillFactor;

			public bool Cheated;

			public ZDOID AttackerZdoId;
		}

		private struct MineRockAreaWorkItem
		{
			public MineRock Rock;

			public int AreaIndex;

			public Vector3 WorldPos;
		}

		[HarmonyPatch(typeof(MineRock5), "DamageArea")]
		private static class MineRock5_DamageArea_Patch
		{
			private static void Postfix(MineRock5 __instance, int hitAreaIndex, HitData hit, bool __result)
			{
				if (__result && !((Object)(object)__instance == (Object)null) && TryValidatePlayerPickaxeHit(hit, out var profile) && !IsPlayerBuiltOrLivingEntity(((Component)__instance).gameObject))
				{
					string cleanPrefabName = GetCleanPrefabName(((Object)((Component)__instance).gameObject).name);
					if (IsDropTableValidTarget(__instance.m_dropItems, cleanPrefabName))
					{
						StartMineRock5Excavation(__instance, hitAreaIndex, hit, profile);
					}
				}
			}
		}

		[HarmonyPatch(typeof(MineRock), "RPC_Hit")]
		private static class MineRock_RPC_Hit_Patch
		{
			private static void Prefix(MineRock __instance, int hitAreaIndex, out bool __state)
			{
				__state = false;
				if (!((Object)(object)__instance == (Object)null) && !isInternalExcavationCall && modEnabled.Value && isOn.Value)
				{
					ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
					if (!((Object)(object)component == (Object)null) && component.IsValid() && component.IsOwner() && component.GetZDO() != null)
					{
						float num = ((!(m_mr_GetHealth != null)) ? __instance.m_health : ((float)m_mr_GetHealth.Invoke(__instance, null)));
						__state = component.GetZDO().GetFloat("Health" + hitAreaIndex, num) > 0f;
					}
				}
			}

			private static void Postfix(MineRock __instance, HitData hit, int hitAreaIndex, bool __state)
			{
				if (!__state || (Object)(object)__instance == (Object)null)
				{
					return;
				}
				ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
				if ((Object)(object)component == (Object)null || !component.IsValid() || component.GetZDO() == null)
				{
					return;
				}
				float num = ((!(m_mr_GetHealth != null)) ? __instance.m_health : ((float)m_mr_GetHealth.Invoke(__instance, null)));
				float num2 = component.GetZDO().GetFloat("Health" + hitAreaIndex, num);
				if (!(num2 > 0f) && TryValidatePlayerPickaxeHit(hit, out var profile) && !IsPlayerBuiltOrLivingEntity(((Component)__instance).gameObject))
				{
					string cleanPrefabName = GetCleanPrefabName(((Object)((Component)__instance).gameObject).name);
					if (IsDropTableValidTarget(__instance.m_dropItems, cleanPrefabName))
					{
						StartMineRockExcavation(__instance, hitAreaIndex, hit, profile);
					}
				}
			}
		}

		[HarmonyPatch(typeof(Destructible), "Destroy")]
		private static class Destructible_Destroy_Patch
		{
			private static void Prefix(Destructible __instance, HitData hit)
			{
				//IL_0035: Unknown result type (might be due to invalid IL or missing references)
				//IL_003b: Invalid comparison between Unknown and I4
				if (!((Object)(object)__instance == (Object)null) && hit != null && !isInternalExcavationCall && !((Object)(object)__instance.m_spawnWhenDestroyed != (Object)null) && (int)__instance.m_damages.m_pickaxe != 3 && TryValidatePlayerPickaxeHit(hit, out var profile) && !IsPlayerBuiltOrLivingEntity(((Component)__instance).gameObject))
				{
					DropOnDestroyed component = ((Component)__instance).GetComponent<DropOnDestroyed>();
					string cleanPrefabName = GetCleanPrefabName(((Object)((Component)__instance).gameObject).name);
					if (!((Object)(object)component == (Object)null) && IsDropTableValidTarget(component.m_dropWhenDestroyed, cleanPrefabName))
					{
						StartDestructibleClusterExcavation(__instance, hit, profile);
					}
				}
			}
		}

		[HarmonyPatch(typeof(DropOnDestroyed), "OnDestroyed")]
		private static class DropOnDestroyed_OnDestroyed_Patch
		{
			private static bool Prefix(DropOnDestroyed __instance)
			{
				if (!activeDropRedirectAnchor.HasValue || activeRedirectBuffer == null || (Object)(object)__instance == (Object)null)
				{
					return true;
				}
				AccumulateDropsFromTable(__instance.m_dropWhenDestroyed, activeRedirectBuffer);
				return false;
			}
		}

		public const string PluginGuid = "com.valheim.oreexcavation";

		public const string PluginName = "Ore Excavation";

		public const string PluginVersion = "1.0.1";

		public static ConfigEntry<bool> modEnabled;

		public static ConfigEntry<bool> isOn;

		public static ConfigEntry<KeyboardShortcut> toggleKey;

		public static ConfigEntry<bool> showNotifications;

		public static ConfigEntry<bool> farthestFirst;

		public static ConfigEntry<string> toggleMessage;

		public static ConfigEntry<float> antlerBaseDelay;

		public static ConfigEntry<float> minChunkDelay;

		public static ConfigEntry<float> speedMultiplier;

		public static ConfigEntry<float> tierSpeedBonus;

		public static ConfigEntry<float> skillSpeedBonus;

		public static ConfigEntry<float> maxMaintainDistance;

		public static ConfigEntry<bool> allowPlainStone;

		public static ConfigEntry<bool> autoDetectModdedOres;

		public static ConfigEntry<float> clusterSearchRadius;

		public static ConfigEntry<string> extraAllowedPrefabs;

		public static ConfigEntry<string> excludedPrefabs;

		public static ConfigEntry<bool> surfaceStackLoot;

		public static ConfigEntry<float> durabilityPerChunk;

		public static ConfigEntry<bool> protectPickaxeFromBreaking;

		public static ConfigEntry<float> staminaPerChunk;

		public static ConfigEntry<float> skillXpPerChunk;

		private static OreExcavationPlugin instance;

		private Harmony harmony;

		private static readonly HashSet<int> activeExcavations = new HashSet<int>();

		private static bool isInternalExcavationCall;

		private static Vector3? activeDropRedirectAnchor;

		private static Dictionary<GameObject, int> activeRedirectBuffer;

		private static float lastWarnTime;

		private static readonly HashSet<string> KnownOreDropNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
		{
			"CopperOre", "TinOre", "IronScrap", "SilverOre", "BlackMetalScrap", "FlametalOre", "FlametalOreNew", "CopperScrap", "BronzeScrap", "Obsidian",
			"Chitin", "Softtissue", "Guck", "RoyalJelly"
		};

		private static readonly HashSet<string> PlainRockDropNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Stone", "Flint", "BlackMarble", "Grausten" };

		private static FieldInfo f_mr5_hitAreas;

		private static FieldInfo f_mr5_allDestroyed;

		private static MethodInfo m_mr5_LoadHealth;

		private static MethodInfo m_mr5_SaveHealth;

		private static MethodInfo m_mr5_AllDestroyed;

		private static FieldInfo f_ha_collider;

		private static FieldInfo f_ha_health;

		private static FieldInfo f_mr_hitAreas;

		private static MethodInfo m_mr_GetHealth;

		private static MethodInfo m_mr_AllDestroyed;

		private static FieldInfo f_dest_destroyed;

		private static MethodInfo m_dest_Destroy;

		private static MethodInfo m_itemDrop_SetStack;

		private static MethodInfo m_itemDrop_AutoStackItems;

		private static MethodInfo m_itemDrop_Save;

		private void Awake()
		{
			//IL_005d: 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_010d: Expected O, but got Unknown
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Expected O, but got Unknown
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Expected O, but got Unknown
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Expected O, but got Unknown
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Expected O, but got Unknown
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Expected O, but got Unknown
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bb: Expected O, but got Unknown
			//IL_0356: Unknown result type (might be due to invalid IL or missing references)
			//IL_0360: Expected O, but got Unknown
			//IL_03b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bd: Expected O, but got Unknown
			//IL_03f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fa: Expected O, but got Unknown
			//IL_040a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0414: Expected O, but got Unknown
			instance = this;
			modEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Enabled", true, "Enable or disable the Ore Excavation mod completely.");
			isOn = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "IsOn", true, "Current active state of automatic vein excavation (toggled in-game with ToggleKey).");
			toggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("1 - General", "ToggleKey", new KeyboardShortcut((KeyCode)121, Array.Empty<KeyCode>()), "Hotkey to toggle Ore Excavation ON/OFF in-game (default: Y, conflict-free with Valheim 1.0 and quickslot mods).");
			showNotifications = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "ShowNotifications", true, "Show HUD notifications when toggling the mode or starting excavation on a vein.");
			toggleMessage = ((BaseUnityPlugin)this).Config.Bind<string>("1 - General", "ToggleMessage", "Ore Excavation: {0}", "HUD message format when toggling mode ({0} is replaced with ON / OFF).");
			farthestFirst = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "FarthestFirst", false, "Experimental: excavate remaining targets from farthest to nearest relative to the original hit point. The first chunk is still broken by the player. Default false preserves the original nearest-neighbor chain.");
			antlerBaseDelay = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Speed & Pickaxe Scaling", "AntlerBaseDelay", 0.22f, new ConfigDescription("Base seconds per chunk when mining with the starter Antler Pickaxe (Tier 0, 18 dmg). Better pickaxes, forge upgrades, and higher Pickaxes skill reduce this delay automatically.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.03f, 1f), Array.Empty<object>()));
			minChunkDelay = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Speed & Pickaxe Scaling", "MinChunkDelay", 0.02f, new ConfigDescription("Minimum delay (in seconds) per chunk for top-tier upgraded pickaxes.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.005f, 0.25f), Array.Empty<object>()));
			speedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Speed & Pickaxe Scaling", "SpeedMultiplier", 1f, new ConfigDescription("Global excavation speed multiplier (1.0 = balanced default, 2.0 = twice as fast, 0.5 = half speed).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 10f), Array.Empty<object>()));
			tierSpeedBonus = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Speed & Pickaxe Scaling", "TierSpeedBonus", 0.35f, new ConfigDescription("Additional speed multiplier bonus per pickaxe tool tier (+0.35 = +35% faster per tier on top of raw pickaxe damage scaling).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1.5f), Array.Empty<object>()));
			skillSpeedBonus = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Speed & Pickaxe Scaling", "SkillSpeedBonus", 0.35f, new ConfigDescription("Additional speed bonus at Pickaxes skill level 100 (+0.35 = up to +35% faster).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1.5f), Array.Empty<object>()));
			maxMaintainDistance = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Speed & Pickaxe Scaling", "MaxMaintainDistance", 25f, new ConfigDescription("Maximum distance (in meters) from the deposit before active chain excavation stops.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 100f), Array.Empty<object>()));
			allowPlainStone = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Targets", "AllowPlainStone", false, "If true, plain stone boulders, Black Marble cliffs, and Grausten rocks will also be chain-excavated. Default false (ores and valuable deposits only).");
			autoDetectModdedOres = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Targets", "AutoDetectModdedOres", true, "Automatically detect custom ores added by other mods (items ending in Ore/Scrap or non-teleportable mineral drops).");
			clusterSearchRadius = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Targets", "ClusterSearchRadius", 10f, new ConfigDescription("Radius (in meters) to chain-excavate neighboring single-node ore deposits of the exact same type (e.g., Tin along a shoreline or Obsidian on a mountain). Set to 0 to disable cluster chaining.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 30f), Array.Empty<object>()));
			extraAllowedPrefabs = ((BaseUnityPlugin)this).Config.Bind<string>("3 - Targets", "ExtraAllowedPrefabs", string.Empty, "Comma-separated list of rock/deposit prefab names to always allow excavating.");
			excludedPrefabs = ((BaseUnityPlugin)this).Config.Bind<string>("3 - Targets", "ExcludedPrefabs", string.Empty, "Comma-separated list of rock/deposit prefab names to never excavate.");
			surfaceStackLoot = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - Balance & Loot", "SurfaceStackLoot", true, "Bring all underground/underwater ore and stone drops neatly to the surface hit spot in merged stacks so nothing gets trapped under terrain.");
			durabilityPerChunk = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Balance & Loot", "DurabilityPerChunk", 0.15f, new ConfigDescription("Gentle pickaxe durability cost per chain-excavated chunk (0.15 = ~15 durability for an entire 100-chunk copper vein; 0 = free).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>()));
			protectPickaxeFromBreaking = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - Balance & Loot", "ProtectPickaxeFromBreaking", true, "Keep at least 1.0 durability on the pickaxe during chain excavation so a vein does not shatter your pickaxe mid-chain.");
			staminaPerChunk = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Balance & Loot", "StaminaPerChunk", 0.2f, new ConfigDescription("Gentle stamina drain per chain-excavated chunk (stops draining if player stamina is below 10; 0 = free).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>()));
			skillXpPerChunk = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Balance & Loot", "SkillXpPerChunk", 0.12f, new ConfigDescription("Pickaxes skill XP awarded per chain-excavated chunk (0.12 = ~12 normal swings worth of XP per 100-chunk copper deposit).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			CacheReflection();
			harmony = new Harmony("com.valheim.oreexcavation");
			harmony.PatchAll(Assembly.GetExecutingAssembly());
			((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} {1} (Valheim 1.0.20+) loaded successfully.", "Ore Excavation", "1.0.1"));
		}

		private void OnDestroy()
		{
			activeExcavations.Clear();
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private static void CacheReflection()
		{
			f_mr5_hitAreas = AccessTools.Field(typeof(MineRock5), "m_hitAreas");
			f_mr5_allDestroyed = AccessTools.Field(typeof(MineRock5), "m_allDestroyed");
			m_mr5_LoadHealth = AccessTools.Method(typeof(MineRock5), "LoadHealth", (Type[])null, (Type[])null);
			m_mr5_SaveHealth = AccessTools.Method(typeof(MineRock5), "SaveHealth", (Type[])null, (Type[])null);
			m_mr5_AllDestroyed = AccessTools.Method(typeof(MineRock5), "AllDestroyed", (Type[])null, (Type[])null);
			Type type = AccessTools.Inner(typeof(MineRock5), "HitArea");
			if (type != null)
			{
				f_ha_collider = AccessTools.Field(type, "m_collider");
				f_ha_health = AccessTools.Field(type, "m_health");
			}
			f_mr_hitAreas = AccessTools.Field(typeof(MineRock), "m_hitAreas");
			m_mr_GetHealth = AccessTools.Method(typeof(MineRock), "GetHealth", (Type[])null, (Type[])null);
			m_mr_AllDestroyed = AccessTools.Method(typeof(MineRock), "AllDestroyed", (Type[])null, (Type[])null);
			f_dest_destroyed = AccessTools.Field(typeof(Destructible), "m_destroyed");
			m_dest_Destroy = AccessTools.Method(typeof(Destructible), "Destroy", new Type[1] { typeof(HitData) }, (Type[])null);
			m_itemDrop_SetStack = AccessTools.Method(typeof(ItemDrop), "SetStack", new Type[1] { typeof(int) }, (Type[])null);
			m_itemDrop_AutoStackItems = AccessTools.Method(typeof(ItemDrop), "AutoStackItems", (Type[])null, (Type[])null);
			m_itemDrop_Save = AccessTools.Method(typeof(ItemDrop), "Save", (Type[])null, (Type[])null);
		}

		private void Update()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if (!modEnabled.Value || ShouldIgnoreInput())
			{
				return;
			}
			KeyboardShortcut value = toggleKey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown())
			{
				isOn.Value = !isOn.Value;
				((BaseUnityPlugin)this).Config.Save();
				if (!isOn.Value)
				{
					activeExcavations.Clear();
				}
				if (showNotifications.Value && (Object)(object)Player.m_localPlayer != (Object)null)
				{
					string arg = ((!isOn.Value) ? "OFF" : "ON");
					string text = string.Format((!string.IsNullOrEmpty(toggleMessage.Value)) ? toggleMessage.Value : "Ore Excavation: {0}", arg);
					((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false);
				}
			}
		}

		private static bool ShouldIgnoreInput()
		{
			if ((Object)(object)ZNetScene.instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return true;
			}
			if (Minimap.IsOpen() || Console.IsVisible() || TextInput.IsVisible() || StoreGui.IsVisible() || InventoryGui.IsVisible() || Menu.IsVisible())
			{
				return true;
			}
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.InPasswordDialog())
			{
				return true;
			}
			if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus())
			{
				return true;
			}
			if ((Object)(object)TextViewer.instance != (Object)null && TextViewer.instance.IsVisible())
			{
				return true;
			}
			return false;
		}

		private static void LogWarningThrottled(string msg)
		{
			if ((Object)(object)instance != (Object)null && Time.realtimeSinceStartup - lastWarnTime > 5f)
			{
				lastWarnTime = Time.realtimeSinceStartup;
				((BaseUnityPlugin)instance).Logger.LogWarning((object)msg);
			}
		}

		private static string GetCleanPrefabName(string rawName)
		{
			if (string.IsNullOrEmpty(rawName))
			{
				return string.Empty;
			}
			int num = rawName.IndexOf('(');
			return ((num < 0) ? rawName : rawName.Substring(0, num)).Trim();
		}

		private static bool MatchesPrefabList(string csvList, string cleanPrefabName)
		{
			if (string.IsNullOrWhiteSpace(csvList) || string.IsNullOrEmpty(cleanPrefabName))
			{
				return false;
			}
			string b = ((!cleanPrefabName.EndsWith("_frac", StringComparison.OrdinalIgnoreCase)) ? cleanPrefabName : cleanPrefabName.Substring(0, cleanPrefabName.Length - 5));
			string[] array = csvList.Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length != 0 && (string.Equals(text, cleanPrefabName, StringComparison.OrdinalIgnoreCase) || string.Equals(text, b, StringComparison.OrdinalIgnoreCase)))
				{
					return true;
				}
			}
			return false;
		}

		private static bool IsPlayerBuiltOrLivingEntity(GameObject go)
		{
			if ((Object)(object)go == (Object)null)
			{
				return true;
			}
			if ((Object)(object)go.GetComponent<Piece>() != (Object)null || (Object)(object)go.GetComponentInParent<Piece>() != (Object)null)
			{
				return true;
			}
			if ((Object)(object)go.GetComponent<WearNTear>() != (Object)null || (Object)(object)go.GetComponentInParent<WearNTear>() != (Object)null)
			{
				return true;
			}
			if ((Object)(object)go.GetComponent<TreeBase>() != (Object)null || (Object)(object)go.GetComponent<TreeLog>() != (Object)null)
			{
				return true;
			}
			if ((Object)(object)go.GetComponent<Character>() != (Object)null || (Object)(object)go.GetComponentInParent<Character>() != (Object)null)
			{
				return true;
			}
			return false;
		}

		private static bool IsDropTableValidTarget(DropTable table, string cleanNodePrefabName)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Invalid comparison between Unknown and I4
			if (MatchesPrefabList(excludedPrefabs.Value, cleanNodePrefabName))
			{
				return false;
			}
			if (MatchesPrefabList(extraAllowedPrefabs.Value, cleanNodePrefabName))
			{
				return true;
			}
			if (table == null || table.m_drops == null || table.m_drops.Count == 0)
			{
				return false;
			}
			bool flag = false;
			bool flag2 = false;
			for (int i = 0; i < table.m_drops.Count; i++)
			{
				GameObject item = table.m_drops[i].m_item;
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				string cleanPrefabName = GetCleanPrefabName(((Object)item).name);
				if (string.IsNullOrEmpty(cleanPrefabName))
				{
					continue;
				}
				if (KnownOreDropNames.Contains(cleanPrefabName))
				{
					flag = true;
					break;
				}
				if (PlainRockDropNames.Contains(cleanPrefabName))
				{
					flag2 = true;
				}
				else
				{
					if (!autoDetectModdedOres.Value)
					{
						continue;
					}
					if (cleanPrefabName.EndsWith("Ore", StringComparison.OrdinalIgnoreCase) || cleanPrefabName.EndsWith("Scrap", StringComparison.OrdinalIgnoreCase))
					{
						flag = true;
						break;
					}
					ItemDrop component = item.GetComponent<ItemDrop>();
					if ((Object)(object)component != (Object)null && component.m_itemData != null && component.m_itemData.m_shared != null)
					{
						SharedData shared = component.m_itemData.m_shared;
						if (!shared.m_teleportable && (int)shared.m_itemType == 1)
						{
							flag = true;
							break;
						}
					}
				}
			}
			if (flag)
			{
				return true;
			}
			return allowPlainStone.Value && flag2;
		}

		private static bool TryValidatePlayerPickaxeHit(HitData hit, out PickaxeProfile profile)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Invalid comparison between Unknown and I4
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			profile = default(PickaxeProfile);
			if (!modEnabled.Value || !isOn.Value || isInternalExcavationCall || hit == null)
			{
				return false;
			}
			if ((int)hit.m_hitType == 15 || hit.m_damage.m_pickaxe <= 0f)
			{
				return false;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead())
			{
				return false;
			}
			Character attacker = hit.GetAttacker();
			if ((Object)(object)attacker == (Object)null || (Object)(object)attacker != (Object)(object)localPlayer)
			{
				return false;
			}
			ItemData currentWeapon = ((Humanoid)localPlayer).GetCurrentWeapon();
			if (currentWeapon == null || currentWeapon.m_shared == null)
			{
				return false;
			}
			float pickaxe = currentWeapon.GetDamage().m_pickaxe;
			if (pickaxe <= 0f)
			{
				pickaxe = hit.m_damage.m_pickaxe;
			}
			if (pickaxe <= 0f)
			{
				return false;
			}
			bool cheated = false;
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			if (inventory != null)
			{
				cheated = inventory.CheatedDamagingItemEquipped();
			}
			string localizedWeaponName = (string.IsNullOrEmpty(currentWeapon.m_shared.m_name) ? "Pickaxe" : currentWeapon.m_shared.m_name);
			profile = new PickaxeProfile
			{
				Weapon = currentWeapon,
				LocalizedWeaponName = localizedWeaponName,
				ToolTier = Mathf.Max(currentWeapon.m_shared.m_toolTier, (int)hit.m_toolTier),
				PickaxeDamage = pickaxe,
				SkillFactor = Mathf.Clamp01(((Character)localPlayer).GetSkillFactor((SkillType)12)),
				Cheated = cheated,
				AttackerZdoId = ((Character)localPlayer).GetZDOID()
			};
			return true;
		}

		private static float CalculateChunkDelay(PickaxeProfile profile, float chunkBaseHealth)
		{
			float num = Mathf.Max(0.35f, profile.PickaxeDamage / 18f);
			float num2 = 1f + (float)Mathf.Max(0, profile.ToolTier) * Mathf.Max(0f, tierSpeedBonus.Value);
			float num3 = 1f + profile.SkillFactor * Mathf.Max(0f, skillSpeedBonus.Value);
			float num4 = Mathf.Clamp((!(chunkBaseHealth > 0f)) ? 35f : chunkBaseHealth, 15f, 100f);
			float num5 = num4 / 35f;
			float num6 = num * num2 * num3 * Mathf.Max(0.1f, speedMultiplier.Value);
			float num7 = antlerBaseDelay.Value * num5 / Mathf.Max(0.1f, num6);
			return Mathf.Clamp(num7, minChunkDelay.Value, 2f);
		}

		private static Vector3 ComputeSafeSurfaceAnchor(Vector3 hitPoint)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			Vector3 val = hitPoint;
			if ((Object)(object)localPlayer != (Object)null)
			{
				Vector3 position = ((Component)localPlayer).transform.position;
				Vector3 val2 = position - hitPoint;
				val2.y = 0f;
				if (((Vector3)(ref val2)).sqrMagnitude > 0.01f)
				{
					float num = Mathf.Min(0.65f, ((Vector3)(ref val2)).magnitude * 0.45f);
					val += ((Vector3)(ref val2)).normalized * num;
				}
				val.y = Mathf.Max(hitPoint.y + 0.35f, position.y + 0.55f);
			}
			else
			{
				val.y += 0.5f;
			}
			if (val.y < 4000f && (Object)(object)ZoneSystem.instance != (Object)null)
			{
				float groundHeight = ZoneSystem.instance.GetGroundHeight(val);
				if (val.y < groundHeight + 0.45f)
				{
					val.y = groundHeight + 0.45f;
				}
			}
			return val;
		}

		private static List<ChunkTarget> OrderNearestNeighborChain(List<ChunkTarget> rawTargets, Vector3 startOrigin)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: 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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: 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_00ea: Unknown result type (might be due to invalid IL or missing references)
			if (farthestFirst.Value)
			{
				rawTargets.Sort(delegate(ChunkTarget a, ChunkTarget b)
				{
					//IL_0002: 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_0012: Unknown result type (might be due to invalid IL or missing references)
					//IL_001f: Unknown result type (might be due to invalid IL or missing references)
					//IL_0025: 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)
					Vector3 val3 = b.WorldPos - startOrigin;
					float sqrMagnitude2 = ((Vector3)(ref val3)).sqrMagnitude;
					Vector3 val4 = a.WorldPos - startOrigin;
					return sqrMagnitude2.CompareTo(((Vector3)(ref val4)).sqrMagnitude);
				});
				return rawTargets;
			}
			int count = rawTargets.Count;
			List<ChunkTarget> list = new List<ChunkTarget>(count);
			if (count == 0)
			{
				return list;
			}
			bool[] array = new bool[count];
			Vector3 val = startOrigin;
			for (int num = 0; num < count; num++)
			{
				int num2 = -1;
				float num3 = float.MaxValue;
				for (int num4 = 0; num4 < count; num4++)
				{
					if (!array[num4])
					{
						Vector3 val2 = rawTargets[num4].WorldPos - val;
						float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
						if (sqrMagnitude < num3)
						{
							num3 = sqrMagnitude;
							num2 = num4;
						}
					}
				}
				if (num2 < 0)
				{
					break;
				}
				array[num2] = true;
				ChunkTarget item = rawTargets[num2];
				list.Add(item);
				val = item.WorldPos;
			}
			return list;
		}

		private static void AccumulateDropsFromTable(DropTable table, Dictionary<GameObject, int> buffer)
		{
			if (table == null || buffer == null)
			{
				return;
			}
			try
			{
				List<GameObject> dropList = table.GetDropList();
				if (dropList == null)
				{
					return;
				}
				for (int i = 0; i < dropList.Count; i++)
				{
					GameObject val = dropList[i];
					if (!((Object)(object)val == (Object)null))
					{
						if (buffer.TryGetValue(val, out var value))
						{
							buffer[val] = value + 1;
						}
						else
						{
							buffer[val] = 1;
						}
					}
				}
			}
			catch (Exception ex)
			{
				LogWarningThrottled("AccumulateDropsFromTable error: " + ex.Message);
			}
		}

		private static void FlushDropBuffer(Dictionary<GameObject, int> buffer, Vector3 surfaceAnchor, bool cheated)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: 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_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: 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_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: 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_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			if (buffer == null || buffer.Count == 0)
			{
				return;
			}
			try
			{
				Vector3 val = surfaceAnchor;
				if (val.y < 4000f && (Object)(object)ZoneSystem.instance != (Object)null)
				{
					float groundHeight = ZoneSystem.instance.GetGroundHeight(val);
					if (val.y < groundHeight + 0.45f)
					{
						val.y = groundHeight + 0.45f;
					}
				}
				int num = 0;
				foreach (KeyValuePair<GameObject, int> item in buffer)
				{
					GameObject key = item.Key;
					int value = item.Value;
					if ((Object)(object)key == (Object)null || value <= 0)
					{
						continue;
					}
					ItemDrop component = key.GetComponent<ItemDrop>();
					if ((Object)(object)component == (Object)null || component.m_itemData == null || component.m_itemData.m_shared == null)
					{
						for (int i = 0; i < value; i++)
						{
							Vector2 val2 = Random.insideUnitCircle * 0.35f;
							Vector3 val3 = val + new Vector3(val2.x, 0.15f, val2.y);
							Object.Instantiate<GameObject>(key, val3, Quaternion.identity);
						}
						continue;
					}
					int num2 = Mathf.Max(1, component.m_itemData.m_stack);
					int num3 = value * num2;
					int num4 = Mathf.Max(1, component.m_itemData.m_shared.m_maxStackSize);
					while (num3 > 0)
					{
						int num5 = Mathf.Min(num3, num4);
						num3 -= num5;
						Vector2 val4 = Random.insideUnitCircle * 0.35f;
						Vector3 val5 = val + new Vector3(val4.x, 0.1f + (float)(num % 4) * 0.12f, val4.y);
						Quaternion val6 = Quaternion.Euler(0f, Random.Range(0f, 360f), 0f);
						num++;
						GameObject val7 = Object.Instantiate<GameObject>(key, val5, val6);
						ItemDrop component2 = val7.GetComponent<ItemDrop>();
						if (!((Object)(object)component2 != (Object)null))
						{
							continue;
						}
						ItemDrop.OnCreateNew(component2, cheated);
						if (num5 > 1)
						{
							if (m_itemDrop_SetStack != null)
							{
								m_itemDrop_SetStack.Invoke(component2, new object[1] { num5 });
							}
							else
							{
								component2.m_itemData.m_stack = num5;
								if ((object)m_itemDrop_Save != null)
								{
									m_itemDrop_Save.Invoke(component2, null);
								}
							}
						}
						if ((object)m_itemDrop_AutoStackItems != null)
						{
							m_itemDrop_AutoStackItems.Invoke(component2, null);
						}
					}
				}
			}
			catch (Exception ex)
			{
				LogWarningThrottled("FlushDropBuffer error: " + ex.Message);
			}
			finally
			{
				buffer.Clear();
			}
		}

		private static bool ApplyPerChunkPlayerCosts(PickaxeProfile profile)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead())
			{
				return false;
			}
			if (durabilityPerChunk.Value > 0f && profile.Weapon != null && profile.Weapon.m_shared != null && profile.Weapon.m_shared.m_useDurability)
			{
				float value = durabilityPerChunk.Value;
				if (protectPickaxeFromBreaking.Value)
				{
					if (profile.Weapon.m_durability > 1f)
					{
						profile.Weapon.m_durability = Mathf.Max(1f, profile.Weapon.m_durability - value);
					}
				}
				else
				{
					profile.Weapon.m_durability = Mathf.Max(0f, profile.Weapon.m_durability - value);
					if (profile.Weapon.m_durability <= 0f)
					{
						return false;
					}
				}
			}
			if (staminaPerChunk.Value > 0f)
			{
				float num = ((Character)localPlayer).GetStaminaPercentage() * ((Character)localPlayer).GetMaxStamina();
				if (num > 10f)
				{
					float num2 = Mathf.Min(staminaPerChunk.Value, num - 10f);
					if (num2 > 0f)
					{
						((Character)localPlayer).UseStamina(num2);
					}
				}
			}
			if (skillXpPerChunk.Value > 0f)
			{
				((Character)localPlayer).RaiseSkill((SkillType)12, skillXpPerChunk.Value);
			}
			return true;
		}

		private static bool ShouldContinueExcavation(Vector3 referencePosition)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			if (!modEnabled.Value || !isOn.Value)
			{
				return false;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead())
			{
				return false;
			}
			float value = maxMaintainDistance.Value;
			Vector3 val = ((Component)localPlayer).transform.position - referencePosition;
			if (((Vector3)(ref val)).sqrMagnitude > value * value)
			{
				return false;
			}
			return true;
		}

		private static void NotifyExcavationStarted(string rawNodeName, int chunkCount, PickaxeProfile profile, float delayPerChunk)
		{
			if (!showNotifications.Value || chunkCount < 2 || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return;
			}
			string text = ((!string.IsNullOrWhiteSpace(rawNodeName)) ? rawNodeName : "Ore Vein");
			float num = (float)chunkCount * delayPerChunk;
			string text2 = $"{text}: {chunkCount} ({num:0.0}s - {profile.LocalizedWeaponName})";
			Sprite val = null;
			try
			{
				if (profile.Weapon != null && profile.Weapon.m_shared != null && profile.Weapon.m_shared.m_icons != null && profile.Weapon.m_shared.m_icons.Length > 0)
				{
					int num2 = Mathf.Clamp(profile.Weapon.m_variant, 0, profile.Weapon.m_shared.m_icons.Length - 1);
					val = profile.Weapon.m_shared.m_icons[num2];
				}
			}
			catch
			{
				val = null;
			}
			((Character)Player.m_localPlayer).Message((MessageType)1, text2, 0, val, false);
		}

		private static void StartMineRock5Excavation(MineRock5 rock, int brokenIndex, HitData hit, PickaxeProfile profile)
		{
			//IL_0038: 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_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)rock == (Object)null || (Object)(object)instance == (Object)null)
			{
				return;
			}
			int instanceID = ((Object)rock).GetInstanceID();
			if (!activeExcavations.Contains(instanceID))
			{
				List<ChunkTarget> list = CollectOrderedMineRock5Chunks(rock, brokenIndex, hit.m_point);
				if (list.Count != 0)
				{
					Vector3 surfaceAnchor = ComputeSafeSurfaceAnchor(hit.m_point);
					float num = CalculateChunkDelay(profile, rock.m_health);
					activeExcavations.Add(instanceID);
					NotifyExcavationStarted(rock.m_name, list.Count, profile, num);
					((MonoBehaviour)instance).StartCoroutine(ExcavateMineRock5Coroutine(rock, instanceID, list, surfaceAnchor, num, profile));
				}
			}
		}

		private static List<ChunkTarget> CollectOrderedMineRock5Chunks(MineRock5 rock, int brokenIndex, Vector3 hitPoint)
		{
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: 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)
			List<ChunkTarget> list = new List<ChunkTarget>();
			try
			{
				if (f_mr5_hitAreas == null || f_ha_health == null || f_ha_collider == null)
				{
					return list;
				}
				if ((object)m_mr5_LoadHealth != null)
				{
					m_mr5_LoadHealth.Invoke(rock, null);
				}
				if (!(f_mr5_hitAreas.GetValue(rock) is IList list2))
				{
					return list;
				}
				for (int i = 0; i < list2.Count; i++)
				{
					if (i == brokenIndex)
					{
						continue;
					}
					object obj = list2[i];
					if (obj == null)
					{
						continue;
					}
					float num = (float)f_ha_health.GetValue(obj);
					if (!(num <= 0f))
					{
						object? value = f_ha_collider.GetValue(obj);
						Collider val = (Collider)((value is Collider) ? value : null);
						Vector3 worldPos = ((Component)rock).transform.position;
						if ((Object)(object)val != (Object)null)
						{
							Bounds bounds = val.bounds;
							Vector3 extents = ((Bounds)(ref bounds)).extents;
							worldPos = ((!(((Vector3)(ref extents)).sqrMagnitude > 0.0001f)) ? ((Component)val).transform.position : ((Bounds)(ref bounds)).center);
						}
						list.Add(new ChunkTarget
						{
							Index = i,
							WorldPos = worldPos
						});
					}
				}
			}
			catch (Exception ex)
			{
				LogWarningThrottled("CollectOrderedMineRock5Chunks error: " + ex.Message);
			}
			return OrderNearestNeighborChain(list, hitPoint);
		}

		private static IEnumerator ExcavateMineRock5Coroutine(MineRock5 rock, int rockKey, List<ChunkTarget> chain, Vector3 surfaceAnchor, float stepDelay, PickaxeProfile profile)
		{
			//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)
			Dictionary<GameObject, int> dropBuffer = new Dictionary<GameObject, int>();
			int cursor = 0;
			float timer = 0f;
			float lastEffectTime = -10f;
			float lastFlushTime = Time.time;
			try
			{
				while (cursor < chain.Count)
				{
					yield return null;
					if ((Object)(object)rock == (Object)null)
					{
						break;
					}
					ZNetView nview = ((Component)rock).GetComponent<ZNetView>();
					if ((Object)(object)nview == (Object)null || !nview.IsValid() || nview.GetZDO() == null || !ShouldContinueExcavation(surfaceAnchor))
					{
						break;
					}
					timer += Time.deltaTime;
					if (!(timer < stepDelay))
					{
						int stepsThisFrame = Mathf.Clamp(Mathf.FloorToInt(timer / stepDelay), 1, 4);
						timer -= (float)stepsThisFrame * stepDelay;
						bool keepGoing = BreakMineRock5StepBatch(rock, nview, chain, ref cursor, stepsThisFrame, surfaceAnchor, profile, dropBuffer, ref lastEffectTime);
						if (surfaceStackLoot.Value && dropBuffer.Count > 0 && Time.time - lastFlushTime >= 0.25f)
						{
							FlushDropBuffer(dropBuffer, surfaceAnchor, profile.Cheated);
							lastFlushTime = Time.time;
						}
						if (!keepGoing)
						{
							break;
						}
					}
				}
			}
			finally
			{
				if (dropBuffer.Count > 0)
				{
					FlushDropBuffer(dropBuffer, surfaceAnchor, profile.Cheated);
				}
				activeExcavations.Remove(rockKey);
			}
		}

		private static bool BreakMineRock5StepBatch(MineRock5 rock, ZNetView nview, List<ChunkTarget> chain, ref int cursor, int maxChunksToBreak, Vector3 surfaceAnchor, PickaxeProfile profile, Dictionary<GameObject, int> dropBuffer, ref float lastEffectTime)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: 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)
			try
			{
				if (!nview.IsOwner())
				{
					nview.ClaimOwnership();
				}
				if ((object)m_mr5_LoadHealth != null)
				{
					m_mr5_LoadHealth.Invoke(rock, null);
				}
				if (!((((object)f_mr5_hitAreas != null) ? f_mr5_hitAreas.GetValue(rock) : null) is IList list))
				{
					return false;
				}
				int num = 0;
				List<int> list2 = new List<int>(maxChunksToBreak);
				Vector3 val = surfaceAnchor;
				while (cursor < chain.Count && num < maxChunksToBreak)
				{
					ChunkTarget chunkTarget = chain[cursor++];
					if (chunkTarget.Index < 0 || chunkTarget.Index >= list.Count)
					{
						continue;
					}
					object obj = list[chunkTarget.Index];
					if (obj == null)
					{
						continue;
					}
					float num2 = (float)f_ha_health.GetValue(obj);
					if (num2 <= 0f)
					{
						continue;
					}
					if (!ApplyPerChunkPlayerCosts(profile))
					{
						return false;
					}
					f_ha_health.SetValue(obj, 0f);
					list2.Add(chunkTarget.Index);
					num++;
					val = chunkTarget.WorldPos;
					if (surfaceStackLoot.Value)
					{
						AccumulateDropsFromTable(rock.m_dropItems, dropBuffer);
					}
					else
					{
						if (rock.m_dropItems == null)
						{
							continue;
						}
						List<GameObject> dropList = rock.m_dropItems.GetDropList();
						for (int i = 0; i < dropList.Count; i++)
						{
							if ((Object)(object)dropList[i] != (Object)null)
							{
								Vector3 val2 = chunkTarget.WorldPos + Random.insideUnitSphere * 0.3f;
								ItemDrop.OnCreateNew(Object.Instantiate<GameObject>(dropList[i], val2, Quaternion.identity), profile.Cheated);
							}
						}
					}
				}
				if (list2.Count > 0)
				{
					if ((object)m_mr5_SaveHealth != null)
					{
						m_mr5_SaveHealth.Invoke(rock, null);
					}
					for (int j = 0; j < list2.Count; j++)
					{
						nview.InvokeRPC(ZNetView.Everybody, "RPC_SetAreaHealth", new object[2]
						{
							list2[j],
							0f
						});
					}
					if (Time.time - lastEffectTime >= 0.14f && rock.m_destroyedEffect != null)
					{
						lastEffectTime = Time.time;
						Vector3 val3 = val;
						if (surfaceAnchor.y - val.y > 2.5f)
						{
							val3 = Vector3.Lerp(val, surfaceAnchor, 0.65f);
						}
						rock.m_destroyedEffect.Create(val3, Quaternion.identity, (Transform)null, 1f, -1, profile.AttackerZdoId);
					}
					if (m_mr5_AllDestroyed != null && (bool)m_mr5_AllDestroyed.Invoke(rock, null))
					{
						if ((object)f_mr5_allDestroyed != null)
						{
							f_mr5_allDestroyed.SetValue(rock, true);
						}
						nview.Destroy();
						return false;
					}
				}
				return true;
			}
			catch (Exception ex)
			{
				LogWarningThrottled("BreakMineRock5StepBatch error: " + ex.Message);
				return false;
			}
		}

		private static void StartMineRockExcavation(MineRock rootRock, int brokenIndex, HitData hit, PickaxeProfile profile)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)rootRock == (Object)null || (Object)(object)instance == (Object)null)
			{
				return;
			}
			int instanceID = ((Object)rootRock).GetInstanceID();
			if (!activeExcavations.Contains(instanceID))
			{
				List<MineRockAreaWorkItem> list = CollectOrderedMineRockWorkItems(rootRock, brokenIndex, hit.m_point, profile.ToolTier);
				if (list.Count != 0)
				{
					Vector3 surfaceAnchor = ComputeSafeSurfaceAnchor(hit.m_point);
					float num = CalculateChunkDelay(profile, rootRock.m_health);
					activeExcavations.Add(instanceID);
					NotifyExcavationStarted(rootRock.m_name, list.Count, profile, num);
					((MonoBehaviour)instance).StartCoroutine(ExcavateMineRockCoroutine(instanceID, list, surfaceAnchor, num, profile));
				}
			}
		}

		private static List<MineRockAreaWorkItem> CollectOrderedMineRockWorkItems(MineRock rootRock, int brokenIndex, Vector3 origin, int toolTier)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0345: Unknown result type (might be due to invalid IL or missing references)
			//IL_034a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_037c: 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)
			//IL_0383: Unknown result type (might be due to invalid IL or missing references)
			//IL_0388: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0281: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b5: Unknown result type (might be due to invalid IL or missing references)
			List<MineRockAreaWorkItem> list = new List<MineRockAreaWorkItem>();
			try
			{
				List<MineRock> list2 = new List<MineRock>();
				list2.Add(rootRock);
				List<MineRock> list3 = list2;
				string cleanPrefabName = GetCleanPrefabName(((Object)((Component)rootRock).gameObject).name);
				if (clusterSearchRadius.Value > 0f && (Object)(object)((Component)rootRock).GetComponent<Leviathan>() == (Object)null)
				{
					Collider[] array = Physics.OverlapSphere(origin, clusterSearchRadius.Value);
					for (int i = 0; i < array.Length; i++)
					{
						if (!((Object)(object)array[i] == (Object)null))
						{
							MineRock componentInParent = ((Component)array[i]).GetComponentInParent<MineRock>();
							if (!((Object)(object)componentInParent == (Object)null) && !((Object)(object)componentInParent == (Object)(object)rootRock) && !list3.Contains(componentInParent) && !activeExcavations.Contains(((Object)componentInParent).GetInstanceID()) && toolTier >= componentInParent.m_minToolTier && !IsPlayerBuiltOrLivingEntity(((Component)componentInParent).gameObject) && string.Equals(GetCleanPrefabName(((Object)((Component)componentInParent).gameObject).name), cleanPrefabName, StringComparison.OrdinalIgnoreCase))
							{
								list3.Add(componentInParent);
							}
						}
					}
				}
				for (int j = 0; j < list3.Count; j++)
				{
					MineRock val = list3[j];
					ZNetView component = ((Component)val).GetComponent<ZNetView>();
					if ((Object)(object)component == (Object)null || !component.IsValid() || component.GetZDO() == null || !((((object)f_mr_hitAreas != null) ? f_mr_hitAreas.GetValue(val) : null) is Collider[] array2))
					{
						continue;
					}
					float num = ((!(m_mr_GetHealth != null)) ? val.m_health : ((float)m_mr_GetHealth.Invoke(val, null)));
					for (int k = 0; k < array2.Length; k++)
					{
						if ((Object)(object)val == (Object)(object)rootRock && k == brokenIndex)
						{
							continue;
						}
						Collider val2 = array2[k];
						if ((Object)(object)val2 == (Object)null || !((Component)val2).gameObject.activeInHierarchy)
						{
							continue;
						}
						float num2 = component.GetZDO().GetFloat("Health" + k, num);
						if (!(num2 <= 0f))
						{
							MineRockAreaWorkItem item = new MineRockAreaWorkItem
							{
								Rock = val,
								AreaIndex = k
							};
							Bounds bounds = val2.bounds;
							Vector3 extents = ((Bounds)(ref bounds)).extents;
							Vector3 worldPos;
							if (((Vector3)(ref extents)).sqrMagnitude > 0.0001f)
							{
								Bounds bounds2 = val2.bounds;
								worldPos = ((Bounds)(ref bounds2)).center;
							}
							else
							{
								worldPos = ((Component)val2).transform.position;
							}
							item.WorldPos = worldPos;
							list.Add(item);
						}
					}
				}
			}
			catch (Exception ex)
			{
				LogWarningThrottled("CollectOrderedMineRockWorkItems error: " + ex.Message);
			}
			if (farthestFirst.Value)
			{
				list.Sort(delegate(MineRockAreaWorkItem a, MineRockAreaWorkItem b)
				{
					//IL_0002: 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_0012: Unknown result type (might be due to invalid IL or missing references)
					//IL_001f: Unknown result type (might be due to invalid IL or missing references)
					//IL_0025: 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)
					Vector3 val5 = b.WorldPos - origin;
					float sqrMagnitude2 = ((Vector3)(ref val5)).sqrMagnitude;
					Vector3 val6 = a.WorldPos - origin;
					return sqrMagnitude2.CompareTo(((Vector3)(ref val6)).sqrMagnitude);
				});
				return list;
			}
			List<MineRockAreaWorkItem> list4 = new List<MineRockAreaWorkItem>(list.Count);
			bool[] array3 = new bool[list.Count];
			Vector3 val3 = origin;
			for (int num3 = 0; num3 < list.Count; num3++)
			{
				int num4 = -1;
				float num5 = float.MaxValue;
				for (int num6 = 0; num6 < list.Count; num6++)
				{
					if (!array3[num6])
					{
						Vector3 val4 = list[num6].WorldPos - val3;
						float sqrMagnitude = ((Vector3)(ref val4)).sqrMagnitude;
						if (sqrMagnitude < num5)
						{
							num5 = sqrMagnitude;
							num4 = num6;
						}
					}
				}
				if (num4 < 0)
				{
					break;
				}
				array3[num4] = true;
				list4.Add(list[num4]);
				val3 = list[num4].WorldPos;
			}
			return list4;
		}

		private static IEnumerator ExcavateMineRockCoroutine(int rootKey, List<MineRockAreaWorkItem> chain, Vector3 surfaceAnchor, float stepDelay, PickaxeProfile profile)
		{
			//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)
			Dictionary<GameObject, int> dropBuffer = new Dictionary<GameObject, int>();
			int cursor = 0;
			float timer = 0f;
			float lastEffectTime = -10f;
			float lastFlushTime = Time.time;
			try
			{
				while (cursor < chain.Count)
				{
					yield return null;
					if (!ShouldContinueExcavation(surfaceAnchor))
					{
						break;
					}
					timer += Time.deltaTime;
					if (!(timer < stepDelay))
					{
						int steps = Mathf.Clamp(Mathf.FloorToInt(timer / stepDelay), 1, 4);
						timer -= (float)steps * stepDelay;
						bool keepGoing = BreakMineRockStepBatch(chain, ref cursor, steps, surfaceAnchor, profile, dropBuffer, ref lastEffectTime);
						if (surfaceStackLoot.Value && dropBuffer.Count > 0 && Time.time - lastFlushTime >= 0.25f)
						{
							FlushDropBuffer(dropBuffer, surfaceAnchor, profile.Cheated);
							lastFlushTime = Time.time;
						}
						if (!keepGoing)
						{
							break;
						}
					}
				}
			}
			finally
			{
				if (dropBuffer.Count > 0)
				{
					FlushDropBuffer(dropBuffer, surfaceAnchor, profile.Cheated);
				}
				activeExcavations.Remove(rootKey);
			}
		}

		private static bool BreakMineRockStepBatch(List<MineRockAreaWorkItem> chain, ref int cursor, int maxToBreak, Vector3 surfaceAnchor, PickaxeProfile profile, Dictionary<GameObject, int> dropBuffer, ref float lastEffectTime)
		{
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				int num = 0;
				while (cursor < chain.Count && num < maxToBreak)
				{
					MineRockAreaWorkItem mineRockAreaWorkItem = chain[cursor++];
					if ((Object)(object)mineRockAreaWorkItem.Rock == (Object)null)
					{
						continue;
					}
					ZNetView component = ((Component)mineRockAreaWorkItem.Rock).GetComponent<ZNetView>();
					if ((Object)(object)component == (Object)null || !component.IsValid() || component.GetZDO() == null)
					{
						continue;
					}
					if (!component.IsOwner())
					{
						component.ClaimOwnership();
					}
					float num2 = ((!(m_mr_GetHealth != null)) ? mineRockAreaWorkItem.Rock.m_health : ((float)m_mr_GetHealth.Invoke(mineRockAreaWorkItem.Rock, null)));
					string text = "Health" + mineRockAreaWorkItem.AreaIndex;
					if (component.GetZDO().GetFloat(text, num2) <= 0f)
					{
						continue;
					}
					if (!ApplyPerChunkPlayerCosts(profile))
					{
						return false;
					}
					component.GetZDO().Set(text, 0f);
					component.InvokeRPC(ZNetView.Everybody, "Hide", new object[1] { mineRockAreaWorkItem.AreaIndex });
					num++;
					if (Time.time - lastEffectTime >= 0.14f && mineRockAreaWorkItem.Rock.m_destroyedEffect != null)
					{
						lastEffectTime = Time.time;
						mineRockAreaWorkItem.Rock.m_destroyedEffect.Create(mineRockAreaWorkItem.WorldPos, Quaternion.identity, (Transform)null, 1f, -1, profile.AttackerZdoId);
					}
					if (surfaceStackLoot.Value)
					{
						AccumulateDropsFromTable(mineRockAreaWorkItem.Rock.m_dropItems, dropBuffer);
					}
					else if (mineRockAreaWorkItem.Rock.m_dropItems != null)
					{
						List<GameObject> dropList = mineRockAreaWorkItem.Rock.m_dropItems.GetDropList();
						for (int i = 0; i < dropList.Count; i++)
						{
							if ((Object)(object)dropList[i] != (Object)null)
							{
								Vector3 val = mineRockAreaWorkItem.WorldPos + Random.insideUnitSphere * 0.3f;
								ItemDrop.OnCreateNew(Object.Instantiate<GameObject>(dropList[i], val, Quaternion.identity), profile.Cheated);
							}
						}
					}
					bool flag = m_mr_AllDestroyed != null && (bool)m_mr_AllDestroyed.Invoke(mineRockAreaWorkItem.Rock, null);
					if (mineRockAreaWorkItem.Rock.m_removeWhenDestroyed && flag)
					{
						component.Destroy();
					}
				}
				return true;
			}
			catch (Exception ex)
			{
				LogWarningThrottled("BreakMineRockStepBatch error: " + ex.Message);
				return false;
			}
		}

		private static void StartDestructibleClusterExcavation(Destructible originNode, HitData hit, PickaxeProfile profile)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)originNode == (Object)null || (Object)(object)instance == (Object)null || clusterSearchRadius.Value <= 0f)
			{
				return;
			}
			Vector3 val = ((!(((Vector3)(ref hit.m_point)).sqrMagnitude > 0.01f)) ? ((Component)originNode).transform.position : hit.m_point);
			string cleanPrefabName = GetCleanPrefabName(((Object)((Component)originNode).gameObject).name);
			if (string.IsNullOrEmpty(cleanPrefabName))
			{
				return;
			}
			List<Destructible> list = FindOrderedNeighborDestructibles(originNode, val, cleanPrefabName, profile.ToolTier);
			if (list.Count != 0)
			{
				Vector3 surfaceAnchor = ComputeSafeSurfaceAnchor(val);
				float num = Mathf.Max(0.08f, CalculateChunkDelay(profile, originNode.m_health) * 1.75f);
				int instanceID = ((Object)list[0]).GetInstanceID();
				for (int i = 0; i < list.Count; i++)
				{
					activeExcavations.Add(((Object)list[i]).GetInstanceID());
				}
				Hoverable component = ((Component)originNode).GetComponent<Hoverable>();
				string rawNodeName = ((component == null) ? cleanPrefabName : component.GetHoverName());
				NotifyExcavationStarted(rawNodeName, list.Count, profile, num);
				((MonoBehaviour)instance).StartCoroutine(ExcavateDestructibleClusterCoroutine(list, surfaceAnchor, num, profile));
			}
		}

		private static List<Destructible> FindOrderedNeighborDestructibles(Destructible originNode, Vector3 originPos, string cleanPrefabName, int toolTier)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_028f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			List<Destructible> list = new List<Destructible>();
			try
			{
				Collider[] array = Physics.OverlapSphere(originPos, clusterSearchRadius.Value);
				for (int i = 0; i < array.Length; i++)
				{
					if ((Object)(object)array[i] == (Object)null)
					{
						continue;
					}
					Destructible componentInParent = ((Component)array[i]).GetComponentInParent<Destructible>();
					if ((Object)(object)componentInParent == (Object)null || (Object)(object)componentInParent == (Object)(object)originNode || list.Contains(componentInParent) || activeExcavations.Contains(((Object)componentInParent).GetInstanceID()) || (Object)(object)componentInParent.m_spawnWhenDestroyed != (Object)null || toolTier < componentInParent.m_minToolTier || IsPlayerBuiltOrLivingEntity(((Component)componentInParent).gameObject) || (f_dest_destroyed != null && (bool)f_dest_destroyed.GetValue(componentInParent)))
					{
						continue;
					}
					ZNetView component = ((Component)componentInParent).GetComponent<ZNetView>();
					if (!((Object)(object)component == (Object)null) && component.IsValid() && component.GetZDO() != null && string.Equals(GetCleanPrefabName(((Object)((Component)componentInParent).gameObject).name), cleanPrefabName, StringComparison.OrdinalIgnoreCase))
					{
						DropOnDestroyed component2 = ((Component)componentInParent).GetComponent<DropOnDestroyed>();
						if (!((Object)(object)component2 == (Object)null) && IsDropTableValidTarget(component2.m_dropWhenDestroyed, cleanPrefabName))
						{
							list.Add(componentInParent);
						}
					}
				}
			}
			catch (Exception ex)
			{
				LogWarningThrottled("FindOrderedNeighborDestructibles error: " + ex.Message);
			}
			if (farthestFirst.Value)
			{
				list.Sort(delegate(Destructible a, Destructible b)
				{
					//IL_0006: 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)
					//IL_0027: Unknown result type (might be due to invalid IL or missing references)
					//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_0037: Unknown result type (might be due to invalid IL or missing references)
					Vector3 val3 = ((Component)b).transform.position - originPos;
					float sqrMagnitude2 = ((Vector3)(ref val3)).sqrMagnitude;
					Vector3 val4 = ((Component)a).transform.position - originPos;
					return sqrMagnitude2.CompareTo(((Vector3)(ref val4)).sqrMagnitude);
				});
				return list;
			}
			List<Destructible> list2 = new List<Destructible>(list.Count);
			bool[] array2 = new bool[list.Count];
			Vector3 val = originPos;
			for (int num = 0; num < list.Count; num++)
			{
				int num2 = -1;
				float num3 = float.MaxValue;
				for (int num4 = 0; num4 < list.Count; num4++)
				{
					if (!array2[num4])
					{
						Vector3 val2 = ((Component)list[num4]).transform.position - val;
						float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
						if (sqrMagnitude < num3)
						{
							num3 = sqrMagnitude;
							num2 = num4;
						}
					}
				}
				if (num2 < 0)
				{
					break;
				}
				array2[num2] = true;
				list2.Add(list[num2]);
				val = ((Component)list[num2]).transform.position;
			}
			return list2;
		}

		private static IEnumerator ExcavateDestructibleClusterCoroutine(List<Destructible> neighbors, Vector3 surfaceAnchor, float stepDelay, PickaxeProfile profile)
		{
			//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)
			Dictionary<GameObject, int> dropBuffer = new Dictionary<GameObject, int>();
			int cursor = 0;
			try
			{
				while (cursor < neighbors.Count)
				{
					yield return (object)new WaitForSeconds(stepDelay);
					if (!ShouldContinueExcavation(surfaceAnchor))
					{
						break;
					}
					Destructible target = neighbors[cursor++];
					if (!BreakSingleNeighborDestructible(target, surfaceAnchor, profile, dropBuffer))
					{
						break;
					}
					if (surfaceStackLoot.Value && dropBuffer.Count > 0)
					{
						FlushDropBuffer(dropBuffer, surfaceAnchor, profile.Cheated);
					}
				}
			}
			finally
			{
				if (dropBuffer.Count > 0)
				{
					FlushDropBuffer(dropBuffer, surfaceAnchor, profile.Cheated);
				}
				for (int i = 0; i < neighbors.Count; i++)
				{
					if ((Object)(object)neighbors[i] != (Object)null)
					{
						activeExcavations.Remove(((Object)neighbors[i]).GetInstanceID());
					}
				}
			}
		}

		private static bool BreakSingleNeighborDestructible(Destructible target, Vector3 surfaceAnchor, PickaxeProfile profile, Dictionary<GameObject, int> dropBuffer)
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)target == (Object)null)
			{
				return true;
			}
			try
			{
				if (f_dest_destroyed != null && (bool)f_dest_destroyed.GetValue(target))
				{
					return true;
				}
				ZNetView component = ((Component)target).GetComponent<ZNetView>();
				if ((Object)(object)component == (Object)null || !component.IsValid() || component.GetZDO() == null)
				{
					return true;
				}
				if (!component.IsOwner())
				{
					component.ClaimOwnership();
				}
				if (!ApplyPerChunkPlayerCosts(profile))
				{
					return false;
				}
				HitData val = new HitData();
				val.m_point = ((Component)target).transform.position;
				val.m_dir = Vector3.up;
				val.m_toolTier = (short)profile.ToolTier;
				val.m_damage.m_pickaxe = profile.PickaxeDamage;
				if ((Object)(object)Player.m_localPlayer != (Object)null)
				{
					val.SetAttacker((Character)(object)Player.m_localPlayer);
				}
				isInternalExcavationCall = true;
				if (surfaceStackLoot.Value)
				{
					activeDropRedirectAnchor = surfaceAnchor;
					activeRedirectBuffer = dropBuffer;
				}
				try
				{
					component.GetZDO().Set("health", 0f);
					if (m_dest_Destroy != null)
					{
						m_dest_Destroy.Invoke(target, new object[1] { val });
					}
					else
					{
						target.Damage(val);
					}
				}
				finally
				{
					activeDropRedirectAnchor = null;
					activeRedirectBuffer = null;
					isInternalExcavationCall = false;
				}
				return true;
			}
			catch (Exception ex)
			{
				LogWarningThrottled("BreakSingleNeighborDestructible error: " + ex.Message);
				return false;
			}
		}
	}
}