Decompiled source of SansaraTools v0.1.0

plugins/SansaraTools.dll

Decompiled 7 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using SansaraTools.Core;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("SansaraTools")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+e2fac571d4f7c138f666b28f378dd6a67cf86f2b")]
[assembly: AssemblyProduct("SansaraTools")]
[assembly: AssemblyTitle("SansaraTools")]
[assembly: AssemblyVersion("0.1.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SansaraTools
{
	internal static class AxeFlagsSync
	{
		internal static readonly int Key = StringExtensionMethods.GetStableHashCode("sansara_tools_axe");

		private static Player _player;

		private static ZNetView _nview;

		private static bool _known;

		private static int _written;

		internal static void Tick()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				_player = null;
				return;
			}
			if (localPlayer != _player)
			{
				_player = localPlayer;
				_nview = ((Component)localPlayer).GetComponent<ZNetView>();
				_known = false;
			}
			ZDO val = (((Object)(object)_nview != (Object)null) ? _nview.GetZDO() : null);
			if (val != null && _nview.IsOwner())
			{
				if (!_known)
				{
					_known = true;
					_written = val.GetInt(Key, 0);
				}
				int num = AxeFlagBits.Pack(ToolConfig.Enabled.Value && ToolInput.HeldKind() == ToolKind.Axe, ToolState.UprootNow);
				if (num != _written)
				{
					val.Set(Key, num, false);
					_written = num;
				}
			}
		}

		internal static int Read(ZDOID attacker)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (((ZDOID)(ref attacker)).IsNone() || ZDOMan.instance == null)
			{
				return 0;
			}
			ZDO zDO = ZDOMan.instance.GetZDO(attacker);
			if (zDO == null)
			{
				return 0;
			}
			return zDO.GetInt(Key, 0);
		}
	}
	internal sealed class FellContext
	{
		internal ZDOID Attacker;

		internal bool Uproot;

		internal bool Felled;

		internal bool Uprooted;

		internal string TreePrefab;

		internal Vector3 Position;

		internal Quaternion Rotation;

		internal Vector3 Scale;
	}
	[HarmonyPatch(typeof(TreeBase), "RPC_Damage")]
	internal static class TreeFellOwnerPatch
	{
		internal const string RpcName = "SansaraTools_TreeFelled";

		private static readonly FieldRef<TreeBase, ZNetView> NViewRef = AccessTools.FieldRefAccess<TreeBase, ZNetView>("m_nview");

		internal static FellContext Current;

		private static void Prefix(TreeBase __instance, HitData hit, ref FellContext __state)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			__state = null;
			Current = null;
			if (hit == null || ToolConfig.Enabled == null || !ToolConfig.Enabled.Value)
			{
				return;
			}
			ZNetView val = NViewRef.Invoke(__instance);
			if (!((Object)(object)val == (Object)null) && val.IsValid() && val.IsOwner())
			{
				int bits = AxeFlagsSync.Read(hit.m_attacker);
				if (AxeFlagBits.HoldsAxe(bits))
				{
					Transform transform = ((Component)__instance).transform;
					__state = new FellContext
					{
						Attacker = hit.m_attacker,
						Uproot = (ToolConfig.Uproot.Value && AxeFlagBits.Uproot(bits)),
						TreePrefab = Utils.GetPrefabName(((Object)((Component)__instance).gameObject).name),
						Position = transform.position,
						Rotation = transform.rotation,
						Scale = transform.localScale
					};
					Current = __state;
				}
			}
		}

		private static void Postfix(FellContext __state)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			if (__state == null || !__state.Felled || !ToolConfig.Forester.Value)
			{
				return;
			}
			ZDO val = ((ZDOMan.instance != null) ? ZDOMan.instance.GetZDO(__state.Attacker) : null);
			if (val != null && ZRoutedRpc.instance != null)
			{
				long owner = val.GetOwner();
				if (owner != 0L)
				{
					ZPackage val2 = new ZPackage();
					val2.Write(__state.Attacker);
					val2.Write(__state.TreePrefab);
					val2.Write(__state.Position);
					val2.Write(((Quaternion)(ref __state.Rotation)).eulerAngles.y);
					val2.Write(__state.Uprooted);
					ZRoutedRpc.instance.InvokeRoutedRPC(owner, "SansaraTools_TreeFelled", new object[1] { val2 });
				}
			}
		}

		private static void Finalizer()
		{
			Current = null;
		}
	}
	[HarmonyPatch(typeof(TreeBase), "SpawnLog")]
	internal static class TreeStubPatch
	{
		private static bool _failLogged;

		private static void Prefix(TreeBase __instance, ref GameObject __state)
		{
			__state = null;
			FellContext current = TreeFellOwnerPatch.Current;
			if (current != null)
			{
				current.Felled = true;
				GameObject stubPrefab = __instance.m_stubPrefab;
				if (current.Uproot && !((Object)(object)stubPrefab == (Object)null) && !((Object)(object)stubPrefab.GetComponent<Destructible>() == (Object)null))
				{
					__state = stubPrefab;
					__instance.m_stubPrefab = null;
				}
			}
		}

		private static void Postfix(GameObject __state)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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)
			FellContext current = TreeFellOwnerPatch.Current;
			if ((Object)(object)__state == (Object)null || current == null)
			{
				return;
			}
			try
			{
				GameObject obj = Object.Instantiate<GameObject>(__state, current.Position, current.Rotation);
				ZNetView component = obj.GetComponent<ZNetView>();
				if ((Object)(object)component != (Object)null)
				{
					component.SetLocalScale(current.Scale);
				}
				obj.GetComponent<Destructible>().Destroy((HitData)null);
				current.Uprooted = true;
			}
			catch (Exception ex)
			{
				if (!_failLogged)
				{
					_failLogged = true;
					Plugin.Log.LogError((object)("Sansara Tools: корчевание пня не выполнено: " + ex));
				}
			}
		}

		private static void Finalizer(TreeBase __instance, GameObject __state)
		{
			if ((Object)(object)__state != (Object)null && (Object)(object)__instance != (Object)null)
			{
				__instance.m_stubPrefab = __state;
			}
		}
	}
	[HarmonyPatch(typeof(Game), "Start")]
	internal static class ForesterRpcPatch
	{
		private static void Postfix()
		{
			if (ZRoutedRpc.instance == null)
			{
				return;
			}
			try
			{
				ZRoutedRpc.instance.Register<ZPackage>("SansaraTools_TreeFelled", (Action<long, ZPackage>)Forester.OnFelled);
			}
			catch (ArgumentException)
			{
			}
		}
	}
	internal static class Forester
	{
		private const float FirstDelay = 2f;

		private const float RetryDelay = 2f;

		private const int Attempts = 4;

		private const float DuplicateWindow = 30f;

		private const float MaxTreeDistance = 30f;

		private static readonly Collider[] Buffer = (Collider[])(object)new Collider[30];

		private static readonly List<Vector3> RecentSpots = new List<Vector3>();

		private static readonly List<float> RecentTimes = new List<float>();

		private static bool _uprootHintShown;

		private static int _spaceMask;

		private static int _roofMask;

		private const string NoSpace = "мешает соседний предмет (бревно, камень, постройка)";

		internal static void OnFelled(long sender, ZPackage pkg)
		{
			//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)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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_006e: 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_0088: 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)
			//IL_0094: 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_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			if (Application.isBatchMode || pkg == null)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			ZDOID val;
			string treePrefab;
			Vector3 val2;
			float rotY;
			bool uprooted;
			try
			{
				val = pkg.ReadZDOID();
				treePrefab = pkg.ReadString();
				val2 = pkg.ReadVector3();
				rotY = pkg.ReadSingle();
				uprooted = pkg.ReadBool();
			}
			catch (Exception)
			{
				return;
			}
			if (((ZDOID)(ref val)).IsNone() || val != ((Character)localPlayer).GetZDOID() || float.IsNaN(val2.x) || float.IsNaN(val2.y) || float.IsNaN(val2.z))
			{
				return;
			}
			Vector3 val3 = val2 - ((Component)localPlayer).transform.position;
			if (((Vector3)(ref val3)).sqrMagnitude > 900f || !ToolConfig.Forestry().TryGet(treePrefab, out var entry))
			{
				return;
			}
			bool flag = true;
			GameObject val4 = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(entry.Sapling) : null);
			GameObject val5 = ((flag && (Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(entry.Seed) : null);
			ItemDrop val6 = (((Object)(object)val5 != (Object)null) ? val5.GetComponent<ItemDrop>() : null);
			flag = flag && (Object)(object)val4 != (Object)null && (Object)(object)val4.GetComponent<Piece>() != (Object)null && (Object)(object)val4.GetComponent<Plant>() != (Object)null && (Object)(object)val6 != (Object)null;
			int seeds = (flag ? ((Humanoid)localPlayer).GetInventory().CountItems(val6.m_itemData.m_shared.m_name, -1, false) : 0);
			switch (ForesterRule.Decide(ToolConfig.Enabled.Value && ToolConfig.Forester.Value, flag, uprooted, seeds))
			{
			case ForesterAction.NeedUproot:
				if (!_uprootHintShown)
				{
					_uprootHintShown = true;
					Say("Лесник: саженец сажается только при корчевании (" + ((object)ToolConfig.ModeKey.Value/*cast due to .constrained prefix*/).ToString() + " — режим топора)");
				}
				break;
			case ForesterAction.Plant:
				if (!IsDuplicate(val2))
				{
					((MonoBehaviour)Plugin.Instance).StartCoroutine(PlantLater(val4, val6, val2, rotY));
				}
				break;
			}
		}

		private static bool IsDuplicate(Vector3 pos)
		{
			//IL_0070: 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_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			float time = Time.time;
			for (int num = RecentTimes.Count - 1; num >= 0; num--)
			{
				if (time - RecentTimes[num] > 30f)
				{
					RecentTimes.RemoveAt(num);
					RecentSpots.RemoveAt(num);
				}
				else
				{
					Vector3 val = RecentSpots[num] - pos;
					if (((Vector3)(ref val)).sqrMagnitude < 0.25f)
					{
						return true;
					}
				}
			}
			RecentSpots.Add(pos);
			RecentTimes.Add(time);
			return false;
		}

		private static IEnumerator PlantLater(GameObject sapling, ItemDrop seed, Vector3 treePos, float rotY)
		{
			//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)
			string text = null;
			for (int attempt = 0; attempt < 4; attempt++)
			{
				yield return (object)new WaitForSeconds((attempt == 0) ? 2f : 2f);
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null || !ToolConfig.Enabled.Value || !ToolConfig.Forester.Value)
				{
					yield break;
				}
				string name = seed.m_itemData.m_shared.m_name;
				if (((Humanoid)localPlayer).GetInventory().CountItems(name, -1, false) <= 0)
				{
					yield break;
				}
				Vector3 val = treePos;
				if ((Object)(object)ZoneSystem.instance != (Object)null)
				{
					val.y = ZoneSystem.instance.GetGroundHeight(val);
				}
				text = CheckSpot(sapling, val);
				if (text == null)
				{
					Piece component = sapling.GetComponent<Piece>();
					localPlayer.PlacePiece(component, val, Quaternion.Euler(0f, rotY, 0f), false, false);
					((Humanoid)localPlayer).GetInventory().RemoveItem(name, 1, -1, false);
					Say("Лесник: посажен " + Localization.instance.Localize(component.m_name) + " (−1 " + Localization.instance.Localize(name) + ")");
					yield break;
				}
				if (text != "мешает соседний предмет (бревно, камень, постройка)")
				{
					break;
				}
			}
			if (text != null)
			{
				Say("Лесник: саженец не посажен — " + text);
			}
		}

		private static string CheckSpot(GameObject saplingPrefab, Vector3 pos)
		{
			//IL_000e: 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_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Invalid comparison between Unknown and I4
			//IL_00b5: 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_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Invalid comparison between Unknown and I4
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Invalid comparison between Unknown and I4
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: 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_00fd: Invalid comparison between Unknown and I4
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			Piece component = saplingPrefab.GetComponent<Piece>();
			Plant component2 = saplingPrefab.GetComponent<Plant>();
			Heightmap val = Heightmap.FindHeightmap(pos);
			if ((Object)(object)val == (Object)null)
			{
				return "нет земли";
			}
			Biome biome = val.GetBiome(pos, 0.02f, false);
			if ((int)component.m_onlyInBiome != 0 && (Heightmap.FindBiome(pos) & component.m_onlyInBiome) == 0)
			{
				return "не тот биом";
			}
			if ((component.m_cultivatedGroundOnly || component2.m_needCultivatedGround) && !val.IsCultivated(pos))
			{
				return "нужна возделанная земля";
			}
			if (component.m_vegetationGroundOnly)
			{
				float vegetationMask = val.GetVegetationMask(pos);
				if (((int)biome == 32) ? (vegetationMask > 0.1f) : (vegetationMask < 0.25f))
				{
					return "здесь ничего не растёт";
				}
			}
			if (!PrivateArea.CheckAccess(pos, 0f, false, false))
			{
				return "чужой охранный камень";
			}
			if (Location.IsInsideNoBuildLocation(pos))
			{
				return "здесь нельзя строить";
			}
			if ((biome & component2.m_biome) == 0)
			{
				return "не тот биом";
			}
			if (!component2.m_tolerateHeat && (int)biome == 32 && !ShieldGenerator.IsInsideShield(pos))
			{
				return "слишком жарко";
			}
			if (!component2.m_tolerateCold && ((int)biome == 64 || (int)biome == 4) && !ShieldGenerator.IsInsideShield(pos))
			{
				return "слишком холодно";
			}
			if (_roofMask == 0)
			{
				_roofMask = LayerMask.GetMask(new string[3] { "Default", "static_solid", "piece" });
				_spaceMask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid" });
			}
			if (Physics.Raycast(pos, Vector3.up, 100f, _roofMask))
			{
				return "над местом крыша";
			}
			int num = Physics.OverlapSphereNonAlloc(pos, component2.m_growRadius, Buffer, _spaceMask);
			for (int i = 0; i < num; i++)
			{
				Plant component3 = ((Component)Buffer[i]).GetComponent<Plant>();
				if ((Object)(object)component3 == (Object)null || (int)component3.GetStatus() == 0)
				{
					return "мешает соседний предмет (бревно, камень, постройка)";
				}
			}
			return null;
		}

		private static void Say(string text)
		{
			Player localPlayer = Player.m_localPlayer;
			if (localPlayer != null)
			{
				((Character)localPlayer).Message((MessageType)1, text, 0, (Sprite)null, false);
			}
		}
	}
	internal static class AxeItem
	{
		internal const string DisplayName = "Топор Вёлунда";

		internal const string Description = "Топор, который валит лес без остатка: разделывает брёвна разом, роняет деревья от дровосека и умеет корчевать пни. Древесины даёт столько же, сколько обычный.";

		internal static void Apply(ItemDrop drop)
		{
			if (!((Object)(object)drop == (Object)null))
			{
				SharedData shared = drop.m_itemData.m_shared;
				shared.m_maxDurability = ToolConfig.Durability.Value;
				shared.m_damages.m_chop = ToolConfig.ChopDamage.Value;
			}
		}
	}
	[HarmonyPatch(typeof(TreeBase), "Damage")]
	internal static class AxeTreePatch
	{
		private static void Prefix(TreeBase __instance, HitData hit)
		{
			//IL_0034: 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_0040: 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_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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)
			if (!ToolSwing.Fresh(ToolKind.Axe, hit))
			{
				return;
			}
			ToolSwing.MarkTreeHit(hit);
			if (ToolConfig.DirectedFall.Value && !((Object)(object)ToolSwing.Player == (Object)null))
			{
				Vector3 position = ((Component)ToolSwing.Player).transform.position;
				Vector3 position2 = ((Component)__instance).transform.position;
				if (FallDirection.TryAway(position.x, position.z, position2.x, position2.z, out var dirX, out var dirZ))
				{
					hit.m_dir = new Vector3(dirX, 0f, dirZ);
				}
			}
		}
	}
	[HarmonyPatch(typeof(TreeLog), "Damage")]
	internal static class AxeLogPatch
	{
		private static readonly Collider[] Buffer = (Collider[])(object)new Collider[64];

		private static readonly List<TreeLog> Logs = new List<TreeLog>();

		private static readonly List<Collider> LogColliders = new List<Collider>();

		private static readonly List<P3> Points = new List<P3>();

		private static readonly List<int> Picked = new List<int>();

		private static int _mask;

		private static bool Prefix(TreeLog __instance, HitData hit, ref bool __state)
		{
			__state = false;
			if (!ToolSwing.Fresh(ToolKind.Axe, hit))
			{
				return true;
			}
			ToolSwing.MarkTreeHit(hit);
			if (!ToolSwing.Logs.Add(__instance))
			{
				return false;
			}
			__state = true;
			return true;
		}

		private static void Postfix(TreeLog __instance, HitData hit, bool __state)
		{
			//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_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: 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_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)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: 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_0108: 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_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			if (!__state || ToolSwing.InArea)
			{
				return;
			}
			float value = ToolConfig.LogAreaRadius.Value;
			if (value <= 0f)
			{
				return;
			}
			if (_mask == 0)
			{
				_mask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid" });
			}
			Vector3 point = hit.m_point;
			int num = Physics.OverlapSphereNonAlloc(point, value, Buffer, _mask, (QueryTriggerInteraction)1);
			Logs.Clear();
			LogColliders.Clear();
			Points.Clear();
			for (int i = 0; i < num; i++)
			{
				Collider val = Buffer[i];
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				TreeLog componentInParent = ((Component)val).GetComponentInParent<TreeLog>();
				if ((Object)(object)componentInParent == (Object)null || componentInParent == __instance || ToolSwing.Logs.Contains(componentInParent))
				{
					continue;
				}
				Vector3 val2 = ToolSwing.ClosestPoint(val, point);
				int num2 = Logs.IndexOf(componentInParent);
				if (num2 >= 0)
				{
					if (P3.DistSq(new P3(point.x, point.y, point.z), new P3(val2.x, val2.y, val2.z)) < P3.DistSq(new P3(point.x, point.y, point.z), Points[num2]))
					{
						Points[num2] = new P3(val2.x, val2.y, val2.z);
						LogColliders[num2] = val;
					}
				}
				else
				{
					Logs.Add(componentInParent);
					LogColliders.Add(val);
					Points.Add(new P3(val2.x, val2.y, val2.z));
				}
			}
			AreaSelect.Pick(Points, new P3(point.x, point.y, point.z), value, Picked);
			if (Picked.Count == 0)
			{
				return;
			}
			ToolSwing.InArea = true;
			try
			{
				foreach (int item in Picked)
				{
					TreeLog val3 = Logs[item];
					if (!((Object)(object)val3 == (Object)null) && !ToolSwing.Logs.Contains(val3))
					{
						HitData val4 = hit.Clone();
						P3 p = Points[item];
						val4.m_point = new Vector3(p.X, p.Y, p.Z);
						val4.m_hitCollider = LogColliders[item];
						val3.Damage(val4);
					}
				}
			}
			finally
			{
				ToolSwing.InArea = false;
			}
		}
	}
	internal static class AxeCareful
	{
		internal static bool Blocks(Component target, HitData hit)
		{
			if (!ToolSwing.Fresh(ToolKind.Axe, hit) || !ToolState.CarefulNow || (Object)(object)target == (Object)null)
			{
				return false;
			}
			Piece component = target.GetComponent<Piece>();
			if ((Object)(object)component != (Object)null && component.IsPlacedByPlayer())
			{
				return true;
			}
			return (Object)(object)target.GetComponent<Plant>() != (Object)null;
		}
	}
	[HarmonyPatch(typeof(WearNTear), "Damage")]
	internal static class AxeCarefulBuildingPatch
	{
		private static bool Prefix(WearNTear __instance, HitData hit)
		{
			return !AxeCareful.Blocks((Component)(object)__instance, hit);
		}
	}
	[HarmonyPatch(typeof(Destructible), "Damage")]
	internal static class AxeCarefulDestructiblePatch
	{
		private static bool Prefix(Destructible __instance, HitData hit)
		{
			return !AxeCareful.Blocks((Component)(object)__instance, hit);
		}
	}
	[HarmonyPatch(typeof(Character), "RPC_Damage")]
	internal static class AxeNoSelfLogPatch
	{
		private static bool Prefix(Character __instance, HitData hit)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			if (hit == null || (int)hit.m_hitType != 13)
			{
				return true;
			}
			if ((object)__instance != Player.m_localPlayer || ToolConfig.Enabled == null || !ToolConfig.Enabled.Value || !ToolConfig.NoSelfLogDamage.Value)
			{
				return true;
			}
			float distance = Vector3.Distance(((Component)__instance).transform.position, ToolSwing.LastTreeHitPoint);
			return !LogGuard.IsProtected(Time.time, ToolSwing.LastTreeHitTime, ToolConfig.NoSelfLogSeconds.Value, distance, ToolConfig.NoSelfLogRadius.Value);
		}
	}
	internal static class HoeControl
	{
		internal static void Tick()
		{
			HoeState hoe = ToolState.Hoe;
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				if (hoe.HeightLocked)
				{
					hoe.ResetHeight();
				}
				HoeFillCost.Clear();
				return;
			}
			if (ToolInput.HeldKind() != ToolKind.Hoe)
			{
				HoeFillCost.Clear();
				if (hoe.HeightLocked)
				{
					hoe.ResetHeight();
					Say("Мотыга: фиксация высоты сброшена");
				}
				return;
			}
			HoeVariant hoeVariant = HoePieces.SelectedVariant(localPlayer);
			if (hoeVariant != null && !HoeOps.SlotBelongsTo(hoe.ActiveSlot, hoeVariant.Spec.Op))
			{
				hoe.ActiveSlot = HoeOps.SizeSlotOf(hoeVariant.Spec.Op);
			}
			if (hoeVariant == null || !hoeVariant.Levels)
			{
				HoeFillCost.Clear();
			}
		}

		internal static void CycleMode()
		{
			HoeState hoe = ToolState.Hoe;
			HoeOp hoeOp = HoePieces.SelectedVariant(Player.m_localPlayer)?.Spec.Op ?? HoeOp.Level;
			if (HoeOps.HasEdge(hoeOp))
			{
				bool flag = hoe.CycleMode(allowed: true);
				HoePieces.OnSelectionChanged();
				Say("Мотыга: чёткий край " + ToolTexts.OnOff(flag));
			}
			else if (hoeOp == HoeOp.Raise)
			{
				hoe.ActiveSlot = ((hoe.ActiveSlot != SizeSlot.RaiseRadius) ? SizeSlot.RaiseRadius : SizeSlot.RaiseStep);
				Say("Мотыга: колесо листает " + ToolTexts.SlotName(hoe.ActiveSlot));
			}
			else
			{
				Say("Мотыга: у операции «" + HoeOps.MenuName(hoeOp) + "» нет режимов");
			}
		}

		internal static string AfterSizeStep()
		{
			HoePieces.OnSelectionChanged();
			HoeVariant hoeVariant = HoePieces.SelectedVariant(Player.m_localPlayer);
			if (hoeVariant == null)
			{
				return "";
			}
			int num = HoeOps.Stones(hoeVariant.Spec, ToolConfig.RaiseStoneBase.Value, ToolConfig.PaveStoneBase.Value);
			bool flag = hoeVariant.Levels && ToolConfig.RaiseStoneBase.Value > 0;
			if (!HoeOps.CostsStone(hoeVariant.Spec.Op))
			{
				if (!flag)
				{
					return "";
				}
				return ", насыпь — камень по объёму";
			}
			string text = ((num > 0) ? (", камней: " + num) : ", бесплатно");
			if (!flag)
			{
				return text;
			}
			return text + " + насыпь по объёму";
		}

		internal static void Say(string text)
		{
			Player localPlayer = Player.m_localPlayer;
			if (localPlayer != null)
			{
				((Character)localPlayer).Message((MessageType)1, text, 0, (Sprite)null, false);
			}
		}
	}
	internal static class HoeFillCost
	{
		internal const float Interval = 0.2f;

		private static readonly FieldRef<Heightmap, HMBuildData> BuildData = AccessTools.FieldRefAccess<Heightmap, HMBuildData>("m_buildData");

		private static readonly List<Heightmap> Maps = new List<Heightmap>();

		private static readonly HoeVolume.HeightSample Sampler = Sample;

		private static HoeVariant _variant;

		private static float _time = -1000f;

		private static int _fill;

		private static float _cx;

		private static float _cz;

		private static float _scale = 1f;

		internal static int Fill
		{
			get
			{
				if (_variant == null)
				{
					return 0;
				}
				return _fill;
			}
		}

		internal static void Update(Player player, HoeVariant v, Vector3 ghostPos, bool force)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			if (v == null || !v.Levels)
			{
				Clear();
				return;
			}
			float time = Time.time;
			if (v != _variant)
			{
				Clear();
				_variant = v;
				force = true;
			}
			if (force || !(time - _time < 0.2f))
			{
				_time = time;
				int baseStones = v.BaseStones;
				int value = ToolConfig.RaiseStoneBase.Value;
				_fill = ((value > 0) ? HoeVolume.Stones(value, Volume(v, ghostPos)) : 0);
				HoePieces.SetStones(v, baseStones + _fill);
			}
		}

		internal static void Clear()
		{
			if (_variant != null)
			{
				HoePieces.SetStones(_variant, _variant.BaseStones);
				_variant = null;
			}
			_fill = 0;
			_time = -1000f;
		}

		private static float Volume(HoeVariant v, Vector3 pos)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: 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_0080: 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_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = pos + Vector3.up * v.Op.m_settings.m_levelOffset;
			Maps.Clear();
			Heightmap.FindHeightmap(val, v.LevelOuter + 1f, Maps);
			if (Maps.Count == 0)
			{
				return 0f;
			}
			Heightmap val2 = Maps[0];
			_scale = ((val2.m_scale > 0f) ? val2.m_scale : 1f);
			int num = default(int);
			int num2 = default(int);
			val2.WorldToVertex(val, ref num, ref num2);
			Vector3 position = ((Component)val2).transform.position;
			int num3 = val2.m_width / 2;
			_cx = position.x + (float)(num - num3) * _scale;
			_cz = position.z + (float)(num2 - num3) * _scale;
			return HoeVolume.Raise(val.y, v.LevelInner / _scale, v.LevelOuter / _scale, 1f * _scale, _scale * _scale, Sampler);
		}

		private static bool Sample(int dx, int dz, out float height, out float maxHeight)
		{
			//IL_0056: 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)
			height = 0f;
			maxHeight = float.MaxValue;
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(_cx + (float)dx * _scale, 0f, _cz + (float)dz * _scale);
			int num = default(int);
			int num2 = default(int);
			for (int i = 0; i < Maps.Count; i++)
			{
				Heightmap val2 = Maps[i];
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				val2.WorldToVertex(val, ref num, ref num2);
				int num3 = val2.m_width + 1;
				if (num >= 0 && num2 >= 0 && num < num3 && num2 < num3)
				{
					float y = ((Component)val2).transform.position.y;
					height = val2.GetHeight(num, num2) + y;
					List<float> list = BuildData.Invoke(val2)?.m_baseHeights;
					int index = num2 * num3 + num;
					if (list != null && list.Count == num3 * num3)
					{
						maxHeight = list[index] + y + 8f;
					}
					return true;
				}
			}
			return false;
		}
	}
	internal static class HoeItem
	{
		internal const string DisplayName = "Мотыга Ивальди";

		internal const string Description = "Мотыга, выкованная для больших строек: ровняет землю широким кругом и запоминает высоту. Не добывает больше, но экономит часы работы.";

		internal static void Apply(ItemDrop drop)
		{
			if (!((Object)(object)drop == (Object)null))
			{
				drop.m_itemData.m_shared.m_maxDurability = ToolConfig.Durability.Value;
				HoePieces.Apply(drop);
			}
		}
	}
	[HarmonyPatch(typeof(TerrainComp), "InternalDoOperation")]
	internal static class SoftLevelPatch
	{
		private static readonly FieldRef<TerrainComp, Heightmap> Hmap = AccessTools.FieldRefAccess<TerrainComp, Heightmap>("m_hmap");

		private static readonly FieldRef<TerrainComp, int> Width = AccessTools.FieldRefAccess<TerrainComp, int>("m_width");

		private static readonly FieldRef<TerrainComp, float[]> LevelDelta = AccessTools.FieldRefAccess<TerrainComp, float[]>("m_levelDelta");

		private static readonly FieldRef<TerrainComp, float[]> SmoothDelta = AccessTools.FieldRefAccess<TerrainComp, float[]>("m_smoothDelta");

		private static readonly FieldRef<TerrainComp, bool[]> Modified = AccessTools.FieldRefAccess<TerrainComp, bool[]>("m_modifiedHeight");

		private static readonly FieldRef<TerrainComp, float> LastOpRadius = AccessTools.FieldRefAccess<TerrainComp, float>("m_lastOpRadius");

		private static bool _errorLogged;

		private static void Prefix(TerrainComp __instance, Vector3 pos, Settings modifier, ref bool __state)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: 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)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			__state = false;
			if (!modifier.m_level || !HoePieces.TryGetSoft(modifier, out var inner))
			{
				return;
			}
			try
			{
				Heightmap val = Hmap.Invoke(__instance);
				if (!((Object)(object)val == (Object)null))
				{
					Vector3 val2 = pos + Vector3.up * modifier.m_levelOffset;
					int cx = default(int);
					int cy = default(int);
					val.WorldToVertex(val2, ref cx, ref cy);
					float y = (val2 - ((Component)__instance).transform.position).y;
					float num = ((val.m_scale > 0f) ? val.m_scale : 1f);
					SoftLevel.Apply(Width.Invoke(__instance) + 1, cx, cy, y, inner / num, modifier.m_levelRadius / num, 1f * num, (Func<int, int, float>)val.GetHeight, LevelDelta.Invoke(__instance), SmoothDelta.Invoke(__instance), Modified.Invoke(__instance));
					modifier.m_level = false;
					__state = true;
				}
			}
			catch (Exception ex)
			{
				if (!_errorLogged)
				{
					_errorLogged = true;
					Plugin.Log.LogError((object)("Sansara Tools: мягкий край выравнивания не выполнен, выравнивание пойдёт ванильным (чёткий край): " + ex));
				}
			}
		}

		private static void Finalizer(TerrainComp __instance, Settings modifier, bool __state)
		{
			if (__state)
			{
				modifier.m_level = true;
				LastOpRadius.Invoke(__instance) = modifier.GetRadius();
			}
		}
	}
	[HarmonyPatch(typeof(Player), "UpdatePlacementGhost")]
	internal static class LockedHeightGhostPatch
	{
		private static readonly FieldRef<Player, GameObject> Ghost = AccessTools.FieldRefAccess<Player, GameObject>("m_placementGhost");

		private static void Postfix(Player __instance, bool flashGuardStone)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			HoeVariant hoeVariant = HoePieces.SelectedVariant(__instance);
			if (hoeVariant == null || !HoeOps.LevelsGround(hoeVariant.Spec.Op))
			{
				return;
			}
			GameObject val = Ghost.Invoke(__instance);
			if ((Object)(object)val == (Object)null || !val.activeSelf)
			{
				return;
			}
			if (ToolState.Hoe.HeightLocked)
			{
				Transform transform = val.transform;
				Vector3 position = transform.position;
				if (position.y != ToolState.Hoe.LockedHeight)
				{
					position.y = ToolState.Hoe.LockedHeight;
					transform.position = position;
				}
			}
			if (!flashGuardStone)
			{
				HoeFillCost.Update(__instance, hoeVariant, val.transform.position, force: false);
			}
		}
	}
	[HarmonyPatch(typeof(Player), "TryPlacePiece")]
	internal static class HoeFillPlacePatch
	{
		private static readonly FieldRef<Player, GameObject> Ghost = AccessTools.FieldRefAccess<Player, GameObject>("m_placementGhost");

		private static bool Prefix(Player __instance, Piece piece, ref bool __result)
		{
			//IL_0063: 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)
			if ((Object)(object)piece == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			if (!HoePieces.TryGetVariant(((Component)piece).gameObject, out var variant) || !HoeOps.LevelsGround(variant.Spec.Op))
			{
				return true;
			}
			GameObject val = Ghost.Invoke(__instance);
			if ((Object)(object)val == (Object)null || !val.activeSelf)
			{
				return true;
			}
			HoeFillCost.Update(__instance, variant, val.transform.position, force: true);
			if (__instance.PlacementCostDisabled || (Object)(object)ZoneSystem.instance == (Object)null || ZoneSystem.instance.GetGlobalKey(piece.FreeBuildKey()) || __instance.HaveRequirements(piece, (RequirementMode)0))
			{
				return true;
			}
			((Character)__instance).Message((MessageType)2, "$msg_missingrequirement", 0, (Sprite)null, false);
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(Player), "PlacePiece")]
	internal static class LockHeightOnPlacePatch
	{
		private static void Postfix(Player __instance, Piece piece, Vector3 pos)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: 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)
			if (!((Object)(object)piece == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !ToolState.Hoe.HeightLocked && HoePieces.TryGetVariant(((Component)piece).gameObject, out var variant) && HoeOps.LevelsGround(variant.Spec.Op))
			{
				ToolState.Hoe.LockHeight(pos.y);
				HoeControl.Say("Мотыга: высота зафиксирована (" + ToolTexts.Meters(Mathf.Round(pos.y * 10f) / 10f) + "), " + ((object)ToolConfig.ResetKey.Value/*cast due to .constrained prefix*/).ToString() + " — сброс");
			}
		}
	}
	[HarmonyPatch(typeof(Player), "GetBuildStamina")]
	internal static class HoeStaminaPatch
	{
		private static void Postfix(Player __instance, ref float __result)
		{
			HoeVariant hoeVariant = HoePieces.SelectedVariant(__instance);
			if (hoeVariant != null)
			{
				__result *= HoeCost.StaminaFactor(HoePieces.StaminaFactors, HoeOps.StaminaIndex(hoeVariant.Spec, HoePieces.Lists));
			}
		}
	}
	internal sealed class HoeVariant
	{
		internal HoeOpSpec Spec;

		internal GameObject Prefab;

		internal TerrainOp Op;

		internal Piece Piece;

		internal float SoftInner;

		internal bool Levels;

		internal float LevelInner;

		internal float LevelOuter;

		internal int BaseStones;
	}
	internal static class HoePieces
	{
		private const string TableName = "_SansaraHoePieceTable";

		private static readonly Dictionary<string, HoeVariant> ByName = new Dictionary<string, HoeVariant>();

		private static readonly Dictionary<GameObject, HoeVariant> ByPrefab = new Dictionary<GameObject, HoeVariant>();

		private static readonly Dictionary<Settings, HoeVariant> BySettings = new Dictionary<Settings, HoeVariant>();

		private static readonly Dictionary<HoeOp, GameObject> Bases = new Dictionary<HoeOp, GameObject>();

		private static readonly HashSet<string> VisualLogged = new HashSet<string>();

		private static GameObject _holder;

		private static PieceTable _table;

		private static PieceTable _vanillaTable;

		private static ItemDrop _stone;

		private static bool _initDone;

		private static bool _initFailed;

		private static HoeLists _lists = HoeLists.Default;

		private static float[] _stamina = (float[])HoeSizes.Stamina.Fallback.Clone();

		private static readonly MethodInfo UpdateAvailable = AccessTools.Method(typeof(Player), "UpdateAvailablePiecesList", (Type[])null, (Type[])null);

		private static readonly MethodInfo SetPlaceMode = AccessTools.Method(typeof(Player), "SetPlaceMode", new Type[1] { typeof(PieceTable) }, (Type[])null);

		internal static PieceTable Table => _table;

		internal static HoeLists Lists => _lists;

		internal static float[] StaminaFactors => _stamina;

		internal static bool TryGetVariant(GameObject prefab, out HoeVariant variant)
		{
			variant = null;
			if ((Object)(object)prefab != (Object)null)
			{
				return ByPrefab.TryGetValue(prefab, out variant);
			}
			return false;
		}

		internal static bool TryGetSoft(Settings settings, out float inner)
		{
			if (settings != null && BySettings.TryGetValue(settings, out var value) && value.SoftInner > 0f)
			{
				inner = value.SoftInner;
				return true;
			}
			inner = 0f;
			return false;
		}

		internal static HoeVariant SelectedVariant(Player player)
		{
			if ((Object)(object)player == (Object)null || (Object)(object)_table == (Object)null || (Object)(object)player.GetBuildTool() != (Object)(object)_table)
			{
				return null;
			}
			Piece selectedPiece = player.GetSelectedPiece();
			if (!((Object)(object)selectedPiece != (Object)null) || !ByPrefab.TryGetValue(((Component)selectedPiece).gameObject, out var value))
			{
				return null;
			}
			return value;
		}

		private static bool Init()
		{
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Expected O, but got Unknown
			if (_initDone || _initFailed)
			{
				return _initDone;
			}
			ItemDrop prefab = Cache.GetPrefab<ItemDrop>("Hoe");
			_vanillaTable = (((Object)(object)prefab != (Object)null) ? prefab.m_itemData.m_shared.m_buildPieces : null);
			_stone = Cache.GetPrefab<ItemDrop>("Stone");
			if ((Object)(object)_vanillaTable == (Object)null || (Object)(object)_stone == (Object)null)
			{
				_initFailed = true;
				Plugin.Log.LogError((object)"Sansara Tools: мотыга — не найдены ванильная таблица Hoe или предмет Stone, операции не созданы.");
				return false;
			}
			FindBase(HoeOp.Level, "mud_road_v2");
			FindBase(HoeOp.Raise, "raise_v2");
			FindBase(HoeOp.Path, "path_v2");
			FindBase(HoeOp.Pave, "paved_road_v2");
			FindBase(HoeOp.PaveCover, "paved_road_v2");
			if (Bases.Count != HoeOps.MenuOrder.Length)
			{
				_initFailed = true;
				Plugin.Log.LogError((object)"Sansara Tools: мотыга — нет ванильных деталей mud_road_v2 / raise_v2 / path_v2 / paved_road_v2, операции не созданы.");
				return false;
			}
			_holder = new GameObject("SansaraToolsHoePrefabs");
			_holder.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)_holder);
			GameObject obj = Object.Instantiate<GameObject>(((Component)_vanillaTable).gameObject, _holder.transform, false);
			((Object)obj).name = "_SansaraHoePieceTable";
			_table = obj.GetComponent<PieceTable>();
			_table.m_pieces = new List<GameObject>();
			ItemManager.OnItemsRegistered += RegisterInObjectDB;
			ItemManager.OnItemsRegisteredFejd += RegisterInObjectDB;
			_initDone = true;
			return true;
		}

		private static void FindBase(HoeOp op, string name)
		{
			foreach (GameObject piece in _vanillaTable.m_pieces)
			{
				if ((Object)(object)piece != (Object)null && ((Object)piece).name == name && (Object)(object)piece.GetComponent<TerrainOp>() != (Object)null && (Object)(object)piece.GetComponent<Piece>() != (Object)null)
				{
					Bases[op] = piece;
					return;
				}
			}
			GameObject prefab = Cache.GetPrefab<GameObject>(name);
			if ((Object)(object)prefab != (Object)null && (Object)(object)prefab.GetComponent<TerrainOp>() != (Object)null && (Object)(object)prefab.GetComponent<Piece>() != (Object)null)
			{
				Bases[op] = prefab;
			}
		}

		internal static void Apply(ItemDrop hoe)
		{
			if ((Object)(object)hoe == (Object)null || !Init())
			{
				return;
			}
			_lists = new HoeLists(ToolConfig.Sizes(SizeSlot.LevelRadius), ToolConfig.Sizes(SizeSlot.RaiseRadius), ToolConfig.Sizes(SizeSlot.RaiseStep), ToolConfig.Sizes(SizeSlot.PathWidth), ToolConfig.Sizes(SizeSlot.PaveWidth));
			_stamina = ToolConfig.Stamina();
			int num = 0;
			List<HoeOpSpec> list = HoeOps.Combinations(_lists);
			foreach (HoeOpSpec item in list)
			{
				if (!ByName.TryGetValue(item.Name, out var value))
				{
					value = Create(item);
					if (value == null)
					{
						continue;
					}
					num++;
				}
				UpdatePiece(value);
			}
			if ((Object)(object)ObjectDB.instance != (Object)null)
			{
				RegisterIn(ObjectDB.instance);
			}
			bool flag = RefreshTable();
			PieceTable val = (ToolConfig.Enabled.Value ? _table : _vanillaTable);
			bool flag2 = (Object)(object)hoe.m_itemData.m_shared.m_buildPieces != (Object)(object)val;
			hoe.m_itemData.m_shared.m_buildPieces = val;
			if (num > 0 || flag2)
			{
				Plugin.Log.LogInfo((object)($"Sansara Tools: мотыга — сочетаний {list.Count}, новых префабов {num}, всего {ByName.Count}; " + (((Object)(object)val == (Object)(object)_table) ? "таблица мотыги Ивальди." : "Enabled=false — у мотыги ванильная таблица.")));
			}
			RefreshPlayer(flag2 || flag);
		}

		private static HoeVariant Create(HoeOpSpec spec)
		{
			if (!Bases.TryGetValue(spec.Op, out var value))
			{
				return null;
			}
			GameObject val = Object.Instantiate<GameObject>(value, _holder.transform, false);
			((Object)val).name = spec.Name;
			HoeVariant hoeVariant = new HoeVariant
			{
				Spec = spec,
				Prefab = val,
				Op = val.GetComponent<TerrainOp>(),
				Piece = val.GetComponent<Piece>()
			};
			HoeTerrainSettings hoeTerrainSettings = HoeOps.Settings(spec);
			WriteSettings(hoeVariant.Op.m_settings, hoeTerrainSettings);
			hoeVariant.SoftInner = hoeTerrainSettings.SoftInner;
			hoeVariant.Levels = HoeOps.LevelShape(spec, out hoeVariant.LevelInner, out hoeVariant.LevelOuter);
			hoeVariant.Op.m_spawnOnPlaced = null;
			hoeVariant.Piece.m_enabled = true;
			hoeVariant.Piece.m_canRotate = false;
			hoeVariant.Piece.m_craftingStation = null;
			float radius = value.GetComponent<TerrainOp>().GetRadius();
			ScaleVisual(val, ((Object)value).name, (radius > 0f) ? (hoeTerrainSettings.Radius / radius) : 1f);
			ByName[spec.Name] = hoeVariant;
			ByPrefab[val] = hoeVariant;
			BySettings[hoeVariant.Op.m_settings] = hoeVariant;
			return hoeVariant;
		}

		private static void WriteSettings(Settings t, HoeTerrainSettings s)
		{
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			t.m_levelOffset = s.LevelOffset;
			t.m_level = s.Level;
			t.m_levelRadius = s.LevelRadius;
			t.m_square = s.Square;
			t.m_raise = s.Raise;
			t.m_raiseRadius = s.RaiseRadius;
			t.m_raisePower = s.RaisePower;
			t.m_raiseDelta = s.RaiseDelta;
			t.m_smooth = s.Smooth;
			t.m_smoothRadius = s.SmoothRadius;
			t.m_smoothPower = s.SmoothPower;
			t.m_paintCleared = s.PaintCleared;
			t.m_paintHeightCheck = false;
			t.m_paintType = (PaintType)((s.PaintType == HoePaint.Paved) ? 2 : 0);
			t.m_paintRadius = s.PaintRadius;
			t.m_paintStrength = s.PaintStrength;
			t.m_paintExp = s.PaintExp;
			t.m_halfOffset = s.HalfOffset;
			t.m_rotation = false;
		}

		private static void UpdatePiece(HoeVariant v)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: 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)
			Piece piece = v.Piece;
			piece.m_name = HoeOps.MenuName(v.Spec.Op);
			piece.m_description = HoeOps.Description(v.Spec, KeyName(ToolConfig.SizeModifier.Value), KeyName(ToolConfig.ModeKey.Value), KeyName(ToolConfig.ResetKey.Value));
			v.BaseStones = HoeOps.Stones(v.Spec, ToolConfig.RaiseStoneBase.Value, ToolConfig.PaveStoneBase.Value);
			SetStones(v, v.BaseStones);
		}

		internal static void SetStones(HoeVariant v, int stones)
		{
			//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_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			Piece piece = v.Piece;
			Requirement[] resources = piece.m_resources;
			bool num;
			if (stones != 0)
			{
				if (resources == null || resources.Length != 1 || !((Object)(object)resources[0].m_resItem == (Object)(object)_stone))
				{
					goto IL_004b;
				}
				num = resources[0].m_amount == stones;
			}
			else
			{
				if (resources == null)
				{
					return;
				}
				num = resources.Length == 0;
			}
			if (num)
			{
				return;
			}
			goto IL_004b;
			IL_004b:
			piece.m_resources = (Requirement[])(object)((stones == 0) ? new Requirement[0] : new Requirement[1]
			{
				new Requirement
				{
					m_resItem = _stone,
					m_amount = stones,
					m_recover = false
				}
			});
		}

		private unsafe static string KeyName(KeyCode key)
		{
			return ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString();
		}

		internal static bool RefreshTable()
		{
			if ((Object)(object)_table == (Object)null)
			{
				return false;
			}
			bool sharpEdge = ToolState.SharpEdge;
			List<GameObject> pieces = _table.m_pieces;
			bool flag = pieces.Count != HoeOps.MenuOrder.Length;
			if (flag)
			{
				pieces.Clear();
				for (int i = 0; i < HoeOps.MenuOrder.Length; i++)
				{
					pieces.Add(null);
				}
			}
			for (int j = 0; j < HoeOps.MenuOrder.Length; j++)
			{
				HoeOpSpec hoeOpSpec = HoeOps.Select(HoeOps.MenuOrder[j], _lists, ToolState.Hoe.Sizes, sharpEdge);
				if (ByName.TryGetValue(hoeOpSpec.Name, out var value) && (Object)(object)pieces[j] != (Object)(object)value.Prefab)
				{
					pieces[j] = value.Prefab;
					flag = true;
				}
			}
			if (pieces.Contains(null))
			{
				pieces.RemoveAll((GameObject p) => (Object)(object)p == (Object)null);
			}
			return flag;
		}

		internal static void OnSelectionChanged()
		{
			if (RefreshTable())
			{
				RefreshPlayer(changed: true);
			}
		}

		private static void RefreshPlayer(bool changed)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!changed || (Object)(object)localPlayer == (Object)null || (Object)(object)_table == (Object)null)
			{
				return;
			}
			ItemData rightItem = ((Humanoid)localPlayer).RightItem;
			if (ToolItems.KindOf(rightItem) == ToolKind.Hoe)
			{
				PieceTable buildPieces = rightItem.m_shared.m_buildPieces;
				if ((Object)(object)localPlayer.GetBuildTool() != (Object)(object)buildPieces)
				{
					SetPlaceMode?.Invoke(localPlayer, new object[1] { buildPieces });
				}
				else if ((Object)(object)buildPieces == (Object)(object)_table)
				{
					UpdateAvailable?.Invoke(localPlayer, null);
				}
			}
		}

		private static void RegisterInObjectDB()
		{
			if ((Object)(object)ObjectDB.instance != (Object)null)
			{
				RegisterIn(ObjectDB.instance);
			}
		}

		private static void RegisterIn(ObjectDB db)
		{
			foreach (HoeVariant value in ByName.Values)
			{
				if (!db.m_terrainOps.Contains(value.Op))
				{
					db.m_terrainOps.Add(value.Op);
				}
				db.m_terrainOpsByHash[StringExtensionMethods.GetStableHashCode(value.Spec.Name)] = value.Op;
			}
		}

		private static void ScaleVisual(GameObject prefab, string baseName, float factor)
		{
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: 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_0109: 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)
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			if (Mathf.Abs(factor - 1f) > 0.001f)
			{
				CircleProjector[] componentsInChildren = prefab.GetComponentsInChildren<CircleProjector>(true);
				foreach (CircleProjector val in componentsInChildren)
				{
					val.m_radius *= factor;
					val.m_nrOfSegments = Mathf.Max(val.m_nrOfSegments, Mathf.CeilToInt((float)val.m_nrOfSegments * factor));
					num++;
				}
				Projector[] componentsInChildren2 = prefab.GetComponentsInChildren<Projector>(true);
				foreach (Projector obj in componentsInChildren2)
				{
					obj.orthographicSize *= factor;
					num2++;
				}
				HashSet<Transform> hashSet = new HashSet<Transform>();
				MeshRenderer[] componentsInChildren3 = prefab.GetComponentsInChildren<MeshRenderer>(true);
				for (int i = 0; i < componentsInChildren3.Length; i++)
				{
					Transform transform = ((Component)componentsInChildren3[i]).transform;
					if (!((Object)(object)transform == (Object)(object)prefab.transform) && !((Object)(object)((Component)transform).GetComponentInParent<CircleProjector>() != (Object)null) && hashSet.Add(transform))
					{
						Vector3 localScale = transform.localScale;
						transform.localScale = new Vector3(localScale.x * factor, localScale.y, localScale.z * factor);
						num3++;
					}
				}
			}
			if (VisualLogged.Add(baseName))
			{
				Plugin.Log.LogInfo((object)$"Sansara Tools: призрак на основе {baseName} — CircleProjector {num}, Projector {num2}, сеток {num3} (масштаб {factor:0.##}).");
			}
		}
	}
	[HarmonyPatch(typeof(ZInput), "GetMouseScrollWheel")]
	internal static class WheelPatch
	{
		private static void Postfix(ref float __result)
		{
			if (__result == 0f)
			{
				return;
			}
			try
			{
				if (ToolInput.ShouldSwallowWheel())
				{
					__result = 0f;
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Sansara Tools: патч колеса: " + ex.Message));
			}
		}
	}
	internal static class PickaxeItem
	{
		internal const string DisplayName = "Кирка Синдри";

		internal const string Description = "Кирка, которая берёт жилу целиком: один удар скалывает всё вокруг точки попадания, тяжёлый удар — ещё шире. Добычи с жилы столько же, сколько у обычной кирки.";

		internal static void Apply(ItemDrop drop)
		{
			if (!((Object)(object)drop == (Object)null))
			{
				SharedData shared = drop.m_itemData.m_shared;
				shared.m_maxDurability = ToolConfig.Durability.Value;
				shared.m_damages.m_pickaxe = ToolConfig.PickaxeDamage.Value;
				ApplyHeavy(shared);
				PickaxeDig.Apply(drop);
			}
		}

		private static void ApplyHeavy(SharedData shared)
		{
			Attack attack = shared.m_attack;
			if (attack != null)
			{
				Attack val = attack.Clone();
				string text = ((ToolConfig.HeavyAnimation.Value != null) ? ToolConfig.HeavyAnimation.Value.Trim() : "");
				val.m_attackAnimation = (ToolConfig.Enabled.Value ? text : "");
				val.m_attackStamina = HeavyStrike.Stamina(attack.m_attackStamina, ToolConfig.HeavyCostFactor.Value);
				shared.m_secondaryAttack = val;
			}
		}
	}
	internal static class PickaxeArea
	{
		internal static bool Applies(HitData hit)
		{
			if (ToolSwing.Fresh(ToolKind.Pickaxe, hit))
			{
				return hit.m_radius <= 0f;
			}
			return false;
		}

		internal static float Radius()
		{
			return HeavyStrike.Radius(ToolSwing.Heavy, ToolConfig.AreaRadius.Value, ToolConfig.HeavyRadius.Value);
		}

		internal static void ScaleHeavy(HitData hit)
		{
			float num = HeavyStrike.RockDamageFactor(ToolSwing.Heavy, ToolConfig.HeavyDamageFactor.Value);
			if (num != 1f)
			{
				((DamageTypes)(ref hit.m_damage)).Modify(num);
			}
		}
	}
	[HarmonyPatch(typeof(MineRock5), "Damage")]
	internal static class PickaxeMineRock5Patch
	{
		private static void Prefix(HitData hit)
		{
			if (PickaxeArea.Applies(hit))
			{
				PickaxeArea.ScaleHeavy(hit);
				hit.m_radius = PickaxeArea.Radius();
			}
		}
	}
	[HarmonyPatch(typeof(Destructible), "Damage")]
	internal static class PickaxeDestructiblePatch
	{
		private static void Prefix(HitData hit)
		{
			if (PickaxeArea.Applies(hit))
			{
				PickaxeArea.ScaleHeavy(hit);
				hit.m_radius = PickaxeArea.Radius();
			}
		}
	}
	[HarmonyPatch(typeof(MineRock), "Damage")]
	internal static class PickaxeMineRockPatch
	{
		private static readonly FieldRef<MineRock, Collider[]> AreasRef = AccessTools.FieldRefAccess<MineRock, Collider[]>("m_hitAreas");

		private static readonly FieldRef<MineRock, ZNetView> NViewRef = AccessTools.FieldRefAccess<MineRock, ZNetView>("m_nview");

		private static readonly List<P3> Points = new List<P3>();

		private static readonly List<int> Index = new List<int>();

		private static readonly List<int> Picked = new List<int>();

		private static bool Prefix(MineRock __instance, HitData hit)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: 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_008a: 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)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: 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)
			if (!PickaxeArea.Applies(hit))
			{
				return true;
			}
			Collider[] array = AreasRef.Invoke(__instance);
			ZNetView val = NViewRef.Invoke(__instance);
			if (array == null || (Object)(object)val == (Object)null || !val.IsValid())
			{
				return true;
			}
			float radius = PickaxeArea.Radius();
			Vector3 point = hit.m_point;
			Points.Clear();
			Index.Clear();
			for (int i = 0; i < array.Length; i++)
			{
				Collider val2 = array[i];
				if (!((Object)(object)val2 == (Object)null) && val2.enabled && ((Component)val2).gameObject.activeInHierarchy)
				{
					Vector3 val3 = ToolSwing.ClosestPoint(val2, point);
					Points.Add(new P3(val3.x, val3.y, val3.z));
					Index.Add(i);
				}
			}
			AreaSelect.Pick(Points, new P3(point.x, point.y, point.z), radius, Picked);
			if (Picked.Count == 0)
			{
				return true;
			}
			PickaxeArea.ScaleHeavy(hit);
			hit.m_radius = radius;
			foreach (int item in Picked)
			{
				val.InvokeRPC("Hit", new object[2]
				{
					hit,
					Index[item]
				});
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Attack), "SpawnOnHitTerrain")]
	internal static class PickaxeTerrainPatch
	{
		private static bool Prefix(ref GameObject prefab, ref GameObject __result)
		{
			if (!ToolSwing.Active || ToolSwing.Kind != ToolKind.Pickaxe)
			{
				return true;
			}
			switch (PickaxeTerrain.For(ToolState.PickaxeModeNow, ToolConfig.WideDigRadius.Value))
			{
			case TerrainAction.None:
				__result = null;
				return false;
			case TerrainAction.Wide:
			{
				GameObject val = PickaxeDig.Current();
				if ((Object)(object)val != (Object)null)
				{
					prefab = val;
				}
				return true;
			}
			default:
				return true;
			}
		}
	}
	internal static class PickaxeDig
	{
		private static readonly Dictionary<string, TerrainOp> ByName = new Dictionary<string, TerrainOp>();

		private static GameObject _holder;

		private static GameObject _base;

		private static bool _hooked;

		private static bool _failLogged;

		private static TerrainOp _current;

		internal static GameObject Current()
		{
			if (!((Object)(object)_current != (Object)null))
			{
				return null;
			}
			return ((Component)_current).gameObject;
		}

		internal static void Apply(ItemDrop pickaxe)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			_current = null;
			if ((Object)(object)pickaxe == (Object)null || ToolConfig.WideDigRadius.Value < 0.5f)
			{
				return;
			}
			if ((Object)(object)_base == (Object)null)
			{
				GameObject spawnOnHitTerrain = pickaxe.m_itemData.m_shared.m_spawnOnHitTerrain;
				if ((Object)(object)spawnOnHitTerrain == (Object)null || (Object)(object)spawnOnHitTerrain.GetComponent<TerrainOp>() == (Object)null)
				{
					if (!_failLogged)
					{
						_failLogged = true;
						Plugin.Log.LogError((object)"Sansara Tools: у кирки нет операции копки с TerrainOp в корне — «широкая копка» недоступна.");
					}
					return;
				}
				_base = spawnOnHitTerrain;
				_holder = new GameObject("SansaraToolsPickaxeDig");
				_holder.SetActive(false);
				Object.DontDestroyOnLoad((Object)(object)_holder);
			}
			string text = PickaxeTerrain.DigName(ToolConfig.WideDigRadius.Value);
			if (!ByName.TryGetValue(text, out var value))
			{
				PickaxeTerrain.TryParseDig(text, out var radius);
				GameObject obj = Object.Instantiate<GameObject>(_base, _holder.transform, false);
				((Object)obj).name = text;
				value = obj.GetComponent<TerrainOp>();
				Settings settings = value.m_settings;
				settings.m_raise = true;
				settings.m_raiseRadius = radius;
				settings.m_paintRadius = PickaxeTerrain.PaintRadius(radius);
				ByName[text] = value;
				Plugin.Log.LogInfo((object)("Sansara Tools: «широкая копка» — операция " + text + " (основа " + ((Object)_base).name + ")."));
			}
			_current = value;
			if (!_hooked)
			{
				_hooked = true;
				ItemManager.OnItemsRegistered += RegisterInObjectDB;
				ItemManager.OnItemsRegisteredFejd += RegisterInObjectDB;
			}
			RegisterInObjectDB();
		}

		private static void RegisterInObjectDB()
		{
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			foreach (KeyValuePair<string, TerrainOp> item in ByName)
			{
				if (!instance.m_terrainOps.Contains(item.Value))
				{
					instance.m_terrainOps.Add(item.Value);
				}
				instance.m_terrainOpsByHash[StringExtensionMethods.GetStableHashCode(item.Key)] = item.Value;
			}
		}
	}
	[HarmonyPatch(typeof(VisEquipment), "SetRightHandEquipped")]
	internal static class PickaxeLightPatch
	{
		private static readonly FieldRef<VisEquipment, GameObject> RightRef = AccessTools.FieldRefAccess<VisEquipment, GameObject>("m_rightItemInstance");

		private static readonly int PickaxeHash = StringExtensionMethods.GetStableHashCode("SansaraPickaxe");

		private const string LightName = "SansaraPickaxeLight";

		private static void Postfix(VisEquipment __instance, int hash, bool __result)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: 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_00b8: Unknown result type (might be due to invalid IL or missing references)
			if (__result && hash == PickaxeHash && !Application.isBatchMode && ToolConfig.Light != null && ToolConfig.Light.Value && ToolConfig.Enabled.Value)
			{
				GameObject val = RightRef.Invoke(__instance);
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val.transform.Find("SansaraPickaxeLight") != (Object)null))
				{
					GameObject val2 = new GameObject("SansaraPickaxeLight");
					val2.transform.SetParent(val.transform, false);
					val2.transform.localPosition = new Vector3(0f, 0.3f, 0f);
					Light obj = val2.AddComponent<Light>();
					obj.type = (LightType)2;
					obj.color = new Color(1f, 0.78f, 0.52f);
					obj.range = 5f;
					obj.intensity = 0.9f;
					obj.shadows = (LightShadows)0;
				}
			}
		}
	}
	[BepInPlugin("sansara.Tools", "Sansara Tools", "0.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Guid = "sansara.Tools";

		public const string Name = "Sansara Tools";

		public const string Version = "0.1.0";

		internal static ManualLogSource Log;

		internal static Plugin Instance;

		private void Awake()
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			ToolConfig.Bind(((BaseUnityPlugin)this).Config);
			ToolItems.Register();
			((BaseUnityPlugin)this).Config.SettingChanged += delegate
			{
				ToolItems.MarkDirty();
			};
			SynchronizationManager.OnConfigurationSynchronized += delegate
			{
				ToolItems.MarkDirty();
			};
			int num = PatchEach(new Harmony("sansara.Tools"));
			Log.LogInfo((object)string.Format("{0} {1} загружен ({2}, патчей {3}).", "Sansara Tools", "0.1.0", Application.isBatchMode ? "сервер: клавиши не подключаются" : "клиент", num));
		}

		private static int PatchEach(Harmony harmony)
		{
			int num = 0;
			Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(typeof(Plugin).Assembly);
			foreach (Type type in typesFromAssembly)
			{
				if (type.GetCustomAttributes(typeof(HarmonyPatch), inherit: false).Length != 0)
				{
					try
					{
						harmony.CreateClassProcessor(type).Patch();
						num++;
					}
					catch (Exception arg)
					{
						Log.LogError((object)$"Sansara Tools: патч {type.Name} не применён: {arg}");
					}
				}
			}
			return num;
		}

		private void Update()
		{
			try
			{
				ToolItems.ApplyIfDirty();
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Sansara Tools: применение настроек: " + ex));
			}
			if (Application.isBatchMode)
			{
				return;
			}
			try
			{
				HoeControl.Tick();
				ToolInput.Tick();
				ToolPickup.Tick();
				AxeFlagsSync.Tick();
			}
			catch (Exception ex2)
			{
				Log.LogError((object)("Sansara Tools: ввод: " + ex2));
			}
		}
	}
	internal static class ToolConfig
	{
		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<int> Durability;

		internal static ConfigEntry<string> LevelRadii;

		internal static ConfigEntry<string> RaiseRadii;

		internal static ConfigEntry<string> RaiseSteps;

		internal static ConfigEntry<string> PathWidths;

		internal static ConfigEntry<string> PaveWidths;

		internal static ConfigEntry<int> RaiseStoneBase;

		internal static ConfigEntry<int> PaveStoneBase;

		internal static ConfigEntry<string> StaminaFactors;

		internal static ConfigEntry<float> PickaxeDamage;

		internal static ConfigEntry<float> AreaRadius;

		internal static ConfigEntry<float> HeavyRadius;

		internal static ConfigEntry<float> HeavyDamageFactor;

		internal static ConfigEntry<float> HeavyCostFactor;

		internal static ConfigEntry<string> HeavyAnimation;

		internal static ConfigEntry<float> WideDigRadius;

		internal static ConfigEntry<bool> Light;

		internal static ConfigEntry<float> PickaxePickupRange;

		internal static ConfigEntry<float> ChopDamage;

		internal static ConfigEntry<float> LogAreaRadius;

		internal static ConfigEntry<bool> DirectedFall;

		internal static ConfigEntry<bool> NoSelfLogDamage;

		internal static ConfigEntry<float> NoSelfLogSeconds;

		internal static ConfigEntry<float> NoSelfLogRadius;

		internal static ConfigEntry<bool> Uproot;

		internal static ConfigEntry<bool> Careful;

		internal static ConfigEntry<bool> Forester;

		internal static ConfigEntry<string> ForesterTrees;

		internal static ConfigEntry<float> AxePickupRange;

		internal static ConfigEntry<KeyCode> SizeModifier;

		internal static ConfigEntry<KeyCode> ModeKey;

		internal static ConfigEntry<KeyCode> ResetKey;

		private static readonly Dictionary<string, string> Warned = new Dictionary<string, string>();

		private static string _forestryText;

		private static ForestryTable _forestry = ForestryTable.Empty;

		private static ConfigEntry<T> Server<T>(ConfigFile cfg, string section, string key, T value, string description, AcceptableValueBase range = null)
		{
			//IL_0010: 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_001d: Expected O, but got Unknown
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			return cfg.Bind<T>(section, key, value, new ConfigDescription(description, range, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
		}

		private static AcceptableValueRange<T> Range<T>(T min, T max) where T : IComparable
		{
			return new AcceptableValueRange<T>(min, max);
		}

		internal static void Bind(ConfigFile cfg)
		{
			Enabled = Server(cfg, "General", "Enabled", value: true, "false — режимы и операции инструментов отключены (горячие клавиши молчат). Предметы регистрируются всегда: иначе игра удалила бы уже выданные. Баланс: выключатель на случай перекоса экономики, предметы остаются в инвентарях обычными инструментами-основами.");
			Durability = Server(cfg, "General", "Durability", 800, "Прочность всех трёх инструментов (максимум, m_maxDurability). Больше — реже ремонт. У уже выданных предметов текущая прочность не меняется, меняется предел; ремонт — в чёрной кузне (рецепт-заглушка без изготовления).", (AcceptableValueBase)(object)Range(50, 10000));
			LevelRadii = Server(cfg, "Hoe", "LevelRadii", HoeSizes.Level.Text, "Радиусы выравнивания, м, через запятую (1–8, до 6 значений; мусор отбрасывается). Колесо мыши с модификатором листает размеры. Срезать землю — бесплатно; подсыпать — камень по объёму насыпи по ставке RaiseStoneBase (насыпь меньше четверти эталона — бесплатно). Баланс: чем больше радиус, тем быстрее стройка; цена — выносливость (StaminaFactors) и камень за насыпь.");
			RaiseRadii = Server(cfg, "Hoe", "RaiseRadii", HoeSizes.RaiseRadius.Text, "Радиусы поднятия земли, м, через запятую (1–4). Баланс: цена в камне растёт с квадратом радиуса.");
			RaiseSteps = Server(cfg, "Hoe", "RaiseSteps", HoeSizes.RaiseStep.Text, "Высота шага поднятия, м, через запятую (0,25–2; десятичная точка). Баланс: цена в камне растёт пропорционально шагу.");
			PathWidths = Server(cfg, "Hoe", "PathWidths", HoeSizes.PathWidth.Text, "Ширина тропинки, м, через запятую (0,5–6). Высота не меняется. Бесплатно.");
			PaveWidths = Server(cfg, "Hoe", "PaveWidths", HoeSizes.PaveWidth.Text, "Ширина мощения, м, через запятую (1–8). Баланс: цена в камне растёт втрое при удвоении ширины.");
			RaiseStoneBase = Server(cfg, "Hoe", "RaiseStoneBase", 2, "Камней за шаг 0,5 м на радиусе 2 м; прочие размеры — пропорционально объёму: base × (r/2)² × (шаг/0,5), вверх. По той же ставке платится насыпь «Выровнять» и «Мощения»: ceil(base × V / 6,28 м³), V — поднимаемый объём. 0 — поднятие и насыпь бесплатны. Баланс: главный тормоз земляных валов (камень — ограниченный ресурс).", (AcceptableValueBase)(object)Range(0, 20));
			PaveStoneBase = Server(cfg, "Hoe", "PaveStoneBase", 1, "Камней за мощение шириной 2 м; на 4 м втрое больше (степень log2(3)); насыпь — сверх этого по RaiseStoneBase. 0 — мостовая без базовой цены.", (AcceptableValueBase)(object)Range(0, 20));
			StaminaFactors = Server(cfg, "Hoe", "StaminaFactors", HoeSizes.Stamina.Text, "Множители выносливости по номеру размера (малый, средний, большой) на каждый удар: 1 — как у ванильной мотыги. Короче списка размеров — последнее значение; 0,1–10.");
			PickaxeDamage = Server(cfg, "Pickaxe", "PickaxeDamage", 65f, "Урон киркой (m_pickaxe) по жилам и камню; у основы из чёрного металла — 65. Уровень инструмента и урон оружием не меняются. Баланс: добыча с жилы зависит от числа кусков, а не от урона; больше урон — быстрее добыча.", (AcceptableValueBase)(object)Range(1f, 500f));
			AreaRadius = Server(cfg, "Pickaxe", "AreaRadius", 1.5f, "Радиус скола по площади, м: удар ломает все куски жилы в этом радиусе от точки попадания. Количество добычи не растёт, растёт скорость.", (AcceptableValueBase)(object)Range(0.5f, 5f));
			HeavyRadius = Server(cfg, "Pickaxe", "HeavyRadius", 3f, "Радиус тяжёлого удара (вторичная атака), м.", (AcceptableValueBase)(object)Range(1f, 8f));
			HeavyDamageFactor = Server(cfg, "Pickaxe", "HeavyDamageFactor", 1.5f, "Множитель урона тяжёлого удара.", (AcceptableValueBase)(object)Range(0.5f, 5f));
			HeavyCostFactor = Server(cfg, "Pickaxe", "HeavyCostFactor", 3f, "Множитель выносливости и износа тяжёлого удара. Баланс: быстрее добыча, но тяжёлым ударом не выгоднее расходуется прочность.", (AcceptableValueBase)(object)Range(1f, 10f));
			HeavyAnimation = Server(cfg, "Pickaxe", "HeavyAnimation", "swing_pickaxe", "Триггер анимации тяжёлого удара (вторичная атака). У ванильных кирок вторичной атаки нет; по умолчанию — тот же замах, что у обычного удара (swing_pickaxe), он точно есть в аниматоре игрока для кирки. Пусто — тяжёлого удара нет. Другие имена (например, sledge_attack, axe_secondary) не проверялись в игре.");
			WideDigRadius = Server(cfg, "Pickaxe", "WideDigRadius", 3f, "Радиус ямы в режиме «широкая копка», м. 0 — режим выключен.", (AcceptableValueBase)(object)Range(0f, 6f));
			Light = Server(cfg, "Pickaxe", "Light", value: true, "Кирка светит, пока в руке (как факел).");
			PickaxePickupRange = Server(cfg, "Pickaxe", "PickupRange", 6f, "С какого расстояния кирка подбирает добычу, м (0 — как у ванильной, стандартный подбор). Не увеличивает добычу.", (AcceptableValueBase)(object)Range(0f, 20f));
			ChopDamage = Server(cfg, "Axe", "ChopDamage", 95f, "Урон рубкой (m_chop); у основы из чёрного металла — 95. Боевой урон и уровень не меняются.", (AcceptableValueBase)(object)Range(1f, 500f));
			LogAreaRadius = Server(cfg, "Axe", "LogAreaRadius", 2f, "Радиус разделки: удар по лежащему бревну задевает все брёвна и половинки в радиусе, м. Стоящие деревья — по одному. Древесины столько же.", (AcceptableValueBase)(object)Range(0.5f, 6f));
			DirectedFall = Server(cfg, "Axe", "DirectedFall", value: true, "Дерево падает от игрока.");
			NoSelfLogDamage = Server(cfg, "Axe", "NoSelfLogDamage", value: true, "Падающий ствол не ранит владельца топора: удар ствола (HitType.Tree) не проходит NoSelfLogSeconds секунд после его удара этим топором по дереву или бревну, если игрок не дальше NoSelfLogRadius от места этого удара. Чей ствол, игра не сообщает: в этом окне и радиусе не ранит и чужой ствол. Других игроков и существ стволы бьют как обычно.");
			NoSelfLogSeconds = Server(cfg, "Axe", "NoSelfLogSeconds", 10f, "Сколько секунд после своего удара по дереву или бревну действует защита от стволов.", (AcceptableValueBase)(object)Range(1f, 60f));
			NoSelfLogRadius = Server(cfg, "Axe", "NoSelfLogRadius", 15f, "Защита от стволов действует, только пока игрок не дальше этого расстояния (м) от точки своего последнего удара по дереву или бревну. Баланс: меньше — уже зона, в которой игрока не ранит и чужой ствол.", (AcceptableValueBase)(object)Range(3f, 50f));
			Uproot = Server(cfg, "Axe", "Uproot", value: true, "Разрешить режим корчевания: пень разрушается вместе с деревом и отдаёт свою древесину. false — режим недоступен.");
			Careful = Server(cfg, "Axe", "Careful", value: true, "Разрешить бережный режим: удары не повреждают постройки игроков и саженцы. false — режим недоступен.");
			Forester = Server(cfg, "Axe", "Forester", value: true, "«Лесник»: при наличии семени того же дерева в инвентаре на месте срубленного сажается саженец, семя тратится. Сажает только при корчевании (иначе пень не даст саженцу вырасти) и если место годится по ванильным условиям роста. Баланс: лес не вырубается насовсем, но каждый саженец стоит семени. Без таблицы ForesterTrees ничего не сажает.");
			ForesterTrees = Server(cfg, "Axe", "ForesterTrees", "Beech1=Beech_Sapling:BeechSeeds,Birch1=Birch_Sapling:BirchSeeds,Birch2=Birch_Sapling:BirchSeeds,Oak1=Oak_Sapling:Acorn,FirTree=FirTree_Sapling:FirCone,FirTree_big=FirTree_big_Sapling:FirConeFrost,Pinetree_01=PineTree_Sapling:PineCone", "Таблица «Лесника»: Дерево=Саженец:Семя через запятую (имена префабов). По умолчанию — ванильные пары l-1.0.21; деревьев без ванильного саженца (болотное, побеги Иггдрасиля, деревья Пепельных земель, снежные ели и сосны, осенние берёзы) в таблице нет. Пусто — «Лесник» ничего не сажает.");
			AxePickupRange = Server(cfg, "Axe", "PickupRange", 6f, "С какого расстояния топор подбирает добычу, м (0 — стандартный подбор). Прибавки к древесине нет.", (AcceptableValueBase)(object)Range(0f, 20f));
			SizeModifier = cfg.Bind<KeyCode>("Keys", "SizeModifier", (KeyCode)308, "Клиентская (не рассылается). Колесо мыши при зажатой клавише листает размер мотыги (и не крутит камеру и деталь). EAQS использует LeftAlt только для перетаскивания своей панели, где инструмент размер не листает.");
			ModeKey = cfg.Bind<KeyCode>("Keys", "ModeKey", (KeyCode)107, "Клиентская. Переключение режима инструмента в руке. По умолчанию K: G занята ванильным радиальным меню, H — быстрым слотом 2 (EAQS, модпак).");
			ResetKey = cfg.Bind<KeyCode>("Keys", "ResetKey", (KeyCode)108, "Клиентская. Сброс фиксации высоты мотыги.");
		}

		internal static float[] Sizes(SizeSlot slot)
		{
			return slot switch
			{
				SizeSlot.RaiseRadius => HoeSizes.RaiseRadius.Parse(RaiseRadii.Value), 
				SizeSlot.RaiseStep => HoeSizes.RaiseStep.Parse(RaiseSteps.Value), 
				SizeSlot.PathWidth => HoeSizes.PathWidth.Parse(PathWidths.Value), 
				SizeSlot.PaveWidth => HoeSizes.PaveWidth.Parse(PaveWidths.Value), 
				_ => HoeSizes.Level.Parse(LevelRadii.Value), 
			};
		}

		internal static float[] Stamina()
		{
			return HoeSizes.Stamina.Parse(StaminaFactors.Value);
		}

		internal static ForestryTable Forestry()
		{
			string value = ForesterTrees.Value;
			if (value != _forestryText)
			{
				_forestryText = value;
				_forestry = ForestryTable.Parse(value);
				if (_forestry.Errors.Count > 0)
				{
					Plugin.Log.LogWarning((object)("Sansara Tools: Axe.ForesterTrees — пропущены записи: " + string.Join("; ", _forestry.Errors.ToArray())));
				}
			}
			return _forestry;
		}

		internal static void WarnBadLists()
		{
			WarnList("Hoe.LevelRadii", LevelRadii.Value, HoeSizes.Level);
			WarnList("Hoe.RaiseRadii", RaiseRadii.Value, HoeSizes.RaiseRadius);
			WarnList("Hoe.RaiseSteps", RaiseSteps.Value, HoeSizes.RaiseStep);
			WarnList("Hoe.PathWidths", PathWidths.Value, HoeSizes.PathWidth);
			WarnList("Hoe.PaveWidths", PaveWidths.Value, HoeSizes.PaveWidth);
			WarnList("Hoe.StaminaFactors", StaminaFactors.Value, HoeSizes.Stamina);
		}

		private static void WarnList(string name, string text, SizeSpec spec)
		{
			if (!Warned.TryGetValue(name, out var value) || !(value == text))
			{
				Warned[name] = text;
				if (!SizeList.TryParse(text, spec.Fallback, spec.Min, spec.Max, out var _))
				{
					Plugin.Log.LogWarning((object)$"Sansara Tools: {name} = «{text}» — нет подходящих чисел ({spec.Min}–{spec.Max}), действует значение по умолчанию {spec.Text}.");
				}
			}
		}
	}
	internal static class ToolState
	{
		internal static readonly HoeState Hoe = new HoeState();

		internal static readonly PickaxeState Pickaxe = new PickaxeState();

		internal static readonly AxeState Axe = new AxeState();

		internal static bool SharpEdge
		{
			get
			{
				if (ToolConfig.Enabled.Value)
				{
					return Hoe.SharpEdge;
				}
				return false;
			}
		}

		internal static PickaxeMode PickaxeModeNow
		{
			get
			{
				if (!ToolConfig.Enabled.Value || (Pickaxe.Mode == PickaxeMode.WideDig && ToolConfig.WideDigRadius.Value <= 0f))
				{
					return PickaxeMode.Normal;
				}
				return Pickaxe.Mode;
			}
		}

		internal static bool UprootNow
		{
			get
			{
				if (ToolConfig.Enabled.Value && ToolConfig.Uproot.Value)
				{
					return Axe.Uproot;
				}
				return false;
			}
		}

		internal static bool CarefulNow
		{
			get
			{
				if (ToolConfig.Enabled.Value && ToolConfig.Careful.Value)
				{
					return Axe.Careful;
				}
				return false;
			}
		}
	}
	internal static class ToolInput
	{
		private static bool _reading;

		private static int _heldFrame = -1;

		private static Player _heldPlayer;

		private static ToolKind _held;

		internal static ToolKind HeldKind()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return ToolKind.None;
			}
			int frameCount = Time.frameCount;
			if (frameCount != _heldFrame || localPlayer != _heldPlayer)
			{
				_heldFrame = frameCount;
				_heldPlayer = localPlayer;
				_held = ToolItems.KindOf(((Humanoid)localPlayer).RightItem);
			}
			return _held;
		}

		private static bool GameUiOpen()
		{
			if (!Console.IsVisible() && (!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Menu.IsVisible() && !InventoryGui.IsVisible() && !Minimap.IsOpen() && !StoreGui.IsVisible())
			{
				return TextInput.IsVisible();
			}
			return true;
		}

		internal static void Tick()
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Player.m_localPlayer == (Object)null || ToolConfig.Enabled == null || !ToolConfig.Enabled.Value)
			{
				return;
			}
			ToolKind toolKind = HeldKind();
			if (toolKind == ToolKind.None || GameUiOpen())
			{
				return;
			}
			if (ZInput.GetKeyDown(ToolConfig.ModeKey.Value, false))
			{
				CycleMode(toolKind);
			}
			if (toolKind != ToolKind.Hoe)
			{
				return;
			}
			if (ZInput.GetKeyDown(ToolConfig.ResetKey.Value, false))
			{
				ToolState.Hoe.ResetHeight();
				Say("Мотыга: высота не зафиксирована, следующий удар «Выровнять» её запомнит");
			}
			if (ZInput.GetKey(ToolConfig.SizeModifier.Value, false))
			{
				float num = ReadWheel();
				if (num != 0f)
				{
					StepSize((num > 0f) ? 1 : (-1));
				}
			}
		}

		internal static bool ShouldSwallowWheel()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if (_reading || ToolConfig.Enabled == null || !ToolConfig.Enabled.Value)
			{
				return false;
			}
			if (HeldKind() != ToolKind.Hoe || GameUiOpen())
			{
				return false;
			}
			return ZInput.GetKey(ToolConfig.SizeModifier.Value, false);
		}

		private static float ReadWheel()
		{
			_reading = true;
			try
			{
				return ZInput.GetMouseScrollWheel();
			}
			finally
			{
				_reading = false;
			}
		}

		private static void StepSize(int delta)
		{
			HoeState hoe = ToolState.Hoe;
			SizeSlot activeSlot = hoe.ActiveSlot;
			float[] array = ToolConfig.Sizes(activeSlot);
			int num = hoe.Sizes.Step(activeSlot, delta, array.Length);
			string text = HoeControl.AfterSizeStep();
			Say("Мотыга: " + ToolTexts.SlotName(activeSlot) + " " + ToolTexts.Meters(array[num]) + " (" + (num + 1) + "/" + array.Length + ")" + text);
		}

		private static void CycleMode(ToolKind kind)
		{
			switch (kind)
			{
			case ToolKind.Hoe:
				HoeControl.CycleMode();
				break;
			case ToolKind.Pickaxe:
			{
				PickaxeMode mode = ToolState.Pickaxe.CycleMode(ToolConfig.WideDigRadius.Value > 0f);
				Say("Кирка: режим — " + ToolTexts.PickaxeModeName(mode));
				break;
			}
			case ToolKind.Axe:
			{
				bool value = ToolConfig.Uproot.Value;
				bool value2 = ToolConfig.Careful.Value;
				if (!value && !value2)
				{
					Say("Топор: режимы отключены сервером");
					break;
				}
				ToolState.Axe.CycleMode(value, value2);
				Say("Топор: корчевание " + ToolTexts.OnOff(ToolState.Axe.Uproot) + ", бережный " + ToolTexts.OnOff(ToolState.Axe.Careful));
				break;
			}
			}
		}

		private static void Say(string text)
		{
			Player localPlayer = Player.m_localPlayer;
			if (localPlayer != null)
			{
				((Character)localPlayer).Message((MessageType)1, text, 0, (Sprite)null, false);
			}
		}
	}
	internal static class ToolItems
	{
		private static ItemDrop _hoe;

		private static ItemDrop _pickaxe;

		private static ItemDrop _axe;

		private static GameObject _hoeGo;

		private static GameObject _pickaxeGo;

		private static GameObject _axeGo;

		private static bool _dirty;

		private static ItemData _lastItem;

		private static SharedData _lastShared;

		private static GameObject _lastDrop;

		private static ToolKind _lastKind;

		internal const string RepairStation = "blackforge";

		internal static void Register()
		{
			PrefabManager.OnVanillaPrefabsAvailable += OnVanillaPrefabs;
		}

		private static void OnVanillaPrefabs()
		{
			PrefabManager.OnVanillaPrefabsAvailable -= OnVanillaPrefabs;
			_hoe = Make("SansaraHoe", "Hoe", "Мотыга Ивальди", "Мотыга, выкованная для больших строек: ровняет землю широким кругом и запоминает высоту. Не добывает больше, но экономит часы работы.");
			_pickaxe = Make("SansaraPickaxe", "PickaxeBlackMetal", "Кирка Синдри", "Кирка, которая берёт жилу целиком: один удар скалывает всё вокруг точки попадания, тяжёлый удар — ещё шире. Добычи с жилы столько же, сколько у обычной кирки.");
			_axe = Make("SansaraAxe", "AxeBlackMetal", "Топор Вёлунда", "Топор, который валит лес без остатка: разделывает брёвна разом, роняет деревья от дровосека и умеет корчевать пни. Древесины даёт столько же, сколько обычный.");
			_hoeGo = (((Object)(object)_hoe != (Object)null) ? ((Component)_hoe).gameObject : null);
			_pickaxeGo = (((Object)(object)_pickaxe != (Object)null) ? ((Component)_pickaxe).gameObject : null);
			_axeGo = (((Object)(object)_axe != (Object)null) ? ((Component)_axe).gameObject : null);
			_lastItem = null;
			ApplyConfig();
		}

		private static ItemDrop Make(string prefab, string basePrefab, string displayName, string description)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			CustomItem val = new CustomItem(prefab, basePrefab);
			if ((Object)(object)val.ItemDrop == (Object)null)
			{
				Plugin.Log.LogError((object)("Sansara Tools: не удалось создать " + prefab + " из " + basePrefab + "."));
				return null;
			}
			SharedData shared = val.ItemDrop.m_itemData.m_shared;
			shared.m_name = displayName;
			shared.m_description = description;
			if (ItemManager.Instance.AddItem(val))
			{
				AddRepairRecipe(prefab);
				Plugin.Log.LogInfo((object)("Sansara Tools: предмет " + prefab + " (основа " + basePrefab + ") зарегистрирован, ремонт — blackforge."));
				return val.ItemDrop;
			}
			Plugin.Log.LogError((object)("Sansara Tools: Jotunn не принял предмет " + prefab + "."));
			return null;
		}

		private static void AddRepairRecipe(string prefab)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: 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_001d: 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)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			CustomRecipe val = new CustomRecipe(new RecipeConfig
			{
				Name = "Recipe_" + prefab,
				Item = prefab,
				Amount = 1,
				Enabled = false,
				CraftingStation = "blackforge",
				RepairStation = "blackforge",
				MinStationLevel = 1,
				Requirements = (RequirementConfig[])(object)new RequirementConfig[0]
			});
			if (!ItemManager.Instance.AddRecipe(val))
			{
				Plugin.Log.LogWarning((object)("Sansara Tools: Jotunn не принял рецепт ремонта " + prefab + " — ремонт этого предмета недоступен."));
			}
		}

		internal static void ShareWithPrefab(ItemData item)
		{
			if (item == null)
			{
				return;
			}
			GameObject dropPrefab = item.m_dropPrefab;
			if (dropPrefab != null)
			{
				ItemDrop val = ((dropPrefab == _hoeGo) ? _hoe : ((dropPrefab == _pickaxeGo) ? _pickaxe : ((dropPrefab == _axeGo) ? _axe : null)));
				if ((Object)(object)val != (Object)null && item.m_shared != val.m_itemData.m_shared)
				{
					item.m_shared = val.m_itemData.m_shared;
				}
			}
		}

		internal static void MarkDirty()
		{
			_dirty = true;
		}

		internal static void ApplyIfDirty()
		{
			if (_dirty)
			{
				_dirty = false;
				ApplyConfig();
			}
		}

		internal static void ApplyConfig()
		{
			HoeItem.Apply(_hoe);
			PickaxeItem.Apply(_pickaxe);
			AxeItem.Apply(_axe);
			ToolConfig.WarnBadLists();
		}

		internal static ToolKind KindOf(ItemData item)
		{
			if (item == null)
			{
				return ToolKind.None;
			}
			if (item == _lastItem && item.m_shared == _lastShared && item.m_dropPrefab == _lastDrop)
			{
				return _lastKind;
			}
			ToolKind num = Classify(item);
			_lastItem = item;
			_lastShared = item.m_shared;
			_lastDrop = item.m_dropPrefab;
			_lastKind = num;
			return num;
		}

		private static ToolKind Classify(ItemData item)
		{
			if (item.m_shared != null)
			{
				if ((Object)(object)_hoe != (Object)null && item.m_shared == _hoe.m_itemData.m_shared)
				{
					return ToolKind.Hoe;
				}
				if ((Object)(object)_pickaxe != (Object)null && item.m_shared == _pickaxe.m_itemData.m_shared)
				{
					return ToolKind.Pickaxe;
				}
				if ((Object)(object)_axe != (Object)null && item.m_shared == _axe.m_itemData.m_shared)
				{
					return ToolKind.Axe;
				}
			}
			GameObject dropPrefab = item.m_dropPrefab;
			if (dropPrefab != null)
			{
				if (dropPrefab == _hoeGo)
				{
					return ToolKind.Hoe;
				}
				if (dropPrefab == _pickaxeGo)
				{
					return ToolKind.Pickaxe;
				}
				if (dropPrefab == _axeGo)
				{
					return ToolKind.Axe;
				}
			}
			ToolKind toolKind = ToolNames.Kind(((Object)(object)dropPrefab != (Object)null) ? ((Object)dropPrefab).name : null);
			if (toolKind != ToolKind.None || item.m_shared == null)
			{
				return toolKind;
			}
			return item.m_shared.m_name switch
			{
				"Мотыга Ивальди" => ToolKind.Hoe, 
				"Кирка Синдри" => ToolKind.Pickaxe, 
				"Топор Вёлунда" => ToolKind.Axe, 
				_ => ToolKind.None, 
			};
		}
	}
	[HarmonyPatch(typeof(ItemDrop), "Awake")]
	internal static class ItemDropSharePatch
	{
		private static void Postfix(ItemDrop __instance)
		{
			ToolItems.ShareWithPrefab(__instance.m_itemData);
		}
	}
	internal static class ToolPickup
	{
		private static Player _player;

		private static float _original;

		private static bool _applied;

		internal static void Tick()
		{
			Player localPlayer = Player.m_localPlayer;
			if (_applied && localPlayer != _player)
			{
				_applied = false;
				_player = null;
			}
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			float num = 0f;