Decompiled source of SunHavenTodo v1.4.2

SunhavenTodo.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using SunhavenMods.Shared;
using SunhavenTodo.Data;
using SunhavenTodo.UI;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
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("SunhavenTodo")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+5c08b5aa5d0be9c4b93df77f697dc55d5ac97088")]
[assembly: AssemblyProduct("SunhavenTodo")]
[assembly: AssemblyTitle("SunhavenTodo")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 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 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;
			}
		}
	}
	public static class OvernightHookUtility
	{
		public static bool TryHookOvernightEvent(ref bool overnightHooked, ref UnityAction overnightCallback, UnityAction callback, Func<Type, object> singletonResolver, Action<string> logInfo = null, Action<string> logWarning = null)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Expected O, but got Unknown
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Expected O, but got Unknown
			if (overnightHooked)
			{
				return true;
			}
			try
			{
				Type type = AccessTools.TypeByName("Wish.DayCycle");
				if (type != null)
				{
					FieldInfo fieldInfo = AccessTools.Field(type, "OnDayStart");
					if (fieldInfo != null)
					{
						object? value = fieldInfo.GetValue(null);
						UnityAction val = (UnityAction)((value is UnityAction) ? value : null);
						overnightCallback = callback;
						if (val != null)
						{
							val = (UnityAction)Delegate.Remove((Delegate?)(object)val, (Delegate?)(object)overnightCallback);
							val = (UnityAction)Delegate.Combine((Delegate?)(object)val, (Delegate?)(object)overnightCallback);
							fieldInfo.SetValue(null, val);
						}
						else
						{
							fieldInfo.SetValue(null, overnightCallback);
						}
						overnightHooked = true;
						logInfo?.Invoke("Hooked into DayCycle.OnDayStart");
						return true;
					}
				}
				Type type2 = AccessTools.TypeByName("Wish.UIHandler");
				if (type2 == null)
				{
					return false;
				}
				object obj = singletonResolver?.Invoke(type2);
				if (obj == null)
				{
					return false;
				}
				FieldInfo fieldInfo2 = AccessTools.Field(type2, "OnCompleteOvernight");
				if (fieldInfo2 == null)
				{
					return false;
				}
				object? value2 = fieldInfo2.GetValue(obj);
				UnityAction val2 = (UnityAction)((value2 is UnityAction) ? value2 : null);
				overnightCallback = callback;
				if (val2 != null)
				{
					val2 = (UnityAction)Delegate.Remove((Delegate?)(object)val2, (Delegate?)(object)overnightCallback);
					val2 = (UnityAction)Delegate.Combine((Delegate?)(object)val2, (Delegate?)(object)overnightCallback);
					fieldInfo2.SetValue(obj, val2);
				}
				else
				{
					fieldInfo2.SetValue(obj, overnightCallback);
				}
				overnightHooked = true;
				logInfo?.Invoke("Hooked into UIHandler.OnCompleteOvernight");
				return true;
			}
			catch (Exception ex)
			{
				logWarning?.Invoke("Failed to hook overnight event: " + ex.Message);
				return false;
			}
		}
	}
	public static class IconCache
	{
		private struct CachedIcon
		{
			public Texture2D Texture;

			public bool OwnsTexture;
		}

		private static readonly Dictionary<int, CachedIcon> _iconCache = new Dictionary<int, CachedIcon>();

		private const int MaxCacheSize = 200;

		private static readonly HashSet<int> _loadingItems = new HashSet<int>();

		private static readonly HashSet<int> _failedItems = new HashSet<int>();

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

		private static Texture2D _fallbackTexture;

		private static ManualLogSource _log;

		private static Type _databaseType;

		private static Type _itemDataType;

		private static MethodInfo _getDataMethod;

		private static bool _reflectionInitialized;

		private static bool _initialized;

		private static bool _iconsLoaded;

		private static int[] _pendingPreloadItemIds;

		public static void Initialize(ManualLogSource log, int[] preloadItemIds = null)
		{
			_log = log;
			if (_initialized)
			{
				ManualLogSource log2 = _log;
				if (log2 != null)
				{
					log2.LogDebug((object)"[IconCache] Already initialized");
				}
				return;
			}
			_initialized = true;
			ManualLogSource log3 = _log;
			if (log3 != null)
			{
				log3.LogInfo((object)"[IconCache] Initializing icon cache...");
			}
			_fallbackTexture = CreateFallbackTexture();
			ManualLogSource log4 = _log;
			if (log4 != null)
			{
				log4.LogInfo((object)"[IconCache] Created fallback texture");
			}
			if (preloadItemIds != null && preloadItemIds.Length != 0)
			{
				_pendingPreloadItemIds = (int[])preloadItemIds.Clone();
				ManualLogSource log5 = _log;
				if (log5 != null)
				{
					log5.LogInfo((object)$"[IconCache] Preload: {_pendingPreloadItemIds.Length} item ID(s) will queue with LoadAllIcons");
				}
			}
		}

		public static void RegisterCurrency(string currencyId, int itemId)
		{
			_currencyToItemId[currencyId] = itemId;
		}

		public static void LoadAllIcons()
		{
			if (_iconsLoaded)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogDebug((object)"[IconCache] Icons already loaded, skipping");
				}
				return;
			}
			if (!InitializeReflection())
			{
				ManualLogSource log2 = _log;
				if (log2 != null)
				{
					log2.LogError((object)"[IconCache] Failed to initialize reflection, cannot load icons");
				}
				_iconsLoaded = true;
				return;
			}
			foreach (KeyValuePair<string, int> item in _currencyToItemId)
			{
				ManualLogSource log3 = _log;
				if (log3 != null)
				{
					log3.LogDebug((object)$"[IconCache] Queuing load for: {item.Key} (ItemID: {item.Value})");
				}
				LoadIcon(item.Value);
			}
			if (_pendingPreloadItemIds != null)
			{
				int[] pendingPreloadItemIds = _pendingPreloadItemIds;
				foreach (int num in pendingPreloadItemIds)
				{
					if (num > 0)
					{
						ManualLogSource log4 = _log;
						if (log4 != null)
						{
							log4.LogDebug((object)$"[IconCache] Queuing preload item ID: {num}");
						}
						LoadIcon(num);
					}
				}
			}
			_iconsLoaded = true;
			ManualLogSource log5 = _log;
			if (log5 != null)
			{
				log5.LogInfo((object)$"[IconCache] Queued {_currencyToItemId.Count} currency icon(s); preload queue processed.");
			}
		}

		public static Texture2D GetIconForCurrency(string currencyId)
		{
			if (_currencyToItemId.TryGetValue(currencyId, out var value))
			{
				return GetIcon(value);
			}
			return GetFallbackTexture();
		}

		public static Texture2D GetIcon(int itemId)
		{
			if (itemId <= 0)
			{
				return GetFallbackTexture();
			}
			if (_iconCache.TryGetValue(itemId, out var value))
			{
				return value.Texture;
			}
			if (!_loadingItems.Contains(itemId) && !_failedItems.Contains(itemId))
			{
				LoadIcon(itemId);
			}
			return GetFallbackTexture();
		}

		private static Texture2D GetFallbackTexture()
		{
			if ((Object)(object)_fallbackTexture == (Object)null)
			{
				_fallbackTexture = CreateFallbackTexture();
			}
			return _fallbackTexture;
		}

		public static bool IsIconLoaded(int itemId)
		{
			return _iconCache.ContainsKey(itemId);
		}

		public static bool IsIconLoaded(string currencyId)
		{
			if (_currencyToItemId.TryGetValue(currencyId, out var value))
			{
				return IsIconLoaded(value);
			}
			return false;
		}

		public static int GetItemIdForCurrency(string currencyId)
		{
			if (!_currencyToItemId.TryGetValue(currencyId, out var value))
			{
				return -1;
			}
			return value;
		}

		private static bool InitializeReflection()
		{
			if (_reflectionInitialized)
			{
				if (_databaseType != null && _itemDataType != null)
				{
					return _getDataMethod != null;
				}
				return false;
			}
			_reflectionInitialized = true;
			try
			{
				string[] array = new string[4] { "Database", "Wish.Database", "PSS.Database", "SunHaven.Database" };
				for (int i = 0; i < array.Length; i++)
				{
					_databaseType = AccessTools.TypeByName(array[i]);
					if (_databaseType != null)
					{
						ManualLogSource log = _log;
						if (log != null)
						{
							log.LogInfo((object)("[IconCache] Found Database type: " + _databaseType.FullName));
						}
						break;
					}
				}
				MethodInfo[] methods;
				if (_databaseType == null)
				{
					Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
					foreach (Assembly assembly in assemblies)
					{
						try
						{
							Type[] types = assembly.GetTypes();
							foreach (Type type in types)
							{
								if (!(type.Name == "Database") || type.IsNested)
								{
									continue;
								}
								methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public);
								foreach (MethodInfo methodInfo in methods)
								{
									if (methodInfo.Name == "GetData" && methodInfo.IsGenericMethod)
									{
										_databaseType = type;
										ManualLogSource log2 = _log;
										if (log2 != null)
										{
											log2.LogInfo((object)("[IconCache] Found Database type: " + type.FullName));
										}
										break;
									}
								}
								if (_databaseType != null)
								{
									break;
								}
							}
							if (_databaseType != null)
							{
								break;
							}
						}
						catch (Exception ex)
						{
							ManualLogSource log3 = _log;
							if (log3 != null)
							{
								log3.LogDebug((object)("[IconCache] Skipping assembly " + assembly.GetName().Name + ": " + ex.Message));
							}
						}
					}
				}
				if (_databaseType == null)
				{
					ManualLogSource log4 = _log;
					if (log4 != null)
					{
						log4.LogError((object)"[IconCache] Could not find Database type");
					}
					return false;
				}
				_itemDataType = AccessTools.TypeByName("Wish.ItemData");
				if (_itemDataType == null)
				{
					ManualLogSource log5 = _log;
					if (log5 != null)
					{
						log5.LogError((object)"[IconCache] Could not find Wish.ItemData type");
					}
					return false;
				}
				methods = _databaseType.GetMethods(BindingFlags.Static | BindingFlags.Public);
				foreach (MethodInfo methodInfo2 in methods)
				{
					if (!(methodInfo2.Name == "GetData") || !methodInfo2.IsGenericMethod)
					{
						continue;
					}
					ParameterInfo[] parameters = methodInfo2.GetParameters();
					if (methodInfo2.GetGenericArguments().Length == 1 && parameters.Length == 3 && parameters[0].ParameterType == typeof(int))
					{
						_getDataMethod = methodInfo2.MakeGenericMethod(_itemDataType);
						ManualLogSource log6 = _log;
						if (log6 != null)
						{
							log6.LogInfo((object)"[IconCache] Found Database.GetData method");
						}
						break;
					}
				}
				if (_getDataMethod == null)
				{
					ManualLogSource log7 = _log;
					if (log7 != null)
					{
						log7.LogError((object)"[IconCache] Could not find Database.GetData method");
					}
					return false;
				}
				return true;
			}
			catch (Exception ex2)
			{
				ManualLogSource log8 = _log;
				if (log8 != null)
				{
					log8.LogError((object)("[IconCache] Error initializing reflection: " + ex2.Message));
				}
				return false;
			}
		}

		private static void LoadIcon(int itemId)
		{
			if (itemId <= 0 || _loadingItems.Contains(itemId) || _iconCache.ContainsKey(itemId))
			{
				return;
			}
			_loadingItems.Add(itemId);
			try
			{
				if (!InitializeReflection() || _getDataMethod == null)
				{
					_failedItems.Add(itemId);
					_loadingItems.Remove(itemId);
					return;
				}
				Type delegateType = typeof(Action<>).MakeGenericType(_itemDataType);
				ParameterExpression parameterExpression = Expression.Parameter(_itemDataType, "itemData");
				ConstantExpression arg = Expression.Constant(itemId);
				MethodCallExpression body = Expression.Call(typeof(IconCache).GetMethod("OnIconLoadedInternal", BindingFlags.Static | BindingFlags.NonPublic), arg, Expression.Convert(parameterExpression, typeof(object)));
				Delegate @delegate = Expression.Lambda(delegateType, body, parameterExpression).Compile();
				Action action = Expression.Lambda<Action>(Expression.Call(typeof(IconCache).GetMethod("OnIconLoadFailed", BindingFlags.Static | BindingFlags.NonPublic), arg), Array.Empty<ParameterExpression>()).Compile();
				_getDataMethod.Invoke(null, new object[3] { itemId, @delegate, action });
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogDebug((object)$"[IconCache] Error loading icon {itemId}: {ex.Message}");
				}
				_failedItems.Add(itemId);
				_loadingItems.Remove(itemId);
			}
		}

		private static void OnIconLoadedInternal(int itemId, object itemData)
		{
			_loadingItems.Remove(itemId);
			if (itemData == null)
			{
				_failedItems.Add(itemId);
				return;
			}
			try
			{
				Type type = itemData.GetType();
				object obj = null;
				BindingFlags[] array = new BindingFlags[4]
				{
					BindingFlags.Instance | BindingFlags.Public,
					BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy,
					BindingFlags.Instance | BindingFlags.NonPublic,
					BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy
				};
				BindingFlags[] array2 = array;
				foreach (BindingFlags bindingAttr in array2)
				{
					PropertyInfo property = type.GetProperty("icon", bindingAttr);
					if (property != null)
					{
						obj = property.GetValue(itemData);
						break;
					}
				}
				if (obj == null)
				{
					array2 = array;
					foreach (BindingFlags bindingAttr2 in array2)
					{
						FieldInfo field = type.GetField("icon", bindingAttr2);
						if (field != null)
						{
							obj = field.GetValue(itemData);
							break;
						}
					}
				}
				if (obj == null)
				{
					Type type2 = type;
					while (type2 != null && obj == null)
					{
						PropertyInfo[] properties = type2.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
						foreach (PropertyInfo propertyInfo in properties)
						{
							if (propertyInfo.Name.Equals("icon", StringComparison.OrdinalIgnoreCase))
							{
								obj = propertyInfo.GetValue(itemData);
								break;
							}
						}
						if (obj == null)
						{
							FieldInfo[] fields = type2.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
							foreach (FieldInfo fieldInfo in fields)
							{
								if (fieldInfo.Name.Equals("icon", StringComparison.OrdinalIgnoreCase))
								{
									obj = fieldInfo.GetValue(itemData);
									break;
								}
							}
						}
						type2 = type2.BaseType;
					}
				}
				Sprite val = (Sprite)((obj is Sprite) ? obj : null);
				if (val != null)
				{
					CacheSprite(itemId, val);
				}
				else
				{
					_failedItems.Add(itemId);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogDebug((object)$"[IconCache] Error processing icon {itemId}: {ex.Message}");
				}
				_failedItems.Add(itemId);
			}
		}

		private static void OnIconLoadFailed(int itemId)
		{
			_loadingItems.Remove(itemId);
			_failedItems.Add(itemId);
		}

		private static void CacheSprite(int itemId, Sprite sprite)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)sprite == (Object)null || (Object)(object)sprite.texture == (Object)null)
			{
				_failedItems.Add(itemId);
				return;
			}
			try
			{
				Rect rect = sprite.rect;
				Texture2D val;
				bool ownsTexture;
				if (((Rect)(ref rect)).width == (float)((Texture)sprite.texture).width)
				{
					rect = sprite.rect;
					if (((Rect)(ref rect)).height == (float)((Texture)sprite.texture).height)
					{
						val = sprite.texture;
						ownsTexture = false;
						goto IL_0077;
					}
				}
				val = ExtractSpriteTexture(sprite);
				ownsTexture = (Object)(object)val != (Object)null;
				goto IL_0077;
				IL_0077:
				if ((Object)(object)val != (Object)null)
				{
					_iconCache[itemId] = new CachedIcon
					{
						Texture = val,
						OwnsTexture = ownsTexture
					};
					if (_iconCache.Count <= 200)
					{
						return;
					}
					int num = -1;
					int num2 = -1;
					foreach (int key in _iconCache.Keys)
					{
						if (num2 < 0)
						{
							num2 = key;
						}
						if (!_loadingItems.Contains(key) && !_failedItems.Contains(key))
						{
							num = key;
							break;
						}
					}
					if (num < 0)
					{
						num = num2;
					}
					if (num >= 0 && _iconCache.TryGetValue(num, out var value))
					{
						if (value.OwnsTexture && (Object)(object)value.Texture != (Object)null)
						{
							Object.Destroy((Object)(object)value.Texture);
						}
						_iconCache.Remove(num);
					}
				}
				else
				{
					_failedItems.Add(itemId);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogDebug((object)$"[IconCache] Error caching sprite {itemId}: {ex.Message}");
				}
				_failedItems.Add(itemId);
			}
		}

		private static Texture2D ExtractSpriteTexture(Sprite sprite)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			try
			{
				Rect rect = sprite.rect;
				int num = (int)((Rect)(ref rect)).width;
				int num2 = (int)((Rect)(ref rect)).height;
				if (!((Texture)sprite.texture).isReadable)
				{
					return CopyTextureViaRenderTexture(sprite);
				}
				Texture2D val = new Texture2D(num, num2, (TextureFormat)4, false);
				Color[] pixels = sprite.texture.GetPixels((int)((Rect)(ref rect)).x, (int)((Rect)(ref rect)).y, num, num2);
				val.SetPixels(pixels);
				val.Apply();
				return val;
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogDebug((object)("[IconCache] Error extracting sprite texture: " + ex.Message));
				}
				return null;
			}
		}

		private static Texture2D CopyTextureViaRenderTexture(Sprite sprite)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			RenderTexture val = null;
			RenderTexture active = RenderTexture.active;
			try
			{
				Rect rect = sprite.rect;
				int num = (int)((Rect)(ref rect)).width;
				int num2 = (int)((Rect)(ref rect)).height;
				val = RenderTexture.GetTemporary(((Texture)sprite.texture).width, ((Texture)sprite.texture).height, 0, (RenderTextureFormat)0);
				Graphics.Blit((Texture)(object)sprite.texture, val);
				RenderTexture.active = val;
				Texture2D val2 = new Texture2D(num, num2, (TextureFormat)4, false);
				val2.ReadPixels(new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).y, (float)num, (float)num2), 0, 0);
				val2.Apply();
				return val2;
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogDebug((object)("[IconCache] Error copying texture via RenderTexture: " + ex.Message));
				}
				return null;
			}
			finally
			{
				RenderTexture.active = active;
				if ((Object)(object)val != (Object)null)
				{
					RenderTexture.ReleaseTemporary(val);
				}
			}
		}

		private static Texture2D CreateFallbackTexture()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			int num = 32;
			Texture2D val = new Texture2D(num, num);
			Color val2 = default(Color);
			((Color)(ref val2))..ctor(0.3f, 0.3f, 0.4f, 0.8f);
			Color val3 = default(Color);
			((Color)(ref val3))..ctor(0.5f, 0.5f, 0.6f, 1f);
			for (int i = 0; i < num; i++)
			{
				for (int j = 0; j < num; j++)
				{
					if (j == 0 || j == num - 1 || i == 0 || i == num - 1)
					{
						val.SetPixel(j, i, val3);
					}
					else
					{
						val.SetPixel(j, i, val2);
					}
				}
			}
			val.Apply();
			return val;
		}

		public static void Clear()
		{
			foreach (KeyValuePair<int, CachedIcon> item in _iconCache)
			{
				if (item.Value.OwnsTexture && (Object)(object)item.Value.Texture != (Object)null)
				{
					Object.Destroy((Object)(object)item.Value.Texture);
				}
			}
			_iconCache.Clear();
			_loadingItems.Clear();
			_failedItems.Clear();
			_initialized = false;
			_iconsLoaded = false;
			_pendingPreloadItemIds = null;
		}

		public static (int loaded, int loading, int failed) GetStats()
		{
			return (_iconCache.Count, _loadingItems.Count, _failedItems.Count);
		}

		public static void LogStatus()
		{
			(int, int, int) stats = GetStats();
			ManualLogSource log = _log;
			if (log != null)
			{
				log.LogInfo((object)$"[IconCache] Loaded: {stats.Item1}, Loading: {stats.Item2}, Failed: {stats.Item3}");
			}
		}
	}
	public static class TextInputFocusGuard
	{
		private const float DefaultPollIntervalSeconds = 0.25f;

		private static float _nextPollTime = -1f;

		private static bool _cachedDefer;

		private static bool _tmpTypeLookupDone;

		private static Type _tmpInputFieldType;

		private static bool _qcLookupDone;

		private static Type _qcType;

		private static PropertyInfo _qcInstanceProp;

		private static PropertyInfo _qcIsActiveProp;

		private static FieldInfo _qcIsActiveField;

		public static bool ShouldDeferModHotkeys(ManualLogSource debugLog = null, float pollIntervalSeconds = 0.25f)
		{
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (realtimeSinceStartup < _nextPollTime)
			{
				return _cachedDefer;
			}
			_nextPollTime = realtimeSinceStartup + Mathf.Max(0.05f, pollIntervalSeconds);
			bool flag = false;
			try
			{
				if (GUIUtility.keyboardControl != 0)
				{
					flag = true;
				}
				if (!flag)
				{
					EventSystem current = EventSystem.current;
					GameObject val = ((current != null) ? current.currentSelectedGameObject : null);
					if ((Object)(object)val != (Object)null)
					{
						if ((Object)(object)val.GetComponent<InputField>() != (Object)null)
						{
							flag = true;
						}
						else if (TryGetTmpInputField(val))
						{
							flag = true;
						}
					}
				}
				if (!flag && IsQuantumConsoleActive(debugLog))
				{
					flag = true;
				}
			}
			catch (Exception ex)
			{
				if (debugLog != null)
				{
					debugLog.LogDebug((object)("[TextInputFocusGuard] " + ex.Message));
				}
			}
			_cachedDefer = flag;
			return flag;
		}

		private static bool TryGetTmpInputField(GameObject go)
		{
			if (!_tmpTypeLookupDone)
			{
				_tmpTypeLookupDone = true;
				_tmpInputFieldType = AccessTools.TypeByName("TMPro.TMP_InputField");
			}
			if (_tmpInputFieldType == null)
			{
				return false;
			}
			return (Object)(object)go.GetComponent(_tmpInputFieldType) != (Object)null;
		}

		private static bool IsQuantumConsoleActive(ManualLogSource debugLog)
		{
			try
			{
				if (!_qcLookupDone)
				{
					_qcLookupDone = true;
					_qcType = AccessTools.TypeByName("QFSW.QC.QuantumConsole");
					if (_qcType != null)
					{
						_qcInstanceProp = AccessTools.Property(_qcType, "Instance");
						_qcIsActiveProp = AccessTools.Property(_qcType, "IsActive");
						_qcIsActiveField = AccessTools.Field(_qcType, "isActive") ?? AccessTools.Field(_qcType, "_isActive");
					}
				}
				if (_qcType == null)
				{
					return false;
				}
				object obj = _qcInstanceProp?.GetValue(null);
				if (obj == null)
				{
					return false;
				}
				if (_qcIsActiveProp != null && _qcIsActiveProp.PropertyType == typeof(bool))
				{
					return (bool)_qcIsActiveProp.GetValue(obj);
				}
				if (_qcIsActiveField != null && _qcIsActiveField.FieldType == typeof(bool))
				{
					return (bool)_qcIsActiveField.GetValue(obj);
				}
			}
			catch (Exception ex)
			{
				if (debugLog != null)
				{
					debugLog.LogDebug((object)("[TextInputFocusGuard] Quantum Console focus check failed: " + ex.Message));
				}
			}
			return false;
		}
	}
	internal static class MinimalJsonParser
	{
		internal static void WriteJsonString(StringBuilder sb, string value)
		{
			sb.Append('"');
			if (value != null)
			{
				foreach (char c in value)
				{
					switch (c)
					{
					case '"':
						sb.Append("\\\"");
						break;
					case '\\':
						sb.Append("\\\\");
						break;
					case '\n':
						sb.Append("\\n");
						break;
					case '\r':
						sb.Append("\\r");
						break;
					case '\t':
						sb.Append("\\t");
						break;
					case '\b':
						sb.Append("\\b");
						break;
					case '\f':
						sb.Append("\\f");
						break;
					default:
						sb.Append(c);
						break;
					}
				}
			}
			sb.Append('"');
		}

		internal static void SkipWhitespace(string json, ref int pos)
		{
			while (pos < json.Length && char.IsWhiteSpace(json[pos]))
			{
				pos++;
			}
		}

		internal static object ParseValue(string json, ref int pos)
		{
			SkipWhitespace(json, ref pos);
			if (pos >= json.Length)
			{
				return null;
			}
			char c = json[pos];
			switch (c)
			{
			case '"':
				return ParseString(json, ref pos);
			case '{':
				return ParseObject(json, ref pos);
			case '[':
				return ParseArray(json, ref pos);
			case 't':
				return ParseLiteral(json, ref pos, "true", true);
			case 'f':
				return ParseLiteral(json, ref pos, "false", false);
			case 'n':
				return ParseLiteral(json, ref pos, "null", null);
			default:
				if (!char.IsDigit(c))
				{
					return null;
				}
				goto case '-';
			case '-':
				return ParseNumber(json, ref pos);
			}
		}

		internal static Dictionary<string, object> ParseObject(string json, ref int pos)
		{
			SkipWhitespace(json, ref pos);
			if (pos >= json.Length || json[pos] != '{')
			{
				return null;
			}
			pos++;
			Dictionary<string, object> dictionary = new Dictionary<string, object>();
			SkipWhitespace(json, ref pos);
			if (pos < json.Length && json[pos] == '}')
			{
				pos++;
				return dictionary;
			}
			while (pos < json.Length)
			{
				SkipWhitespace(json, ref pos);
				string text = ParseString(json, ref pos);
				if (text == null)
				{
					break;
				}
				SkipWhitespace(json, ref pos);
				if (pos >= json.Length || json[pos] != ':')
				{
					break;
				}
				pos++;
				SkipWhitespace(json, ref pos);
				dictionary[text] = ParseValue(json, ref pos);
				SkipWhitespace(json, ref pos);
				if (pos >= json.Length || json[pos] != ',')
				{
					break;
				}
				pos++;
			}
			SkipWhitespace(json, ref pos);
			if (pos < json.Length && json[pos] == '}')
			{
				pos++;
			}
			return dictionary;
		}

		internal static List<object> ParseArray(string json, ref int pos)
		{
			SkipWhitespace(json, ref pos);
			if (pos >= json.Length || json[pos] != '[')
			{
				return null;
			}
			pos++;
			List<object> list = new List<object>();
			SkipWhitespace(json, ref pos);
			if (pos < json.Length && json[pos] == ']')
			{
				pos++;
				return list;
			}
			while (pos < json.Length)
			{
				SkipWhitespace(json, ref pos);
				list.Add(ParseValue(json, ref pos));
				SkipWhitespace(json, ref pos);
				if (pos >= json.Length || json[pos] != ',')
				{
					break;
				}
				pos++;
			}
			SkipWhitespace(json, ref pos);
			if (pos < json.Length && json[pos] == ']')
			{
				pos++;
			}
			return list;
		}

		internal static string ParseString(string json, ref int pos)
		{
			SkipWhitespace(json, ref pos);
			if (pos >= json.Length || json[pos] != '"')
			{
				return null;
			}
			pos++;
			StringBuilder stringBuilder = new StringBuilder();
			while (pos < json.Length)
			{
				char c = json[pos];
				if (c == '\\' && pos + 1 < json.Length)
				{
					pos++;
					switch (json[pos])
					{
					case '"':
						stringBuilder.Append('"');
						break;
					case '\\':
						stringBuilder.Append('\\');
						break;
					case '/':
						stringBuilder.Append('/');
						break;
					case 'n':
						stringBuilder.Append('\n');
						break;
					case 'r':
						stringBuilder.Append('\r');
						break;
					case 't':
						stringBuilder.Append('\t');
						break;
					case 'b':
						stringBuilder.Append('\b');
						break;
					case 'f':
						stringBuilder.Append('\f');
						break;
					case 'u':
					{
						if (pos + 4 < json.Length && ushort.TryParse(json.Substring(pos + 1, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result))
						{
							pos += 4;
							if (result >= 55296 && result <= 56319 && pos + 5 < json.Length && json[pos] == '\\' && json[pos + 1] == 'u' && ushort.TryParse(json.Substring(pos + 2, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result2) && result2 >= 56320 && result2 <= 57343)
							{
								stringBuilder.Append(char.ConvertFromUtf32(char.ConvertToUtf32((char)result, (char)result2)));
								pos += 6;
							}
							else
							{
								stringBuilder.Append((char)result);
							}
						}
						else
						{
							stringBuilder.Append('u');
						}
						break;
					}
					default:
						stringBuilder.Append(json[pos]);
						break;
					}
					pos++;
				}
				else
				{
					if (c == '"')
					{
						pos++;
						return stringBuilder.ToString();
					}
					stringBuilder.Append(c);
					pos++;
				}
			}
			return stringBuilder.ToString();
		}

		internal static object ParseNumber(string json, ref int pos)
		{
			int num = pos;
			bool flag = false;
			if (pos < json.Length && json[pos] == '-')
			{
				pos++;
			}
			while (pos < json.Length && char.IsDigit(json[pos]))
			{
				pos++;
			}
			if (pos < json.Length && json[pos] == '.')
			{
				flag = true;
				pos++;
				while (pos < json.Length && char.IsDigit(json[pos]))
				{
					pos++;
				}
			}
			if (pos < json.Length && (json[pos] == 'e' || json[pos] == 'E'))
			{
				flag = true;
				pos++;
				if (pos < json.Length && (json[pos] == '+' || json[pos] == '-'))
				{
					pos++;
				}
				while (pos < json.Length && char.IsDigit(json[pos]))
				{
					pos++;
				}
			}
			string s = json.Substring(num, pos - num);
			if (flag && double.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				return result;
			}
			if (!flag && long.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2))
			{
				return result2;
			}
			return 0L;
		}

		internal static object ParseLiteral(string json, ref int pos, string literal, object result)
		{
			if (pos + literal.Length <= json.Length && json.Substring(pos, literal.Length) == literal)
			{
				pos += literal.Length;
				return result;
			}
			pos++;
			return null;
		}

		internal static int ToInt(object val)
		{
			if (val is long num)
			{
				return (int)num;
			}
			if (val is double num2)
			{
				return (int)num2;
			}
			if (val is int)
			{
				return (int)val;
			}
			return 0;
		}
	}
}
namespace SunhavenTodo
{
	[BepInPlugin("com.azraelgodking.sunhaventodo", "Sunhaven Todo", "1.4.2")]
	public class Plugin : BaseUnityPlugin
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static UnityAction <0>__OnNewDay;
		}

		private static TodoManager _staticTodoManager;

		private static TodoSaveSystem _staticSaveSystem;

		private static TodoUI _staticTodoUI;

		private static TodoHUD _staticTodoHUD;

		private static GameObject _persistentRunner;

		private static PersistentRunner _persistentRunnerComponent;

		private static KeyCode _staticToggleKey = (KeyCode)116;

		private static bool _staticRequireCtrl = true;

		private static bool _staticAutoSave = true;

		private static float _staticAutoSaveInterval = 60f;

		private static bool _staticHUDEnabled = true;

		private static float _staticHUDPositionX = -1f;

		private static float _staticHUDPositionY = -1f;

		private static KeyCode _staticHUDToggleKey = (KeyCode)104;

		private static float _staticUIScale = 1f;

		private ConfigEntry<KeyCode> _toggleKey;

		private ConfigEntry<bool> _requireCtrl;

		private ConfigEntry<bool> _autoSave;

		private ConfigEntry<float> _autoSaveInterval;

		private ConfigEntry<bool> _hudEnabled;

		private ConfigEntry<float> _hudPositionX;

		private ConfigEntry<float> _hudPositionY;

		private ConfigEntry<KeyCode> _hudToggleKey;

		private ConfigEntry<bool> _checkForUpdates;

		private ConfigEntry<float> _uiScale;

		private TodoManager _todoManager;

		private TodoSaveSystem _saveSystem;

		private TodoUI _todoUI;

		private TodoHUD _todoHUD;

		private Harmony _harmony;

		private static float _lastAutoSaveTime;

		private bool _isDataLoaded;

		private string _loadedCharacterName;

		private bool _wasInMenuScene = true;

		private static bool _applicationQuitting;

		private static bool _overnightHooked;

		private static UnityAction _overnightCallback;

		public static Plugin Instance { get; private set; }

		public static ManualLogSource Log { get; private set; }

		public static ConfigFile ConfigFile { get; private set; }

		public static KeyCode StaticToggleKey => _staticToggleKey;

		public static bool StaticRequireCtrl => _staticRequireCtrl;

		public static KeyCode StaticHUDToggleKey => _staticHUDToggleKey;

		public static bool StaticHUDEnabled => _staticHUDEnabled;

		public static string GetOpenListShortcutDisplay()
		{
			//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)
			KeyCode staticToggleKey = StaticToggleKey;
			string text = ((object)(KeyCode)(ref staticToggleKey)).ToString();
			if (!StaticRequireCtrl)
			{
				return text;
			}
			return "Ctrl+" + text;
		}

		private void Awake()
		{
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			ConfigFile = CreateNamedConfig();
			ConfigFileHelper.ReplacePluginConfig((BaseUnityPlugin)(object)this, ConfigFile, (Action<string>)Log.LogWarning);
			Log.LogInfo((object)"Loading Sunhaven Todo v1.4.2");
			IconCache.Initialize(Log);
			BindConfiguration();
			CreatePersistentRunner();
			InitializeManagers();
			ApplyPatches();
			SceneManager.sceneLoaded += OnSceneLoaded;
			if (_checkForUpdates.Value)
			{
				VersionChecker.CheckForUpdate("com.azraelgodking.sunhaventodo", "1.4.2", Log, delegate(VersionChecker.VersionCheckResult result)
				{
					result.NotifyUpdateAvailable(Log);
				});
			}
			Log.LogInfo((object)"Sunhaven Todo loaded successfully!");
		}

		private void BindConfiguration()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: Expected O, but got Unknown
			_toggleKey = ConfigFile.Bind<KeyCode>("Hotkeys", "ToggleKey", (KeyCode)116, "Key to toggle the Todo List window");
			_staticToggleKey = _toggleKey.Value;
			_toggleKey.SettingChanged += delegate
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				_staticToggleKey = _toggleKey.Value;
			};
			_requireCtrl = ConfigFile.Bind<bool>("Hotkeys", "RequireCtrl", true, "Require Ctrl to be held when pressing the toggle key");
			_staticRequireCtrl = _requireCtrl.Value;
			_requireCtrl.SettingChanged += delegate
			{
				_staticRequireCtrl = _requireCtrl.Value;
			};
			_autoSave = ConfigFile.Bind<bool>("Saving", "AutoSave", true, "Automatically save the todo list periodically");
			_staticAutoSave = _autoSave.Value;
			_autoSave.SettingChanged += delegate
			{
				_staticAutoSave = _autoSave.Value;
			};
			_autoSaveInterval = ConfigFile.Bind<float>("Saving", "AutoSaveInterval", 60f, "Auto-save interval in seconds");
			_staticAutoSaveInterval = _autoSaveInterval.Value;
			_autoSaveInterval.SettingChanged += delegate
			{
				_staticAutoSaveInterval = _autoSaveInterval.Value;
			};
			_hudEnabled = ConfigFile.Bind<bool>("HUD", "Enabled", true, "Show the movable HUD panel with top 5 urgent tasks");
			_staticHUDEnabled = _hudEnabled.Value;
			_hudEnabled.SettingChanged += delegate
			{
				_staticHUDEnabled = _hudEnabled.Value;
				_staticTodoHUD?.SetEnabled(_staticHUDEnabled);
			};
			_hudPositionX = ConfigFile.Bind<float>("HUD", "PositionX", -1f, "HUD X position (-1 for default)");
			_staticHUDPositionX = _hudPositionX.Value;
			_hudPositionY = ConfigFile.Bind<float>("HUD", "PositionY", -1f, "HUD Y position (-1 for default)");
			_staticHUDPositionY = _hudPositionY.Value;
			_hudToggleKey = ConfigFile.Bind<KeyCode>("Hotkeys", "HUDToggleKey", (KeyCode)104, "Key to toggle the HUD panel (with Ctrl if RequireCtrl is enabled)");
			_staticHUDToggleKey = _hudToggleKey.Value;
			_hudToggleKey.SettingChanged += delegate
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				_staticHUDToggleKey = _hudToggleKey.Value;
			};
			_checkForUpdates = ConfigFile.Bind<bool>("Updates", "CheckForUpdates", true, "Check for mod updates on startup");
			_uiScale = ConfigFile.Bind<float>("Display", "UIScale", 1f, new ConfigDescription("Scale factor for the Todo list and HUD (1.0 = default, 1.5 = 50% larger)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 2.5f), Array.Empty<object>()));
			_staticUIScale = Mathf.Clamp(_uiScale.Value, 0.5f, 2.5f);
			_uiScale.SettingChanged += delegate
			{
				_staticUIScale = Mathf.Clamp(_uiScale.Value, 0.5f, 2.5f);
				_staticTodoUI?.SetScale(_staticUIScale);
				_staticTodoHUD?.SetScale(_staticUIScale);
			};
		}

		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, "SunhavenTodo.cfg");
			string text2 = Path.Combine(Paths.ConfigPath, "com.azraelgodking.sunhaventodo.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 SunhavenTodo.cfg failed: " + ex.Message));
				}
			}
			return new ConfigFile(text, true);
		}

		private void CreatePersistentRunner()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			if (!((Object)(object)_persistentRunner != (Object)null) || !((Object)(object)_persistentRunnerComponent != (Object)null))
			{
				_persistentRunner = new GameObject("SunhavenTodo_PersistentRunner");
				Object.DontDestroyOnLoad((Object)(object)_persistentRunner);
				((Object)_persistentRunner).hideFlags = (HideFlags)61;
				SceneRootSurvivor.TryRegisterPersistentRunnerGameObject(_persistentRunner);
				_persistentRunnerComponent = _persistentRunner.AddComponent<PersistentRunner>();
				Log.LogInfo((object)"[PersistentRunner] Created");
			}
		}

		private void InitializeManagers()
		{
			_todoManager = new TodoManager();
			_staticTodoManager = _todoManager;
			_saveSystem = new TodoSaveSystem(_todoManager);
			_staticSaveSystem = _saveSystem;
			_todoManager.OnTodosChanged += OnTodosChanged;
		}

		private void ApplyPatches()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			_harmony = new Harmony("com.azraelgodking.sunhaventodo");
			try
			{
				Type type = AccessTools.TypeByName("Wish.Player");
				if (type != null)
				{
					MethodInfo methodInfo = AccessTools.Method(type, "InitializeAsOwner", (Type[])null, (Type[])null);
					if (methodInfo != null)
					{
						MethodInfo methodInfo2 = AccessTools.Method(typeof(PlayerPatches), "OnPlayerInitialized", (Type[])null, (Type[])null);
						_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						Log.LogInfo((object)"Applied player initialization patch");
					}
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Failed to apply patches: " + ex.Message));
			}
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			if (((Scene)(ref scene)).name == "MainMenu" || ((Scene)(ref scene)).name == "Bootstrap")
			{
				_overnightHooked = false;
				_overnightCallback = null;
				if (!_wasInMenuScene)
				{
					SaveData();
					PlayerPatches.ResetForMenu();
				}
				_wasInMenuScene = true;
			}
			else
			{
				_wasInMenuScene = false;
				EnsureUIComponentsExist();
			}
		}

		public static void EnsureUIComponentsExist()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Expected O, but got Unknown
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Expected O, but got Unknown
			try
			{
				if ((Object)(object)_persistentRunner == (Object)null || (Object)(object)_persistentRunnerComponent == (Object)null)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogInfo((object)"[EnsureUI] Recreating PersistentRunner...");
					}
					_persistentRunner = new GameObject("SunhavenTodo_PersistentRunner");
					Object.DontDestroyOnLoad((Object)(object)_persistentRunner);
					((Object)_persistentRunner).hideFlags = (HideFlags)61;
					SceneRootSurvivor.TryRegisterPersistentRunnerGameObject(_persistentRunner);
					_persistentRunnerComponent = _persistentRunner.AddComponent<PersistentRunner>();
					ManualLogSource log2 = Log;
					if (log2 != null)
					{
						log2.LogInfo((object)"[EnsureUI] PersistentRunner recreated");
					}
				}
				if ((Object)(object)_staticTodoUI == (Object)null)
				{
					ManualLogSource log3 = Log;
					if (log3 != null)
					{
						log3.LogInfo((object)"[EnsureUI] Recreating TodoUI...");
					}
					GameObject val = new GameObject("SunhavenTodo_UI");
					Object.DontDestroyOnLoad((Object)val);
					_staticTodoUI = val.AddComponent<TodoUI>();
					_staticTodoUI.Initialize(_staticTodoManager);
					_staticTodoUI.SetScale(_staticUIScale);
					ManualLogSource log4 = Log;
					if (log4 != null)
					{
						log4.LogInfo((object)"[EnsureUI] TodoUI recreated");
					}
				}
				if ((Object)(object)_staticTodoHUD == (Object)null)
				{
					ManualLogSource log5 = Log;
					if (log5 != null)
					{
						log5.LogInfo((object)"[EnsureUI] Recreating TodoHUD...");
					}
					GameObject val2 = new GameObject("SunhavenTodo_HUD");
					Object.DontDestroyOnLoad((Object)val2);
					_staticTodoHUD = val2.AddComponent<TodoHUD>();
					_staticTodoHUD.Initialize(_staticTodoManager);
					_staticTodoHUD.SetScale(_staticUIScale);
					_staticTodoHUD.SetEnabled(_staticHUDEnabled);
					if (_staticHUDPositionX >= 0f && _staticHUDPositionY >= 0f)
					{
						_staticTodoHUD.SetPosition(_staticHUDPositionX, _staticHUDPositionY);
					}
					_staticTodoHUD.OnPositionChanged = delegate(float x, float y)
					{
						_staticHUDPositionX = x;
						_staticHUDPositionY = y;
						Plugin instance = Instance;
						if (instance != null)
						{
							ConfigEntry<float> hudPositionX = instance._hudPositionX;
							if (hudPositionX != null)
							{
								((ConfigEntryBase)hudPositionX).SetSerializedValue(x.ToString());
							}
						}
						Plugin instance2 = Instance;
						if (instance2 != null)
						{
							ConfigEntry<float> hudPositionY = instance2._hudPositionY;
							if (hudPositionY != null)
							{
								((ConfigEntryBase)hudPositionY).SetSerializedValue(y.ToString());
							}
						}
					};
					ManualLogSource log6 = Log;
					if (log6 != null)
					{
						log6.LogInfo((object)"[EnsureUI] TodoHUD recreated");
					}
				}
				if ((Object)(object)Instance != (Object)null)
				{
					Instance._todoUI = _staticTodoUI;
					Instance._todoHUD = _staticTodoHUD;
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log7 = Log;
				if (log7 != null)
				{
					log7.LogError((object)("[EnsureUI] Error: " + ex.Message));
				}
			}
		}

		private void OnTodosChanged()
		{
			_lastAutoSaveTime = Time.unscaledTime - _staticAutoSaveInterval + 5f;
		}

		public void LoadDataForCharacter(string characterName)
		{
			if (string.IsNullOrEmpty(characterName))
			{
				Log.LogWarning((object)"Cannot load data: No character name");
				return;
			}
			if (_isDataLoaded && _loadedCharacterName != characterName)
			{
				SaveData();
			}
			TodoListData data = _staticSaveSystem.Load(characterName);
			_staticTodoManager.LoadForCharacter(characterName, data);
			_isDataLoaded = true;
			_loadedCharacterName = characterName;
			Log.LogInfo((object)("Loaded todo list for character: " + characterName));
			TryHookOvernight();
		}

		public static void SaveData()
		{
			if (_staticTodoManager != null && _staticTodoManager.IsDirty)
			{
				_staticSaveSystem?.Save();
			}
		}

		public static void TryHookOvernight()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			object obj = <>O.<0>__OnNewDay;
			if (obj == null)
			{
				UnityAction val = OnNewDay;
				<>O.<0>__OnNewDay = val;
				obj = (object)val;
			}
			OvernightHookUtility.TryHookOvernightEvent(ref _overnightHooked, ref _overnightCallback, (UnityAction)obj, delegate(Type type)
			{
				try
				{
					Type type2 = AccessTools.TypeByName("Wish.SingletonBehaviour`1");
					if (type2 != null)
					{
						return type2.MakeGenericType(type).GetProperty("Instance")?.GetValue(null);
					}
				}
				catch (Exception)
				{
				}
				return null;
			}, delegate(string msg)
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogInfo((object)msg);
				}
			}, delegate(string msg)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)msg);
				}
			});
		}

		private static void OnNewDay()
		{
			if (_staticTodoManager == null)
			{
				return;
			}
			_staticTodoManager.ResetRecurringTodos(RecurInterval.Daily);
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogInfo((object)"[Todo] Reset daily recurring tasks.");
			}
			try
			{
				Type type = AccessTools.TypeByName("Wish.DayCycle");
				if (type != null)
				{
					PropertyInfo propertyInfo = AccessTools.Property(type, "MonthDay");
					int num = ((propertyInfo != null) ? ((int)propertyInfo.GetValue(null)) : 0);
					if (num > 0)
					{
						if ((num - 1) % 7 == 0)
						{
							_staticTodoManager.ResetRecurringTodos(RecurInterval.Weekly);
							ManualLogSource log2 = Log;
							if (log2 != null)
							{
								log2.LogInfo((object)"[Todo] Reset weekly recurring tasks.");
							}
						}
						if (num == 1)
						{
							_staticTodoManager.ResetRecurringTodos(RecurInterval.Seasonal);
							ManualLogSource log3 = Log;
							if (log3 != null)
							{
								log3.LogInfo((object)"[Todo] Reset seasonal recurring tasks.");
							}
						}
					}
				}
			}
			catch (Exception)
			{
			}
			SaveData();
		}

		public static void ToggleUI()
		{
			EnsureUIComponentsExist();
			_staticTodoUI?.Toggle();
		}

		public static void ShowUI()
		{
			EnsureUIComponentsExist();
			_staticTodoUI?.Show();
		}

		public static void HideUI()
		{
			_staticTodoUI?.Hide();
		}

		public static TodoManager GetTodoManager()
		{
			return _staticTodoManager;
		}

		public static TodoUI GetTodoUI()
		{
			return _staticTodoUI;
		}

		public static TodoHUD GetTodoHUD()
		{
			return _staticTodoHUD;
		}

		public static void ToggleHUD()
		{
			EnsureUIComponentsExist();
			_staticTodoHUD?.Toggle();
		}

		internal static void TickAutoSave()
		{
			if (_staticAutoSave && _staticTodoManager != null && _staticTodoManager.IsDirty && !(Time.unscaledTime - _lastAutoSaveTime < _staticAutoSaveInterval))
			{
				SaveData();
				_lastAutoSaveTime = Time.unscaledTime;
			}
		}

		private void OnDestroy()
		{
			//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)
			SceneManager.sceneLoaded -= OnSceneLoaded;
			if (_todoManager != null)
			{
				_todoManager.OnTodosChanged -= OnTodosChanged;
			}
			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"))
			{
				Log.LogInfo((object)("Plugin OnDestroy during expected teardown (scene: " + text + ")"));
			}
			else
			{
				Log.LogWarning((object)("[CRITICAL] Plugin OnDestroy outside expected teardown (scene: " + text + ")"));
			}
			SaveData();
		}

		private void OnApplicationQuit()
		{
			_applicationQuitting = true;
			SaveData();
		}
	}
	public class PersistentRunner : MonoBehaviour
	{
		private void Update()
		{
			CheckHotkeys();
			Plugin.TickAutoSave();
		}

		private void CheckHotkeys()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			TodoUI todoUI = Plugin.GetTodoUI();
			if ((!((Object)(object)todoUI != (Object)null) || !todoUI.IsVisible) && !TextInputFocusGuard.ShouldDeferModHotkeys(Plugin.Log))
			{
				bool flag = Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305);
				bool keyDown = Input.GetKeyDown(Plugin.StaticToggleKey);
				bool keyDown2 = Input.GetKeyDown(Plugin.StaticHUDToggleKey);
				if (keyDown && flag == Plugin.StaticRequireCtrl)
				{
					Plugin.ToggleUI();
				}
				if (keyDown2 && flag == Plugin.StaticRequireCtrl)
				{
					Plugin.ToggleHUD();
				}
			}
		}

		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).ToLowerInvariant();
			if (!Application.isPlaying || text.Contains("menu") || text.Contains("title"))
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)"[PersistentRunner] OnDestroy during app quit/menu unload (expected).");
				}
			}
			else
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)"[PersistentRunner] OnDestroy outside quit/menu (unexpected).");
				}
			}
		}
	}
	public static class PlayerPatches
	{
		private static bool _isDataLoaded;

		private static string _loadedCharacterName;

		public static void OnPlayerInitialized(object __instance)
		{
			try
			{
				Plugin.EnsureUIComponentsExist();
				string currentCharacterName = GetCurrentCharacterName(__instance);
				if (_isDataLoaded && _loadedCharacterName != currentCharacterName)
				{
					Plugin.SaveData();
					ResetState();
				}
				if (!string.IsNullOrEmpty(currentCharacterName))
				{
					Plugin.Instance?.LoadDataForCharacter(currentCharacterName);
					_isDataLoaded = true;
					_loadedCharacterName = currentCharacterName;
					return;
				}
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"Skipping todo load because character name is unavailable.");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogError((object)("Error in OnPlayerInitialized: " + ex.Message));
				}
			}
		}

		private static string GetCurrentCharacterName(object player)
		{
			try
			{
				Type type = AccessTools.TypeByName("Wish.GameSave");
				if (type != null)
				{
					PropertyInfo propertyInfo = AccessTools.Property(type, "CurrentCharacter");
					if (propertyInfo != null)
					{
						object value = propertyInfo.GetValue(null);
						if (value != null)
						{
							PropertyInfo propertyInfo2 = AccessTools.Property(value.GetType(), "characterName");
							if (propertyInfo2 != null)
							{
								string text = propertyInfo2.GetValue(value) as string;
								if (!string.IsNullOrEmpty(text))
								{
									return text;
								}
							}
						}
					}
					object obj = AccessTools.Property(type, "Instance")?.GetValue(null);
					if (obj != null)
					{
						object obj2 = AccessTools.Property(type, "CurrentSave")?.GetValue(obj);
						if (obj2 != null)
						{
							object obj3 = AccessTools.Property(obj2.GetType(), "characterData")?.GetValue(obj2);
							if (obj3 != null)
							{
								string text2 = AccessTools.Property(obj3.GetType(), "characterName")?.GetValue(obj3) as string;
								if (!string.IsNullOrEmpty(text2))
								{
									return text2;
								}
							}
						}
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("Failed to get character name: " + ex.Message));
				}
			}
			if (!string.IsNullOrEmpty(_loadedCharacterName))
			{
				return _loadedCharacterName;
			}
			return null;
		}

		private static void ResetState()
		{
			_isDataLoaded = false;
			_loadedCharacterName = null;
		}

		internal static void ResetForMenu()
		{
			ResetState();
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "com.azraelgodking.sunhaventodo";

		public const string PLUGIN_NAME = "Sunhaven Todo";

		public const string PLUGIN_VERSION = "1.4.2";
	}
}
namespace SunhavenTodo.UI
{
	public class TodoHUD : MonoBehaviour
	{
		private const int WINDOW_ID = 98766;

		private const float BASE_WINDOW_WIDTH = 280f;

		private const float BASE_MIN_HEIGHT = 100f;

		private const float BASE_MAX_HEIGHT = 300f;

		private const float BASE_HEADER_HEIGHT = 28f;

		private const float BASE_ITEM_HEIGHT = 24f;

		private const float BASE_ICON_SIZE = 16f;

		private const int MAX_ITEMS = 5;

		private float _scale = 1f;

		private TodoManager _manager;

		private bool _isEnabled = true;

		private Rect _windowRect;

		public Action<float, float> OnPositionChanged;

		private List<TodoItem> _cachedItems = new List<TodoItem>();

		private float _lastUpdateTime;

		private const float UPDATE_INTERVAL = 1f;

		private readonly Color _parchmentLight = new Color(0.96f, 0.93f, 0.86f, 0.95f);

		private readonly Color _parchment = new Color(0.92f, 0.87f, 0.78f, 0.95f);

		private readonly Color _parchmentDark = new Color(0.85f, 0.78f, 0.65f, 0.95f);

		private readonly Color _woodDark = new Color(0.35f, 0.25f, 0.15f);

		private readonly Color _woodMedium = new Color(0.5f, 0.38f, 0.25f);

		private readonly Color _goldRich = new Color(0.85f, 0.68f, 0.2f);

		private readonly Color _goldBright = new Color(0.95f, 0.8f, 0.3f);

		private readonly Color _textDark = new Color(0.25f, 0.2f, 0.15f);

		private readonly Color _borderDark = new Color(0.4f, 0.3f, 0.2f, 0.8f);

		private readonly Dictionary<TodoPriority, Color> _priorityColors = new Dictionary<TodoPriority, Color>
		{
			{
				TodoPriority.Low,
				new Color(0.5f, 0.6f, 0.7f)
			},
			{
				TodoPriority.Normal,
				new Color(0.45f, 0.55f, 0.45f)
			},
			{
				TodoPriority.High,
				new Color(0.85f, 0.65f, 0.25f)
			},
			{
				TodoPriority.Urgent,
				new Color(0.8f, 0.3f, 0.25f)
			}
		};

		private readonly Dictionary<TodoCategory, Color> _categoryColors = new Dictionary<TodoCategory, Color>
		{
			{
				TodoCategory.General,
				new Color(0.55f, 0.5f, 0.45f)
			},
			{
				TodoCategory.Farming,
				new Color(0.45f, 0.65f, 0.35f)
			},
			{
				TodoCategory.Mining,
				new Color(0.5f, 0.45f, 0.55f)
			},
			{
				TodoCategory.Fishing,
				new Color(0.4f, 0.6f, 0.75f)
			},
			{
				TodoCategory.Combat,
				new Color(0.75f, 0.35f, 0.35f)
			},
			{
				TodoCategory.Crafting,
				new Color(0.65f, 0.55f, 0.4f)
			},
			{
				TodoCategory.Social,
				new Color(0.7f, 0.5f, 0.6f)
			},
			{
				TodoCategory.Quests,
				new Color(0.8f, 0.7f, 0.3f)
			},
			{
				TodoCategory.Collection,
				new Color(0.55f, 0.7f, 0.65f)
			}
		};

		private bool _stylesInitialized;

		private GUIStyle _windowStyle;

		private GUIStyle _headerStyle;

		private GUIStyle _itemStyle;

		private GUIStyle _priorityStyle;

		private GUIStyle _categoryStyle;

		private GUIStyle _titleStyle;

		private GUIStyle _emptyStyle;

		private Texture2D _windowBackground;

		private Texture2D _headerBackground;

		private Texture2D _itemEven;

		private Texture2D _itemOdd;

		private float WindowWidth => 280f * _scale;

		private float MinHeight => 100f * _scale;

		private float MaxHeight => 300f * _scale;

		private float HeaderHeight => 28f * _scale;

		private float ItemHeight => 24f * _scale;

		private float IconSize => 16f * _scale;

		public bool IsEnabled => _isEnabled;

		private int ScaledFont(int baseSize)
		{
			return Mathf.Max(8, Mathf.RoundToInt((float)baseSize * _scale));
		}

		private float Scaled(float value)
		{
			return value * _scale;
		}

		private int ScaledInt(float value)
		{
			return Mathf.RoundToInt(value * _scale);
		}

		public void Initialize(TodoManager manager)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			_manager = manager;
			_windowRect = new Rect((float)Screen.width - WindowWidth - Scaled(20f), Scaled(100f), WindowWidth, MinHeight);
			if (_manager != null)
			{
				_manager.OnTodosChanged += RefreshCache;
				_manager.OnDataLoaded += RefreshCache;
			}
		}

		public void SetPosition(float x, float y)
		{
			((Rect)(ref _windowRect)).x = Mathf.Clamp(x, 0f, (float)Screen.width - ((Rect)(ref _windowRect)).width);
			((Rect)(ref _windowRect)).y = Mathf.Clamp(y, 0f, (float)Screen.height - ((Rect)(ref _windowRect)).height);
		}

		public (float x, float y) GetPosition()
		{
			return (((Rect)(ref _windowRect)).x, ((Rect)(ref _windowRect)).y);
		}

		public void SetEnabled(bool enabled)
		{
			_isEnabled = enabled;
		}

		public void SetScale(float scale)
		{
			_scale = Mathf.Clamp(scale, 0.5f, 2.5f);
			_stylesInitialized = false;
		}

		public void Toggle()
		{
			_isEnabled = !_isEnabled;
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)("TodoHUD toggled: " + (_isEnabled ? "ON" : "OFF")));
			}
		}

		private void Update()
		{
			if (_isEnabled && _manager != null && Time.unscaledTime - _lastUpdateTime > 1f)
			{
				RefreshCache();
				_lastUpdateTime = Time.unscaledTime;
			}
		}

		private void RefreshCache()
		{
			if (_manager != null)
			{
				_cachedItems = (from t in _manager.GetActiveTodos()
					orderby (int)t.Priority descending, t.CreatedAt descending
					select t).Take(5).ToList();
			}
		}

		private void OnGUI()
		{
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Expected O, but got Unknown
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			if (!_isEnabled || _manager == null)
			{
				return;
			}
			TodoUI todoUI = Plugin.GetTodoUI();
			if (((Object)(object)todoUI != (Object)null && todoUI.IsVisible) || string.IsNullOrEmpty(_manager.CurrentCharacter))
			{
				return;
			}
			InitializeStyles();
			float num = HeaderHeight + Scaled(8f);
			if (_cachedItems.Count == 0)
			{
				num += Scaled(40f);
			}
			else
			{
				for (int i = 0; i < _cachedItems.Count; i++)
				{
					num += GetItemRowHeight(_cachedItems[i]);
				}
				num += Scaled(4f);
			}
			((Rect)(ref _windowRect)).width = WindowWidth;
			((Rect)(ref _windowRect)).height = Mathf.Clamp(num, MinHeight, MaxHeight);
			Rect windowRect = _windowRect;
			GUI.depth = -500;
			_windowRect = GUI.Window(98766, _windowRect, new WindowFunction(DrawWindow), "", _windowStyle);
			((Rect)(ref _windowRect)).x = Mathf.Clamp(((Rect)(ref _windowRect)).x, 0f, (float)Screen.width - ((Rect)(ref _windowRect)).width);
			((Rect)(ref _windowRect)).y = Mathf.Clamp(((Rect)(ref _windowRect)).y, 0f, (float)Screen.height - ((Rect)(ref _windowRect)).height);
			if (Math.Abs(((Rect)(ref _windowRect)).x - ((Rect)(ref windowRect)).x) > 0.1f || Math.Abs(((Rect)(ref _windowRect)).y - ((Rect)(ref windowRect)).y) > 0.1f)
			{
				OnPositionChanged?.Invoke(((Rect)(ref _windowRect)).x, ((Rect)(ref _windowRect)).y);
			}
		}

		private void DrawWindow(int windowId)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
			DrawHeader();
			DrawItems();
			GUILayout.EndVertical();
			GUI.DragWindow(new Rect(0f, 0f, ((Rect)(ref _windowRect)).width, HeaderHeight));
		}

		private void DrawHeader()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: 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_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Expected O, but got Unknown
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(0f, 0f, ((Rect)(ref _windowRect)).width, HeaderHeight);
			if ((Object)(object)_headerBackground != (Object)null)
			{
				GUI.DrawTexture(val, (Texture)(object)_headerBackground);
			}
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Space(Scaled(8f));
			int num = _manager?.GetActiveTodos().Count() ?? 0;
			GUILayout.Label($"Todo ({num})", _headerStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(HeaderHeight) });
			GUILayout.FlexibleSpace();
			GUIStyle val2 = new GUIStyle(_headerStyle)
			{
				fontSize = ScaledFont(9),
				fontStyle = (FontStyle)2
			};
			val2.normal.textColor = new Color(_textDark.r, _textDark.g, _textDark.b, 0.5f);
			GUIStyle val3 = val2;
			GUILayout.Label(Plugin.GetOpenListShortcutDisplay() + " to open", val3, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(HeaderHeight) });
			GUILayout.FlexibleSpace();
			GUILayout.Label("drag to move", val3, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(HeaderHeight) });
			GUILayout.Space(Scaled(8f));
			GUILayout.EndHorizontal();
		}

		private void DrawItems()
		{
			GUILayout.Space(Scaled(4f));
			if (_cachedItems.Count == 0)
			{
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUILayout.FlexibleSpace();
				GUILayout.Label("No active tasks", _emptyStyle, Array.Empty<GUILayoutOption>());
				GUILayout.FlexibleSpace();
				GUILayout.EndHorizontal();
			}
			else
			{
				for (int i = 0; i < _cachedItems.Count; i++)
				{
					DrawItem(_cachedItems[i], i);
				}
			}
			GUILayout.Space(Scaled(4f));
		}

		private void DrawItem(TodoItem item, int index)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: 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_0050: Expected O, but got Unknown
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Expected O, but got Unknown
			//IL_00ea: Expected O, but got Unknown
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: 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_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Expected O, but got Unknown
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Expected O, but got Unknown
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			Texture2D background = ((index % 2 == 0) ? _itemEven : _itemOdd);
			string text = (string.IsNullOrWhiteSpace(item.Title) ? "(No title)" : item.Title);
			GUIStyle val = new GUIStyle(_titleStyle)
			{
				wordWrap = true,
				clipping = (TextClipping)0,
				alignment = (TextAnchor)0
			};
			float titleAvailableWidth = GetTitleAvailableWidth(item);
			float num = Mathf.Ceil(val.CalcHeight(new GUIContent(text), titleAvailableWidth));
			float num2 = Mathf.Max(ItemHeight, num + Scaled(6f));
			GUIStyle val2 = new GUIStyle(_itemStyle);
			val2.normal.background = background;
			val2.padding = new RectOffset(ScaledInt(6f), ScaledInt(6f), ScaledInt(2f), ScaledInt(2f));
			GUILayout.BeginHorizontal(val2, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinHeight(num2) });
			GUILayout.Space(Scaled(6f));
			Color value;
			Color textColor = (_priorityColors.TryGetValue(item.Priority, out value) ? value : _textDark);
			GUIStyle val3 = new GUIStyle(_priorityStyle);
			val3.normal.textColor = textColor;
			GUIStyle val4 = val3;
			GUILayout.Label(GetPriorityIcon(item.Priority), val4, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(Scaled(16f)) });
			Color value2;
			Color textColor2 = (_categoryColors.TryGetValue(item.Category, out value2) ? value2 : _textDark);
			GUIStyle val5 = new GUIStyle(_categoryStyle);
			val5.normal.textColor = textColor2;
			GUIStyle val6 = val5;
			GUILayout.Label("[" + GetCategoryShort(item.Category) + "]", val6, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(Scaled(36f)) });
			GUILayout.Space(Scaled(4f));
			if (item.IconItemId > 0)
			{
				Texture2D icon = IconCache.GetIcon(item.IconItemId);
				if ((Object)(object)icon != (Object)null)
				{
					GUI.DrawTexture(GUILayoutUtility.GetRect(IconSize, IconSize, (GUILayoutOption[])(object)new GUILayoutOption[2]
					{
						GUILayout.Width(IconSize),
						GUILayout.Height(IconSize)
					}), (Texture)(object)icon, (ScaleMode)2);
				}
				else
				{
					GUILayout.Space(IconSize);
				}
				GUILayout.Space(Scaled(4f));
			}
			GUILayout.Label(text, val, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(titleAvailableWidth),
				GUILayout.MinHeight(num)
			});
			GUILayout.FlexibleSpace();
			GUILayout.Space(Scaled(6f));
			GUILayout.EndHorizontal();
		}

		private float GetItemRowHeight(TodoItem item)
		{
			//IL_002b: 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_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			if (item == null)
			{
				return ItemHeight;
			}
			string text = (string.IsNullOrWhiteSpace(item.Title) ? "(No title)" : item.Title);
			GUIStyle val = new GUIStyle(_titleStyle)
			{
				wordWrap = true,
				clipping = (TextClipping)0,
				alignment = (TextAnchor)0
			};
			float titleAvailableWidth = GetTitleAvailableWidth(item);
			float num = Mathf.Ceil(val.CalcHeight(new GUIContent(text), titleAvailableWidth));
			return Mathf.Max(ItemHeight, num + Scaled(6f));
		}

		private float GetTitleAvailableWidth(TodoItem item)
		{
			float num = Scaled(68f);
			if (item != null && item.IconItemId > 0)
			{
				num += IconSize + Scaled(4f);
			}
			return Mathf.Max(Scaled(100f), WindowWidth - num);
		}

		private string GetPriorityIcon(TodoPriority priority)
		{
			return priority switch
			{
				TodoPriority.Low => "-", 
				TodoPriority.Normal => "o", 
				TodoPriority.High => "!", 
				TodoPriority.Urgent => "!!", 
				_ => "o", 
			};
		}

		private string GetCategoryShort(TodoCategory category)
		{
			return category switch
			{
				TodoCategory.General => "GEN", 
				TodoCategory.Farming => "FRM", 
				TodoCategory.Mining => "MIN", 
				TodoCategory.Fishing => "FSH", 
				TodoCategory.Combat => "CMB", 
				TodoCategory.Crafting => "CRF", 
				TodoCategory.Social => "SOC", 
				TodoCategory.Quests => "QST", 
				TodoCategory.Collection => "COL", 
				_ => "GEN", 
			};
		}

		private void InitializeStyles()
		{
			if (!_stylesInitialized)
			{
				CreateTextures();
				CreateStyles();
				_stylesInitialized = true;
			}
		}

		private void CreateTextures()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			_windowBackground = MakeParchmentTexture(16, 64, _parchment, _parchmentLight, _borderDark, 2);
			_headerBackground = MakeGradientTex(8, Mathf.Max(1, ScaledInt(HeaderHeight)), _parchmentDark, _parchment);
			_itemEven = MakeTex(1, 1, new Color(_parchmentLight.r, _parchmentLight.g, _parchmentLight.b, 0.3f));
			_itemOdd = MakeTex(1, 1, new Color(_parchment.r, _parchment.g, _parchment.b, 0.3f));
		}

		private void CreateStyles()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: 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_005f: Expected O, but got Unknown
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			//IL_009b: Expected O, but got Unknown
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: 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_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: 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_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Expected O, but got Unknown
			//IL_010a: Expected O, but got Unknown
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: 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_012f: 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_0166: Expected O, but got Unknown
			//IL_016b: Expected O, but got Unknown
			//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)
			//IL_017f: 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_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Expected O, but got Unknown
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: 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_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Expected O, but got Unknown
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: 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_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Expected O, but got Unknown
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: 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_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_029e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Expected O, but got Unknown
			//IL_02ad: Expected O, but got Unknown
			GUIStyle val = new GUIStyle();
			val.normal.background = _windowBackground;
			val.normal.textColor = _textDark;
			val.padding = new RectOffset(ScaledInt(4f), ScaledInt(4f), ScaledInt(4f), ScaledInt(4f));
			val.border = new RectOffset(ScaledInt(4f), ScaledInt(4f), ScaledInt(4f), ScaledInt(4f));
			_windowStyle = val;
			GUIStyle val2 = new GUIStyle
			{
				fontSize = ScaledFont(13),
				fontStyle = (FontStyle)1
			};
			val2.normal.textColor = _woodDark;
			val2.alignment = (TextAnchor)3;
			val2.padding = new RectOffset(ScaledInt(2f), ScaledInt(2f), ScaledInt(2f), ScaledInt(2f));
			_headerStyle = val2;
			GUIStyle val3 = new GUIStyle
			{
				fontSize = ScaledFont(11)
			};
			val3.normal.textColor = _textDark;
			val3.padding = new RectOffset(ScaledInt(2f), ScaledInt(2f), ScaledInt(2f), ScaledInt(2f));
			_itemStyle = val3;
			GUIStyle val4 = new GUIStyle
			{
				fontSize = ScaledFont(11),
				fontStyle = (FontStyle)1,
				alignment = (TextAnchor)4
			};
			val4.normal.textColor = _textDark;
			_priorityStyle = val4;
			GUIStyle val5 = new GUIStyle
			{
				fontSize = ScaledFont(8),
				fontStyle = (FontStyle)1,
				alignment = (TextAnchor)3
			};
			val5.normal.textColor = _textDark;
			_categoryStyle = val5;
			GUIStyle val6 = new GUIStyle
			{
				fontSize = ScaledFont(11)
			};
			val6.normal.textColor = _textDark;
			val6.alignment = (TextAnchor)3;
			val6.clipping = (TextClipping)0;
			val6.wordWrap = true;
			_titleStyle = val6;
			GUIStyle val7 = new GUIStyle
			{
				fontSize = ScaledFont(11),
				fontStyle = (FontStyle)2
			};
			val7.normal.textColor = new Color(_textDark.r, _textDark.g, _textDark.b, 0.6f);
			val7.alignment = (TextAnchor)4;
			val7.padding = new RectOffset(ScaledInt(10f), ScaledI