Decompiled source of TheVault v2.0.4

TheVault.dll

Decompiled 2 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using SunhavenMods.Shared;
using TheVault.Patches;
using TheVault.UI;
using TheVault.Vault;
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("TheVault")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+c7976283ee1309608b00428a169c130e784344a0")]
[assembly: AssemblyProduct("TheVault")]
[assembly: AssemblyTitle("TheVault")]
[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 TheVault
{
	public static class ItemIds
	{
		public const int SpringToken = 18020;

		public const int SummerToken = 18021;

		public const int WinterToken = 18022;

		public const int FallToken = 18023;

		public const int CopperKey = 1251;

		public const int IronKey = 1252;

		public const int AdamantKey = 1253;

		public const int MithrilKey = 1254;

		public const int SuniteKey = 1255;

		public const int GloriteKey = 1256;

		public const int KingsLostMineKey = 1257;

		public const int CommunityToken = 18013;

		public const int Doubloon = 60014;

		public const int BlackBottleCap = 60013;

		public const int RedCarnivalTicket = 18012;

		public const int CandyCornPieces = 18016;

		public const int ManaShard = 18015;
	}
	[BepInPlugin("com.azraelgodking.thevault", "The Vault", "2.0.3")]
	public class Plugin : BaseUnityPlugin
	{
		private static VaultManager _staticVaultManager;

		private static VaultSaveSystem _staticSaveSystem;

		private static VaultUI _staticVaultUI;

		private static VaultHUD _staticVaultHUD;

		internal static KeyCode StaticToggleKey = (KeyCode)118;

		internal static bool StaticRequireCtrl = true;

		internal static KeyCode StaticAltToggleKey = (KeyCode)289;

		internal static KeyCode StaticHUDToggleKey = (KeyCode)288;

		private Harmony _harmony;

		private VaultManager _vaultManager;

		private VaultSaveSystem _saveSystem;

		private VaultUI _vaultUI;

		private VaultHUD _vaultHUD;

		private ConfigEntry<KeyCode> _toggleKey;

		private ConfigEntry<bool> _requireCtrlModifier;

		private ConfigEntry<KeyCode> _altToggleKey;

		private ConfigEntry<bool> _enableHUD;

		private ConfigEntry<string> _hudPosition;

		private ConfigEntry<KeyCode> _hudToggleKey;

		private ConfigEntry<bool> _enableAutoSave;

		private ConfigEntry<float> _autoSaveInterval;

		private ConfigEntry<bool> _checkForUpdates;

		private string _lastKnownScene = "";

		private bool _wasInMenuScene = true;

		private float _sceneCheckTimer;

		private const float SCENE_CHECK_INTERVAL = 0.5f;

		private float _heartbeatTimer;

		private const float HEARTBEAT_INTERVAL = 30f;

		private int _heartbeatCount;

		private static GameObject _persistentRunner;

		private static PersistentUpdateRunner _updateRunner;

		public static Plugin Instance { get; private set; }

		public static ManualLogSource Log { get; private set; }

		public static ConfigFile ConfigFile { get; private set; }

		private void Awake()
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			//IL_00a3: 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_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Expected O, but got Unknown
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			ConfigFile = ((BaseUnityPlugin)this).Config;
			Log.LogInfo((object)"Loading The Vault v2.0.3");
			CreatePersistentRunner();
			try
			{
				InitializeConfig();
				_vaultManager = new VaultManager();
				_saveSystem = new VaultSaveSystem(_vaultManager);
				_staticVaultManager = _vaultManager;
				_staticSaveSystem = _saveSystem;
				GameObject val = new GameObject("TheVault_UI");
				Object.DontDestroyOnLoad((Object)(object)val);
				_vaultUI = val.AddComponent<VaultUI>();
				_vaultUI.Initialize(_vaultManager);
				_vaultUI.SetToggleKey(_toggleKey.Value, _requireCtrlModifier.Value);
				_vaultUI.SetAltToggleKey(_altToggleKey.Value);
				_staticVaultUI = _vaultUI;
				StaticToggleKey = _toggleKey.Value;
				StaticRequireCtrl = _requireCtrlModifier.Value;
				StaticAltToggleKey = _altToggleKey.Value;
				StaticHUDToggleKey = _hudToggleKey.Value;
				_vaultHUD = val.AddComponent<VaultHUD>();
				_vaultHUD.Initialize(_vaultManager);
				_vaultHUD.SetEnabled(_enableHUD.Value);
				_vaultHUD.SetPosition(ParseHUDPosition(_hudPosition.Value));
				_staticVaultHUD = _vaultHUD;
				IconCache.Initialize();
				RegisterItemMappings();
				_harmony = new Harmony("com.azraelgodking.thevault");
				ApplyPatches();
				PatchGameSave();
				SceneManager.sceneLoaded += OnSceneLoaded;
				Log.LogInfo((object)"Subscribed to SceneManager.sceneLoaded for vault loading");
				if (_checkForUpdates.Value)
				{
					VersionChecker.CheckForUpdate("com.azraelgodking.thevault", "2.0.3", Log, delegate(VersionChecker.VersionCheckResult result)
					{
						result.NotifyUpdateAvailable(Log);
					});
				}
				Log.LogInfo((object)"The Vault loaded successfully!");
				Log.LogInfo((object)string.Format("Press {0}{1} or {2} to open the vault", _requireCtrlModifier.Value ? "Ctrl+" : "", _toggleKey.Value, _altToggleKey.Value));
			}
			catch (Exception arg)
			{
				Log.LogError((object)string.Format("Failed to load {0}: {1}", "The Vault", 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("TheVault_PersistentRunner");
			Object.DontDestroyOnLoad((Object)(object)_persistentRunner);
			((Object)_persistentRunner).hideFlags = (HideFlags)61;
			_updateRunner = _persistentRunner.AddComponent<PersistentUpdateRunner>();
			Log.LogInfo((object)"Created hidden PersistentRunner that survives game cleanup");
		}

		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_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Expected O, but got Unknown
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			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("TheVault_PersistentRunner");
					Object.DontDestroyOnLoad((Object)(object)_persistentRunner);
					((Object)_persistentRunner).hideFlags = (HideFlags)61;
					_updateRunner = _persistentRunner.AddComponent<PersistentUpdateRunner>();
					ManualLogSource log2 = Log;
					if (log2 != null)
					{
						log2.LogInfo((object)"[EnsureUI] PersistentRunner recreated");
					}
				}
				if ((Object)(object)_staticVaultUI == (Object)null)
				{
					ManualLogSource log3 = Log;
					if (log3 != null)
					{
						log3.LogInfo((object)"[EnsureUI] Recreating VaultUI...");
					}
					GameObject val = new GameObject("TheVault_UI");
					Object.DontDestroyOnLoad((Object)val);
					_staticVaultUI = val.AddComponent<VaultUI>();
					_staticVaultUI.Initialize(_staticVaultManager);
					_staticVaultUI.SetToggleKey(StaticToggleKey, StaticRequireCtrl);
					_staticVaultUI.SetAltToggleKey(StaticAltToggleKey);
					_staticVaultHUD = val.AddComponent<VaultHUD>();
					_staticVaultHUD.Initialize(_staticVaultManager);
					ManualLogSource log4 = Log;
					if (log4 != null)
					{
						log4.LogInfo((object)"[EnsureUI] VaultUI and VaultHUD recreated");
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log5 = Log;
				if (log5 != null)
				{
					log5.LogError((object)("[EnsureUI] Error recreating UI: " + ex.Message));
				}
			}
		}

		private void InitializeConfig()
		{
			_toggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("UI", "ToggleKey", (KeyCode)118, "Key to toggle the vault UI");
			_requireCtrlModifier = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "RequireCtrlModifier", true, "Require Ctrl key to be held when pressing toggle key");
			_altToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("UI", "AltToggleKey", (KeyCode)289, "Alternative key to toggle vault UI (no modifier required). Useful for Steam Deck.");
			_enableHUD = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "EnableHUD", true, "Show a persistent HUD bar displaying vault currency totals");
			_hudPosition = ((BaseUnityPlugin)this).Config.Bind<string>("HUD", "Position", "TopLeft", "HUD position: TopLeft, TopCenter, TopRight, BottomLeft, BottomCenter, BottomRight");
			_hudToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("HUD", "ToggleKey", (KeyCode)288, "Key to toggle the HUD display on/off");
			_enableAutoSave = ((BaseUnityPlugin)this).Config.Bind<bool>("Saving", "EnableAutoSave", true, "Automatically save vault data periodically");
			_autoSaveInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Saving", "AutoSaveInterval", 300f, "Auto-save interval in seconds (default: 5 minutes)");
			_checkForUpdates = ((BaseUnityPlugin)this).Config.Bind<bool>("Updates", "CheckForUpdates", true, "Check for mod updates on startup");
		}

		private void RegisterItemMappings()
		{
			ItemPatches.AutoDepositEnabled = true;
			ItemPatches.RegisterItemCurrencyMapping(18020, "seasonal_Spring", autoDeposit: true);
			ItemPatches.RegisterItemCurrencyMapping(18021, "seasonal_Summer", autoDeposit: true);
			ItemPatches.RegisterItemCurrencyMapping(18022, "seasonal_Winter", autoDeposit: true);
			ItemPatches.RegisterItemCurrencyMapping(18023, "seasonal_Fall", autoDeposit: true);
			ItemPatches.RegisterItemCurrencyMapping(1251, "key_copper", autoDeposit: true);
			ItemPatches.RegisterItemCurrencyMapping(1252, "key_iron", autoDeposit: true);
			ItemPatches.RegisterItemCurrencyMapping(1253, "key_adamant", autoDeposit: true);
			ItemPatches.RegisterItemCurrencyMapping(1254, "key_mithril", autoDeposit: true);
			ItemPatches.RegisterItemCurrencyMapping(1255, "key_sunite", autoDeposit: true);
			ItemPatches.RegisterItemCurrencyMapping(1256, "key_glorite", autoDeposit: true);
			ItemPatches.RegisterItemCurrencyMapping(1257, "key_kingslostmine", autoDeposit: true);
			ItemPatches.RegisterItemCurrencyMapping(18013, "special_communitytoken", autoDeposit: true);
			ItemPatches.RegisterItemCurrencyMapping(60014, "special_doubloon", autoDeposit: true);
			ItemPatches.RegisterItemCurrencyMapping(60013, "special_blackbottlecap", autoDeposit: true);
			ItemPatches.RegisterItemCurrencyMapping(18012, "special_redcarnivalticket", autoDeposit: true);
			ItemPatches.RegisterItemCurrencyMapping(18016, "special_candycornpieces", autoDeposit: true);
			ItemPatches.RegisterItemCurrencyMapping(18015, "special_manashard", autoDeposit: true);
			Log.LogInfo((object)"Registered item-to-currency mappings with auto-deposit enabled");
		}

		private void ApplyPatches()
		{
			try
			{
				Type typeFromHandle = typeof(Player);
				PatchMethod(typeFromHandle, "InitializeAsOwner", typeof(PlayerPatches), "OnPlayerInitialized");
				Type type = AccessTools.TypeByName("Wish.ShopMenu");
				if (type != null)
				{
					PatchMethodPrefix(type, "BuyItem", typeof(ShopPatches), "OnBeforeBuyItem");
				}
				else
				{
					Log.LogWarning((object)"Could not find ShopMenu type - shop vault integration unavailable");
				}
				Type type2 = AccessTools.TypeByName("Wish.SaveLoadManager");
				if (type2 != null)
				{
					PatchMethod(type2, "Save", typeof(SaveLoadPatches), "OnGameSaved");
					PatchMethod(type2, "Load", typeof(SaveLoadPatches), "OnGameLoaded");
				}
				else
				{
					Log.LogWarning((object)"Could not find SaveLoadManager - using fallback save triggers");
				}
				Type type3 = AccessTools.TypeByName("Wish.MainMenuController");
				if (type3 != null)
				{
					PatchMethod(type3, "ReturnToMainMenu", typeof(SaveLoadPatches), "OnReturnToMenu");
				}
				Type type4 = AccessTools.TypeByName("Wish.TitleScreen");
				if (type4 != null)
				{
					PatchMethod(type4, "Start", typeof(SaveLoadPatches), "OnReturnToMenu");
				}
				Type type5 = AccessTools.TypeByName("Wish.GameManager");
				if (type5 != null)
				{
					PatchMethod(type5, "ReturnToMainMenu", typeof(SaveLoadPatches), "OnReturnToMenu");
					PatchMethod(type5, "QuitToMainMenu", typeof(SaveLoadPatches), "OnReturnToMenu");
				}
				PatchItemPickup(typeFromHandle);
				IEnumerable<MethodBase> patchedMethods = _harmony.GetPatchedMethods();
				int num = 0;
				foreach (MethodBase item in patchedMethods)
				{
					Log.LogInfo((object)("Patched: " + item.DeclaringType?.Name + "." + item.Name));
					num++;
				}
				Log.LogInfo((object)$"Total methods patched: {num}");
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Harmony patching failed: {arg}");
			}
		}

		private void PatchMethod(Type targetType, string methodName, Type patchType, string patchMethodName, Type[] parameters = null)
		{
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = ((parameters == null) ? AccessTools.Method(targetType, methodName, (Type[])null, (Type[])null) : AccessTools.Method(targetType, methodName, parameters, (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);
				if (methodInfo2 == null)
				{
					Log.LogWarning((object)("Could not find patch method " + patchType.Name + "." + patchMethodName));
					return;
				}
				_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Log.LogInfo((object)("Successfully patched " + targetType.Name + "." + methodName));
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Failed to patch " + targetType.Name + "." + methodName + ": " + ex.Message));
			}
		}

		private void PatchMethodPrefix(Type targetType, string methodName, Type patchType, string patchMethodName, Type[] parameters = null)
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = ((parameters == null) ? AccessTools.Method(targetType, methodName, (Type[])null, (Type[])null) : AccessTools.Method(targetType, methodName, parameters, (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);
				if (methodInfo2 == null)
				{
					Log.LogWarning((object)("Could not find patch method " + patchType.Name + "." + patchMethodName));
					return;
				}
				_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Log.LogInfo((object)("Successfully patched " + targetType.Name + "." + methodName + " (prefix)"));
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Failed to patch " + targetType.Name + "." + methodName + ": " + ex.Message));
			}
		}

		private void PatchGameSave()
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Expected O, but got Unknown
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Expected O, but got Unknown
			try
			{
				Type type = AccessTools.TypeByName("Wish.GameSave");
				if (type == null)
				{
					Log.LogWarning((object)"Could not find Wish.GameSave type");
					return;
				}
				MethodInfo methodInfo = AccessTools.Method(type, "Load", (Type[])null, (Type[])null);
				if (methodInfo != null)
				{
					MethodInfo methodInfo2 = AccessTools.Method(typeof(GameSavePatches), "OnGameSaveLoad", (Type[])null, (Type[])null);
					if (methodInfo2 != null)
					{
						_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						Log.LogInfo((object)"Patched GameSave.Load");
					}
				}
				MethodInfo methodInfo3 = AccessTools.Method(type, "LoadCharacter", (Type[])null, (Type[])null);
				if (methodInfo3 != null)
				{
					MethodInfo methodInfo4 = AccessTools.Method(typeof(GameSavePatches), "OnLoadCharacter", (Type[])null, (Type[])null);
					if (methodInfo4 != null)
					{
						_harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(methodInfo4), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						Log.LogInfo((object)"Patched GameSave.LoadCharacter");
					}
				}
				MethodInfo methodInfo5 = AccessTools.Method(type, "SetCurrentCharacter", (Type[])null, (Type[])null);
				if (methodInfo5 != null)
				{
					MethodInfo methodInfo6 = AccessTools.Method(typeof(GameSavePatches), "OnSetCurrentCharacter", (Type[])null, (Type[])null);
					if (methodInfo6 != null)
					{
						_harmony.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, new HarmonyMethod(methodInfo6), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						Log.LogInfo((object)"Patched GameSave.SetCurrentCharacter");
					}
				}
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Error patching GameSave: " + ex.Message));
			}
		}

		private void PatchItemPickup(Type playerType)
		{
			//IL_0398: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b9: Expected O, but got Unknown
			//IL_092f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c1a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c27: Expected O, but got Unknown
			//IL_098d: Unknown result type (might be due to invalid IL or missing references)
			//IL_099a: Expected O, but got Unknown
			//IL_0943: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c9f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0cac: Expected O, but got Unknown
			//IL_0950: Expected O, but got Unknown
			//IL_0d42: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d4f: Expected O, but got Unknown
			//IL_0acb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e16: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e1d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e2a: Expected O, but got Unknown
			//IL_0e2a: Expected O, but got Unknown
			//IL_0b47: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b54: Expected O, but got Unknown
			//IL_0adf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0aec: Expected O, but got Unknown
			Log.LogInfo((object)"Searching for item pickup methods on Player...");
			MethodInfo[] methods = playerType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo in methods)
			{
				string text = methodInfo.Name.ToLowerInvariant();
				if (text.Contains("pickup") || text.Contains("additem") || text.Contains("collect") || text.Contains("gain"))
				{
					ParameterInfo[] parameters = methodInfo.GetParameters();
					string text2 = string.Join(", ", parameters.Select((ParameterInfo p) => p.ParameterType.Name + " " + p.Name));
					Log.LogInfo((object)("  Found: " + methodInfo.Name + "(" + text2 + ") in " + methodInfo.DeclaringType.Name));
				}
			}
			string[] array = new string[12]
			{
				"Wish.ItemPickup", "Wish.DroppedItem", "Wish.Collectible", "Wish.GroundItem", "Wish.ItemEntity", "Wish.PickupItem", "Wish.WorldItem", "Wish.ItemDrop", "ItemPickup", "DroppedItem",
				"Collectible", "GroundItem"
			};
			for (int i = 0; i < array.Length; i++)
			{
				Type type = AccessTools.TypeByName(array[i]);
				if (!(type != null))
				{
					continue;
				}
				Log.LogInfo((object)("Found potential pickup class: " + type.FullName));
				methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo2 in methods)
				{
					string text3 = methodInfo2.Name.ToLowerInvariant();
					if (text3.Contains("pickup") || text3.Contains("collect") || text3.Contains("interact") || text3.Contains("onpick") || text3.Contains("trigger"))
					{
						ParameterInfo[] parameters2 = methodInfo2.GetParameters();
						string text4 = string.Join(", ", parameters2.Select((ParameterInfo p) => p.ParameterType.Name + " " + p.Name));
						Log.LogInfo((object)("  " + type.Name + "." + methodInfo2.Name + "(" + text4 + ")"));
					}
				}
			}
			MethodInfo methodInfo3 = AccessTools.Method(playerType, "Pickup", (Type[])null, (Type[])null);
			if (methodInfo3 != null)
			{
				Log.LogInfo((object)("Found Pickup method: " + methodInfo3.DeclaringType.FullName + "." + methodInfo3.Name));
				ParameterInfo[] parameters3 = methodInfo3.GetParameters();
				string text5 = string.Join(", ", parameters3.Select((ParameterInfo p) => p.ParameterType.Name + " " + p.Name));
				Log.LogInfo((object)("  Parameters: (" + text5 + ")"));
				MethodInfo methodInfo4 = AccessTools.Method(typeof(ItemPatches), "OnPlayerPickupPrefix", (Type[])null, (Type[])null);
				MethodInfo methodInfo5 = AccessTools.Method(typeof(ItemPatches), "OnPlayerPickup", (Type[])null, (Type[])null);
				if (methodInfo4 != null)
				{
					object obj = _harmony;
					object obj2 = methodInfo3;
					? val = new HarmonyMethod(methodInfo4);
					if (methodInfo5 != null)
					{
						obj = (object)new HarmonyMethod(methodInfo5);
						obj2 = (object)val;
						val = obj2;
					}
					else
					{
						obj = null;
						obj2 = (object)val;
						val = obj2;
					}
					((Harmony)obj).Patch((MethodBase)val, (HarmonyMethod)obj2, (HarmonyMethod)obj, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					Log.LogInfo((object)("Successfully patched " + playerType.Name + ".Pickup with PREFIX for auto-deposit"));
				}
			}
			else
			{
				Log.LogWarning((object)"Could not find Pickup method on Player");
			}
			Type type2 = AccessTools.TypeByName("Wish.Inventory");
			if (type2 == null)
			{
				type2 = AccessTools.TypeByName("Wish.PlayerInventory");
			}
			if (type2 != null)
			{
				Log.LogInfo((object)("Searching Inventory class: " + type2.FullName));
				MethodInfo[] methods2 = type2.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				Log.LogInfo((object)"=== Inventory methods for checking item amounts ===");
				methods = methods2;
				foreach (MethodInfo methodInfo6 in methods)
				{
					string text6 = methodInfo6.Name.ToLowerInvariant();
					if (text6.Contains("get") || text6.Contains("has") || text6.Contains("count") || text6.Contains("amount") || text6.Contains("total") || text6.Contains("contain"))
					{
						ParameterInfo[] parameters4 = methodInfo6.GetParameters();
						string text7 = string.Join(", ", parameters4.Select((ParameterInfo p) => p.ParameterType.Name + " " + p.Name));
						Log.LogInfo((object)("  " + methodInfo6.Name + "(" + text7 + ") -> " + methodInfo6.ReturnType.Name));
					}
				}
				Log.LogInfo((object)"=== Inventory AddItem methods ===");
				methods = methods2;
				foreach (MethodInfo methodInfo7 in methods)
				{
					string text8 = methodInfo7.Name.ToLowerInvariant();
					if (text8.Contains("add") && text8.Contains("item"))
					{
						ParameterInfo[] parameters5 = methodInfo7.GetParameters();
						string text9 = string.Join(", ", parameters5.Select((ParameterInfo p) => p.ParameterType.Name + " " + p.Name));
						Log.LogInfo((object)("  " + methodInfo7.Name + "(" + text9 + ") in " + methodInfo7.DeclaringType.Name));
					}
				}
				Log.LogInfo((object)"=== Inventory RemoveItem methods ===");
				methods = methods2;
				foreach (MethodInfo methodInfo8 in methods)
				{
					if (methodInfo8.Name.ToLowerInvariant().Contains("remove"))
					{
						ParameterInfo[] parameters6 = methodInfo8.GetParameters();
						string text10 = string.Join(", ", parameters6.Select((ParameterInfo p) => p.ParameterType.Name + " " + p.Name));
						Log.LogInfo((object)("  " + methodInfo8.Name + "(" + text10 + ") -> " + methodInfo8.ReturnType.Name));
					}
				}
				Log.LogInfo((object)"=== Searching for Shop/Store/Purchase types ===");
				Assembly assembly = type2.Assembly;
				Type[] types = assembly.GetTypes();
				foreach (Type type3 in types)
				{
					string text11 = type3.Name.ToLowerInvariant();
					if (text11.Contains("shop") || text11.Contains("store") || text11.Contains("purchase") || text11.Contains("buy") || text11.Contains("vendor") || text11.Contains("merchant"))
					{
						Log.LogInfo((object)("  Found type: " + type3.FullName));
					}
				}
				Log.LogInfo((object)"=== Searching for Door/Chest/Lock types ===");
				types = assembly.GetTypes();
				foreach (Type type4 in types)
				{
					string text12 = type4.Name.ToLowerInvariant();
					if (text12.Contains("door") || text12.Contains("chest") || text12.Contains("lock") || text12.Contains("treasure") || text12.Contains("gate"))
					{
						Log.LogInfo((object)("  Found type: " + type4.FullName));
					}
				}
				Type type5 = AccessTools.TypeByName("Wish.Item");
				if (type5 != null)
				{
					Log.LogInfo((object)("Found Wish.Item type: " + type5.FullName));
					MethodInfo methodInfo9 = AccessTools.Method(type2, "AddItem", new Type[6]
					{
						type5,
						typeof(int),
						typeof(int),
						typeof(bool),
						typeof(bool),
						typeof(bool)
					}, (Type[])null);
					if (methodInfo9 != null)
					{
						MethodInfo methodInfo10 = AccessTools.Method(typeof(ItemPatches), "OnInventoryAddItemObjectPrefix", (Type[])null, (Type[])null);
						MethodInfo methodInfo11 = AccessTools.Method(typeof(ItemPatches), "OnInventoryAddItemObjectPostfix", (Type[])null, (Type[])null);
						if (methodInfo10 != null)
						{
							object obj3 = _harmony;
							object obj4 = methodInfo9;
							? val2 = new HarmonyMethod(methodInfo10);
							if (methodInfo11 != null)
							{
								obj3 = (object)new HarmonyMethod(methodInfo11);
								obj4 = (object)val2;
								val2 = obj4;
							}
							else
							{
								obj3 = null;
								obj4 = (object)val2;
								val2 = obj4;
							}
							((Harmony)obj3).Patch((MethodBase)val2, (HarmonyMethod)obj4, (HarmonyMethod)obj3, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
							Log.LogInfo((object)("Successfully patched " + type2.Name + ".AddItem(Item,int,int,bool,bool,bool) with PREFIX+POSTFIX for auto-deposit"));
						}
						else if (methodInfo11 != null)
						{
							_harmony.Patch((MethodBase)methodInfo9, (HarmonyMethod)null, new HarmonyMethod(methodInfo11), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
							Log.LogInfo((object)("Successfully patched " + type2.Name + ".AddItem(Item,int,int,bool,bool,bool) with POSTFIX only for auto-deposit"));
						}
					}
					else
					{
						Log.LogWarning((object)"Could not find AddItem(Item,int,int,bool,bool,bool) method");
						methods = methods2;
						foreach (MethodInfo methodInfo12 in methods)
						{
							if (!(methodInfo12.Name == "AddItem"))
							{
								continue;
							}
							ParameterInfo[] parameters7 = methodInfo12.GetParameters();
							if (parameters7.Length == 0 || !(parameters7[0].ParameterType == type5))
							{
								continue;
							}
							string text13 = string.Join(", ", parameters7.Select((ParameterInfo p) => p.ParameterType.Name + " " + p.Name));
							Log.LogInfo((object)("Found alternative AddItem: " + methodInfo12.Name + "(" + text13 + ")"));
							MethodInfo methodInfo13 = AccessTools.Method(typeof(ItemPatches), "OnInventoryAddItemObjectPrefix", (Type[])null, (Type[])null);
							MethodInfo methodInfo14 = AccessTools.Method(typeof(ItemPatches), "OnInventoryAddItemObjectPostfix", (Type[])null, (Type[])null);
							if (methodInfo13 != null)
							{
								object obj5 = _harmony;
								object obj6 = methodInfo12;
								? val3 = new HarmonyMethod(methodInfo13);
								if (methodInfo14 != null)
								{
									obj5 = (object)new HarmonyMethod(methodInfo14);
									obj6 = (object)val3;
									val3 = obj6;
								}
								else
								{
									obj5 = null;
									obj6 = (object)val3;
									val3 = obj6;
								}
								((Harmony)obj5).Patch((MethodBase)val3, (HarmonyMethod)obj6, (HarmonyMethod)obj5, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
								Log.LogInfo((object)("Successfully patched " + type2.Name + "." + methodInfo12.Name + " with PREFIX+POSTFIX for auto-deposit"));
								break;
							}
							if (methodInfo14 != null)
							{
								_harmony.Patch((MethodBase)methodInfo12, (HarmonyMethod)null, new HarmonyMethod(methodInfo14), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
								Log.LogInfo((object)("Successfully patched " + type2.Name + "." + methodInfo12.Name + " with POSTFIX for auto-deposit"));
								break;
							}
						}
					}
				}
				else
				{
					Log.LogWarning((object)"Could not find Wish.Item type");
				}
				MethodInfo methodInfo15 = AccessTools.Method(type2, "AddItem", new Type[2]
				{
					typeof(int),
					typeof(int)
				}, (Type[])null);
				if (methodInfo15 != null)
				{
					MethodInfo methodInfo16 = AccessTools.Method(typeof(ItemPatches), "OnInventoryAddItem", (Type[])null, (Type[])null);
					if (methodInfo16 != null)
					{
						_harmony.Patch((MethodBase)methodInfo15, (HarmonyMethod)null, new HarmonyMethod(methodInfo16), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						Log.LogInfo((object)("Successfully patched " + type2.Name + ".AddItem(int,int) for auto-deposit"));
					}
				}
				MethodInfo methodInfo17 = AccessTools.Method(type2, "GetAmount", new Type[1] { typeof(int) }, (Type[])null);
				if (methodInfo17 != null)
				{
					MethodInfo methodInfo18 = AccessTools.Method(typeof(ItemPatches), "OnInventoryGetAmount", (Type[])null, (Type[])null);
					if (methodInfo18 != null)
					{
						_harmony.Patch((MethodBase)methodInfo17, (HarmonyMethod)null, new HarmonyMethod(methodInfo18), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						Log.LogInfo((object)("Successfully patched " + type2.Name + ".GetAmount for vault integration"));
					}
				}
				else
				{
					Log.LogWarning((object)"Could not find Inventory.GetAmount method");
				}
				MethodInfo methodInfo19 = AccessTools.Method(type2, "HasEnough", new Type[2]
				{
					typeof(int),
					typeof(int)
				}, (Type[])null);
				if (methodInfo19 != null)
				{
					MethodInfo methodInfo20 = AccessTools.Method(typeof(ItemPatches), "OnInventoryHasEnough", (Type[])null, (Type[])null);
					if (methodInfo20 != null)
					{
						_harmony.Patch((MethodBase)methodInfo19, (HarmonyMethod)null, new HarmonyMethod(methodInfo20), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						Log.LogInfo((object)("Successfully patched " + type2.Name + ".HasEnough for vault integration"));
					}
				}
				else
				{
					Log.LogWarning((object)"Could not find Inventory.HasEnough method");
				}
				MethodInfo methodInfo21 = AccessTools.Method(type2, "RemoveItem", new Type[3]
				{
					typeof(int),
					typeof(int),
					typeof(int)
				}, (Type[])null);
				if (methodInfo21 != null)
				{
					MethodInfo methodInfo22 = AccessTools.Method(typeof(ItemPatches), "OnInventoryRemoveItemPrefix", (Type[])null, (Type[])null);
					MethodInfo methodInfo23 = AccessTools.Method(typeof(ItemPatches), "OnInventoryRemoveItemPostfix", (Type[])null, (Type[])null);
					if (methodInfo22 != null && methodInfo23 != null)
					{
						_harmony.Patch((MethodBase)methodInfo21, new HarmonyMethod(methodInfo22), new HarmonyMethod(methodInfo23), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						Log.LogInfo((object)("Successfully patched " + type2.Name + ".RemoveItem for vault integration"));
					}
				}
				else
				{
					Log.LogWarning((object)"Could not find Inventory.RemoveItem method");
				}
			}
			else
			{
				Log.LogWarning((object)"Could not find Inventory type");
			}
		}

		private void Update()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if (_enableAutoSave.Value)
			{
				_saveSystem?.CheckAutoSave();
			}
			if (Input.GetKeyDown(_hudToggleKey.Value))
			{
				_vaultHUD?.Toggle();
			}
			_sceneCheckTimer += Time.deltaTime;
			if (_sceneCheckTimer >= 0.5f)
			{
				_sceneCheckTimer = 0f;
				CheckForMenuSceneChange();
			}
			_heartbeatTimer += Time.deltaTime;
			if (_heartbeatTimer >= 30f)
			{
				_heartbeatTimer = 0f;
				_heartbeatCount++;
				Log.LogInfo((object)string.Format("[Heartbeat #{0}] Plugin alive. Scene: {1}, VaultLoaded: {2}, Character: {3}", _heartbeatCount, _lastKnownScene, PlayerPatches.IsVaultLoaded, PlayerPatches.LoadedCharacterName ?? "none"));
			}
		}

		private void CheckForMenuSceneChange()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Scene activeScene = SceneManager.GetActiveScene();
				string name = ((Scene)(ref activeScene)).name;
				if (name != _lastKnownScene)
				{
					Log.LogInfo((object)("[ScenePoll] Scene changed: '" + _lastKnownScene + "' -> '" + name + "'"));
					_lastKnownScene = name;
					string text = name.ToLowerInvariant();
					bool flag = text.Contains("menu") || text.Contains("title");
					if (flag && !_wasInMenuScene)
					{
						Log.LogInfo((object)("[ScenePoll] Menu scene detected via polling: " + name));
						PlayerPatches.SaveAndReset();
					}
					_wasInMenuScene = flag;
				}
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Error in CheckForMenuSceneChange: " + ex.Message));
			}
		}

		private static VaultHUD.HUDPosition ParseHUDPosition(string position)
		{
			return position?.ToLower() switch
			{
				"topleft" => VaultHUD.HUDPosition.TopLeft, 
				"topcenter" => VaultHUD.HUDPosition.TopCenter, 
				"topright" => VaultHUD.HUDPosition.TopRight, 
				"bottomleft" => VaultHUD.HUDPosition.BottomLeft, 
				"bottomcenter" => VaultHUD.HUDPosition.BottomCenter, 
				"bottomright" => VaultHUD.HUDPosition.BottomRight, 
				_ => VaultHUD.HUDPosition.TopLeft, 
			};
		}

		private void OnApplicationQuit()
		{
			Log.LogInfo((object)"Application quitting - saving vault data");
			_saveSystem?.ForceSave();
		}

		private void OnDisable()
		{
			Log.LogWarning((object)"[CRITICAL] Plugin OnDisable called! Plugin is being disabled.");
			Log.LogWarning((object)("[CRITICAL] Last known scene: " + _lastKnownScene));
			Log.LogWarning((object)("[CRITICAL] Stack trace: " + Environment.StackTrace));
		}

		private void OnDestroy()
		{
			Log.LogWarning((object)"[CRITICAL] Plugin OnDestroy called! Plugin is being destroyed.");
			Log.LogWarning((object)("[CRITICAL] Last known scene: " + _lastKnownScene));
			Log.LogWarning((object)("[CRITICAL] Stack trace: " + Environment.StackTrace));
			SceneManager.sceneLoaded -= OnSceneLoaded;
			_saveSystem?.ForceSave();
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Log.LogInfo((object)$"[SceneChange] Scene loaded: '{((Scene)(ref scene)).name}' (mode: {mode})");
				string text = ((Scene)(ref scene)).name.ToLowerInvariant();
				if (text.Contains("menu") || text.Contains("title"))
				{
					Log.LogInfo((object)("Menu scene detected: " + ((Scene)(ref scene)).name));
					PlayerPatches.SaveAndReset();
				}
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Error in OnSceneLoaded: " + ex.Message));
			}
		}

		public static VaultManager GetVaultManager()
		{
			return _staticVaultManager;
		}

		public static VaultSaveSystem GetSaveSystem()
		{
			return _staticSaveSystem;
		}

		public static VaultUI GetVaultUI()
		{
			return _staticVaultUI;
		}

		public static void OpenVault()
		{
			_staticVaultUI?.Show();
		}

		public static void CloseVault()
		{
			_staticVaultUI?.Hide();
		}

		public static void LoadVaultForPlayer(string playerName)
		{
			_staticSaveSystem?.Load(playerName);
		}

		public static void SaveVault()
		{
			_staticSaveSystem?.ForceSave();
		}

		public static VaultHUD GetVaultHUD()
		{
			return _staticVaultHUD;
		}

		public static void ToggleHUD()
		{
			_staticVaultHUD?.Toggle();
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "com.azraelgodking.thevault";

		public const string PLUGIN_NAME = "The Vault";

		public const string PLUGIN_VERSION = "2.0.3";
	}
	public class PersistentUpdateRunner : MonoBehaviour
	{
		private string _lastKnownScene = "";

		private bool _wasInMenuScene = true;

		private float _sceneCheckTimer;

		private float _heartbeatTimer;

		private int _heartbeatCount;

		private const float SCENE_CHECK_INTERVAL = 0.5f;

		private const float HEARTBEAT_INTERVAL = 30f;

		private void Awake()
		{
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)"[PersistentRunner] Created hidden persistent runner");
			}
		}

		private void Update()
		{
			_sceneCheckTimer += Time.deltaTime;
			if (_sceneCheckTimer >= 0.5f)
			{
				_sceneCheckTimer = 0f;
				CheckForMenuSceneChange();
			}
			_heartbeatTimer += Time.deltaTime;
			if (_heartbeatTimer >= 30f)
			{
				_heartbeatTimer = 0f;
				_heartbeatCount++;
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)string.Format("[PersistentRunner Heartbeat #{0}] Scene: {1}, VaultLoaded: {2}, Character: {3}", _heartbeatCount, _lastKnownScene, PlayerPatches.IsVaultLoaded, PlayerPatches.LoadedCharacterName ?? "none"));
				}
			}
			CheckHotkeys();
		}

		private void CheckHotkeys()
		{
			//IL_0048: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				VaultUI vaultUI = Plugin.GetVaultUI();
				if (!((Object)(object)vaultUI == (Object)null))
				{
					if ((!Plugin.StaticRequireCtrl || Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305)) && Input.GetKeyDown(Plugin.StaticToggleKey))
					{
						vaultUI.Toggle();
					}
					if ((int)Plugin.StaticAltToggleKey != 0 && Input.GetKeyDown(Plugin.StaticAltToggleKey))
					{
						vaultUI.Toggle();
					}
					if (Input.GetKeyDown(Plugin.StaticHUDToggleKey))
					{
						Plugin.GetVaultHUD()?.Toggle();
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)("[PersistentRunner] Hotkey error: " + ex.Message));
				}
			}
		}

		private void CheckForMenuSceneChange()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Scene activeScene = SceneManager.GetActiveScene();
				string name = ((Scene)(ref activeScene)).name;
				if (!(name != _lastKnownScene))
				{
					return;
				}
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)("[PersistentRunner] Scene changed: '" + _lastKnownScene + "' -> '" + name + "'"));
				}
				_lastKnownScene = name;
				string text = name.ToLowerInvariant();
				bool flag = text.Contains("menu") || text.Contains("title");
				if (flag && !_wasInMenuScene)
				{
					ManualLogSource log2 = Plugin.Log;
					if (log2 != null)
					{
						log2.LogInfo((object)("[PersistentRunner] Menu scene detected: " + name));
					}
					PlayerPatches.SaveAndReset();
				}
				_wasInMenuScene = flag;
			}
			catch (Exception ex)
			{
				ManualLogSource log3 = Plugin.Log;
				if (log3 != null)
				{
					log3.LogError((object)("[PersistentRunner] Error: " + ex.Message));
				}
			}
		}

		private void OnDestroy()
		{
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogWarning((object)"[PersistentRunner] OnDestroy called - this should NOT happen!");
			}
		}
	}
	public static class SecretGifts
	{
		private static readonly HashSet<string> _eligibleSteamIdHashes = new HashSet<string> { "Tr4eyf86yKRu6fhNQjQOrO/ZnwasQaY/fgKV0PcnoGA=", "zAKJKUjJVGiQRm+4gCGcMZqq1sF8vQZT7bhd+r0Q0kw=" };

		private const int TREASURE_CHEST_ITEM_ID = 3789;

		private const int GIFT_QUANTITY = 10;

		private const string ENCRYPTION_SALT = "SecretG1fts_S@lt2026_Secure";

		private const int KEY_SIZE = 256;

		private const int ITERATIONS = 10000;

		private static readonly byte[] _iv = new byte[16]
		{
			83, 101, 99, 114, 101, 116, 71, 105, 102, 116,
			115, 73, 86, 48, 48, 49
		};

		private const string FILE_HEADER = "SCRTGIFT";

		private static string _currentSteamId;

		private static bool _giftCheckPerformed;

		private static bool _dataLoaded;

		private static HashSet<string> _giftRecipients = new HashSet<string>();

		public static void CheckAndGiveFirstOpenGift(string characterName)
		{
			if (_giftCheckPerformed)
			{
				return;
			}
			_giftCheckPerformed = true;
			try
			{
				_currentSteamId = TryGetSteamId();
				if (string.IsNullOrEmpty(_currentSteamId))
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogInfo((object)"[SecretGifts] Could not retrieve Steam ID");
					}
					return;
				}
				if (!_dataLoaded)
				{
					LoadGiftRecipients();
					_dataLoaded = true;
				}
				string text = ComputeHash(_currentSteamId);
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogInfo((object)("[SecretGifts] Steam hash: " + text));
				}
				if (!_eligibleSteamIdHashes.Contains(text))
				{
					ManualLogSource log3 = Plugin.Log;
					if (log3 != null)
					{
						log3.LogInfo((object)"[SecretGifts] User not eligible for secret gift");
					}
					return;
				}
				if (HasReceivedGift(characterName))
				{
					ManualLogSource log4 = Plugin.Log;
					if (log4 != null)
					{
						log4.LogInfo((object)("[SecretGifts] " + characterName + " has already received the secret gift"));
					}
					return;
				}
				ManualLogSource log5 = Plugin.Log;
				if (log5 != null)
				{
					log5.LogInfo((object)("[SecretGifts] Giving secret gift to " + characterName + "!"));
				}
				if (SpawnItems(3789, 10))
				{
					MarkGiftReceived(characterName);
					ManualLogSource log6 = Plugin.Log;
					if (log6 != null)
					{
						log6.LogInfo((object)$"[SecretGifts] Successfully gave {10} treasure chests to {characterName}!");
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log7 = Plugin.Log;
				if (log7 != null)
				{
					log7.LogError((object)("[SecretGifts] Error: " + ex.Message));
				}
			}
		}

		public static void ResetGiftCheck()
		{
			_giftCheckPerformed = false;
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)$"[SecretGifts] Reset for character switch. {_giftRecipients.Count} gift records in memory.");
			}
		}

		private static bool SpawnItems(int itemId, int amount)
		{
			try
			{
				Player instance = Player.Instance;
				if ((Object)(object)instance == (Object)null || (Object)(object)instance.Inventory == (Object)null)
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogWarning((object)"[SecretGifts] Player or inventory not available");
					}
					return false;
				}
				Inventory inventory = instance.Inventory;
				MethodInfo methodInfo = AccessTools.Method(((object)inventory).GetType(), "AddItem", new Type[3]
				{
					typeof(int),
					typeof(int),
					typeof(bool)
				}, (Type[])null);
				if (methodInfo != null)
				{
					methodInfo.Invoke(inventory, new object[3] { itemId, amount, true });
					return true;
				}
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)"[SecretGifts] Could not find AddItem method");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log3 = Plugin.Log;
				if (log3 != null)
				{
					log3.LogError((object)("[SecretGifts] Spawn error: " + ex.Message));
				}
			}
			return false;
		}

		private static string GetSaveDirectory()
		{
			return Path.Combine(Paths.ConfigPath, "TheVault", "Saves");
		}

		private static string GetGiftTrackingFilePath()
		{
			return Path.Combine(GetSaveDirectory(), "SecretGifts.dat");
		}

		private static string GetBackupFilePath()
		{
			return Path.Combine(GetSaveDirectory(), "SecretGifts.dat.backup");
		}

		private static void LoadGiftRecipients()
		{
			try
			{
				string giftTrackingFilePath = GetGiftTrackingFilePath();
				string backupFilePath = GetBackupFilePath();
				if (File.Exists(giftTrackingFilePath) && TryLoadFromFile(giftTrackingFilePath))
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogInfo((object)$"[SecretGifts] Loaded {_giftRecipients.Count} gift records");
					}
					return;
				}
				if (File.Exists(backupFilePath))
				{
					ManualLogSource log2 = Plugin.Log;
					if (log2 != null)
					{
						log2.LogInfo((object)"[SecretGifts] Main file failed, trying backup...");
					}
					if (TryLoadFromFile(backupFilePath))
					{
						ManualLogSource log3 = Plugin.Log;
						if (log3 != null)
						{
							log3.LogInfo((object)$"[SecretGifts] Restored {_giftRecipients.Count} gift records from backup");
						}
						SaveGiftRecipients();
						return;
					}
				}
				_giftRecipients = new HashSet<string>();
				ManualLogSource log4 = Plugin.Log;
				if (log4 != null)
				{
					log4.LogInfo((object)"[SecretGifts] No existing gift records found, starting fresh");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log5 = Plugin.Log;
				if (log5 != null)
				{
					log5.LogWarning((object)("[SecretGifts] Error loading gift records: " + ex.Message));
				}
				_giftRecipients = new HashSet<string>();
			}
		}

		private static bool TryLoadFromFile(string filePath)
		{
			try
			{
				string text = Decrypt(File.ReadAllBytes(filePath));
				if (string.IsNullOrEmpty(text))
				{
					return false;
				}
				_giftRecipients = new HashSet<string>();
				string[] array = text.Split(new char[2] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
				foreach (string text2 in array)
				{
					if (!string.IsNullOrWhiteSpace(text2))
					{
						_giftRecipients.Add(text2.Trim());
					}
				}
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static void SaveGiftRecipients()
		{
			try
			{
				string giftTrackingFilePath = GetGiftTrackingFilePath();
				string backupFilePath = GetBackupFilePath();
				string saveDirectory = GetSaveDirectory();
				if (!Directory.Exists(saveDirectory))
				{
					Directory.CreateDirectory(saveDirectory);
				}
				byte[] bytes = Encrypt(string.Join("\n", _giftRecipients));
				string text = giftTrackingFilePath + ".tmp";
				File.WriteAllBytes(text, bytes);
				if (File.Exists(giftTrackingFilePath))
				{
					if (File.Exists(backupFilePath))
					{
						File.Delete(backupFilePath);
					}
					File.Move(giftTrackingFilePath, backupFilePath);
				}
				File.Move(text, giftTrackingFilePath);
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)$"[SecretGifts] Saved {_giftRecipients.Count} gift records (encrypted)");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("[SecretGifts] Error saving gift records: " + ex.Message));
				}
			}
		}

		private static bool HasReceivedGift(string characterName)
		{
			string item = _currentSteamId + ":" + characterName;
			return _giftRecipients.Contains(item);
		}

		private static void MarkGiftReceived(string characterName)
		{
			string item = _currentSteamId + ":" + characterName;
			_giftRecipients.Add(item);
			SaveGiftRecipients();
		}

		private static byte[] GenerateKey()
		{
			string text = ((!string.IsNullOrEmpty(_currentSteamId)) ? ("Steam_" + _currentSteamId) : "DefaultKey");
			using Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes("SecretG1fts_S@lt2026_Secure_" + text + "_SecretGiftsKey", Encoding.UTF8.GetBytes("SecretG1fts_S@lt2026_Secure"), 10000);
			return rfc2898DeriveBytes.GetBytes(32);
		}

		private static byte[] Encrypt(string plainText)
		{
			byte[] key = GenerateKey();
			using Aes aes = Aes.Create();
			aes.Key = key;
			aes.IV = _iv;
			aes.Mode = CipherMode.CBC;
			aes.Padding = PaddingMode.PKCS7;
			using ICryptoTransform transform = aes.CreateEncryptor();
			using MemoryStream memoryStream = new MemoryStream();
			byte[] bytes = Encoding.UTF8.GetBytes("SCRTGIFT");
			memoryStream.Write(bytes, 0, bytes.Length);
			using (CryptoStream stream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write))
			{
				using StreamWriter streamWriter = new StreamWriter(stream, Encoding.UTF8);
				streamWriter.Write(plainText);
			}
			return memoryStream.ToArray();
		}

		private static string Decrypt(byte[] cipherData)
		{
			try
			{
				if (cipherData.Length < "SCRTGIFT".Length)
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogWarning((object)"[SecretGifts] File too small, may be corrupted");
					}
					return null;
				}
				if (Encoding.UTF8.GetString(cipherData, 0, "SCRTGIFT".Length) != "SCRTGIFT")
				{
					ManualLogSource log2 = Plugin.Log;
					if (log2 != null)
					{
						log2.LogInfo((object)"[SecretGifts] Detected legacy unencrypted file, will re-encrypt on save");
					}
					return Encoding.UTF8.GetString(cipherData);
				}
				byte[] key = GenerateKey();
				using Aes aes = Aes.Create();
				aes.Key = key;
				aes.IV = _iv;
				aes.Mode = CipherMode.CBC;
				aes.Padding = PaddingMode.PKCS7;
				using ICryptoTransform transform = aes.CreateDecryptor();
				using MemoryStream stream = new MemoryStream(cipherData, "SCRTGIFT".Length, cipherData.Length - "SCRTGIFT".Length);
				using CryptoStream stream2 = new CryptoStream(stream, transform, CryptoStreamMode.Read);
				using StreamReader streamReader = new StreamReader(stream2, Encoding.UTF8);
				return streamReader.ReadToEnd();
			}
			catch (CryptographicException ex)
			{
				ManualLogSource log3 = Plugin.Log;
				if (log3 != null)
				{
					log3.LogError((object)("[SecretGifts] Decryption failed: " + ex.Message));
				}
				return null;
			}
			catch (Exception ex2)
			{
				ManualLogSource log4 = Plugin.Log;
				if (log4 != null)
				{
					log4.LogError((object)("[SecretGifts] Error decrypting: " + ex2.Message));
				}
				return null;
			}
		}

		private static string TryGetSteamId()
		{
			try
			{
				Assembly assembly = null;
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly2 in assemblies)
				{
					string name = assembly2.GetName().Name;
					if (name.Contains("rlabrecque") || name == "Steamworks.NET")
					{
						assembly = assembly2;
						break;
					}
				}
				if (assembly == null)
				{
					assemblies = AppDomain.CurrentDomain.GetAssemblies();
					foreach (Assembly assembly3 in assemblies)
					{
						try
						{
							if (assembly3.GetType("Steamworks.SteamUser") != null)
							{
								assembly = assembly3;
								break;
							}
						}
						catch
						{
						}
					}
				}
				if (assembly == null)
				{
					return null;
				}
				Type type = assembly.GetType("Steamworks.SteamUser");
				if (type == null)
				{
					return null;
				}
				MethodInfo method = type.GetMethod("GetSteamID", BindingFlags.Static | BindingFlags.Public);
				if (method == null)
				{
					return null;
				}
				object obj2 = method.Invoke(null, null);
				if (obj2 == null)
				{
					return null;
				}
				string text = obj2.ToString();
				if (string.IsNullOrEmpty(text) || text == "0" || text.Length < 10)
				{
					return null;
				}
				return text;
			}
			catch
			{
				return null;
			}
		}

		private static string ComputeHash(string input)
		{
			using SHA256 sHA = SHA256.Create();
			return Convert.ToBase64String(sHA.ComputeHash(Encoding.UTF8.GetBytes(input)));
		}
	}
}
namespace TheVault.Vault
{
	[Serializable]
	public class VaultData
	{
		public int Version { get; set; } = 1;


		public Dictionary<SeasonalTokenType, int> SeasonalTokens { get; set; }

		public Dictionary<string, int> CommunityTokens { get; set; }

		public Dictionary<string, int> Keys { get; set; }

		public Dictionary<string, int> CustomCurrencies { get; set; }

		public Dictionary<string, int> Tickets { get; set; }

		public Dictionary<string, int> Orbs { get; set; }

		public DateTime LastSaved { get; set; }

		public string PlayerName { get; set; }

		public VaultData()
		{
			SeasonalTokens = new Dictionary<SeasonalTokenType, int>();
			CommunityTokens = new Dictionary<string, int>();
			Keys = new Dictionary<string, int>();
			CustomCurrencies = new Dictionary<string, int>();
			Tickets = new Dictionary<string, int>();
			Orbs = new Dictionary<string, int>();
			LastSaved = DateTime.Now;
			PlayerName = "";
			foreach (SeasonalTokenType value in Enum.GetValues(typeof(SeasonalTokenType)))
			{
				SeasonalTokens[value] = 0;
			}
		}

		public VaultData Clone()
		{
			return new VaultData
			{
				Version = Version,
				LastSaved = LastSaved,
				PlayerName = PlayerName,
				SeasonalTokens = new Dictionary<SeasonalTokenType, int>(SeasonalTokens),
				CommunityTokens = new Dictionary<string, int>(CommunityTokens),
				Keys = new Dictionary<string, int>(Keys),
				CustomCurrencies = new Dictionary<string, int>(CustomCurrencies),
				Tickets = new Dictionary<string, int>(Tickets),
				Orbs = new Dictionary<string, int>(Orbs)
			};
		}
	}
	public enum SeasonalTokenType
	{
		Spring,
		Summer,
		Fall,
		Winter,
		Anniversary,
		Special
	}
	public class CurrencyDefinition
	{
		public string Id { get; set; }

		public string DisplayName { get; set; }

		public string Description { get; set; }

		public CurrencyCategory Category { get; set; }

		public string IconPath { get; set; }

		public int GameItemId { get; set; }

		public CurrencyDefinition(string id, string displayName, CurrencyCategory category, int gameItemId = -1)
		{
			Id = id;
			DisplayName = displayName;
			Category = category;
			GameItemId = gameItemId;
			Description = "";
			IconPath = "";
		}
	}
	public enum CurrencyCategory
	{
		SeasonalToken,
		CommunityToken,
		Key,
		Special,
		Orb,
		Custom
	}
	public class VaultManager
	{
		private VaultData _vaultData;

		private Dictionary<string, CurrencyDefinition> _currencyDefinitions;

		private bool _isDirty;

		public bool IsDirty => _isDirty;

		public event Action<string, int, int> OnCurrencyChanged;

		public event Action OnVaultLoaded;

		public VaultManager()
		{
			_vaultData = new VaultData();
			_currencyDefinitions = new Dictionary<string, CurrencyDefinition>();
			_isDirty = false;
			InitializeCurrencyDefinitions();
		}

		private void InitializeCurrencyDefinitions()
		{
			RegisterCurrency(new CurrencyDefinition("token_spring", "Spring Token", CurrencyCategory.SeasonalToken, 18020));
			RegisterCurrency(new CurrencyDefinition("token_summer", "Summer Token", CurrencyCategory.SeasonalToken, 18021));
			RegisterCurrency(new CurrencyDefinition("token_fall", "Fall Token", CurrencyCategory.SeasonalToken, 18023));
			RegisterCurrency(new CurrencyDefinition("token_winter", "Winter Token", CurrencyCategory.SeasonalToken, 18022));
			RegisterCurrency(new CurrencyDefinition("key_copper", "Copper Key", CurrencyCategory.Key, 1251));
			RegisterCurrency(new CurrencyDefinition("key_iron", "Iron Key", CurrencyCategory.Key, 1252));
			RegisterCurrency(new CurrencyDefinition("key_adamant", "Adamant Key", CurrencyCategory.Key, 1253));
			RegisterCurrency(new CurrencyDefinition("key_mithril", "Mithril Key", CurrencyCategory.Key, 1254));
			RegisterCurrency(new CurrencyDefinition("key_sunite", "Sunite Key", CurrencyCategory.Key, 1255));
			RegisterCurrency(new CurrencyDefinition("key_glorite", "Glorite Key", CurrencyCategory.Key, 1256));
			RegisterCurrency(new CurrencyDefinition("key_kingslostmine", "King's Lost Mine Key", CurrencyCategory.Key, 1257));
			RegisterCurrency(new CurrencyDefinition("special_communitytoken", "Community Token", CurrencyCategory.Special, 18013));
			RegisterCurrency(new CurrencyDefinition("special_doubloon", "Doubloon", CurrencyCategory.Special, 60014));
			RegisterCurrency(new CurrencyDefinition("special_blackbottlecap", "Black Bottle Cap", CurrencyCategory.Special, 60013));
			RegisterCurrency(new CurrencyDefinition("special_redcarnivalticket", "Red Carnival Ticket", CurrencyCategory.Special, 18012));
			RegisterCurrency(new CurrencyDefinition("special_candycornpieces", "Candy Corn Pieces", CurrencyCategory.Special, 18016));
			RegisterCurrency(new CurrencyDefinition("special_manashard", "Mana Shard", CurrencyCategory.Special, 18015));
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)$"Initialized {_currencyDefinitions.Count} currency definitions");
			}
		}

		public void RegisterCurrency(CurrencyDefinition definition)
		{
			_currencyDefinitions[definition.Id] = definition;
		}

		public CurrencyDefinition GetCurrencyDefinition(string currencyId)
		{
			if (!_currencyDefinitions.TryGetValue(currencyId, out var value))
			{
				return null;
			}
			return value;
		}

		public CurrencyDefinition GetCurrencyByGameItemId(int gameItemId)
		{
			foreach (CurrencyDefinition value in _currencyDefinitions.Values)
			{
				if (value.GameItemId == gameItemId)
				{
					return value;
				}
			}
			return null;
		}

		public IEnumerable<CurrencyDefinition> GetAllCurrencies()
		{
			return _currencyDefinitions.Values;
		}

		public IEnumerable<CurrencyDefinition> GetCurrenciesByCategory(CurrencyCategory category)
		{
			foreach (KeyValuePair<string, CurrencyDefinition> currencyDefinition in _currencyDefinitions)
			{
				if (currencyDefinition.Value.Category == category)
				{
					yield return currencyDefinition.Value;
				}
			}
		}

		public void LoadVaultData(VaultData data)
		{
			_vaultData = data ?? new VaultData();
			_isDirty = false;
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)("Vault data loaded for player: " + _vaultData.PlayerName));
			}
			this.OnVaultLoaded?.Invoke();
		}

		public VaultData GetVaultData()
		{
			_vaultData.LastSaved = DateTime.Now;
			return _vaultData;
		}

		public void MarkClean()
		{
			_isDirty = false;
		}

		public void SetPlayerName(string playerName)
		{
			_vaultData.PlayerName = playerName;
			_isDirty = true;
		}

		public int GetSeasonalTokens(SeasonalTokenType type)
		{
			if (!_vaultData.SeasonalTokens.TryGetValue(type, out var value))
			{
				return 0;
			}
			return value;
		}

		public bool AddSeasonalTokens(SeasonalTokenType type, int amount)
		{
			if (amount < 0)
			{
				return false;
			}
			int seasonalTokens = GetSeasonalTokens(type);
			_vaultData.SeasonalTokens[type] = seasonalTokens + amount;
			_isDirty = true;
			this.OnCurrencyChanged?.Invoke($"seasonal_{type}", seasonalTokens, seasonalTokens + amount);
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)$"Added {amount} {type} tokens. New total: {_vaultData.SeasonalTokens[type]}");
			}
			return true;
		}

		public bool RemoveSeasonalTokens(SeasonalTokenType type, int amount)
		{
			if (amount < 0)
			{
				return false;
			}
			int seasonalTokens = GetSeasonalTokens(type);
			if (seasonalTokens < amount)
			{
				return false;
			}
			int arg = seasonalTokens;
			_vaultData.SeasonalTokens[type] = seasonalTokens - amount;
			_isDirty = true;
			this.OnCurrencyChanged?.Invoke($"seasonal_{type}", arg, seasonalTokens - amount);
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)$"Removed {amount} {type} tokens. New total: {_vaultData.SeasonalTokens[type]}");
			}
			return true;
		}

		public bool HasSeasonalTokens(SeasonalTokenType type, int amount)
		{
			return GetSeasonalTokens(type) >= amount;
		}

		public int GetCommunityTokens(string tokenId)
		{
			if (!_vaultData.CommunityTokens.TryGetValue(tokenId, out var value))
			{
				return 0;
			}
			return value;
		}

		public bool AddCommunityTokens(string tokenId, int amount)
		{
			if (amount < 0 || string.IsNullOrEmpty(tokenId))
			{
				return false;
			}
			int communityTokens = GetCommunityTokens(tokenId);
			_vaultData.CommunityTokens[tokenId] = communityTokens + amount;
			_isDirty = true;
			this.OnCurrencyChanged?.Invoke("community_" + tokenId, communityTokens, communityTokens + amount);
			return true;
		}

		public bool RemoveCommunityTokens(string tokenId, int amount)
		{
			if (amount < 0 || string.IsNullOrEmpty(tokenId))
			{
				return false;
			}
			int communityTokens = GetCommunityTokens(tokenId);
			if (communityTokens < amount)
			{
				return false;
			}
			int arg = communityTokens;
			_vaultData.CommunityTokens[tokenId] = communityTokens - amount;
			_isDirty = true;
			this.OnCurrencyChanged?.Invoke("community_" + tokenId, arg, communityTokens - amount);
			return true;
		}

		public bool HasCommunityTokens(string tokenId, int amount)
		{
			return GetCommunityTokens(tokenId) >= amount;
		}

		public int GetKeys(string keyId)
		{
			if (!_vaultData.Keys.TryGetValue(keyId, out var value))
			{
				return 0;
			}
			return value;
		}

		public bool AddKeys(string keyId, int amount)
		{
			if (amount < 0 || string.IsNullOrEmpty(keyId))
			{
				return false;
			}
			int keys = GetKeys(keyId);
			_vaultData.Keys[keyId] = keys + amount;
			_isDirty = true;
			this.OnCurrencyChanged?.Invoke("key_" + keyId, keys, keys + amount);
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)$"Added {amount} {keyId} keys. New total: {_vaultData.Keys[keyId]}");
			}
			return true;
		}

		public bool RemoveKeys(string keyId, int amount)
		{
			if (amount < 0 || string.IsNullOrEmpty(keyId))
			{
				return false;
			}
			int keys = GetKeys(keyId);
			if (keys < amount)
			{
				return false;
			}
			int arg = keys;
			_vaultData.Keys[keyId] = keys - amount;
			_isDirty = true;
			this.OnCurrencyChanged?.Invoke("key_" + keyId, arg, keys - amount);
			return true;
		}

		public bool HasKeys(string keyId, int amount)
		{
			return GetKeys(keyId) >= amount;
		}

		public int GetSpecial(string specialId)
		{
			if (!_vaultData.Tickets.TryGetValue(specialId, out var value))
			{
				return 0;
			}
			return value;
		}

		public bool AddSpecial(string specialId, int amount)
		{
			if (amount < 0 || string.IsNullOrEmpty(specialId))
			{
				return false;
			}
			int special = GetSpecial(specialId);
			_vaultData.Tickets[specialId] = special + amount;
			_isDirty = true;
			this.OnCurrencyChanged?.Invoke("special_" + specialId, special, special + amount);
			return true;
		}

		public bool RemoveSpecial(string specialId, int amount)
		{
			if (amount < 0 || string.IsNullOrEmpty(specialId))
			{
				return false;
			}
			int special = GetSpecial(specialId);
			if (special < amount)
			{
				return false;
			}
			int arg = special;
			_vaultData.Tickets[specialId] = special - amount;
			_isDirty = true;
			this.OnCurrencyChanged?.Invoke("special_" + specialId, arg, special - amount);
			return true;
		}

		public bool HasSpecial(string specialId, int amount)
		{
			return GetSpecial(specialId) >= amount;
		}

		public int GetTickets(string ticketId)
		{
			return GetSpecial(ticketId);
		}

		public bool AddTickets(string ticketId, int amount)
		{
			return AddSpecial(ticketId, amount);
		}

		public bool RemoveTickets(string ticketId, int amount)
		{
			return RemoveSpecial(ticketId, amount);
		}

		public bool HasTickets(string ticketId, int amount)
		{
			return HasSpecial(ticketId, amount);
		}

		public int GetOrbs(string orbId)
		{
			if (!_vaultData.Orbs.TryGetValue(orbId, out var value))
			{
				return 0;
			}
			return value;
		}

		public bool AddOrbs(string orbId, int amount)
		{
			if (amount < 0 || string.IsNullOrEmpty(orbId))
			{
				return false;
			}
			int orbs = GetOrbs(orbId);
			_vaultData.Orbs[orbId] = orbs + amount;
			_isDirty = true;
			this.OnCurrencyChanged?.Invoke("orb_" + orbId, orbs, orbs + amount);
			return true;
		}

		public bool RemoveOrbs(string orbId, int amount)
		{
			if (amount < 0 || string.IsNullOrEmpty(orbId))
			{
				return false;
			}
			int orbs = GetOrbs(orbId);
			if (orbs < amount)
			{
				return false;
			}
			int arg = orbs;
			_vaultData.Orbs[orbId] = orbs - amount;
			_isDirty = true;
			this.OnCurrencyChanged?.Invoke("orb_" + orbId, arg, orbs - amount);
			return true;
		}

		public bool HasOrbs(string orbId, int amount)
		{
			return GetOrbs(orbId) >= amount;
		}

		public int GetCustomCurrency(string currencyId)
		{
			if (!_vaultData.CustomCurrencies.TryGetValue(currencyId, out var value))
			{
				return 0;
			}
			return value;
		}

		public bool AddCustomCurrency(string currencyId, int amount)
		{
			if (amount < 0 || string.IsNullOrEmpty(currencyId))
			{
				return false;
			}
			int customCurrency = GetCustomCurrency(currencyId);
			_vaultData.CustomCurrencies[currencyId] = customCurrency + amount;
			_isDirty = true;
			this.OnCurrencyChanged?.Invoke("custom_" + currencyId, customCurrency, customCurrency + amount);
			return true;
		}

		public bool RemoveCustomCurrency(string currencyId, int amount)
		{
			if (amount < 0 || string.IsNullOrEmpty(currencyId))
			{
				return false;
			}
			int customCurrency = GetCustomCurrency(currencyId);
			if (customCurrency < amount)
			{
				return false;
			}
			int arg = customCurrency;
			_vaultData.CustomCurrencies[currencyId] = customCurrency - amount;
			_isDirty = true;
			this.OnCurrencyChanged?.Invoke("custom_" + currencyId, arg, customCurrency - amount);
			return true;
		}

		public bool HasCustomCurrency(string currencyId, int amount)
		{
			return GetCustomCurrency(currencyId) >= amount;
		}

		public int GetCurrency(string fullCurrencyId)
		{
			if (string.IsNullOrEmpty(fullCurrencyId))
			{
				return 0;
			}
			if (fullCurrencyId.StartsWith("seasonal_"))
			{
				if (Enum.TryParse<SeasonalTokenType>(fullCurrencyId.Substring("seasonal_".Length), out var result))
				{
					return GetSeasonalTokens(result);
				}
			}
			else
			{
				if (fullCurrencyId.StartsWith("community_"))
				{
					return GetCommunityTokens(fullCurrencyId.Substring("community_".Length));
				}
				if (fullCurrencyId.StartsWith("key_"))
				{
					return GetKeys(fullCurrencyId.Substring("key_".Length));
				}
				if (fullCurrencyId.StartsWith("special_"))
				{
					return GetSpecial(fullCurrencyId.Substring("special_".Length));
				}
				if (fullCurrencyId.StartsWith("orb_"))
				{
					return GetOrbs(fullCurrencyId.Substring("orb_".Length));
				}
				if (fullCurrencyId.StartsWith("custom_"))
				{
					return GetCustomCurrency(fullCurrencyId.Substring("custom_".Length));
				}
			}
			return 0;
		}

		public bool HasCurrency(string fullCurrencyId, int amount)
		{
			return GetCurrency(fullCurrencyId) >= amount;
		}

		public Dictionary<string, int> GetAllNonZeroCurrencies()
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			foreach (KeyValuePair<SeasonalTokenType, int> seasonalToken in _vaultData.SeasonalTokens)
			{
				if (seasonalToken.Value > 0)
				{
					dictionary[$"seasonal_{seasonalToken.Key}"] = seasonalToken.Value;
				}
			}
			foreach (KeyValuePair<string, int> communityToken in _vaultData.CommunityTokens)
			{
				if (communityToken.Value > 0)
				{
					dictionary["community_" + communityToken.Key] = communityToken.Value;
				}
			}
			foreach (KeyValuePair<string, int> key in _vaultData.Keys)
			{
				if (key.Value > 0)
				{
					dictionary["key_" + key.Key] = key.Value;
				}
			}
			foreach (KeyValuePair<string, int> ticket in _vaultData.Tickets)
			{
				if (ticket.Value > 0)
				{
					dictionary["special_" + ticket.Key] = ticket.Value;
				}
			}
			foreach (KeyValuePair<string, int> orb in _vaultData.Orbs)
			{
				if (orb.Value > 0)
				{
					dictionary["orb_" + orb.Key] = orb.Value;
				}
			}
			foreach (KeyValuePair<string, int> customCurrency in _vaultData.CustomCurrencies)
			{
				if (customCurrency.Value > 0)
				{
					dictionary["custom_" + customCurrency.Key] = customCurrency.Value;
				}
			}
			return dictionary;
		}
	}
	public class VaultSaveSystem
	{
		private readonly string _saveDirectory;

		private readonly VaultManager _vaultManager;

		private string _currentSaveFile;

		private static string _cachedSteamId = null;

		private static bool _steamIdChecked = false;

		private const string ENCRYPTION_SALT = "TheV4ultS@lt2026Secure";

		private const int KEY_SIZE = 256;

		private const int ITERATIONS = 10000;

		private static readonly byte[] _iv = new byte[16]
		{
			67, 117, 114, 114, 101, 110, 99, 121, 83, 112,
			101, 108, 108, 73, 86, 49
		};

		private const float AUTO_SAVE_INTERVAL = 300f;

		private float _lastAutoSave;

		private bool _needsReEncryption;

		public VaultSaveSystem(VaultManager vaultManager)
		{
			_vaultManager = vaultManager;
			_saveDirectory = Path.Combine(Paths.ConfigPath, "TheVault", "Saves");
			_lastAutoSave = Time.time;
			if (!Directory.Exists(_saveDirectory))
			{
				Directory.CreateDirectory(_saveDirectory);
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)("Created save directory: " + _saveDirectory));
				}
			}
			MigrateOldSaves();
		}

		private void MigrateOldSaves()
		{
			try
			{
				string path = Path.Combine(Paths.ConfigPath, "CurrencySpell", "Saves");
				if (!Directory.Exists(path))
				{
					return;
				}
				string[] files = Directory.GetFiles(path, "*.vault");
				if (files.Length == 0)
				{
					return;
				}
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)$"Found {files.Length} save files in old CurrencySpell folder, migrating...");
				}
				string[] array = files;
				foreach (string text in array)
				{
					string fileName = Path.GetFileName(text);
					string text2 = Path.Combine(_saveDirectory, fileName);
					if (!File.Exists(text2))
					{
						File.Copy(text, text2);
						ManualLogSource log2 = Plugin.Log;
						if (log2 != null)
						{
							log2.LogInfo((object)("Migrated save: " + fileName));
						}
					}
				}
				ManualLogSource log3 = Plugin.Log;
				if (log3 != null)
				{
					log3.LogInfo((object)"Save migration complete. You can delete the old CurrencySpell folder if desired.");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log4 = Plugin.Log;
				if (log4 != null)
				{
					log4.LogWarning((object)("Failed to migrate old saves: " + ex.Message));
				}
			}
		}

		private string GetSaveFilePath(string playerName)
		{
			string text = SanitizeFileName(playerName);
			if (string.IsNullOrEmpty(text))
			{
				text = "default";
			}
			return Path.Combine(_saveDirectory, text + ".vault");
		}

		private string SanitizeFileName(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return "";
			}
			char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
			foreach (char oldChar in invalidFileNameChars)
			{
				name = name.Replace(oldChar, '_');
			}
			return name.Trim();
		}

		public bool Load(string playerName)
		{
			try
			{
				_currentSaveFile = GetSaveFilePath(playerName);
				if (!File.Exists(_currentSaveFile))
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogInfo((object)("No existing save file for player '" + playerName + "', creating new vault"));
					}
					VaultData data = new VaultData
					{
						PlayerName = playerName
					};
					_vaultManager.LoadVaultData(data);
					return true;
				}
				byte[] array = File.ReadAllBytes(_currentSaveFile);
				string text = Decrypt(array, playerName);
				if (string.IsNullOrEmpty(text))
				{
					ManualLogSource log2 = Plugin.Log;
					if (log2 != null)
					{
						log2.LogInfo((object)("Current decryption failed, attempting legacy migration for '" + playerName + "'..."));
					}
					text = TryLegacyDecryption(array, playerName);
					if (!string.IsNullOrEmpty(text))
					{
						ManualLogSource log3 = Plugin.Log;
						if (log3 != null)
						{
							log3.LogInfo((object)"Legacy decryption successful - will re-encrypt with new method on save");
						}
						_needsReEncryption = true;
					}
				}
				if (string.IsNullOrEmpty(text))
				{
					ManualLogSource log4 = Plugin.Log;
					if (log4 != null)
					{
						log4.LogWarning((object)("Failed to decrypt vault data for '" + playerName + "' with all methods, creating new vault"));
					}
					VaultData data2 = new VaultData
					{
						PlayerName = playerName
					};
					_vaultManager.LoadVaultData(data2);
					return true;
				}
				VaultDataWrapper vaultDataWrapper = JsonUtility.FromJson<VaultDataWrapper>(text);
				VaultData data3;
				if (vaultDataWrapper != null)
				{
					data3 = vaultDataWrapper.ToVaultData();
				}
				else
				{
					ManualLogSource log5 = Plugin.Log;
					if (log5 != null)
					{
						log5.LogWarning((object)"Failed to deserialize vault data, creating new vault");
					}
					data3 = new VaultData
					{
						PlayerName = playerName
					};
				}
				data3 = MigrateData(data3);
				_vaultManager.LoadVaultData(data3);
				ManualLogSource log6 = Plugin.Log;
				if (log6 != null)
				{
					log6.LogInfo((object)("Loaded vault data for player '" + playerName + "'"));
				}
				if (_needsReEncryption)
				{
					ManualLogSource log7 = Plugin.Log;
					if (log7 != null)
					{
						log7.LogInfo((object)"Re-encrypting vault with new method...");
					}
					Save();
					_needsReEncryption = false;
					ManualLogSource log8 = Plugin.Log;
					if (log8 != null)
					{
						log8.LogInfo((object)"Vault successfully migrated to new encryption!");
					}
				}
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource log9 = Plugin.Log;
				if (log9 != null)
				{
					log9.LogError((object)("Failed to load vault data: " + ex.Message));
				}
				_vaultManager.LoadVaultData(new VaultData
				{
					PlayerName = playerName
				});
				return false;
			}
		}

		private string TryLegacyDecryption(byte[] encryptedData, string playerName)
		{
			string[] array = new string[3]
			{
				"TheV4ultS@lt2026Secure_" + playerName + "_TheVaultPortable",
				"TheV4ultS@lt2026Secure_Player_" + playerName + "_TheVaultPortable",
				"TheV4ultS@lt2026Secure_" + playerName + "_" + GetMachineId()
			};
			foreach (string combined in array)
			{
				try
				{
					byte[] key = GenerateLegacyKey(combined);
					string text = DecryptWithKey(encryptedData, key);
					if (!string.IsNullOrEmpty(text) && text.Contains("PlayerName"))
					{
						ManualLogSource log = Plugin.Log;
						if (log != null)
						{
							log.LogInfo((object)"Successfully decrypted with legacy method");
						}
						return text;
					}
				}
				catch
				{
				}
			}
			return null;
		}

		private string GetMachineId()
		{
			try
			{
				return SystemInfo.deviceUniqueIdentifier;
			}
			catch
			{
				return "unknown";
			}
		}

		private byte[] GenerateLegacyKey(string combined)
		{
			using Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(combined, Encoding.UTF8.GetBytes("TheV4ultS@lt2026Secure"), 10000);
			return rfc2898DeriveBytes.GetBytes(32);
		}

		private string DecryptWithKey(byte[] encryptedData, byte[] key)
		{
			try
			{
				using Aes aes = Aes.Create();
				aes.Key = key;
				aes.IV = _iv;
				aes.Mode = CipherMode.CBC;
				aes.Padding = PaddingMode.PKCS7;
				using ICryptoTransform cryptoTransform = aes.CreateDecryptor();
				byte[] bytes = cryptoTransform.TransformFinalBlock(encryptedData, 0, encryptedData.Length);
				return Encoding.UTF8.GetString(bytes);
			}
			catch
			{
				return null;
			}
		}

		public bool Save()
		{
			if (string.IsNullOrEmpty(_currentSaveFile))
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"No save file set, cannot save");
				}
				return false;
			}
			try
			{
				VaultData vaultData = _vaultManager.GetVaultData();
				string plainText = JsonUtility.ToJson((object)VaultDataWrapper.FromVaultData(vaultData), true);
				byte[] bytes = Encrypt(plainText, vaultData.PlayerName);
				string text = _currentSaveFile + ".tmp";
				File.WriteAllBytes(text, bytes);
				if (File.Exists(_currentSaveFile))
				{
					string text2 = _currentSaveFile + ".backup";
					if (File.Exists(text2))
					{
						File.Delete(text2);
					}
					File.Move(_currentSaveFile, text2);
				}
				File.Move(text, _currentSaveFile);
				_vaultManager.MarkClean();
				_lastAutoSave = Time.time;
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogInfo((object)("Saved vault data to " + _currentSaveFile));
				}
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource log3 = Plugin.Log;
				if (log3 != null)
				{
					log3.LogError((object)("Failed to save vault data: " + ex.Message));
				}
				return false;
			}
		}

		public void ForceSave()
		{
			if (_vaultManager.IsDirty)
			{
				Save();
			}
		}

		public void CheckAutoSave()
		{
			if (_vaultManager.IsDirty && Time.time - _lastAutoSave >= 300f)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)"Auto-saving vault data...");
				}
				Save();
			}
		}

		private VaultData MigrateData(VaultData data)
		{
			if (data.Version < 1)
			{
				data.Version = 1;
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)"Migrated vault data to version 1");
				}
			}
			return data;
		}

		public bool DeleteSave(string playerName)
		{
			try
			{
				string saveFilePath = GetSaveFilePath(playerName);
				if (File.Exists(saveFilePath))
				{
					File.Delete(saveFilePath);
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogInfo((object)("Deleted vault save for player '" + playerName + "'"));
					}
				}
				string path = saveFilePath + ".backup";
				if (File.Exists(path))
				{
					File.Delete(path);
				}
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogError((object)("Failed to delete vault save: " + ex.Message));
				}
				return false;
			}
		}

		public string[] GetAllSavedPlayers()
		{
			try
			{
				string[] files = Directory.GetFiles(_saveDirectory, "*.vault");
				string[] array = new string[files.Length];
				for (int i = 0; i < files.Length; i++)
				{
					string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(files[i]);
					array[i] = fileNameWithoutExtension;
				}
				return array;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)("Failed to get saved players: " + ex.Message));
				}
				return Array.Empty<string>();
			}
		}

		public bool ExportVault(string exportPath)
		{
			try
			{
				string contents = JsonUtility.ToJson((object)VaultDataWrapper.FromVaultData(_vaultManager.GetVaultData()), true);
				File.WriteAllText(exportPath, contents);
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)("Exported vault to " + exportPath));
				}
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogError((object)("Failed to export vault: " + ex.Message));
				}
				return false;
			}
		}

		public bool ImportVault(string importPath)
		{
			try
			{
				if (!File.Exists(importPath))
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogError((object)("Import file not found: " + importPath));
					}
					return false;
				}
				VaultDataWrapper vaultDataWrapper = JsonUtility.FromJson<VaultDataWrapper>(File.ReadAllText(importPath));
				if (vaultDataWrapper == null)
				{
					ManualLogSource log2 = Plugin.Log;
					if (log2 != null)
					{
						log2.LogError((object)"Failed to parse import file");
					}
					return false;
				}
				VaultData data = vaultDataWrapper.ToVaultData();
				data = MigrateData(data);
				_vaultManager.LoadVaultData(data);
				ManualLogSource log3 = Plugin.Log;
				if (log3 != null)
				{
					log3.LogInfo((object)("Imported vault from " + importPath));
				}
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource log4 = Plugin.Log;
				if (log4 != null)
				{
					log4.LogError((object)("Failed to import vault: " + ex.Message));
				}
				return false;
			}
		}

		private static string TryGetSteamId()
		{
			if (_steamIdChecked)
			{
				return _cachedSteamId;
			}
			_steamIdChecked = true;
			_cachedSteamId = null;
			try
			{
				Assembly assembly = null;
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly2 in assemblies)
				{
					string name = assembly2.GetName().Name;
					if (name.Contains("rlabrecque") || name == "Steamworks.NET")
					{
						assembly = assembly2;
						ManualLogSource log = Plugin.Log;
						if (log != null)
						{
							log.LogInfo((object)("[VaultSave] Found Steamworks assembly: " + name));
						}
						break;
					}
				}
				if (assembly == null)
				{
					assemblies = AppDomain.CurrentDomain.GetAssemblies();
					foreach (Assembly assembly3 in assemblies)
					{
						try
						{
							if (assembly3.GetType("Steamworks.SteamUser") != null)
							{
								assembly = assembly3;
								ManualLogSource log2 = Plugin.Log;
								if (log2 != null)
								{
									log2.LogInfo((object)("[VaultSave] Found SteamUser in assembly: " + assembly3.GetName().Name));
								}
								break;
							}
						}
						catch
						{
						}
					}
				}
				if (assembly == null)
				{
					ManualLogSource log3 = Plugin.Log;
					if (log3 != null)
					{
						log3.LogInfo((object)"[VaultSave] Steam assembly not found - using player name for encryption");
					}
					return null;
				}
				Type type = assembly.GetType("Steamworks.SteamUser");
				if (type == null)
				{
					ManualLogSource log4 = Plugin.Log;
					if (log4 != null)
					{
						log4.LogInfo((object)"[VaultSave] SteamUser type not found in assembly");
					}
					return null;
				}
				MethodInfo method = type.GetMethod("GetSteamID", BindingFlags.Static | BindingFlags.Public);
				if (method == null)
				{
					ManualLogSource log5 = Plugin.Log;
					if (log5 != null)
					{
						log5.LogInfo((object)"[VaultSave] GetSteamID method not found");
					}
					return null;
				}
				object obj2 = method.Invoke(null, null);
				if (obj2 == null)
				{
					ManualLogSource log6 = Plugin.Log;
					if (log6 != null)
					{
						log6.LogInfo((object)"[VaultSave] GetSteamID returned null");
					}
					return null;
				}
				string text = obj2.ToString();
				if (string.IsNullOrEmpty(text) || text == "0" || text.Length < 10)
				{
					ManualLogSource log7 = Plugin.Log;
					if (log7 != null)
					{
						log7.LogInfo((object)("[VaultSave] Invalid Steam ID: " + text));
					}
					return null;
				}
				_cachedSteamId = text;
				ManualLogSource log8 = Plugin.Log;
				if (log8 != null)
				{
					log8.LogInfo((object)$"[VaultSave] Successfully retrieved Steam ID for encryption (length: {text.Length})");
				}
				return _cachedSteamId;
			}
			catch (Exception ex)
			{
				ManualLogSource log9 = Plugin.Log;
				if (log9 != null)
				{
					log9.LogWarning((object)("[VaultSave] Failed to get Steam ID: " + ex.Message));
				}
				return null;
			}
		}

		private byte[] GenerateKey(string playerName)
		{
			string text = TryGetSteamId();
			string text2;
			if (!string.IsNullOrEmpty(text))
			{
				text2 = "Steam_" + text;
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)"Using Steam ID for vault encryption (cross-device compatible)");
				}
			}
			else
			{
				text2 = "Player_" + playerName;
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogInfo((object)"Using player name for vault encryption (non-Steam mode)");
				}
			}
			using Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes("TheV4ultS@lt2026Secure_" + text2 + "_TheVaultPortable", Encoding.UTF8.GetBytes("TheV4ultS@lt2026Secure"), 10000);
			return rfc2898DeriveBytes.GetBytes(32);
		}

		private byte[] Encrypt(string plainText, string playerName)
		{
			byte[] key = GenerateKey(playerName);
			using Aes aes = Aes.Create();
			aes.Key = key;
			aes.IV = _iv;
			aes.Mode = CipherMode.CBC;
			aes.Padding = PaddingMode.PKCS7;
			using ICryptoTransform transform = aes.CreateEncryptor();
			using MemoryStream memoryStream = new MemoryStream();
			byte[] bytes = Encoding.UTF8.GetBytes("CSVAULT2");
			memoryStream.Write(bytes, 0, bytes.Length);
			using (CryptoStream stream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write))
			{
				using StreamWriter streamWriter = new StreamWriter(stream, Encoding.UTF8);
				streamWriter.Write(plainText);
			}
			return memoryStream.ToArray();
		}

		private string Decrypt(byte[] cipherData, string playerName)
		{
			try
			{
				if (cipherData.Length < 8)
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogWarning((object)"Vault file too small, may be corrupted");
					}
					return null;
				}
				if (Encoding.UTF8.GetString(cipherData, 0, 8) != "CSVAULT2")
				{
					ManualLogSource log2 = Plugin.Log;
					if (log2 != null)
					{
						log2.LogInfo((object)"Detected legacy unencrypted vault file, will re-encrypt on save");
					}
					return Encoding.UTF8.GetString(cipherData);
				}
				byte[] key = GenerateKey(playerName);
				using Aes aes = Aes.Create();
				aes.Key = key;
				aes.IV = _iv;
				aes.Mode = CipherMode.CBC;
				aes.Padding = PaddingMode.PKCS7;
				using ICryptoTransform transform = aes.CreateDecryptor();
				using MemoryStream stream = new MemoryStream(cipherData, 8, cipherData.Length - 8);
				using CryptoStream stream2 = new CryptoStream(stream, trans