Decompiled source of SenpaisChest v1.1.0

SenpaisChest.dll

Decompiled 13 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
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.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using SenpaisChest.Config;
using SenpaisChest.Data;
using SenpaisChest.Integration;
using SenpaisChest.UI;
using SunHavenMuseumUtilityTracker;
using SunHavenMuseumUtilityTracker.Data;
using SunhavenMods.Shared;
using SunhavenTodo;
using SunhavenTodo.Data;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
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("SenpaisChest")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+b72ac30fec0dbf108a60f7a3222b24b27660f6bf")]
[assembly: AssemblyProduct("SenpaisChest")]
[assembly: AssemblyTitle("SenpaisChest")]
[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.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 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; }
		}

		private class VersionCheckRunner : MonoBehaviour
		{
			public void StartCheck(string pluginGuid, string currentVersion, Action<VersionCheckResult> onComplete)
			{
				((MonoBehaviour)this).StartCoroutine(CheckVersionCoroutine(pluginGuid, currentVersion, onComplete));
			}

			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;
						LogWarning(result.ErrorMessage);
						onComplete?.Invoke(result);
						Object.Destroy((Object)(object)((Component)this).gameObject);
						yield break;
					}
					try
					{
						string text = www.downloadHandler.text;
						string pattern = "\"" + Regex.Escape(pluginGuid) + "\"\\s*:\\s*\\{([^}]+)\\}";
						Match match = Regex.Match(text, pattern, RegexOptions.Singleline);
						if (!match.Success)
						{
							result.Success = false;
							result.ErrorMessage = "Mod '" + pluginGuid + "' not found in versions.json";
							LogWarning(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";
							LogWarning(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)
						{
							Log("Update available for " + result.ModName + ": " + currentVersion + " -> " + result.LatestVersion);
						}
						else
						{
							Log(result.ModName + " is up to date (v" + currentVersion + ")");
						}
					}
					catch (Exception ex)
					{
						result.Success = false;
						result.ErrorMessage = "Parse error: " + ex.Message;
						LogError(result.ErrorMessage);
					}
				}
				finally
				{
					((IDisposable)www)?.Dispose();
				}
				onComplete?.Invoke(result);
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}

			private string ExtractJsonString(string json, string key)
			{
				string pattern = "\"" + key + "\"\\s*:\\s*(?:\"([^\"]*)\"|null)";
				Match match = Regex.Match(json, pattern);
				if (!match.Success)
				{
					return null;
				}
				return match.Groups[1].Value;
			}
		}

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

		private static ManualLogSource _logger;

		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)
			_logger = logger;
			VersionCheckRunner versionCheckRunner = new GameObject("VersionChecker").AddComponent<VersionCheckRunner>();
			Object.DontDestroyOnLoad((Object)(object)((Component)versionCheckRunner).gameObject);
			versionCheckRunner.StartCheck(pluginGuid, currentVersion, onComplete);
		}

		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');
			string[] array = v1.Split(new char[1] { '.' });
			string[] array2 = v2.Split(new char[1] { '.' });
			int num = Math.Max(array.Length, array2.Length);
			for (int i = 0; i < num; i++)
			{
				int result;
				int num2 = ((i < array.Length && int.TryParse(array[i], out result)) ? result : 0);
				int result2;
				int num3 = ((i < array2.Length && int.TryParse(array2[i], out result2)) ? result2 : 0);
				if (num2 < num3)
				{
					return -1;
				}
				if (num2 > num3)
				{
					return 1;
				}
			}
			return 0;
		}

		internal static void Log(string message)
		{
			ManualLogSource logger = _logger;
			if (logger != null)
			{
				logger.LogInfo((object)("[VersionChecker] " + message));
			}
		}

		internal static void LogWarning(string message)
		{
			ManualLogSource logger = _logger;
			if (logger != null)
			{
				logger.LogWarning((object)("[VersionChecker] " + message));
			}
		}

		internal static void LogError(string message)
		{
			ManualLogSource logger = _logger;
			if (logger != null)
			{
				logger.LogError((object)("[VersionChecker] " + message));
			}
		}
	}
	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 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)
		{
			Type type = AccessTools.TypeByName(typeName);
			if (type != null)
			{
				return type;
			}
			for (int i = 0; i < namespaces.Length; i++)
			{
				type = AccessTools.TypeByName(namespaces[i] + "." + typeName);
				if (type != null)
				{
					return type;
				}
			}
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				try
				{
					type = assembly.GetTypes().FirstOrDefault((Type t) => t.Name == typeName || t.FullName == typeName);
					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;
			}
			PropertyInfo property = type.GetProperty(memberName, AllBindingFlags);
			if (property != null && property.GetMethod != null)
			{
				return property.GetValue(null);
			}
			FieldInfo field = type.GetField(memberName, AllBindingFlags);
			if (field != null)
			{
				return field.GetValue(null);
			}
			return null;
		}

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

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

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

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

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

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

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

		public static T TryGetValue<T>(object instance, string memberName, T defaultValue = default(T))
		{
			try
			{
				object instanceValue = GetInstanceValue(instance, memberName);
				if (instanceValue is T result)
				{
					return result;
				}
				if (instanceValue != null && typeof(T).IsAssignableFrom(instanceValue.GetType()))
				{
					return (T)instanceValue;
				}
				return defaultValue;
			}
			catch
			{
				return defaultValue;
			}
		}
	}
}
namespace SenpaisChest
{
	[BepInPlugin("com.azraelgodking.senpaischest", "Senpai's Chest", "1.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		private static SmartChestManager _staticManager;

		private static SmartChestSaveSystem _staticSaveSystem;

		private static SmartChestUI _staticUI;

		private static SmartChestConfig _staticConfig;

		private static MuseumTodoIntegration _museumTodoIntegration;

		internal static Chest CurrentInteractingChest;

		private Harmony _harmony;

		private SmartChestManager _manager;

		private SmartChestSaveSystem _saveSystem;

		private SmartChestUI _ui;

		private SmartChestConfig _config;

		private static GameObject _persistentRunner;

		private static SmartChestPersistentRunner _updateRunner;

		private string _lastKnownScene = "";

		private bool _wasInMenuScene = true;

		public static Plugin Instance { get; private set; }

		public static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Expected O, but got Unknown
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)"Loading Senpai's Chest v1.1.0");
			CreatePersistentRunner();
			try
			{
				_config = new SmartChestConfig();
				_config.Initialize(((BaseUnityPlugin)this).Config);
				_staticConfig = _config;
				_manager = new SmartChestManager();
				_saveSystem = new SmartChestSaveSystem(_manager);
				_staticManager = _manager;
				_staticSaveSystem = _saveSystem;
				GameObject val = new GameObject("SenpaisChest_UI");
				Object.DontDestroyOnLoad((Object)(object)val);
				_ui = val.AddComponent<SmartChestUI>();
				_ui.Initialize(_manager);
				_staticUI = _ui;
				_harmony = new Harmony("com.azraelgodking.senpaischest");
				ApplyPatches();
				InitializeIntegrations();
				SceneManager.sceneLoaded += OnSceneLoaded;
				if (_config.CheckForUpdates.Value)
				{
					VersionChecker.CheckForUpdate("com.azraelgodking.senpaischest", "1.1.0", Log, delegate(VersionChecker.VersionCheckResult result)
					{
						result.NotifyUpdateAvailable(Log);
					});
				}
				Log.LogInfo((object)"Senpai's Chest loaded successfully!");
				Log.LogInfo((object)string.Format("Press {0}{1} to configure a chest while interacting with it", _config.RequireCtrlModifier.Value ? "Ctrl+" : "", _config.ToggleKey.Value));
			}
			catch (Exception arg)
			{
				Log.LogError((object)string.Format("Failed to load {0}: {1}", "Senpai's Chest", arg));
			}
		}

		private void CreatePersistentRunner()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			if ((Object)(object)_persistentRunner != (Object)null)
			{
				Log.LogInfo((object)"PersistentRunner already exists");
				return;
			}
			_persistentRunner = new GameObject("SenpaisChest_PersistentRunner");
			Object.DontDestroyOnLoad((Object)(object)_persistentRunner);
			((Object)_persistentRunner).hideFlags = (HideFlags)61;
			_updateRunner = _persistentRunner.AddComponent<SmartChestPersistentRunner>();
			Log.LogInfo((object)"Created hidden PersistentRunner");
		}

		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_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			try
			{
				if ((Object)(object)_persistentRunner == (Object)null || (Object)(object)_updateRunner == (Object)null)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogInfo((object)"[EnsureUI] Recreating PersistentRunner...");
					}
					_persistentRunner = new GameObject("SenpaisChest_PersistentRunner");
					Object.DontDestroyOnLoad((Object)(object)_persistentRunner);
					((Object)_persistentRunner).hideFlags = (HideFlags)61;
					_updateRunner = _persistentRunner.AddComponent<SmartChestPersistentRunner>();
				}
				if ((Object)(object)_staticUI == (Object)null)
				{
					ManualLogSource log2 = Log;
					if (log2 != null)
					{
						log2.LogInfo((object)"[EnsureUI] Recreating SmartChestUI...");
					}
					GameObject val = new GameObject("SenpaisChest_UI");
					Object.DontDestroyOnLoad((Object)val);
					_staticUI = val.AddComponent<SmartChestUI>();
					_staticUI.Initialize(_staticManager);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log3 = Log;
				if (log3 != null)
				{
					log3.LogError((object)("[EnsureUI] Error recreating UI: " + ex.Message));
				}
			}
		}

		private void InitializeIntegrations()
		{
			try
			{
				Dictionary<string, PluginInfo> pluginInfos = Chainloader.PluginInfos;
				bool flag = pluginInfos.ContainsKey("com.azraelgodking.sunhavenmuseumutilitytracker");
				bool flag2 = pluginInfos.ContainsKey("com.azraelgodking.sunhaventodo");
				if (flag && flag2)
				{
					_museumTodoIntegration = new MuseumTodoIntegration();
					return;
				}
				if (!flag)
				{
					Log.LogInfo((object)"[Integrations] S.M.U.T. not found");
				}
				if (!flag2)
				{
					Log.LogInfo((object)"[Integrations] SunhavenTodo not found");
				}
				Log.LogInfo((object)"[Integrations] Museum todo integration disabled (requires both S.M.U.T. and Todo)");
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("[Integrations] Error initializing: " + ex.Message));
			}
		}

		private void ApplyPatches()
		{
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Expected O, but got Unknown
			try
			{
				PatchMethod(typeof(Player), "InitializeAsOwner", typeof(Plugin), "OnPlayerInitialized");
				PatchMethod(typeof(Chest), "Interact", typeof(Plugin), "OnChestInteract", new Type[1] { typeof(int) });
				MethodInfo methodInfo = AccessTools.Method(typeof(Chest), "EndInteract", new Type[1] { typeof(int) }, (Type[])null);
				if (methodInfo != null)
				{
					HarmonyMethod val = new HarmonyMethod(AccessTools.Method(typeof(Plugin), "OnChestEndInteract_Prefix", (Type[])null, (Type[])null));
					_harmony.Patch((MethodBase)methodInfo, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					Log.LogInfo((object)"Patched Chest.EndInteract (prefix)");
				}
				else
				{
					Log.LogWarning((object)"Could not find method Chest.EndInteract");
				}
				Log.LogInfo((object)"Harmony patches applied successfully");
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Failed to apply patches: {arg}");
			}
		}

		private void PatchMethod(Type targetType, string methodName, Type patchType, string patchMethodName, Type[] parameters = null)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			MethodInfo methodInfo = ((parameters != null) ? AccessTools.Method(targetType, methodName, parameters, (Type[])null) : AccessTools.Method(targetType, methodName, (Type[])null, (Type[])null));
			if (methodInfo == null)
			{
				Log.LogWarning((object)("Could not find method " + targetType.Name + "." + methodName));
				return;
			}
			MethodInfo methodInfo2 = AccessTools.Method(patchType, patchMethodName, (Type[])null, (Type[])null);
			_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			Log.LogInfo((object)("Patched " + targetType.Name + "." + methodName));
		}

		private static void OnPlayerInitialized(Player __instance)
		{
			try
			{
				if ((Object)(object)__instance != (Object)(object)Player.Instance)
				{
					return;
				}
				EnsureUIComponentsExist();
				string text = null;
				CharacterData currentCharacter = GameSave.CurrentCharacter;
				if (currentCharacter != null)
				{
					text = currentCharacter.characterName;
				}
				if (string.IsNullOrEmpty(text))
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogWarning((object)"Player initialized but no character name found");
					}
					return;
				}
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogInfo((object)("Player initialized: " + text));
				}
				_staticManager?.SetCharacterName(text);
				_museumTodoIntegration?.Reset();
				SmartChestSaveData data = _staticSaveSystem?.Load(text);
				_staticManager?.LoadData(data);
			}
			catch (Exception arg)
			{
				ManualLogSource log3 = Log;
				if (log3 != null)
				{
					log3.LogError((object)$"Error in OnPlayerInitialized: {arg}");
				}
			}
		}

		private static void OnChestInteract(Chest __instance, int interactType)
		{
			if (interactType == 0)
			{
				CurrentInteractingChest = __instance;
			}
		}

		private static bool OnChestEndInteract_Prefix(Chest __instance, int interactType)
		{
			if ((Object)(object)CurrentInteractingChest == (Object)(object)__instance && (Object)(object)_staticUI != (Object)null && _staticUI.IsVisible)
			{
				return false;
			}
			if ((Object)(object)CurrentInteractingChest == (Object)(object)__instance)
			{
				CurrentInteractingChest = null;
				_staticUI?.Hide();
			}
			return true;
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			bool flag = ((Scene)(ref scene)).name == "MainMenu" || ((Scene)(ref scene)).name == "Menu";
			if (flag && !_wasInMenuScene)
			{
				Log.LogInfo((object)"Returned to menu, saving data...");
				_staticSaveSystem?.Save();
			}
			_wasInMenuScene = flag;
			_lastKnownScene = ((Scene)(ref scene)).name;
		}

		private void OnDestroy()
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogInfo((object)"Plugin OnDestroy called — static references preserved");
			}
			_staticSaveSystem?.Save();
		}

		private void OnApplicationQuit()
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogInfo((object)"Application quitting — saving data");
			}
			_staticSaveSystem?.Save();
		}

		internal static SmartChestManager GetManager()
		{
			return _staticManager;
		}

		internal static SmartChestSaveSystem GetSaveSystem()
		{
			return _staticSaveSystem;
		}

		internal static SmartChestUI GetUI()
		{
			return _staticUI;
		}

		internal static SmartChestConfig GetConfig()
		{
			return _staticConfig;
		}

		internal static MuseumTodoIntegration GetMuseumTodoIntegration()
		{
			return _museumTodoIntegration;
		}
	}
	public class SmartChestPersistentRunner : MonoBehaviour
	{
		private float _scanTimer;

		private float _autoSaveTimer;

		private const float AUTO_SAVE_INTERVAL = 300f;

		private int _lastCountdownSecond = -1;

		private void Update()
		{
			SmartChestConfig config = Plugin.GetConfig();
			SmartChestManager manager = Plugin.GetManager();
			if (config == null || manager == null)
			{
				return;
			}
			float unscaledDeltaTime = Time.unscaledDeltaTime;
			float scanInterval = config.GetScanInterval();
			_scanTimer += unscaledDeltaTime;
			int num = (int)Math.Ceiling(scanInterval - _scanTimer);
			if (num >= 1 && num <= 10 && num != _lastCountdownSecond)
			{
				_lastCountdownSecond = num;
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)$"[Scan] Next scan in {num}...");
				}
			}
			if (_scanTimer >= scanInterval)
			{
				_scanTimer = 0f;
				_lastCountdownSecond = -1;
				try
				{
					manager.ExecuteScan(config.MaxItemsPerScan.Value, config.EnableNotifications.Value);
					Plugin.GetMuseumTodoIntegration()?.OnScanComplete();
				}
				catch (Exception arg)
				{
					ManualLogSource log2 = Plugin.Log;
					if (log2 != null)
					{
						log2.LogError((object)$"Error during scan: {arg}");
					}
				}
			}
			_autoSaveTimer += unscaledDeltaTime;
			if (_autoSaveTimer >= 300f)
			{
				_autoSaveTimer = 0f;
				if (manager.IsDirty)
				{
					Plugin.GetSaveSystem()?.Save();
				}
			}
			DetectHotkey(config);
		}

		private void DetectHotkey(SmartChestConfig config)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			KeyCode staticToggleKey = SmartChestConfig.StaticToggleKey;
			bool staticRequireCtrl = SmartChestConfig.StaticRequireCtrl;
			if (Input.GetKeyDown(staticToggleKey) && (!staticRequireCtrl || Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305)))
			{
				SmartChestUI uI = Plugin.GetUI();
				if (!((Object)(object)uI == (Object)null) && (Object)(object)Plugin.CurrentInteractingChest != (Object)null)
				{
					uI.ToggleForChest(Plugin.CurrentInteractingChest);
				}
			}
		}

		private void OnDestroy()
		{
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogWarning((object)"[PersistentRunner] OnDestroy called — this should NOT happen!");
			}
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "com.azraelgodking.senpaischest";

		public const string PLUGIN_NAME = "Senpai's Chest";

		public const string PLUGIN_VERSION = "1.1.0";
	}
}
namespace SenpaisChest.UI
{
	public class SmartChestUI : MonoBehaviour
	{
		private SmartChestManager _manager;

		private bool _isVisible;

		private Chest _currentChest;

		private SmartChestData _currentData;

		private string _chestId;

		private Rect _windowRect = new Rect(100f, 100f, 420f, 500f);

		private Vector2 _rulesScrollPos;

		private float _contentHeight = 500f;

		private int _selectedRuleType;

		private string _itemIdInput = "";

		private int _selectedCategory;

		private int _selectedItemType;

		private int _selectedProperty;

		private string _lastSearchQuery = "";

		private List<KeyValuePair<int, string>> _searchResults = new List<KeyValuePair<int, string>>();

		private Vector2 _searchScrollPos;

		private int _selectedItemId = -1;

		private string _selectedItemName = "";

		private static readonly string[] RuleTypeNames = new string[4] { "By Item", "By Category", "By Item Type", "By Property" };

		private static readonly string[] CategoryNames = new string[6] { "Equip", "Use", "Craftable", "Monster", "Furniture", "Quest" };

		private static readonly string[] ItemTypeNames = new string[9] { "Normal", "Armor", "Food", "Fish", "Crop", "WateringCan", "Animal", "Pet", "Tool" };

		private static readonly string[] PropertyNames = new string[8] { "isGem", "isForageable", "isAnimalProduct", "isMeal", "isFruit", "isArtisanryItem", "isPotion", "isNotDonated" };

		private static readonly string[] PropertyDisplayNames = new string[8] { "Gems", "Forageables", "Animal Products", "Meals", "Fruits", "Artisanry Items", "Potions", "Museum (Not Donated)" };

		private readonly Color _bgDark = new Color(0.15f, 0.16f, 0.24f, 1f);

		private readonly Color _borderGold = new Color(0.75f, 0.65f, 0.3f, 1f);

		private readonly Color _goldText = new Color(0.95f, 0.85f, 0.35f);

		private readonly Color _whiteText = new Color(0.95f, 0.95f, 0.95f);

		private readonly Color _dimText = new Color(0.6f, 0.6f, 0.7f);

		private readonly Color _greenActive = new Color(0.2f, 0.55f, 0.45f, 1f);

		private readonly Color _greenHover = new Color(0.25f, 0.65f, 0.52f, 1f);

		private readonly Color _greenBright = new Color(0.3f, 0.7f, 0.55f, 1f);

		private readonly Color _redDanger = new Color(0.75f, 0.2f, 0.2f, 1f);

		private readonly Color _redHover = new Color(0.85f, 0.28f, 0.28f, 1f);

		private readonly Color _btnInactive = new Color(0.22f, 0.24f, 0.34f, 1f);

		private readonly Color _btnHover = new Color(0.3f, 0.32f, 0.44f, 1f);

		private readonly Color _ruleBoxColor = new Color(0.18f, 0.19f, 0.28f, 1f);

		private readonly Color _fieldBg = new Color(0.12f, 0.13f, 0.22f, 1f);

		private Texture2D _solidBg;

		private Texture2D _windowBg;

		private Texture2D _ruleBg;

		private Texture2D _btnInactiveTex;

		private Texture2D _btnHoverTex;

		private Texture2D _btnActiveTex;

		private Texture2D _btnActiveHoverTex;

		private Texture2D _redBtnTex;

		private Texture2D _redBtnHoverTex;

		private Texture2D _greenBtnTex;

		private Texture2D _greenBtnHoverTex;

		private Texture2D _closeBtnTex;

		private Texture2D _closeBtnHoverTex;

		private Texture2D _fieldBgTex;

		private Texture2D _separatorTex;

		private GUIStyle _windowStyle;

		private GUIStyle _titleStyle;

		private GUIStyle _sectionHeaderStyle;

		private GUIStyle _labelStyle;

		private GUIStyle _labelBoldStyle;

		private GUIStyle _labelDimStyle;

		private GUIStyle _ruleBoxStyle;

		private GUIStyle _ruleTextStyle;

		private GUIStyle _removeRuleBtnStyle;

		private GUIStyle _closeButtonStyle;

		private GUIStyle _toggleStyle;

		private GUIStyle _textFieldStyle;

		private GUIStyle _selectorStyle;

		private GUIStyle _selectorActiveStyle;

		private GUIStyle _addButtonStyle;

		private GUIStyle _dangerButtonStyle;

		private GUIStyle _closeBottomButtonStyle;

		private GUIStyle _searchResultStyle;

		private GUIStyle _searchResultSelectedStyle;

		private bool _stylesInitialized;

		public bool IsVisible => _isVisible;

		public void Initialize(SmartChestManager manager)
		{
			_manager = manager;
		}

		public void Show()
		{
			_isVisible = true;
		}

		public void Hide()
		{
			_isVisible = false;
			Chest currentChest = _currentChest;
			_currentChest = null;
			_currentData = null;
			Plugin.CurrentInteractingChest = null;
			SaveIfDirty();
			if ((Object)(object)currentChest != (Object)null)
			{
				try
				{
					currentChest.EndInteract(0);
				}
				catch
				{
				}
			}
		}

		public void Toggle()
		{
			if (_isVisible)
			{
				Hide();
			}
			else
			{
				Show();
			}
		}

		public void ToggleForChest(Chest chest)
		{
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			if (_isVisible && (Object)(object)_currentChest == (Object)(object)chest)
			{
				Hide();
				return;
			}
			_currentChest = chest;
			_chestId = SmartChestManager.GetChestId(chest);
			if (string.IsNullOrEmpty(_chestId))
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"Cannot configure chest: no valid ID");
				}
				return;
			}
			string chestName = GetChestName(chest);
			_currentData = _manager.GetOrCreateSmartChest(_chestId, chestName);
			_selectedRuleType = 0;
			_itemIdInput = "";
			_lastSearchQuery = "";
			_searchResults.Clear();
			_selectedItemId = -1;
			_selectedItemName = "";
			_searchScrollPos = Vector2.zero;
			_selectedCategory = 0;
			_selectedItemType = 0;
			_selectedProperty = 0;
			_isVisible = true;
		}

		private string GetChestName(Chest chest)
		{
			try
			{
				FieldInfo field = typeof(Chest).GetField("data", BindingFlags.Instance | BindingFlags.NonPublic);
				if (field != null)
				{
					object? value = field.GetValue(chest);
					ChestData val = (ChestData)((value is ChestData) ? value : null);
					if (val != null && !string.IsNullOrEmpty(val.name))
					{
						return val.name;
					}
				}
			}
			catch
			{
			}
			return "Chest";
		}

		private void OnGUI()
		{
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Expected O, but got Unknown
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			if (_isVisible && _currentData != null)
			{
				if (!_stylesInitialized)
				{
					InitializeStyles();
				}
				float num = (float)Screen.height - 40f;
				((Rect)(ref _windowRect)).height = Mathf.Clamp(_contentHeight, 300f, num);
				((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);
				_windowRect = GUI.Window("com.azraelgodking.senpaischest".GetHashCode(), _windowRect, new WindowFunction(DrawWindow), "", _windowStyle);
			}
		}

		private void DrawWindow(int windowId)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_041d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0423: Invalid comparison between Unknown and I4
			//IL_0459: Unknown result type (might be due to invalid IL or missing references)
			//IL_0425: Unknown result type (might be due to invalid IL or missing references)
			//IL_042a: Unknown result type (might be due to invalid IL or missing references)
			GUI.DrawTexture(new Rect(0f, 0f, ((Rect)(ref _windowRect)).width, ((Rect)(ref _windowRect)).height), (Texture)(object)_solidBg);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Smart Chest Config - " + _currentData.ChestName, _titleStyle, Array.Empty<GUILayoutOption>());
			GUILayout.FlexibleSpace();
			if (GUILayout.Button("X", _closeButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(26f),
				GUILayout.Height(22f)
			}))
			{
				Hide();
			}
			GUILayout.EndHorizontal();
			GUILayout.Space(4f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			bool flag = GUILayout.Toggle(_currentData.IsEnabled, " Smart Chest Enabled", _toggleStyle, Array.Empty<GUILayoutOption>());
			if (flag != _currentData.IsEnabled)
			{
				_currentData.IsEnabled = flag;
				_manager.MarkDirty();
				SaveIfDirty();
			}
			GUILayout.EndHorizontal();
			GUILayout.Space(8f);
			GUILayout.Label("Item Rules:", _sectionHeaderStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Space(4f);
			if (_currentData.Rules.Count == 0)
			{
				GUILayout.Label("  No rules configured. Add rules below.", _labelDimStyle, Array.Empty<GUILayoutOption>());
			}
			else
			{
				float num = 36f;
				float num2 = Mathf.Min((float)_currentData.Rules.Count * num, 180f);
				_rulesScrollPos = GUILayout.BeginScrollView(_rulesScrollPos, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(num2) });
				int num3 = -1;
				for (int i = 0; i < _currentData.Rules.Count; i++)
				{
					GUILayout.BeginHorizontal(_ruleBoxStyle, Array.Empty<GUILayoutOption>());
					GUILayout.Label($"{i + 1}. {GetRuleDisplayText(_currentData.Rules[i])}", _ruleTextStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
					if (GUILayout.Button("X", _removeRuleBtnStyle, (GUILayoutOption[])(object)new GUILayoutOption[2]
					{
						GUILayout.Width(26f),
						GUILayout.Height(22f)
					}))
					{
						num3 = i;
					}
					GUILayout.EndHorizontal();
					GUILayout.Space(2f);
				}
				GUILayout.EndScrollView();
				if (num3 >= 0)
				{
					_currentData.Rules.RemoveAt(num3);
					_manager.MarkDirty();
					SaveIfDirty();
				}
			}
			GUILayout.Space(10f);
			GUILayout.Label("Add New Rule:", _sectionHeaderStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Space(6f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			DrawSelectorButton(0, GUILayout.Height(28f));
			DrawSelectorButton(1, GUILayout.Height(28f));
			GUILayout.EndHorizontal();
			GUILayout.Space(2f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			DrawSelectorButton(2, GUILayout.Height(28f));
			DrawSelectorButton(3, GUILayout.Height(28f));
			GUILayout.EndHorizontal();
			GUILayout.Space(8f);
			DrawRuleInput();
			GUILayout.Space(8f);
			if (GUILayout.Button("Add Rule", _addButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
			{
				AddRule();
			}
			GUILayout.Space(12f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Remove Smart Chest", _dangerButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(28f) }))
			{
				_manager.RemoveSmartChest(_chestId);
				SaveIfDirty();
				Hide();
			}
			GUILayout.Space(8f);
			if (GUILayout.Button("Close", _closeBottomButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(28f) }))
			{
				Hide();
			}
			GUILayout.EndHorizontal();
			if ((int)Event.current.type == 7)
			{
				Rect lastRect = GUILayoutUtility.GetLastRect();
				_contentHeight = ((Rect)(ref lastRect)).yMax + 24f;
			}
			GUI.DragWindow(new Rect(0f, 0f, ((Rect)(ref _windowRect)).width, 28f));
		}

		private void DrawSelectorButton(int index, params GUILayoutOption[] options)
		{
			GUIStyle val = ((index == _selectedRuleType) ? _selectorActiveStyle : _selectorStyle);
			if (GUILayout.Button(RuleTypeNames[index], val, options))
			{
				_selectedRuleType = index;
			}
		}

		private void DrawRuleInput()
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: 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)
			switch (_selectedRuleType)
			{
			case 0:
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUILayout.Label("Search:", _labelBoldStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(55f) });
				_itemIdInput = GUILayout.TextField(_itemIdInput, _textFieldStyle, Array.Empty<GUILayoutOption>());
				GUILayout.EndHorizontal();
				if (_itemIdInput != _lastSearchQuery)
				{
					_lastSearchQuery = _itemIdInput;
					_searchResults = SmartChestManager.SearchItems(_itemIdInput);
					_searchScrollPos = Vector2.zero;
				}
				if (_selectedItemId > 0)
				{
					GUILayout.Space(2f);
					GUILayout.Label($"Selected: {_selectedItemName} ({_selectedItemId})", _labelStyle, Array.Empty<GUILayoutOption>());
				}
				if (_searchResults.Count > 0)
				{
					GUILayout.Space(4f);
					_searchScrollPos = GUILayout.BeginScrollView(_searchScrollPos, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(120f) });
					foreach (KeyValuePair<int, string> searchResult in _searchResults)
					{
						GUIStyle val = ((searchResult.Key == _selectedItemId) ? _searchResultSelectedStyle : _searchResultStyle);
						if (GUILayout.Button($"{searchResult.Value} ({searchResult.Key})", val, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(22f) }))
						{
							_selectedItemId = searchResult.Key;
							_selectedItemName = searchResult.Value;
						}
					}
					GUILayout.EndScrollView();
				}
				else if (_itemIdInput.Length >= 2)
				{
					GUILayout.Space(2f);
					GUILayout.Label("  No items found.", _labelDimStyle, Array.Empty<GUILayoutOption>());
				}
				break;
			case 1:
				GUILayout.Label("Category:", _labelBoldStyle, Array.Empty<GUILayoutOption>());
				DrawOptionGrid(CategoryNames, ref _selectedCategory, 3);
				break;
			case 2:
				GUILayout.Label("Item Type:", _labelBoldStyle, Array.Empty<GUILayoutOption>());
				DrawOptionGrid(ItemTypeNames, ref _selectedItemType, 3);
				break;
			case 3:
				GUILayout.Label("Property:", _labelBoldStyle, Array.Empty<GUILayoutOption>());
				DrawOptionGrid(PropertyDisplayNames, ref _selectedProperty, 2);
				break;
			}
		}

		private void DrawOptionGrid(string[] options, ref int selected, int columns)
		{
			int num = (options.Length + columns - 1) / columns;
			for (int i = 0; i < num; i++)
			{
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				for (int j = 0; j < columns; j++)
				{
					int num2 = i * columns + j;
					if (num2 < options.Length)
					{
						GUIStyle val = ((num2 == selected) ? _selectorActiveStyle : _selectorStyle);
						if (GUILayout.Button(options[num2], val, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) }))
						{
							selected = num2;
						}
					}
					else
					{
						GUILayout.FlexibleSpace();
					}
				}
				GUILayout.EndHorizontal();
				GUILayout.Space(2f);
			}
		}

		private string GetRuleDisplayText(SmartChestRule rule)
		{
			if (rule.Type == RuleType.ByItemId)
			{
				string itemName = SmartChestManager.GetItemName(rule.ItemId);
				if (!string.IsNullOrEmpty(itemName))
				{
					return $"{itemName} ({rule.ItemId})";
				}
				return $"Item ID: {rule.ItemId}";
			}
			return rule.GetDisplayText();
		}

		private void AddRule()
		{
			SmartChestRule smartChestRule = null;
			switch (_selectedRuleType)
			{
			case 0:
				if (_selectedItemId > 0)
				{
					smartChestRule = new SmartChestRule
					{
						Type = RuleType.ByItemId,
						ItemId = _selectedItemId
					};
					_itemIdInput = "";
					_lastSearchQuery = "";
					_searchResults.Clear();
					_selectedItemId = -1;
					_selectedItemName = "";
				}
				else
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogWarning((object)"Select an item from the search results first");
					}
				}
				break;
			case 1:
				if (_selectedCategory >= 0 && _selectedCategory < CategoryNames.Length)
				{
					smartChestRule = new SmartChestRule
					{
						Type = RuleType.ByCategory,
						CategoryName = CategoryNames[_selectedCategory]
					};
				}
				break;
			case 2:
				if (_selectedItemType >= 0 && _selectedItemType < ItemTypeNames.Length)
				{
					smartChestRule = new SmartChestRule
					{
						Type = RuleType.ByItemType,
						ItemTypeName = ItemTypeNames[_selectedItemType]
					};
				}
				break;
			case 3:
				if (_selectedProperty >= 0 && _selectedProperty < PropertyNames.Length)
				{
					smartChestRule = new SmartChestRule
					{
						Type = RuleType.ByProperty,
						PropertyName = PropertyNames[_selectedProperty]
					};
				}
				break;
			}
			if (smartChestRule == null)
			{
				return;
			}
			foreach (SmartChestRule rule in _currentData.Rules)
			{
				if (rule.Type == smartChestRule.Type && rule.ItemId == smartChestRule.ItemId && rule.CategoryName == smartChestRule.CategoryName && rule.ItemTypeName == smartChestRule.ItemTypeName && rule.PropertyName == smartChestRule.PropertyName)
				{
					ManualLogSource log2 = Plugin.Log;
					if (log2 != null)
					{
						log2.LogInfo((object)"Rule already exists, skipping duplicate");
					}
					return;
				}
			}
			_currentData.Rules.Add(smartChestRule);
			_manager.MarkDirty();
			SaveIfDirty();
			ManualLogSource log3 = Plugin.Log;
			if (log3 != null)
			{
				log3.LogInfo((object)("Added rule: " + smartChestRule.GetDisplayText()));
			}
		}

		private void SaveIfDirty()
		{
			SmartChestSaveSystem saveSystem = Plugin.GetSaveSystem();
			if (saveSystem == null)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"[UI] SaveIfDirty: SaveSystem is null!");
				}
			}
			else
			{
				saveSystem.Save();
			}
		}

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

		private void CreateTextures()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: 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_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: 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)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			_solidBg = MakeTex(4, 4, _bgDark);
			_windowBg = MakeBorderedTex(16, 16, _bgDark, _borderGold, 2);
			_ruleBg = MakeTex(1, 1, _ruleBoxColor);
			_btnInactiveTex = MakeTex(1, 1, _btnInactive);
			_btnHoverTex = MakeTex(1, 1, _btnHover);
			_btnActiveTex = MakeTex(1, 1, _greenActive);
			_btnActiveHoverTex = MakeTex(1, 1, _greenHover);
			_redBtnTex = MakeTex(1, 1, _redDanger);
			_redBtnHoverTex = MakeTex(1, 1, _redHover);
			_greenBtnTex = MakeTex(1, 1, _greenActive);
			_greenBtnHoverTex = MakeTex(1, 1, _greenBright);
			_closeBtnTex = MakeTex(1, 1, _redDanger);
			_closeBtnHoverTex = MakeTex(1, 1, _redHover);
			_fieldBgTex = MakeTex(1, 1, _fieldBg);
			_separatorTex = MakeTex(1, 1, _borderGold);
		}

		private void CreateStyles()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			//IL_0037: Expected O, but got Unknown
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Expected O, but got Unknown
			//IL_00d0: Expected O, but got Unknown
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: 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_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Expected O, but got Unknown
			//IL_0111: Expected O, but got Unknown
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: 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_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Expected O, but got Unknown
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Expected O, but got Unknown
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Expected O, but got Unknown
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Expected O, but got Unknown
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Expected O, but got Unknown
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Expected O, but got Unknown
			//IL_01d6: Expected O, but got Unknown
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Expected O, but got Unknown
			//IL_01f0: 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_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_0259: 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_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Expected O, but got Unknown
			//IL_0285: Expected O, but got Unknown
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0300: Unknown result type (might be due to invalid IL or missing references)
			//IL_0307: Unknown result type (might be due to invalid IL or missing references)
			//IL_030c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0316: Expected O, but got Unknown
			//IL_031b: Expected O, but got Unknown
			//IL_0326: Unknown result type (might be due to invalid IL or missing references)
			//IL_032b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0338: Expected O, but got Unknown
			//IL_0344: Unknown result type (might be due to invalid IL or missing references)
			//IL_035a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0370: Unknown result type (might be due to invalid IL or missing references)
			//IL_0386: Unknown result type (might be due to invalid IL or missing references)
			//IL_0391: Unknown result type (might be due to invalid IL or missing references)
			//IL_0396: Unknown result type (might be due to invalid IL or missing references)
			//IL_039e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03af: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f1: Expected O, but got Unknown
			//IL_03f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0400: Expected O, but got Unknown
			//IL_0405: Expected O, but got Unknown
			//IL_0406: Unknown result type (might be due to invalid IL or missing references)
			//IL_040b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0413: Unknown result type (might be due to invalid IL or missing references)
			//IL_041a: Unknown result type (might be due to invalid IL or missing references)
			//IL_042b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0432: Unknown result type (might be due to invalid IL or missing references)
			//IL_043c: Unknown result type (might be due to invalid IL or missing references)
			//IL_044d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0454: Unknown result type (might be due to invalid IL or missing references)
			//IL_045e: Unknown result type (might be due to invalid IL or missing references)
			//IL_046f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0476: Unknown result type (might be due to invalid IL or missing references)
			//IL_0480: Unknown result type (might be due to invalid IL or missing references)
			//IL_0487: Unknown result type (might be due to invalid IL or missing references)
			//IL_048c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0496: Expected O, but got Unknown
			//IL_0496: Unknown result type (might be due to invalid IL or missing references)
			//IL_049b: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a5: Expected O, but got Unknown
			//IL_04aa: Expected O, but got Unknown
			//IL_04b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ff: Expected O, but got Unknown
			//IL_0500: Unknown result type (might be due to invalid IL or missing references)
			//IL_0505: Unknown result type (might be due to invalid IL or missing references)
			//IL_050d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0514: Unknown result type (might be due to invalid IL or missing references)
			//IL_0525: Unknown result type (might be due to invalid IL or missing references)
			//IL_052c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0536: Unknown result type (might be due to invalid IL or missing references)
			//IL_0547: Unknown result type (might be due to invalid IL or missing references)
			//IL_054e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0558: Unknown result type (might be due to invalid IL or missing references)
			//IL_0569: Unknown result type (might be due to invalid IL or missing references)
			//IL_0570: Unknown result type (might be due to invalid IL or missing references)
			//IL_057a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0581: Unknown result type (might be due to invalid IL or missing references)
			//IL_0588: Unknown result type (might be due to invalid IL or missing references)
			//IL_0592: Expected O, but got Unknown
			//IL_0597: Expected O, but got Unknown
			//IL_0598: Unknown result type (might be due to invalid IL or missing references)
			//IL_059d: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_05bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_05df: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0601: Unknown result type (might be due to invalid IL or missing references)
			//IL_0608: Unknown result type (might be due to invalid IL or missing references)
			//IL_0612: Unknown result type (might be due to invalid IL or missing references)
			//IL_0619: Unknown result type (might be due to invalid IL or missing references)
			//IL_0620: Unknown result type (might be due to invalid IL or missing references)
			//IL_062a: Expected O, but got Unknown
			//IL_062f: Expected O, but got Unknown
			//IL_0630: Unknown result type (might be due to invalid IL or missing references)
			//IL_0635: Unknown result type (might be due to invalid IL or missing references)
			//IL_063d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0644: Unknown result type (might be due to invalid IL or missing references)
			//IL_0655: Unknown result type (might be due to invalid IL or missing references)
			//IL_065c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0666: Unknown result type (might be due to invalid IL or missing references)
			//IL_0677: Unknown result type (might be due to invalid IL or missing references)
			//IL_067e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0688: Unknown result type (might be due to invalid IL or missing references)
			//IL_0699: Unknown result type (might be due to invalid IL or missing references)
			//IL_06a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_06aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_06b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_06b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_06c2: Expected O, but got Unknown
			//IL_06c7: Expected O, but got Unknown
			//IL_06c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_06cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_06d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_06e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_06ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_06f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0708: Unknown result type (might be due to invalid IL or missing references)
			//IL_070f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0719: Unknown result type (might be due to invalid IL or missing references)
			//IL_072a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0731: Unknown result type (might be due to invalid IL or missing references)
			//IL_073b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0742: Unknown result type (might be due to invalid IL or missing references)
			//IL_0747: Unknown result type (might be due to invalid IL or missing references)
			//IL_0751: Expected O, but got Unknown
			//IL_0751: Unknown result type (might be due to invalid IL or missing references)
			//IL_0756: Unknown result type (might be due to invalid IL or missing references)
			//IL_0760: Expected O, but got Unknown
			//IL_0765: Expected O, but got Unknown
			//IL_076c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0771: Unknown result type (might be due to invalid IL or missing references)
			//IL_0778: Unknown result type (might be due to invalid IL or missing references)
			//IL_0789: Unknown result type (might be due to invalid IL or missing references)
			//IL_0790: Unknown result type (might be due to invalid IL or missing references)
			//IL_079a: Unknown result type (might be due to invalid IL or missing references)
			//IL_07ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_07b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_07c1: Expected O, but got Unknown
			_windowStyle = new GUIStyle(GUI.skin.window)
			{
				padding = new RectOffset(14, 14, 12, 12),
				border = new RectOffset(2, 2, 2, 2)
			};
			_windowStyle.normal.background = _windowBg;
			_windowStyle.normal.textColor = _whiteText;
			_windowStyle.onNormal.background = _windowBg;
			_windowStyle.onNormal.textColor = _whiteText;
			GUIStyle val = new GUIStyle
			{
				fontSize = 15,
				fontStyle = (FontStyle)1
			};
			val.normal.textColor = _whiteText;
			val.alignment = (TextAnchor)3;
			val.padding = new RectOffset(2, 2, 2, 2);
			_titleStyle = val;
			GUIStyle val2 = new GUIStyle
			{
				fontSize = 15,
				fontStyle = (FontStyle)1
			};
			val2.normal.textColor = _goldText;
			val2.alignment = (TextAnchor)4;
			val2.padding = new RectOffset(4, 4, 2, 2);
			_sectionHeaderStyle = val2;
			GUIStyle val3 = new GUIStyle
			{
				fontSize = 13
			};
			val3.normal.textColor = _whiteText;
			val3.alignment = (TextAnchor)3;
			val3.padding = new RectOffset(2, 2, 2, 2);
			val3.wordWrap = true;
			_labelStyle = val3;
			_labelBoldStyle = new GUIStyle(_labelStyle)
			{
				fontStyle = (FontStyle)1
			};
			GUIStyle val4 = new GUIStyle(_labelStyle)
			{
				fontSize = 12,
				fontStyle = (FontStyle)2
			};
			val4.normal.textColor = _dimText;
			_labelDimStyle = val4;
			GUIStyle val5 = new GUIStyle();
			val5.normal.background = _ruleBg;
			val5.padding = new RectOffset(10, 8, 6, 6);
			val5.margin = new RectOffset(4, 4, 2, 2);
			_ruleBoxStyle = val5;
			_ruleTextStyle = new GUIStyle(_labelStyle)
			{
				fontSize = 13
			};
			GUIStyle val6 = new GUIStyle
			{
				fontSize = 13,
				fontStyle = (FontStyle)1
			};
			val6.normal.background = _redBtnTex;
			val6.normal.textColor = _whiteText;
			val6.hover.background = _redBtnHoverTex;
			val6.hover.textColor = _whiteText;
			val6.active.background = _redBtnHoverTex;
			val6.active.textColor = _whiteText;
			val6.alignment = (TextAnchor)4;
			val6.padding = new RectOffset(2, 2, 2, 2);
			_removeRuleBtnStyle = val6;
			GUIStyle val7 = new GUIStyle
			{
				fontSize = 14,
				fontStyle = (FontStyle)1
			};
			val7.normal.background = _closeBtnTex;
			val7.normal.textColor = _whiteText;
			val7.hover.background = _closeBtnHoverTex;
			val7.hover.textColor = _whiteText;
			val7.active.background = _closeBtnHoverTex;
			val7.active.textColor = _whiteText;
			val7.alignment = (TextAnchor)4;
			val7.padding = new RectOffset(2, 2, 1, 1);
			_closeButtonStyle = val7;
			_toggleStyle = new GUIStyle(GUI.skin.toggle)
			{
				fontSize = 13
			};
			_toggleStyle.normal.textColor = _whiteText;
			_toggleStyle.onNormal.textColor = _whiteText;
			_toggleStyle.hover.textColor = _whiteText;
			_toggleStyle.onHover.textColor = _whiteText;
			GUIStyle val8 = new GUIStyle
			{
				fontSize = 13
			};
			val8.normal.background = _fieldBgTex;
			val8.normal.textColor = _whiteText;
			val8.focused.background = _fieldBgTex;
			val8.focused.textColor = _whiteText;
			val8.padding = new RectOffset(8, 8, 5, 5);
			val8.border = new RectOffset(2, 2, 2, 2);
			_textFieldStyle = val8;
			GUIStyle val9 = new GUIStyle
			{
				fontSize = 12,
				fontStyle = (FontStyle)1
			};
			val9.normal.background = _btnInactiveTex;
			val9.normal.textColor = _whiteText;
			val9.hover.background = _btnHoverTex;
			val9.hover.textColor = _whiteText;
			val9.active.background = _btnActiveTex;
			val9.active.textColor = _whiteText;
			val9.alignment = (TextAnchor)4;
			val9.padding = new RectOffset(8, 8, 5, 5);
			val9.margin = new RectOffset(2, 2, 1, 1);
			_selectorStyle = val9;
			GUIStyle val10 = new GUIStyle(_selectorStyle);
			val10.normal.background = _btnActiveTex;
			val10.normal.textColor = _whiteText;
			val10.hover.background = _btnActiveHoverTex;
			val10.hover.textColor = _whiteText;
			_selectorActiveStyle = val10;
			GUIStyle val11 = new GUIStyle
			{
				fontSize = 14,
				fontStyle = (FontStyle)1
			};
			val11.normal.background = _greenBtnTex;
			val11.normal.textColor = _whiteText;
			val11.hover.background = _greenBtnHoverTex;
			val11.hover.textColor = _whiteText;
			val11.active.background = _greenBtnHoverTex;
			val11.active.textColor = _whiteText;
			val11.alignment = (TextAnchor)4;
			val11.padding = new RectOffset(10, 10, 5, 5);
			_addButtonStyle = val11;
			GUIStyle val12 = new GUIStyle
			{
				fontSize = 12,
				fontStyle = (FontStyle)1
			};
			val12.normal.background = _redBtnTex;
			val12.normal.textColor = _whiteText;
			val12.hover.background = _redBtnHoverTex;
			val12.hover.textColor = _whiteText;
			val12.active.background = _redBtnHoverTex;
			val12.active.textColor = _whiteText;
			val12.alignment = (TextAnchor)4;
			val12.padding = new RectOffset(10, 10, 4, 4);
			_dangerButtonStyle = val12;
			GUIStyle val13 = new GUIStyle
			{
				fontSize = 12,
				fontStyle = (FontStyle)1
			};
			val13.normal.background = _btnInactiveTex;
			val13.normal.textColor = _whiteText;
			val13.hover.background = _btnHoverTex;
			val13.hover.textColor = _whiteText;
			val13.active.background = _btnHoverTex;
			val13.active.textColor = _whiteText;
			val13.alignment = (TextAnchor)4;
			val13.padding = new RectOffset(10, 10, 4, 4);
			_closeBottomButtonStyle = val13;
			GUIStyle val14 = new GUIStyle
			{
				fontSize = 12
			};
			val14.normal.background = _ruleBg;
			val14.normal.textColor = _whiteText;
			val14.hover.background = _btnHoverTex;
			val14.hover.textColor = _whiteText;
			val14.active.background = _btnActiveTex;
			val14.active.textColor = _whiteText;
			val14.alignment = (TextAnchor)3;
			val14.padding = new RectOffset(8, 8, 3, 3);
			val14.margin = new RectOffset(0, 0, 1, 1);
			_searchResultStyle = val14;
			GUIStyle val15 = new GUIStyle(_searchResultStyle)
			{
				fontStyle = (FontStyle)1
			};
			val15.normal.background = _btnActiveTex;
			val15.normal.textColor = _whiteText;
			val15.hover.background = _btnActiveHoverTex;
			val15.hover.textColor = _whiteText;
			_searchResultSelectedStyle = val15;
		}

		private Texture2D MakeTex(int width, int height, Color color)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			Color[] array = (Color[])(object)new Color[width * height];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = color;
			}
			Texture2D val = new Texture2D(width, height);
			val.SetPixels(array);
			val.Apply();
			return val;
		}

		private Texture2D MakeBorderedTex(int width, int height, Color fillColor, Color borderColor, int borderWidth)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: 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)
			Texture2D val = new Texture2D(width, height);
			Color[] array = (Color[])(object)new Color[width * height];
			for (int i = 0; i < height; i++)
			{
				for (int j = 0; j < width; j++)
				{
					bool flag = j < borderWidth || j >= width - borderWidth || i < borderWidth || i >= height - borderWidth;
					array[i * width + j] = (flag ? borderColor : fillColor);
				}
			}
			val.SetPixels(array);
			val.Apply();
			return val;
		}

		private void OnDestroy()
		{
			if ((Object)(object)_solidBg != (Object)null)
			{
				Object.Destroy((Object)(object)_solidBg);
			}
			if ((Object)(object)_windowBg != (Object)null)
			{
				Object.Destroy((Object)(object)_windowBg);
			}
			if ((Object)(object)_ruleBg != (Object)null)
			{
				Object.Destroy((Object)(object)_ruleBg);
			}
			if ((Object)(object)_btnInactiveTex != (Object)null)
			{
				Object.Destroy((Object)(object)_btnInactiveTex);
			}
			if ((Object)(object)_btnHoverTex != (Object)null)
			{
				Object.Destroy((Object)(object)_btnHoverTex);
			}
			if ((Object)(object)_btnActiveTex != (Object)null)
			{
				Object.Destroy((Object)(object)_btnActiveTex);
			}
			if ((Object)(object)_btnActiveHoverTex != (Object)null)
			{
				Object.Destroy((Object)(object)_btnActiveHoverTex);
			}
			if ((Object)(object)_redBtnTex != (Object)null)
			{
				Object.Destroy((Object)(object)_redBtnTex);
			}
			if ((Object)(object)_redBtnHoverTex != (Object)null)
			{
				Object.Destroy((Object)(object)_redBtnHoverTex);
			}
			if ((Object)(object)_greenBtnTex != (Object)null)
			{
				Object.Destroy((Object)(object)_greenBtnTex);
			}
			if ((Object)(object)_greenBtnHoverTex != (Object)null)
			{
				Object.Destroy((Object)(object)_greenBtnHoverTex);
			}
			if ((Object)(object)_closeBtnTex != (Object)null)
			{
				Object.Destroy((Object)(object)_closeBtnTex);
			}
			if ((Object)(object)_closeBtnHoverTex != (Object)null)
			{
				Object.Destroy((Object)(object)_closeBtnHoverTex);
			}
			if ((Object)(object)_fieldBgTex != (Object)null)
			{
				Object.Destroy((Object)(object)_fieldBgTex);
			}
			if ((Object)(object)_separatorTex != (Object)null)
			{
				Object.Destroy((Object)(object)_separatorTex);
			}
		}
	}
}
namespace SenpaisChest.Integration
{
	public class MuseumTodoIntegration
	{
		private readonly Dictionary<int, string> _museumTodoIds = new Dictionary<int, string>();

		private int _scanCounter;

		private const int SCAN_INTERVAL = 3;

		public MuseumTodoIntegration()
		{
			DonationManager donationManager = Plugin.GetDonationManager();
			if (donationManager != null)
			{
				donationManager.OnDonationsChanged += OnDonationsChanged;
			}
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)"[MuseumTodoIntegration] Initialized - museum item todos will sync with S.M.U.T. and Todo");
			}
		}

		public void OnScanComplete()
		{
			_scanCounter++;
			if (_scanCounter < 3)
			{
				return;
			}
			_scanCounter = 0;
			try
			{
				DonationManager donationManager = Plugin.GetDonationManager();
				TodoManager todoManager = Plugin.GetTodoManager();
				if (donationManager == null || !donationManager.IsLoaded || todoManager == null)
				{
					return;
				}
				HashSet<Inventory> inventories = ChestManager.inventories;
				if (inventories == null || inventories.Count == 0)
				{
					return;
				}
				foreach (Inventory item in inventories)
				{
					if ((Object)(object)item == (Object)null)
					{
						continue;
					}
					List<SlotItemData> items = item.Items;
					if (items == null)
					{
						continue;
					}
					int num = Math.Min(item.maxSlots, items.Count);
					for (int i = 0; i < num; i++)
					{
						SlotItemData val = items[i];
						if (val.id > 0 && val.amount > 0)
						{
							CheckMuseumItem(val.id, donationManager, todoManager);
						}
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[MuseumTodoIntegration] Error during scan: " + ex.Message));
				}
			}
		}

		private void CheckMuseumItem(int gameItemId, DonationManager donationManager, TodoManager todoManager)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			if (_museumTodoIds.ContainsKey(gameItemId))
			{
				return;
			}
			MuseumItem val = MuseumContent.FindByGameItemId(gameItemId);
			if (val != null && !donationManager.HasDonatedByGameId(gameItemId))
			{
				string text = "Donate " + val.Name + " to the museum";
				string text2 = "Found in a chest - this item is still needed for the museum!";
				TodoItem val2 = new TodoItem(text, text2, (TodoPriority)2, (TodoCategory)8);
				todoManager.AddTodo(val2);
				_museumTodoIds[gameItemId] = val2.Id;
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)$"[MuseumTodoIntegration] Created todo for museum item: {val.Name} (ID: {gameItemId})");
				}
			}
		}

		private void OnDonationsChanged()
		{
			try
			{
				DonationManager donationManager = Plugin.GetDonationManager();
				TodoManager todoManager = Plugin.GetTodoManager();
				if (donationManager == null || todoManager == null)
				{
					return;
				}
				List<int> list = new List<int>();
				foreach (KeyValuePair<int, string> museumTodoId in _museumTodoIds)
				{
					if (donationManager.HasDonatedByGameId(museumTodoId.Key))
					{
						list.Add(museumTodoId.Key);
					}
				}
				foreach (int item in list)
				{
					if (!_museumTodoIds.TryGetValue(item, out var todoId))
					{
						continue;
					}
					TodoItem val = todoManager.GetAllTodos().FirstOrDefault((Func<TodoItem, bool>)((TodoItem t) => t.Id == todoId));
					if (val != null && !val.IsCompleted)
					{
						todoManager.ToggleComplete(todoId);
						MuseumItem val2 = MuseumContent.FindByGameItemId(item);
						ManualLogSource log = Plugin.Log;
						if (log != null)
						{
							log.LogInfo((object)("[MuseumTodoIntegration] Completed todo for donated item: " + (((val2 != null) ? val2.Name : null) ?? item.ToString())));
						}
					}
					_museumTodoIds.Remove(item);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("[MuseumTodoIntegration] Error processing donation change: " + ex.Message));
				}
			}
		}

		public void Reset()
		{
			_museumTodoIds.Clear();
			_scanCounter = 0;
		}
	}
}
namespace SenpaisChest.Data
{
	public enum RuleType
	{
		ByItemId,
		ByCategory,
		ByItemType,
		ByProperty
	}
	[Serializable]
	public class SmartChestRule
	{
		public RuleType Type;

		public int ItemId;

		public string CategoryName = "";

		public string ItemTypeName = "";

		public string PropertyName = "";

		public string GetDisplayText()
		{
			return Type switch
			{
				RuleType.ByItemId => $"Item ID: {ItemId}", 
				RuleType.ByCategory => "Category: " + CategoryName, 
				RuleType.ByItemType => "Type: " + ItemTypeName, 
				RuleType.ByProperty => "Property: " + PropertyName, 
				_ => "Unknown Rule", 
			};
		}
	}
	[Serializable]
	public class SmartChestData
	{
		public string ChestId = "";

		public string ChestName = "";

		public bool IsEnabled = true;

		public List<SmartChestRule> Rules = new List<SmartChestRule>();

		public SmartChestData()
		{
		}

		public SmartChestData(string chestId, string chestName)
		{
			ChestId = chestId;
			ChestName = chestName;
			IsEnabled = true;
			Rules = new List<SmartChestRule>();
		}
	}
	[Serializable]
	public class SmartChestSaveData
	{
		public string CharacterName = "";

		public List<SmartChestData> Chests = new List<SmartChestData>();

		public SmartChestSaveData()
		{
		}

		public SmartChestSaveData(string characterName)
		{
			CharacterName = characterName;
			Chests = new List<SmartChestData>();
		}
	}
	public class SmartChestManager
	{
		private readonly Dictionary<string, SmartChestData> _smartChests = new Dictionary<string, SmartChestData>();

		private string _characterName = "";

		private bool _isDirty;

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

		private static FieldInfo _chestDataField;

		private static object _itemInfoDbInstance;

		private static FieldInfo _allItemSellInfosField;

		private static object _notificationStackInstance;

		private static MethodInfo _sendNotificationMethod;

		private static MethodInfo _databaseGetDataMethod;

		private static bool _reflectionInitialized;

		private static bool _museumReflectionInitialized;

		private static bool _museumModAvailable;

		private static MethodInfo _getDonationManagerMethod;

		private static MethodInfo _hasDonatedByGameIdMethod;

		private static MethodInfo _findByGameItemIdMethod;

		private static PropertyInfo _isLoadedProperty;

		public bool IsDirty => _isDirty;

		public void LoadData(SmartChestSaveData data)
		{
			_smartChests.Clear();
			_categoryCache.Clear();
			if (data == null)
			{
				return;
			}
			_characterName = data.CharacterName;
			foreach (SmartChestData chest in data.Chests)
			{
				_smartChests[chest.ChestId] = chest;
			}
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)$"Loaded {_smartChests.Count} smart chest configurations");
			}
		}

		public SmartChestSaveData GetSaveData()
		{
			return new SmartChestSaveData
			{
				CharacterName = _characterName,
				Chests = _smartChests.Values.ToList()
			};
		}

		public void SetCharacterName(string name)
		{
			_characterName = name;
		}

		public void MarkClean()
		{
			_isDirty = false;
		}

		public void MarkDirty()
		{
			_isDirty = true;
		}

		public SmartChestData GetOrCreateSmartChest(string chestId, string chestName)
		{
			if (_smartChests.TryGetValue(chestId, out var value))
			{
				value.ChestName = chestName;
				return value;
			}
			SmartChestData smartChestData = new SmartChestData(chestId, chestName);
			_smartChests[chestId] = smartChestData;
			_isDirty = true;
			return smartChestData;
		}

		public SmartChestData GetSmartChest(string chestId)
		{
			_smartChests.TryGetValue(chestId, out var value);
			return value;
		}

		public bool IsSmartChest(string chestId)
		{
			if (_smartChests.ContainsKey(chestId) && _smartChests[chestId].IsEnabled)
			{
				return _smartChests[chestId].Rules.Count > 0;
			}
			return false;
		}

		public void RemoveSmartChest(string chestId)
		{
			if (_smartChests.Remove(chestId))
			{
				_isDirty = true;
			}
		}

		public static string GetChestId(Chest chest)
		{
			//IL_0019: 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)
			if ((Object)(object)chest == (Object)null)
			{
				return null;
			}
			if ((Object)(object)chest == (Object)null)
			{
				return null;
			}
			Vector3Int position = ((Decoration)chest).Position;
			return $"{((Vector3Int)(ref position)).x}_{((Vector3Int)(ref position)).y}_{((Vector3Int)(ref position)).z}";
		}

		private static void InitReflection()
		{
			if (_reflectionInitialized)
			{
				return;
			}
			try
			{
				_chestDataField = typeof(Chest).GetField("data", BindingFlags.Instance | BindingFlags.NonPublic);
				Type type = AccessTools.TypeByName("Wish.Database") ?? AccessTools.TypeByName("Database");
				if (type != null)
				{
					MethodInfo methodInfo = type.GetMethods(BindingFlags.Static | BindingFlags.Public).FirstOrDefault((MethodInfo m) => m.Name == "GetData" && m.IsGenericMethod && m.GetParameters().Length == 3);
					if (methodInfo != null)
					{
						_databaseGetDataMethod = methodInfo.MakeGenericMethod(typeof(ItemData));
					}
				}
				_reflectionInitialized = true;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)("Failed to initialize reflection: " + ex.Message));
				}
			}
		}

		private static object GetSingletonInstance(string typeName)
		{
			try
			{
				Type type = AccessTools.TypeByName("Wish.SingletonBehaviour`1");
				if (type == null)
				{
					return null;
				}
				Type type2 = AccessTools.TypeByName(typeName);
				if (type2 == null)
				{
					return null;
				}
				return type.MakeGenericType(type2).GetProperty("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy)?.GetValue(null);
			}
			catch
			{
				return null;
			}
		}

		private static ItemSellInfo GetItemSellInfo(int itemId)
		{
			try
			{
				if (_itemInfoDbInstance != null)
				{
					object itemInfoDbInstance = _itemInfoDbInstance;
					Object val = (Object)((itemInfoDbInstance is Object) ? itemInfoDbInstance : null);
					if (val == null || !(val == (Object)null))
					{
						goto IL_004f;
					}
				}
				_itemInfoDbInstance = GetSingletonInstance("Wish.ItemInfoDatabase");
				if (_itemInfoDbInstance != null)
				{
					_allItemSellInfosField = _itemInfoDbInstance.GetType().GetField("allItemSellInfos", BindingFlags.Instance | BindingFlags.Public);
				}
				goto IL_004f;
				IL_004f:
				if (_itemInfoDbInstance == null || _allItemSellInfosField == null)
				{
					return null;
				}
				if (_allItemSellInfosField.GetValue(_itemInfoDbInstance) is Dictionary<int, ItemSellInfo> dictionary && dictionary.ContainsKey(itemId))
				{
					return dictionary[itemId];
				}
			}
			catch
			{
			}
			return null;
		}

		private static void SendNotification(string message)
		{
			try
			{
				if (_notificationStackInstance != null)
				{
					object notificationStackInstance = _notificationStackInstance;
					Object val = (Object)((notificationStackInstance is Object) ? notificationStackInstance : null);
					if (val == null || !(val == (Object)null))
					{
						goto IL_0094;
					}
				}
				_notificationStackInstance = GetSingletonInstance("Wish.NotificationStack");
				if (_notificationStackInstance != null)
				{
					_sendNotificationMethod = _notificationStackInstance.GetType().GetMethod("SendNotification", new Type[5]
					{
						typeof(string),
						typeof(int),
						typeof(int),
						typeof(bool),
						typeof(bool)
					});
				}
				goto IL_0094;
				IL_0094:
				_sendNotificationMethod?.Invoke(_notificationStackInstance, new object[5] { message, 0, 0, true, false });
			}
			catch
			{
			}
		}

		private bool IsChestInUse(Chest chest)
		{
			try
			{
				InitReflection();
				if (_chestDataField != null)
				{
					object? value = _chestDataField.GetValue(chest);
					object? obj = ((value is ChestData) ? value : null);
					return obj != null && ((ChestData)obj).inUse;
				}
			}
			catch
			{
			}
			return false;
		}

		public static List<KeyValuePair<int, string>> SearchItems(string query, int maxResults = 20)
		{
			List<KeyValuePair<int, string>> list = new List<KeyValuePair<int, string>>();
			if (string.IsNullOrEmpty(query) || query.Length < 2)
			{
				return list;
			}
			try
			{
				if (_itemInfoDbInstance != null)
				{
					object itemInfoDbInstance = _itemInfoDbInstance;
					Object val = (Object)((itemInfoDbInstance is Object) ? itemInfoDbInstance : null);
					if (val == null || !(val == (Object)null))
					{
						goto IL_0069;
					}
				}
				_itemInfoDbInstance = GetSingletonInstance("Wish.ItemInfoDatabase");
				if (_itemInfoDbInstance != null)
				{
					_allItemSellInfosField = _itemInfoDbInstance.GetType().GetField("allItemSellInfos", BindingFlags.Instance | BindingFlags.Public);
				}
				goto IL_0069;
				IL_0069:
				if (_itemInfoDbInstance == null || _allItemSellInfosField == null)
				{
					return list;
				}
				if (!(_allItemSellInfosField.GetValue(_itemInfoDbInstance) is Dictionary<int, ItemSellInfo> dictionary))
				{
					return list;
				}
				string text = query.ToLowerInvariant();
				int result;
				bool flag = int.TryParse(query, out result);
				List<KeyValuePair<int, string>> list2 = new List<KeyValuePair<int, string>>();
				List<KeyValuePair<int, string>> list3 = new List<KeyValuePair<int, string>>();
				List<KeyValuePair<int, string>> list4 = new List<KeyValuePair<int, string>>();
				foreach (KeyValuePair<int, ItemSellInfo> item2 in dictionary)
				{
					if (item2.Value != null && !string.IsNullOrEmpty(item2.Value.name))
					{
						KeyValuePair<int, string> item = new KeyValuePair<int, string>(item2.Key, item2.Value.name);
						string text2 = item2.Value.name.ToLowerInvariant();
						if (flag && item2.Key == result)
						{
							list2.Add(item);
						}
						else if (text2 == text)
						{
							list2.Add(item);
						}
						else if (text2.StartsWith(text))
						{
							list3.Add(item);
						}
						else if (text2.Contains(text))
						{
							list4.Add(item);
						}
						else if (flag && item2.Key.ToString().Contains(query))
						{
							list4.Add(item);
						}
					}
				}
				list3.Sort((KeyValuePair<int, string> a, KeyValuePair<int, string> b) => string.Compare(a.Value, b.Value, StringComparison.OrdinalIgnoreCase));
				list4.Sort((KeyValuePair<int, string> a, KeyValuePair<int, string> b) => string.Compare(a.Value, b.Value, StringComparison.OrdinalIgnoreCase));
				list.AddRange(list2);
				list.AddRange(list3);
				list.AddRange(list4);
				if (list.Count > maxResults)
				{
					list.RemoveRange(maxResults, list.Count - maxResults);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("Error searching items: " + ex.Message));
				}
			}
			return list;
		}

		public static string GetItemName(int itemId)
		{
			return GetItemSellInfo(itemId)?.name;
		}

		public void ExecuteScan(int maxItemsPerScan, bool enableNotifications)
		{
			if (_smartChests.Count == 0)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogDebug((object)"[Scan] No smart chests configured, skipping scan");
				}
				return;
			}
			InitReflection();
			HashSet<Inventory> inventories = ChestManager.inventories;
			Dictionary<Inventory, Chest> associatedChests = ChestManager.associatedChests;
			if (inventories == null || inventories.Count == 0)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogDebug((object)"[Scan] No inventories loaded, skipping scan");
				}
				return;
			}
			if (associatedChests == null || associatedChests.Count == 0)
			{
				ManualLogSource log3 = Plugin.Log;
				if (log3 != null)
				{
					log3.LogDebug((object)"[Scan] No associated chests found, skipping scan");
				}
				return;
			}
			ManualLogSource log4 = Plugin.Log;
			if (log4 != null)
			{
				log4.LogInfo((object)$"[Scan] Starting scan: {_smartChests.Count} smart chest(s), {associatedChests.Count} associated chest(s)");
			}
			int num = 0;
			HashSet<Chest> hashSet = new HashSet<Chest>();
			Dictionary<string, KeyValuePair<Inventory, Chest>> dictionary = new Dictionary<string, KeyValuePair<Inventory, Chest>>();
			foreach (KeyValuePair<Inventory, Chest> item in associatedChests)
			{
				string chestId = GetChestId(item.Value);
				if (chestId != null && !dictionary.ContainsKey(chestId))
				{
					dictionary[chestId] = new KeyValuePair<Inventory, Chest>(item.Key, item.Value);
				}
			}
			ManualLogSource log5 = Plugin.Log;
			if (log5 != null)
			{
				log5.LogDebug((object)$"[Scan] Built chest lookup: {dictionary.Count} unique chests");
			}
			foreach (KeyValuePair<string, SmartChestData> smartChest in _smartChests)
			{
				if (num >= maxItemsPerScan)
				{
					break;
				}
				SmartChestData value = smartChest.Value;
				if (!value.IsEnabled || value.Rules.Count == 0)
				{
					ManualLogSource log6 = Plugin.Log;
					if (log6 != null)
					{
						log6.LogDebug((object)$"[Scan] Skipping '{value.ChestName}' (enabled={value.IsEnabled}, rules={value.Rules.Count})");
					}
					continue;
				}
				if (!dictionary.TryGetValue(value.ChestId, out var value2))
				{
					ManualLogSource log7 = Plugin.Log;
					if (log7 != null)
					{
						log7.LogWarning((object)("[Scan] Smart chest '" + value.ChestName + "' (id=" + value.ChestId + ") not found in loaded chests"));
					}
					continue;
				}
				Inventory key = value2.Key;
				Chest value3 = value2.Value;
				if (IsChestInUse(value3))
				{
					ManualLogSource log8 = Plugin.Log;
					if (log8 != null)
					{
						log8.LogDebug((object)("[Scan] Target chest '" + value.ChestName + "' is in use, skipping"));
					}
					continue;
				}
				ManualLogSource log9 = Plugin.Log;
				if (log9 != null)
				{
					log9.LogInfo((object)$"[Scan] Scanning for items matching '{value.ChestName}' ({value.Rules.Count} rules)");
				}
				int num2 = 0;
				foreach (KeyValuePair<string, KeyValuePair<Inventory, Chest>> item2 in dictionary)
				{
					if (num >= maxItemsPerScan)
					{
						break;
					}
					if (item2.Key == value.ChestId)
					{
						continue;
					}
					Inventory key2 = item2.Value.Key;
					Chest value4 = item2.Value.Value;
					if (!IsChestInUse(value4) && !IsSmartChest(item2.Key))
					{
						num2++;
						int num3 = TransferMatchingItems(key2, value4, key, value3, value.Rules, maxItemsPerScan - num);
						if (num3 > 0)
						{
							num += num3;
							hashSet.Add(value4);
							hashSet.Add(value3);
						}
					}
				}
				ManualLogSource log10 = Plugin.Log;
				if (log10 != null)
				{
					log10.LogDebug((object)$"[Scan] Scanned {num2} source chests for '{value.ChestName}'");
				}
			}
			int num5 = default(int);
			int num6 = default(int);
			foreach (KeyValuePair<string, SmartChestData> smartChest2 in _smartChests)
			{
				if (num >= maxItemsPerScan)
				{
					break;
				}
				SmartChestData value5 = smartChest2.Value;
				if (!value5.IsEnabled || value5.Rules.Count == 0 || !dictionary.TryGetValue(value5.ChestId, out var value6))
				{
					continue;
				}
				Inventory key3 = value6.Key;
				Chest value7 = value6.Value;
				if (IsChestInUse(value7))
				{
					continue;
				}
				List<SlotItemData> items = key3.Items;
				if (items == null)
				{
					continue;
				}
				int num4 = Mathf.Min(key3.maxSlots, items.Count) - 1;
				while (num4 >= 0 && num < maxItemsPerScan)
				{
					SlotItemData val = items[num4];
					if (val.id > 0 && val.amount > 0 && !MatchesAnyRule(val.id, value5.Rules))
					{
						string text = GetItemSellInfo(val.id)?.name ?? $"Item {val.id}";
						bool flag = false;
						foreach (KeyValuePair<string, SmartChestData> smartChest3 in _smartChests)
						{
							if (!(smartChest3.Key == value5.ChestId) && smartChest3.Value.IsEnabled && smartChest3.Value.Rules.Count != 0 && MatchesAnyRule(val.id, smartChest3.Value.Rules) && dictionary.TryGetValue(smartChest3.Value.ChestId, out var value8) && !IsChestInUse(value8.Value) && value8.Key.CanAcceptItem(val.item, val.amount, ref num5) && num5 > 0)
							{
								ManualLogSource log11 = Plugin.Log;
								if (log11 != null)
								{
									log11.LogInfo((object)$"[Scan] Ejecting {text} x{num5} from '{value5.ChestName}' to smart chest '{smartChest3.Value.ChestName}'");
								}
								TransferItemData(key3, num4, value8.Key, val.item, num5);
								hashSet.Add(value7);
								hashSet.Add(value8.Value);
								num++;
								flag = true;
								break;
							}
						}
						if (!flag)
						{
							foreach (KeyValuePair<string, KeyValuePair<Inventory, Chest>> item3 in dictionary)
							{
								if (!IsSmartChest(item3.Key) && !IsChestInUse(item3.Value.Value) && item3.Value.Key.CanAcceptItem(val.item, val.amount, ref num6) && num6 > 0)
								{
									ManualLogSource log12 = Plugin.Log;
									if (log12 != null)
									{
										log12.LogInfo((object)$"[Scan] Ejecting {text} x{num6} from '{value5.ChestName}' to normal chest");
									}
									TransferItemData(key3, num4, item3.Value.Key, val.item, num6);
									hashSet.Add(value7);
									hashSet.Add(item3.Value.Value);
									num++;
									break;
								}
							}
						}
					}
					num4--;
				}
			}
			foreach (Chest item4 in hashSet)
			{
				try
				{
					((Decoration)item4).SaveMeta();
					((Decoration)item4).SendNewMeta(((Decoration)item4).meta);
				}
				catch (Exception ex)
				{
					ManualLogSource log13 = Plugin.Log;
					if (log13 != null)
					{
						log13.LogError((object)("Error saving chest meta: " + ex.Message));
					}
				}
			}
			if (num > 0)
			{
				ManualLogSource log14 = Plugin.Log;
				if (log14 != null)
				{
					log14.LogInfo((object)$"[Scan] Complete: sorted {num} item stack(s)");
				}
				if (enableNotifications)
				{
					SendNotification("Senpai's Chest: Sorted");
				}
			}
			else
			{
				ManualLogSource log15 = Plugin.Log;
				if (log15 != null)
				{
					log15.LogInfo((object)"[Scan] Complete: no items to sort");
				}
			}
		}

		private int TransferMatchingItems(Inventory sourceInv, Chest sourceChest, Inventory targetInv, Chest targetChest, List<SmartChestRule> rules, int maxItems)
		{
			int num = 0;
			List<SlotItemData> items = sourceInv.Items;
			if (items == null)
			{
				return 0;
			}
			int num2 = Mathf.Min(sourceInv.maxSlots, items.Count) - 1;
			int num3 = default(int);
			while (num2 >= 0 && num < maxItems)
			{
				SlotItemData val = items[num2];
				if (val.id > 0 && val.amount > 0 && MatchesAnyRule(val.id, rules))
				{
					if (!targetInv.CanAcceptItem(val.item, val.amount, ref num3))
					{
						ManualLogSource log = Plugin.Log;
						if (log != null)
						{
							log.LogDebug((object)$"[Scan] Target cannot accept item {val.id} (amount={val.amount})");
						}
					}
					else if (num3 > 0)
					{
						string arg = GetItemSellInfo(val.id)?.name ?? $"Item {val.id}";
						ManualLogSource log2 = Plugin.Log;
						if (log2 != null)
						{
							log2.LogInfo((object)$"[Scan] Moving {arg} x{num3}");
						}
						TransferItemData(sourceInv, num2, targetInv, val.item, num3);
						num++;
					}
				}
				num2--;
			}
			return num;
		}

		private void TransferItemData(Inventory sourceInv, int sourceSlot, Inventory targetInv, Item item, int amount)
		{
			targetInv.AddItem(item, amount, false);
			sourceInv.RemoveItemAt(sourceSlot, amount);
		}

		private bool MatchesAnyRule(int itemId, List<SmartChestRule> rules)
		{
			foreach (SmartChestRule rule in rules)
			{
				if (MatchesRule(itemId, rule))
				{
					return true;
				}
			}
			return false;
		}

		private bool MatchesRule(int itemId, SmartChestRule rule)
		{
			switch (rule.Type)
			{
			case RuleType.ByItemId:
				return itemId == rule.ItemId;
			case RuleType.ByItemType:
			{
				ItemSellInfo itemSellInfo2 = GetItemSellInfo(itemId);
				if (itemSellInfo2 == null)
				{
					return false;
				}
				return ((object)(ItemType)(ref itemSellInfo2.itemType)).ToString() == rule.ItemTypeName;
			}
			case RuleType.ByProperty:
			{
				if (rule.PropertyName == "isNotDonated")
				{
					return IsMuseumItemNotDonated(itemId);
				}
				ItemSellInfo itemSellInfo = GetItemSellInfo(itemId);
				if (itemSellInfo == null)
				{
					return false;
				}
				return rule.PropertyName switch
				{
					"isGem" => itemSellInfo.isGem, 
					"isForageable" => itemSellInfo.isForageable, 
					"isAnimalProduct" => itemSellInfo.isAnimalProduct, 
					"isMeal" => itemSellInfo.isMeal, 
					"isFruit" => itemSellInfo.isFruit, 
					"isArtisanryItem" => itemSellInfo.isArtisanryItem, 
					"isPotion" => itemSellInfo.isPotion, 
					_ => false, 
				};
			}
			case RuleType.ByCategory:
				return MatchesCategory(itemId, rule.CategoryName);
			default:
				return false;
			}
		}

		private bool MatchesCategory(int itemId, string categoryName)
		{
			if (_categoryCache.TryGetValue(itemId, out var value))
			{
				return value == categoryName;
			}
			bool matched = false;
			try
			{
				if (_databaseGetDataMethod != null)
				{
					Action<ItemData> action = delegate(ItemData itemData)
					{
						if ((Object)(object)itemData != (Object)null)
						{
							_categoryCache[itemId] = ((object)(ItemCategory)(ref itemData.category)).ToString();
							matched = ((object)(ItemCategory)(ref itemData.category)).ToString() == categoryName;
						}
					};
					_databaseGetDataMethod.Invoke(null, new object[3] { itemId, action, null });
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)$"Failed to lookup category for item {itemId}: {ex.Message}");
				}
			}
			return matched;
		}

		private static bool IsMuseumItemNotDonated(int itemId)
		{
			if (!_museumReflectionInitialized)
			{
				_museumReflectionInitialized = true;
				try
				{
					Type type = AccessTools.TypeByName("SunHavenMuseumUtilityTracker.Plugin");
					if (type != null)
					{
						_getDonationManagerMethod = type.GetMethod("GetDonationManager", BindingFlags.Static | BindingFlags.Public);
						Type type2 = AccessTools.TypeByName("SunHavenMuseumUtilityTracker.Data.MuseumContent");
						if (type2 != null)
						{
							_findByGameItemIdMethod = type2.GetMethod("FindByGameItemId", BindingFlags.Static | BindingFlags.Public);
						}
						_museumModAvailable = _getDonationManagerMethod != null && _findByGameItemIdMethod != null;