Decompiled source of HavenDevTools v1.0.2
HavenDevTools.dll
Decompiled 6 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; 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 HavenDevTools.Config; using HavenDevTools.Services; using HavenDevTools.UI; using Microsoft.CodeAnalysis; using SunhavenMods.Shared; 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("HavenDevTools")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+c7976283ee1309608b00428a169c130e784344a0")] [assembly: AssemblyProduct("HavenDevTools")] [assembly: AssemblyTitle("HavenDevTools")] [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 HavenDevTools { [BepInPlugin("com.azraelgodking.havendevtools", "Haven Dev Tools", "1.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { private static ItemInspector _staticItemInspector; private static CurrencyTracker _staticCurrencyTracker; private static BundleInspector _staticBundleInspector; private static RaceModifierTracker _staticRaceModifierTracker; private static DebugWindow _staticDebugWindow; private static DebugOverlay _staticDebugOverlay; private static GameObject _persistentRunner; private static PersistentRunner _persistentRunnerComponent; internal static KeyCode StaticToggleKey = (KeyCode)292; internal static KeyCode StaticOverlayToggleKey = (KeyCode)287; private static readonly HashSet<string> _authorizedSteamIdHashes = new HashSet<string> { "Tr4eyf86yKRu6fhNQjQOrO/ZnwasQaY/fgKV0PcnoGA=" }; private static bool _isAuthorized; private static string _currentSteamId; private static string _currentPlayerName; private Harmony _harmony; private string _lastScene = ""; public static Plugin Instance { get; private set; } public static ManualLogSource Log { get; private set; } public static ConfigFile ConfigFile { get; private set; } public static bool HasTheVault { get; private set; } public static bool HasSMUT { get; private set; } public static bool HasHavensBirthright { get; private set; } public static bool IsAuthorized => _isAuthorized; public static string CurrentPlayerName => _currentPlayerName; private void Awake() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Expected O, but got Unknown //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0135: 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 Haven Dev Tools v1.0.1"); try { ModConfig.Initialize(((BaseUnityPlugin)this).Config); StaticToggleKey = ModConfig.ToggleKey.Value; StaticOverlayToggleKey = ModConfig.OverlayToggleKey.Value; CreatePersistentRunner(); DetectInstalledMods(); _staticItemInspector = new ItemInspector(); _staticCurrencyTracker = new CurrencyTracker(); _staticBundleInspector = new BundleInspector(); _staticRaceModifierTracker = new RaceModifierTracker(); CreateUIComponents(); _harmony = new Harmony("com.azraelgodking.havendevtools"); PatchPlayerInit(); SceneManager.sceneLoaded += OnSceneLoaded; if (ModConfig.CheckForUpdates.Value) { VersionChecker.CheckForUpdate("com.azraelgodking.havendevtools", "1.0.1", Log, delegate(VersionChecker.VersionCheckResult result) { result.NotifyUpdateAvailable(Log); }); } Log.LogInfo((object)"Haven Dev Tools loaded successfully!"); Log.LogInfo((object)$"Press {ModConfig.ToggleKey.Value} to open the debug window (requires authorization)"); Log.LogInfo((object)$"Press {ModConfig.OverlayToggleKey.Value} to toggle the overlay"); Log.LogInfo((object)$"Detected mods - TheVault: {HasTheVault}, SMUT: {HasSMUT}, HavensBirthright: {HasHavensBirthright}"); } catch (Exception arg) { Log.LogError((object)string.Format("Failed to load {0}: {1}", "Haven Dev Tools", arg)); } } private void CreatePersistentRunner() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown if (!((Object)(object)_persistentRunner != (Object)null) || !((Object)(object)_persistentRunnerComponent != (Object)null)) { _persistentRunner = new GameObject("HavenDevTools_PersistentRunner"); Object.DontDestroyOnLoad((Object)(object)_persistentRunner); ((Object)_persistentRunner).hideFlags = (HideFlags)61; _persistentRunnerComponent = _persistentRunner.AddComponent<PersistentRunner>(); Log.LogInfo((object)"[PersistentRunner] Created hidden persistent runner"); } } private void CreateUIComponents() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0010: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("HavenDevTools_UI"); Object.DontDestroyOnLoad((Object)val); _staticDebugWindow = val.AddComponent<DebugWindow>(); _staticDebugOverlay = val.AddComponent<DebugOverlay>(); Log.LogInfo((object)"UI components created"); } 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_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Expected O, but got Unknown //IL_00b7: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)_persistentRunner == (Object)null || (Object)(object)_persistentRunnerComponent == (Object)null) { ManualLogSource log = Log; if (log != null) { log.LogInfo((object)"[EnsureUI] Recreating PersistentRunner..."); } _persistentRunner = new GameObject("HavenDevTools_PersistentRunner"); Object.DontDestroyOnLoad((Object)(object)_persistentRunner); ((Object)_persistentRunner).hideFlags = (HideFlags)61; _persistentRunnerComponent = _persistentRunner.AddComponent<PersistentRunner>(); ManualLogSource log2 = Log; if (log2 != null) { log2.LogInfo((object)"[EnsureUI] PersistentRunner recreated"); } } if ((Object)(object)_staticDebugWindow == (Object)null || (Object)(object)_staticDebugOverlay == (Object)null) { ManualLogSource log3 = Log; if (log3 != null) { log3.LogInfo((object)"[EnsureUI] Recreating UI components..."); } GameObject val = new GameObject("HavenDevTools_UI"); Object.DontDestroyOnLoad((Object)val); _staticDebugWindow = val.AddComponent<DebugWindow>(); _staticDebugOverlay = val.AddComponent<DebugOverlay>(); ManualLogSource log4 = Log; if (log4 != null) { log4.LogInfo((object)"[EnsureUI] UI components recreated"); } } if (_staticItemInspector == null) { _staticItemInspector = new ItemInspector(); } if (_staticCurrencyTracker == null) { _staticCurrencyTracker = new CurrencyTracker(); } if (_staticBundleInspector == null) { _staticBundleInspector = new BundleInspector(); } if (_staticRaceModifierTracker == null) { _staticRaceModifierTracker = new RaceModifierTracker(); } } catch (Exception ex) { ManualLogSource log5 = Log; if (log5 != null) { log5.LogError((object)("[EnsureUI] Error recreating components: " + ex.Message)); } } } private void DetectInstalledMods() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { string? name = assemblies[i].GetName().Name; if (name == "TheVault") { HasTheVault = true; } if (name == "SunHavenMuseumUtilityTracker") { HasSMUT = true; } if (name == "HavensBirthright") { HasHavensBirthright = true; } } Log.LogInfo((object)$"Mod detection complete - TheVault: {HasTheVault}, SMUT: {HasSMUT}, HavensBirthright: {HasHavensBirthright}"); } private void PatchPlayerInit() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method(typeof(Player), "InitializeAsOwner", (Type[])null, (Type[])null); if (methodInfo != null) { MethodInfo methodInfo2 = AccessTools.Method(typeof(Plugin), "OnPlayerInitialized", (Type[])null, (Type[])null); _harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)"Patched Player.InitializeAsOwner"); } } catch (Exception ex) { Log.LogError((object)("Failed to patch player init: " + ex.Message)); } } private static void OnPlayerInitialized() { ManualLogSource log = Log; if (log != null) { log.LogInfo((object)"[HavenDevTools] Player initialized, ensuring UI exists and checking authorization..."); } EnsureUIComponentsExist(); CheckAuthorization(); } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { Log.LogInfo((object)("[SceneChange] Scene loaded: '" + ((Scene)(ref scene)).name + "'")); string text = ((Scene)(ref scene)).name.ToLowerInvariant(); if (text.Contains("menu") || text.Contains("title")) { Log.LogInfo((object)("Menu scene detected: " + ((Scene)(ref scene)).name)); _isAuthorized = false; _currentPlayerName = null; } } private void Update() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) Scene activeScene = SceneManager.GetActiveScene(); string name = ((Scene)(ref activeScene)).name; if (name != _lastScene) { Log.LogInfo((object)("[ScenePoll] Scene changed: '" + _lastScene + "' -> '" + name + "'")); _lastScene = name; } } private void OnDestroy() { Log.LogWarning((object)"[CRITICAL] Plugin OnDestroy called!"); SceneManager.sceneLoaded -= OnSceneLoaded; } private static void CheckAuthorization() { try { try { if ((Object)(object)Player.Instance != (Object)null) { PropertyInfo property = ((object)Player.Instance).GetType().GetProperty("PlayerName", BindingFlags.Instance | BindingFlags.Public); if (property != null) { _currentPlayerName = property.GetValue(Player.Instance) as string; } if (string.IsNullOrEmpty(_currentPlayerName)) { _currentPlayerName = ((Object)Player.Instance).name; } } } catch { _currentPlayerName = "Unknown"; } _currentSteamId = TryGetSteamId(); if (!string.IsNullOrEmpty(_currentSteamId)) { string text = ComputeHash(_currentSteamId); if (_authorizedSteamIdHashes.Contains(text)) { ManualLogSource log = Log; if (log != null) { log.LogInfo((object)"[HavenDevTools] Authorized via Steam ID"); } _isAuthorized = true; return; } ManualLogSource log2 = Log; if (log2 != null) { log2.LogInfo((object)("[HavenDevTools] Steam ID hash not authorized: " + text)); } } else { ManualLogSource log3 = Log; if (log3 != null) { log3.LogInfo((object)"[HavenDevTools] Could not retrieve Steam ID"); } } ManualLogSource log4 = Log; if (log4 != null) { log4.LogInfo((object)"[HavenDevTools] Not authorized - Steam ID required"); } } catch (Exception ex) { ManualLogSource log5 = Log; if (log5 != null) { log5.LogError((object)("[HavenDevTools] Authorization error: " + ex.Message)); } } } 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))); } public static string GenerateHash(string input) { return ComputeHash(input); } public static ItemInspector GetItemInspector() { return _staticItemInspector; } public static CurrencyTracker GetCurrencyTracker() { return _staticCurrencyTracker; } public static BundleInspector GetBundleInspector() { return _staticBundleInspector; } public static RaceModifierTracker GetRaceModifierTracker() { return _staticRaceModifierTracker; } public static DebugWindow GetDebugWindow() { return _staticDebugWindow; } public static DebugOverlay GetDebugOverlay() { return _staticDebugOverlay; } public static void ToggleDebugWindow() { if (_isAuthorized) { _staticDebugWindow?.Toggle(); return; } CheckAuthorization(); if (_isAuthorized) { _staticDebugWindow?.Toggle(); } } public static void ToggleDebugOverlay() { if (_isAuthorized) { _staticDebugOverlay?.Toggle(); } } } public class PersistentRunner : MonoBehaviour { private string _lastScene = ""; private float _heartbeatTimer; private int _heartbeatCount; 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] Awake - hidden persistent runner active"); } } private void Update() { CheckHotkeys(); CheckSceneChange(); _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}, Authorized: {2}, Player: {3}", _heartbeatCount, _lastScene, Plugin.IsAuthorized, Plugin.CurrentPlayerName ?? "none")); } } } private void CheckHotkeys() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) try { if (Input.GetKeyDown(Plugin.StaticToggleKey)) { Plugin.ToggleDebugWindow(); } if (Input.GetKeyDown(Plugin.StaticOverlayToggleKey)) { Plugin.ToggleDebugOverlay(); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("[PersistentRunner] Hotkey error: " + ex.Message)); } } } private void CheckSceneChange() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) Scene activeScene = SceneManager.GetActiveScene(); string name = ((Scene)(ref activeScene)).name; if (!(name != _lastScene)) { return; } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[PersistentRunner] Scene changed: '" + _lastScene + "' -> '" + name + "'")); } _lastScene = name; string text = name.ToLowerInvariant(); if (text.Contains("menu") || text.Contains("title")) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)"[PersistentRunner] Menu scene detected"); } } } private void OnDestroy() { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[PersistentRunner] OnDestroy called - this should NOT happen!"); } } } public static class PluginInfo { public const string PLUGIN_GUID = "com.azraelgodking.havendevtools"; public const string PLUGIN_NAME = "Haven Dev Tools"; public const string PLUGIN_VERSION = "1.0.1"; } } namespace HavenDevTools.UI { public class DebugOverlay : MonoBehaviour { private bool _isVisible; private GUIStyle _overlayStyle; private GUIStyle _labelStyle; private GUIStyle _valueStyle; private bool _stylesInitialized; private float _updateTimer; private const float UPDATE_INTERVAL = 0.5f; private string _playerName = ""; private string _currentRace = ""; private int _gold; private string _heldItemInfo = ""; private string _position = ""; private void Awake() { _isVisible = ModConfig.ShowOverlayOnStart?.Value ?? false; } public void Toggle() { _isVisible = !_isVisible; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[DebugOverlay] " + (_isVisible ? "Shown" : "Hidden"))); } } public void Show() { _isVisible = true; } public void Hide() { _isVisible = false; } private void Update() { if (_isVisible && Plugin.IsAuthorized) { _updateTimer += Time.deltaTime; if (_updateTimer >= 0.5f) { _updateTimer = 0f; UpdateCachedData(); } } } private void UpdateCachedData() { //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) try { _playerName = Plugin.CurrentPlayerName ?? "Unknown"; _currentRace = Plugin.GetRaceModifierTracker()?.GetCurrentRace() ?? "Unknown"; _gold = Plugin.GetCurrencyTracker()?.GetGold() ?? 0; GameItemInfo gameItemInfo = Plugin.GetItemInspector()?.GetHeldItem(); _heldItemInfo = ((gameItemInfo != null) ? $"[{gameItemInfo.Id}] {gameItemInfo.Name}" : "None"); if ((Object)(object)Player.Instance != (Object)null) { Vector3 position = ((Component)Player.Instance).transform.position; _position = $"({position.x:F1}, {position.y:F1})"; } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[DebugOverlay] Update error: " + ex.Message)); } } } private void OnGUI() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) if (_isVisible && Plugin.IsAuthorized) { InitializeStyles(); OverlayPositionType overlayPosition = ModConfig.GetOverlayPosition(); Rect overlayRect = GetOverlayRect(overlayPosition); GUI.Box(overlayRect, "", _overlayStyle); GUILayout.BeginArea(new Rect(((Rect)(ref overlayRect)).x + 8f, ((Rect)(ref overlayRect)).y + 8f, ((Rect)(ref overlayRect)).width - 16f, ((Rect)(ref overlayRect)).height - 16f)); DrawOverlayContent(); GUILayout.EndArea(); } } private void InitializeStyles() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Expected O, but got Unknown if (!_stylesInitialized) { Texture2D val = new Texture2D(1, 1); val.SetPixel(0, 0, new Color(0.05f, 0.05f, 0.1f, 0.85f)); val.Apply(); GUIStyle val2 = new GUIStyle(GUI.skin.box); val2.normal.background = val; _overlayStyle = val2; GUIStyle val3 = new GUIStyle(GUI.skin.label) { fontSize = 11 }; val3.normal.textColor = new Color(0.7f, 0.7f, 0.8f); _labelStyle = val3; GUIStyle val4 = new GUIStyle(GUI.skin.label) { fontSize = 11, fontStyle = (FontStyle)1 }; val4.normal.textColor = new Color(0.9f, 0.95f, 1f); _valueStyle = val4; _stylesInitialized = true; } } private Rect GetOverlayRect(OverlayPositionType position) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) float num = 220f; float num2 = 130f; float num3 = 10f; return (Rect)(position switch { OverlayPositionType.TopLeft => new Rect(num3, num3, num, num2), OverlayPositionType.TopRight => new Rect((float)Screen.width - num - num3, num3, num, num2), OverlayPositionType.BottomLeft => new Rect(num3, (float)Screen.height - num2 - num3, num, num2), OverlayPositionType.BottomRight => new Rect((float)Screen.width - num - num3, (float)Screen.height - num2 - num3, num, num2), _ => new Rect((float)Screen.width - num - num3, num3, num, num2), }); } private void DrawOverlayContent() { GUILayout.Label("Haven Dev Tools", _valueStyle, Array.Empty<GUILayoutOption>()); GUILayout.Space(3f); DrawRow("Player:", _playerName); DrawRow("Race:", _currentRace); DrawRow("Gold:", _gold.ToString("N0")); DrawRow("Position:", _position); DrawRow("Held:", _heldItemInfo); GUILayout.FlexibleSpace(); GUILayout.Label("F11: Window | F6: Toggle", _labelStyle, Array.Empty<GUILayoutOption>()); } private void DrawRow(string label, string value) { GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label(label, _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(55f) }); GUILayout.Label(value, _valueStyle, Array.Empty<GUILayoutOption>()); GUILayout.EndHorizontal(); } } public class DebugWindow : MonoBehaviour { private bool _isVisible; private Rect _windowRect; private Vector2 _scrollPosition; private GUIStyle _windowStyle; private GUIStyle _headerStyle; private GUIStyle _sectionHeaderStyle; private GUIStyle _buttonStyle; private GUIStyle _labelStyle; private GUIStyle _textFieldStyle; private GUIStyle _boxStyle; private bool _stylesInitialized; private int _selectedTab; private readonly string[] _tabNames = new string[5] { "Items", "Currencies", "Bundles", "Race Bonuses", "Utility" }; private string _itemSearchText = ""; private string _itemIdInput = ""; private string _spawnAmount = "1"; private List<GameItemInfo> _searchResults = new List<GameItemInfo>(); private Vector2 _itemScrollPosition; private Vector2 _currencyScrollPosition; private int _selectedSectionIndex; private int _selectedBundleIndex; private Vector2 _bundleScrollPosition; private int _selectedRaceIndex; private Vector2 _raceScrollPosition; private static Dictionary<string, VersionChecker.VersionCheckResult> _versionResults = new Dictionary<string, VersionChecker.VersionCheckResult>(); private static bool _isCheckingVersions; private Vector2 _versionScrollPosition; private static readonly (string guid, string name, string version)[] _knownMods = new(string, string, string)[6] { ("com.azraelgodking.havendevtools", "Haven Dev Tools", "1.0.1"), ("com.azraelgodking.squirrelsbirthdayreminder", "Birthday Reminder", "1.0.2"), ("com.azraelgodking.havensbirthright", "Haven's Birthright", "1.0.2"), ("com.azraelgodking.sunhavenmuseumutilitytracker", "S.M.U.T.", "2.0.1"), ("com.azraelgodking.sunhaventodo", "Sunhaven Todo", "1.0.0"), ("com.azraelgodking.thevault", "The Vault", "2.0.3") }; private const string PAUSE_ID = "HavenDevTools_Debug"; private void Awake() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) _windowRect = new Rect(50f, 50f, 500f, 600f); } public void Toggle() { if (_isVisible) { Hide(); } else { Show(); } } public void Show() { _isVisible = true; BlockInput(); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[DebugWindow] Shown"); } } public void Hide() { _isVisible = false; UnblockInput(); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[DebugWindow] Hidden"); } } private void BlockInput() { try { if ((Object)(object)Player.Instance != (Object)null) { Player.Instance.AddPauseObject("HavenDevTools_Debug"); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[DebugWindow] Could not block input: " + ex.Message)); } } } private void UnblockInput() { try { if ((Object)(object)Player.Instance != (Object)null) { Player.Instance.RemovePauseObject("HavenDevTools_Debug"); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[DebugWindow] Could not unblock input: " + ex.Message)); } } } private void Update() { if (_isVisible && Input.GetKeyDown((KeyCode)27)) { Hide(); } } private void OnGUI() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (_isVisible && Plugin.IsAuthorized) { InitializeStyles(); _windowRect = GUI.Window(((object)this).GetHashCode(), _windowRect, new WindowFunction(DrawWindow), "", _windowStyle); } } private void InitializeStyles() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Expected O, but got Unknown //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Expected O, but got Unknown //IL_0109: Expected O, but got Unknown //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Expected O, but got Unknown //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Expected O, but got Unknown //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Expected O, but got Unknown //IL_01fa: Expected O, but got Unknown //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Expected O, but got Unknown //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Expected O, but got Unknown //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0284: Expected O, but got Unknown if (!_stylesInitialized) { Texture2D val = new Texture2D(1, 1); val.SetPixel(0, 0, new Color(0.08f, 0.08f, 0.12f, 0.98f)); val.Apply(); Texture2D val2 = new Texture2D(1, 1); val2.SetPixel(0, 0, new Color(0.2f, 0.4f, 0.6f, 0.9f)); val2.Apply(); Texture2D val3 = new Texture2D(1, 1); val3.SetPixel(0, 0, new Color(0.3f, 0.5f, 0.7f, 0.95f)); val3.Apply(); Texture2D val4 = new Texture2D(1, 1); val4.SetPixel(0, 0, new Color(0.12f, 0.12f, 0.18f, 0.9f)); val4.Apply(); GUIStyle val5 = new GUIStyle(GUI.skin.window); val5.normal.background = val; val5.normal.textColor = Color.white; val5.padding = new RectOffset(10, 10, 25, 10); _windowStyle = val5; GUIStyle val6 = new GUIStyle(GUI.skin.label) { fontSize = 18, fontStyle = (FontStyle)1, alignment = (TextAnchor)4 }; val6.normal.textColor = new Color(0.4f, 0.8f, 1f); _headerStyle = val6; GUIStyle val7 = new GUIStyle(GUI.skin.label) { fontSize = 14, fontStyle = (FontStyle)1 }; val7.normal.textColor = new Color(0.8f, 0.9f, 1f); _sectionHeaderStyle = val7; GUIStyle val8 = new GUIStyle(GUI.skin.button) { fontSize = 12 }; val8.normal.background = val2; val8.normal.textColor = Color.white; val8.hover.background = val3; val8.hover.textColor = Color.white; val8.padding = new RectOffset(8, 8, 4, 4); _buttonStyle = val8; GUIStyle val9 = new GUIStyle(GUI.skin.label) { fontSize = 12 }; val9.normal.textColor = new Color(0.9f, 0.9f, 0.95f); _labelStyle = val9; GUIStyle val10 = new GUIStyle(GUI.skin.textField) { fontSize = 12 }; val10.normal.textColor = Color.white; _textFieldStyle = val10; GUIStyle val11 = new GUIStyle(GUI.skin.box); val11.normal.background = val4; _boxStyle = val11; _stylesInitialized = true; } } private void DrawWindow(int windowId) { //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) GUILayout.Label("Haven Dev Tools", _headerStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label("Player: " + Plugin.CurrentPlayerName, _labelStyle, Array.Empty<GUILayoutOption>()); GUILayout.Space(5f); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label("TheVault: " + (Plugin.HasTheVault ? "Yes" : "No"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) }); GUILayout.Label("SMUT: " + (Plugin.HasSMUT ? "Yes" : "No"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(100f) }); GUILayout.Label("Birthright: " + (Plugin.HasHavensBirthright ? "Yes" : "No"), _labelStyle, Array.Empty<GUILayoutOption>()); GUILayout.EndHorizontal(); GUILayout.Space(10f); _selectedTab = GUILayout.Toolbar(_selectedTab, _tabNames, _buttonStyle, Array.Empty<GUILayoutOption>()); GUILayout.Space(10f); _scrollPosition = GUILayout.BeginScrollView(_scrollPosition, Array.Empty<GUILayoutOption>()); switch (_selectedTab) { case 0: DrawItemsTab(); break; case 1: DrawCurrenciesTab(); break; case 2: DrawBundlesTab(); break; case 3: DrawRaceBonusesTab(); break; case 4: DrawUtilityTab(); break; } GUILayout.EndScrollView(); GUILayout.Space(10f); if (GUILayout.Button("Close (Esc)", _buttonStyle, Array.Empty<GUILayoutOption>())) { Hide(); } GUI.DragWindow(new Rect(0f, 0f, 500f, 30f)); } private void DrawItemsTab() { //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginVertical(_boxStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label("Item Inspector", _sectionHeaderStyle, Array.Empty<GUILayoutOption>()); GUILayout.Space(5f); GameItemInfo gameItemInfo = Plugin.GetItemInspector()?.GetHeldItem(); if (gameItemInfo != null) { GUILayout.Label($"Held Item: [{gameItemInfo.Id}] {gameItemInfo.Name}", _labelStyle, Array.Empty<GUILayoutOption>()); } else { GUILayout.Label("Held Item: None", _labelStyle, Array.Empty<GUILayoutOption>()); } GUILayout.Space(10f); GUILayout.Label("Search Items:", _labelStyle, Array.Empty<GUILayoutOption>()); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); _itemSearchText = GUILayout.TextField(_itemSearchText, _textFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(250f) }); if (GUILayout.Button("Search", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) })) { _searchResults = Plugin.GetItemInspector()?.SearchByName(_itemSearchText) ?? new List<GameItemInfo>(); } if (GUILayout.Button("Clear", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) })) { _itemSearchText = ""; _searchResults.Clear(); } GUILayout.EndHorizontal(); if (_searchResults.Count > 0) { GUILayout.Label($"Results ({_searchResults.Count}):", _labelStyle, Array.Empty<GUILayoutOption>()); _itemScrollPosition = GUILayout.BeginScrollView(_itemScrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(150f) }); foreach (GameItemInfo searchResult in _searchResults) { GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label($"[{searchResult.Id}] {searchResult.Name}", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(300f) }); if (GUILayout.Button("Spawn", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) })) { _itemIdInput = searchResult.Id.ToString(); } GUILayout.EndHorizontal(); } GUILayout.EndScrollView(); } GUILayout.Space(10f); GUILayout.Label("Spawn Item:", _labelStyle, Array.Empty<GUILayoutOption>()); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label("ID:", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(25f) }); _itemIdInput = GUILayout.TextField(_itemIdInput, _textFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }); GUILayout.Label("Qty:", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(30f) }); _spawnAmount = GUILayout.TextField(_spawnAmount, _textFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) }); if (GUILayout.Button("1", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(25f) })) { _spawnAmount = "1"; } if (GUILayout.Button("10", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(30f) })) { _spawnAmount = "10"; } if (GUILayout.Button("99", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(30f) })) { _spawnAmount = "99"; } GUILayout.EndHorizontal(); if (GUILayout.Button("Spawn to Inventory", _buttonStyle, Array.Empty<GUILayoutOption>()) && int.TryParse(_itemIdInput, out var result) && int.TryParse(_spawnAmount, out var result2)) { Plugin.GetItemInspector()?.SpawnItem(result, result2); } GUILayout.EndVertical(); } private void DrawCurrenciesTab() { //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginVertical(_boxStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label("Currency Tracker", _sectionHeaderStyle, Array.Empty<GUILayoutOption>()); GUILayout.Space(5f); CurrencyTracker currencyTracker = Plugin.GetCurrencyTracker(); if (currencyTracker == null) { GUILayout.Label("Currency tracker not available", _labelStyle, Array.Empty<GUILayoutOption>()); GUILayout.EndVertical(); return; } CurrencySummary summary = currencyTracker.GetSummary(); GUILayout.Label($"Gold: {summary.Gold:N0}", _labelStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label($"Orbs: {summary.Orbs:N0}", _labelStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label($"Tickets: {summary.Tickets:N0}", _labelStyle, Array.Empty<GUILayoutOption>()); GUILayout.Space(10f); GUILayout.Label("Inventory Currencies:", _sectionHeaderStyle, Array.Empty<GUILayoutOption>()); _currencyScrollPosition = GUILayout.BeginScrollView(_currencyScrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(120f) }); if (summary.InventoryCurrencies.Count == 0) { GUILayout.Label(" (none)", _labelStyle, Array.Empty<GUILayoutOption>()); } else { foreach (KeyValuePair<string, int> inventoryCurrency in summary.InventoryCurrencies) { GUILayout.Label($" {inventoryCurrency.Key}: {inventoryCurrency.Value}", _labelStyle, Array.Empty<GUILayoutOption>()); } } GUILayout.EndScrollView(); if (Plugin.HasTheVault) { GUILayout.Space(10f); GUILayout.Label("Vault Currencies:", _sectionHeaderStyle, Array.Empty<GUILayoutOption>()); if (summary.VaultCurrencies.Count == 0) { GUILayout.Label(" (vault empty)", _labelStyle, Array.Empty<GUILayoutOption>()); } else { foreach (KeyValuePair<string, int> vaultCurrency in summary.VaultCurrencies) { GUILayout.Label($" {vaultCurrency.Key}: {vaultCurrency.Value}", _labelStyle, Array.Empty<GUILayoutOption>()); } } } else { GUILayout.Space(5f); GUILayout.Label("(The Vault not installed)", _labelStyle, Array.Empty<GUILayoutOption>()); } GUILayout.EndVertical(); } private void DrawBundlesTab() { //IL_02a9: Unknown result type (might be due to invalid IL or missing references) //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginVertical(_boxStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label("Museum Bundle Inspector", _sectionHeaderStyle, Array.Empty<GUILayoutOption>()); GUILayout.Space(5f); if (!Plugin.HasSMUT) { GUILayout.Label("S.M.U.T. not installed", _labelStyle, Array.Empty<GUILayoutOption>()); GUILayout.EndVertical(); return; } BundleInspector bundleInspector = Plugin.GetBundleInspector(); if (bundleInspector == null) { GUILayout.Label("Bundle inspector not available", _labelStyle, Array.Empty<GUILayoutOption>()); GUILayout.EndVertical(); return; } DonationStats donationStats = bundleInspector.GetDonationStats(); if (donationStats.IsLoaded) { GUILayout.Label("Character: " + donationStats.CharacterName, _labelStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label($"Progress: {donationStats.TotalDonated}/{donationStats.TotalItems} ({donationStats.CompletionPercent:F1}%)", _labelStyle, Array.Empty<GUILayoutOption>()); } else { GUILayout.Label("Donation data not loaded", _labelStyle, Array.Empty<GUILayoutOption>()); } GUILayout.Space(10f); List<MuseumSectionInfo> allSections = bundleInspector.GetAllSections(); if (allSections.Count == 0) { GUILayout.Label("No museum data available", _labelStyle, Array.Empty<GUILayoutOption>()); GUILayout.EndVertical(); return; } string[] array = new string[allSections.Count]; for (int i = 0; i < allSections.Count; i++) { array[i] = allSections[i].Name; } GUILayout.Label("Section:", _labelStyle, Array.Empty<GUILayoutOption>()); _selectedSectionIndex = GUILayout.SelectionGrid(_selectedSectionIndex, array, 3, _buttonStyle, Array.Empty<GUILayoutOption>()); if (_selectedSectionIndex >= allSections.Count) { _selectedSectionIndex = 0; } MuseumSectionInfo museumSectionInfo = allSections[_selectedSectionIndex]; GUILayout.Space(5f); if (museumSectionInfo.Bundles.Count > 0) { string[] array2 = new string[museumSectionInfo.Bundles.Count]; for (int j = 0; j < museumSectionInfo.Bundles.Count; j++) { array2[j] = museumSectionInfo.Bundles[j].Name; } if (_selectedBundleIndex >= museumSectionInfo.Bundles.Count) { _selectedBundleIndex = 0; } GUILayout.Label("Bundle:", _labelStyle, Array.Empty<GUILayoutOption>()); _selectedBundleIndex = GUILayout.SelectionGrid(_selectedBundleIndex, array2, 2, _buttonStyle, Array.Empty<GUILayoutOption>()); MuseumBundleInfo museumBundleInfo = museumSectionInfo.Bundles[_selectedBundleIndex]; GUILayout.Space(5f); GUILayout.Label("Items in " + museumBundleInfo.Name + ":", _sectionHeaderStyle, Array.Empty<GUILayoutOption>()); _bundleScrollPosition = GUILayout.BeginScrollView(_bundleScrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(150f) }); foreach (MuseumItemInfo item in museumBundleInfo.Items) { string arg = (bundleInspector.HasDonated(item.Id) ? "[X]" : "[ ]"); string text = ((item.Quantity > 1) ? $" x{item.Quantity}" : ""); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label($"{arg} {item.Name} (ID: {item.GameItemId})", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(320f) }); if (GUILayout.Button("Spawn" + text, _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) })) { Plugin.GetItemInspector()?.SpawnItem(item.GameItemId, item.Quantity); } GUILayout.EndHorizontal(); } GUILayout.EndScrollView(); } GUILayout.EndVertical(); } private void DrawRaceBonusesTab() { //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginVertical(_boxStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label("Race Modifier Tracker", _sectionHeaderStyle, Array.Empty<GUILayoutOption>()); GUILayout.Space(5f); RaceModifierTracker raceModifierTracker = Plugin.GetRaceModifierTracker(); if (raceModifierTracker == null) { GUILayout.Label("Race tracker not available", _labelStyle, Array.Empty<GUILayoutOption>()); GUILayout.EndVertical(); return; } string currentRace = raceModifierTracker.GetCurrentRace(); GUILayout.Label("Current Race: " + currentRace, _labelStyle, Array.Empty<GUILayoutOption>()); GUILayout.Space(10f); if (Plugin.HasHavensBirthright) { List<RaceBonusInfo> activeRaceBonuses = raceModifierTracker.GetActiveRaceBonuses(); GUILayout.Label("Active Bonuses:", _sectionHeaderStyle, Array.Empty<GUILayoutOption>()); if (activeRaceBonuses.Count == 0) { GUILayout.Label(" (no bonuses active)", _labelStyle, Array.Empty<GUILayoutOption>()); } else { foreach (RaceBonusInfo item in activeRaceBonuses) { GUILayout.Label(" " + item.Type + ": " + item.GetFormattedValue(), _labelStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label(" " + item.Description, _labelStyle, Array.Empty<GUILayoutOption>()); } } } else { GUILayout.Label("Haven's Birthright not installed", _labelStyle, Array.Empty<GUILayoutOption>()); } GUILayout.Space(10f); GUILayout.Label("Browse Race Bonuses:", _sectionHeaderStyle, Array.Empty<GUILayoutOption>()); List<string> allRaces = raceModifierTracker.GetAllRaces(); if (allRaces.Count > 0) { string[] array = allRaces.ToArray(); if (_selectedRaceIndex >= allRaces.Count) { _selectedRaceIndex = 0; } _selectedRaceIndex = GUILayout.SelectionGrid(_selectedRaceIndex, array, 4, _buttonStyle, Array.Empty<GUILayoutOption>()); GUILayout.Space(5f); List<RaceBonusInfo> bonusesForRace = raceModifierTracker.GetBonusesForRace(allRaces[_selectedRaceIndex]); _raceScrollPosition = GUILayout.BeginScrollView(_raceScrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(150f) }); if (bonusesForRace.Count == 0) { GUILayout.Label(" (no bonuses defined)", _labelStyle, Array.Empty<GUILayoutOption>()); } else { foreach (RaceBonusInfo item2 in bonusesForRace) { GUILayout.Label(" " + item2.Type + ": " + item2.GetFormattedValue(), _labelStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label(" " + item2.Description, _labelStyle, Array.Empty<GUILayoutOption>()); } } GUILayout.EndScrollView(); } GUILayout.EndVertical(); } private void DrawUtilityTab() { GUILayout.BeginVertical(_boxStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label("Utility", _sectionHeaderStyle, Array.Empty<GUILayoutOption>()); GUILayout.Space(5f); DrawVersionCheckerSection(); GUILayout.Space(10f); ItemInspector itemInspector = Plugin.GetItemInspector(); GUILayout.Label(string.Format("Item Cache: {0} items ({1})", itemInspector?.CacheCount ?? 0, (itemInspector != null && itemInspector.IsCacheBuilt) ? "built" : "not built"), _labelStyle, Array.Empty<GUILayoutOption>()); if (GUILayout.Button("Build Item Cache", _buttonStyle, Array.Empty<GUILayoutOption>())) { itemInspector?.BuildCache(); } GUILayout.Space(10f); GUILayout.Label("Logging:", _sectionHeaderStyle, Array.Empty<GUILayoutOption>()); if (GUILayout.Button("Log All Currency IDs", _buttonStyle, Array.Empty<GUILayoutOption>())) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"=== Currency Item IDs ==="); } foreach (KeyValuePair<string, int> currencyItemId in CurrencyTracker.CurrencyItemIds) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$" {currencyItemId.Key}: {currencyItemId.Value}"); } } } if (GUILayout.Button("Log Player Stats", _buttonStyle, Array.Empty<GUILayoutOption>())) { LogPlayerStats(); } GUILayout.Space(10f); GUILayout.Label("Authorization Hash Generator:", _sectionHeaderStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label("Use this to generate hashes for new authorized Steam IDs", _labelStyle, Array.Empty<GUILayoutOption>()); if (GUILayout.Button("Log Current Steam ID Hash", _buttonStyle, Array.Empty<GUILayoutOption>())) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)"Check BepInEx console for your Steam ID hash"); } } GUILayout.EndVertical(); } private void DrawVersionCheckerSection() { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Expected O, but got Unknown //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Expected O, but got Unknown //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Expected O, but got Unknown GUILayout.Label("Version Checker:", _sectionHeaderStyle, Array.Empty<GUILayoutOption>()); GUILayout.Space(3f); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUI.enabled = !_isCheckingVersions; if (GUILayout.Button(_isCheckingVersions ? "Checking..." : "Check All Mod Versions", _buttonStyle, Array.Empty<GUILayoutOption>())) { CheckAllModVersions(); } GUI.enabled = true; if (GUILayout.Button("Test Notification", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) })) { TestUpdateNotification(); } GUILayout.EndHorizontal(); GUILayout.Space(5f); _versionScrollPosition = GUILayout.BeginScrollView(_versionScrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(140f) }); (string, string, string)[] knownMods = _knownMods; for (int i = 0; i < knownMods.Length; i++) { (string, string, string) tuple = knownMods[i]; GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label(tuple.Item2 + " v" + tuple.Item3, _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) }); if (_versionResults.TryGetValue(tuple.Item1, out var value)) { if (!value.Success) { GUIStyle val = new GUIStyle(_labelStyle); val.normal.textColor = new Color(1f, 0.5f, 0.5f); GUIStyle val2 = val; GUILayout.Label("Error: " + value.ErrorMessage, val2, Array.Empty<GUILayoutOption>()); } else if (value.UpdateAvailable) { GUIStyle val3 = new GUIStyle(_labelStyle); val3.normal.textColor = new Color(1f, 0.9f, 0.3f); GUIStyle val4 = val3; GUILayout.Label("Update: v" + value.LatestVersion, val4, Array.Empty<GUILayoutOption>()); } else { GUIStyle val5 = new GUIStyle(_labelStyle); val5.normal.textColor = new Color(0.5f, 1f, 0.5f); GUIStyle val6 = val5; GUILayout.Label("Up to date", val6, Array.Empty<GUILayoutOption>()); } } else { GUILayout.Label("Not checked", _labelStyle, Array.Empty<GUILayoutOption>()); } GUILayout.EndHorizontal(); } GUILayout.EndScrollView(); } private void CheckAllModVersions() { _isCheckingVersions = true; _versionResults.Clear(); int pendingChecks = _knownMods.Length; (string, string, string)[] knownMods = _knownMods; for (int i = 0; i < knownMods.Length; i++) { (string guid, string name, string version) mod = knownMods[i]; VersionChecker.CheckForUpdate(mod.guid, mod.version, Plugin.Log, delegate(VersionChecker.VersionCheckResult result) { _versionResults[mod.guid] = result; int num = pendingChecks; pendingChecks = num - 1; if (pendingChecks <= 0) { _isCheckingVersions = false; } if (result.Success) { if (result.UpdateAvailable) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[VersionChecker] " + mod.name + ": Update available v" + result.LatestVersion)); } } else { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)("[VersionChecker] " + mod.name + ": Up to date (v" + mod.version + ")")); } } } else { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)("[VersionChecker] " + mod.name + ": " + result.ErrorMessage)); } } }); } } private void TestUpdateNotification() { VersionChecker.VersionCheckResult result = new VersionChecker.VersionCheckResult { Success = true, UpdateAvailable = true, CurrentVersion = "1.0.0", LatestVersion = "9.9.9", ModName = "Test Mod (HavenDevTools)", NexusUrl = "https://www.nexusmods.com/sunhaven" }; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[VersionChecker] Testing notification system..."); } result.NotifyUpdateAvailable(Plugin.Log); } private void LogPlayerStats() { try { if ((Object)(object)Player.Instance == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"Player not available"); } return; } ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)"=== Player Stats ==="); } PropertyInfo[] properties = ((object)Player.Instance).GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); foreach (PropertyInfo propertyInfo in properties) { try { if (!propertyInfo.CanRead || propertyInfo.GetIndexParameters().Length != 0) { continue; } object value = propertyInfo.GetValue(Player.Instance); if (value != null && (value is int || value is float || value is string || value is bool)) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)$" {propertyInfo.Name}: {value}"); } } } catch { } } } catch (Exception ex) { ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogError((object)("Error logging player stats: " + ex.Message)); } } } } } namespace HavenDevTools.Services { public class BundleInspector { public BundleInspector() { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[BundleInspector] Initialized"); } } public List<MuseumSectionInfo> GetAllSections() { List<MuseumSectionInfo> list = new List<MuseumSectionInfo>(); if (!Plugin.HasSMUT) { return list; } try { Assembly sMUTAssembly = GetSMUTAssembly(); if (sMUTAssembly == null) { return list; } Type type = sMUTAssembly.GetType("SunHavenMuseumUtilityTracker.Data.MuseumContent"); if (type == null) { return list; } MethodInfo method = type.GetMethod("GetAllSections", BindingFlags.Static | BindingFlags.Public); if (method == null) { return list; } if (!(method.Invoke(null, null) is IList list2)) { return list; } foreach (object item2 in list2) { MuseumSectionInfo museumSectionInfo = new MuseumSectionInfo { Name = (item2.GetType().GetProperty("Name")?.GetValue(item2)?.ToString() ?? "Unknown"), Bundles = new List<MuseumBundleInfo>() }; PropertyInfo property = item2.GetType().GetProperty("Bundles"); if (property != null && property.GetValue(item2) is IList list3) { foreach (object item3 in list3) { MuseumBundleInfo museumBundleInfo = new MuseumBundleInfo { Name = (item3.GetType().GetProperty("Name")?.GetValue(item3)?.ToString() ?? "Unknown"), Items = new List<MuseumItemInfo>() }; PropertyInfo property2 = item3.GetType().GetProperty("Items"); if (property2 != null && property2.GetValue(item3) is IList list4) { foreach (object item4 in list4) { string name = item4.GetType().GetProperty("Name")?.GetValue(item4)?.ToString() ?? "Unknown"; MuseumItemInfo item = new MuseumItemInfo { Id = (item4.GetType().GetProperty("Id")?.GetValue(item4)?.ToString() ?? ""), Name = name, GameItemId = Convert.ToInt32(item4.GetType().GetProperty("GameItemId")?.GetValue(item4) ?? ((object)0)), Quantity = MuseumItemInfo.ParseQuantityFromName(name) }; museumBundleInfo.Items.Add(item); } } museumSectionInfo.Bundles.Add(museumBundleInfo); } } list.Add(museumSectionInfo); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[BundleInspector] Error getting sections: " + ex.Message)); } } return list; } public DonationStats GetDonationStats() { DonationStats donationStats = new DonationStats(); if (!Plugin.HasSMUT) { return donationStats; } try { Assembly sMUTAssembly = GetSMUTAssembly(); if (sMUTAssembly == null) { return donationStats; } Type type = sMUTAssembly.GetType("SunHavenMuseumUtilityTracker.Plugin"); if (type == null) { return donationStats; } MethodInfo method = type.GetMethod("GetDonationManager", BindingFlags.Static | BindingFlags.Public); if (method == null) { return donationStats; } object obj = method.Invoke(null, null); if (obj == null) { return donationStats; } PropertyInfo property = obj.GetType().GetProperty("IsLoaded"); if (property != null && !(bool)property.GetValue(obj)) { return donationStats; } MethodInfo method2 = obj.GetType().GetMethod("GetOverallStats"); if (method2 != null) { object obj2 = method2.Invoke(obj, null); if (obj2 != null) { FieldInfo fieldInfo = obj2.GetType().GetField("donated") ?? obj2.GetType().GetField("Item1"); FieldInfo fieldInfo2 = obj2.GetType().GetField("total") ?? obj2.GetType().GetField("Item2"); if (fieldInfo != null) { donationStats.TotalDonated = Convert.ToInt32(fieldInfo.GetValue(obj2)); } if (fieldInfo2 != null) { donationStats.TotalItems = Convert.ToInt32(fieldInfo2.GetValue(obj2)); } } } MethodInfo method3 = obj.GetType().GetMethod("GetOverallCompletionPercent"); if (method3 != null) { donationStats.CompletionPercent = (float)method3.Invoke(obj, null); } PropertyInfo property2 = obj.GetType().GetProperty("CurrentCharacter"); if (property2 != null) { donationStats.CharacterName = property2.GetValue(obj)?.ToString() ?? "Unknown"; } donationStats.IsLoaded = true; } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[BundleInspector] Error getting donation stats: " + ex.Message)); } } return donationStats; } public bool HasDonated(string itemId) { if (!Plugin.HasSMUT) { return false; } try { Assembly sMUTAssembly = GetSMUTAssembly(); if (sMUTAssembly == null) { return false; } object obj = (sMUTAssembly.GetType("SunHavenMuseumUtilityTracker.Plugin")?.GetMethod("GetDonationManager", BindingFlags.Static | BindingFlags.Public))?.Invoke(null, null); if (obj == null) { return false; } MethodInfo method = obj.GetType().GetMethod("HasDonated", new Type[1] { typeof(string) }); if (method != null) { return (bool)method.Invoke(obj, new object[1] { itemId }); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[BundleInspector] Error checking donation: " + ex.Message)); } } return false; } private Assembly GetSMUTAssembly() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (assembly.GetName().Name == "SunHavenMuseumUtilityTracker") { return assembly; } } return null; } } public class MuseumSectionInfo { public string Name { get; set; } public List<MuseumBundleInfo> Bundles { get; set; } } public class MuseumBundleInfo { public string Name { get; set; } public List<MuseumItemInfo> Items { get; set; } } public class MuseumItemInfo { public string Id { get; set; } public string Name { get; set; } public int GameItemId { get; set; } public int Quantity { get; set; } = 1; public static int ParseQuantityFromName(string name) { if (string.IsNullOrEmpty(name)) { return 1; } Match match = Regex.Match(name, "\\(x([\\d,]+)\\)"); if (match.Success && int.TryParse(match.Groups[1].Value.Replace(",", ""), out var result)) { return result; } return 1; } } public class DonationStats { public bool IsLoaded { get; set; } public string CharacterName { get; set; } public int TotalDonated { get; set; } public int TotalItems { get; set; } public float CompletionPercent { get; set; } } public class CurrencyTracker { public static readonly Dictionary<string, int> CurrencyItemIds = new Dictionary<string, int> { { "Spring Token", 18020 }, { "Summer Token", 18021 }, { "Fall Token", 18023 }, { "Winter Token", 18022 }, { "Copper Key", 1251 }, { "Iron Key", 1252 }, { "Adamant Key", 1253 }, { "Mithril Key", 1254 }, { "Sunite Key", 1255 }, { "Glorite Key", 1256 }, { "King's Lost Mine Key", 1257 }, { "Community Token", 18013 }, { "Doubloon", 60014 }, { "Black Bottle Cap", 60013 }, { "Red Carnival Ticket", 18012 }, { "Candy Corn Pieces", 18016 }, { "Mana Shard", 18015 } }; public CurrencyTracker() { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[CurrencyTracker] Initialized"); } } public int GetInventoryAmount(int itemId) { try { Player instance = Player.Instance; if ((Object)(object)((instance != null) ? instance.Inventory : null) == (Object)null) { return 0; } Inventory inventory = Player.Instance.Inventory; MethodInfo methodInfo = AccessTools.Method(((object)inventory).GetType(), "GetAmount", new Type[1] { typeof(int) }, (Type[])null); if (methodInfo != null) { return (int)methodInfo.Invoke(inventory, new object[1] { itemId }); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[CurrencyTracker] Error getting inventory amount: " + ex.Message)); } } return 0; } public int GetVaultAmount(string currencyId) { if (!Plugin.HasTheVault) { return 0; } try { Assembly vaultAssembly = GetVaultAssembly(); if (vaultAssembly == null) { return 0; } Type type = vaultAssembly.GetType("TheVault.Plugin"); if (type == null) { return 0; } MethodInfo method = type.GetMethod("GetVaultManager", BindingFlags.Static | BindingFlags.Public); if (method == null) { return 0; } object obj = method.Invoke(null, null); if (obj == null) { return 0; } MethodInfo method2 = obj.GetType().GetMethod("GetCurrency", new Type[1] { typeof(string) }); if (method2 != null) { return (int)method2.Invoke(obj, new object[1] { currencyId }); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[CurrencyTracker] Error getting vault amount: " + ex.Message)); } } return 0; } public Dictionary<string, int> GetAllVaultCurrencies() { Dictionary<string, int> result = new Dictionary<string, int>(); if (!Plugin.HasTheVault) { return result; } try { Assembly vaultAssembly = GetVaultAssembly(); if (vaultAssembly == null) { return result; } Type type = vaultAssembly.GetType("TheVault.Plugin"); if (type == null) { return result; } MethodInfo method = type.GetMethod("GetVaultManager", BindingFlags.Static | BindingFlags.Public); if (method == null) { return result; } object obj = method.Invoke(null, null); if (obj == null) { return result; } MethodInfo method2 = obj.GetType().GetMethod("GetAllNonZeroCurrencies"); if (method2 != null && method2.Invoke(obj, null) is Dictionary<string, int> result2) { return result2; } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[CurrencyTracker] Error getting all vault currencies: " + ex.Message)); } } return result; } public int GetGold() { try { Type type = AccessTools.TypeByName("Wish.GameSave"); if (type != null) { PropertyInfo property = type.GetProperty("Coins", BindingFlags.Static | BindingFlags.Public); if (property != null) { return (int)property.GetValue(null); } } Type type2 = AccessTools.TypeByName("SingletonBehaviour`1"); if (type2 != null && type != null) { PropertyInfo property2 = type2.MakeGenericType(type).GetProperty("Instance", BindingFlags.Static | BindingFlags.Public); if (property2 != null) { object value = property2.GetValue(null); if (value != null) { PropertyInfo property3 = value.GetType().GetProperty("CurrentSave"); if (property3 != null) { object value2 = property3.GetValue(value); if (value2 != null) { FieldInfo field = value2.GetType().GetField("coins", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { return Convert.ToInt32(field.GetValue(value2)); } } } } } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[CurrencyTracker] Error getting gold: " + ex.Message)); } } return 0; } public int GetOrbs() { try { if ((Object)(object)Player.Instance == (Object)null) { return 0; } PropertyInfo property = ((object)Player.Instance).GetType().GetProperty("Orbs", BindingFlags.Instance | BindingFlags.Public); if (property != null) { return (int)property.GetValue(Player.Instance); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[CurrencyTracker] Error getting orbs: " + ex.Message)); } } return 0; } public int GetTickets() { try { if ((Object)(object)Player.Instance == (Object)null) { return 0; } PropertyInfo property = ((object)Player.Instance).GetType().GetProperty("Tickets", BindingFlags.Instance | BindingFlags.Public); if (property != null) { return (int)property.GetValue(Player.Instance); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[CurrencyTracker] Error getting tickets: " + ex.Message)); } } return 0; } public CurrencySummary GetSummary() { CurrencySummary currencySummary = new CurrencySummary { Gold = GetGold(), Orbs = GetOrbs(), Tickets = GetTickets(), InventoryCurrencies = new Dictionary<string, int>(), VaultCurrencies = new Dictionary<string, int>() }; foreach (KeyValuePair<string, int> currencyItemId in CurrencyItemIds) { int inventoryAmount = GetInventoryAmount(currencyItemId.Value); if (inventoryAmount > 0) { currencySummary.InventoryCurrencies[currencyItemId.Key] = inventoryAmount; } } if (Plugin.HasTheVault) { currencySummary.VaultCurrencies = GetAllVaultCurrencies(); } return currencySummary; } private Assembly GetVaultAssembly() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (assembly.GetName().Name == "TheVault") { return assembly; } } return null; } } public class CurrencySummary { public int Gold { get; set; } public int Orbs { get; set; } public int Tickets { get; set; } public Dictionary<string, int> InventoryCurrencies { get; set; } public Dictionary<string, int> VaultCurrencies { get; set; } } public class ItemInspector { private Dictionary<int, GameItemInfo> _itemCache = new Dictionary<int, GameItemInfo>(); private Dictionary<string, int> _nameToIdCache = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); private bool _cacheBuilt; public int CacheCount => _itemCache.Count; public bool IsCacheBuilt => _cacheBuilt; public ItemInspector() { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[ItemInspector] Initialized"); } } public void BuildCache() { if (_cacheBuilt) { return; } try { Type type = AccessTools.TypeByName("Wish.ItemDatabase") ?? AccessTools.TypeByName("ItemDatabase"); if (type == null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[ItemInspector] Could not find ItemDatabase type"); } return; } PropertyInfo property = type.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public); if (property == null) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)"[ItemInspector] Could not find ItemDatabase.Instance"); } return; } object value = property.GetValue(null); if (value == null) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)"[ItemInspector] ItemDatabase.Instance is null"); } return; } FieldInfo field = type.GetField("items", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { field = type.GetField("_items", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } if (field != null) { object value2 = field.GetValue(value); if (value2 is IDictionary<int, object> dictionary) { foreach (KeyValuePair<int, object> item in dictionary) { CacheItem(item.Key, item.Value); } } else if (value2 is IEnumerable enumerable) { foreach (object item2 in enumerable) { PropertyInfo propertyInfo = item2.GetType().GetProperty("id") ?? item2.GetType().GetProperty("ID"); if (propertyInfo != null) { int id = (int)propertyInfo.GetValue(item2); CacheItem(id, item2); } } } } _cacheBuilt = true; ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogInfo((object)$"[ItemInspector] Built cache with {_itemCache.Count} items"); } } catch (Exception ex) { ManualLogSource log5 = Plugin.Log; if (log5 != null) { log5.LogError((object)("[ItemInspector] Error building cache: " + ex.Message)); } } } private void CacheItem(int id, object item) { try { Type type = item.GetType(); PropertyInfo? obj = type.GetProperty("name") ?? type.GetProperty("Name") ?? type.GetProperty("itemName"); PropertyInfo propertyInfo = type.GetProperty("description") ?? type.GetProperty("Description"); PropertyInfo propertyInfo2 = type.GetProperty("category") ?? type.GetProperty("Category"); PropertyInfo propertyInfo3 = type.GetProperty("sellPrice") ?? type.GetProperty("SellPrice"); string text = obj?.GetValue(item)?.ToString() ?? "Unknown"; string description = propertyInfo?.GetValue(item)?.ToString() ?? ""; string category = propertyInfo2?.GetValue(item)?.ToString() ?? "Unknown"; int sellPrice = ((propertyInfo3 != null) ? Convert.ToInt32(propertyInfo3.GetValue(item)) : 0); GameItemInfo value = new GameItemInfo { Id = id, Name = text, Description = description, Category = category, SellPrice = sellPrice }; _itemCache[id] = value; if (!_nameToIdCache.ContainsKey(text)) { _nameToIdCache[text] = id; } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)$"[ItemInspector] Error caching item {id}: {ex.Message}"); } } } public GameItemInfo GetItemById(int id) { if (!_cacheBuilt) { BuildCache(); } if (_itemCache.TryGetValue(id, out var value)) { return value; } return TryGetItemFromDatabase(id); } public List<GameItemInfo> SearchByName(string searchTerm) { if (!_cacheBuilt) { BuildCache(); } List<GameItemInfo> list = new List<GameItemInfo>(); string value = searchTerm.ToLower(); foreach (GameItemInfo value2 in _itemCache.Values) { if (value2.Name.ToLower().Contains(value)) { list.Add(value2); } } return list; } public int? GetIdByName(string name) { if (!_cacheBuilt) { BuildCache(); } if (_nameToIdCache.TryGetValue(name, out var value)) { return value; } return null; } public IEnumerable<GameItemInfo> GetAllItems() { if (!_cacheBuilt) { BuildCache(); } return _itemCache.Values; } public GameItemInfo GetHeldItem() { try { if ((Object)(object)Player.Instance == (Object)null || (Object)(object)Player.Instance.Inventory == (Object)null) { return null; } Inventory inventory = Player.Instance.Inventory; Type type = ((object)inventory).GetType(); int num = 0; PropertyInfo propertyInfo = type.GetProperty("SelectedSlot") ?? type.GetProperty("selectedSlot"); if (propertyInfo != null) { num = (int)propertyInfo.GetValue(inventory); } else { FieldInfo field = type.GetField("selectedSlot", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(field != null)) { return null; } num = (int)field.GetValue(inventory); } MethodInfo methodInfo = AccessTools.Method(((object)inventory).GetType(), "GetItem", new Type[1] { typeof(int) }, (Type[])null); if (methodInfo != null) { object obj = methodInfo.Invoke(inventory, new object[1] { num }); if (obj != null) { PropertyInfo propertyInfo2 = obj.GetType().GetProperty("id") ?? obj.GetType().GetProperty("ID"); if (propertyInfo2 != null) { int id = (int)propertyInfo2.GetValue(obj); return GetItemById(id); } } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[ItemInspector] Error getting held item: " + ex.Message)); } } return null; } private GameItemInfo TryGetItemFromDatabase(int id) { try { Type type = AccessTools.TypeByName("Wish.ItemDatabase") ?? AccessTools.TypeByName("ItemDatabase"); if (type == null) { return null; } MethodInfo methodInfo = AccessTools.Method(type, "GetItem", new Type[1] { typeof(int) }, (Type[])null); if (methodInfo == null) { return null; } object obj = type.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null); if (obj == null) { return null; } object obj2 = methodInfo.Invoke(obj, new object[1] { id }); if (obj2 != null) { CacheItem(id, obj2); GameItemInfo value; return _itemCache.TryGetValue(id, out value) ? value : null; } } catch { } return null; } public bool SpawnItem(int itemId, int amount = 1) { try { if ((Object)(object)Player.Instance == (Object)null || (Object)(object)Player.Instance.Inventory == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[ItemInspector] Player or inventory not available"); } return false; } Inventory inventory = Player.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 }); ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[ItemInspector] Spawned {amount}x item {itemId}"); } return true; } ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)"[ItemInspector] Could not find AddItem method"); } } catch (Exception ex) { ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogError((object)("[ItemInspector] Spawn error: " + ex.Message)); } } return false; } } public class GameItemInfo { public int Id { get; set; } public string Name { get; set; } public string Description { get; set; } public string Category { get; set; } public int SellPrice { get; set; } public override string ToString() { return $"[{Id}] {Name} ({Category}) - {SellPrice}g"; } } public class RaceModifierTracker { public RaceModifierTracker() { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[RaceModifierTracker] Initialized"); } } public string GetCurrentRace() { if (!Plugin.HasHavensBirthright) { return "Unknown (Haven's Birthright not loaded)"; } try { Assembly birthrightAssembly = GetBirthrightAssembly(); if (birthrightAssembly == null) { return "Unknown"; } Type type = birthrightAssembly.GetType("HavensBirthright.Plugin"); if (type == null) { return "Unknown"; } MethodInfo method = type.GetMethod("GetRacialBonusManager", BindingFlags.Static | BindingFlags.Public); if (method == null) { return "Unknown"; } object obj = method.Invoke(null, null); if (obj == null) { return "Unknown"; } MethodInfo method2 = obj.GetType().GetMethod("GetPlayerRace"); if (method2 != null) { object obj2 = method2.Invoke(obj, null); if (obj2 != null) { return obj2.ToString(); } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[RaceModifierTracker] Error getting race: " + ex.Message)); } } return "Unknown"; } public List<RaceBonusInfo> GetActiveRaceBonuses() { List<RaceBonusInfo> list = new List<RaceBonusInfo>(); if (!Plugin.HasHavensBirthright) { return list; } try { Assembly birthrightAssembly = GetBirthrightAssembly(); if (birthrightAssembly == null) { return list; } Type type = birthrightAssembly.GetType("HavensBirthright.Plugin"); if (type == null) { return list; } MethodInfo method = type.GetMethod("GetRacialBonusManager", BindingFlags.Static | BindingFlags.Public); if (method == null) { return list; } object obj = method.Invoke(null, null); if (obj == null) { return list; } MethodInfo method2 = obj.GetType().GetMethod("GetCurrentPlayerBonuses"); if (method2 == null) { return list; } if (!(method2.Invoke(obj, null) is IList list2)) { return list; } foreach (object item2 in list2) { Type type2 = item2.GetType(); PropertyInfo property = type2.GetProperty("Type"); PropertyInfo property2 = type2.GetProperty("Value"); PropertyInfo property3 = type2.GetProperty("IsPercentage"); PropertyInfo property4 = type2.GetProperty("Description"); RaceBonusInfo item = new RaceBonusInfo { Type = (property?.GetValue(item2)?.ToString() ?? "Unknown"), Value = ((property2 != null) ? Convert.ToSingle(property2.GetValue(item2)) : 0f), IsPercentage = (property3 != null && (bool)property3.GetValue(item2)), Description = (property4?.GetValue(item2)?.ToString() ?? "") }; list.Add(item); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[RaceModifierTracker] Error getting bonuses: " + ex.Message)); } } return list; } public List<RaceBonusInfo> GetBonusesForRace(string raceName) { List<RaceBonusInfo> list = new List<RaceBonusInfo>(); if (!Plugin.HasHavensBirthright) { return list; } try { Assembly birthrightAssembly = GetBirthrightAssembly(); if (birthrightAssembly == null) { return list; } Type type = birthrightAssembly.GetType("HavensBirthright.Plugin"); if (type == null) { return list; } MethodInfo method = type.GetMethod("GetRacialBonusManager", BindingFlags.Static | BindingFlags.Public); if (method == null) { return list; } object obj = method.Invoke(null, null); if (obj == null) { return list; } Type type2 = birthrightAssembly.GetType("HavensBirthright.Race"); if (type2 == null) { return list; } object obj2; try { obj2 = Enum.Parse(type2, raceName, ignoreCase: true); } catch { return list; } MethodInfo method2 = obj.GetType().GetMethod("GetBonusesForRace"); if (method2 == null) { return list; } if (!(method2.Invoke(obj, new object[1] { obj2 }) is IList list2)) { return list; } foreach (object item2 in list2) { Type type3 = item2.GetType(); PropertyInfo property = type3.GetProperty("Type"); PropertyInfo property2 = type3.GetProperty("Value"); PropertyInfo property3 = type3.GetProperty("IsPercentage"); PropertyInfo property4 = type3.GetProperty("Description"); RaceBonusInfo item = new RaceBonusInfo { Type = (property?.GetValue(item2)?.ToString() ?? "Unknown"), Value = ((property2 != null) ? Convert.ToSingle(property2.GetValue(item2)) : 0f), IsPercentage = (property3 != null && (bool)property3.GetValue(item2)), Description = (property4?.GetValue(item2)?.ToString() ?? "") }; list.Add(item); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[RaceModifierTracker] Error getting bonuses for race: " + ex.Message)); } } return list; } public List<string> GetAllRaces() { List<string> list = new List<string>(); if (!Plugin.HasHavensBirthright) { return new List<string> { "Human", "Elf", "Angel", "Demon", "Elemental", "FireElemental", "WaterElemental", "Amari", "AmariCat", "AmariDog", "AmariBird", "AmariAquatic", "AmariReptile", "Naga" }; } try { Ass