Decompiled source of CropOptimizer v1.4.3

CropOptimizer.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using CropOptimizer.Config;
using CropOptimizer.Data;
using CropOptimizer.Integration;
using CropOptimizer.Patches;
using CropOptimizer.UI;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using SunhavenMods.Shared;
using TMPro;
using TheVault.Modding;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using Wish;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("CropOptimizer")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+dbdcb88891adceccfb15f78cab211a27ae203678")]
[assembly: AssemblyProduct("CropOptimizer")]
[assembly: AssemblyTitle("CropOptimizer")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 SunhavenMods.Shared
{
	public static class ConfigFileHelper
	{
		public static ConfigFile CreateNamedConfig(string pluginGuid, string configFileName, Action<string> logWarning = null)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			string text = Path.Combine(Paths.ConfigPath, configFileName);
			string text2 = Path.Combine(Paths.ConfigPath, pluginGuid + ".cfg");
			try
			{
				if (!File.Exists(text) && File.Exists(text2))
				{
					File.Copy(text2, text);
				}
			}
			catch (Exception ex)
			{
				logWarning?.Invoke("[Config] Migration to " + configFileName + " failed: " + ex.Message);
			}
			return new ConfigFile(text, true);
		}

		public static bool ReplacePluginConfig(BaseUnityPlugin plugin, ConfigFile newConfig, Action<string> logWarning = null)
		{
			if ((Object)(object)plugin == (Object)null || newConfig == null)
			{
				return false;
			}
			try
			{
				Type typeFromHandle = typeof(BaseUnityPlugin);
				PropertyInfo property = typeFromHandle.GetProperty("Config", BindingFlags.Instance | BindingFlags.Public);
				if (property != null && property.CanWrite)
				{
					property.SetValue(plugin, newConfig, null);
					return true;
				}
				FieldInfo field = typeFromHandle.GetField("<Config>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic);
				if (field != null)
				{
					field.SetValue(plugin, newConfig);
					return true;
				}
				FieldInfo[] fields = typeFromHandle.GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo in fields)
				{
					if (fieldInfo.FieldType == typeof(ConfigFile))
					{
						fieldInfo.SetValue(plugin, newConfig);
						return true;
					}
				}
			}
			catch (Exception ex)
			{
				logWarning?.Invoke("[Config] ReplacePluginConfig failed: " + ex.Message);
			}
			return false;
		}
	}
	public abstract class PersistentRunnerBase : MonoBehaviour
	{
		private bool _wasInGame;

		private float _lastHeartbeat;

		private string _lastSceneName = "";

		private float _lastSceneCheckTime;

		private const float SceneCheckInterval = 0.5f;

		protected virtual float HeartbeatInterval => 0f;

		protected virtual string RunnerName => ((object)this).GetType().Name;

		protected virtual void OnUpdate()
		{
		}

		protected virtual void OnMenuTransition()
		{
		}

		protected virtual void OnGameTransition()
		{
		}

		protected virtual void Log(string message)
		{
		}

		protected virtual void LogWarning(string message)
		{
		}

		public static T CreateRunner<T>() where T : PersistentRunnerBase
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			GameObject val = new GameObject("[" + typeof(T).Name + "]")
			{
				hideFlags = (HideFlags)61
			};
			Object.DontDestroyOnLoad((Object)val);
			SceneRootSurvivor.TryRegisterPersistentRunnerGameObject(val);
			return val.AddComponent<T>();
		}

		protected virtual void Awake()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			_lastSceneName = ((Scene)(ref activeScene)).name;
			_wasInGame = !SceneHelpers.IsMenuScene(_lastSceneName);
			Log("[" + RunnerName + "] Initialized in scene: " + _lastSceneName);
		}

		protected virtual void Update()
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			if (HeartbeatInterval > 0f)
			{
				_lastHeartbeat += Time.deltaTime;
				if (_lastHeartbeat >= HeartbeatInterval)
				{
					_lastHeartbeat = 0f;
					Log("[" + RunnerName + "] Heartbeat - still alive");
				}
			}
			float unscaledTime = Time.unscaledTime;
			if (unscaledTime - _lastSceneCheckTime >= 0.5f)
			{
				_lastSceneCheckTime = unscaledTime;
				Scene activeScene = SceneManager.GetActiveScene();
				string name = ((Scene)(ref activeScene)).name;
				if (name != _lastSceneName)
				{
					_lastSceneName = name;
					HandleSceneChange(name);
				}
			}
			try
			{
				OnUpdate();
			}
			catch (Exception ex)
			{
				LogWarning("[" + RunnerName + "] Error in OnUpdate: " + ex.Message);
			}
		}

		private void HandleSceneChange(string sceneName)
		{
			bool flag = SceneHelpers.IsMenuScene(sceneName);
			if (_wasInGame && flag)
			{
				Log("[" + RunnerName + "] Menu transition detected");
				try
				{
					OnMenuTransition();
				}
				catch (Exception ex)
				{
					LogWarning("[" + RunnerName + "] Error in OnMenuTransition: " + ex.Message);
				}
			}
			else if (!_wasInGame && !flag)
			{
				Log("[" + RunnerName + "] Game transition detected");
				try
				{
					OnGameTransition();
				}
				catch (Exception ex2)
				{
					LogWarning("[" + RunnerName + "] Error in OnGameTransition: " + ex2.Message);
				}
			}
			_wasInGame = !flag;
		}

		protected virtual void OnDestroy()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			string text = (((Scene)(ref activeScene)).name ?? string.Empty).ToLowerInvariant();
			if (!Application.isPlaying || text.Contains("menu") || text.Contains("title"))
			{
				Log("[" + RunnerName + "] OnDestroy during app quit/menu unload (expected).");
			}
			else
			{
				LogWarning("[" + RunnerName + "] OnDestroy outside quit/menu (unexpected).");
			}
		}
	}
	public static class VersionChecker
	{
		public class VersionCheckResult
		{
			public bool Success { get; set; }

			public bool UpdateAvailable { get; set; }

			public string CurrentVersion { get; set; }

			public string LatestVersion { get; set; }

			public string ModName { get; set; }

			public string NexusUrl { get; set; }

			public string Changelog { get; set; }

			public string ErrorMessage { get; set; }
		}

		public class ModHealthSnapshot
		{
			public string PluginGuid { get; set; }

			public DateTime LastCheckUtc { get; set; }

			public int ExceptionCount { get; set; }

			public string LastError { get; set; }
		}

		private class VersionCheckRunner : MonoBehaviour
		{
			private ManualLogSource _pluginLog;

			public void StartCheck(string pluginGuid, string currentVersion, ManualLogSource pluginLog, Action<VersionCheckResult> onComplete)
			{
				_pluginLog = pluginLog;
				((MonoBehaviour)this).StartCoroutine(CheckVersionCoroutine(pluginGuid, currentVersion, onComplete));
			}

			private void LogInfo(string message)
			{
				ManualLogSource pluginLog = _pluginLog;
				if (pluginLog != null)
				{
					pluginLog.LogInfo((object)("[VersionChecker] " + message));
				}
			}

			private void LogWarningMsg(string message)
			{
				ManualLogSource pluginLog = _pluginLog;
				if (pluginLog != null)
				{
					pluginLog.LogWarning((object)("[VersionChecker] " + message));
				}
			}

			private void LogErrorMsg(string message)
			{
				ManualLogSource pluginLog = _pluginLog;
				if (pluginLog != null)
				{
					pluginLog.LogError((object)("[VersionChecker] " + message));
				}
			}

			private IEnumerator CheckVersionCoroutine(string pluginGuid, string currentVersion, Action<VersionCheckResult> onComplete)
			{
				VersionCheckResult result = new VersionCheckResult
				{
					CurrentVersion = currentVersion
				};
				UnityWebRequest www = UnityWebRequest.Get("https://azraelgodking.github.io/SunhavenMod/versions.json");
				try
				{
					www.timeout = 10;
					yield return www.SendWebRequest();
					if ((int)www.result == 2 || (int)www.result == 3)
					{
						result.Success = false;
						result.ErrorMessage = "Network error: " + www.error;
						RecordHealthError(pluginGuid, result.ErrorMessage);
						LogWarningMsg(result.ErrorMessage);
						onComplete?.Invoke(result);
						Object.Destroy((Object)(object)((Component)this).gameObject);
						yield break;
					}
					try
					{
						string text = www.downloadHandler.text;
						Match match = GetModPattern(pluginGuid).Match(text);
						if (!match.Success)
						{
							result.Success = false;
							result.ErrorMessage = "Mod '" + pluginGuid + "' not found in versions.json";
							RecordHealthError(pluginGuid, result.ErrorMessage);
							LogWarningMsg(result.ErrorMessage);
							onComplete?.Invoke(result);
							Object.Destroy((Object)(object)((Component)this).gameObject);
							yield break;
						}
						string value = match.Groups[1].Value;
						result.LatestVersion = ExtractJsonString(value, "version");
						result.ModName = ExtractJsonString(value, "name");
						result.NexusUrl = ExtractJsonString(value, "nexus");
						result.Changelog = ExtractJsonString(value, "changelog");
						if (string.IsNullOrEmpty(result.LatestVersion))
						{
							result.Success = false;
							result.ErrorMessage = "Could not parse version from response";
							RecordHealthError(pluginGuid, result.ErrorMessage);
							LogWarningMsg(result.ErrorMessage);
							onComplete?.Invoke(result);
							Object.Destroy((Object)(object)((Component)this).gameObject);
							yield break;
						}
						result.Success = true;
						result.UpdateAvailable = CompareVersions(currentVersion, result.LatestVersion) < 0;
						if (result.UpdateAvailable)
						{
							LogInfo("Update available for " + result.ModName + ": " + currentVersion + " -> " + result.LatestVersion);
						}
						else
						{
							LogInfo(result.ModName + " is up to date (v" + currentVersion + ")");
						}
					}
					catch (Exception ex)
					{
						result.Success = false;
						result.ErrorMessage = "Parse error: " + ex.Message;
						RecordHealthError(pluginGuid, result.ErrorMessage);
						LogErrorMsg(result.ErrorMessage);
					}
				}
				finally
				{
					((IDisposable)www)?.Dispose();
				}
				onComplete?.Invoke(result);
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}

			private string ExtractJsonString(string json, string key)
			{
				Match match = ExtractFieldRegex.Match(json);
				while (match.Success)
				{
					if (string.Equals(match.Groups["key"].Value, key, StringComparison.Ordinal))
					{
						return match.Groups["value"].Value;
					}
					match = match.NextMatch();
				}
				return null;
			}
		}

		private const string VersionsUrl = "https://azraelgodking.github.io/SunhavenMod/versions.json";

		private static readonly Dictionary<string, ModHealthSnapshot> HealthByPluginGuid = new Dictionary<string, ModHealthSnapshot>(StringComparer.OrdinalIgnoreCase);

		private static readonly object HealthLock = new object();

		private static readonly Dictionary<string, Regex> ModPatternCache = new Dictionary<string, Regex>(StringComparer.Ordinal);

		private static readonly object ModPatternCacheLock = new object();

		private static readonly Regex ExtractFieldRegex = new Regex("\"(?<key>[^\"]+)\"\\s*:\\s*(?:\"(?<value>[^\"]*)\"|null)", RegexOptions.Compiled);

		public static void CheckForUpdate(string pluginGuid, string currentVersion, ManualLogSource logger = null, Action<VersionCheckResult> onComplete = null)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			TouchHealth(pluginGuid);
			VersionCheckRunner versionCheckRunner = new GameObject("VersionChecker").AddComponent<VersionCheckRunner>();
			Object.DontDestroyOnLoad((Object)(object)((Component)versionCheckRunner).gameObject);
			SceneRootSurvivor.TryRegisterPersistentRunnerGameObject(((Component)versionCheckRunner).gameObject);
			versionCheckRunner.StartCheck(pluginGuid, currentVersion, logger, onComplete);
		}

		public static ModHealthSnapshot GetHealthSnapshot(string pluginGuid)
		{
			if (string.IsNullOrWhiteSpace(pluginGuid))
			{
				return null;
			}
			lock (HealthLock)
			{
				if (!HealthByPluginGuid.TryGetValue(pluginGuid, out ModHealthSnapshot value))
				{
					return null;
				}
				return new ModHealthSnapshot
				{
					PluginGuid = value.PluginGuid,
					LastCheckUtc = value.LastCheckUtc,
					ExceptionCount = value.ExceptionCount,
					LastError = value.LastError
				};
			}
		}

		public static int CompareVersions(string v1, string v2)
		{
			if (string.IsNullOrEmpty(v1) || string.IsNullOrEmpty(v2))
			{
				return 0;
			}
			v1 = v1.TrimStart('v', 'V');
			v2 = v2.TrimStart('v', 'V');
			int num = v1.IndexOfAny(new char[2] { '-', '+' });
			if (num >= 0)
			{
				v1 = v1.Substring(0, num);
			}
			int num2 = v2.IndexOfAny(new char[2] { '-', '+' });
			if (num2 >= 0)
			{
				v2 = v2.Substring(0, num2);
			}
			string[] array = v1.Split(new char[1] { '.' });
			string[] array2 = v2.Split(new char[1] { '.' });
			int num3 = Math.Max(array.Length, array2.Length);
			for (int i = 0; i < num3; i++)
			{
				int result;
				int num4 = ((i < array.Length && int.TryParse(array[i], out result)) ? result : 0);
				int result2;
				int num5 = ((i < array2.Length && int.TryParse(array2[i], out result2)) ? result2 : 0);
				if (num4 < num5)
				{
					return -1;
				}
				if (num4 > num5)
				{
					return 1;
				}
			}
			return 0;
		}

		private static void TouchHealth(string pluginGuid)
		{
			if (string.IsNullOrWhiteSpace(pluginGuid))
			{
				return;
			}
			lock (HealthLock)
			{
				if (!HealthByPluginGuid.TryGetValue(pluginGuid, out ModHealthSnapshot value))
				{
					value = new ModHealthSnapshot
					{
						PluginGuid = pluginGuid
					};
					HealthByPluginGuid[pluginGuid] = value;
				}
				value.LastCheckUtc = DateTime.UtcNow;
			}
		}

		private static void RecordHealthError(string pluginGuid, string errorMessage)
		{
			if (string.IsNullOrWhiteSpace(pluginGuid))
			{
				return;
			}
			lock (HealthLock)
			{
				if (!HealthByPluginGuid.TryGetValue(pluginGuid, out ModHealthSnapshot value))
				{
					value = new ModHealthSnapshot
					{
						PluginGuid = pluginGuid
					};
					HealthByPluginGuid[pluginGuid] = value;
				}
				value.LastCheckUtc = DateTime.UtcNow;
				value.ExceptionCount++;
				value.LastError = errorMessage;
			}
		}

		private static Regex GetModPattern(string pluginGuid)
		{
			lock (ModPatternCacheLock)
			{
				if (!ModPatternCache.TryGetValue(pluginGuid, out Regex value))
				{
					value = new Regex("\"" + Regex.Escape(pluginGuid) + "\"\\s*:\\s*\\{([^}]+)\\}", RegexOptions.Compiled | RegexOptions.Singleline);
					ModPatternCache[pluginGuid] = value;
				}
				return value;
			}
		}
	}
	public static class VersionCheckerExtensions
	{
		public static void NotifyUpdateAvailable(this VersionChecker.VersionCheckResult result, ManualLogSource logger = null)
		{
			if (!result.UpdateAvailable)
			{
				return;
			}
			string text = result.ModName + " update available: v" + result.LatestVersion;
			try
			{
				Type type = ReflectionHelper.FindWishType("NotificationStack");
				if (type != null)
				{
					Type type2 = ReflectionHelper.FindType("SingletonBehaviour`1", "Wish");
					if (type2 != null)
					{
						object obj = type2.MakeGenericType(type).GetProperty("Instance")?.GetValue(null);
						if (obj != null)
						{
							MethodInfo method = type.GetMethod("SendNotification", new Type[5]
							{
								typeof(string),
								typeof(int),
								typeof(int),
								typeof(bool),
								typeof(bool)
							});
							if (method != null)
							{
								method.Invoke(obj, new object[5] { text, 0, 1, false, true });
								return;
							}
						}
					}
				}
			}
			catch (Exception ex)
			{
				if (logger != null)
				{
					logger.LogWarning((object)("Failed to send native notification: " + ex.Message));
				}
			}
			if (logger != null)
			{
				logger.LogWarning((object)("[UPDATE AVAILABLE] " + text));
			}
			if (!string.IsNullOrEmpty(result.NexusUrl) && logger != null)
			{
				logger.LogWarning((object)("Download at: " + result.NexusUrl));
			}
		}
	}
	public static class SceneHelpers
	{
		private static readonly string[] MenuScenePatterns = new string[3] { "menu", "title", "bootstrap" };

		private static readonly string[] ExactMenuScenes = new string[2] { "MainMenu", "Bootstrap" };

		public static bool IsMenuScene(string sceneName)
		{
			if (string.IsNullOrEmpty(sceneName))
			{
				return true;
			}
			string[] exactMenuScenes = ExactMenuScenes;
			foreach (string text in exactMenuScenes)
			{
				if (sceneName == text)
				{
					return true;
				}
			}
			string text2 = sceneName.ToLowerInvariant();
			exactMenuScenes = MenuScenePatterns;
			foreach (string value in exactMenuScenes)
			{
				if (text2.Contains(value))
				{
					return true;
				}
			}
			return false;
		}

		public static bool IsCurrentSceneMenu()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			return IsMenuScene(((Scene)(ref activeScene)).name);
		}

		public static bool IsInGame()
		{
			return !IsCurrentSceneMenu();
		}

		public static string GetCurrentSceneName()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			return ((Scene)(ref activeScene)).name;
		}

		public static bool IsMainMenu()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			return ((Scene)(ref activeScene)).name == "MainMenu";
		}
	}
	public static class SceneRootSurvivor
	{
		private static readonly object Lock = new object();

		private static readonly List<string> NoKillSubstrings = new List<string>();

		private static Harmony _harmony;

		public static void TryRegisterPersistentRunnerGameObject(GameObject go)
		{
			if (!((Object)(object)go == (Object)null))
			{
				TryAddNoKillListSubstring(((Object)go).name);
			}
		}

		public static void TryAddNoKillListSubstring(string nameSubstring)
		{
			if (string.IsNullOrEmpty(nameSubstring))
			{
				return;
			}
			lock (Lock)
			{
				bool flag = false;
				for (int i = 0; i < NoKillSubstrings.Count; i++)
				{
					if (string.Equals(NoKillSubstrings[i], nameSubstring, StringComparison.OrdinalIgnoreCase))
					{
						flag = true;
						break;
					}
				}
				if (!flag)
				{
					NoKillSubstrings.Add(nameSubstring);
				}
			}
			EnsurePatched();
		}

		private static void EnsurePatched()
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Expected O, but got Unknown
			//IL_00a3: Expected O, but got Unknown
			if (_harmony != null)
			{
				return;
			}
			lock (Lock)
			{
				if (_harmony == null)
				{
					MethodInfo methodInfo = AccessTools.Method(typeof(Scene), "GetRootGameObjects", Type.EmptyTypes, (Type[])null);
					if (!(methodInfo == null))
					{
						string text = typeof(SceneRootSurvivor).Assembly.GetName().Name ?? "Unknown";
						Harmony val = new Harmony("SunhavenMods.SceneRootSurvivor." + text);
						val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(SceneRootSurvivor), "OnGetRootGameObjectsPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						_harmony = val;
					}
				}
			}
		}

		private static void OnGetRootGameObjectsPostfix(ref GameObject[] __result)
		{
			if (__result == null || __result.Length == 0)
			{
				return;
			}
			List<string> list;
			lock (Lock)
			{
				if (NoKillSubstrings.Count == 0)
				{
					return;
				}
				list = new List<string>(NoKillSubstrings);
			}
			List<GameObject> list2 = new List<GameObject>(__result);
			for (int i = 0; i < list.Count; i++)
			{
				string noKill = list[i];
				list2.RemoveAll((GameObject a) => (Object)(object)a != (Object)null && ((Object)a).name.IndexOf(noKill, StringComparison.OrdinalIgnoreCase) >= 0);
			}
			__result = list2.ToArray();
		}
	}
	public static class ReflectionHelper
	{
		public static readonly BindingFlags AllBindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;

		public static Type FindType(string typeName, params string[] namespaces)
		{
			string typeName2 = typeName;
			Type type = AccessTools.TypeByName(typeName2);
			if (type != null)
			{
				return type;
			}
			for (int i = 0; i < namespaces.Length; i++)
			{
				type = AccessTools.TypeByName(namespaces[i] + "." + typeName2);
				if (type != null)
				{
					return type;
				}
			}
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				try
				{
					type = assembly.GetTypes().FirstOrDefault((Type t) => t.Name == typeName2 || t.FullName == typeName2);
					if (type != null)
					{
						return type;
					}
				}
				catch (ReflectionTypeLoadException)
				{
				}
			}
			return null;
		}

		public static Type FindWishType(string typeName)
		{
			return FindType(typeName, "Wish");
		}

		public static object GetStaticValue(Type type, string memberName)
		{
			if (type == null)
			{
				return null;
			}
			try
			{
				PropertyInfo property = type.GetProperty(memberName, AllBindingFlags);
				if (property != null && property.GetMethod != null && property.GetIndexParameters().Length == 0)
				{
					return property.GetValue(null);
				}
			}
			catch (AmbiguousMatchException)
			{
				return null;
			}
			FieldInfo field = type.GetField(memberName, AllBindingFlags);
			if (field != null)
			{
				return field.GetValue(null);
			}
			return null;
		}

		public static object GetSingletonInstance(Type type)
		{
			if (type == null)
			{
				return null;
			}
			string[] array = new string[5] { "Instance", "instance", "_instance", "Singleton", "singleton" };
			foreach (string memberName in array)
			{
				object staticValue = GetStaticValue(type, memberName);
				if (staticValue != null)
				{
					return staticValue;
				}
			}
			return null;
		}

		public static object GetInstanceValue(object instance, string memberName)
		{
			if (instance == null)
			{
				return null;
			}
			Type type = instance.GetType();
			while (type != null)
			{
				PropertyInfo property = type.GetProperty(memberName, AllBindingFlags);
				if (property != null && property.GetMethod != null)
				{
					return property.GetValue(instance);
				}
				FieldInfo field = type.GetField(memberName, AllBindingFlags);
				if (field != null)
				{
					return field.GetValue(instance);
				}
				type = type.BaseType;
			}
			return null;
		}

		public static bool SetInstanceValue(object instance, string memberName, object value)
		{
			if (instance == null)
			{
				return false;
			}
			Type type = instance.GetType();
			while (type != null)
			{
				PropertyInfo property = type.GetProperty(memberName, AllBindingFlags);
				if (property != null && property.SetMethod != null)
				{
					property.SetValue(instance, value);
					return true;
				}
				FieldInfo field = type.GetField(memberName, AllBindingFlags);
				if (field != null)
				{
					field.SetValue(instance, value);
					return true;
				}
				type = type.BaseType;
			}
			return false;
		}

		public static object InvokeMethod(object instance, string methodName, params object[] args)
		{
			if (instance == null)
			{
				return null;
			}
			Type type = instance.GetType();
			Type[] array = args?.Select((object a) => a?.GetType() ?? typeof(object)).ToArray() ?? Type.EmptyTypes;
			MethodInfo methodInfo = AccessTools.Method(type, methodName, array, (Type[])null);
			if (methodInfo == null)
			{
				methodInfo = type.GetMethod(methodName, AllBindingFlags);
			}
			if (methodInfo == null)
			{
				return null;
			}
			return methodInfo.Invoke(instance, args);
		}

		public static object InvokeStaticMethod(Type type, string methodName, params object[] args)
		{
			if (type == null)
			{
				return null;
			}
			Type[] array = args?.Select((object a) => a?.GetType() ?? typeof(object)).ToArray() ?? Type.EmptyTypes;
			MethodInfo methodInfo = AccessTools.Method(type, methodName, array, (Type[])null);
			if (methodInfo == null)
			{
				methodInfo = type.GetMethod(methodName, AllBindingFlags);
			}
			if (methodInfo == null)
			{
				return null;
			}
			return methodInfo.Invoke(null, args);
		}

		public static FieldInfo[] GetAllFields(Type type)
		{
			if (type == null)
			{
				return Array.Empty<FieldInfo>();
			}
			FieldInfo[] fields = type.GetFields(AllBindingFlags);
			IEnumerable<FieldInfo> second;
			if (!(type.BaseType != null) || !(type.BaseType != typeof(object)))
			{
				second = Enumerable.Empty<FieldInfo>();
			}
			else
			{
				IEnumerable<FieldInfo> allFields = GetAllFields(type.BaseType);
				second = allFields;
			}
			return fields.Concat(second).Distinct().ToArray();
		}

		public static PropertyInfo[] GetAllProperties(Type type)
		{
			if (type == null)
			{
				return Array.Empty<PropertyInfo>();
			}
			PropertyInfo[] properties = type.GetProperties(AllBindingFlags);
			IEnumerable<PropertyInfo> second;
			if (!(type.BaseType != null) || !(type.BaseType != typeof(object)))
			{
				second = Enumerable.Empty<PropertyInfo>();
			}
			else
			{
				IEnumerable<PropertyInfo> allProperties = GetAllProperties(type.BaseType);
				second = allProperties;
			}
			return (from p in properties.Concat(second)
				group p by p.Name into g
				select g.First()).ToArray();
		}

		public static T TryGetValue<T>(object instance, string memberName, T defaultValue = default(T))
		{
			try
			{
				object instanceValue = GetInstanceValue(instance, memberName);
				if (instanceValue is T result)
				{
					return result;
				}
				if (instanceValue != null && typeof(T).IsAssignableFrom(instanceValue.GetType()))
				{
					return (T)instanceValue;
				}
				return defaultValue;
			}
			catch
			{
				return defaultValue;
			}
		}
	}
}
namespace CropOptimizer
{
	[BepInPlugin("com.azraelgodking.cropoptimizer", "Crop Optimizer", "1.4.3")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		private Harmony _harmony;

		private CropOptimizerConfig _config;

		internal CropForecast _forecast;

		private CropHUD _hud;

		private TodoIntegration _todoIntegration;

		private BirthdayIntegration _birthdayIntegration;

		private VaultIntegration _vaultIntegration;

		private bool _hudVisible = true;

		private bool _applicationQuitting;

		private bool _isVaultLoadedEventSubscribed;

		private EventInfo _vaultLoadedEventInfo;

		private Delegate _vaultLoadedHandler;

		public static ManualLogSource Log { get; private set; }

		public static Plugin Instance { get; private set; }

		public static bool IsDebugLoggingEnabled
		{
			get
			{
				Plugin instance = Instance;
				if (instance == null)
				{
					return false;
				}
				return (instance._config?.DebugLogging?.Value).GetValueOrDefault();
			}
		}

		private void Awake()
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			ConfigFile val = CreateNamedConfig();
			ConfigFileHelper.ReplacePluginConfig((BaseUnityPlugin)(object)this, val, (Action<string>)Log.LogWarning);
			_config = new CropOptimizerConfig(val);
			if (!_config.Enabled.Value)
			{
				Log.LogInfo((object)"Crop Optimizer disabled in config.");
				return;
			}
			_forecast = new CropForecast();
			_todoIntegration = new TodoIntegration();
			_birthdayIntegration = new BirthdayIntegration();
			_vaultIntegration = new VaultIntegration();
			_harmony = new Harmony("com.azraelgodking.cropoptimizer");
			CropGrowthPatch.Apply(_harmony, _forecast);
			CharacterLoadPatch.Apply(_harmony, _forecast);
			_hud = PersistentRunnerBase.CreateRunner<CropHUD>();
			_hud.Initialize(_forecast);
			_hud.SetPlacement(_config.HudPositionX.Value, _config.HudPositionY.Value);
			_hud.SetScale(_config.HudScale.Value);
			_hud.SetVisible(_config.HudEnabled.Value);
			_hudVisible = _config.HudEnabled.Value;
			_hud.PlacementChanged += OnCropHudPlacementChanged;
			_hud.SetHoverConfig(_config.HoverTooltipEnabled, _config.HoverTooltipMaxWorldDistance);
			TrySubscribeVaultLoaded();
			if (_config.CheckForUpdates.Value)
			{
				VersionChecker.CheckForUpdate("com.azraelgodking.cropoptimizer", "1.4.3", Log, delegate(VersionChecker.VersionCheckResult result)
				{
					result.NotifyUpdateAvailable(Log);
				});
			}
			Log.LogInfo((object)"Crop Optimizer v1.4.3 loaded");
		}

		private void OnDestroy()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			string text = ((Scene)(ref activeScene)).name ?? string.Empty;
			string text2 = text.ToLowerInvariant();
			if (_applicationQuitting || !Application.isPlaying || text2.Contains("menu") || text2.Contains("title"))
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogInfo((object)("[Lifecycle] Plugin OnDestroy during expected teardown (scene: " + text + ")"));
				}
			}
			else
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("[Lifecycle] Plugin OnDestroy outside expected teardown (scene: " + text + ")"));
				}
			}
			if ((Object)(object)_hud != (Object)null)
			{
				_hud.PlacementChanged -= OnCropHudPlacementChanged;
			}
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			if (_isVaultLoadedEventSubscribed && _vaultLoadedEventInfo != null && (object)_vaultLoadedHandler != null)
			{
				_vaultLoadedEventInfo.RemoveEventHandler(null, _vaultLoadedHandler);
				_isVaultLoadedEventSubscribed = false;
				_vaultLoadedEventInfo = null;
				_vaultLoadedHandler = null;
			}
		}

		private void OnApplicationQuit()
		{
			_applicationQuitting = true;
		}

		private void OnCropHudPlacementChanged(float x, float y)
		{
			if (_config != null)
			{
				_config.HudPositionX.Value = x;
				_config.HudPositionY.Value = y;
			}
		}

		private void Update()
		{
			//IL_0022: 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)
			if (_config != null && !((Object)(object)_hud == (Object)null) && (int)_config.ToggleHudKey.Value != 0 && Input.GetKeyDown(_config.ToggleHudKey.Value))
			{
				_hudVisible = !_hudVisible;
				_hud.SetVisible(_hudVisible);
			}
		}

		public static string GetHudSummary()
		{
			if (Instance?._forecast == null)
			{
				return "Not ready";
			}
			return $"Crops: {Instance._forecast.Snapshot().Count}, Value: {Instance._forecast.GetProjectedSellTotal()}g";
		}

		internal static List<CropForecast.CropTypeSummary> GetTopCrops(int count = 5)
		{
			return Instance?._forecast?.GetTopCropsByValue(count) ?? new List<CropForecast.CropTypeSummary>();
		}

		private void TrySubscribeVaultLoaded()
		{
			if (_vaultIntegration == null || !_vaultIntegration.IsAvailable)
			{
				return;
			}
			try
			{
				EventInfo @event = typeof(VaultModApiBridge).GetEvent("OnVaultLoaded", BindingFlags.Static | BindingFlags.Public);
				if (@event == null)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogDebug((object)"[CropOptimizer] Vault bridge OnVaultLoaded event not found; skipping subscription.");
					}
					return;
				}
				MethodInfo method = ((object)this).GetType().GetMethod("OnVaultLoaded", BindingFlags.Instance | BindingFlags.NonPublic);
				if (method == null)
				{
					return;
				}
				Delegate @delegate = Delegate.CreateDelegate(@event.EventHandlerType, this, method, throwOnBindFailure: false);
				if ((object)@delegate == null)
				{
					ManualLogSource log2 = Log;
					if (log2 != null)
					{
						log2.LogWarning((object)"[CropOptimizer] Vault OnVaultLoaded handler could not be bound.");
					}
					return;
				}
				@event.AddEventHandler(null, @delegate);
				_isVaultLoadedEventSubscribed = true;
				_vaultLoadedEventInfo = @event;
				_vaultLoadedHandler = @delegate;
				if (VaultModApiBridge.Instance != null && VaultModApiBridge.Instance.IsVaultReady)
				{
					_vaultIntegration.TryRegisterProjectedValueCurrency();
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log3 = Log;
				if (log3 != null)
				{
					log3.LogWarning((object)("[CropOptimizer] Failed to subscribe to Vault OnVaultLoaded: " + ex.Message));
				}
			}
		}

		private void OnVaultLoaded()
		{
			try
			{
				_vaultIntegration?.TryRegisterProjectedValueCurrency();
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)("[CropOptimizer] Vault currency registration failed on OnVaultLoaded: " + ex.Message));
				}
			}
		}

		private static ConfigFile CreateNamedConfig()
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			string text = Path.Combine(Paths.ConfigPath, "CropOptimizer.cfg");
			string text2 = Path.Combine(Paths.ConfigPath, "com.azraelgodking.cropoptimizer.cfg");
			try
			{
				if (!File.Exists(text) && File.Exists(text2))
				{
					File.Copy(text2, text);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)("[Config] Migration to CropOptimizer.cfg failed: " + ex.Message));
				}
			}
			return new ConfigFile(text, true);
		}
	}
	internal static class PluginInfo
	{
		public const string PLUGIN_GUID = "com.azraelgodking.cropoptimizer";

		public const string PLUGIN_NAME = "Crop Optimizer";

		public const string PLUGIN_VERSION = "1.4.3";
	}
}
namespace CropOptimizer.UI
{
	internal static class CropHoverQuery
	{
		private static Type _cropType;

		private static Object[] _cachedCrops;

		private static float _nextCacheTime;

		private static Camera _cachedGameplayCamera;

		private static float _nextGameplayCameraSearchTime;

		private static Vector3 _lastHoverMouseScreen;

		private static Component _lastHoverCrop;

		private static float _nextHoverFullScanTime;

		private const float CropCacheRefreshSeconds = 1.5f;

		private const float HoverRescanMinInterval = 0.055f;

		private const float MouseMoveSkipScanPxSq = 9f;

		private const float GameplayCameraSearchCooldown = 2f;

		private static readonly string[] WaterMemberNames = new string[10] { "isWatered", "IsWatered", "watered", "Watered", "needsWater", "NeedsWater", "water", "Water", "hasWater", "HasWater" };

		private static readonly string[] FertilizerMemberNames = new string[10] { "fertilizer", "Fertilizer", "fertilized", "Fertilized", "hasFertilizer", "HasFertilizer", "fertilizerType", "FertilizerType", "soilFertility", "SoilFertility" };

		private static bool _dumpedCropMembers;

		private static bool _loggedTileProbe;

		private const BindingFlags MemberFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;

		private static Type CropType => _cropType ?? (_cropType = AccessTools.TypeByName("Wish.Crop"));

		public static Camera ResolveGameplayCamera()
		{
			if ((Object)(object)Camera.main != (Object)null && ((Behaviour)Camera.main).enabled)
			{
				_cachedGameplayCamera = Camera.main;
				return Camera.main;
			}
			if ((Object)(object)_cachedGameplayCamera != (Object)null && ((Behaviour)_cachedGameplayCamera).enabled && ((Component)_cachedGameplayCamera).gameObject.activeInHierarchy)
			{
				return _cachedGameplayCamera;
			}
			float unscaledTime = Time.unscaledTime;
			if (unscaledTime < _nextGameplayCameraSearchTime)
			{
				return _cachedGameplayCamera;
			}
			Camera[] array = Object.FindObjectsOfType<Camera>();
			Camera val = null;
			Camera[] array2 = array;
			foreach (Camera val2 in array2)
			{
				if (!((Object)(object)val2 == (Object)null) && ((Behaviour)val2).enabled && ((Component)val2).gameObject.activeInHierarchy && ((Object)(object)val == (Object)null || val2.depth > val.depth))
				{
					val = val2;
				}
			}
			_cachedGameplayCamera = val;
			_nextGameplayCameraSearchTime = unscaledTime + (((Object)(object)val != (Object)null) ? 2f : 0.25f);
			return val;
		}

		public static void InvalidateGameplayCameraCache()
		{
			_cachedGameplayCamera = null;
			_nextGameplayCameraSearchTime = 0f;
		}

		public static void InvalidateHoverAssist()
		{
			_lastHoverCrop = null;
			_nextHoverFullScanTime = 0f;
		}

		public static bool TryMouseWorldOnPlane(Camera camera, float planeZ, out Vector3 world)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: 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_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: 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_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)
			world = default(Vector3);
			if ((Object)(object)camera == (Object)null)
			{
				return false;
			}
			Ray val = camera.ScreenPointToRay(Input.mousePosition);
			Plane val2 = default(Plane);
			((Plane)(ref val2))..ctor(Vector3.forward, new Vector3(0f, 0f, planeZ));
			float num = default(float);
			if (((Plane)(ref val2)).Raycast(val, ref num))
			{
				world = ((Ray)(ref val)).GetPoint(num);
				return true;
			}
			Vector3 mousePosition = Input.mousePosition;
			mousePosition.z = Mathf.Max(0.01f, Mathf.Abs(((Component)camera).transform.position.z));
			world = camera.ScreenToWorldPoint(mousePosition);
			world.z = planeZ;
			return true;
		}

		public static bool TryGetClosestCropNearMouse(Camera camera, float maxWorldDistance, out Component crop)
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//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_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: 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_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: 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)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			crop = null;
			if (CropType == null || (Object)(object)camera == (Object)null)
			{
				return false;
			}
			RefreshCropCache();
			if (_cachedCrops == null || _cachedCrops.Length == 0)
			{
				return false;
			}
			float planeZ = 0f;
			Object[] cachedCrops = _cachedCrops;
			foreach (Object obj in cachedCrops)
			{
				Component val = (Component)(object)((obj is Component) ? obj : null);
				if (val != null && (Object)(object)val != (Object)null)
				{
					planeZ = val.transform.position.z;
					break;
				}
			}
			if (!TryMouseWorldOnPlane(camera, planeZ, out var world))
			{
				return false;
			}
			Vector3 mousePosition = Input.mousePosition;
			float unscaledTime = Time.unscaledTime;
			float num = maxWorldDistance * maxWorldDistance;
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(world.x, world.y);
			Vector3 val3 = mousePosition - _lastHoverMouseScreen;
			bool num2 = ((Vector3)(ref val3)).sqrMagnitude <= 9f;
			_lastHoverMouseScreen = mousePosition;
			Vector2 val4;
			if (num2 && unscaledTime < _nextHoverFullScanTime && (Object)(object)_lastHoverCrop != (Object)null)
			{
				Component lastHoverCrop = _lastHoverCrop;
				if ((Object)(object)lastHoverCrop != (Object)null)
				{
					val4 = new Vector2(lastHoverCrop.transform.position.x, lastHoverCrop.transform.position.y) - val2;
					if (((Vector2)(ref val4)).sqrMagnitude < num)
					{
						crop = lastHoverCrop;
						return true;
					}
				}
			}
			_nextHoverFullScanTime = unscaledTime + 0.055f;
			float num3 = num;
			Component val5 = null;
			cachedCrops = _cachedCrops;
			foreach (Object obj2 in cachedCrops)
			{
				Component val6 = (Component)(object)((obj2 is Component) ? obj2 : null);
				if (val6 != null && !((Object)(object)val6 == (Object)null) && CropInstanceRegistry.IsKnownActive(((Object)val6).GetInstanceID()))
				{
					val4 = new Vector2(val6.transform.position.x, val6.transform.position.y) - val2;
					float sqrMagnitude = ((Vector2)(ref val4)).sqrMagnitude;
					if (sqrMagnitude < num3)
					{
						num3 = sqrMagnitude;
						val5 = val6;
					}
				}
			}
			if ((Object)(object)val5 == (Object)null)
			{
				_lastHoverCrop = null;
				return false;
			}
			crop = val5;
			_lastHoverCrop = val5;
			return true;
		}

		private static void RefreshCropCache()
		{
			float unscaledTime = Time.unscaledTime;
			if (_cachedCrops != null && unscaledTime < _nextCacheTime)
			{
				return;
			}
			_nextCacheTime = unscaledTime + 1.5f;
			Type cropType = CropType;
			if (cropType == null)
			{
				_cachedCrops = Array.Empty<Object>();
				return;
			}
			Object[] array = Object.FindObjectsOfType(cropType);
			for (int i = 0; i < array.Length; i++)
			{
				CropInstanceRegistry.Register(array[i]);
			}
			_cachedCrops = array;
		}

		public static string FormatWaterGuess(object cropInstance)
		{
			return FormatMemberGuess(cropInstance, WaterMemberNames);
		}

		public static string FormatFertilizerGuess(object cropInstance)
		{
			return FormatMemberGuess(cropInstance, FertilizerMemberNames);
		}

		private static void LogTileDebugOnce(Component crop, Vector2Int tile)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (_loggedTileProbe)
			{
				return;
			}
			_loggedTileProbe = true;
			try
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)CropTileReflection.BuildDebugSnapshot(crop, tile));
				}
			}
			catch
			{
			}
		}

		private static void DumpCropMembersOnce(object cropInstance)
		{
			if (_dumpedCropMembers || cropInstance == null)
			{
				return;
			}
			_dumpedCropMembers = true;
			try
			{
				Plugin instance = Plugin.Instance;
				if (instance != null)
				{
					_ = ((BaseUnityPlugin)instance).Config;
				}
				if (!((Object)(object)Plugin.Instance != (Object)null) || !IsDebugLogEnabled())
				{
					return;
				}
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					Type type = cropInstance.GetType();
					log.LogInfo((object)("[HoverDebug] Dumping members of " + type.FullName));
					FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
					foreach (FieldInfo fieldInfo in fields)
					{
						log.LogInfo((object)("[HoverDebug]   field  " + fieldInfo.FieldType.Name + " " + fieldInfo.Name));
					}
					PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
					foreach (PropertyInfo propertyInfo in properties)
					{
						log.LogInfo((object)("[HoverDebug]   prop   " + propertyInfo.PropertyType.Name + " " + propertyInfo.Name));
					}
				}
			}
			catch
			{
			}
		}

		private static bool IsDebugLogEnabled()
		{
			try
			{
				return (Object)(object)Plugin.Instance != (Object)null && Plugin.IsDebugLoggingEnabled;
			}
			catch
			{
				return false;
			}
		}

		private static string FormatMemberGuess(object instance, string[] names)
		{
			if (instance == null)
			{
				return "?";
			}
			try
			{
				Type type = instance.GetType();
				while (type != null)
				{
					foreach (string name in names)
					{
						FieldInfo fieldInfo = null;
						PropertyInfo propertyInfo = null;
						try
						{
							fieldInfo = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
						}
						catch
						{
						}
						try
						{
							propertyInfo = ((fieldInfo == null) ? type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy) : null);
						}
						catch
						{
						}
						if (!(fieldInfo == null) || !(propertyInfo == null))
						{
							object obj3 = ((fieldInfo != null) ? fieldInfo.GetValue(instance) : propertyInfo.GetValue(instance, null));
							if (obj3 != null)
							{
								return FormatPrimitiveGuess(obj3);
							}
						}
					}
					type = type.BaseType;
				}
			}
			catch
			{
			}
			return "?";
		}

		private static string FormatPrimitiveGuess(object raw)
		{
			if (raw is bool)
			{
				if (!(bool)raw)
				{
					return "no";
				}
				return "yes";
			}
			if (raw is int num)
			{
				if (num == 0)
				{
					return "no";
				}
				return $"yes ({num})";
			}
			if (raw is float num2)
			{
				if (!(Math.Abs(num2) > 0.0001f))
				{
					return "no";
				}
				return $"yes ({num2:0.##})";
			}
			if (raw is double num3)
			{
				if (!(Math.Abs(num3) > 0.0001))
				{
					return "no";
				}
				return $"yes ({num3:0.##})";
			}
			string text = raw.ToString();
			if (string.IsNullOrWhiteSpace(text))
			{
				return "?";
			}
			if (text.Length > 48)
			{
				return text.Substring(0, 45) + "...";
			}
			return text;
		}

		public static TooltipContent BuildTooltipContent(Component crop, CropForecast forecast)
		{
			//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_00a4: 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_00c9: 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_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: 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_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: 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_0286: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0347: Unknown result type (might be due to invalid IL or missing references)
			//IL_0353: Unknown result type (might be due to invalid IL or missing references)
			//IL_0359: Unknown result type (might be due to invalid IL or missing references)
			//IL_036e: Unknown result type (might be due to invalid IL or missing references)
			//IL_039c: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0318: Unknown result type (might be due to invalid IL or missing references)
			//IL_0311: Unknown result type (might be due to invalid IL or missing references)
			//IL_0321: Unknown result type (might be due to invalid IL or missing references)
			//IL_0327: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)crop == (Object)null)
			{
				return null;
			}
			DumpCropMembersOnce(crop);
			TooltipContent tooltipContent = new TooltipContent();
			int itemId = 0;
			string title = "Crop";
			if (CropGrowthPatch.TryGetTooltipHarvestItemId(crop, out itemId) && itemId > 0)
			{
				title = ((!CropGrowthPatch.TryGetItemDisplayName(itemId, out string displayName) || string.IsNullOrWhiteSpace(displayName)) ? $"Item #{itemId}" : displayName);
			}
			tooltipContent.Title = title;
			bool fullyGrown = false;
			CropGrowthPatch.TryGetTooltipFullyGrown(crop, out fullyGrown);
			if (fullyGrown)
			{
				tooltipContent.HeaderTag = "ready to harvest";
			}
			if (CropGrowthPatch.TryGetTooltipQualityInfo(crop, out string label, out float multiplier) && !string.IsNullOrEmpty(label))
			{
				tooltipContent.QualityColor = QualityColorFor(label);
				tooltipContent.Rows.Add(RowSpec.Make(UiStyle.IconKind.Quality, tooltipContent.QualityColor, string.Format("Quality: <b>{0}</b> <color={1}>(×{2:0.##})</color>", label, "#B8A078", multiplier)));
			}
			if (CropGrowthPatch.TryGetTooltipGrowthStageInfo(crop, out string stageText, out float grownRatio) && !string.IsNullOrEmpty(stageText))
			{
				tooltipContent.Rows.Add(RowSpec.Make(UiStyle.IconKind.Sprout, UiStyle.Sprout, "Growth: <b>" + stageText + "</b>"));
			}
			float etaHours;
			bool resolvedFromReflection;
			CropForecast.CropState state;
			if (fullyGrown)
			{
				tooltipContent.Rows.Add(RowSpec.Make(UiStyle.IconKind.Ready, UiStyle.Fertilizer, "<b><color=#F7D982>Ready now</color></b>"));
			}
			else if (CropGrowthPatch.TryGetTooltipEtaHours(crop, out etaHours, out resolvedFromReflection) && resolvedFromReflection)
			{
				tooltipContent.Rows.Add(RowSpec.Make(UiStyle.IconKind.Clock, UiStyle.Clock, string.Format("Ready in <b><color={0}>~{1:0.#} h</color></b>", "#F7D982", Mathf.Max(0f, etaHours))));
			}
			else if (forecast != null && forecast.TryGetState(((Object)crop).GetInstanceID(), out state))
			{
				tooltipContent.Rows.Add(RowSpec.Make(UiStyle.IconKind.Clock, UiStyle.Clock, string.Format("Ready in <b><color={0}>~{1:0.#} h</color></b> <color={2}>(cached)</color>", "#F7D982", Mathf.Max(0f, state.NextHarvestEtaHours), "#B8A078")));
			}
			else
			{
				tooltipContent.Rows.Add(RowSpec.Make(UiStyle.IconKind.Clock, UiStyle.Clock, "<color=#B8A078>ETA unknown — grow once to calibrate</color>"));
			}
			if (CropGrowthPatch.TryGetTooltipProjectedGold(crop, out var projectedGold, out grownRatio) && projectedGold > 0)
			{
				tooltipContent.Rows.Add(RowSpec.Make(UiStyle.IconKind.Coin, UiStyle.Coin, string.Format("<b><color={0}>~{1:N0}g</color></b> at shop", "#F7D982", projectedGold)));
			}
			Vector2Int tile = default(Vector2Int);
			bool num = CropTileReflection.TryGetTileCoordForCrop(crop, out tile);
			string raw = null;
			if (num)
			{
				raw = CropTileReflection.DescribeFarmingTileState(tile, crop.transform.position, haveWorldPos: true, out var _);
				if (IsDebugLogEnabled())
				{
					LogTileDebugOnce(crop, tile);
				}
			}
			var (text, iconColor) = DescribeWaterState(raw);
			tooltipContent.Rows.Add(RowSpec.Make(UiStyle.IconKind.Water, iconColor, text));
			if (CropGrowthPatch.TryGetTooltipFertilized(crop, out var fertilized))
			{
				string obj = (fertilized ? "<b>Fertilized</b>" : "Not fertilized");
				tooltipContent.Rows.Add(RowSpec.Make(text: obj, icon: UiStyle.IconKind.Fertilizer, iconColor: (Color32)(fertilized ? UiStyle.Fertilizer : new Color32((byte)154, (byte)136, (byte)96, byte.MaxValue))));
			}
			if (CropGrowthPatch.TryGetTooltipManaInfused(crop, out var manaInfused) && manaInfused)
			{
				tooltipContent.Rows.Add(RowSpec.Make(UiStyle.IconKind.Mana, UiStyle.Mana, "<b>Mana infused</b>"));
			}
			if (num)
			{
				tooltipContent.Rows.Add(RowSpec.Make(UiStyle.IconKind.Tile, UiStyle.Tile, string.Format("<color={0}>Tile ({1}, {2})</color>", "#B8A078", ((Vector2Int)(ref tile)).x, ((Vector2Int)(ref tile)).y)));
			}
			if (itemId > 0)
			{
				List<string> list = new List<string>();
				CropGrowthPatch.AppendItemExtraLines(itemId, list);
				if (list.Count > 0)
				{
					tooltipContent.Extras = string.Join(" · ", list);
				}
			}
			return tooltipContent;
		}

		private static Color32 QualityColorFor(string label)
		{
			//IL_0008: 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_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(label))
			{
				return UiStyle.QualityNormal;
			}
			string text = label.ToLowerInvariant();
			if (text.Contains("gold") || text.Contains("iridium"))
			{
				return UiStyle.QualityGold;
			}
			if (text.Contains("silver"))
			{
				return UiStyle.QualitySilver;
			}
			return UiStyle.QualityNormal;
		}

		private static (string text, Color32 color) DescribeWaterState(string raw)
		{
			//IL_000d: 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_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(raw))
			{
				return ("Water: <color=#B8A078>unknown</color>", UiStyle.Water);
			}
			string text = raw.ToLowerInvariant();
			if (text.Contains("water"))
			{
				return ("<b><color=#8AD4FF>Watered</color></b>", UiStyle.Water);
			}
			if (text.Contains("hoed"))
			{
				return ("Hoed <color=#B8A078>(dry — needs water)</color>", new Color32((byte)201, (byte)160, (byte)112, byte.MaxValue));
			}
			return ("Water: " + raw, UiStyle.Water);
		}
	}
	internal sealed class CropHUD : PersistentRunnerBase
	{
		private CropForecast _forecast;

		private Canvas _canvas;

		private GameObject _canvasGo;

		private CropHudView _hudView;

		private CropTooltipView _tooltipView;

		private float _scale = 1f;

		private bool _isVisible = true;

		private float _initialX = 24f;

		private float _initialY = 80f;

		private bool _hasInitialPlacement;

		private ConfigEntry<bool> _hoverTooltipEnabled;

		private ConfigEntry<float> _hoverTooltipMaxWorldDistance;

		private Component _tooltipContentCrop;

		private TooltipContent _tooltipContentCache;

		private float _nextTooltipContentRebuildTime;

		private int _lastHudTrackedCount = -1;

		private long _lastHudProjectedGold = long.MinValue;

		private bool? _lastHudTooltipShownInUi;

		private const float TooltipContentRefreshSeconds = 0.22f;

		protected override string RunnerName => "CropHUD";

		public event Action<float, float> PlacementChanged;

		public void Initialize(CropForecast forecast)
		{
			_forecast = forecast;
		}

		public void SetHoverConfig(ConfigEntry<bool> enabled, ConfigEntry<float> maxWorldDistance)
		{
			_hoverTooltipEnabled = enabled;
			_hoverTooltipMaxWorldDistance = maxWorldDistance;
		}

		public void SetPlacement(float x, float y)
		{
			_initialX = x;
			_initialY = y;
			_hasInitialPlacement = true;
			_hudView?.SetPlacement(x, y);
		}

		public void SetScale(float scale)
		{
			_scale = Mathf.Clamp(scale, 0.5f, 2.5f);
			_hudView?.SetScale(_scale);
			_tooltipView?.SetScale(_scale);
		}

		public void SetVisible(bool visible)
		{
			_isVisible = visible;
			_hudView?.SetVisible(visible && IsCharacterSessionActive());
		}

		private static bool IsCharacterSessionActive()
		{
			if (!SceneHelpers.IsInGame())
			{
				return false;
			}
			try
			{
				GameSave instance = SingletonBehaviour<GameSave>.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					return false;
				}
				GameSaveData currentSave = instance.CurrentSave;
				if (currentSave == null)
				{
					return false;
				}
				return currentSave.characterData != null;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogDebug((object)("[CropHUD] Failed to determine character session state: " + ex.Message));
				}
				return false;
			}
		}

		private void EnsureCanvas()
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_canvas != (Object)null) || !((Object)(object)_canvasGo != (Object)null))
			{
				_canvasGo = new GameObject("CropOptimizer_HUDCanvas", new Type[3]
				{
					typeof(Canvas),
					typeof(CanvasScaler),
					typeof(GraphicRaycaster)
				});
				Object.DontDestroyOnLoad((Object)(object)_canvasGo);
				_canvas = _canvasGo.GetComponent<Canvas>();
				_canvas.renderMode = (RenderMode)0;
				_canvas.sortingOrder = 5000;
				CanvasScaler component = _canvasGo.GetComponent<CanvasScaler>();
				component.uiScaleMode = (ScaleMode)1;
				component.referenceResolution = new Vector2(1920f, 1080f);
				component.matchWidthOrHeight = 0.5f;
				_hudView = new CropHudView(_canvasGo.transform);
				_hudView.PlacementChanged += delegate(float x, float y)
				{
					this.PlacementChanged?.Invoke(x, y);
				};
				_hudView.TooltipToggleClicked += OnTooltipToggleClicked;
				_hudView.SetScale(_scale);
				if (_hasInitialPlacement)
				{
					_hudView.SetPlacement(_initialX, _initialY);
				}
				_hudView.SetVisible(_isVisible);
				_hudView.SetTooltipEnabled(_hoverTooltipEnabled != null && _hoverTooltipEnabled.Value);
				_tooltipView = new CropTooltipView(_canvasGo.transform);
				_tooltipView.SetScale(_scale);
				_tooltipView.SetVisible(visible: false);
			}
		}

		private void RebuildCanvas()
		{
			if ((Object)(object)_canvasGo != (Object)null)
			{
				Object.Destroy((Object)(object)_canvasGo);
				_canvasGo = null;
				_canvas = null;
				_hudView = null;
				_tooltipView = null;
			}
			EnsureCanvas();
		}

		protected override void OnUpdate()
		{
			if (_forecast == null)
			{
				return;
			}
			EnsureCanvas();
			bool flag = IsCharacterSessionActive();
			if (_hudView != null)
			{
				bool flag2 = _isVisible && flag;
				_hudView.SetVisible(flag2);
				if (flag2)
				{
					int count = _forecast.Snapshot().Count;
					long num = _forecast.GetProjectedSellTotal();
					if (count != _lastHudTrackedCount || num != _lastHudProjectedGold)
					{
						_lastHudTrackedCount = count;
						_lastHudProjectedGold = num;
						_hudView.UpdateStats(count, num);
					}
					bool flag3 = _hoverTooltipEnabled != null && _hoverTooltipEnabled.Value;
					if (!_lastHudTooltipShownInUi.HasValue || flag3 != _lastHudTooltipShownInUi.Value)
					{
						_lastHudTooltipShownInUi = flag3;
						_hudView.SetTooltipEnabled(flag3);
					}
				}
				else
				{
					_lastHudTrackedCount = -1;
					_lastHudProjectedGold = long.MinValue;
					_lastHudTooltipShownInUi = null;
				}
			}
			UpdateHoverTooltip(flag);
		}

		private void OnTooltipToggleClicked()
		{
			if (_hoverTooltipEnabled == null)
			{
				return;
			}
			_hoverTooltipEnabled.Value = !_hoverTooltipEnabled.Value;
			_lastHudTooltipShownInUi = _hoverTooltipEnabled.Value;
			_hudView?.SetTooltipEnabled(_hoverTooltipEnabled.Value);
			try
			{
				ConfigFile configFile = ((ConfigEntryBase)_hoverTooltipEnabled).ConfigFile;
				if (configFile != null)
				{
					configFile.Save();
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogDebug((object)("[CropHUD] Failed to flush hover-tooltip config change: " + ex.Message));
				}
			}
		}

		private void UpdateHoverTooltip(bool sessionLive)
		{
			//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_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			if (_tooltipView == null)
			{
				return;
			}
			if (!sessionLive || _hoverTooltipEnabled == null || !_hoverTooltipEnabled.Value)
			{
				ClearTooltipContentState();
				_tooltipView.SetVisible(visible: false);
				return;
			}
			if (_hudView != null && _hudView.IsVisible && RectTransformUtility.RectangleContainsScreenPoint(_hudView.Rect, Vector2.op_Implicit(Input.mousePosition)))
			{
				ClearTooltipContentState();
				_tooltipView.SetVisible(visible: false);
				return;
			}
			Camera val = CropHoverQuery.ResolveGameplayCamera();
			if ((Object)(object)val == (Object)null)
			{
				ClearTooltipContentState();
				_tooltipView.SetVisible(visible: false);
				return;
			}
			float maxWorldDistance = ((_hoverTooltipMaxWorldDistance != null) ? _hoverTooltipMaxWorldDistance.Value : 5f);
			if (!CropHoverQuery.TryGetClosestCropNearMouse(val, maxWorldDistance, out Component crop))
			{
				ClearTooltipContentState();
				_tooltipView.SetVisible(visible: false);
				return;
			}
			float unscaledTime = Time.unscaledTime;
			bool flag = (Object)(object)crop != (Object)(object)_tooltipContentCrop || _tooltipContentCache == null || unscaledTime >= _nextTooltipContentRebuildTime;
			if (flag)
			{
				_tooltipContentCache = CropHoverQuery.BuildTooltipContent(crop, _forecast);
				_tooltipContentCrop = crop;
				_nextTooltipContentRebuildTime = unscaledTime + 0.22f;
			}
			if (_tooltipContentCache == null)
			{
				ClearTooltipContentState();
				_tooltipView.SetVisible(visible: false);
				return;
			}
			_tooltipView.SetVisible(visible: true);
			if (flag)
			{
				_tooltipView.ApplyContent(_tooltipContentCache);
			}
			_tooltipView.SetScreenPosition(Vector2.op_Implicit(Input.mousePosition));
		}

		private void ClearTooltipContentState()
		{
			_tooltipContentCrop = null;
			_tooltipContentCache = null;
			_nextTooltipContentRebuildTime = 0f;
		}

		protected override void OnGameTransition()
		{
			CropHoverQuery.InvalidateGameplayCameraCache();
			CropHoverQuery.InvalidateHoverAssist();
			ClearTooltipContentState();
			RebuildCanvas();
		}

		protected override void OnMenuTransition()
		{
			CropHoverQuery.InvalidateGameplayCameraCache();
			CropHoverQuery.InvalidateHoverAssist();
			ClearTooltipContentState();
			_hudView?.SetVisible(visible: false);
			_tooltipView?.SetVisible(visible: false);
		}

		protected override void OnDestroy()
		{
			base.OnDestroy();
			if ((Object)(object)_canvasGo != (Object)null)
			{
				Object.Destroy((Object)(object)_canvasGo);
				_canvasGo = null;
				_canvas = null;
				_hudView = null;
				_tooltipView = null;
			}
		}

		protected override void Log(string message)
		{
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogDebug((object)message);
			}
		}

		protected override void LogWarning(string message)
		{
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogWarning((object)message);
			}
		}
	}
	internal sealed class CropHudView
	{
		internal sealed class TooltipToggleButton : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler, IPointerDownHandler, IPointerUpHandler, IPointerClickHandler
		{
			public Image Background;

			public Color32 NormalColor;

			public Color32 HoverColor;

			public Color32 PressedColor;

			private GameObject _hoverLabelRoot;

			private TMP_Text _hoverLabelText;

			private string _pendingLabel = "Toggle Crop Tooltips";

			private bool _hovered;

			private bool _pressed;

			public event Action Clicked;

			public void SetTooltipLabel(string label)
			{
				_pendingLabel = label ?? string.Empty;
				if ((Object)(object)_hoverLabelText != (Object)null)
				{
					_hoverLabelText.text = _pendingLabel;
					ResizeLabelToContent();
				}
			}

			public void OnPointerEnter(PointerEventData e)
			{
				_hovered = true;
				EnsureHoverLabel();
				SetLabelVisible(visible: true);
				Refresh();
			}

			public void OnPointerExit(PointerEventData e)
			{
				_hovered = false;
				_pressed = false;
				SetLabelVisible(visible: false);
				Refresh();
			}

			public void OnPointerDown(PointerEventData e)
			{
				_pressed = true;
				Refresh();
			}

			public void OnPointerUp(PointerEventData e)
			{
				_pressed = false;
				Refresh();
			}

			public void OnPointerClick(PointerEventData e)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				if ((int)e.button == 0)
				{
					this.Clicked?.Invoke();
				}
			}

			private void Refresh()
			{
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: 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)
				if (!((Object)(object)Background == (Object)null))
				{
					((Graphic)Background).color = Color32.op_Implicit(_pressed ? PressedColor : (_hovered ? HoverColor : NormalColor));
				}
			}

			private void EnsureHoverLabel()
			{
				//IL_0035: Unknown result type (might be due to invalid IL or missing references)
				//IL_003f: Expected O, but got Unknown
				//IL_0061: Unknown result type (might be due to invalid IL or missing references)
				//IL_0066: Unknown result type (might be due to invalid IL or missing references)
				//IL_0071: 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_0086: 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_009b: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
				//IL_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_013b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0141: Unknown result type (might be due to invalid IL or missing references)
				//IL_0146: Unknown result type (might be due to invalid IL or missing references)
				//IL_0147: Unknown result type (might be due to invalid IL or missing references)
				//IL_0151: Unknown result type (might be due to invalid IL or missing references)
				//IL_0152: Unknown result type (might be due to invalid IL or missing references)
				//IL_015c: 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_017b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0196: Unknown result type (might be due to invalid IL or missing references)
				//IL_019b: 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_01c9: Expected O, but got Unknown
				//IL_0212: Unknown result type (might be due to invalid IL or missing references)
				//IL_0217: Unknown result type (might be due to invalid IL or missing references)
				//IL_028b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0296: Unknown result type (might be due to invalid IL or missing references)
				//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
				//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)_hoverLabelRoot != (Object)null))
				{
					_hoverLabelRoot = new GameObject("HoverLabel", new Type[2]
					{
						typeof(RectTransform),
						typeof(Image)
					});
					_hoverLabelRoot.transform.SetParent(((Component)this).transform, false);
					RectTransform val = (RectTransform)_hoverLabelRoot.transform;
					val.anchorMin = new Vector2(0.5f, 0f);
					val.anchorMax = new Vector2(0.5f, 0f);
					val.pivot = new Vector2(0.5f, 1f);
					val.anchoredPosition = new Vector2(0f, -6f);
					val.sizeDelta = new Vector2(140f, 22f);
					Image component = _hoverLabelRoot.GetComponent<Image>();
					component.sprite = UiStyle.SolidSprite;
					((Graphic)component).color = Color32.op_Implicit(UiStyle.WoodBorder);
					((Graphic)component).raycastTarget = false;
					GameObject val2 = new GameObject("Fill", new Type[2]
					{
						typeof(RectTransform),
						typeof(Image)
					});
					val2.transform.SetParent(_hoverLabelRoot.transform, false);
					RectTransform val3 = (RectTransform)val2.transform;
					val3.anchorMin = Vector2.zero;
					val3.anchorMax = Vector2.one;
					val3.offsetMin = new Vector2(2f, 2f);
					val3.offsetMax = new Vector2(-2f, -2f);
					Image component2 = val2.GetComponent<Image>();
					component2.sprite = UiStyle.SolidSprite;
					((Graphic)component2).color = Color32.op_Implicit(UiStyle.PanelFill);
					((Graphic)component2).raycastTarget = false;
					GameObject val4 = new GameObject("Text", new Type[1] { typeof(RectTransform) });
					val4.transform.SetParent(_hoverLabelRoot.transform, false);
					_hoverLabelText = (TMP_Text)(object)val4.AddComponent<TextMeshProUGUI>();
					_hoverLabelText.alignment = (TextAlignmentOptions)514;
					_hoverLabelText.fontSize = 12f;
					((Graphic)_hoverLabelText).color = Color32.op_Implicit(UiStyle.HeaderGold);
					_hoverLabelText.enableWordWrapping = false;
					_hoverLabelText.overflowMode = (TextOverflowModes)0;
					((Graphic)_hoverLabelText).raycastTarget = false;
					_hoverLabelText.richText = true;
					if ((Object)(object)UiStyle.Font != (Object)null)
					{
						_hoverLabelText.font = UiStyle.Font;
					}
					_hoverLabelText.text = _pendingLabel;
					RectTransform rectTransform = _hoverLabelText.rectTransform;
					rectTransform.anchorMin = Vector2.zero;
					rectTransform.anchorMax = Vector2.one;
					rectTransform.offsetMin = new Vector2(6f, 0f);
					rectTransform.offsetMax = new Vector2(-6f, 0f);
					ResizeLabelToContent();
					_hoverLabelRoot.SetActive(false);
				}
			}

			private void ResizeLabelToContent()
			{
				//IL_0051: Unknown result type (might be due to invalid IL or missing references)
				//IL_005c: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)_hoverLabelRoot == (Object)null) && !((Object)(object)_hoverLabelText == (Object)null))
				{
					_hoverLabelText.ForceMeshUpdate(false, false);
					float num = Mathf.Max(80f, _hoverLabelText.preferredWidth + 16f);
					((RectTransform)_hoverLabelRoot.transform).sizeDelta = new Vector2(num, 22f);
				}
			}

			private void SetLabelVisible(bool visible)
			{
				if (!((Object)(object)_hoverLabelRoot == (Object)null))
				{
					_hoverLabelRoot.SetActive(visible);
					if (visible)
					{
						_hoverLabelRoot.transform.SetAsLastSibling();
					}
				}
			}

			private void OnDisable()
			{
				_hovered = false;
				_pressed = false;
				SetLabelVisible(visible: false);
				Refresh();
			}
		}

		internal sealed class DragHandle : MonoBehaviour, IPointerDownHandler, IEventSystemHandler, IDragHandler, IBeginDragHandler
		{
			public RectTransform Target;

			private Vector2 _grabOffset;

			public event Action<float, float> Moved;

			public void OnPointerDown(PointerEventData e)
			{
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Expected O, but got Unknown
				//IL_003a: Unknown result type (might be due to invalid IL or missing references)
				//IL_003f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: Unknown result type (might be due to invalid IL or missing references)
				//IL_0045: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)Target == (Object)null))
				{
					Vector2 val = default(Vector2);
					RectTransformUtility.ScreenPointToLocalPointInRectangle((RectTransform)((Transform)Target).parent, e.position, e.pressEventCamera, ref val);
					_grabOffset = Target.anchoredPosition - val;
				}
			}

			public void OnBeginDrag(PointerEventData e)
			{
				OnPointerDown(e);
			}

			public void OnDrag(PointerEventData e)
			{
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Expected O, but got Unknown
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				//IL_003d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0042: Unknown result type (might be due to invalid IL or missing references)
				//IL_005d: 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)
				Vector2 val = default(Vector2);
				if (!((Object)(object)Target == (Object)null) && RectTransformUtility.ScreenPointToLocalPointInRectangle((RectTransform)((Transform)Target).parent, e.position, e.pressEventCamera, ref val))
				{
					Target.anchoredPosition = val + _grabOffset;
					this.Moved?.Invoke(Target.anchoredPosition.x, Target.anchoredPosition.y);
				}
			}
		}

		private readonly Transform _canvasRoot;

		private GameObject _panel;

		private RectTransform _panelRt;

		private TMP_Text _trackedLabel;

		private TMP_Text _valueLabel;

		private DragHandle _dragHandle;

		private Image _tooltipToggleIcon;

		private TooltipToggleButton _tooltipToggle;

		public RectTransform Rect => _panelRt;

		public bool IsVisible
		{
			get
			{
				if ((Object)(object)_panel != (Object)null)
				{
					return _panel.activeSelf;
				}
				return false;
			}
		}

		public event Action<float, float> PlacementChanged;

		public event Action TooltipToggleClicked;

		public CropHudView(Transform canvasRoot)
		{
			_canvasRoot = canvasRoot;
			Build();
		}

		public void SetVisible(bool visible)
		{
			if ((Object)(object)_panel == (Object)null)
			{
				Build();
			}
			if ((Object)(object)_panel != (Object)null)
			{
				_panel.SetActive(visible);
			}
		}

		public void SetPlacement(float x, float y)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_panelRt == (Object)null)
			{
				Build();
			}
			if ((Object)(object)_panelRt != (Object)null)
			{
				_panelRt.anchoredPosition = new Vector2(x, 0f - y);
			}
		}

		public void SetScale(float scale)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_panelRt == (Object)null)
			{
				Build();
			}
			if ((Object)(object)_panelRt != (Object)null)
			{
				((Transform)_panelRt).localScale = new Vector3(scale, scale, 1f);
			}
		}

		public void UpdateStats(int trackedCount, long projectedGold)
		{
			if (!((Object)(object)_trackedLabel == (Object)null))
			{
				_trackedLabel.text = $"Tracked crops: <b>{trackedCount}</b>";
				_valueLabel.text = $"Projected sell: <color=#F7D982><b>{projectedGold:N0}g</b></color>";
			}
		}

		public void SetTooltipEnabled(bool enabled)
		{
			//IL_0038: 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_003d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_tooltipToggleIcon == (Object)null))
			{
				_tooltipToggleIcon.sprite = UiStyle.GetIcon(enabled ? UiStyle.IconKind.Tooltip : UiStyle.IconKind.TooltipOff);
				((Graphic)_tooltipToggleIcon).color = Color32.op_Implicit(enabled ? UiStyle.HeaderGold : UiStyle.TextSub);
				if ((Object)(object)_tooltipToggle != (Object)null)
				{
					_tooltipToggle.SetTooltipLabel(enabled ? "Toggle Crop Tooltips <color=#B8A078>(on)</color>" : "Toggle Crop Tooltips <color=#B8A078>(off)</color>");
				}
			}
		}

		public void Destroy()
		{
			if ((Object)(object)_panel != (Object)null)
			{
				Object.Destroy((Object)(object)_panel);
				_panel = null;
				_panelRt = null;
				_trackedLabel = null;
				_valueLabel = null;
				_dragHandle = null;
			}
		}

		private void Build()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Expected O, but got Unknown
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: 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_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Expected O, but got Unknown
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: 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_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_0251: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: 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_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_030a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0310: Unknown result type (might be due to invalid IL or missing references)
			//IL_0315: Unknown result type (might be due to invalid IL or missing references)
			//IL_0320: Unknown result type (might be due to invalid IL or missing references)
			//IL_032a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0335: Unknown result type (might be due to invalid IL or missing references)
			//IL_033f: Unknown result type (might be due to invalid IL or missing references)
			//IL_034a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0354: Unknown result type (might be due to invalid IL or missing references)
			//IL_035f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0373: Unknown result type (might be due to invalid IL or missing references)
			//IL_038e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0393: Unknown result type (might be due to invalid IL or missing references)
			//IL_03aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03de: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0407: Unknown result type (might be due to invalid IL or missing references)
			//IL_0422: Unknown result type (might be due to invalid IL or missing references)
			//IL_0441: Unknown result type (might be due to invalid IL or missing references)
			//IL_0456: Unknown result type (might be due to invalid IL or missing references)
			//IL_046b: Unknown result type (might be due to invalid IL or missing references)
			//IL_047f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b4: Expected O, but got Unknown
			//IL_04cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0506: Unknown result type (might be due to invalid IL or missing references)
			//IL_0510: Unknown result type (might be due to invalid IL or missing references)
			//IL_051b: Unknown result type (might be due to invalid IL or missing references)
			//IL_052f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0550: Unknown result type (might be due to invalid IL or missing references)
			//IL_0555: Unknown result type (might be due to invalid IL or missing references)
			//IL_056f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0599: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_05cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0605: Unknown result type (might be due to invalid IL or missing references)
			//IL_060a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0620: Unknown result type (might be due to invalid IL or missing references)
			//IL_0625: Unknown result type (might be due to invalid IL or missing references)
			//IL_063e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0643: Unknown result type (might be due to invalid IL or missing references)
			//IL_0677: Unknown result type (might be due to invalid IL or missing references)
			//IL_067e: Expected O, but got Unknown
			//IL_0698: Unknown result type (might be due to invalid IL or missing references)
			//IL_069d: Unknown result type (might be due to invalid IL or missing references)
			//IL_06a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_06b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_06bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_06c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_06d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_06e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_06fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0719: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_canvasRoot == (Object)null))
			{
				_panel = new GameObject("CropOptimizer_Hud", new Type[2]
				{
					typeof(RectTransform),
					typeof(Image)
				});
				_panel.transform.SetParent(_canvasRoot, false);
				_panelRt = (RectTransform)_panel.transform;
				_panelRt.anchorMin = new Vector2(0f, 1f);
				_panelRt.anchorMax = new Vector2(0f, 1f);
				_panelRt.pivot = new Vector2(0f, 1f);
				_panelRt.anchoredPosition = new Vector2(24f, -80f);
				_panelRt.sizeDelta = new Vector2(320f, 96f);
				Image component = _panel.GetComponent<Image>();
				component.sprite = UiStyle.SolidSprite;
				component.type = (Type)0;
				((Graphic)component).color = Color32.op_Implicit(UiStyle.WoodBorder);
				((Graphic)component).raycastTarget = true;
				GameObject val = new GameObject("Fill", new Type[2]
				{
					typeof(RectTransform),
					typeof(Image)
				});
				val.transform.SetParent(_panel.transform, false);
				RectTransform val2 = (RectTransform)val.transform;
				val2.anchorMin = Vector2.zero;
				val2.anchorMax = Vector2.one;
				val2.offsetMin = new Vector2(3f, 3f);
				val2.offsetMax = new Vector2(-3f, -3f);
				Image component2 = val.GetComponent<Image>();
				component2.sprite = UiStyle.SolidSprite;
				((Graphic)component2).color = Color32.op_Implicit(UiStyle.PanelFill);
				((Graphic)component2).raycastTarget = false;
				GameObject val3 = new GameObject("Header", new Type[2]
				{
					typeof(RectTransform),
					typeof(Image)
				});
				val3.transform.SetParent(val.transform, false);
				RectTransform val4 = (RectTransform)val3.transform;
				val4.anchorMin = new Vector2(0f, 1f);
				val4.anchorMax = new Vector2(1f, 1f);
				val4.pivot = new Vector2(0.5f, 1f);
				val4.anchoredPosition = Vector2.zero;
				val4.sizeDelta = new Vector2(0f, 30f);
				Image component3 = val3.GetComponent<Image>();
				component3.sprite = UiStyle.SolidSprite;
				((Graphic)component3).color = Color32.op_Implicit(UiStyle.HeaderFill);
				_dragHandle = val3.AddComponent<DragHandle>();
				_dragHandle.Target = _panelRt;
				_dragHandle.Moved += delegate(float x, float y)
				{
					this.PlacementChanged?.Invoke(x, 0f - y);
				};
				GameObject val5 = new GameObject("Divider", new Type[2]
				{
					typeof(RectTransform),
					typeof(Image)
				});
				val5.transform.SetParent(val.transform, false);
				RectTransform val6 = (RectTransform)val5.transform;
				val6.anchorMin = new Vector2(0f, 1f);
				val6.anchorMax = new Vector2(1f, 1f);
				val6.pivot = new Vector2(0.5f, 1f);
				val6.anchoredPosition = new Vector2(0f, -30f);
				val6.sizeDelta = new Vector2(0f, 1f);
				Image component4 = val5.GetComponent<Image>();
				component4.sprite = UiStyle.SolidSprite;
				((Graphic)component4).color = Color32.op_Implicit(UiStyle.WoodBorderLit);
				((Graphic)component4).raycastTarget = false;
				RectTransform rectTransform = ((Graphic)CreateIcon(val3.transform, UiStyle.IconKind.Sprout, UiStyle.Sprout, 20f)).rectTransform;
				rectTransform.anchorMin = new Vector2(0f, 0.5f);
				rectTransform.anchorMax = new Vector2(0f, 0.5f);
				rectTransform.pivot = new Vector2(0f, 0.5f);
				rectTransform.anchoredPosition = new Vector2(10f, 0f);
				RectTransform rectTransform2 = CreateText(val3.transform, "Crop Optimizer", 16f, (FontStyles)1, UiStyle.HeaderGold, (TextAlignmentOptions)4097).rectTransform;
				rectTransform2.anchorMin = new Vector2(0f, 0f);
				rectTransform2.anchorMax = new Vector2(1f, 1f);
				rectTransform2.offsetMin = new Vector2(36f, 0f);
				rectTransform2.offsetMax = new Vector2(-36f, 0f);
				GameObject val7 = new GameObject("TooltipToggle", new Type[2]
				{
					typeof(RectTransform),
					typeof(Image)
				});
				val7.transform.SetParent(val3.transform, false);
				RectTransform val8 = (RectTransform)val7.transform;
				val8.anchorMin = new Vector2(1f, 0.5f);
				val8.anchorMax = new Vector2(1f, 0.5f);
				val8.pivot = new Vector2(1f, 0.5f);
				val8.anchoredPosition = new Vector2(-8f, 0f);
				val8.sizeDelta = new Vector2(24f, 24f);
				Image component5 = val7.GetComponent<Image>();
				component5.sprite = UiStyle.SolidSprite;
				((Graphic)component5).color = Color32.op_Implicit(new Color32((byte)0, (byte)0, (byte)0, (byte)0));
				((Graphic)component5).raycastTarget = true;
				_tooltipToggleIcon = CreateIcon(val7.transform, UiStyle.IconKind.Tooltip, UiStyle.HeaderGold, 16f);
				RectTransform rectTransform3 = ((Graphic)_tooltipToggleIcon).rectTransform;
				rectTransform3.anchorMin = new Vector2(0.5f, 0.5f);
				rectTransform3.anchorMax = new Vector2(0.5f, 0.5f);
				rectTransform3.pivot = new Vector2(0.5f, 0.5f);
				rectTransform3.anchoredPosition = Vector2.zero;
				((Graphic)_tooltipToggleIcon).raycastTarget = false;
				_tooltipToggle = val7.AddComponent<TooltipToggleButton>();
				_tooltipToggle.Background = component5;
				_tooltipToggle.NormalColor = new Color32((byte)0, (byte)0, (byte)0, (byte)0);
				_tooltipToggle.HoverColor = new Color32((byte)176, (byte)122, (byte)62, (byte)96);
				_tooltipToggle.PressedColor = new Color32((byte)176, (byte)122, (byte)62, (byte)160);
				_tooltipToggle.Clicked += delegate
				{
					this.TooltipToggleClicked?.Invoke();
				};
				GameObject val9 = new GameObject("Body", new Type[1] { typeof(RectTransform) });
				val9.transform.SetParent(val.transform, false);
				RectTransform val10 = (RectTransform)val9.transform;
				val10.anchorMin = new Vector2(0f, 0f);
				val10.anchorMax = new Vector2(1f, 1f);
				val10.offsetMin = new Vector2(14f, 8f);
				val10.offsetMax = new Vector2(-14f, -36f);
				_trackedLabel = AddRow(val9.transform, UiStyle.IconKind.Sprout, UiStyle.Sprout, "Tracked crops: 0", 0);
				_valueLabel = AddRow(val9.transform, UiStyle.IconKind.Coin, UiStyle.Coin, "Projected sell: 0g", 1);
			}
		}

		private TMP_Text AddRow(Transform parent, UiStyle.IconKind icon, Color32 iconColor, string initialText, int rowIndex)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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_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_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: 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_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: 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_00f9: 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_0124: 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_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject($"Row_{icon}", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(parent, false);
			RectTransform val2 = (RectTransform)val.transform;
			val2.anchorMin = new Vector2(0f, 1f);
			val2.anchorMax = new Vector2(1f, 1f);
			val2.pivot = new Vector2(0f, 1f);
			val2.anchoredPosition = new Vector2(0f, (float)(-rowIndex) * 24f);
			val2.sizeDelta = new Vector2(0f, 22f);
			RectTransform rectTransform = ((Graphic)CreateIcon(val.transform, icon, iconColor, 18f)).rectTransform;
			rectTransform.anchorMin = new Vector2(0f, 0.5f);
			rectTransform.anchorMax = new Vector2(0f, 0.5f);
			rectTransform.pivot = new Vector2(0f, 0.5f);
			rectTransform.anchoredPosition = new Vector2(0f, 0f);
			TMP_Text obj = CreateText(val.transform, initialText, 15f, (FontStyles)0, UiStyle.TextDark, (TextAlignmentOptions)4097);
			RectTransform rectTransform2 = obj.rectTransform;
			rectTransform2.anchorMin = new Vector2(0f, 0f);
			rectTransform2.anchorMax = new Vector2(1f, 1f);
			rectTransform2.offsetMin = new Vector2(26f, 0f);
			rectTransform2.offsetMax = new Vector2(-2f, 0f);
			return obj;
		}

		private static Image CreateIcon(Transform parent, UiStyle.IconKind kind, Color32 color, float size)
		{
			//IL_0030: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject($"Icon_{kind}", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val.transform.SetParent(parent, false);
			((RectTransform)val.transform).sizeDelta = new Vector2(size, size);
			Image component = val.GetComponent<Image>();
			component.sprite = UiStyle.GetIcon(kind);
			((Graphic)component).color = Color32.op_Implicit(color);
			((Graphic)component).raycastTarget = false;
			return component;
		}

		private static TMP_Text CreateText(Transform parent, string text, float size, FontStyles style, Color32 color, TextAlignmentOptions align)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (