Decompiled source of BuildExtend v0.9.3

plugins/BuildExtend.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.UI;
using Valheim.SettingsGui;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.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 BuildExtend
{
	public static class Api
	{
		public const int Version = 1;

		public static string ModeLabel => Plugin.ModeTab(Plugin.Hammer.Value);

		public static string ModeTooltip => HelpButton.ModeTip();

		public static string HelpTooltip => HelpButton.HelpTip;

		public static void ShowHelp()
		{
			HelpButton.Show();
		}

		public static void NextMode()
		{
			Plugin.NextMode(1);
		}
	}
	internal static class Planet
	{
		private static bool looked;

		private static PropertyInfo active;

		private static Func<Vector3, Vector3> up;

		private static MethodInfo ground;

		private static MethodInfo raise;

		private static MethodInfo level;

		internal static bool CanRaise
		{
			get
			{
				Look();
				return raise != null;
			}
		}

		internal static bool CanLevel
		{
			get
			{
				Look();
				return level != null;
			}
		}

		internal static bool On
		{
			get
			{
				Look();
				try
				{
					return active != null && up != null && (bool)active.GetValue(null);
				}
				catch
				{
					return false;
				}
			}
		}

		private static void Look()
		{
			if (looked)
			{
				return;
			}
			looked = true;
			try
			{
				Type type = (from a in AppDomain.CurrentDomain.GetAssemblies()
					select a.GetType("PlanetPrototype.PlanetApi", throwOnError: false)).FirstOrDefault((Type t) => t != null);
				if (type == null)
				{
					return;
				}
				PropertyInfo property = type.GetProperty("ApiVersion", BindingFlags.Static | BindingFlags.Public);
				if (property == null || (int)property.GetValue(null) < 2)
				{
					Plugin.Warn("PlanetApi is older than v2: building uses world up");
					return;
				}
				active = type.GetProperty("Active", BindingFlags.Static | BindingFlags.Public);
				MethodInfo method = type.GetMethod("Up", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(Vector3) }, null);
				if (method != null)
				{
					up = (Func<Vector3, Vector3>)Delegate.CreateDelegate(typeof(Func<Vector3, Vector3>), method);
				}
				ground = type.GetMethod("GroundPoint", BindingFlags.Static | BindingFlags.Public);
				Type[] types = new Type[6]
				{
					typeof(Vector3),
					typeof(Vector3),
					typeof(float),
					typeof(float),
					typeof(float),
					typeof(bool)
				};
				raise = type.GetMethod("RaiseArea", BindingFlags.Static | BindingFlags.Public, null, types, null);
				level = type.GetMethod("LevelArea", BindingFlags.Static | BindingFlags.Public, null, types, null);
				Plugin.Log("PlanetApi found: local up from the planet; the hoe's area raise " + ((raise != null) ? "through RaiseArea" : "not there (no RaiseArea)") + ", area levelling " + ((level != null) ? "through LevelArea" : "not there (no LevelArea)"));
			}
			catch (Exception ex)
			{
				Plugin.Warn("PlanetApi: " + ex.Message);
				active = null;
				up = null;
				ground = null;
				raise = (level = null);
			}
		}

		internal static float RaiseArea(Ground.Area a, bool apply)
		{
			return Area(raise, "RaiseArea", a, apply);
		}

		internal static float LevelArea(Ground.Area a, bool apply)
		{
			return Area(level, "LevelArea", a, apply);
		}

		private static float Area(MethodInfo method, string name, Ground.Area a, bool apply)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//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_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			if (method == null)
			{
				return 0f;
			}
			try
			{
				Vector3 val = a.Anchor + a.Fwd * ((a.A0 + a.A1) * 0.5f);
				return (float)method.Invoke(null, new object[6]
				{
					val,
					a.Fwd,
					(a.A1 - a.A0) * 0.5f,
					a.Half,
					a.Top,
					apply
				});
			}
			catch (Exception ex)
			{
				Plugin.Warn("PlanetApi." + name + ": " + (ex.InnerException ?? ex).Message);
				return 0f;
			}
		}

		internal static Vector3 Up(Vector3 point)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: 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)
			if (On)
			{
				try
				{
					Vector3 val = up(point);
					if (((Vector3)(ref val)).sqrMagnitude > 0.5f)
					{
						return ((Vector3)(ref val)).normalized;
					}
				}
				catch
				{
				}
			}
			return Vector3.up;
		}

		internal static bool Depth(Vector3 point, out float depth)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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_0051: 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)
			depth = 0f;
			if (On && ground != null)
			{
				try
				{
					object[] array = new object[3] { point, null, null };
					if (!(bool)ground.Invoke(null, array))
					{
						return false;
					}
					depth = Vector3.Dot((Vector3)array[1] - point, Up(point));
					return true;
				}
				catch
				{
					return false;
				}
			}
			if ((Object)(object)ZoneSystem.instance == (Object)null)
			{
				return false;
			}
			float groundHeight = ZoneSystem.instance.GetGroundHeight(point);
			depth = groundHeight - point.y;
			return true;
		}
	}
	internal static class Chests
	{
		internal enum Gate
		{
			Ready,
			Wait,
			Refused
		}

		private static bool looked;

		private static MethodInfo reserve;

		private static MethodInfo requirements;

		private static MethodInfo gate;

		private static PropertyInfo pending;

		internal static bool Present
		{
			get
			{
				Look();
				if (!(reserve != null))
				{
					return gate != null;
				}
				return true;
			}
		}

		private static void Look()
		{
			if (looked)
			{
				return;
			}
			looked = true;
			try
			{
				Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "ValheimUnified");
				if (assembly == null)
				{
					return;
				}
				reserve = assembly.GetType("ValheimUnified.BuildResources", throwOnError: false)?.GetMethod("Reserve", BindingFlags.Static | BindingFlags.Public, null, new Type[4]
				{
					typeof(Player),
					typeof(Requirement[]),
					typeof(int),
					typeof(Action)
				}, null);
				Type type = assembly.GetType("ValheimUnified.Resources", throwOnError: false);
				BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
				pending = type?.GetProperty("Pending", bindingAttr);
				if (reserve != null)
				{
					Plugin.Log("ValheimUnified: chests through BuildResources.Reserve");
					return;
				}
				requirements = type?.GetMethod("Requirements", bindingAttr, null, new Type[5]
				{
					typeof(Player),
					typeof(Requirement[]),
					typeof(int),
					typeof(int),
					typeof(bool)
				}, null);
				gate = type?.GetMethods(bindingAttr).FirstOrDefault((MethodInfo m) => m.Name == "Gate" && m.GetParameters().Length == 3);
				if (requirements != null && gate != null)
				{
					Plugin.Log("ValheimUnified: chests through its resource gate");
					return;
				}
				requirements = (gate = null);
				Plugin.Warn("ValheimUnified found, but not its chest gate: building spends what the inventory has");
			}
			catch (Exception ex)
			{
				Plugin.Warn("ValheimUnified: " + ex.Message);
				reserve = (requirements = (gate = null));
			}
		}

		internal static Gate Reserve(Player player, Piece piece, int count)
		{
			Look();
			try
			{
				if (reserve != null)
				{
					if ((bool)reserve.Invoke(null, new object[4] { player, piece.m_resources, count, null }))
					{
						return Gate.Ready;
					}
				}
				else
				{
					if (gate == null)
					{
						return Gate.Ready;
					}
					object obj = requirements.Invoke(null, new object[5] { player, piece.m_resources, 0, count, false });
					if (obj is ICollection { Count: 0 })
					{
						return Gate.Ready;
					}
					if ((bool)gate.Invoke(null, new object[3] { player, obj, null }))
					{
						return Gate.Ready;
					}
				}
				if (pending == null)
				{
					return Gate.Wait;
				}
				return ((bool)pending.GetValue(null)) ? Gate.Wait : Gate.Refused;
			}
			catch (Exception ex)
			{
				Plugin.Warn("ValheimUnified chests: " + (ex.InnerException ?? ex).Message);
				return Gate.Refused;
			}
		}
	}
	internal enum Verdict : byte
	{
		Unknown,
		Ok,
		Invalid,
		Exists,
		Swap
	}
	internal static class Checks
	{
		private static readonly Dictionary<Piece, string> refusals = new Dictionary<Piece, string>();

		private static readonly List<Transform> snaps = new List<Transform>();

		internal static string Refuse(Piece p)
		{
			if ((Object)(object)p == (Object)null)
			{
				return "";
			}
			if (refusals.TryGetValue(p, out var value))
			{
				return value;
			}
			string text = null;
			if (p.m_repairPiece || p.m_removePiece || p.m_groundPiece || p.m_groundOnly || p.m_cultivatedGroundOnly || p.m_vegetationGroundOnly || p.m_waterPiece || p.m_onlyInTeleportArea || p.m_requireDeepSnow || (Object)(object)p.m_mustConnectTo != (Object)null || Object.op_Implicit((Object)(object)((Component)p).GetComponent<TerrainModifier>()) || Object.op_Implicit((Object)(object)((Component)p).GetComponent<TerrainOp>()) || Object.op_Implicit((Object)(object)((Component)p).GetComponent<Plant>()) || Object.op_Implicit((Object)(object)((Component)p).GetComponent<PrivateArea>()) || Object.op_Implicit((Object)(object)((Component)p).GetComponent<StationExtension>()) || Object.op_Implicit((Object)(object)((Component)p).GetComponent<Ship>()) || Object.op_Implicit((Object)(object)((Component)p).GetComponent<Vagon>()) || Object.op_Implicit((Object)(object)((Component)p).GetComponent<ItemDrop>()) || Object.op_Implicit((Object)(object)((Component)p).GetComponent<Feast>()))
			{
				text = Plugin.T("Эту деталь нельзя протянуть", "This piece cannot be stretched");
			}
			if (refusals.Count > 512)
			{
				refusals.Clear();
			}
			refusals[p] = text;
			return text;
		}

		internal static Bounds LocalBounds(Transform root)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: 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_00c5: 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_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: 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_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: 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_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			bool any = false;
			Bounds box = default(Bounds);
			Collider[] componentsInChildren = ((Component)root).GetComponentsInChildren<Collider>(true);
			foreach (Collider val in componentsInChildren)
			{
				if (val.isTrigger)
				{
					continue;
				}
				Collider val2 = val;
				BoxCollider val3 = (BoxCollider)(object)((val2 is BoxCollider) ? val2 : null);
				if (val3 == null)
				{
					MeshCollider val4 = (MeshCollider)(object)((val2 is MeshCollider) ? val2 : null);
					if (val4 == null)
					{
						SphereCollider val5 = (SphereCollider)(object)((val2 is SphereCollider) ? val2 : null);
						if (val5 == null)
						{
							CapsuleCollider val6 = (CapsuleCollider)(object)((val2 is CapsuleCollider) ? val2 : null);
							if (val6 != null)
							{
								Vector3 val7 = Vector3.one * val6.radius * 2f;
								((Vector3)(ref val7))[val6.direction] = Mathf.Max(val6.height, val6.radius * 2f);
								Add(((Component)val6).transform, new Bounds(val6.center, val7));
							}
						}
						else
						{
							Add(((Component)val5).transform, new Bounds(val5.center, Vector3.one * val5.radius * 2f));
						}
					}
					else if ((Object)(object)val4.sharedMesh != (Object)null)
					{
						Add(((Component)val4).transform, val4.sharedMesh.bounds);
					}
				}
				else
				{
					Add(((Component)val3).transform, new Bounds(val3.center, val3.size));
				}
			}
			if (!any)
			{
				MeshFilter[] componentsInChildren2 = ((Component)root).GetComponentsInChildren<MeshFilter>(true);
				foreach (MeshFilter val8 in componentsInChildren2)
				{
					if ((Object)(object)val8.sharedMesh != (Object)null)
					{
						Add(((Component)val8).transform, val8.sharedMesh.bounds);
					}
				}
			}
			return box;
			void Add(Transform t, Bounds b)
			{
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				//IL_0038: Unknown result type (might be due to invalid IL or missing references)
				//IL_003d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0042: 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_004b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0050: Unknown result type (might be due to invalid IL or missing references)
				//IL_0055: Unknown result type (might be due to invalid IL or missing references)
				//IL_007e: Unknown result type (might be due to invalid IL or missing references)
				//IL_005f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0060: 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_006a: Unknown result type (might be due to invalid IL or missing references)
				for (int j = 0; j < 8; j++)
				{
					Vector3 val9 = ((Bounds)(ref b)).center + Vector3.Scale(((Bounds)(ref b)).extents, new Vector3((float)(((j & 1) != 0) ? 1 : (-1)), (float)(((j & 2) != 0) ? 1 : (-1)), (float)(((j & 4) != 0) ? 1 : (-1))));
					Vector3 val10 = root.InverseTransformPoint(t.TransformPoint(val9));
					if (!any)
					{
						box = new Bounds(val10, Vector3.zero);
						any = true;
					}
					else
					{
						((Bounds)(ref box)).Encapsulate(val10);
					}
				}
			}
		}

		internal static Shape ShapeOf(Piece instance, Bounds bounds)
		{
			//IL_0044: 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_0074: 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)
			snaps.Clear();
			instance.GetSnapPoints(snaps);
			Transform transform = ((Component)instance).transform;
			List<Vec> list = new List<Vec>(snaps.Count);
			foreach (Transform snap in snaps)
			{
				list.Add(V(transform.InverseTransformPoint(snap.position)));
			}
			return Lattice.FromPiece(list, V(((Bounds)(ref bounds)).min), V(((Bounds)(ref bounds)).max), Plugin.Beams.Value == BeamSpacing.Touching);
		}

		internal static Vec V(Vector3 v)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			return new Vec(v.x, v.y, v.z);
		}

		internal static Vector3 V(Vec v)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(v.X, v.Y, v.Z);
		}

		internal static Verdict Cell(Piece prefab, Vector3 pos, Vector3 stationAt, bool noStation)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: 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_0045: Unknown result type (might be due to invalid IL or missing references)
			if (Location.IsInsideNoBuildLocation(pos))
			{
				return Verdict.Invalid;
			}
			if (!PrivateArea.CheckAccess(pos, 0f, false, false))
			{
				return Verdict.Invalid;
			}
			if ((Object)(object)prefab.m_craftingStation != (Object)null && !noStation && !ZoneSystem.instance.GetGlobalKey((GlobalKeys)27) && (Object)(object)CraftingStation.HaveBuildStationInRange(prefab.m_craftingStation.m_name, stationAt) == (Object)null)
			{
				return Verdict.Invalid;
			}
			if ((int)prefab.m_onlyInBiome != 0 && (Heightmap.FindBiome(pos) & prefab.m_onlyInBiome) == 0)
			{
				return Verdict.Invalid;
			}
			return Verdict.Ok;
		}
	}
	[HarmonyPatch(typeof(BuildUi), "Awake")]
	internal static class HelpButton
	{
		private sealed class Live : MonoBehaviour
		{
			internal Action Refresh;

			private void Update()
			{
				Refresh?.Invoke();
			}
		}

		private const float Width = 48f;

		private const float Gap = 6f;

		internal static string HelpTip => Plugin.T("Массовая стройка: как пользоваться", "Mass building: how to use");

		internal static string Topic => Plugin.T("Массовая стройка", "Mass building");

		private static void Postfix(BuildUi __instance)
		{
			try
			{
				Add(__instance);
			}
			catch (Exception ex)
			{
				Plugin.Warn("help button not added: " + ex.Message);
			}
		}

		private static void Add(BuildUi ui)
		{
			RectTransform tabContainer = ui.m_tabContainer;
			if ((Object)(object)tabContainer == (Object)null || ((Transform)tabContainer).childCount == 0)
			{
				return;
			}
			GameObject gameObject = ((Component)((Transform)tabContainer).GetChild(((Transform)tabContainer).childCount - 1)).gameObject;
			HorizontalOrVerticalLayoutGroup component = ((Component)tabContainer).GetComponent<HorizontalOrVerticalLayoutGroup>();
			float padding = (((Object)(object)component != (Object)null) ? ((LayoutGroup)component).padding.right : 0);
			if ((Object)(object)component != (Object)null)
			{
				RectOffset padding2 = ((LayoutGroup)component).padding;
				padding2.right += 108;
			}
			Tab(tabContainer, gameObject, "BuildExtend help", "?", HelpTip, padding, 0, Show);
			GameObject val = Tab(tabContainer, gameObject, "BuildExtend switch", "xN", "", padding, 1, delegate
			{
				Plugin.NextMode(1);
			});
			if ((Object)(object)val != (Object)null)
			{
				TMP_Text text = val.GetComponentInChildren<TMP_Text>(true);
				UITooltip tip = val.GetComponent<UITooltip>();
				val.AddComponent<Live>().Refresh = delegate
				{
					HammerMode value = Plugin.Hammer.Value;
					if ((Object)(object)text != (Object)null)
					{
						text.text = Plugin.ModeTab(value);
					}
					if ((Object)(object)tip != (Object)null)
					{
						tip.m_text = ModeTip();
					}
				};
			}
			LayoutRebuilder.MarkLayoutForRebuild(tabContainer);
			Plugin.Debug($"help button: tab row {((Object)tabContainer).name}, {((Transform)tabContainer).childCount} tabs");
		}

		internal static string ModeTip()
		{
			HammerMode value = Plugin.Hammer.Value;
			return Plugin.T("Режим молота: ", "Hammer mode: ") + Plugin.ModeName(value) + Plugin.T(". Нажмите — следующий: ", ". Click for the next: ") + Plugin.ModeName((HammerMode)((int)(value + 1) % 3)) + Plugin.T(". В игре — ", ". In game: ") + Stretch.ModeKey() + Plugin.T("колесо.", "wheel.");
		}

		private static GameObject Tab(RectTransform tabs, GameObject source, string name, string label, string tooltip, float padding, int slot, Action click)
		{
			//IL_0044: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: 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_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Expected O, but got Unknown
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Expected O, but got Unknown
			GameObject val = Object.Instantiate<GameObject>(source, (Transform)(object)tabs);
			((Object)val).name = name;
			val.transform.SetAsLastSibling();
			(val.GetComponent<LayoutElement>() ?? val.AddComponent<LayoutElement>()).ignoreLayout = true;
			RectTransform val2 = (RectTransform)val.transform;
			val2.anchorMin = new Vector2(1f, 0f);
			val2.anchorMax = new Vector2(1f, 1f);
			val2.pivot = new Vector2(1f, 0.5f);
			val2.sizeDelta = new Vector2(48f, 0f);
			val2.anchoredPosition = new Vector2(0f - padding - (float)slot * 54f, 0f);
			TMP_Text[] componentsInChildren = val.GetComponentsInChildren<TMP_Text>(true);
			foreach (TMP_Text obj in componentsInChildren)
			{
				obj.text = label;
				obj.fontStyle = (FontStyles)(obj.fontStyle | 1);
			}
			Transform val3 = val.transform.Find("Selected");
			if ((Object)(object)val3 != (Object)null)
			{
				((Component)val3).gameObject.SetActive(false);
			}
			UITooltip component = val.GetComponent<UITooltip>();
			if ((Object)(object)component != (Object)null)
			{
				component.m_text = tooltip;
			}
			Button component2 = val.GetComponent<Button>();
			if ((Object)(object)component2 == (Object)null)
			{
				Object.Destroy((Object)(object)val);
				return null;
			}
			component2.onClick = new ButtonClickedEvent();
			((UnityEvent)component2.onClick).AddListener((UnityAction)delegate
			{
				try
				{
					click();
				}
				catch (Exception ex)
				{
					Plugin.Warn("build menu tab: " + ex.Message);
				}
			});
			return val;
		}

		internal static void Show()
		{
			try
			{
				if ((Object)(object)Hud.instance != (Object)null)
				{
					Hud.instance.m_buildUi.Close();
				}
				InventoryGui instance = InventoryGui.instance;
				if (!((Object)(object)instance == (Object)null) && !((Object)(object)Player.m_localPlayer == (Object)null))
				{
					instance.Show((Container)null, 1);
					instance.OnOpenTexts();
					TextsDialog textsDialog = instance.m_textsDialog;
					TextInfo val = textsDialog.m_texts.Find((TextInfo t) => t.m_topic == Topic);
					if (val != null)
					{
						textsDialog.ShowText(val);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Warn("help: " + ex.Message);
			}
		}

		internal static void AddEntry(TextsDialog __instance)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			try
			{
				if (Plugin.Enabled.Value)
				{
					__instance.m_texts.Insert(Math.Min(1, __instance.m_texts.Count), new TextInfo(Topic, Text()));
				}
			}
			catch (Exception ex)
			{
				Plugin.Warn("compendium entry: " + ex.Message);
			}
		}

		private static string Key(string k)
		{
			return Plugin.Hint(k);
		}

		private static string Head(string h)
		{
			return "<color=#FFB75B><b>" + h + "</b></color>";
		}

		private static string Text()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Invalid comparison between Unknown and I4
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			string k = (((int)Plugin.UndoModifier.Value == 0) ? "" : (((int)Plugin.UndoModifier.Value == 306 || (int)Plugin.UndoModifier.Value == 305) ? "Ctrl+" : (((object)Plugin.UndoModifier.Value/*cast due to .constrained prefix*/).ToString() + "+"))) + ((object)Plugin.UndoKey.Value/*cast due to .constrained prefix*/).ToString();
			if (!Plugin.Russian)
			{
				return Head("Stretch building") + "\n" + Key("hold LMB") + " on the ghost and look around — the piece follows the aim as a grid. Let go to build. A short click places one piece as usual.\nTranslucent silhouettes and yellow arrows at the ghost show where it can go: walls aside and up, floors aside and forward, roofs and stairs along the ridge and down the slope, diagonal beams along themselves.\n\n" + Head("Hammer modes") + "\n" + Key("Shift+wheel") + " (while nothing is stretched) or the " + Key("x1 / xN / xF") + " tab in the build menu:\n- " + Key("x1") + " normal building — exactly as in the game, one piece at a time, for precise building;\n- " + Key("xN") + " stretching — silhouettes and arrows, hold LMB and drag;\n- " + Key("xF") + " shapes — the remembered shape follows the ghost, a click builds it whole; " + Key("E") + " — another shape; hold LMB and look — resize (remembered).\n\n" + Head("While held") + "\n" + Key("E") + " — shape: plane, box (walls round a rectangle, for roofs a gable roof), cylinder (a round tower, for floors a round floor), arch of beams, dome.\n" + Key("wheel") + " or " + Key("Shift+wheel") + " — floors (rows) of a box or tower.   " + Key("Ctrl+wheel") + " — gaps: every 2nd, every 3rd, checkerboard.\n" + Key("RMB") + " or " + Key("Esc") + " — cancel.\nThe whole stretch is one sheet from the first piece: its height and tilt, pieces edge to edge holding each other up. Everything is placed except in others' wards, no-build places and out of the workbench's reach from where the stretch started.\n\n" + Head("Iron hoe: level to height") + "\nThe iron hoe is made at the forge from a level 3 hoe and iron. Besides the usual \"Level ground\" and \"Raise ground\" it has \"Level to height\": " + Key("hold LMB") + " and look ahead — a level rectangle along the look, " + Key("wheel") + " — width, " + Key("Ctrl+wheel") + " — height over the press point (0 by default). A click — a strip as wide as the frame.\nEverything in the rectangle goes to that height: cut above, filled below, square, no rounding. Cutting is free, filling costs stone by the volume, as the game's raise does; short of it, as much is done from the press point as is paid for.\n\n" + Head("Removing and undo") + "\n" + Key("hold MMB") + " on a placed piece and look — a removal zone from that point to the aim: " + Key("wall") + " (the wall's plane), " + Key("floor") + " (the floor's plane) or " + Key("box") + "; " + Key("E") + " — next zone. Pieces in the zone glow red, release to remove; resources to the backpack. A short click removes one piece, as in the game. Stations, beds, portals and wards are left alone. Own pieces only by default.\n" + Key(k) + " — undo the last stretch: its pieces come down, what it cost comes back.\n\n" + Head("Colours") + "\n<color=#99CCFF>pale blue</color> — full strength; <color=#66FF66>green</color> → <color=#FF8000>orange</color> — weaker, orange falls;\n<color=#FF4040>red</color> — not possible or not enough materials; <color=#B366FF>violet</color> — replaces a standing piece (doors and windows along a wall).\n\n" + Head("Resources") + "\nThe build panel shows what all the segments need, how many are paid for and what is short. Nearby chests count if a chest mod adds them. As many are built as can be paid for.\n\n" + Head("Settings") + "\nSettings → Graphics, section \"Stretch building — BuildExtend\": shape, gaps, strength, replacing, own-only removal, segment limit, speed, stamina, beams.";
			}
			return Head("Стройка протяжкой") + "\n" + Key("удерживать ЛКМ") + " на призраке и вести взгляд — деталь тянется сеткой за прицелом. Отпустить — построить. Короткий щелчок ставит одну деталь, как обычно.\nПрозрачные силуэты и жёлтые стрелки у призрака показывают, куда деталь можно тянуть: стены — вбок и вверх, полы — вбок и вперёд, крыши и лестницы — вдоль конька и по скату, диагональные балки — вдоль себя.\n\n" + Head("Режимы молота") + "\n" + Key("Shift+колесо") + " (пока ничего не тянется) или вкладка " + Key("x1 / xN / xF") + " в меню стройки:\n- " + Key("x1") + " обычная стройка — ровно как в игре, по одной детали, для точной стройки;\n- " + Key("xN") + " протяжка — силуэты и стрелки, зажать ЛКМ и тянуть;\n- " + Key("xF") + " фигуры — фигура запомненного размера идёт за призраком, щелчок ЛКМ строит её целиком; " + Key("E") + " — другая фигура; зажать ЛКМ и повести — изменить размер (он запоминается).\n\n" + Head("Пока кнопка зажата") + "\n" + Key("E") + " — форма: плоскость, коробка (стены по краю прямоугольника, для крыш — двускатная крыша), цилиндр (круглая башня, для полов — круглый пол), арка из балок, купол.\n" + Key("колесо") + " или " + Key("Shift+колесо") + " — этажи (ряды) коробки и башни.   " + Key("Ctrl+колесо") + " — пропуски: через одну, через две, шахматкой.\n" + Key("ПКМ") + " или " + Key("Esc") + " — отмена.\nВся протяжка — одно полотно от первой детали: её высота и наклон, детали стык в стык держат друг друга. Ставится всё, кроме чужих владений, мест без стройки и мест вне досягаемости верстака от начала протяжки.\n\n" + Head("Железная мотыга: выравнивание по высоте") + "\nЖелезная мотыга делается в кузнице из обычной мотыги 3 уровня и железа. Кроме обычных «Выровнять землю» и «Поднять землю» у неё есть «Выровнять по высоте»: " + Key("удерживать ЛКМ") + " и вести взгляд вперёд — ровный прямоугольник по взгляду, " + Key("колесо") + " — ширина, " + Key("Ctrl+колесо") + " — высота над точкой нажатия (по умолчанию 0). Щелчок — полоса шириной в рамку.\nВсё в прямоугольнике встаёт на эту высоту: выше срезается, ниже подсыпается, без скруглений. Срез бесплатно, подсыпка — камень по объёму, как за обычный подъём; не хватает — делается сколько оплачено от точки нажатия.\n\n" + Head("Снос и отмена") + "\n" + Key("удерживать СКМ") + " на поставленной детали и вести взгляд — зона сноса от этой точки до прицела: " + Key("стена") + " (плоскость стены), " + Key("пол") + " (плоскость пола) или " + Key("куб") + "; " + Key("E") + " — сменить зону. Детали в зоне подсвечены красным, отпустить — снести; ресурсы — в рюкзак. Короткий щелчок — одна деталь, как в игре. Верстаки, кровати, порталы и обереги зона не трогает. По умолчанию только свои детали.\n" + Key(k) + " — отменить последнюю протяжку: детали снимаются, потраченное возвращается.\n\n" + Head("Цвета") + "\n<color=#99CCFF>голубой</color> — полная прочность; <color=#66FF66>зелёный</color> → <color=#FF8000>оранжевый</color> — слабее, оранжевый рухнет;\n<color=#FF4040>красный</color> — строить нельзя или не хватает материалов; <color=#B366FF>фиолетовый</color> — заменит стоящую деталь (двери и окна по стене).\n\n" + Head("Ресурсы") + "\nВ панели стройки — сколько нужно на все сегменты, на сколько хватает и чего не хватает. Материалы из ближних сундуков учитываются, если их добавляет мод на сундуки. Строится столько, на сколько хватает.\n\n" + Head("Настройки") + "\nНастройки → Графика, раздел «Протяжная стройка — BuildExtend»: форма, пропуски, прочность, замена, снос только своих, предел сегментов, скорость, выносливость, балки.";
		}
	}
	[HarmonyPatch(typeof(TextsDialog), "UpdateTextsList")]
	internal static class HelpEntry
	{
		private static void Postfix(TextsDialog __instance)
		{
			HelpButton.AddEntry(__instance);
		}
	}
	internal static class Hoe
	{
		private enum Kind
		{
			Raise,
			Level
		}

		private const float MaxLength = 32f;

		private const float MaxWidth = 32f;

		private const float MaxHeight = 8f;

		private static bool busy;

		private static bool wheeled;

		private static Kind kind;

		private static Player player;

		private static Piece piece;

		private static TerrainOp op;

		private static Vector3 anchor;

		private static Vector3 up;

		private static Vector3 fwd;

		private static Vector3 side;

		private static float length;

		private static float paidLength;

		private static Ground.Fill fill;

		private static Ground.Fill paidFill;

		private static int ops;

		private static int paid;

		private static bool dirty;

		private static bool free;

		private static float nextMeasure;

		private static Piece probe;

		internal static bool Busy => busy;

		internal static Piece Piece => piece;

		internal static int Ops => Math.Max(1, ops);

		private static TerrainOp OpOf(Piece p, out Kind k)
		{
			k = Kind.Raise;
			TerrainOp val = (IronHoe.IsAreaPiece(p) ? ((Component)p).GetComponent<TerrainOp>() : null);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			Settings settings = val.m_settings;
			if ((settings.m_raise && settings.m_raiseDelta > 0f) || settings.m_level)
			{
				k = Kind.Level;
				return val;
			}
			return null;
		}

		internal static string Refuse(Player p, Piece selected)
		{
			if (!Plugin.Enabled.Value || !Plugin.HoeArea.Value || (Object)(object)OpOf(selected, out var k) == (Object)null)
			{
				return "";
			}
			if (!IronHoe.Is(((Humanoid)p).GetRightItem()))
			{
				if (Plugin.IronHoeOn.Value)
				{
					if (k != Kind.Level)
					{
						return Plugin.T("насыпать областью умеет железная мотыга (кузница: мотыга 3 уровня и железо)", "the iron hoe raises an area (forge: a level 3 hoe and iron)");
					}
					return Plugin.T("выравнивать областью умеет железная мотыга (кузница: мотыга 3 уровня и железо)", "the iron hoe levels an area (forge: a level 3 hoe and iron)");
				}
				return "";
			}
			if (Planet.On)
			{
				bool canRaise;
				if (k != Kind.Level)
				{
					canRaise = Planet.CanRaise;
				}
				else
				{
					if (!Planet.CanLevel)
					{
						goto IL_0094;
					}
					canRaise = Planet.CanRaise;
				}
				if (!canRaise)
				{
					goto IL_0094;
				}
			}
			return null;
			IL_0094:
			return Plugin.T("на планете это областью ждёт новой PlanetPrototype", "on the planet this needs a newer PlanetPrototype");
		}

		internal static bool Start(Player p)
		{
			//IL_0029: 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_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: 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_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: 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_00da: 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_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			Piece selectedPiece = p.GetSelectedPiece();
			GameObject placementGhost = p.m_placementGhost;
			if (Refuse(p, selectedPiece) != null || (Object)(object)placementGhost == (Object)null || !placementGhost.activeInHierarchy || (int)p.m_placementStatus != 0)
			{
				return false;
			}
			player = p;
			piece = selectedPiece;
			op = OpOf(selectedPiece, out kind);
			anchor = placementGhost.transform.position;
			up = Planet.Up(anchor);
			fwd = Vector3.ProjectOnPlane(((Object)(object)GameCamera.instance != (Object)null) ? ((Component)GameCamera.instance).transform.forward : ((Component)p).transform.forward, up);
			if (((Vector3)(ref fwd)).sqrMagnitude < 0.0001f)
			{
				fwd = Vector3.ProjectOnPlane(((Component)p).transform.forward, up);
			}
			((Vector3)(ref fwd)).Normalize();
			Vector3 val = Vector3.Cross(up, fwd);
			side = ((Vector3)(ref val)).normalized;
			length = 0f;
			wheeled = false;
			busy = true;
			dirty = true;
			nextMeasure = 0f;
			Measure();
			return true;
		}

		internal static bool Update(Player p, bool takeInput)
		{
			if ((Object)(object)p != (Object)(object)player || !((Character)p).InPlaceMode() || ((Character)p).IsDead() || (Object)(object)p.GetSelectedPiece() != (Object)(object)piece || Refuse(p, piece) != null)
			{
				Reset();
				return true;
			}
			if (takeInput && Stretch.CancelPressed())
			{
				Reset();
				return false;
			}
			if (!Stretch.PlaceHeld)
			{
				return Release(p);
			}
			if (!takeInput)
			{
				return false;
			}
			float mouseScrollWheel = ZInput.GetMouseScrollWheel();
			int num = ((mouseScrollWheel > 0f) ? 1 : ((mouseScrollWheel < 0f) ? (-1) : (ZInput.GetButtonDown("JoyDPadUp") ? 1 : (ZInput.GetButtonDown("JoyDPadDown") ? (-1) : 0))));
			bool flag = ZInput.GetKey((KeyCode)306, false) || ZInput.GetKey((KeyCode)305, false) || ZInput.GetButton("JoyAltKeys");
			if (num != 0)
			{
				wheeled = true;
				dirty = true;
				if (flag)
				{
					Plugin.HoeHeight.Value = Mathf.Clamp(Mathf.Round((Plugin.HoeHeight.Value + (float)num * 0.25f) * 4f) / 4f, -8f, 8f);
				}
				else if (!flag)
				{
					Plugin.HoeWidth.Value = Mathf.Clamp(Mathf.Round(Plugin.HoeWidth.Value) + (float)num, 1f, 32f);
				}
			}
			Follow();
			Measure();
			return false;
		}

		private static void Follow()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: 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_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)
			//IL_0053: 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_0066: 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_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: 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)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)GameCamera.instance == (Object)null)
			{
				return;
			}
			Transform transform = ((Component)GameCamera.instance).transform;
			Vector3 position = transform.position;
			Vector3 forward = transform.forward;
			float num = 64f;
			float num2 = Vector3.Dot(forward, up);
			float num3 = ((Mathf.Abs(num2) > 0.001f) ? (Vector3.Dot(anchor - position, up) / num2) : (-1f));
			RaycastHit val = default(RaycastHit);
			Vector3 val2;
			if (Physics.Raycast(position, forward, ref val, num, player.m_placeRayMask, (QueryTriggerInteraction)1) && (num3 < 0f || ((RaycastHit)(ref val)).distance < num3))
			{
				val2 = ((RaycastHit)(ref val)).point;
			}
			else
			{
				if (!(num3 > 0f))
				{
					return;
				}
				val2 = position + forward * Mathf.Min(num3, num);
			}
			float num4 = Mathf.Clamp(Vector3.Dot(val2 - anchor, fwd), -32f, 32f);
			float num5 = ((Mathf.Abs(num4 - length) < 0.65f) ? length : Mathf.Round(num4));
			if (num5 != length)
			{
				length = num5;
				dirty = true;
			}
		}

		private static Ground.Area Area(float len)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			return new Ground.Area
			{
				Anchor = anchor,
				Up = up,
				Fwd = fwd,
				A0 = Mathf.Min(0f, len) - 0.5f,
				A1 = Mathf.Max(0f, len) + 0.5f,
				Half = Plugin.HoeWidth.Value * 0.5f,
				Top = Plugin.HoeHeight.Value,
				Level = (kind == Kind.Level),
				Op = StringExtensionMethods.GetStableHashCode(IronHoe.Source(piece) ?? Utils.GetPrefabName(((Component)piece).gameObject))
			};
		}

		private static void Measure(bool now = false)
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			if ((!now && !dirty && Time.unscaledTime < nextMeasure) || (!now && Time.unscaledTime < nextMeasure - 0.15f))
			{
				return;
			}
			nextMeasure = Time.unscaledTime + 0.25f;
			dirty = false;
			Ground.Area a = Area(length);
			Hoe.fill = Measure(a);
			ops = Cost(a, Hoe.fill);
			free = ops == 0 || player.NoCostCheat() || ZoneSystem.instance.GetGlobalKey(piece.FreeBuildKey()) || ZoneSystem.instance.GetGlobalKey((GlobalKeys)24);
			paid = (free ? ops : Lattice.Affordable(Enough, ops));
			paidLength = length;
			paidFill = Hoe.fill;
			if (paid >= ops)
			{
				return;
			}
			int num = 0;
			int num2 = (int)Mathf.Abs(length);
			Ground.Fill f = default(Ground.Fill);
			while (num < num2)
			{
				int num3 = num + (num2 - num + 1) / 2;
				Ground.Area a2 = Area(Mathf.Sign(length) * (float)num3);
				Ground.Fill fill = Measure(a2);
				if (Cost(a2, fill) <= paid)
				{
					num = num3;
					f = fill;
				}
				else
				{
					num2 = num3 - 1;
				}
			}
			if (num == 0)
			{
				Ground.Area a3 = Area(0f);
				f = Measure(a3);
				if (Cost(a3, f) > paid)
				{
					f = default(Ground.Fill);
				}
			}
			paidLength = Mathf.Sign(length) * (float)num;
			paidFill = f;
		}

		private static Ground.Fill Measure(Ground.Area a)
		{
			if (!Planet.On)
			{
				return Ground.Measure(a);
			}
			float num = Planet.RaiseArea(a, apply: false);
			if (!a.Level)
			{
				return new Ground.Fill
				{
					Up = num
				};
			}
			return new Ground.Fill
			{
				Up = num,
				Down = Mathf.Max(0f, Planet.LevelArea(a, apply: false) - num)
			};
		}

		private static int Cost(Ground.Area a, Ground.Fill f)
		{
			Settings settings = op.m_settings;
			if (!settings.m_raise)
			{
				if (!piece.m_resources.Any((Requirement q) => (Object)(object)q.m_resItem != (Object)null && q.GetAmount(0) > 0) || f.Moved <= 0.005f)
				{
					return 0;
				}
				float num = Mathf.Max(0.5f, settings.m_levelRadius);
				float num2 = (settings.m_square ? (4f * num * num) : ((float)Math.PI * num * num));
				return Mathf.CeilToInt((a.A1 - a.A0) * 2f * a.Half / num2 - 0.001f);
			}
			float num3 = Mathf.Max(0.5f, settings.m_raiseRadius);
			float num4 = (settings.m_square ? (4f * num3 * num3) : ((float)Math.PI * num3 * num3 * ((settings.m_raisePower > 0f) ? (2f / ((settings.m_raisePower + 1f) * (settings.m_raisePower + 2f))) : 1f)));
			float num5 = Mathf.Max(0.1f, num4 * settings.m_raiseDelta);
			if (!(f.Up <= 0.005f))
			{
				return Mathf.CeilToInt(f.Up / num5 - 0.001f);
			}
			return 0;
		}

		private static bool Enough(int k)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			if ((Object)(object)probe == (Object)null)
			{
				GameObject val = new GameObject("BuildExtend hoe probe");
				val.SetActive(false);
				Object.DontDestroyOnLoad((Object)val);
				probe = val.AddComponent<Piece>();
				probe.m_dlc = "";
			}
			Requirement[] resources = piece.m_resources;
			probe.m_resources = ((IEnumerable<Requirement>)resources).Select((Func<Requirement, Requirement>)((Requirement q) => new Requirement
			{
				m_resItem = q.m_resItem,
				m_amount = (int)Math.Min(2147483647L, (long)q.GetAmount(0) * (long)k)
			})).ToArray();
			probe.m_craftingStation = null;
			probe.m_name = piece.m_name;
			return player.HaveRequirements(probe, (RequirementMode)0);
		}

		private static bool Release(Player p)
		{
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: 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_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			Measure(now: true);
			if (paidFill.Moved <= 0.005f)
			{
				((Character)p).Message((MessageType)2, (ops > 0 && paid < ops) ? "$msg_missingrequirement" : ((kind == Kind.Level) ? Plugin.T("Здесь уже ровно", "Already level here") : Plugin.T("Здесь нечего насыпать", "Nothing to raise here")), 0, (Sprite)null, false);
				Reset();
				return false;
			}
			Ground.Area a = Area(paidLength);
			int num = ((!free) ? Cost(a, paidFill) : 0);
			if (num > 0 && Chests.Present && Chests.Reserve(p, piece, num) != Chests.Gate.Ready)
			{
				((Character)p).Message((MessageType)2, Plugin.T("Материалы из сундуков ещё не переданы — повторите", "The chests' materials are not handed over yet - try again"), 0, (Sprite)null, false);
				Reset();
				return false;
			}
			ItemData rightItem = ((Humanoid)p).GetRightItem();
			float buildStamina = p.GetBuildStamina();
			if (!((Character)p).HaveStamina(buildStamina))
			{
				Hud.instance.StaminaBarEmptyFlash();
				Reset();
				return false;
			}
			((Character)p).UseStamina(buildStamina);
			if (rightItem != null && rightItem.m_shared.m_useDurability)
			{
				rightItem.m_durability -= p.GetPlaceDurability(rightItem) * Game.m_durabilityRate;
			}
			if (num > 0)
			{
				p.ConsumeResources(piece.m_resources, 0, -1, num);
			}
			if (Planet.On)
			{
				if (a.Level && Planet.CanLevel)
				{
					Planet.LevelArea(a, apply: true);
				}
				else
				{
					Planet.RaiseArea(a, apply: true);
				}
			}
			else
			{
				Ground.Apply(a);
			}
			Vector3 val = anchor + fwd * ((a.A0 + a.A1) * 0.5f);
			piece.m_placeEffect.Create(val, Quaternion.identity, (Transform)null, 1f, -1, ((Character)p).GetZDOID());
			op.m_onPlacedEffect.Create(val, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
			p.m_lastToolUseTime = Time.time;
			string text = Plugin.T("Выровнено по высоте " + Size(a), "Levelled to height " + Size(a)) + ((paidFill.Up > 0.005f) ? Plugin.T($", подсыпано {paidFill.Up:0.#} м³", $", {paidFill.Up:0.#} m³ filled") : "");
			((Character)p).Message((MessageType)1, text + ((paid < ops) ? Plugin.T(": на остальное не хватило материалов", ": not enough materials for the rest") : ""), 0, (Sprite)null, false);
			Reset();
			return false;
		}

		private static string Size(Ground.Area a)
		{
			return string.Format("{0:0.#} × {1:0.#} {2}", a.A1 - a.A0, 2f * a.Half, Plugin.T("м", "m"));
		}

		internal static void Reset()
		{
			busy = false;
			player = null;
			piece = null;
			op = null;
		}

		internal static void Draw()
		{
			//IL_0051: 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_0056: 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_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			if (busy)
			{
				Ground.Area area = Area(length);
				bool num = paid < ops;
				Color faceColor = (num ? new Color(1f, 0.3f, 0.2f, 0.14f) : new Color(0.85f, 0.7f, 0.35f, 0.14f));
				Color edgeColor = (num ? new Color(1f, 0.45f, 0.35f, 0.9f) : new Color(1f, 0.85f, 0.4f, 0.9f));
				float num2 = ((kind == Kind.Level) ? (area.Top - 0.05f) : (Mathf.Min(fill.Low, area.Top) - 0.05f));
				float num3 = ((kind == Kind.Level) ? (area.Top + 0.05f) : area.Top);
				Overlay.Box(anchor, fwd, side, up, new Vector3(area.A0, 0f - area.Half, num2), new Vector3(area.A1, area.Half, num3), faceColor, edgeColor);
			}
		}

		internal static string Description()
		{
			Ground.Area a = Area(length);
			string text = Plugin.T("м³", "m³");
			string text2 = ((kind == Kind.Level) ? (Plugin.T("Отпустите ЛКМ — выровнять по высоте: ", "Release LMB to level to height: ") + Size(a) + string.Format(", {0}{1:0.##} {2}", (a.Top >= 0f) ? "+" : "", a.Top, Plugin.T("м", "m")) + Plugin.T($" · срезать {fill.Down:0.#} {text}, подсыпать {fill.Up:0.#} {text}", $" · cut {fill.Down:0.#} {text}, fill {fill.Up:0.#} {text}")) : (Plugin.T("Отпустите ЛКМ — насыпать: ", "Release LMB to raise: ") + Size(a) + string.Format(", +{0:0.##} {1} · {2:0.#} {3}", Plugin.HoeHeight.Value, Plugin.T("м", "m"), fill.Up, text)));
			if (fill.Moved <= 0.005f)
			{
				text2 = text2 + " · " + ((kind == Kind.Level) ? Plugin.T("здесь уже ровно", "already level") : Plugin.T("здесь уже выше", "already higher here"));
			}
			else if (paid < ops)
			{
				text2 = text2 + " · <color=red>" + Plugin.T($"хватит на {Math.Abs(paidLength) + 1f:0} м", $"enough for {Math.Abs(paidLength) + 1f:0} m") + "</color>";
			}
			text2 = text2 + "\n" + Plugin.Hint(Plugin.T("колесо", "wheel")) + " " + Plugin.T("ширина", "width") + "   ";
			text2 = text2 + Plugin.Hint(Plugin.T("Ctrl+колесо", "Ctrl+wheel")) + " " + Plugin.T("высота", "height") + "   ";
			return text2 + Plugin.Hint(Plugin.T("ПКМ", "RMB")) + " " + Plugin.T("отмена", "cancel");
		}
	}
	internal static class Ground
	{
		internal struct Area
		{
			public Vector3 Anchor;

			public Vector3 Up;

			public Vector3 Fwd;

			public float A0;

			public float A1;

			public float Half;

			public float Top;

			public bool Level;

			public int Op;
		}

		internal struct Fill
		{
			public float Up;

			public float Down;

			public float Low;

			internal float Moved => Up + Down;
		}

		private sealed class Pending
		{
			internal long Id;

			internal TerrainComp Comp;

			internal Area Area;

			internal float Since;
		}

		private const string Rpc = "BuildExtend_RaiseArea";

		private const string Done = "BuildExtend_RaiseDone";

		private const int Format = 2;

		private const float MaxDelta = 8f;

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

		private static readonly List<Pending> pending = new List<Pending>();

		private static ZRoutedRpc registered;

		private static Vector3 Side(Area a)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Vector3.Cross(Vector3.up, a.Fwd);
			return ((Vector3)(ref val)).normalized;
		}

		private static Vector3 Center(Area a)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			return a.Anchor + a.Fwd * ((a.A0 + a.A1) * 0.5f);
		}

		private static float Radius(Area a)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = new Vector2((a.A1 - a.A0) * 0.5f, a.Half);
			return ((Vector2)(ref val)).magnitude + 1.5f;
		}

		private static bool Inside(Area a, Vector3 p)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = p - a.Anchor;
			float num = Vector3.Dot(val, a.Fwd);
			float num2 = Vector3.Dot(val, Side(a));
			if (num >= a.A0 - 0.01f && num <= a.A1 + 0.01f)
			{
				return Mathf.Abs(num2) <= a.Half + 0.01f;
			}
			return false;
		}

		private static IEnumerable<(int x, int y, Vector3 world)> Vertices(Heightmap h, Area a)
		{
			int n = h.m_width + 1;
			int half = h.m_width / 2;
			float s = h.m_scale;
			float num = Radius(a);
			Vector3 origin = ((Component)h).transform.position;
			int cx = default(int);
			int cy = default(int);
			h.WorldToVertex(Center(a), ref cx, ref cy);
			int reach = Mathf.CeilToInt(num / s);
			for (int y = Math.Max(0, cy - reach); y <= Math.Min(n - 1, cy + reach); y++)
			{
				for (int x = Math.Max(0, cx - reach); x <= Math.Min(n - 1, cx + reach); x++)
				{
					Vector3 val = origin + new Vector3((float)(x - half) * s, 0f, (float)(y - half) * s);
					if (Inside(a, val))
					{
						yield return (x: x, y: y, world: val);
					}
				}
			}
		}

		private static float Target(Area a, TerrainComp comp, int index, float height)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			float num = a.Anchor.y + a.Top;
			if ((Object)(object)comp != (Object)null && comp.m_initialized && comp.m_levelDelta != null && index < comp.m_levelDelta.Length)
			{
				float num2 = height - (comp.m_levelDelta[index] + comp.m_smoothDelta[index]);
				num = Mathf.Clamp(num, num2 - 8f, num2 + 8f);
			}
			if (!a.Level)
			{
				return Mathf.Max(height, num);
			}
			return num;
		}

		private static void Maps(Area a)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			maps.Clear();
			Heightmap.FindHeightmap(Center(a), Radius(a), maps);
			maps.RemoveAll((Heightmap h) => (Object)(object)h == (Object)null || h.IsDistantLod || h.m_heights == null || h.m_heights.Count == 0);
		}

		internal static Fill Measure(Area a)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			Fill result = default(Fill);
			Maps(a);
			HashSet<long> hashSet = new HashSet<long>();
			bool flag = false;
			foreach (Heightmap map in maps)
			{
				TerrainComp comp = TerrainComp.FindTerrainCompiler(((Component)map).transform.position);
				int num = map.m_width + 1;
				float num2 = map.m_scale * map.m_scale;
				foreach (var (num3, num4, val) in Vertices(map, a))
				{
					if (hashSet.Add(((long)Mathf.RoundToInt(val.x * 4f) << 32) ^ (uint)Mathf.RoundToInt(val.z * 4f)))
					{
						float num5 = ((Component)map).transform.position.y + map.GetHeight(num3, num4);
						float num6 = num5 - a.Anchor.y;
						if (!flag || num6 < result.Low)
						{
							result.Low = num6;
							flag = true;
						}
						float num7 = Target(a, comp, num4 * num + num3, num5) - num5;
						if (num7 > 0f)
						{
							result.Up += num7 * num2;
						}
						else
						{
							result.Down -= num7 * num2;
						}
					}
				}
			}
			return result;
		}

		private static void Register()
		{
			if (ZRoutedRpc.instance != null && registered != ZRoutedRpc.instance)
			{
				registered = ZRoutedRpc.instance;
				registered.Register<long, ZDOID>("BuildExtend_RaiseDone", (Action<long, long, ZDOID>)OnDone);
			}
		}

		internal static void Apply(Area a)
		{
			//IL_0175: 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_008f: Expected O, but got Unknown
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			Register();
			Maps(a);
			long num = ((long)Random.Range(int.MinValue, int.MaxValue) << 32) ^ Time.frameCount;
			foreach (Heightmap map in maps)
			{
				TerrainComp andCreateTerrainCompiler = map.GetAndCreateTerrainCompiler();
				if (!((Object)(object)andCreateTerrainCompiler == (Object)null) && !((Object)(object)andCreateTerrainCompiler.m_nview == (Object)null) && andCreateTerrainCompiler.m_nview.IsValid())
				{
					if (andCreateTerrainCompiler.m_nview.IsOwner())
					{
						Change(andCreateTerrainCompiler, a);
						continue;
					}
					ZPackage val = new ZPackage();
					val.Write(2);
					val.Write(num);
					val.Write(a.Anchor);
					val.Write(a.Fwd);
					val.Write(a.A0);
					val.Write(a.A1);
					val.Write(a.Half);
					val.Write(a.Top);
					val.Write(a.Level);
					val.Write(a.Op);
					andCreateTerrainCompiler.m_nview.InvokeRPC("BuildExtend_RaiseArea", new object[1] { val });
					pending.Add(new Pending
					{
						Id = num,
						Comp = andCreateTerrainCompiler,
						Area = a,
						Since = Time.unscaledTime
					});
				}
			}
			if ((Object)(object)ClutterSystem.instance != (Object)null)
			{
				ClutterSystem.instance.ResetGrass(Center(a), Radius(a));
			}
		}

		internal static void Tick()
		{
			for (int num = Ground.pending.Count - 1; num >= 0; num--)
			{
				Pending pending = Ground.pending[num];
				if ((Object)(object)pending.Comp == (Object)null || (Object)(object)pending.Comp.m_nview == (Object)null || !pending.Comp.m_nview.IsValid())
				{
					Ground.pending.RemoveAt(num);
				}
				else if (!(Time.unscaledTime - pending.Since < 3f))
				{
					Ground.pending.RemoveAt(num);
					Plugin.Warn("area raise: the ground's owner did not answer (no BuildExtend there?), changing it here");
					pending.Comp.m_nview.ClaimOwnership();
					Change(pending.Comp, pending.Area);
				}
			}
		}

		private static void OnDone(long sender, long id, ZDOID zdo)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			pending.RemoveAll((Pending p) => p.Id == id && ((Object)(object)p.Comp == (Object)null || (Object)(object)p.Comp.m_nview == (Object)null || !p.Comp.m_nview.IsValid() || p.Comp.m_nview.GetZDO().m_uid == zdo));
		}

		internal static void Listen(TerrainComp comp)
		{
			if (!((Object)(object)comp.m_nview == (Object)null))
			{
				comp.m_nview.Register<ZPackage>("BuildExtend_RaiseArea", (Action<long, ZPackage>)delegate(long sender, ZPackage pkg)
				{
					OnChange(comp, sender, pkg);
				});
			}
		}

		private static void OnChange(TerrainComp comp, long sender, ZPackage pkg)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)comp == (Object)null || !comp.m_nview.IsValid() || !comp.m_nview.IsOwner())
			{
				return;
			}
			int num = pkg.ReadInt();
			if (num >= 1 && num <= 2)
			{
				long num2 = pkg.ReadLong();
				Area a = new Area
				{
					Anchor = pkg.ReadVector3(),
					Up = Vector3.up,
					Fwd = pkg.ReadVector3(),
					A0 = pkg.ReadSingle(),
					A1 = pkg.ReadSingle(),
					Half = pkg.ReadSingle(),
					Top = pkg.ReadSingle()
				};
				if (num >= 2)
				{
					a.Level = pkg.ReadBool();
					a.Op = pkg.ReadInt();
				}
				Change(comp, a);
				Register();
				if (ZRoutedRpc.instance != null && sender != ZNet.GetUID())
				{
					ZRoutedRpc.instance.InvokeRoutedRPC(sender, "BuildExtend_RaiseDone", new object[2]
					{
						num2,
						comp.m_nview.GetZDO().m_uid
					});
				}
			}
		}

		private static void Change(TerrainComp comp, Area a)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)comp == (Object)null || !comp.m_initialized || (Object)(object)comp.m_hmap == (Object)null || comp.m_hmap.m_heights == null)
			{
				return;
			}
			Heightmap hmap = comp.m_hmap;
			int num = comp.m_width + 1;
			float y = ((Component)comp).transform.position.y;
			bool flag = false;
			foreach (var item3 in Vertices(hmap, a))
			{
				int item = item3.x;
				int item2 = item3.y;
				int num2 = item2 * num + item;
				if (num2 >= 0 && num2 < comp.m_levelDelta.Length)
				{
					float num3 = y + hmap.GetHeight(item, item2);
					float num4 = Target(a, comp, num2, num3) - num3;
					if (!(Mathf.Abs(num4) <= 0.001f))
					{
						comp.m_levelDelta[num2] = Mathf.Clamp(comp.m_levelDelta[num2] + num4 + comp.m_smoothDelta[num2], -8f, 8f);
						comp.m_smoothDelta[num2] = 0f;
						comp.m_modifiedHeight[num2] = true;
						flag = true;
					}
				}
			}
			bool flag2 = a.Level && Paint(comp, a);
			if (flag || flag2)
			{
				comp.Save(false);
				hmap.Poke(1, false);
				if ((Object)(object)ClutterSystem.instance != (Object)null)
				{
					ClutterSystem.instance.ResetGrass(Center(a), Radius(a));
				}
			}
		}

		private static bool Paint(TerrainComp comp, Area a)
		{
			//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_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			TerrainOp val = default(TerrainOp);
			if (a.Op == 0 || (Object)(object)ObjectDB.instance == (Object)null || !ObjectDB.instance.TryGetTerrainOp(a.Op, ref val) || (Object)(object)val == (Object)null)
			{
				return false;
			}
			Settings settings = val.m_settings;
			if (!settings.m_paintCleared)
			{
				return false;
			}
			float num = Mathf.Max(0.5f, settings.m_paintRadius);
			Vector3 val2 = Side(a);
			float y = a.Anchor.y + a.Top;
			int num2 = Mathf.Max(1, Mathf.CeilToInt((a.A1 - a.A0) / num));
			int num3 = Mathf.Max(1, Mathf.CeilToInt(2f * a.Half / num));
			for (int i = 0; i <= num2; i++)
			{
				for (int j = 0; j <= num3; j++)
				{
					Vector3 val3 = a.Anchor + a.Fwd * Mathf.Lerp(a.A0, a.A1, (float)i / (float)num2) + val2 * Mathf.Lerp(0f - a.Half, a.Half, (float)j / (float)num3);
					val3.y = y;
					comp.PaintCleared(val3, Vector3.zero, settings);
				}
			}
			return true;
		}
	}
	[HarmonyPatch]
	internal static class Hooks
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		[HarmonyPatch(typeof(Player), "UpdatePlacement")]
		private static bool Placement(Player __instance, bool takeInput)
		{
			try
			{
				return Stretch.BeforePlacement(__instance, takeInput);
			}
			catch (Exception ex)
			{
				Plugin.Warn("placement: " + ex);
				Stretch.Cancel();
				return true;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "UpdatePlacementGhost")]
		private static void Ghost(Player __instance)
		{
			if ((Stretch.HidesGhost || Hoe.Busy) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				if ((Object)(object)__instance.m_placementGhost != (Object)null)
				{
					__instance.m_placementGhost.SetActive(false);
				}
				if ((Object)(object)__instance.m_placementMarkerInstance != (Object)null)
				{
					__instance.m_placementMarkerInstance.SetActive(false);
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Hud), "SetupPieceInfo")]
		private static void PieceInfo(Hud __instance, Piece piece)
		{
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Invalid comparison between Unknown and I4
			//IL_03fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0406: Invalid comparison between Unknown and I4
			//IL_040d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0417: Invalid comparison between Unknown and I4
			//IL_045b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0460: Unknown result type (might be due to invalid IL or missing references)
			//IL_041e: Unknown result type (might be due to invalid IL or missing references)
			//IL_042a: Unknown result type (might be due to invalid IL or missing references)
			//IL_042f: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)piece == (Object)null || (Object)(object)localPlayer == (Object)null)
				{
					return;
				}
				if (Hoe.Busy)
				{
					if (!((Object)(object)piece != (Object)(object)Hoe.Piece))
					{
						for (int i = 0; i < piece.m_resources.Length && i < __instance.m_requirementItems.Length; i++)
						{
							InventoryGui.SetupRequirement(__instance.m_requirementItems[i].transform, piece.m_resources[i], localPlayer, false, 0, Hoe.Ops);
						}
						TMP_Text buildSelection = __instance.m_buildSelection;
						buildSelection.text += $" ×{Hoe.Ops}";
						__instance.m_pieceDescription.text = Hoe.Description();
					}
					return;
				}
				if (Plugin.KeyHint.Value && (Object)(object)piece == (Object)(object)localPlayer.GetSelectedPiece())
				{
					string text = Hoe.Refuse(localPlayer, piece);
					if (text == null)
					{
						TMP_Text pieceDescription = __instance.m_pieceDescription;
						pieceDescription.text = pieceDescription.text + "\n" + Plugin.Hint(Plugin.T("удерживать ЛКМ и вести", "hold LMB and look")) + " " + Plugin.T("выровнять по высоте", "level to height");
						return;
					}
					if (text != "")
					{
						TMP_Text pieceDescription2 = __instance.m_pieceDescription;
						pieceDescription2.text = pieceDescription2.text + "\n" + text;
						return;
					}
				}
				if (Stretch.Removing)
				{
					__instance.m_pieceDescription.text = Stretch.Description();
				}
				else if (Stretch.ShowsPanel)
				{
					if (!((Object)(object)piece != (Object)(object)Stretch.Prefab))
					{
						int num = Math.Max(1, Stretch.Segments);
						bool flag = (int)piece.FreeBuildKey() == 25;
						for (int j = 0; j < piece.m_resources.Length && j < __instance.m_requirementItems.Length; j++)
						{
							InventoryGui.SetupRequirement(__instance.m_requirementItems[j].transform, piece.m_resources[j], localPlayer, flag, 0, num);
						}
						TMP_Text buildSelection2 = __instance.m_buildSelection;
						buildSelection2.text += $" ×{Stretch.Segments}";
						__instance.m_pieceDescription.text = Stretch.Description();
					}
				}
				else if (Plugin.Enabled.Value && Plugin.KeyHint.Value && !((Object)(object)piece != (Object)(object)localPlayer.GetSelectedPiece()) && !((Object)(object)((Component)piece).GetComponent<TerrainOp>() != (Object)null) && !((Object)(object)((Component)piece).GetComponent<TerrainModifier>() != (Object)null))
				{
					string text2 = "   " + Plugin.Hint(Stretch.ModeKey() + Plugin.T("колесо", "wheel")) + " " + Plugin.T("режим", "mode");
					if (Plugin.Hammer.Value == HammerMode.Normal)
					{
						TMP_Text pieceDescription = __instance.m_pieceDescription;
						pieceDescription.text = pieceDescription.text + "\n" + Plugin.Hint(Stretch.ModeKey() + Plugin.T("колесо", "wheel")) + " " + Plugin.T("режим молота: обычная стройка (x1)", "hammer mode: normal building (x1)");
					}
					else if (Checks.Refuse(piece) == null)
					{
						TMP_Text pieceDescription = __instance.m_pieceDescription;
						pieceDescription.text = pieceDescription.text + "\n" + Plugin.Hint(Plugin.T("удерживать ЛКМ", "hold LMB")) + " " + Plugin.T("протянуть", "stretch") + (Plugin.StretchRemoval.Value ? ("   " + Plugin.Hint(Plugin.T("удерживать СКМ и вести", "hold MMB and look")) + " " + Plugin.T("снести зону", "remove a zone")) : "") + "   " + Plugin.Hint((((int)Plugin.UndoModifier.Value == 306 || (int)Plugin.UndoModifier.Value == 305) ? "Ctrl+" : (((int)Plugin.UndoModifier.Value == 0) ? "" : (((object)Plugin.UndoModifier.Value/*cast due to .constrained prefix*/).ToString() + "+"))) + ((object)Plugin.UndoKey.Value/*cast due to .constrained prefix*/).ToString()) + " " + Plugin.T("отменить", "undo") + text2;
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Warn("build panel: " + ex.Message);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(TerrainComp), "Awake")]
		private static void TerrainListen(TerrainComp __instance)
		{
			try
			{
				Ground.Listen(__instance);
			}
			catch (Exception ex)
			{
				Plugin.Warn("terrain: " + ex.Message);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(GameCamera), "UpdateCamera")]
		private static void CameraBefore(GameCamera __instance, out float __state)
		{
			__state = __instance.m_distance;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(GameCamera), "UpdateCamera")]
		private static void CameraAfter(GameCamera __instance, float __state)
		{
			if (Hoe.Busy)
			{
				__instance.m_distance = __state;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Menu), "Update")]
		private static void Escape(Menu __instance)
		{
			if (Stretch.EatEscape())
			{
				__instance.m_hiddenFrames = 0;
			}
		}
	}
	[HarmonyPatch]
	internal static class IronHoe
	{
		internal const string Name = "BuildExtend_HoeIron";

		private const string Token = "be_hoe_iron";

		private static GameObject prefab;

		private const string LevelName = "BuildExtend_LevelHeight";

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

		private static readonly List<Requirement[]> ours = new List<Requirement[]>();

		internal static bool Made => (Object)(object)prefab != (Object)null;

		internal static bool Is(ItemData item)
		{
			if (item != null && (Object)(object)item.m_dropPrefab != (Object)null)
			{
				return ((Object)item.m_dropPrefab).name == "BuildExtend_HoeIron";
			}
			return false;
		}

		private static GameObject Make(GameObject hoe)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Expected O, but got Unknown
			//IL_00a3: Expected O, but got Unknown
			if ((Object)(object)prefab != (Object)null)
			{
				return prefab;
			}
			if ((Object)(object)hoe == (Object)null)
			{
				return null;
			}
			GameObject val = new GameObject("BuildExtend prefabs");
			val.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)val);
			GameObject val2 = Object.Instantiate<GameObject>(hoe, val.transform);
			((Object)val2).name = "BuildExtend_HoeIron";
			ItemDrop component = val2.GetComponent<ItemDrop>();
			SharedData val3 = component.m_itemData.m_shared;
			if (val3 == hoe.GetComponent<ItemDrop>().m_itemData.m_shared)
			{
				ItemData itemData = component.m_itemData;
				SharedData val4 = (SharedData)typeof(object).GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(val3, null);
				val3 = val4;
				itemData.m_shared = val4;
			}
			val3.m_name = "$be_hoe_iron";
			val3.m_description = "$be_hoe_iron_description";
			val3.m_maxQuality = 1;
			SharedData obj = val3;
			obj.m_maxDurability *= 1.5f;
			Material val5 = null;
			Renderer[] componentsInChildren = val2.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val6 in componentsInChildren)
			{
				Material[] sharedMaterials = val6.sharedMaterials;
				bool flag = false;
				for (int j = 0; j < sharedMaterials.Length; j++)
				{
					if (!((Object)(object)sharedMaterials[j] == (Object)null) && ((Object)sharedMaterials[j]).name.StartsWith("stone", StringComparison.OrdinalIgnoreCase))
					{
						sharedMaterials[j] = val5 ?? (val5 = Metal(sharedMaterials[j]));
						flag = true;
					}
				}
				if (flag)
				{
					val6.sharedMaterials = sharedMaterials;
				}
			}
			Pieces(val.transform, val3);
			prefab = val2;
			return prefab;
		}

		private static Material Metal(Material stone)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			//IL_0018: 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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			//IL_0159: 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_00e9: Unknown result type (might be due to invalid IL or missing references)
			Material val = new Material(stone)
			{
				name = "BuildExtend iron head"
			};
			Texture2D val2 = new Texture2D(32, 32, (TextureFormat)4, true)
			{
				name = "BuildExtend iron",
				wrapMode = (TextureWrapMode)0,
				filterMode = (FilterMode)1
			};
			Random random = new Random(1337);
			float[] array = new float[32];
			for (int i = 0; i < 32; i++)
			{
				array[i] = (float)random.NextDouble() * 0.12f - 0.06f;
			}
			Color[] array2 = (Color[])(object)new Color[1024];
			for (int j = 0; j < 32; j++)
			{
				for (int k = 0; k < 32; k++)
				{
					float num = 0.62f + array[j] + (float)random.NextDouble() * 0.05f - 0.025f;
					if (random.NextDouble() < 0.02)
					{
						num -= 0.18f;
					}
					array2[j * 32 + k] = new Color(num * 0.96f, num * 0.98f, num, 1f);
				}
			}
			val2.SetPixels(array2);
			val2.Apply(true, true);
			if (val.HasProperty("_MainTex"))
			{
				val.SetTexture("_MainTex", (Texture)(object)val2);
			}
			if (val.HasProperty("_Color"))
			{
				val.SetColor("_Color", new Color(0.78f, 0.8f, 0.84f, 1f));
			}
			if (val.HasProperty("_Metallic"))
			{
				val.SetFloat("_Metallic", 0.85f);
			}
			if (val.HasProperty("_Glossiness"))
			{
				val.SetFloat("_Glossiness", 0.6f);
			}
			if (val.HasProperty("_MetalGloss"))
			{
				val.SetFloat("_MetalGloss", 0.6f);
			}
			return val;
		}

		internal static bool IsAreaPiece(Piece p)
		{
			if ((Object)(object)p != (Object)null)
			{
				return sources.ContainsKey(Utils.GetPrefabName(((Component)p).gameObject));
			}
			return false;
		}

		internal static string Source(Piece p)
		{
			if (!((Object)(object)p != (Object)null) || !sources.TryGetValue(Utils.GetPrefabName(((Component)p).gameObject), out var value))
			{
				return null;
			}
			return value;
		}

		private static void Pieces(Transform holder, SharedData shared)
		{
			PieceTable table = shared.m_buildPieces;
			PieceTable own;
			if (!((Object)(object)table == (Object)null))
			{
				own = Object.Instantiate<GameObject>(((Component)table).gameObject, holder).GetComponent<PieceTable>();
				((Object)own).name = "BuildExtend_HoeIronPieces";
				own.m_pieces = new List<GameObject>(table.m_pieces);
				GameObject obj = Find((Settings s) => s.m_raise && s.m_raiseDelta > 0f, "raise");
				if ((Object)(object)obj == (Object)null)
				{
					Plugin.Warn("iron hoe: no raise piece in the hoe's table, no \"Level to height\"");
				}
				Kin(obj, "BuildExtend_LevelHeight", "be_level_height");
				shared.m_buildPieces = own;
			}
			GameObject Find(Func<Settings, bool> fits, string hint)
			{
				List<GameObject> source = table.m_pieces.Where(delegate(GameObject g)
				{
					if ((Object)(object)g != (Object)null)
					{
						TerrainOp component = g.GetComponent<TerrainOp>();
						if (component != null)
						{
							return fits(component.m_settings);
						}
					}
					return false;
				}).ToList();
				return ((IEnumerable<GameObject>)source).FirstOrDefault((Func<GameObject, bool>)((GameObject g) => ((Object)g).name.IndexOf(hint, StringComparison.OrdinalIgnoreCase) >= 0)) ?? source.FirstOrDefault();
			}
			void Kin(GameObject source, string name, string token)
			{
				if (!((Object)(object)source == (Object)null))
				{
					GameObject val = Object.Instantiate<GameObject>(source, holder);
					((Object)val).name = name;
					Piece component = val.GetComponent<Piece>();
					component.m_name = "$" + token;
					component.m_description = "$" + token + "_description";
					component.m_icon = AreaIcon(component.m_icon);
					own.m_pieces.Insert(own.m_pieces.IndexOf(source) + 1, val);
					sources[name] = ((Object)source).name;
					Plugin.Log("iron hoe: \"" + name + "\" after \"" + ((Object)source).name + "\"");
				}
			}
		}

		private static Sprite AreaIcon(Sprite icon)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: 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_00a9: Expected O, but got Unknown
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)icon == (Object)null || (Object)(object)icon.texture == (Object)null)
			{
				return icon;
			}
			RenderTexture val = null;
			RenderTexture active = RenderTexture.active;
			try
			{
				Rect textureRect = icon.textureRect;
				int num = Mathf.RoundToInt(((Rect)(ref textureRect)).width);
				int num2 = Mathf.RoundToInt(((Rect)(ref textureRect)).height);
				if (num < 8 || num2 < 8)
				{
					return icon;
				}
				val = RenderTexture.GetTemporary(((Texture)icon.texture).width, ((Texture)icon.texture).height, 0, (RenderTextureFormat)0);
				Graphics.Blit((Texture)(object)icon.texture, val);
				RenderTexture.active = val;
				Texture2D val2 = new Texture2D(num, num2, (TextureFormat)4, false)
				{
					name = "BuildExtend area icon",
					filterMode = (FilterMode)1,
					wrapMode = (TextureWrapMode)1
				};
				val2.ReadPixels(new Rect(((Rect)(ref textureRect)).x, ((Rect)(ref textureRect)).y, (float)num, (float)num2), 0, 0);
				Color val3 = default(Color);
				((Color)(ref val3))..ctor(1f, 0.8f, 0.2f, 1f);
				int num3 = Mathf.Max(2, num / 24);
				int num4 = Mathf.Max(1, num / 16);
				for (int i = num4; i < num2 - num4; i++)
				{
					for (int j = num4; j < num - num4; j++)
					{
						bool num5 = j < num4 + num3 || j >= num - num4 - num3 || i < num4 + num3 || i >= num2 - num4 - num3;
						bool flag = (j < num4 + num / 5 || j >= num - num4 - num / 5) && (i < num4 + num2 / 5 || i >= num2 - num4 - num2 / 5);
						bool flag2 = (j + i) / Mathf.Max(1, num / 8) % 2 == 0;
						if (num5 && (flag || flag2))
						{
							val2.SetPixel(j, i, val3);
						}
					}
				}
				val2.Apply();
				return Sprite.Create(val2, new Rect(0f, 0f, (float)num, (float)num2), new Vector2(0.5f, 0.5f), icon.pixelsPerUnit);
			}
			catch (Exception ex)
			{
				Plugin.Warn("iron hoe icon: " + ex.Message);
				return icon;
			}
			finally
			{
				RenderTexture.active = active;
				if ((Object)(object)val != (Object)null)
				{
					RenderTexture.ReleaseTemporary(val);
				}
			}
		}

		internal static void Words()
		{
			Localization instance = Localization.instance;
			if (instance != null)
			{
				Dictionary<string, string> value = Traverse.Create((object)instance).Field("m_translations").GetValue<Dictionary<string, string>>();
				if (value != null)
				{
					value["be_hoe_iron"] = Plugin.T("Железная мотыга", "Iron hoe");
					value["be_hoe_iron_description"] = Plugin.T("Мотыга с железным наконечником. Делается в кузнице из мотыги 3 уровня и железа. Кроме обычных «Выровнять землю» и «Поднять землю» умеет «Выровнять по высоте»: зажать ЛКМ и вести взгляд вперёд, колесо — ширина, Ctrl+колесо — высота.", "A hoe with an iron head, made at the forge from a level 3 hoe and iron. Besides the usual \"Level ground\" and \"Raise ground\" it has \"Level to height\": hold LMB and look ahead, wheel - width, Ctrl+wheel - height.");
					value["be_level_height"] = Plugin.T("Выровнять по высоте", "Level to height");
					value["be_level_height_description"] = Plugin.T("Зажать ЛКМ и вести взгляд вперёд — прямоугольник по взгляду; колесо — ширина, Ctrl+колесо — высота (от точки нажатия). Всё внутри встаёт ровно на эту высоту: выше срезается, ниже подсыпается, края прямые. Срез бесплатно, подсыпка — камень по объёму. Щелчок — полоса шириной в рамку.", "Hold LMB and look ahead - a rectangle along the look; wheel - width, Ctrl+wheel - height (from the press point). Everything inside goes to that height: cut above, filled below, straight edges. Cutting is free, filling costs stone by the volume. A click - a strip as wide as the frame.");
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		private static void Scene(ZNetScene __instance)
		{
			try
			{
				if (Plugin.IronHoeOn.Value)
				{
					GameObject val = Make(((IEnumerable<GameObject>)__instance.m_prefabs).FirstOrDefault((Func<GameObject, bool>)((GameObject p) => (Object)(object)p != (Object)null && ((Object)p).name == "Hoe")));
					if ((Object)(object)val != (Object)null && !__instance.m_prefabs.Contains(val))
					{
						__instance.m_prefabs.Add(val);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Warn("iron hoe (scene): " + ex.Message);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		private static void Items(ObjectDB __instance)
		{
			Add(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
		private static void ItemsCopied(ObjectDB __instance)
		{
			Add(__instance);
		}

		private static void Add(ObjectDB db)
		{
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Expected O, but got Unknown
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Expected O, but got Unknown
			try
			{
				if (!Plugin.IronHoeOn.Value)
				{
					return;
				}
				GameObject itemPrefab = db.GetItemPrefab("Hoe");
				GameObject itemPrefab2 = db.GetItemPrefab("Iron");
				ItemDrop val = ((itemPrefab2 != null) ? itemPrefab2.GetComponent<ItemDrop>() : null);
				GameObject val2 = Make(itemPrefab);
				if ((Object)(object)val2 == (Object)null || (Object)(object)val == (Object)null)
				{
					return;
				}
				Words();
				if (!db.m_items.Contains(val2))
				{
					db.m_items.Add(val2);
					db.UpdateRegisters();
				}
				ItemDrop drop = val2.GetComponent<ItemDrop>();
				if (!db.m_recipes.Any((Recipe r) => (Object)(object)r != (Object)null && (Object)(object)r.m_item == (Object)(object)drop))
				{
					CraftingStation val3 = db.m_recipes.Select((Recipe r) => (!((Object)(object)r != (Object)null)) ? null : r.m_craftingStation).FirstOrDefault((Func<CraftingStation, bool>)((CraftingStation s) => (Object)(object)s != (Object)null && s.m_name == "$piece_forge"));
					Recipe val4 = ScriptableObject.CreateInstance<Recipe>();
					((Object)val4).name = "Recipe_BuildExtend_HoeIron";
					val4.m_item = drop;
					val4.m_amount = 1;
					val4.m_enabled = true;
					val4.m_craftingStation = val3;
					val4.m_repairStation = val3;
					val4.m_minStationLevel = 1;
					val4.m_resources = (Requirement[])(object)new Requirement[2]
					{
						new Requirement
						{
							m_resItem = itemPrefab.GetComponent<ItemDrop>(),
							m_amount = 1,
							m_recover = true
						},
						new Requirement
						{
							m_resItem = val,
							m_amount = Math.Max(1, Plugin.IronHoeIron.Value),
							m_recover = true
						}
					};
					db.m_recipes.Add(val4);
					ours.Add(val4.m_resources);
				}
			}
			catch (Exception ex)
			{
				Plugin.Warn("iron hoe: " + ex.Message);
			}
		}

		private static bool IsOurs(Recipe r)
		{
			if ((Object)(object)r != (Object)null && r.m_resources != null)
			{
				return ours.Contains(r.m_resources);
			}
			return false;
		}

		private static bool Full(ItemData i, string hoeName)
		{
			if (i != null && i.m_shared.m_name == hoeName)
			{
				return i.m_quality >= i.m_shared.m_maxQuality;
			}
			return false;
		}

		internal static int MaxLevel(ObjectDB db)
		{
			int? obj;
			if (db == null)
			{
				obj = null;
			}
			else
			{
				GameObject itemPrefab = db.GetItemPrefab("Hoe");
				obj = ((itemPrefab == null) ? ((int?)null) : itemPrefab.GetComponent<ItemDrop>()?.m_itemData.m_shared.m_maxQuality);
			}
			return obj ?? 3;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "HaveRequirementItems")]
		private static void Enough(Player __instance, Recipe piece, int amount, ref bool __result)
		{
			try
			{
				if (__result && IsOurs(piece))
				{
					string hoeName = piece.m_resources[0].m_resItem.m_itemData.m_shared.m_name;
					if (((Humanoid)__instance).GetInventory().GetAllItems().Count((ItemData i) => Full(i, hoeName)) < Math.Max(1, amount))
					{
						__result = false;
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Warn("iron hoe recipe: " + ex.Message);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "ConsumeResources")]
		private static bool Take(Player __instance, Requirement[] requirements, int multiplier)
		{
			try
			{
				if (requirements == null || !ours.Contains(requirements))
				{
					return true;
				}
				Inventory inventory = ((Humanoid)__instance).GetInventory();
				string hoeName = requirements[0].m_resItem.m_itemData.m_shared.m_name;
				for (int i = 0; i < Math.Max(1, multiplier); i++)
				{
					ItemData val = ((IEnumerable<ItemData>)inventory.GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData i2) => Full(i2, hoeName)));
					if (val == null)
					{
						break;
					}
					inventory.RemoveItem(val);
				}
				for (int num = 1; num < requirements.Length; num++)
				{
					Requirement val2 = requirements[num];
					int num2 = val2.GetAmount(1) * Math.Max(1, multiplier);
					if ((Object)(object)val2.m_resItem != (Object)null && num2 > 0)
					{
						inventory.RemoveItem(val2.m_resItem.m_itemData.m_shared.m_name, num2, -1, true);
					}
				}
				return false;
			}
			catch (Exception ex)
			{
				Plugin.Warn("iron hoe recipe: " + ex.Message);
				return true;
			}
		}
	}
	[HarmonyPatch]
	internal static class IronHoeLanguage
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.GetDeclaredMethods(typeof(Localization)).FirstOrDefault((MethodInfo m) => m.Name == "SetupLanguage");
		}

		private static bool Prepare()
		{
			return TargetMethod() != null;
		}

		private static void Postfix()
		{
			try
			{
				if (IronHoe.Made)
				{
					IronHoe.Words();
				}
			}
			catch (Exception ex)
			{
				Plugin.Warn("iron hoe words: " + ex.Message);
			}
		}
	}
	internal struct Vec
	{
		public float X;

		public float Y;

		public float Z;

		public float Length => (float)Math.Sqrt(Dot(this, this));

		public float this[int axis] => axis switch
		{
			1 => Y, 
			0 => X, 
			_ => Z, 
		};

		public Vec(float x, float y, float z)
		{
			X = x;
			Y = y;
			Z = z;
		}

		public static Vec operator +(Vec a, Vec b)
		{
			return new Vec(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
		}

		public static Vec operator -(Vec a, Vec b)
		{
			return new Vec(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
		}

		public static Vec operator *(Vec a, float k)
		{
			return new Vec(a.X * k, a.Y * k, a.Z * k);
		}

		public static float Dot(Vec a, Vec b)
		{
			return a.X * b.X + a.Y * b.Y + a.Z * b.Z;
		}

		public static Vec Cross(Vec a, Vec b)
		{
			return new Vec(a.Y * b.Z - a.Z * b.Y, a.Z * b.X - a.X * b.Z, a.X * b.Y - a.Y * b.X);
		}

		public static Vec Axis(int axis, float length)
		{
			return new Vec((axis == 0) ? length : 0f, (axis == 1) ? length : 0f, (axis == 2) ? length : 0f);
		}

		public override string ToString()
		{
			return $"({X:0.##}, {Y:0.##}, {Z:0.##})";
		}
	}
	internal enum ShapeKind
	{
		None,
		Line,
		Plane
	}
	internal sealed class Shape
	{
		public ShapeKind Kind;

		public Vec U;

		public Vec V;

		public Vec W;

		public bool Cube;

		public bool Beam;

		public bool Pole;

		public override string ToString()
		{
			if (Kind != ShapeKind.None)
			{
				Vec u;
				if (Kind != ShapeKind.Line)
				{
					string obj = (Cube ? "cube " : "plane ");
					u = U;
					string text = u.ToString();
					u = V;
					return obj + text + " × " + u.ToString();
				}
				u = U;
				return "line " + u.ToString();
			}
			return "none";
		}
	}
	internal static class Lattice
	{
		internal struct Cell
		{
			public int I;

			public int J;

			public Vec Pos;

			public Vec Dir;

			public Vec Up;
		}

		private const float Min = 0.05f;

		internal static Shape FromPiece(IList<Vec> snaps, Vec boundsMin, Vec boundsMax, bool beamsTouching = false)
		{
			Vec vec = boundsMax - boundsMin;
			if (snaps != null && snaps.Count >= 2)
			{
				Shape shape = FromSnaps(snaps);
				if (shape.Beam && beamsTouching)
				{
					if (!shape.Pole)
					{
						if (vec.Y > 0.05f)
						{
							shape.V = Vec.Axis(1, vec.Y);
						}
					}
					else if (vec.X > 0.05f)
					{
						shape.U = Vec.Axis(0, vec.X);
					}
				}
				if (shape.Kind != ShapeKind.None)
				{
					return shape;
				}
			}
			bool flag = vec.X > 0.05f;
			bool flag2 = vec.Z > 0.05f;
			if (flag && flag2)
			{
				return new Shape
				{
					Kind = ShapeKind.Plane,
					U = Vec.Axis(0, vec.X),
					V = Vec.Axis(2, vec.Z)
				};
			}
			if (flag)
			{
				return new Shape
				{
					Kind = Sh