Decompiled source of CropOptimizer v1.4.3
CropOptimizer.dll
Decompiled 2 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.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 (