Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of FarmHand v1.0.0
plugins/FarmHand.dll
Decompiled 2 days ago
The result has been truncated due to the large size, download it to view full contents!
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