Decompiled source of FarmHand v1.0.0

plugins/FarmHand.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace FarmHand
{
	[HarmonyPatch(typeof(Plant), "GetHoverText")]
	internal static class PlantHoverPatch
	{
		private const string Good = "#9FE07A";

		private const string Warn = "#FFB44A";

		private const string Bad = "#FF7A6A";

		private const string Dim = "#BFB29C";

		private static bool Showing
		{
			get
			{
				if (Plugin.Enabled.Value)
				{
					if (Plugin.CropInfo.Value != InfoMode.Always)
					{
						if (Plugin.CropInfo.Value == InfoMode.FarmModeOnly)
						{
							return FarmMode.On;
						}
						return false;
					}
					return true;
				}
				return false;
			}
		}

		private static void Postfix(Plant __instance, ref string __result)
		{
			if (!Showing || string.IsNullOrEmpty(__result))
			{
				return;
			}
			try
			{
				__result += Describe(__instance);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogDebug((object)("Crop info failed: " + ex.Message));
			}
		}

		internal unsafe static string Describe(Plant plant)
		{
			//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_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Invalid comparison between Unknown and I4
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			StringBuilder stringBuilder = new StringBuilder();
			Status status = plant.GetStatus();
			if (Crops.Growth(plant, out var progress, out var secondsLeft))
			{
				string text = ((secondsLeft <= 0.0) ? Lang.T("ready_soon") : Lang.T("time_left", Lang.Duration(secondsLeft)));
				stringBuilder.Append("\n<size=85%><color=#9FE07A>" + Bar(progress) + "</color> " + Lang.T("growth", Mathf.FloorToInt(progress * 100f)) + " <color=#BFB29C>· " + text + "</color></size>");
			}
			if ((int)status == 0)
			{
				stringBuilder.Append("\n<size=80%><color=#9FE07A>" + Lang.T("ok") + "</color></size>");
			}
			else
			{
				string key = "st_" + ((object)(*(Status*)(&status))/*cast due to .constrained prefix*/).ToString();
				string text2 = (((int)status == 3) ? Lang.T(key, Crops.BiomeNames(plant.m_biome)) : (Lang.Has(key) ? Lang.T(key) : Lang.T("st_other", status)));
				stringBuilder.Append("\n<size=85%><color=#FF7A6A>" + text2 + "</color></size>");
				stringBuilder.Append("\n<size=75%><color=#FFB44A>" + Lang.T(plant.m_destroyIfCantGrow ? "will_wither" : "wont_grow") + "</color></size>");
			}
			return stringBuilder.ToString();
		}

		private static string Bar(float progress)
		{
			int num = Mathf.Clamp(Mathf.RoundToInt(progress * 10f), 0, 10);
			return "[" + new string('|', num) + "<alpha=#44>" + new string('|', 10 - num) + "<alpha=#FF>]";
		}
	}
	[HarmonyPatch(typeof(Pickable), "GetHoverText")]
	internal static class RipeHoverPatch
	{
		private static void Postfix(Pickable __instance, ref string __result)
		{
			if (!string.IsNullOrEmpty(__result) && FarmMode.On && Plugin.Helpers && Plugin.MassHarvest.Value && Crops.IsCrop(__instance))
			{
				__result = __result + "\n<size=80%><color=#FFC766>" + Lang.T("ripe_hint", Mathf.RoundToInt(Plugin.HarvestRadius.Value)) + "</color></size>";
			}
		}
	}
	internal static class Crops
	{
		private static readonly MethodInfo TimeSincePlantedMethod = AccessTools.Method(typeof(Plant), "TimeSincePlanted", (Type[])null, (Type[])null);

		private static readonly MethodInfo GetGrowTimeMethod = AccessTools.Method(typeof(Plant), "GetGrowTime", (Type[])null, (Type[])null);

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

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

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

		private static ZNetScene _indexedScene;

		public static float SpaceRadius(Plant plant)
		{
			return plant.m_growRadius;
		}

		public static float Spacing(Plant plant)
		{
			return Mathf.Max(0.3f, plant.m_growRadius * 2f + Plugin.ExtraSpacing.Value);
		}

		private static void EnsureIndex()
		{
			ZNetScene instance = ZNetScene.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance == (Object)(object)_indexedScene)
			{
				return;
			}
			_indexedScene = instance;
			PlantByCrop.Clear();
			PieceBySeed.Clear();
			SourceOfItem.Clear();
			foreach (GameObject prefab in instance.m_prefabs)
			{
				if ((Object)(object)prefab == (Object)null)
				{
					continue;
				}
				Plant component = prefab.GetComponent<Plant>();
				Piece component2 = prefab.GetComponent<Piece>();
				if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || component.m_grownPrefabs == null)
				{
					continue;
				}
				bool flag = false;
				GameObject[] grownPrefabs = component.m_grownPrefabs;
				foreach (GameObject val in grownPrefabs)
				{
					Pickable val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Pickable>() : null);
					if (!((Object)(object)val2 == (Object)null))
					{
						flag = true;
						if (!PlantByCrop.ContainsKey(((Object)val).name))
						{
							PlantByCrop[((Object)val).name] = prefab;
						}
						if ((Object)(object)val2.m_itemPrefab != (Object)null && !SourceOfItem.ContainsKey(((Object)val2.m_itemPrefab).name))
						{
							SourceOfItem[((Object)val2.m_itemPrefab).name] = component2;
						}
					}
				}
				ItemDrop val3 = SeedItem(component2);
				if (flag && (Object)(object)val3 != (Object)null && !PieceBySeed.ContainsKey(((Object)val3).name))
				{
					PieceBySeed[((Object)val3).name] = component2;
				}
			}
			Plugin.Log.LogInfo((object)$"Crops indexed: {PlantByCrop.Count} harvestable crops");
		}

		public static bool IsCrop(Pickable pickable)
		{
			if ((Object)(object)pickable == (Object)null)
			{
				return false;
			}
			EnsureIndex();
			return PlantByCrop.ContainsKey(PrefabName(((Component)pickable).gameObject));
		}

		public static Piece ReplantPiece(Pickable pickable)
		{
			EnsureIndex();
			if (!PlantByCrop.TryGetValue(PrefabName(((Component)pickable).gameObject), out var value))
			{
				return null;
			}
			return value.GetComponent<Piece>();
		}

		public static ItemDrop SeedItem(Piece piece)
		{
			if (piece?.m_resources == null)
			{
				return null;
			}
			Requirement[] resources = piece.m_resources;
			foreach (Requirement val in resources)
			{
				if ((Object)(object)val?.m_resItem != (Object)null && val.m_amount > 0)
				{
					return val.m_resItem;
				}
			}
			return null;
		}

		public static Piece PieceUsing(string itemPrefabName)
		{
			EnsureIndex();
			if (itemPrefabName == null || !PieceBySeed.TryGetValue(itemPrefabName, out var value))
			{
				return null;
			}
			return value;
		}

		public static Piece SourceOf(string itemPrefabName)
		{
			EnsureIndex();
			if (itemPrefabName == null || !SourceOfItem.TryGetValue(itemPrefabName, out var value))
			{
				return null;
			}
			return value;
		}

		public static string Localize(string token)
		{
			if (Localization.instance == null)
			{
				return token;
			}
			return Localization.instance.Localize(token);
		}

		public static string PrefabName(GameObject go)
		{
			string name = ((Object)go).name;
			int num = name.IndexOf("(Clone)", StringComparison.Ordinal);
			if (num < 0)
			{
				return name;
			}
			return name.Substring(0, num).TrimEnd(Array.Empty<char>());
		}

		public static bool IsReal(Plant plant)
		{
			if ((Object)(object)plant == (Object)null)
			{
				return false;
			}
			ZNetView component = ((Component)plant).GetComponent<ZNetView>();
			if ((Object)(object)component != (Object)null)
			{
				return component.IsValid();
			}
			return false;
		}

		public static bool Growth(Plant plant, out float progress, out double secondsLeft)
		{
			progress = 0f;
			secondsLeft = 0.0;
			if (!IsReal(plant) || TimeSincePlantedMethod == null || GetGrowTimeMethod == null)
			{
				return false;
			}
			try
			{
				double num = (double)TimeSincePlantedMethod.Invoke(plant, null);
				float num2 = (float)GetGrowTimeMethod.Invoke(plant, null);
				if (num2 <= 0f)
				{
					return false;
				}
				progress = Mathf.Clamp01((float)(num / (double)num2));
				secondsLeft = Math.Max(0.0, (double)num2 - num);
				return true;
			}
			catch (Exception)
			{
				return false;
			}
		}

		public static bool Times(Plant plant, out double since, out float grow)
		{
			since = 0.0;
			grow = 0f;
			if (!IsReal(plant) || TimeSincePlantedMethod == null || GetGrowTimeMethod == null)
			{
				return false;
			}
			try
			{
				since = (double)TimeSincePlantedMethod.Invoke(plant, null);
				grow = (float)GetGrowTimeMethod.Invoke(plant, null);
				return grow > 0f;
			}
			catch (Exception)
			{
				return false;
			}
		}

		public static string BiomeNames(Biome mask)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: 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_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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)
			List<string> list = new List<string>();
			foreach (Biome value in Enum.GetValues(typeof(Biome)))
			{
				if ((int)value != 0 && (mask & value) != 0 && (value & (value - 1)) == 0)
				{
					string text = "$biome_" + ((object)value/*cast due to .constrained prefix*/).ToString().ToLowerInvariant();
					string text2 = ((Localization.instance != null) ? Localization.instance.Localize(text) : ((object)value/*cast due to .constrained prefix*/).ToString());
					list.Add((string.IsNullOrEmpty(text2) || text2.Contains("biome_")) ? ((object)value/*cast due to .constrained prefix*/).ToString() : text2);
				}
			}
			return string.Join(", ", list);
		}
	}
	internal static class CropIndex
	{
		public static readonly List<Plant> Plants = new List<Plant>();

		public static readonly List<Pickable> Ripe = new List<Pickable>();

		private static readonly HashSet<Plant> AllPlants = new HashSet<Plant>();

		private static readonly HashSet<Pickable> AllCrops = new HashSet<Pickable>();

		private static readonly List<Plant> DeadPlants = new List<Plant>();

		private static readonly List<Pickable> DeadCrops = new List<Pickable>();

		private static float _next;

		private static float _nextRescue;

		private static bool _warned;

		internal static void Track(Plant plant)
		{
			if (Crops.IsReal(plant))
			{
				AllPlants.Add(plant);
			}
		}

		internal static void Track(Pickable pickable)
		{
			if ((Object)(object)pickable != (Object)null && Crops.IsCrop(pickable))
			{
				AllCrops.Add(pickable);
			}
		}

		public static void Refresh(bool force = false)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_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)
			if (!force && Time.unscaledTime < _next)
			{
				return;
			}
			_next = Time.unscaledTime + 0.5f;
			Plants.Clear();
			Ripe.Clear();
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			Vector3 position = ((Component)localPlayer).transform.position;
			Vector3 val;
			foreach (Plant allPlant in AllPlants)
			{
				if ((Object)(object)allPlant == (Object)null || !Crops.IsReal(allPlant))
				{
					DeadPlants.Add(allPlant);
					continue;
				}
				val = ((Component)allPlant).transform.position - position;
				if (((Vector3)(ref val)).sqrMagnitude < 3600f)
				{
					Plants.Add(allPlant);
				}
			}
			foreach (Pickable allCrop in AllCrops)
			{
				if ((Object)(object)allCrop == (Object)null)
				{
					DeadCrops.Add(allCrop);
					continue;
				}
				try
				{
					val = ((Component)allCrop).transform.position - position;
					if (((Vector3)(ref val)).sqrMagnitude < 3600f && allCrop.CanBePicked())
					{
						Ripe.Add(allCrop);
					}
				}
				catch (Exception)
				{
					DeadCrops.Add(allCrop);
				}
			}
			foreach (Plant deadPlant in DeadPlants)
			{
				AllPlants.Remove(deadPlant);
			}
			foreach (Pickable deadCrop in DeadCrops)
			{
				AllCrops.Remove(deadCrop);
			}
			DeadPlants.Clear();
			DeadCrops.Clear();
		}

		internal static void RescueStuck()
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			if (Time.unscaledTime < _nextRescue)
			{
				return;
			}
			_nextRescue = Time.unscaledTime + 1f;
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || AllPlants.Count == 0)
			{
				return;
			}
			Vector3 position = ((Component)localPlayer).transform.position;
			int num = 0;
			foreach (Plant item in new List<Plant>(AllPlants))
			{
				if (num >= 10)
				{
					break;
				}
				try
				{
					if ((Object)(object)item == (Object)null || !Crops.IsReal(item))
					{
						continue;
					}
					Vector3 val = ((Component)item).transform.position - position;
					if (((Vector3)(ref val)).sqrMagnitude > 6400f)
					{
						continue;
					}
					ZNetView component = ((Component)item).GetComponent<ZNetView>();
					if (!((Object)(object)component == (Object)null) && component.IsOwner() && Crops.Times(item, out var since, out var grow) && !(since < (double)grow + 15.0))
					{
						item.UpdateHealth(since);
						if ((int)item.GetStatus() == 0 && (Object)(object)item.Grow() != (Object)null)
						{
							num++;
						}
					}
				}
				catch (Exception ex)
				{
					Plugin.Log.LogDebug((object)("Rescue failed: " + ex.Message));
				}
			}
			if (num > 0 && !_warned)
			{
				_warned = true;
				Plugin.Log.LogWarning((object)($"{num} crops were more than 15 s past their grow time without growing (the game's plant updater " + "did not process them). FarmHand grew them with the game's own Plant.Grow."));
			}
		}

		public static List<Pickable> RipeAround(Vector3 center, float radius)
		{
			//IL_002e: 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_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)
			List<Pickable> list = new List<Pickable>();
			float num = radius * radius;
			foreach (Pickable allCrop in AllCrops)
			{
				try
				{
					if ((Object)(object)allCrop != (Object)null)
					{
						Vector3 val = ((Component)allCrop).transform.position - center;
						if (((Vector3)(ref val)).sqrMagnitude <= num && allCrop.CanBePicked())
						{
							list.Add(allCrop);
						}
					}
				}
				catch (Exception)
				{
				}
			}
			return list;
		}
	}
	[HarmonyPatch(typeof(Plant), "Awake")]
	internal static class PlantAwakePatch
	{
		private static void Postfix(Plant __instance)
		{
			CropIndex.Track(__instance);
		}
	}
	[HarmonyPatch(typeof(Pickable), "Awake")]
	internal static class PickableAwakePatch
	{
		private static void Postfix(Pickable __instance)
		{
			try
			{
				CropIndex.Track(__instance);
			}
			catch (Exception)
			{
			}
		}
	}
	internal class FarmHud : MonoBehaviour
	{
		private class Box
		{
			public RectTransform Root;

			public RawImage Frame;

			public Texture2D Tex;
		}

		private const float BarWidth = 780f;

		private const float BarTop = 128f;

		private const float PanelWidth = 330f;

		private const float PanelTop = 340f;

		private const float PanelMargin = 34f;

		private const float Pad = 16f;

		private static readonly Color Gold = new Color(1f, 0.78f, 0.4f);

		private static readonly Color Text = new Color(0.93f, 0.88f, 0.8f);

		private static readonly Color Dim = new Color(0.72f, 0.66f, 0.57f);

		private static readonly Color Good = new Color(0.62f, 0.88f, 0.48f);

		private static readonly Color Bad = new Color(1f, 0.48f, 0.4f);

		private static readonly Color Warn = new Color(1f, 0.7f, 0.3f);

		private Canvas _canvas;

		private RectTransform _root;

		private Box _bar;

		private Box _panel;

		private readonly List<TextMeshProUGUI> _barLines = new List<TextMeshProUGUI>();

		private TextMeshProUGUI _panelTitle;

		private TextMeshProUGUI _panelBody;

		private TextMeshProUGUI _panelNext;

		private TextMeshProUGUI _panelWarn;

		private RawImage _panelRule;

		private float _nextScan;

		private void LateUpdate()
		{
			//IL_00b1: 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_00bb: 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)
			if (!FarmMode.On || !((Object)(object)Player.m_localPlayer != (Object)null) || !((Object)(object)Hud.instance != (Object)null) || IsHudHidden())
			{
				if ((Object)(object)_root != (Object)null && ((Component)_root).gameObject.activeSelf)
				{
					((Component)_root).gameObject.SetActive(false);
				}
			}
			else
			{
				if ((Object)(object)_canvas == (Object)null && !TryBuild())
				{
					return;
				}
				if (!((Component)_root).gameObject.activeSelf)
				{
					((Component)_root).gameObject.SetActive(true);
				}
				float scaleFactor = _canvas.scaleFactor;
				Rect rect = ((RectTransform)((Component)_canvas).transform).rect;
				float width = ((Rect)(ref rect)).width;
				LayoutBar(width, scaleFactor);
				bool value = Plugin.ShowFieldPanel.Value;
				((Component)_panel.Root).gameObject.SetActive(value);
				if (value)
				{
					if (Time.unscaledTime >= _nextScan)
					{
						_nextScan = Time.unscaledTime + 1f;
						FieldScanner.Scan(((Component)Player.m_localPlayer).transform.position, Plugin.FieldRadius.Value);
					}
					LayoutPanel(width, scaleFactor);
				}
			}
		}

		private static bool IsHudHidden()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			GameObject rootObject = Hud.instance.m_rootObject;
			if (!((Object)(object)rootObject == (Object)null) && rootObject.activeInHierarchy)
			{
				return rootObject.transform.localPosition.x >= 1000f;
			}
			return true;
		}

		private void LayoutBar(float screenW, float unit)
		{
			string[] array = FarmMode.BarLines();
			float num = 14f;
			float[] array2 = new float[3] { 21f, 17f, 15f };
			for (int i = 0; i < _barLines.Count; i++)
			{
				TextMeshProUGUI val = _barLines[i];
				string text = ((i < array.Length) ? array[i] : null);
				bool flag = !string.IsNullOrEmpty(text);
				UiKit.SetActive((Component)(object)val, flag);
				if (flag)
				{
					if (((TMP_Text)val).text != text)
					{
						((TMP_Text)val).text = text;
					}
					float num2 = Mathf.Ceil(array2[Mathf.Min(i, array2.Length - 1)] * 1.55f) + 6f;
					UiKit.Place(((TMP_Text)val).rectTransform, 16f, num, 748f, num2);
					num += num2;
				}
			}
			float num3 = num + 16f - 4f;
			UiKit.Place(_bar.Root, (screenW - 780f) / 2f, 128f, 780f, num3);
			SetFrame(_bar, 780f, num3, unit);
		}

		private void LayoutPanel(float screenW, float unit)
		{
			//IL_0028: 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_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: 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_0278: Unknown result type (might be due to invalid IL or missing references)
			FieldScanner.Summary last = FieldScanner.Last;
			string text = Lang.T("field_title") + " <size=70%><color=#" + Hex(Dim) + ">" + Lang.T("field_radius", Mathf.RoundToInt(Plugin.FieldRadius.Value)) + "</color></size>";
			if (((TMP_Text)_panelTitle).text != text)
			{
				((TMP_Text)_panelTitle).text = text;
			}
			string text2 = ((last.Ready + last.Growing + last.Problem != 0) ? (Row(Lang.T("field_ready"), last.Ready, Good) + "\n" + Row(Lang.T("field_growing"), last.Growing, Text) + "\n" + Row(Lang.T("field_problem"), last.Problem, (last.Problem > 0) ? Bad : Dim)) : ("<color=#" + Hex(Dim) + ">" + Lang.T("field_none") + "</color>"));
			if (((TMP_Text)_panelBody).text != text2)
			{
				((TMP_Text)_panelBody).text = text2;
			}
			List<string> list = new List<string>();
			foreach (FieldScanner.Upcoming item in last.Next)
			{
				list.Add(Lang.T("field_next", item.Name, item.Count, Lang.Duration(item.Seconds)));
			}
			string text3 = string.Join("\n", list);
			if (((TMP_Text)_panelNext).text != text3)
			{
				((TMP_Text)_panelNext).text = text3;
			}
			List<string> list2 = new List<string>();
			foreach (FieldScanner.Shortage item2 in last.Short)
			{
				list2.Add("<color=#" + Hex(Warn) + ">" + Lang.T("seed_short", item2.Seed, item2.Missing) + "</color>");
				if (item2.Source != null)
				{
					list2.Add("<size=85%>  " + Lang.T(Plugin.ReplantWithHarvest.Value ? "seed_hint_alt" : "seed_hint", item2.Source) + "</size>");
				}
			}
			string text4 = string.Join("\n", list2);
			if (((TMP_Text)_panelWarn).text != text4)
			{
				((TMP_Text)_panelWarn).text = text4;
			}
			float num = 14f;
			UiKit.Place(((TMP_Text)_panelTitle).rectTransform, 16f, num, 298f, 34f);
			num += 36f;
			UiKit.Place(((Graphic)_panelRule).rectTransform, 16f, num, 298f, 1.5f);
			num += 8f;
			int num2 = text2.Split(new char[1] { '\n' }).Length;
			UiKit.Place(((TMP_Text)_panelBody).rectTransform, 16f, num, 298f, (float)num2 * 30f);
			num += (float)num2 * 30f + 4f;
			UiKit.SetActive((Component)(object)_panelNext, list.Count > 0);
			if (list.Count > 0)
			{
				UiKit.Place(((TMP_Text)_panelNext).rectTransform, 16f, num, 298f, (float)list.Count * 25f);
				num += (float)list.Count * 25f;
			}
			UiKit.SetActive((Component)(object)_panelWarn, list2.Count > 0);
			if (list2.Count > 0)
			{
				num += 6f;
				UiKit.Place(((TMP_Text)_panelWarn).rectTransform, 16f, num, 298f, (float)list2.Count * 25f);
				num += (float)list2.Count * 25f;
			}
			float num3 = num + 16f - 2f;
			UiKit.Place(_panel.Root, screenW - 330f - 34f, 340f, 330f, num3);
			SetFrame(_panel, 330f, num3, unit);
		}

		private static string Row(string label, int count, Color c)
		{
			//IL_000d: 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)
			return $"<color=#{Hex(c)}>●</color> {label}<pos=86%><color=#{Hex(Gold)}>{count}</color>";
		}

		private static string Hex(Color c)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return ColorUtility.ToHtmlStringRGB(c);
		}

		private static void SetFrame(Box box, float width, float height, float unit)
		{
			int num = Mathf.Max(8, Mathf.RoundToInt(width * unit));
			int num2 = Mathf.Max(8, Mathf.RoundToInt(height * unit));
			if ((Object)(object)box.Tex == (Object)null || ((Texture)box.Tex).width != num || ((Texture)box.Tex).height != num2)
			{
				if ((Object)(object)box.Tex != (Object)null)
				{
					Object.Destroy((Object)(object)box.Tex);
				}
				box.Tex = PanelArt.Frame(num, num2, unit);
				box.Frame.texture = (Texture)(object)box.Tex;
			}
			UiKit.Place(((Graphic)box.Frame).rectTransform, 0f, 0f, width, height);
		}

		private Box NewBox(string name)
		{
			Box box = new Box
			{
				Root = UiKit.Rect(name, (Transform)(object)_root)
			};
			box.Frame = UiKit.Raw("Frame", (Transform)(object)box.Root, 0f, 0f, 10f, 10f);
			return box;
		}

		private bool TryBuild()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			//IL_006e: 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_0127: 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_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
			if (!GameFont.TryFind())
			{
				return false;
			}
			GameObject val = new GameObject("FarmHandCanvas");
			val.transform.SetParent(((Component)this).transform, false);
			_canvas = val.AddComponent<Canvas>();
			_canvas.renderMode = (RenderMode)0;
			_canvas.pixelPerfect = true;
			_canvas.sortingOrder = 2;
			CanvasScaler obj = val.AddComponent<CanvasScaler>();
			obj.uiScaleMode = (ScaleMode)1;
			obj.referenceResolution = new Vector2(1920f, 1080f);
			obj.screenMatchMode = (ScreenMatchMode)0;
			obj.matchWidthOrHeight = 1f;
			_root = UiKit.Rect("FarmHud", val.transform);
			_bar = NewBox("Bar");
			_barLines.Add(UiKit.Text("Line0", (Transform)(object)_bar.Root, 0f, 0f, 10f, 10f, 21f, (TextAlignmentOptions)514, Gold));
			_barLines.Add(UiKit.Text("Line1", (Transform)(object)_bar.Root, 0f, 0f, 10f, 10f, 17f, (TextAlignmentOptions)514, Text));
			_barLines.Add(UiKit.Text("Line2", (Transform)(object)_bar.Root, 0f, 0f, 10f, 10f, 15f, (TextAlignmentOptions)514, Dim));
			_panel = NewBox("Field");
			_panelTitle = UiKit.Text("Title", (Transform)(object)_panel.Root, 0f, 0f, 10f, 10f, 20f, (TextAlignmentOptions)514, Gold);
			_panelRule = UiKit.Raw("Rule", (Transform)(object)_panel.Root, 0f, 0f, 10f, 1f);
			_panelRule.texture = (Texture)(object)PanelArt.FadeLine(horizontal: true);
			_panelBody = UiKit.Text("Body", (Transform)(object)_panel.Root, 0f, 0f, 10f, 10f, 18f, (TextAlignmentOptions)257, Text);
			((TMP_Text)_panelBody).lineSpacing = 12f;
			_panelNext = UiKit.Text("Next", (Transform)(object)_panel.Root, 0f, 0f, 10f, 10f, 15f, (TextAlignmentOptions)257, Dim);
			((TMP_Text)_panelNext).lineSpacing = 6f;
			_panelWarn = UiKit.Text("Warn", (Transform)(object)_panel.Root, 0f, 0f, 10f, 10f, 15f, (TextAlignmentOptions)257, Dim);
			((TMP_Text)_panelWarn).lineSpacing = 6f;
			TextMeshProUGUI[] componentsInChildren = ((Component)_root).GetComponentsInChildren<TextMeshProUGUI>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				((TMP_Text)componentsInChildren[i]).overflowMode = (TextOverflowModes)0;
			}
			return true;
		}
	}
	internal class FarmMode : MonoBehaviour
	{
		private static ItemData _cultivator;

		private static ItemData _prevRight;

		private static ItemData _prevLeft;

		private float _wheel;

		public static bool On { get; private set; }

		private void Update()
		{
			//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_00a1: 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)
			Player localPlayer = Player.m_localPlayer;
			if (On && ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || !Plugin.Enabled.Value))
			{
				SetOn(on: false, quiet: true);
			}
			else
			{
				if ((Object)(object)localPlayer == (Object)null || !Plugin.Enabled.Value || Typing())
				{
					return;
				}
				KeyboardShortcut value = Plugin.FarmModeKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					SetOn(!On);
					return;
				}
				if (GridPlanter.PlacingCrop && !((Character)localPlayer).InPlaceMode())
				{
					GridPlanter.HideGhosts();
				}
				if (On && Plugin.Helpers && GridPlanter.PlacingCrop)
				{
					value = Plugin.GridToggleKey.Value;
					if (((KeyboardShortcut)(ref value)).IsDown())
					{
						Plugin.GridPlanting.Value = !Plugin.GridPlanting.Value;
					}
					AdjustGridWithWheel();
				}
			}
		}

		private void AdjustGridWithWheel()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			bool key = ZInput.GetKey(Plugin.ColumnModifier.Value, true);
			bool key2 = ZInput.GetKey(Plugin.RowModifier.Value, true);
			if (!key && !key2)
			{
				_wheel = 0f;
				return;
			}
			_wheel += WheelBlockPatch.ReadRaw();
			if (!(Mathf.Abs(_wheel) < 0.01f))
			{
				int num = ((_wheel > 0f) ? 1 : (-1));
				_wheel = 0f;
				if (!Plugin.GridPlanting.Value)
				{
					Plugin.GridPlanting.Value = true;
				}
				if (key)
				{
					Plugin.Columns.Value = Mathf.Clamp(Plugin.Columns.Value + num, 1, 10);
				}
				else
				{
					Plugin.Rows.Value = Mathf.Clamp(Plugin.Rows.Value + num, 1, 10);
				}
			}
		}

		private static bool Typing()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Invalid comparison between Unknown and I4
			if (!SettingsWindow.IsOpen && (!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Console.IsVisible() && !TextInput.IsVisible() && !Menu.IsVisible() && !InventoryGui.IsVisible() && !StoreGui.IsVisible())
			{
				if ((Object)(object)Minimap.instance != (Object)null)
				{
					return (int)Minimap.instance.m_mode == 2;
				}
				return false;
			}
			return true;
		}

		internal static void Exit()
		{
			SetOn(on: false);
		}

		private static void SetOn(bool on, bool quiet = false)
		{
			if (On == on)
			{
				return;
			}
			On = on;
			Player localPlayer = Player.m_localPlayer;
			if (on)
			{
				if ((Object)(object)localPlayer != (Object)null && Plugin.AutoEquipCultivator.Value)
				{
					EquipCultivator(localPlayer);
				}
				if (!quiet && (Object)(object)localPlayer != (Object)null)
				{
					((Character)localPlayer).Message((MessageType)2, Plugin.PlantEasilyInstalled ? (Lang.T("mode_on") + "\n" + Lang.T("plant_easily")) : Lang.T("mode_on"), 0, (Sprite)null, false);
				}
				return;
			}
			GridPlanter.HideGhosts();
			if ((Object)(object)localPlayer != (Object)null)
			{
				RestoreWeapons(localPlayer);
			}
			if (!quiet && (Object)(object)localPlayer != (Object)null)
			{
				((Character)localPlayer).Message((MessageType)2, Lang.T("mode_off"), 0, (Sprite)null, false);
			}
		}

		private static void EquipCultivator(Player player)
		{
			_cultivator = null;
			if (IsCultivator(((Humanoid)player).RightItem))
			{
				return;
			}
			ItemData val = ((IEnumerable<ItemData>)((Humanoid)player).GetInventory().GetAllItems()).FirstOrDefault((Func<ItemData, bool>)IsCultivator);
			if (val == null)
			{
				((Character)player).Message((MessageType)1, Lang.T("no_cultivator"), 0, (Sprite)null, false);
				return;
			}
			_prevRight = ((Humanoid)player).RightItem;
			_prevLeft = ((Humanoid)player).LeftItem;
			if (((Humanoid)player).EquipItem(val, true))
			{
				_cultivator = val;
			}
		}

		private static void RestoreWeapons(Player player)
		{
			if (_cultivator != null)
			{
				if (((Humanoid)player).IsItemEquiped(_cultivator))
				{
					((Humanoid)player).UnequipItem(_cultivator, true);
				}
				Inventory inventory = ((Humanoid)player).GetInventory();
				if (_prevRight != null && inventory.ContainsItem(_prevRight))
				{
					((Humanoid)player).EquipItem(_prevRight, true);
				}
				if (_prevLeft != null && inventory.ContainsItem(_prevLeft) && !((Humanoid)player).IsItemEquiped(_prevLeft))
				{
					((Humanoid)player).EquipItem(_prevLeft, true);
				}
				_cultivator = (_prevRight = (_prevLeft = null));
			}
		}

		internal static bool IsCultivator(ItemData item)
		{
			PieceTable val = item?.m_shared?.m_buildPieces;
			if ((Object)(object)val == (Object)null || val.m_pieces == null)
			{
				return false;
			}
			return val.m_pieces.Any((GameObject p) => (Object)(object)p != (Object)null && (Object)(object)p.GetComponent<Plant>() != (Object)null);
		}

		internal static string[] BarLines()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
			string text = Lang.T("title");
			KeyboardShortcut value = Plugin.FarmModeKey.Value;
			string text2 = Lang.KeyName(((KeyboardShortcut)(ref value)).MainKey);
			if (!Plugin.PlantEasilyInstalled)
			{
				string text3 = (Plugin.MassHarvest.Value ? Lang.T("hint_harvest", Mathf.RoundToInt(Plugin.HarvestRadius.Value), Lang.T(Plugin.Replant.Value ? "hint_replant" : "hint_no_replant")) : "");
				if (!GridPlanter.PlacingCrop)
				{
					Player localPlayer = Player.m_localPlayer;
					string text4 = (((Object)(object)localPlayer != (Object)null && IsCultivator(((Humanoid)localPlayer).RightItem)) ? Lang.T("hold_seeds") : text3);
					return new string[3]
					{
						text,
						text4,
						"[" + text2 + "] " + Lang.T("mode_off")
					};
				}
				string text5 = (Plugin.GridPlanting.Value ? Lang.T("grid", Plugin.Columns.Value, Plugin.Rows.Value) : Lang.T("single"));
				string text6 = text + "  ·  " + text5 + "  ·  " + Lang.T("spacing", GridPlanter.Spacing);
				if (GridPlanter.Snapped)
				{
					text6 = text6 + "  ·  " + Lang.T("snapped");
				}
				string text7 = Lang.T("seeds", GridPlanter.SeedsHave, GridPlanter.SeedsNeed);
				if (Plugin.StaminaPercent.Value != 100)
				{
					text7 = text7 + "  ·  " + Lang.T("stamina", Plugin.StaminaPercent.Value);
				}
				if (GridPlanter.BadCells > 0)
				{
					text7 = text7 + "  ·  <color=#FFB44A>" + Lang.T("bad_cells", GridPlanter.BadCells) + "</color>";
				}
				if (!string.IsNullOrEmpty(GridPlanter.MainProblem))
				{
					text7 = text7 + "  ·  <color=#FF7A6A>" + GridPlanter.MainProblem + "</color>";
				}
				object[] obj = new object[4]
				{
					Lang.KeyName(Plugin.ColumnModifier.Value),
					Lang.KeyName(Plugin.RowModifier.Value),
					null,
					null
				};
				value = Plugin.GridToggleKey.Value;
				obj[2] = Lang.KeyName(((KeyboardShortcut)(ref value)).MainKey);
				obj[3] = text2;
				string text8 = Lang.T("hint_plant", obj);
				return new string[3] { text6, text7, text8 };
			}
			return new string[3]
			{
				text,
				Lang.T("plant_easily"),
				""
			};
		}
	}
	[HarmonyPatch]
	internal static class BuildStaminaPatch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(typeof(Player), "GetBuildStamina", (Type[])null, (Type[])null);
		}

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

		private static void Postfix(Player __instance, ref float __result)
		{
			if (FarmMode.On && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && Plugin.Enabled.Value)
			{
				PieceTable val = ((Humanoid)__instance).RightItem?.m_shared?.m_buildPieces;
				if (FarmMode.IsCultivator(((Humanoid)__instance).RightItem) && !((Object)(object)val == (Object)null))
				{
					__result *= (float)Plugin.StaminaPercent.Value / 100f;
				}
			}
		}
	}
	[HarmonyPatch(typeof(ZInput), "GetMouseScrollWheel")]
	internal static class WheelBlockPatch
	{
		private static bool _reading;

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

		private static void Postfix(ref float __result)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if (!_reading && FarmMode.On && GridPlanter.PlacingCrop && (ZInput.GetKey(Plugin.ColumnModifier.Value, true) || ZInput.GetKey(Plugin.RowModifier.Value, true)))
			{
				__result = 0f;
			}
		}
	}
	[HarmonyPatch(typeof(Menu), "Update")]
	internal static class EscExitsFarmModePatch
	{
		private static bool Prefix()
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Invalid comparison between Unknown and I4
			if (!FarmMode.On || SettingsWindow.BlocksInput)
			{
				return true;
			}
			if (!ZInput.GetKeyDown((KeyCode)27, true) && !ZInput.GetButtonDown("JoyMenu"))
			{
				return true;
			}
			if (Menu.IsVisible() || InventoryGui.IsVisible() || Hud.IsPieceSelectionVisible() || StoreGui.IsVisible() || Console.IsVisible() || TextInput.IsVisible() || ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus()) || ((Object)(object)Minimap.instance != (Object)null && (int)Minimap.instance.m_mode == 2))
			{
				return true;
			}
			FarmMode.Exit();
			return false;
		}
	}
	internal static class FieldScanner
	{
		internal struct Upcoming
		{
			public string Name;

			public int Count;

			public double Seconds;
		}

		internal struct Shortage
		{
			public string Seed;

			public int Missing;

			public string Source;
		}

		internal class Summary
		{
			public int Ready;

			public int Growing;

			public int Problem;

			public readonly List<Upcoming> Next = new List<Upcoming>();

			public readonly List<Shortage> Short = new List<Shortage>();
		}

		private class Need
		{
			public ItemDrop Seed;

			public int Amount;
		}

		private class Group
		{
			public int Count;

			public double Soonest;
		}

		public static Summary Last { get; private set; } = new Summary();

		public static void Scan(Vector3 center, float radius)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_028f: Unknown result type (might be due to invalid IL or missing references)
			CropIndex.Refresh();
			Summary summary = new Summary();
			float num = radius * radius;
			Dictionary<string, Group> dictionary = new Dictionary<string, Group>();
			Dictionary<string, Need> dictionary2 = new Dictionary<string, Need>();
			Vector3 val;
			foreach (Pickable item in CropIndex.Ripe)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				val = ((Component)item).transform.position - center;
				if (((Vector3)(ref val)).sqrMagnitude > num)
				{
					continue;
				}
				summary.Ready++;
				if (!Plugin.Replant.Value || NewCrops.Regrows(item))
				{
					continue;
				}
				Piece val2 = Crops.ReplantPiece(item);
				ItemDrop val3 = Crops.SeedItem(val2);
				if ((Object)(object)val3 == (Object)null)
				{
					continue;
				}
				int num2 = 1;
				Requirement[] resources = val2.m_resources;
				foreach (Requirement val4 in resources)
				{
					if ((Object)(object)val4?.m_resItem == (Object)(object)val3)
					{
						num2 = val4.m_amount;
						break;
					}
				}
				if (!dictionary2.TryGetValue(((Object)val3).name, out var value))
				{
					string name = ((Object)val3).name;
					Need obj = new Need
					{
						Seed = val3
					};
					value = obj;
					dictionary2[name] = obj;
				}
				value.Amount += num2;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				foreach (Need value3 in dictionary2.Values)
				{
					int num3 = ((Humanoid)localPlayer).GetInventory().CountItems(value3.Seed.m_itemData.m_shared.m_name, -1, true);
					if (num3 < value3.Amount)
					{
						Piece val5 = Crops.SourceOf(((Object)value3.Seed).name);
						summary.Short.Add(new Shortage
						{
							Seed = Crops.Localize(value3.Seed.m_itemData.m_shared.m_name),
							Missing = value3.Amount - num3,
							Source = (((Object)(object)val5 != (Object)null) ? Crops.Localize(val5.m_name) : null)
						});
					}
				}
			}
			foreach (Plant plant in CropIndex.Plants)
			{
				if ((Object)(object)plant == (Object)null)
				{
					continue;
				}
				val = ((Component)plant).transform.position - center;
				if (((Vector3)(ref val)).sqrMagnitude > num)
				{
					continue;
				}
				if ((int)plant.GetStatus() != 0)
				{
					summary.Problem++;
					continue;
				}
				summary.Growing++;
				if (Crops.Growth(plant, out var _, out var secondsLeft))
				{
					string key = ((Localization.instance != null) ? Localization.instance.Localize(plant.m_name) : plant.m_name);
					if (!dictionary.TryGetValue(key, out var value2))
					{
						Group obj2 = new Group
						{
							Soonest = secondsLeft
						};
						value2 = obj2;
						dictionary[key] = obj2;
					}
					value2.Count++;
					if (secondsLeft < value2.Soonest)
					{
						value2.Soonest = secondsLeft;
					}
				}
			}
			foreach (KeyValuePair<string, Group> item2 in dictionary.OrderBy((KeyValuePair<string, Group> kv) => kv.Value.Soonest).Take(3))
			{
				summary.Next.Add(new Upcoming
				{
					Name = item2.Key,
					Count = item2.Value.Count,
					Seconds = item2.Value.Soonest
				});
			}
			Last = summary;
		}
	}
	internal static class GameFont
	{
		private static TMP_FontAsset _font;

		private static Material _material;

		public static bool Ready => (Object)(object)_font != (Object)null;

		public static bool TryFind()
		{
			if ((Object)(object)_font != (Object)null)
			{
				return true;
			}
			if ((Object)(object)Hud.instance != (Object)null)
			{
				TMP_Text val = null;
				TMP_Text[] componentsInChildren = ((Component)Hud.instance).GetComponentsInChildren<TMP_Text>(true);
				foreach (TMP_Text val2 in componentsInChildren)
				{
					if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.font == (Object)null))
					{
						if ((Object)(object)val == (Object)null)
						{
							val = val2;
						}
						if (IsValheimSerif(((Object)val2.font).name))
						{
							val = val2;
							break;
						}
					}
				}
				if ((Object)(object)val != (Object)null)
				{
					_font = val.font;
				}
			}
			if ((Object)(object)_font == (Object)null)
			{
				TMP_FontAsset[] array = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();
				foreach (TMP_FontAsset val3 in array)
				{
					if ((Object)(object)val3 != (Object)null && IsValheimSerif(((Object)val3).name))
					{
						_font = val3;
						break;
					}
				}
			}
			if ((Object)(object)_font == (Object)null)
			{
				_font = TMP_Settings.defaultFontAsset;
			}
			if ((Object)(object)_font == (Object)null)
			{
				return false;
			}
			_material = MakeCrispMaterial(_font);
			int num = ((_font.fallbackFontAssetTable != null) ? _font.fallbackFontAssetTable.Count : 0);
			Plugin.Log.LogInfo((object)string.Format("HUD font: {0} (fallback fonts: {1}, material: {2})", ((Object)_font).name, num, ((Object)(object)_material != (Object)null) ? ((Object)_material).name : "default"));
			return true;
		}

		private static Material MakeCrispMaterial(TMP_FontAsset font)
		{
			//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_0030: Expected O, but got Unknown
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)font == (Object)null || (Object)(object)((TMP_Asset)font).material == (Object)null)
			{
				return null;
			}
			Material val = new Material(((TMP_Asset)font).material)
			{
				name = "FarmHand Crisp"
			};
			SetIf(val, "_Sharpness", 0.35f);
			SetIf(val, "_FaceDilate", 0.05f);
			SetIf(val, "_OutlineWidth", 0f);
			if (val.HasProperty("_UnderlayColor"))
			{
				val.EnableKeyword("UNDERLAY_ON");
				val.SetColor("_UnderlayColor", new Color(0f, 0f, 0f, 0.85f));
				SetIf(val, "_UnderlayOffsetX", 0.55f);
				SetIf(val, "_UnderlayOffsetY", -0.55f);
				SetIf(val, "_UnderlayDilate", 0.1f);
				SetIf(val, "_UnderlaySoftness", 0.05f);
			}
			return val;
		}

		private static void SetIf(Material m, string prop, float value)
		{
			if (m.HasProperty(prop))
			{
				m.SetFloat(prop, value);
			}
		}

		public static void Apply(TMP_Text text)
		{
			text.font = _font;
			if ((Object)(object)_material != (Object)null)
			{
				text.fontSharedMaterial = _material;
			}
		}

		private static bool IsValheimSerif(string name)
		{
			if (name != null)
			{
				return name.IndexOf("Averia", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}
	}
	internal static class GridPlanter
	{
		private struct Cell
		{
			public Vector3 Pos;

			public bool Ok;
		}

		private static readonly FieldRef<Player, GameObject> GhostRef = AccessTools.FieldRefAccess<Player, GameObject>("m_placementGhost");

		private static readonly FieldInfo StatusField = AccessTools.Field(typeof(Player), "m_placementStatus");

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

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

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

		private static readonly FieldInfo BuildPiecesField = AccessTools.Field(typeof(Player), "m_buildPieces");

		private static int _spaceMask;

		private static int _roofMask;

		private static readonly Collider[] SpaceHits = (Collider[])(object)new Collider[32];

		private static readonly List<Cell> Cells = new List<Cell>();

		private static readonly List<GameObject> Ghosts = new List<GameObject>();

		private static string _ghostSource;

		private static Quaternion _rotation;

		private static bool _placingExtras;

		private static Vector3 _lastPos;

		private static Vector3 _lastFwd;

		private static int _lastCols;

		private static int _lastRows;

		private static float _lastSpacing;

		private static float _nextCheck;

		private static bool _wasSnapped;

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

		private static GameObject _cloneHolder;

		private static MaterialPropertyBlock _badTint;

		public static bool PlacingCrop { get; private set; }

		public static float Spacing { get; private set; }

		public static bool Snapped { get; private set; }

		public static int SeedsHave { get; private set; }

		public static int SeedsNeed { get; private set; }

		public static int BadCells { get; private set; }

		public static string MainProblem { get; private set; }

		internal static void AfterGhostUpdate(Player player)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: 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_008d: 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_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_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: 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_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: 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_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = GhostRef.Invoke(player);
			Plant val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Plant>() : null);
			if (!FarmMode.On || !Plugin.Helpers || (Object)(object)val2 == (Object)null || !val.activeSelf)
			{
				PlacingCrop = false;
				HideGhosts();
				return;
			}
			PlacingCrop = true;
			Spacing = Crops.Spacing(val2);
			CropIndex.Refresh();
			Vector3 pos = val.transform.position;
			Quaternion val3 = Quaternion.Euler(0f, val.transform.eulerAngles.y, 0f);
			Vector3 fwd = val3 * Vector3.forward;
			Vector3 right = val3 * Vector3.right;
			bool flag = ZInput.GetButton("AltPlace") || ZInput.GetKey((KeyCode)304, true);
			Snapped = Plugin.SnapToCrops.Value && !flag && Snap(ref pos, ref fwd, ref right, Spacing);
			if (Snapped)
			{
				pos.y = Ground(pos);
				val.transform.position = pos;
			}
			int num = ((!Plugin.GridPlanting.Value) ? 1 : Plugin.Columns.Value);
			int num2 = ((!Plugin.GridPlanting.Value) ? 1 : Plugin.Rows.Value);
			Vector3 val4 = pos - _lastPos;
			if (((Vector3)(ref val4)).sqrMagnitude > 0.0004f || Vector3.Dot(fwd, _lastFwd) < 0.9999f || num != _lastCols || num2 != _lastRows || !Mathf.Approximately(Spacing, _lastSpacing) || ((Object)val).name != _ghostSource || Time.time >= _nextCheck)
			{
				_lastPos = pos;
				_lastFwd = fwd;
				_lastCols = num;
				_lastRows = num2;
				_lastSpacing = Spacing;
				_nextCheck = Time.time + 0.5f;
				_rotation = Quaternion.LookRotation(fwd, Vector3.up);
				BuildCells(val2, val, pos, fwd, right, num, num2);
				CountSeeds(player, val.GetComponent<Piece>());
				ShowGhosts(val);
			}
			if (Plugin.BlockBadSpots.Value && MainProblem != null)
			{
				SetStatus(player, MainProblem);
			}
			else if (Snapped && MainProblem == null)
			{
				ClearCultivatedStatus(player);
			}
		}

		internal static void Invalidate()
		{
			_nextCheck = 0f;
		}

		private static void BuildCells(Plant plant, GameObject ghost, Vector3 pos, Vector3 fwd, Vector3 right, int cols, int rows)
		{
			//IL_0022: 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_003e: 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_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)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			int num = (cols - 1) / 2;
			int num2 = (rows - 1) / 2;
			Cells.Clear();
			BadCells = 0;
			string mainProblem = null;
			AddCell(plant, ghost, pos, ref mainProblem, main: true);
			for (int i = 0; i < rows; i++)
			{
				for (int j = 0; j < cols; j++)
				{
					if (i != num2 || j != num)
					{
						Vector3 p = pos + right * ((float)(j - num) * Spacing) + fwd * ((float)(i - num2) * Spacing);
						p.y = Ground(p);
						AddCell(plant, ghost, p, ref mainProblem, main: false);
					}
				}
			}
			MainProblem = mainProblem;
		}

		private static void AddCell(Plant plant, GameObject ghost, Vector3 p, ref string mainProblem, bool main)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: 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)
			string text = Problem(plant, p, ghost);
			if (main)
			{
				mainProblem = text;
			}
			if (text != null)
			{
				BadCells++;
			}
			Cells.Add(new Cell
			{
				Pos = p,
				Ok = (text == null)
			});
		}

		private static string Problem(Plant plant, Vector3 p, GameObject ghost)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: 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_011e: 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_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Invalid comparison between Unknown and I4
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Invalid comparison between Unknown and I4
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Invalid comparison between Unknown and I4
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			if (_spaceMask == 0)
			{
				_spaceMask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid" });
				_roofMask = LayerMask.GetMask(new string[3] { "Default", "static_solid", "piece" });
			}
			Heightmap val = Heightmap.FindHeightmap(p);
			if ((Object)(object)val != (Object)null)
			{
				Biome biome = val.GetBiome(p, 0.02f, false);
				if ((biome & plant.m_biome) == 0)
				{
					return Lang.T("bad_biome");
				}
				if (plant.m_needCultivatedGround && !val.IsCultivated(p))
				{
					return Lang.T("bad_soil");
				}
				bool flag = ShieldGenerator.IsInsideShield(p);
				if (!plant.m_tolerateHeat && (int)biome == 32 && !flag)
				{
					return Lang.T("st_TooHot");
				}
				if (!plant.m_tolerateCold && ((int)biome == 64 || (int)biome == 4) && !flag)
				{
					return Lang.T("st_TooCold");
				}
			}
			if (Physics.Raycast(p + Vector3.up * 0.05f, Vector3.up, 100f, _roofMask))
			{
				return Lang.T("bad_roof");
			}
			int num = Physics.OverlapSphereNonAlloc(p, plant.m_growRadius, SpaceHits, _spaceMask);
			for (int i = 0; i < num; i++)
			{
				Collider val2 = SpaceHits[i];
				if (!((Object)(object)val2 == (Object)null) && !((Component)val2).transform.IsChildOf(ghost.transform))
				{
					Plant component = ((Component)val2).GetComponent<Plant>();
					if (!((Object)(object)component != (Object)null) || (int)component.GetStatus() == 0)
					{
						return Lang.T("bad_space");
					}
				}
			}
			return null;
		}

		private static bool Snap(ref Vector3 pos, ref Vector3 fwd, ref Vector3 right, float spacing)
		{
			//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_002e: 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_0035: 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_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: 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_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: 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_00b8: 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_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: 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_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Unknown result type (might be due to invalid IL or missing references)
			//IL_0277: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_029e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			float num = spacing * (_wasSnapped ? 3.2f : 2.2f);
			Vector3 val = Vector3.zero;
			bool flag = false;
			foreach (Vector3 item in CropPositions())
			{
				float num2 = FlatDistance(item, pos);
				if (num2 < num)
				{
					num = num2;
					val = item;
					flag = true;
				}
			}
			_wasSnapped = flag;
			if (!flag)
			{
				return false;
			}
			Vector3 val2 = Vector3.zero;
			float num3 = spacing * 1.7f;
			foreach (Vector3 item2 in CropPositions())
			{
				float num4 = FlatDistance(item2, val);
				if (!(num4 < 0.05f) && !(num4 > num3))
				{
					num3 = num4;
					val2 = Flat(item2 - val);
				}
			}
			if (val2 != Vector3.zero)
			{
				Vector3 val3 = default(Vector3);
				((Vector3)(ref val3))..ctor(val2.z, 0f, 0f - val2.x);
				Vector3 val4 = val2;
				Vector3[] array = (Vector3[])(object)new Vector3[4]
				{
					val2,
					-val2,
					val3,
					-val3
				};
				foreach (Vector3 val5 in array)
				{
					if (Vector3.Dot(val5, fwd) > Vector3.Dot(val4, fwd))
					{
						val4 = val5;
					}
				}
				if (Vector3.Dot(val4, fwd) > 0.7f)
				{
					fwd = val4;
					right = new Vector3(fwd.z, 0f, 0f - fwd.x);
				}
			}
			Vector3 val6 = pos - val;
			float num5 = Mathf.Round(Vector3.Dot(val6, fwd) / spacing);
			float num6 = Mathf.Round(Vector3.Dot(val6, right) / spacing);
			if (Mathf.Approximately(num5, 0f) && Mathf.Approximately(num6, 0f))
			{
				if (Mathf.Abs(Vector3.Dot(val6, fwd)) >= Mathf.Abs(Vector3.Dot(val6, right)))
				{
					num5 = ((Vector3.Dot(val6, fwd) >= 0f) ? 1f : (-1f));
				}
				else
				{
					num6 = ((Vector3.Dot(val6, right) >= 0f) ? 1f : (-1f));
				}
			}
			pos = val + fwd * (num5 * spacing) + right * (num6 * spacing);
			return true;
		}

		private static IEnumerable<Vector3> CropPositions()
		{
			foreach (Plant plant in CropIndex.Plants)
			{
				if ((Object)(object)plant != (Object)null)
				{
					yield return ((Component)plant).transform.position;
				}
			}
			foreach (Pickable item in CropIndex.Ripe)
			{
				if ((Object)(object)item != (Object)null)
				{
					yield return ((Component)item).transform.position;
				}
			}
		}

		private static void CountSeeds(Player player, Piece piece)
		{
			int num = 0;
			foreach (Cell cell in Cells)
			{
				if (cell.Ok)
				{
					num++;
				}
			}
			SeedsHave = 0;
			SeedsNeed = 0;
			if ((Object)(object)piece == (Object)null)
			{
				return;
			}
			Requirement[] resources = piece.m_resources;
			foreach (Requirement val in resources)
			{
				if (!((Object)(object)val?.m_resItem == (Object)null) && val.m_amount > 0)
				{
					SeedsHave = ((Humanoid)player).GetInventory().CountItems(val.m_resItem.m_itemData.m_shared.m_name, -1, true);
					SeedsNeed = num * val.m_amount;
					break;
				}
			}
		}

		private static void ShowGhosts(GameObject ghost)
		{
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			if (_ghostSource != ((Object)ghost).name)
			{
				DestroyGhosts();
			}
			_ghostSource = ((Object)ghost).name;
			for (int i = 1; i < Cells.Count; i++)
			{
				while (Ghosts.Count < i)
				{
					Ghosts.Add(CloneGhost(ghost));
					GhostTint.Add(-1);
				}
				GameObject val = Ghosts[i - 1];
				if ((Object)(object)val == (Object)null)
				{
					val = CloneGhost(ghost);
					Ghosts[i - 1] = val;
					GhostTint[i - 1] = -1;
				}
				if (!val.activeSelf)
				{
					val.SetActive(true);
				}
				val.transform.SetPositionAndRotation(Cells[i].Pos, _rotation);
				int num = (Cells[i].Ok ? 1 : 0);
				if (GhostTint[i - 1] != num)
				{
					GhostTint[i - 1] = num;
					Tint(val, Cells[i].Ok);
				}
			}
			for (int j = Math.Max(0, Cells.Count - 1); j < Ghosts.Count; j++)
			{
				if ((Object)(object)Ghosts[j] != (Object)null && Ghosts[j].activeSelf)
				{
					Ghosts[j].SetActive(false);
				}
			}
		}

		private static GameObject CloneGhost(GameObject ghost)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			if ((Object)(object)_cloneHolder == (Object)null)
			{
				_cloneHolder = new GameObject("FarmHandGhostHolder");
				_cloneHolder.SetActive(false);
				Object.DontDestroyOnLoad((Object)(object)_cloneHolder);
			}
			GameObject val = Object.Instantiate<GameObject>(ghost, _cloneHolder.transform, false);
			((Object)val).name = ((Object)ghost).name + "_FarmHandGhost";
			for (int i = 0; i < 3; i++)
			{
				MonoBehaviour[] componentsInChildren = val.GetComponentsInChildren<MonoBehaviour>(true);
				foreach (MonoBehaviour val2 in componentsInChildren)
				{
					try
					{
						Object.DestroyImmediate((Object)(object)val2);
					}
					catch (Exception)
					{
					}
				}
			}
			Collider[] componentsInChildren2 = val.GetComponentsInChildren<Collider>(true);
			foreach (Collider val3 in componentsInChildren2)
			{
				try
				{
					Object.DestroyImmediate((Object)(object)val3);
				}
				catch (Exception)
				{
					val3.enabled = false;
				}
			}
			Rigidbody[] componentsInChildren3 = val.GetComponentsInChildren<Rigidbody>(true);
			foreach (Rigidbody val4 in componentsInChildren3)
			{
				try
				{
					Object.DestroyImmediate((Object)(object)val4);
				}
				catch (Exception)
				{
				}
			}
			val.transform.SetParent((Transform)null, false);
			return val;
		}

		private static void Tint(GameObject g, bool ok)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_002f: 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)
			if (_badTint == null)
			{
				_badTint = new MaterialPropertyBlock();
				_badTint.SetColor("_Color", new Color(1f, 0.25f, 0.2f, 1f));
				_badTint.SetColor("_EmissionColor", new Color(0.7f, 0.08f, 0.04f, 1f));
			}
			Renderer[] componentsInChildren = g.GetComponentsInChildren<Renderer>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].SetPropertyBlock(ok ? null : _badTint);
			}
		}

		private static void DestroyGhosts()
		{
			foreach (GameObject ghost in Ghosts)
			{
				if ((Object)(object)ghost != (Object)null)
				{
					Object.Destroy((Object)(object)ghost);
				}
			}
			Ghosts.Clear();
			GhostTint.Clear();
		}

		internal static void HideGhosts()
		{
			if (Ghosts.Count > 0)
			{
				DestroyGhosts();
			}
			Cells.Clear();
			_ghostSource = null;
			PlacingCrop = false;
			_nextCheck = 0f;
		}

		internal static void AfterPlaced(Player player, Piece piece)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			if (_placingExtras || !PlacingCrop || Cells.Count <= 1 || (Object)(object)piece == (Object)null || (Object)(object)((Component)piece).GetComponent<Plant>() == (Object)null)
			{
				return;
			}
			_placingExtras = true;
			try
			{
				int num = 1;
				string missing = null;
				bool globalKey = ZoneSystem.instance.GetGlobalKey(piece.FreeBuildKey());
				ItemData rightItem = ((Humanoid)player).RightItem;
				for (int i = 1; i < Cells.Count; i++)
				{
					if (Cells[i].Ok)
					{
						if (!globalKey && !HaveSeeds(player, piece, 1, out missing))
						{
							break;
						}
						float num2 = ((BuildStamina != null) ? ((float)BuildStamina.Invoke(player, null)) : 0f);
						if (!((Character)player).HaveStamina(num2 + 0.1f))
						{
							Hud.instance.StaminaBarEmptyFlash();
							break;
						}
						if (rightItem != null && rightItem.m_shared.m_useDurability && rightItem.m_durability <= 0f)
						{
							break;
						}
						bool flag = ((Humanoid)player).GetInventory().ItemCheated(piece.m_resources, -1, true) && !PlayerProfile.s_bypassCheatChecks;
						player.PlacePiece(piece, Cells[i].Pos, _rotation, false, flag);
						if (!globalKey)
						{
							player.ConsumeResources(piece.m_resources, 0, -1, 1);
						}
						((Character)player).UseStamina(num2);
						if (rightItem != null && rightItem.m_shared.m_useDurability && PlaceDurability != null)
						{
							rightItem.m_durability -= (float)PlaceDurability.Invoke(player, new object[1] { rightItem }) * Game.m_durabilityRate;
						}
						RaiseSkill(player);
						num++;
					}
				}
				((Character)player).Message((MessageType)1, (missing != null) ? Lang.T("planted_short", num, missing) : Lang.T("planted", num), 0, (Sprite)null, false);
				Invalidate();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Grid planting failed: " + ex));
			}
			finally
			{
				_placingExtras = false;
			}
		}

		private static bool HaveSeeds(Player player, Piece piece, int reserve, out string missing)
		{
			missing = null;
			Requirement[] resources = piece.m_resources;
			foreach (Requirement val in resources)
			{
				if (!((Object)(object)val?.m_resItem == (Object)null) && val.m_amount > 0)
				{
					string name = val.m_resItem.m_itemData.m_shared.m_name;
					if (((Humanoid)player).GetInventory().CountItems(name, -1, true) < val.m_amount * (1 + reserve))
					{
						missing = Localization.instance.Localize(name);
						return false;
					}
				}
			}
			return true;
		}

		private static void RaiseSkill(Player player)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			object? obj = BuildPiecesField?.GetValue(player);
			PieceTable val = (PieceTable)((obj is PieceTable) ? obj : null);
			if (val != null && (int)val.m_skill != 0)
			{
				((Character)player).RaiseSkill(val.m_skill, 1f);
			}
		}

		private static void SetStatus(Player player, string problem)
		{
			if (StatusField == null)
			{
				return;
			}
			string value = ((problem == Lang.T("bad_biome")) ? "WrongBiome" : ((problem == Lang.T("bad_soil")) ? "NeedCultivated" : ((problem == Lang.T("bad_space")) ? "MoreSpace" : "Invalid")));
			try
			{
				StatusField.SetValue(player, Enum.Parse(StatusField.FieldType, value));
				SetGhostValid?.Invoke(player, new object[1] { false });
			}
			catch (Exception)
			{
			}
		}

		private static void ClearCultivatedStatus(Player player)
		{
			if (!(StatusField == null) && !(StatusField.GetValue(player).ToString() != "NeedCultivated"))
			{
				StatusField.SetValue(player, Enum.Parse(StatusField.FieldType, "Valid"));
				SetGhostValid?.Invoke(player, new object[1] { true });
			}
		}

		internal static float Ground(Vector3 p)
		{
			//IL_001c: 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)
			float result = default(float);
			if (!((Object)(object)ZoneSystem.instance != (Object)null) || !ZoneSystem.instance.GetGroundHeight(p, ref result))
			{
				return p.y;
			}
			return result;
		}

		private static Vector3 Flat(Vector3 v)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			v.y = 0f;
			if (!(((Vector3)(ref v)).sqrMagnitude < 1E-06f))
			{
				return ((Vector3)(ref v)).normalized;
			}
			return Vector3.forward;
		}

		private static float FlatDistance(Vector3 a, Vector3 b)
		{
			//IL_0016: 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)
			a.y = (b.y = 0f);
			return Vector3.Distance(a, b);
		}
	}
	[HarmonyPatch]
	internal static class KeepGridRotationPatch
	{
		private static readonly FieldRef<Player, int> PlaceRotation = AccessTools.FieldRefAccess<Player, int>("m_placeRotation");

		private static IEnumerable<MethodBase> TargetMethods()
		{
			MethodBase methodBase = AccessTools.Method(typeof(Player), "PlacePiece", (Type[])null, (Type[])null);
			MethodBase setup = AccessTools.Method(typeof(Player), "SetupPlacementGhost", (Type[])null, (Type[])null);
			if (methodBase != null)
			{
				yield return methodBase;
			}
			if (setup != null)
			{
				yield return setup;
			}
		}

		private static void Prefix(Player __instance, out int __state)
		{
			__state = PlaceRotation.Invoke(__instance);
		}

		private static void Postfix(Player __instance, int __state)
		{
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer && FarmMode.On && Plugin.Helpers && GridPlanter.PlacingCrop)
			{
				PlaceRotation.Invoke(__instance) = __state;
			}
		}
	}
	[HarmonyPatch(typeof(Player), "UpdatePlacementGhost")]
	internal static class UpdatePlacementGhostPatch
	{
		private static void Postfix(Player __instance)
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			try
			{
				GridPlanter.AfterGhostUpdate(__instance);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Grid preview failed: " + ex.Message));
				GridPlanter.HideGhosts();
			}
		}
	}
	[HarmonyPatch(typeof(Player), "TryPlacePiece")]
	internal static class TryPlacePiecePatch
	{
		private static void Postfix(Player __instance, Piece piece, bool __result)
		{
			if (__result && (Object)(object)__instance == (Object)(object)Player.m_localPlayer && FarmMode.On && Plugin.Helpers)
			{
				GridPlanter.AfterPlaced(__instance, piece);
			}
		}
	}
	[HarmonyPatch(typeof(Pickable), "Interact")]
	internal static class MassHarvestPatch
	{
		private static bool _busy;

		private static bool Active
		{
			get
			{
				if (FarmMode.On)
				{
					return Plugin.Helpers;
				}
				return false;
			}
		}

		private static void Prefix(Pickable __instance, Humanoid character, bool repeat, ref bool __state)
		{
			__state = !repeat && (Object)(object)character == (Object)(object)Player.m_localPlayer && Active && Crops.IsCrop(__instance) && __instance.CanBePicked();
		}

		private static void Postfix(Pickable __instance, Humanoid character, bool __state)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			if (!__state || _busy)
			{
				return;
			}
			Player val = (Player)character;
			_busy = true;
			try
			{
				Replanter.Queue(__instance);
				if (!Plugin.MassHarvest.Value)
				{
					return;
				}
				int num = 1;
				Vector3 position = ((Component)__instance).transform.position;
				float value = Plugin.HarvestRadius.Value;
				foreach (Pickable item in CropIndex.RipeAround(position, value))
				{
					if (!((Object)(object)item == (Object)(object)__instance) && item.CanBePicked())
					{
						Replanter.Queue(item);
						item.Interact((Humanoid)(object)val, false, false);
						num++;
					}
				}
				if (num > 1)
				{
					((Character)val).Message((MessageType)1, Lang.T("harvested", num), 0, (Sprite)null, false);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Mass harvest failed: " + ex));
			}
			finally
			{
				_busy = false;
			}
		}
	}
	internal class Replanter : MonoBehaviour
	{
		private struct Job
		{
			public Piece Piece;

			public string Harvest;

			public Vector3 Pos;

			public float At;

			public float Queued;
		}

		private const float Delay = 1f;

		private const float GiveUpAfter = 4f;

		private static readonly List<Job> Jobs = new List<Job>();

		private static int _planted;

		private static int _short;

		private static int _alt;

		private static float _reportAt;

		public static void Queue(Pickable pickable)
		{
			//IL_007e: 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)
			if (Plugin.Replant.Value && FarmMode.On && Plugin.Helpers && !((Object)(object)pickable == (Object)null) && !NewCrops.Regrows(pickable))
			{
				Piece val = Crops.ReplantPiece(pickable);
				if (!((Object)(object)val == (Object)null))
				{
					Jobs.Add(new Job
					{
						Piece = val,
						Harvest = (((Object)(object)pickable.m_itemPrefab != (Object)null) ? ((Object)pickable.m_itemPrefab).name : null),
						Pos = ((Component)pickable).transform.position,
						At = Time.time + 1f,
						Queued = Time.time
					});
				}
			}
		}

		private void Update()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				Jobs.Clear();
				return;
			}
			if (Plugin.Enabled.Value)
			{
				CropIndex.RescueStuck();
			}
			for (int num = Jobs.Count - 1; num >= 0; num--)
			{
				if (!(Time.time < Jobs[num].At))
				{
					Job job = Jobs[num];
					Jobs.RemoveAt(num);
					try
					{
						PlantJob(localPlayer, job);
					}
					catch (Exception ex)
					{
						Plugin.Log.LogWarning((object)("Replant failed: " + ex.Message));
					}
					_reportAt = Time.time + 0.4f;
				}
			}
			if (Jobs.Count == 0 && _reportAt > 0f && Time.time >= _reportAt)
			{
				_reportAt = 0f;
				if (_planted > 0)
				{
					((Character)localPlayer).Message((MessageType)1, Lang.T("replanted", _planted), 0, (Sprite)null, false);
				}
				if (_alt > 0)
				{
					((Character)localPlayer).Message((MessageType)1, Lang.T("replant_alt", _alt), 0, (Sprite)null, false);
				}
				if (_short > 0)
				{
					((Character)localPlayer).Message((MessageType)1, Lang.T("replant_short", _short), 0, (Sprite)null, false);
				}
				_planted = (_short = (_alt = 0));
			}
		}

		private static void PlantJob(Player player, Job job)
		{
			//IL_000f: 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_00bb: 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_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			Piece val = job.Piece;
			bool flag = false;
			bool globalKey = ZoneSystem.instance.GetGlobalKey(val.FreeBuildKey());
			if (!globalKey && !player.HaveRequirements(val, (RequirementMode)0))
			{
				Piece val2 = (Plugin.ReplantWithHarvest.Value ? Crops.PieceUsing(job.Harvest) : null);
				if (!((Object)(object)val2 != (Object)null) || !((Object)(object)val2 != (Object)(object)val) || !player.HaveRequirements(val2, (RequirementMode)0))
				{
					if (Time.time - job.Queued < 4f)
					{
						job.At = Time.time + 0.5f;
						Jobs.Add(job);
					}
					else
					{
						_short++;
					}
					return;
				}
				val = val2;
				flag = true;
			}
			job.Piece = val;
			Vector3 pos = job.Pos;
			pos.y = GridPlanter.Ground(pos);
			Plant component = ((Component)job.Piece).GetComponent<Plant>();
			Heightmap val3 = Heightmap.FindHeightmap(pos);
			if (!((Object)(object)component != (Object)null) || !((Object)(object)val3 != (Object)null) || !component.m_needCultivatedGround || val3.IsCultivated(pos))
			{
				Quaternion val4 = Quaternion.Euler(0f, (float)Random.Range(0, 16) * 22.5f, 0f);
				bool flag2 = ((Humanoid)player).GetInventory().ItemCheated(job.Piece.m_resources, -1, true) && !PlayerProfile.s_bypassCheatChecks;
				player.PlacePiece(job.Piece, pos, val4, false, flag2);
				if (!globalKey)
				{
					player.ConsumeResources(job.Piece.m_resources, 0, -1, 1);
				}
				if (flag)
				{
					_alt++;
				}
				else
				{
					_planted++;
				}
			}
		}
	}
	internal static class Lang
	{
		private static readonly Dictionary<string, string[]> Table = new Dictionary<string, string[]>
		{
			["mode_on"] = new string[2] { "Farm mode ON", "농사 모드 켜짐" },
			["mode_off"] = new string[2] { "Farm mode OFF", "농사 모드 꺼짐" },
			["no_cultivator"] = new string[2] { "No cultivator in your inventory - harvesting and crop info still work", "인벤토리에 경작기가 없어요 - 수확과 작물 정보는 쓸 수 있어요" },
			["plant_easily"] = new string[2] { "PlantEasily is installed - FarmHand shows crop info only", "PlantEasily 가 설치돼 있어서 FarmHand 는 작물 정보만 보여줘요" },
			["title"] = new string[2] { "Farm mode", "농사 모드" },
			["grid"] = new string[2] { "Grid {0} × {1}", "격자 {0} × {1}" },
			["single"] = new string[2] { "Single seed", "한 개씩" },
			["spacing"] = new string[2] { "spacing {0:0.0#} m", "간격 {0:0.0#}m" },
			["snapped"] = new string[2] { "lined up with your field (hold Shift: free)", "기존 밭에 맞춤 (Shift: 자유 배치)" },
			["seeds"] = new string[2] { "Seeds: {1} needed ({0} in bag)", "씨앗 {1}개 필요 (보유 {0}개)" },
			["bad_cells"] = new string[2] { "{0} can't be planted", "{0}칸 심을 수 없음" },
			["stamina"] = new string[2] { "stamina {0}%", "스태미나 {0}%" },
			["hint_plant"] = new string[2] { "[Wheel] turn · [{0}+Wheel] per row · [{1}+Wheel] rows · [Shift] free · [{2}] grid · [{3}] exit", "[휠] 방향 · [{0}+휠] 칸 수 · [{1}+휠] 줄 수 · [Shift] 자유 배치 · [{2}] 격자 · [{3}] 나가기" },
			["hint_harvest"] = new string[2] { "Pick a ripe crop to harvest everything within {0} m{1}", "다 자란 작물을 수확하면 주변 {0}m 를 한꺼번에{1}" },
			["hint_replant"] = new string[2] { " and replant it", " 수확하고 다시 심어요" },
			["hint_no_replant"] = new string[2] { "", " 수확해요" },
			["hold_seeds"] = new string[2] { "Pick a seed with the cultivator (right click) to plant", "경작기를 들고 오른쪽 클릭으로 씨앗을 고르세요" },
			["planted"] = new string[2] { "Planted {0}", "{0}개 심음" },
			["planted_short"] = new string[2] { "Planted {0} - not enough {1}", "{0}개 심음 - {1} 부족" },
			["harvested"] = new string[2] { "Harvested {0} crops", "작물 {0}개 수확" },
			["replanted"] = new string[2] { "Replanted {0}", "{0}개 다시 심음" },
			["replant_alt"] = new string[2] { "Out of seeds: planted {0} seed crops with your harvest", "씨앗이 없어 수확물로 씨앗 작물 {0}개를 심었어요" },
			["seed_short"] = new string[2] { "{0}: {1} short to replant", "다시 심기에 {0} {1}개 부족" },
			["seed_hint"] = new string[2] { "grow {0} to get more", "{0}을(를) 키우면 얻어요" },
			["seed_hint_alt"] = new string[2] { "harvest will plant {0} instead", "모자라면 수확물로 {0}을(를) 대신 심어요" },
			["set_replant_harvest"] = new string[2] { "Out of seeds: plant seed crops with the harvest", "씨앗이 없으면 수확물로 씨앗 작물 심기" },
			["replant_short"] = new string[2] { "Not enough seeds to replant {0}", "씨앗이 부족해 {0}개는 다시 못 심었어요" },
			["field_title"] = new string[2] { "Fields nearby", "근처 밭 현황" },
			["field_radius"] = new string[2] { "({0} m)", "({0}m)" },
			["field_ready"] = new string[2] { "Ready", "다 자람" },
			["field_growing"] = new string[2] { "Growing", "자라는 중" },
			["field_problem"] = new string[2] { "Not growing", "문제 있음" },
			["field_next"] = new string[2] { "{0} ×{1} · in {2}", "{0} {1}개 · {2} 뒤" },
			["field_none"] = new string[2] { "No crops nearby", "근처에 작물이 없어요" },
			["growth"] = new string[2] { "Growth {0}%", "성장 {0}%" },
			["time_left"] = new string[2] { "about {0} left", "약 {0} 남음" },
			["ready_soon"] = new string[2] { "ready any moment", "곧 다 자라요" },
			["ok"] = new string[2] { "Growing well", "잘 자라는 중" },
			["st_NoSun"] = new string[2] { "No sunlight - move it out from under the roof", "햇빛이 없어요 - 지붕 밑에서는 안 자라요" },
			["st_NoSpace"] = new string[2] { "Too close to another crop - dig it up and replant", "옆 작물과 너무 가까워요 - 뽑고 다시 심으세요" },
			["st_WrongBiome"] = new string[2] { "Can't grow in this biome (grows in: {0})", "이 바이옴에서는 안 자라요 (자라는 곳: {0})" },
			["st_NotCultivated"] = new string[2] { "The ground isn't cultivated", "경작한 땅이 아니에요" },
			["st_NoAttachPiece"] = new string[2] { "Needs something to climb on", "타고 올라갈 곳이 필요해요" },
			["st_TooHot"] = new string[2] { "Too hot here", "여기는 너무 더워요" },
			["st_TooCold"] = new string[2] { "Too cold here", "여기는 너무 추워요" },
			["st_other"] = new string[2] { "Not growing ({0})", "자라지 않음 ({0})" },
			["wont_grow"] = new string[2] { "It won't grow up until this is fixed", "이 문제가 풀리기 전에는 다 자라지 않아요" },
			["will_wither"] = new string[2] { "It will wither away if this isn't fixed in time", "제때 해결하지 않으면 시들어 없어져요" },
			["ripe_hint"] = new string[2] { "Farm mode: picks every ripe crop within {0} m", "농사 모드: 주변 {0}m 다 자란 작물을 한꺼번에 수확" },
			["bad_biome"] = new string[2] { "Can't grow in this biome", "이 바이옴에서는 안 자라요" },
			["bad_roof"] = new string[2] { "No sunlight here", "여기는 햇빛이 없어요" },
			["bad_space"] = new string[2] { "Too close to another crop", "다른 작물과 너무 가까워요" },
			["bad_soil"] = new string[2] { "Needs cultivated ground", "경작한 땅이 필요해요" },
			["seedling"] = new string[2] { "{0} seedling", "{0} 모종" },
			["bush_seedling"] = new string[2] { "{0} bush seedling", "{0} 덤불 모종" },
			["seedling_desc"] = new string[2] { "FarmHand: plant on cultivated ground. Grows in {1} days, and gives {0} again {2} days after each harvest.", "FarmHand: 경작지에 심어요. {1}일 뒤 다 자라고, 수확할 때마다 {2}일 뒤 {0}이(가) 다시 열려요." },
			["menu_button"] = new string[2] { "Farm Settings", "농사 설정" },
			["settings_title"] = new string[2] { "FarmHand Settings", "FarmHand 설정" },
			["tab_Planting"] = new string[2] { "Planting", "심기" },
			["tab_Harvest"] = new string[2] { "Harvest", "수확" },
			["tab_NewCrops"] = new string[2] { "New crops", "새 작물" },
			["tab_General"] = new string[2] { "General", "일반" },
			["close"] = new string[2] { "Close", "닫기" },
			["set_grid"] = new string[2] { "Grid planting (farm mode)", "격자 심기 (농사 모드)" },
			["set_columns"] = new string[2] { "Seeds per row", "한 줄 칸 수" },
			["set_rows"] = new string[2] { "Rows", "줄 수" },
			["set_spacing"] = new string[2] { "Extra spacing (m)", "추가 간격 (m)" },
			["set_snap"] = new string[2] { "Line up with crops already planted", "이미 심은 밭에 줄 맞추기" },
			["set_block"] = new string[2] { "Don't plant where crops can't grow", "안 자랄 자리에는 심지 않기" },
			["set_stamina"] = new string[2] { "Stamina use (%)", "스태미나 소모 (%)" },
			["set_mass"] = new string[2] { "Harvest everything around at once", "주변 작물 한꺼번에 수확" },
			["set_radius"] = new string[2] { "Harvest radius (m)", "수확 범위 (m)" },
			["set_replant"] = new string[2] { "Replant after harvesting", "수확하고 다시 심기" },
			["set_panel"] = new string[2] { "Show the field panel", "밭 현황 패널 보이기" },
			["set_panel_radius"] = new string[2] { "Field panel radius (m)", "밭 현황 범위 (m)" },
			["set_restart"] = new string[2] { "Changes on this tab apply after restarting the game", "이 탭의 변경은 게임을 다시 시작하면 적용돼요" },
			["set_newcrops"] = new string[2] { "Plant bushes, mushrooms and herbs", "덤불·버섯·약초 심기" },
			["set_native"] = new string[2] { "Only in their own biome", "원래 자라는 바이옴에서만" },
			["set_grow_days"] = new string[2] { "Days to grow", "자라는 날 (게임 일)" },
			["set_regrow_days"] = new string[2] { "Days to regrow", "다시 열리는 날 (게임 일)" },
			["col_plant"] = new string[2] { "Plant", "식물" },
			["col_cost"] = new string[2] { "Cost", "재료" },
			["col_yield"] = new string[2] { "Harvest", "수확량" },
			["set_enabled"] = new string[2] { "FarmHand on", "FarmHand 켜기" },
			["set_equip"] = new string[2] { "Farm mode takes out the cultivator", "농사 모드에서 경작기 자동으로 들기" },
			["set_info"] = new string[2] { "Crop info", "작물 정보" },
			["info_Always"] = new string[2] { "Always", "항상" },
			["info_FarmModeOnly"] = new string[2] { "Farm mode", "농사 모드만" },
			["info_Off"] = new string[2] { "Off", "끄기" },
			["set_language"] = new string[2] { "Language", "언어" },
			["lang_Auto"] = new string[2] { "Auto", "자동" },
			["lang_English"] = new string[2] { "English", "English" },
			["lang_Korean"] = new string[2] { "한국어", "한국어" },
			["set_keys"] = new string[2] { "Keys", "단축키" },
			["key_mode"] = new string[2] { "Farm mode on / off", "농사 모드 켜기/끄기" },
			["key_grid"] = new string[2] { "Grid on / off", "격자 켜기/끄기" },
			["key_columns"] = new string[2] { "Seeds per row", "한 줄 칸 수" },
			["key_rows"] = new string[2] { "Rows", "줄 수" },
			["key_menu"] = new string[2] { "This window", "이 창" },
			["key_menu_value"] = new string[2] { "ESC menu > Farm Settings", "ESC 메뉴 > 농사 설정" },
			["set_keys_hint"] = new string[2] { "Keys can be changed in BepInEx/config/lazly.valheim.farmhand.cfg", "단축키는 BepInEx/config/lazly.valheim.farmhand.cfg 에서 바꿀 수 있어요" },
			["set_reset"] = new string[2] { "Reset to defaults", "기본값으로 되돌리기" },
			["crop_Raspberry"] = new string[2] { "Raspberry bush", "라즈베리 덤불" },
			["crop_Blueberry"] = new string[2] { "Blueberry bush", "블루베리 덤불" },
			["crop_Cloudberry"] = new string[2] { "Cloudberry bush", "클라우드베리 덤불" },
			["crop_Mushroom"] = new string[2] { "Mushroom", "버섯" },
			["crop_MushroomYellow"] = new string[2] { "Yellow mushroom", "노란 버섯" },
			["crop_MushroomBlue"] = new string[2] { "Blue mushroom", "파란 버섯" },
			["crop_Thistle"] = new string[2] { "Thistle", "엉겅퀴" },
			["crop_Dandelion"] = new string[2] { "Dandelion", "민들레" },
			["crop_Fiddlehead"] = new string[2] { "Fiddlehead", "고사리순" },
			["crop_SmokePuff"] = new string[2] { "Smoke puff", "연기버섯" },
			["min"] = new string[2] { "{0} min", "{0}분" },
			["hour"] = new string[2] { "{0} h {1} min", "{0}시간 {1}분" },
			["sec"] = new string[2] { "{0} s", "{0}초" }
		};

		private static bool _korean;

		private static float _korenCheckedAt = -10f;

		public static bool IsKorean
		{
			get
			{
				if (Time.unscaledTime - _korenCheckedAt < 1f)
				{
					return _korean;
				}
				_korenCheckedAt = Time.unscaledTime;
				_korean = ReadKorean;
				return _korean;
			}
		}

		private static bool ReadKorean
		{
			get
			{
				switch (Plugin.Language.Value)
				{
				case UiLanguage.Korean:
					return true;
				case UiLanguage.English:
					return false;
				default:
					if (Localization.instance == null)
					{
						return false;
					}
					return Traverse.Create((object)Localization.instance).Method("GetSelectedLanguage", Array.Empty<object>()).GetValue() as string == "Korean";
				}
			}
		}

		public static string T(string key, params object[] args)
		{
			if (!Table.TryGetValue(key, out var value))
			{
				return key;
			}
			string text = value[IsKorean ? 1u : 0u];
			if (args.Length != 0)
			{
				return string.Format(text, args);
			}
			return text;
		}

		public static string BoldHangul(string text)
		{
			if (string.IsNullOrEmpty(text))
			{
				return text ?? "";
			}
			StringBuilder stringBuilder = new StringBuilder(text.Length + 16);
			bool flag = false;
			foreach (char c in text)
			{
				bool flag2 = (c >= '가' && c <= '힣') || (c >= 'ᄀ' && c <= 'ᇿ') || (c >= '\u3130' && c <= '\u318f');
				if (flag2 && !flag)
				{
					stringBuilder.Append("<b>");
					flag = true;
				}
				else if (!flag2 && flag)
				{
					stringBuilder.Append("</b>");
					flag = false;
				}
				if (c == '<')
				{
					stringBuilder.Append("<noparse><</noparse>");
				}
				else
				{
					stringBuilder.Append(c);
				}
			}
			if (flag)
			{
				stringBuilder.Append("</b>");
			}
			return stringBuilder.ToString();
		}

		public static bool Has(string key)
		{
			return Table.ContainsKey(key);
		}

		public static string Duration(double seconds)
		{
			if (seconds < 60.0)
			{
				return T("sec", (int)Math.Ceiling(seconds));
			}
			int num = (int)Math.Ceiling(seconds / 60.0);
			if (num >= 60)
			{
				return T("hour", num / 60, num % 60);
			}
			return T("min", num);
		}

		public unsafe static string KeyName(KeyCode key)
		{
			//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_0024: Expected I4, but got Unknown
			switch (key - 303)
			{
			case 4:
			case 5:
				return "Alt";
			case 2:
			case 3:
				return "Ctrl";
			case 0:
			case 1:
				return "Shift";
			default:
				return ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString();
			}
		}
	}
	internal static class NewCrops
	{
		private class Def
		{
			public string Key;

			public string Wild;

			public bool Bush;

			public int Cost;

			public int Yield;

			public Biome Biome;

			public bool Heat;

			public bool Cold;

			public ConfigEntry<bool> On;

			public ConfigEntry<int> CostEntry;

			public ConfigEntry<int> YieldEntry;

			public GameObject Sapling;

			public GameObject Grown;
		}

		internal struct Entry
		{
			public string Name;

			public ConfigEntry<bool> On;

			public ConfigEntry<int> Cost;

			public ConfigEntry<int> Yield;
		}

		private const Biome AllBiomes = (Biome)639;

		private static readonly List<Def> Defs = new List<Def>
		{
			new Def
			{
				Key = "Raspberry",
				Wild = "RaspberryBush",
				Bush = true,
				Cost = 10,
				Yield = 3,
				Biome = (Biome)1
			},
			new Def
			{
				Key = "Blueberry",
				Wild = "BlueberryBush",
				Bush = true,
				Cost = 10,
				Yield = 3,
				Biome = (Biome)8
			},
			new Def
			{
				Key = "Cloudberry",
				Wild = "CloudberryBush",
				Bush = true,
				Cost = 10,
				Yield = 3,
				Biome = (Biome)16
			},
			new Def
			{
				Key = "Mushroom",
				Wild = "Pickable_Mushroom",
				Cost = 5,
				Yield = 2,
				Biome = (Biome)9
			},
			new Def
			{
				Key = "MushroomYellow",
				Wild = "Pickable_Mushroom_yellow",
				Cost = 5,
				Yield = 2,
				Biome = (Biome)10
			},
			new Def
			{
				Key = "MushroomBlue",
				Wild = "Pickable_Mushroom_blue",
				Cost = 5,
				Yield = 2,
				Biome = (Biome)76,
				Cold = true
			},
			new Def
			{
				Key = "Thistle",
				Wild = "Pickable_Thistle",
				Cost = 5,
				Yield = 2,
				Biome = (Biome)9
			},
			new Def
			{
				Key = "Dandelion",
				Wild = "Pickable_Dandelion",
				Cost = 5,
				Yield = 2,
				Biome = (Biome)1
			},
			new Def
			{
				Key = "Fiddlehead",
				Wild