using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.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.API; using HavenDevTools.Config; using HavenDevTools.Integrations; using HavenDevTools.Services; using HavenDevTools.UI; using Microsoft.CodeAnalysis; using SunhavenMods.Shared; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Networking; using UnityEngine.SceneManagement; using UnityEngine.UI; using Wish; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("HavenDevTools")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+5c08b5aa5d0be9c4b93df77f697dc55d5ac97088")] [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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SunhavenMods.Shared { public static class ConfigFileHelper { public static ConfigFile CreateNamedConfig(string pluginGuid, string configFileName, Action logWarning = null) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown string text = Path.Combine(Paths.ConfigPath, configFileName); string text2 = Path.Combine(Paths.ConfigPath, pluginGuid + ".cfg"); try { if (!File.Exists(text) && File.Exists(text2)) { File.Copy(text2, text); } } catch (Exception ex) { logWarning?.Invoke("[Config] Migration to " + configFileName + " failed: " + ex.Message); } return new ConfigFile(text, true); } public static bool ReplacePluginConfig(BaseUnityPlugin plugin, ConfigFile newConfig, Action logWarning = null) { if ((Object)(object)plugin == (Object)null || newConfig == null) { return false; } try { Type typeFromHandle = typeof(BaseUnityPlugin); PropertyInfo property = typeFromHandle.GetProperty("Config", BindingFlags.Instance | BindingFlags.Public); if (property != null && property.CanWrite) { property.SetValue(plugin, newConfig, null); return true; } FieldInfo field = typeFromHandle.GetField("k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic); if (field != null) { field.SetValue(plugin, newConfig); return true; } FieldInfo[] fields = typeFromHandle.GetFields(BindingFlags.Instance | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (fieldInfo.FieldType == typeof(ConfigFile)) { fieldInfo.SetValue(plugin, newConfig); return true; } } } catch (Exception ex) { logWarning?.Invoke("[Config] ReplacePluginConfig failed: " + ex.Message); } return false; } } public static class VersionChecker { public class VersionCheckResult { public bool Success { get; set; } public bool UpdateAvailable { get; set; } public string CurrentVersion { get; set; } public string LatestVersion { get; set; } public string ModName { get; set; } public string NexusUrl { get; set; } public string Changelog { get; set; } public string ErrorMessage { get; set; } } public class ModHealthSnapshot { public string PluginGuid { get; set; } public DateTime LastCheckUtc { get; set; } public int ExceptionCount { get; set; } public string LastError { get; set; } } private class VersionCheckRunner : MonoBehaviour { private ManualLogSource _pluginLog; public void StartCheck(string pluginGuid, string currentVersion, ManualLogSource pluginLog, Action onComplete) { _pluginLog = pluginLog; ((MonoBehaviour)this).StartCoroutine(CheckVersionCoroutine(pluginGuid, currentVersion, onComplete)); } private void LogInfo(string message) { ManualLogSource pluginLog = _pluginLog; if (pluginLog != null) { pluginLog.LogInfo((object)("[VersionChecker] " + message)); } } private void LogWarningMsg(string message) { ManualLogSource pluginLog = _pluginLog; if (pluginLog != null) { pluginLog.LogWarning((object)("[VersionChecker] " + message)); } } private void LogErrorMsg(string message) { ManualLogSource pluginLog = _pluginLog; if (pluginLog != null) { pluginLog.LogError((object)("[VersionChecker] " + message)); } } private IEnumerator CheckVersionCoroutine(string pluginGuid, string currentVersion, Action onComplete) { VersionCheckResult result = new VersionCheckResult { CurrentVersion = currentVersion }; UnityWebRequest www = UnityWebRequest.Get("https://azraelgodking.github.io/SunhavenMod/versions.json"); try { www.timeout = 10; yield return www.SendWebRequest(); if ((int)www.result == 2 || (int)www.result == 3) { result.Success = false; result.ErrorMessage = "Network error: " + www.error; RecordHealthError(pluginGuid, result.ErrorMessage); LogWarningMsg(result.ErrorMessage); onComplete?.Invoke(result); Object.Destroy((Object)(object)((Component)this).gameObject); yield break; } try { string text = www.downloadHandler.text; Match match = GetModPattern(pluginGuid).Match(text); if (!match.Success) { result.Success = false; result.ErrorMessage = "Mod '" + pluginGuid + "' not found in versions.json"; RecordHealthError(pluginGuid, result.ErrorMessage); LogWarningMsg(result.ErrorMessage); onComplete?.Invoke(result); Object.Destroy((Object)(object)((Component)this).gameObject); yield break; } string value = match.Groups[1].Value; result.LatestVersion = ExtractJsonString(value, "version"); result.ModName = ExtractJsonString(value, "name"); result.NexusUrl = ExtractJsonString(value, "nexus"); result.Changelog = ExtractJsonString(value, "changelog"); if (string.IsNullOrEmpty(result.LatestVersion)) { result.Success = false; result.ErrorMessage = "Could not parse version from response"; RecordHealthError(pluginGuid, result.ErrorMessage); LogWarningMsg(result.ErrorMessage); onComplete?.Invoke(result); Object.Destroy((Object)(object)((Component)this).gameObject); yield break; } result.Success = true; result.UpdateAvailable = CompareVersions(currentVersion, result.LatestVersion) < 0; if (result.UpdateAvailable) { LogInfo("Update available for " + result.ModName + ": " + currentVersion + " -> " + result.LatestVersion); } else { LogInfo(result.ModName + " is up to date (v" + currentVersion + ")"); } } catch (Exception ex) { result.Success = false; result.ErrorMessage = "Parse error: " + ex.Message; RecordHealthError(pluginGuid, result.ErrorMessage); LogErrorMsg(result.ErrorMessage); } } finally { ((IDisposable)www)?.Dispose(); } onComplete?.Invoke(result); Object.Destroy((Object)(object)((Component)this).gameObject); } private string ExtractJsonString(string json, string key) { Match match = ExtractFieldRegex.Match(json); while (match.Success) { if (string.Equals(match.Groups["key"].Value, key, StringComparison.Ordinal)) { return match.Groups["value"].Value; } match = match.NextMatch(); } return null; } } private const string VersionsUrl = "https://azraelgodking.github.io/SunhavenMod/versions.json"; private static readonly Dictionary HealthByPluginGuid = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly object HealthLock = new object(); private static readonly Dictionary ModPatternCache = new Dictionary(StringComparer.Ordinal); private static readonly object ModPatternCacheLock = new object(); private static readonly Regex ExtractFieldRegex = new Regex("\"(?[^\"]+)\"\\s*:\\s*(?:\"(?[^\"]*)\"|null)", RegexOptions.Compiled); public static void CheckForUpdate(string pluginGuid, string currentVersion, ManualLogSource logger = null, Action onComplete = null) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) TouchHealth(pluginGuid); VersionCheckRunner versionCheckRunner = new GameObject("VersionChecker").AddComponent(); Object.DontDestroyOnLoad((Object)(object)((Component)versionCheckRunner).gameObject); SceneRootSurvivor.TryRegisterPersistentRunnerGameObject(((Component)versionCheckRunner).gameObject); versionCheckRunner.StartCheck(pluginGuid, currentVersion, logger, onComplete); } public static ModHealthSnapshot GetHealthSnapshot(string pluginGuid) { if (string.IsNullOrWhiteSpace(pluginGuid)) { return null; } lock (HealthLock) { if (!HealthByPluginGuid.TryGetValue(pluginGuid, out ModHealthSnapshot value)) { return null; } return new ModHealthSnapshot { PluginGuid = value.PluginGuid, LastCheckUtc = value.LastCheckUtc, ExceptionCount = value.ExceptionCount, LastError = value.LastError }; } } public static int CompareVersions(string v1, string v2) { if (string.IsNullOrEmpty(v1) || string.IsNullOrEmpty(v2)) { return 0; } v1 = v1.TrimStart('v', 'V'); v2 = v2.TrimStart('v', 'V'); int num = v1.IndexOfAny(new char[2] { '-', '+' }); if (num >= 0) { v1 = v1.Substring(0, num); } int num2 = v2.IndexOfAny(new char[2] { '-', '+' }); if (num2 >= 0) { v2 = v2.Substring(0, num2); } string[] array = v1.Split(new char[1] { '.' }); string[] array2 = v2.Split(new char[1] { '.' }); int num3 = Math.Max(array.Length, array2.Length); for (int i = 0; i < num3; i++) { int result; int num4 = ((i < array.Length && int.TryParse(array[i], out result)) ? result : 0); int result2; int num5 = ((i < array2.Length && int.TryParse(array2[i], out result2)) ? result2 : 0); if (num4 < num5) { return -1; } if (num4 > num5) { return 1; } } return 0; } private static void TouchHealth(string pluginGuid) { if (string.IsNullOrWhiteSpace(pluginGuid)) { return; } lock (HealthLock) { if (!HealthByPluginGuid.TryGetValue(pluginGuid, out ModHealthSnapshot value)) { value = new ModHealthSnapshot { PluginGuid = pluginGuid }; HealthByPluginGuid[pluginGuid] = value; } value.LastCheckUtc = DateTime.UtcNow; } } private static void RecordHealthError(string pluginGuid, string errorMessage) { if (string.IsNullOrWhiteSpace(pluginGuid)) { return; } lock (HealthLock) { if (!HealthByPluginGuid.TryGetValue(pluginGuid, out ModHealthSnapshot value)) { value = new ModHealthSnapshot { PluginGuid = pluginGuid }; HealthByPluginGuid[pluginGuid] = value; } value.LastCheckUtc = DateTime.UtcNow; value.ExceptionCount++; value.LastError = errorMessage; } } private static Regex GetModPattern(string pluginGuid) { lock (ModPatternCacheLock) { if (!ModPatternCache.TryGetValue(pluginGuid, out Regex value)) { value = new Regex("\"" + Regex.Escape(pluginGuid) + "\"\\s*:\\s*\\{([^}]+)\\}", RegexOptions.Compiled | RegexOptions.Singleline); ModPatternCache[pluginGuid] = value; } return value; } } } public static class VersionCheckerExtensions { public static void NotifyUpdateAvailable(this VersionChecker.VersionCheckResult result, ManualLogSource logger = null) { if (!result.UpdateAvailable) { return; } string text = result.ModName + " update available: v" + result.LatestVersion; try { Type type = ReflectionHelper.FindWishType("NotificationStack"); if (type != null) { Type type2 = ReflectionHelper.FindType("SingletonBehaviour`1", "Wish"); if (type2 != null) { object obj = type2.MakeGenericType(type).GetProperty("Instance")?.GetValue(null); if (obj != null) { MethodInfo method = type.GetMethod("SendNotification", new Type[5] { typeof(string), typeof(int), typeof(int), typeof(bool), typeof(bool) }); if (method != null) { method.Invoke(obj, new object[5] { text, 0, 1, false, true }); return; } } } } } catch (Exception ex) { if (logger != null) { logger.LogWarning((object)("Failed to send native notification: " + ex.Message)); } } if (logger != null) { logger.LogWarning((object)("[UPDATE AVAILABLE] " + text)); } if (!string.IsNullOrEmpty(result.NexusUrl) && logger != null) { logger.LogWarning((object)("Download at: " + result.NexusUrl)); } } } public static class SceneRootSurvivor { private static readonly object Lock = new object(); private static readonly List NoKillSubstrings = new List(); private static Harmony _harmony; public static void TryRegisterPersistentRunnerGameObject(GameObject go) { if (!((Object)(object)go == (Object)null)) { TryAddNoKillListSubstring(((Object)go).name); } } public static void TryAddNoKillListSubstring(string nameSubstring) { if (string.IsNullOrEmpty(nameSubstring)) { return; } lock (Lock) { bool flag = false; for (int i = 0; i < NoKillSubstrings.Count; i++) { if (string.Equals(NoKillSubstrings[i], nameSubstring, StringComparison.OrdinalIgnoreCase)) { flag = true; break; } } if (!flag) { NoKillSubstrings.Add(nameSubstring); } } EnsurePatched(); } private static void EnsurePatched() { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown //IL_00a3: Expected O, but got Unknown if (_harmony != null) { return; } lock (Lock) { if (_harmony == null) { MethodInfo methodInfo = AccessTools.Method(typeof(Scene), "GetRootGameObjects", Type.EmptyTypes, (Type[])null); if (!(methodInfo == null)) { string text = typeof(SceneRootSurvivor).Assembly.GetName().Name ?? "Unknown"; Harmony val = new Harmony("SunhavenMods.SceneRootSurvivor." + text); val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(SceneRootSurvivor), "OnGetRootGameObjectsPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _harmony = val; } } } } private static void OnGetRootGameObjectsPostfix(ref GameObject[] __result) { if (__result == null || __result.Length == 0) { return; } List list; lock (Lock) { if (NoKillSubstrings.Count == 0) { return; } list = new List(NoKillSubstrings); } List list2 = new List(__result); for (int i = 0; i < list.Count; i++) { string noKill = list[i]; list2.RemoveAll((GameObject a) => (Object)(object)a != (Object)null && ((Object)a).name.IndexOf(noKill, StringComparison.OrdinalIgnoreCase) >= 0); } __result = list2.ToArray(); } } public static class ReflectionHelper { public static readonly BindingFlags AllBindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy; public static Type FindType(string typeName, params string[] namespaces) { string typeName2 = typeName; Type type = AccessTools.TypeByName(typeName2); if (type != null) { return type; } for (int i = 0; i < namespaces.Length; i++) { type = AccessTools.TypeByName(namespaces[i] + "." + typeName2); if (type != null) { return type; } } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { type = assembly.GetTypes().FirstOrDefault((Type t) => t.Name == typeName2 || t.FullName == typeName2); if (type != null) { return type; } } catch (ReflectionTypeLoadException) { } } return null; } public static Type FindWishType(string typeName) { return FindType(typeName, "Wish"); } public static object GetStaticValue(Type type, string memberName) { if (type == null) { return null; } try { PropertyInfo property = type.GetProperty(memberName, AllBindingFlags); if (property != null && property.GetMethod != null && property.GetIndexParameters().Length == 0) { return property.GetValue(null); } } catch (AmbiguousMatchException) { return null; } FieldInfo field = type.GetField(memberName, AllBindingFlags); if (field != null) { return field.GetValue(null); } return null; } public static object GetSingletonInstance(Type type) { if (type == null) { return null; } string[] array = new string[5] { "Instance", "instance", "_instance", "Singleton", "singleton" }; foreach (string memberName in array) { object staticValue = GetStaticValue(type, memberName); if (staticValue != null) { return staticValue; } } return null; } public static object GetInstanceValue(object instance, string memberName) { if (instance == null) { return null; } Type type = instance.GetType(); while (type != null) { PropertyInfo property = type.GetProperty(memberName, AllBindingFlags); if (property != null && property.GetMethod != null) { return property.GetValue(instance); } FieldInfo field = type.GetField(memberName, AllBindingFlags); if (field != null) { return field.GetValue(instance); } type = type.BaseType; } return null; } public static bool SetInstanceValue(object instance, string memberName, object value) { if (instance == null) { return false; } Type type = instance.GetType(); while (type != null) { PropertyInfo property = type.GetProperty(memberName, AllBindingFlags); if (property != null && property.SetMethod != null) { property.SetValue(instance, value); return true; } FieldInfo field = type.GetField(memberName, AllBindingFlags); if (field != null) { field.SetValue(instance, value); return true; } type = type.BaseType; } return false; } public static object InvokeMethod(object instance, string methodName, params object[] args) { if (instance == null) { return null; } Type type = instance.GetType(); Type[] array = args?.Select((object a) => a?.GetType() ?? typeof(object)).ToArray() ?? Type.EmptyTypes; MethodInfo methodInfo = AccessTools.Method(type, methodName, array, (Type[])null); if (methodInfo == null) { methodInfo = type.GetMethod(methodName, AllBindingFlags); } if (methodInfo == null) { return null; } return methodInfo.Invoke(instance, args); } public static object InvokeStaticMethod(Type type, string methodName, params object[] args) { if (type == null) { return null; } Type[] array = args?.Select((object a) => a?.GetType() ?? typeof(object)).ToArray() ?? Type.EmptyTypes; MethodInfo methodInfo = AccessTools.Method(type, methodName, array, (Type[])null); if (methodInfo == null) { methodInfo = type.GetMethod(methodName, AllBindingFlags); } if (methodInfo == null) { return null; } return methodInfo.Invoke(null, args); } public static FieldInfo[] GetAllFields(Type type) { if (type == null) { return Array.Empty(); } FieldInfo[] fields = type.GetFields(AllBindingFlags); IEnumerable second; if (!(type.BaseType != null) || !(type.BaseType != typeof(object))) { second = Enumerable.Empty(); } else { IEnumerable 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[] properties = type.GetProperties(AllBindingFlags); IEnumerable second; if (!(type.BaseType != null) || !(type.BaseType != typeof(object))) { second = Enumerable.Empty(); } else { IEnumerable 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(object instance, string memberName, T defaultValue = default(T)) { try { object instanceValue = GetInstanceValue(instance, memberName); if (instanceValue is T result) { return result; } if (instanceValue != null && typeof(T).IsAssignableFrom(instanceValue.GetType())) { return (T)instanceValue; } return defaultValue; } catch { return defaultValue; } } } public static class ItemSearch { private static readonly ManualLogSource _log = Logger.CreateLogSource("ItemSearch"); private static object _dbInstance; private static FieldInfo _dictField; public static string FormatDisplay(string name, int itemId) { if (string.IsNullOrEmpty(name)) { return $"#{itemId}"; } return $"{name} (#{itemId})"; } public static List> SearchItems(string query, int maxResults = 50) { List> list = new List>(); if (string.IsNullOrEmpty(query) || query.Trim().Length < 2) { return list; } try { Dictionary itemDictionary = GetItemDictionary(); if (itemDictionary == null) { return list; } string text = query.Trim().ToLowerInvariant(); int result; bool flag = int.TryParse(query.Trim(), out result); List> list2 = new List>(); List> list3 = new List>(); List> list4 = new List>(); foreach (KeyValuePair item2 in itemDictionary) { int key = item2.Key; string text2 = item2.Value?.name; if (!string.IsNullOrEmpty(text2)) { KeyValuePair item = new KeyValuePair(key, text2); string text3 = text2.ToLowerInvariant(); if (flag && key == result) { list2.Add(item); } else if (text3 == text) { list2.Add(item); } else if (text3.StartsWith(text)) { list3.Add(item); } else if (text3.Contains(text)) { list4.Add(item); } else if (flag && key.ToString().Contains(query.Trim())) { list4.Add(item); } } } list3.Sort((KeyValuePair a, KeyValuePair b) => string.Compare(a.Value, b.Value, StringComparison.OrdinalIgnoreCase)); list4.Sort((KeyValuePair a, KeyValuePair b) => string.Compare(a.Value, b.Value, StringComparison.OrdinalIgnoreCase)); list.AddRange(list2); list.AddRange(list3); list.AddRange(list4); if (list.Count > maxResults) { list.RemoveRange(maxResults, list.Count - maxResults); } } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogDebug((object)("[ItemSearch] SearchItems error: " + ex.Message)); } } return list; } public static string GetItemName(int itemId) { try { Dictionary itemDictionary = GetItemDictionary(); if (itemDictionary == null || !itemDictionary.ContainsKey(itemId)) { return null; } return itemDictionary[itemId]?.name; } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogDebug((object)$"[ItemSearch] GetItemName({itemId}): {ex.Message}"); } return null; } } public static ItemSellInfo GetItemSellInfo(int itemId) { try { Dictionary itemDictionary = GetItemDictionary(); if (itemDictionary != null && itemDictionary.TryGetValue(itemId, out var value)) { return value; } } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogDebug((object)$"[ItemSearch] GetItemSellInfo({itemId}): {ex.Message}"); } } return null; } private static Dictionary GetItemDictionary() { try { if (_dbInstance != null) { object dbInstance = _dbInstance; Object val = (Object)((dbInstance is Object) ? dbInstance : null); if (val == null || !(val == (Object)null)) { goto IL_005b; } } _dbInstance = null; _dictField = null; _dbInstance = GetSingletonInstance("Wish.ItemInfoDatabase"); if (_dbInstance != null) { _dictField = _dbInstance.GetType().GetField("allItemSellInfos", BindingFlags.Instance | BindingFlags.Public); } goto IL_005b; IL_005b: if (_dbInstance == null || _dictField == null) { return null; } return _dictField.GetValue(_dbInstance) as Dictionary; } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogDebug((object)("[ItemSearch] GetItemDictionary: " + ex.Message)); } return null; } } private static object GetSingletonInstance(string typeName) { try { Type type = AccessTools.TypeByName("Wish.SingletonBehaviour`1"); if (type == null) { return null; } Type type2 = AccessTools.TypeByName(typeName); if (type2 == null) { return null; } return type.MakeGenericType(type2).GetProperty("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy)?.GetValue(null); } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogDebug((object)("[ItemSearch] GetSingletonInstance(" + typeName + "): " + ex.Message)); } return null; } } } public static class TextInputFocusGuard { private const float DefaultPollIntervalSeconds = 0.25f; private static float _nextPollTime = -1f; private static bool _cachedDefer; private static bool _tmpTypeLookupDone; private static Type _tmpInputFieldType; private static bool _qcLookupDone; private static Type _qcType; private static PropertyInfo _qcInstanceProp; private static PropertyInfo _qcIsActiveProp; private static FieldInfo _qcIsActiveField; public static bool ShouldDeferModHotkeys(ManualLogSource debugLog = null, float pollIntervalSeconds = 0.25f) { float realtimeSinceStartup = Time.realtimeSinceStartup; if (realtimeSinceStartup < _nextPollTime) { return _cachedDefer; } _nextPollTime = realtimeSinceStartup + Mathf.Max(0.05f, pollIntervalSeconds); bool flag = false; try { if (GUIUtility.keyboardControl != 0) { flag = true; } if (!flag) { EventSystem current = EventSystem.current; GameObject val = ((current != null) ? current.currentSelectedGameObject : null); if ((Object)(object)val != (Object)null) { if ((Object)(object)val.GetComponent() != (Object)null) { flag = true; } else if (TryGetTmpInputField(val)) { flag = true; } } } if (!flag && IsQuantumConsoleActive(debugLog)) { flag = true; } } catch (Exception ex) { if (debugLog != null) { debugLog.LogDebug((object)("[TextInputFocusGuard] " + ex.Message)); } } _cachedDefer = flag; return flag; } private static bool TryGetTmpInputField(GameObject go) { if (!_tmpTypeLookupDone) { _tmpTypeLookupDone = true; _tmpInputFieldType = AccessTools.TypeByName("TMPro.TMP_InputField"); } if (_tmpInputFieldType == null) { return false; } return (Object)(object)go.GetComponent(_tmpInputFieldType) != (Object)null; } private static bool IsQuantumConsoleActive(ManualLogSource debugLog) { try { if (!_qcLookupDone) { _qcLookupDone = true; _qcType = AccessTools.TypeByName("QFSW.QC.QuantumConsole"); if (_qcType != null) { _qcInstanceProp = AccessTools.Property(_qcType, "Instance"); _qcIsActiveProp = AccessTools.Property(_qcType, "IsActive"); _qcIsActiveField = AccessTools.Field(_qcType, "isActive") ?? AccessTools.Field(_qcType, "_isActive"); } } if (_qcType == null) { return false; } object obj = _qcInstanceProp?.GetValue(null); if (obj == null) { return false; } if (_qcIsActiveProp != null && _qcIsActiveProp.PropertyType == typeof(bool)) { return (bool)_qcIsActiveProp.GetValue(obj); } if (_qcIsActiveField != null && _qcIsActiveField.FieldType == typeof(bool)) { return (bool)_qcIsActiveField.GetValue(obj); } } catch (Exception ex) { if (debugLog != null) { debugLog.LogDebug((object)("[TextInputFocusGuard] Quantum Console focus check failed: " + ex.Message)); } } return false; } } } namespace HavenDevTools { [BepInPlugin("com.azraelgodking.havendevtools", "Haven Dev Tools", "1.2.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [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 CommandConsole _staticCommandConsole; private static LogViewerPanel _staticLogViewer; private static GameObject _persistentRunner; private static PersistentRunner _persistentRunnerComponent; internal static KeyCode StaticToggleKey = (KeyCode)292; internal static KeyCode StaticOverlayToggleKey = (KeyCode)287; private static readonly HashSet _authorizedSteamIdHashes = new HashSet { "Tr4eyf86yKRu6fhNQjQOrO/ZnwasQaY/fgKV0PcnoGA=" }; private static bool _isAuthorized; private static string _currentSteamId; private static string _currentPlayerName; private Harmony _harmony; private bool _applicationQuitting; 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 HasSenpaisChest { get; private set; } public static bool HasBirthdayReminder { get; private set; } public static bool HasSunhavenTodo { get; private set; } public static bool HasHavensAlmanac { get; private set; } public static bool HasTrinketFortune { get; private set; } public static bool IsAuthorized => _isAuthorized; public static string CurrentPlayerName => _currentPlayerName; private void Awake() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Expected O, but got Unknown //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) Instance = this; Log = ((BaseUnityPlugin)this).Logger; ConfigFile = CreateNamedConfig(); ConfigFileHelper.ReplacePluginConfig((BaseUnityPlugin)(object)this, ConfigFile, (Action)Log.LogWarning); Log.LogInfo((object)"Loading Haven Dev Tools v1.2.2"); try { ModConfig.Initialize(ConfigFile); StaticToggleKey = ModConfig.ToggleKey.Value; StaticOverlayToggleKey = ModConfig.OverlayToggleKey.Value; CreatePersistentRunner(); DetectInstalledMods(); ModConfig.SyncTheVaultFullVaultInspectorToPlugin(); _staticItemInspector = new ItemInspector(); _staticCurrencyTracker = new CurrencyTracker(); _staticBundleInspector = new BundleInspector(); _staticRaceModifierTracker = new RaceModifierTracker(); _staticCommandConsole = new CommandConsole(); _staticLogViewer = new LogViewerPanel(); CreateUIComponents(); _harmony = new Harmony("com.azraelgodking.havendevtools"); PatchPlayerInit(); SceneManager.sceneLoaded += OnSceneLoaded; if (ModConfig.CheckForUpdates.Value) { VersionChecker.CheckForUpdate("com.azraelgodking.havendevtools", "1.2.2", 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}, Birthright: {HasHavensBirthright}, SenpaisChest: {HasSenpaisChest}, Birthday: {HasBirthdayReminder}, Todo: {HasSunhavenTodo}, Almanac: {HasHavensAlmanac}, TrinketFortune: {HasTrinketFortune}"); } catch (Exception arg) { Log.LogError((object)string.Format("Failed to load {0}: {1}", "Haven Dev Tools", arg)); } } private static ConfigFile CreateNamedConfig() { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown string text = Path.Combine(Paths.ConfigPath, "HavenDevTools.cfg"); string text2 = Path.Combine(Paths.ConfigPath, "com.azraelgodking.havendevtools.cfg"); try { if (!File.Exists(text) && File.Exists(text2)) { File.Copy(text2, text); } } catch (Exception ex) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("[Config] Migration to HavenDevTools.cfg failed: " + ex.Message)); } } return new ConfigFile(text, true); } private void CreatePersistentRunner() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown if (!((Object)(object)_persistentRunner != (Object)null) || !((Object)(object)_persistentRunnerComponent != (Object)null)) { _persistentRunner = new GameObject("HavenDevTools_PersistentRunner"); Object.DontDestroyOnLoad((Object)(object)_persistentRunner); ((Object)_persistentRunner).hideFlags = (HideFlags)61; SceneRootSurvivor.TryRegisterPersistentRunnerGameObject(_persistentRunner); _persistentRunnerComponent = _persistentRunner.AddComponent(); 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(); _staticDebugOverlay = val.AddComponent(); 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_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Expected O, but got Unknown //IL_00c1: 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; SceneRootSurvivor.TryRegisterPersistentRunnerGameObject(_persistentRunner); _persistentRunnerComponent = _persistentRunner.AddComponent(); 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(); _staticDebugOverlay = val.AddComponent(); 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(); } if (_staticCommandConsole == null) { _staticCommandConsole = new CommandConsole(); } if (_staticLogViewer == null) { _staticLogViewer = new LogViewerPanel(); } } 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; } if (name == "SenpaisChest") { HasSenpaisChest = true; } if (name == "BirthdayReminder") { HasBirthdayReminder = true; } if (name == "SunhavenTodo") { HasSunhavenTodo = true; } if (name == "HavensAlmanac") { HasHavensAlmanac = true; } if (name == "TrinketFortune") { HasTrinketFortune = true; } } Log.LogInfo((object)$"Mod detection complete - TheVault: {HasTheVault}, SMUT: {HasSMUT}, Birthright: {HasHavensBirthright}, SenpaisChest: {HasSenpaisChest}, Birthday: {HasBirthdayReminder}, Todo: {HasSunhavenTodo}, Almanac: {HasHavensAlmanac}, TrinketFortune: {HasTrinketFortune}"); } 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.LogDebug((object)("[SceneChange] Scene loaded: '" + ((Scene)(ref scene)).name + "'")); string text = ((Scene)(ref scene)).name.ToLowerInvariant(); if (text.Contains("menu") || text.Contains("title")) { Log.LogDebug((object)("Menu scene detected: " + ((Scene)(ref scene)).name)); _isAuthorized = false; _currentPlayerName = null; } } private void OnApplicationQuit() { _applicationQuitting = true; } private void OnDestroy() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) SceneManager.sceneLoaded -= OnSceneLoaded; Scene activeScene = SceneManager.GetActiveScene(); string text = ((Scene)(ref activeScene)).name ?? string.Empty; string text2 = text.ToLowerInvariant(); if (_applicationQuitting || !Application.isPlaying || text2.Contains("menu") || text2.Contains("title")) { ManualLogSource log = Log; if (log != null) { log.LogInfo((object)("[Lifecycle] Plugin OnDestroy during expected teardown (scene: " + text + ")")); } } else { ManualLogSource log2 = Log; if (log2 != null) { log2.LogWarning((object)("[Lifecycle] Plugin OnDestroy outside expected teardown (scene: " + text + ")")); } } } 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 (Exception ex) { ManualLogSource log = Log; if (log != null) { log.LogDebug((object)("[HavenDevTools] Player name fallback: " + ex.Message)); } _currentPlayerName = "Unknown"; } _currentSteamId = TryGetSteamId(); if (!string.IsNullOrEmpty(_currentSteamId)) { string text = ComputeHash(_currentSteamId); if (_authorizedSteamIdHashes.Contains(text)) { ManualLogSource log2 = Log; if (log2 != null) { log2.LogInfo((object)"[HavenDevTools] Authorized via Steam ID"); } _isAuthorized = true; return; } ManualLogSource log3 = Log; if (log3 != null) { log3.LogInfo((object)("[HavenDevTools] Steam ID hash not authorized: " + text)); } } else { ManualLogSource log4 = Log; if (log4 != null) { log4.LogInfo((object)"[HavenDevTools] Could not retrieve Steam ID"); } } ManualLogSource log5 = Log; if (log5 != null) { log5.LogInfo((object)"[HavenDevTools] Not authorized - Steam ID required"); } } catch (Exception ex2) { ManualLogSource log6 = Log; if (log6 != null) { log6.LogError((object)("[HavenDevTools] Authorization error: " + ex2.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 (Exception ex) { ManualLogSource log = Log; if (log != null) { log.LogDebug((object)("[HavenDevTools] TryGetSteamId assembly search: " + ex.Message)); } } } } 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 obj = method.Invoke(null, null); if (obj == null) { return null; } string text = obj.ToString(); if (string.IsNullOrEmpty(text) || text == "0" || text.Length < 10) { return null; } return text; } catch (Exception ex2) { ManualLogSource log2 = Log; if (log2 != null) { log2.LogDebug((object)("[HavenDevTools] TryGetSteamId: " + ex2.Message)); } 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 CommandConsole GetCommandConsole() { return _staticCommandConsole; } public static LogViewerPanel GetLogViewer() { return _staticLogViewer; } 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 float _heartbeatTimer; private int _heartbeatCount; private const float HEARTBEAT_INTERVAL = 30f; private bool _syncedTheVaultInspectorOnce; 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() { if (!_syncedTheVaultInspectorOnce) { _syncedTheVaultInspectorOnce = true; ModConfig.SyncTheVaultFullVaultInspectorToPlugin(); } CheckHotkeys(); _heartbeatTimer += Time.deltaTime; if (_heartbeatTimer >= 30f) { _heartbeatTimer = 0f; _heartbeatCount++; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)string.Format("[PersistentRunner Heartbeat #{0}] Authorized: {1}, Player: {2}", _heartbeatCount, Plugin.IsAuthorized, Plugin.CurrentPlayerName ?? "none")); } } } private void CheckHotkeys() { //IL_0013: 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) try { if (!TextInputFocusGuard.ShouldDeferModHotkeys(Plugin.Log)) { 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 OnDestroy() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) Scene activeScene = SceneManager.GetActiveScene(); string text = (((Scene)(ref activeScene)).name ?? string.Empty).ToLowerInvariant(); if (!Application.isPlaying || text.Contains("menu") || text.Contains("title")) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[PersistentRunner] OnDestroy during app quit/menu unload (expected)."); } } else { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)"[PersistentRunner] OnDestroy outside quit/menu (unexpected)."); } } } } public static class PluginInfo { public const string PLUGIN_GUID = "com.azraelgodking.havendevtools"; public const string PLUGIN_NAME = "Haven Dev Tools"; public const string PLUGIN_VERSION = "1.2.2"; } } 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_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_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: 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; (int, string)? tuple = Plugin.GetItemInspector()?.GetHeldItem(); _heldItemInfo = (tuple.HasValue ? $"{tuple.Value.Item2} ({tuple.Value.Item1})" : "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_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: 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_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: 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_00ab: Unknown result type (might be due to invalid IL or missing references) float num = 220f; ConfigEntry showPerformance = ModConfig.ShowPerformance; float num2 = ((showPerformance == null || showPerformance.Value) ? 155 : 130); 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()); GUILayout.Space(3f); DrawRow("Player:", _playerName); DrawRow("Race:", _currentRace); DrawRow("Gold:", _gold.ToString("N0")); DrawRow("Position:", _position); DrawRow("Held:", _heldItemInfo); ConfigEntry showPerformance = ModConfig.ShowPerformance; if (showPerformance == null || showPerformance.Value) { float num = 1f / Mathf.Max(0.0001f, Time.deltaTime); float num2 = (float)GC.GetTotalMemory(forceFullCollection: false) / 1048576f; DrawRow("FPS:", num.ToString("F1")); DrawRow("Memory:", $"{num2:F1} MB"); } GUILayout.FlexibleSpace(); GUILayout.Label("F11: Window | F6: Toggle", _labelStyle, Array.Empty()); } private void DrawRow(string label, string value) { GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label(label, _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(55f) }); GUILayout.Label(value, _valueStyle, Array.Empty()); 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[3] { "Tools", "Azrael's Mods", "Extensions" }; private int _toolsSubTab; private readonly string[] _toolsSubTabNames = new string[6] { "Items", "Currencies", "Console", "Log", "Perf", "Utility" }; private string _itemSearchText = ""; private string _lastItemSearchQuery; private string _itemIdInput = ""; private string _spawnAmount = "1"; private int _selectedItemId; private string _selectedItemName = ""; private List> _searchResults = new List>(); private Vector2 _itemScrollPosition; private Vector2 _currencyScrollPosition; private int _selectedSectionIndex; private int _selectedBundleIndex; private Vector2 _bundleScrollPosition; private int _selectedRaceIndex; private Vector2 _raceScrollPosition; private static Dictionary _versionResults = new Dictionary(); private static bool _isCheckingVersions; private Vector2 _versionScrollPosition; private static readonly (string guid, string name, string version)[] _knownMods = new(string, string, string)[12] { ("com.azraelgodking.havendevtools", "Haven Dev Tools", "1.2.2"), ("com.azraelgodking.senpaischest", "Senpai's Chest", "2.6.2"), ("com.azraelgodking.squirrelsbirthdayreminder", "Birthday Reminder", "1.4.2"), ("com.azraelgodking.havensbirthright", "Haven's Birthright", "2.2.2"), ("com.azraelgodking.sunhavenmuseumutilitytracker", "S.M.U.T.", "2.4.2"), ("com.azraelgodking.sunhaventodo", "Sunhaven Todo", "1.4.2"), ("com.azraelgodking.thevault", "The Vault", "3.3.2"), ("com.azraelgodking.havensalmanac", "Haven's Almanac", "1.4.2"), ("com.azraelgodking.fasterraces", "Faster Races", "1.4.2"), ("com.azraelgodking.trinketfortune", "Trinket Fortune", "1.2.2"), ("com.azraelgodking.cropoptimizer", "Crop Optimizer", "1.4.2"), ("com.azraelgodking.havensrespec", "Haven's Respec", "1.3.2") }; 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_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) GUILayout.Label("Haven Dev Tools", _headerStyle, Array.Empty()); GUILayout.Label("Player: " + Plugin.CurrentPlayerName, _labelStyle, Array.Empty()); GUILayout.Space(5f); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("TheVault: " + (Plugin.HasTheVault ? "Yes" : "No"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(100f) }); GUILayout.Label("SMUT: " + (Plugin.HasSMUT ? "Yes" : "No"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }); GUILayout.Label("Birthright: " + (Plugin.HasHavensBirthright ? "Yes" : "No"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(100f) }); GUILayout.Label("Senpai: " + (Plugin.HasSenpaisChest ? "Yes" : "No"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }); GUILayout.Label("Todo: " + (Plugin.HasSunhavenTodo ? "Yes" : "No"), _labelStyle, Array.Empty()); GUILayout.EndHorizontal(); GUILayout.Space(10f); _selectedTab = GUILayout.Toolbar(_selectedTab, _tabNames, _buttonStyle, Array.Empty()); GUILayout.Space(10f); _scrollPosition = GUILayout.BeginScrollView(_scrollPosition, Array.Empty()); switch (_selectedTab) { case 0: DrawToolsTab(); break; case 1: AzraelsModsPanel.Draw(_boxStyle, _buttonStyle, _labelStyle, _sectionHeaderStyle); break; case 2: DrawExtensionsTab(); break; } GUILayout.EndScrollView(); GUILayout.Space(10f); if (GUILayout.Button("Close (Esc)", _buttonStyle, Array.Empty())) { Hide(); } GUI.DragWindow(new Rect(0f, 0f, 500f, 30f)); } private void DrawExtensionsTab() { IReadOnlyList panels = DevToolsRegistry.Panels; if (panels.Count == 0) { GUILayout.BeginVertical(_boxStyle, Array.Empty()); GUILayout.Label("Extensions", _sectionHeaderStyle, Array.Empty()); GUILayout.Space(5f); GUILayout.Label("No extension panels registered. Mods can implement IDevToolsPanel and call DevToolsRegistry.Register() to add panels here.", _labelStyle, Array.Empty()); GUILayout.EndVertical(); return; } HashSet hashSet = new HashSet { "com.azraelgodking.trinketfortune" }; foreach (IDevToolsPanel item in panels) { if (!hashSet.Contains(item.ModGuid)) { GUILayout.BeginVertical(_boxStyle, Array.Empty()); GUILayout.Label(item.DisplayName, _sectionHeaderStyle, Array.Empty()); GUILayout.Space(5f); try { item.Draw(_boxStyle, _buttonStyle, _labelStyle); } catch (Exception ex) { GUILayout.Label("Error: " + ex.Message, _labelStyle, Array.Empty()); } GUILayout.EndVertical(); GUILayout.Space(8f); } } } private void DrawToolsTab() { _toolsSubTab = GUILayout.Toolbar(_toolsSubTab, _toolsSubTabNames, _buttonStyle, Array.Empty()); GUILayout.Space(8f); switch (_toolsSubTab) { case 0: DrawItemsTab(); break; case 1: DrawCurrenciesTab(); break; case 2: DrawConsoleTab(); break; case 3: DrawLogViewerTab(); break; case 4: DrawPerformanceTab(); break; case 5: DrawUtilityTab(); break; } } private void DrawConsoleTab() { GUILayout.BeginVertical(_boxStyle, Array.Empty()); GUILayout.Label("Command Console", _sectionHeaderStyle, Array.Empty()); GUILayout.Space(5f); GUILayout.Label("Type commands and press Enter. Supported: spawn, tp, time.set, reload.config", _labelStyle, Array.Empty()); CommandConsole commandConsole = Plugin.GetCommandConsole(); if (commandConsole != null) { commandConsole.Draw(_boxStyle, _buttonStyle, _labelStyle, _textFieldStyle); } else { GUILayout.Label("(Console service initializing...)", _labelStyle, Array.Empty()); } GUILayout.EndVertical(); } private void DrawLogViewerTab() { GUILayout.BeginVertical(_boxStyle, Array.Empty()); GUILayout.Label("Log Viewer", _sectionHeaderStyle, Array.Empty()); GUILayout.Space(5f); LogViewerPanel logViewer = Plugin.GetLogViewer(); if (logViewer != null) { logViewer.Draw(_boxStyle, _buttonStyle, _labelStyle); } else { GUILayout.Label("(Log viewer initializing...)", _labelStyle, Array.Empty()); } GUILayout.EndVertical(); } private void DrawPerformanceTab() { GUILayout.BeginVertical(_boxStyle, Array.Empty()); GUILayout.Label("Performance", _sectionHeaderStyle, Array.Empty()); GUILayout.Space(5f); float num = 1f / Mathf.Max(0.0001f, Time.deltaTime); float num2 = (float)GC.GetTotalMemory(forceFullCollection: false) / 1048576f; GUILayout.Label($"FPS: {num:F1}", _labelStyle, Array.Empty()); GUILayout.Label($"Memory: {num2:F1} MB", _labelStyle, Array.Empty()); GUILayout.Label("(Also shown in overlay when ShowPerformance is enabled)", _labelStyle, Array.Empty()); GUILayout.EndVertical(); } private void DrawItemsTab() { //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginVertical(_boxStyle, Array.Empty()); GUILayout.Label("Item Inspector", _sectionHeaderStyle, Array.Empty()); GUILayout.Space(5f); (int, string)? tuple = Plugin.GetItemInspector()?.GetHeldItem(); if (tuple.HasValue) { GUILayout.Label($"Held: {tuple.Value.Item2} ({tuple.Value.Item1})", _labelStyle, Array.Empty()); } else { GUILayout.Label("Held: None", _labelStyle, Array.Empty()); } GUILayout.Space(10f); GUILayout.Label("Search:", _labelStyle, Array.Empty()); GUILayout.BeginHorizontal(Array.Empty()); _itemSearchText = GUILayout.TextField(_itemSearchText, _textFieldStyle, Array.Empty()); if (GUILayout.Button("Clear", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) })) { _itemSearchText = ""; _lastItemSearchQuery = ""; _searchResults.Clear(); } GUILayout.EndHorizontal(); if (_itemSearchText != _lastItemSearchQuery) { _lastItemSearchQuery = _itemSearchText; _searchResults = ItemSearch.SearchItems(_itemSearchText); } if (_selectedItemId > 0) { GUILayout.Space(2f); GUILayout.Label("Selected: " + ItemSearch.FormatDisplay(_selectedItemName, _selectedItemId), _labelStyle, Array.Empty()); } if (_searchResults.Count > 0) { GUILayout.Space(4f); float num = Mathf.Min(180, 24 + _searchResults.Count * 22); _itemScrollPosition = GUILayout.BeginScrollView(_itemScrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(num) }); foreach (KeyValuePair searchResult in _searchResults) { if (GUILayout.Button(ItemSearch.FormatDisplay(searchResult.Value, searchResult.Key), (searchResult.Key == _selectedItemId) ? _buttonStyle : _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(22f) })) { _selectedItemId = searchResult.Key; _selectedItemName = searchResult.Value; _itemIdInput = searchResult.Key.ToString(); } } GUILayout.EndScrollView(); } else if (_itemSearchText.Length >= 2) { GUILayout.Space(2f); GUILayout.Label("No items found.", _labelStyle, Array.Empty()); } GUILayout.Space(10f); GUILayout.Label("Spawn:", _labelStyle, Array.Empty()); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("ID:", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(22f) }); _itemIdInput = GUILayout.TextField(_itemIdInput, _textFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); GUILayout.Label("Qty:", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(28f) }); _spawnAmount = GUILayout.TextField(_spawnAmount, _textFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(40f) }); if (GUILayout.Button("1", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(22f) })) { _spawnAmount = "1"; } if (GUILayout.Button("10", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(28f) })) { _spawnAmount = "10"; } if (GUILayout.Button("99", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(28f) })) { _spawnAmount = "99"; } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty()); if (GUILayout.Button("Spawn to Inventory", _buttonStyle, Array.Empty()) && int.TryParse(_itemIdInput, out var result) && int.TryParse(_spawnAmount, out var result2) && result2 > 0) { Plugin.GetItemInspector()?.SpawnItem(result, result2); } if (_selectedItemId > 0 && GUILayout.Button("Spawn 1", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) })) { Plugin.GetItemInspector()?.SpawnItem(_selectedItemId); } GUILayout.EndHorizontal(); 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()); GUILayout.Label("Currency Tracker", _sectionHeaderStyle, Array.Empty()); GUILayout.Space(5f); CurrencyTracker currencyTracker = Plugin.GetCurrencyTracker(); if (currencyTracker == null) { GUILayout.Label("Currency tracker not available", _labelStyle, Array.Empty()); GUILayout.EndVertical(); return; } CurrencySummary summary = currencyTracker.GetSummary(); GUILayout.Label($"Gold: {summary.Gold:N0}", _labelStyle, Array.Empty()); GUILayout.Label($"Orbs: {summary.Orbs:N0}", _labelStyle, Array.Empty()); GUILayout.Label($"Tickets: {summary.Tickets:N0}", _labelStyle, Array.Empty()); GUILayout.Space(10f); GUILayout.Label("Inventory Currencies:", _sectionHeaderStyle, Array.Empty()); _currencyScrollPosition = GUILayout.BeginScrollView(_currencyScrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(120f) }); if (summary.InventoryCurrencies.Count == 0) { GUILayout.Label(" (none)", _labelStyle, Array.Empty()); } else { foreach (KeyValuePair inventoryCurrency in summary.InventoryCurrencies) { GUILayout.Label($" {inventoryCurrency.Key}: {inventoryCurrency.Value}", _labelStyle, Array.Empty()); } } GUILayout.EndScrollView(); if (Plugin.HasTheVault) { GUILayout.Space(10f); GUILayout.Label("Vault Currencies:", _sectionHeaderStyle, Array.Empty()); if (summary.VaultCurrencies.Count == 0) { GUILayout.Label(" (vault empty)", _labelStyle, Array.Empty()); } else { foreach (KeyValuePair vaultCurrency in summary.VaultCurrencies) { GUILayout.Label($" {vaultCurrency.Key}: {vaultCurrency.Value}", _labelStyle, Array.Empty()); } } } else { GUILayout.Space(5f); GUILayout.Label("(The Vault not installed)", _labelStyle, Array.Empty()); } 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()); GUILayout.Label("Museum Bundle Inspector", _sectionHeaderStyle, Array.Empty()); GUILayout.Space(5f); if (!Plugin.HasSMUT) { GUILayout.Label("S.M.U.T. not installed", _labelStyle, Array.Empty()); GUILayout.EndVertical(); return; } BundleInspector bundleInspector = Plugin.GetBundleInspector(); if (bundleInspector == null) { GUILayout.Label("Bundle inspector not available", _labelStyle, Array.Empty()); GUILayout.EndVertical(); return; } DonationStats donationStats = bundleInspector.GetDonationStats(); if (donationStats.IsLoaded) { GUILayout.Label("Character: " + donationStats.CharacterName, _labelStyle, Array.Empty()); GUILayout.Label($"Progress: {donationStats.TotalDonated}/{donationStats.TotalItems} ({donationStats.CompletionPercent:F1}%)", _labelStyle, Array.Empty()); } else { GUILayout.Label("Donation data not loaded", _labelStyle, Array.Empty()); } GUILayout.Space(10f); List allSections = bundleInspector.GetAllSections(); if (allSections.Count == 0) { GUILayout.Label("No museum data available", _labelStyle, Array.Empty()); 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()); _selectedSectionIndex = GUILayout.SelectionGrid(_selectedSectionIndex, array, 3, _buttonStyle, Array.Empty()); 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()); _selectedBundleIndex = GUILayout.SelectionGrid(_selectedBundleIndex, array2, 2, _buttonStyle, Array.Empty()); MuseumBundleInfo museumBundleInfo = museumSectionInfo.Bundles[_selectedBundleIndex]; GUILayout.Space(5f); GUILayout.Label("Items in " + museumBundleInfo.Name + ":", _sectionHeaderStyle, Array.Empty()); _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}" : ""); bool flag = item.GameItemId > 0; GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label($"{arg} {item.Name} (ID: {item.GameItemId})", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(320f) }); bool enabled = GUI.enabled; GUI.enabled = flag; if (GUILayout.Button(flag ? ("Spawn" + text) : "—", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }) && flag) { Plugin.GetItemInspector()?.SpawnItem(item.GameItemId, item.Quantity); } GUI.enabled = enabled; if (!flag) { GUILayout.Label("(ID in Unity assets)", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(100f) }); } 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()); GUILayout.Label("Race Modifier Tracker", _sectionHeaderStyle, Array.Empty()); GUILayout.Space(5f); RaceModifierTracker raceModifierTracker = Plugin.GetRaceModifierTracker(); if (raceModifierTracker == null) { GUILayout.Label("Race tracker not available", _labelStyle, Array.Empty()); GUILayout.EndVertical(); return; } string currentRace = raceModifierTracker.GetCurrentRace(); GUILayout.Label("Current Race: " + currentRace, _labelStyle, Array.Empty()); GUILayout.Space(10f); if (Plugin.HasHavensBirthright) { List activeRaceBonuses = raceModifierTracker.GetActiveRaceBonuses(); GUILayout.Label("Active Bonuses:", _sectionHeaderStyle, Array.Empty()); if (activeRaceBonuses.Count == 0) { GUILayout.Label(" (no bonuses active)", _labelStyle, Array.Empty()); } else { foreach (RaceBonusInfo item in activeRaceBonuses) { GUILayout.Label(" " + item.Type + ": " + item.GetFormattedValue(), _labelStyle, Array.Empty()); GUILayout.Label(" " + item.Description, _labelStyle, Array.Empty()); } } } else { GUILayout.Label("Haven's Birthright not installed", _labelStyle, Array.Empty()); } GUILayout.Space(10f); GUILayout.Label("Browse Race Bonuses:", _sectionHeaderStyle, Array.Empty()); List 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()); GUILayout.Space(5f); List 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()); } else { foreach (RaceBonusInfo item2 in bonusesForRace) { GUILayout.Label(" " + item2.Type + ": " + item2.GetFormattedValue(), _labelStyle, Array.Empty()); GUILayout.Label(" " + item2.Description, _labelStyle, Array.Empty()); } } GUILayout.EndScrollView(); } GUILayout.EndVertical(); } private void DrawUtilityTab() { GUILayout.BeginVertical(_boxStyle, Array.Empty()); GUILayout.Label("Utility", _sectionHeaderStyle, Array.Empty()); GUILayout.Space(5f); DrawVersionCheckerSection(); GUILayout.Space(10f); GUILayout.Label("Config:", _sectionHeaderStyle, Array.Empty()); if (GUILayout.Button("Reload HavenDevTools Config", _buttonStyle, Array.Empty())) { ConfigReloader.ReloadHavenDevToolsConfig(); } GUILayout.Space(10f); GUILayout.Label("Logging:", _sectionHeaderStyle, Array.Empty()); if (GUILayout.Button("Log All Currency IDs", _buttonStyle, Array.Empty())) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"=== Currency Item IDs ==="); } foreach (KeyValuePair 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())) { LogPlayerStats(); } GUILayout.Space(10f); GUILayout.Label("Authorization Hash Generator:", _sectionHeaderStyle, Array.Empty()); GUILayout.Label("Use this to generate hashes for new authorized Steam IDs", _labelStyle, Array.Empty()); if (GUILayout.Button("Log Current Steam ID Hash", _buttonStyle, Array.Empty())) { try { string text = typeof(Plugin).GetMethod("TryGetSteamId", BindingFlags.Static | BindingFlags.NonPublic)?.Invoke(null, null) as string; if (!string.IsNullOrEmpty(text)) { string text2 = Plugin.GenerateHash(text); ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)("Steam ID: " + text)); } ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogInfo((object)("Steam ID Hash: " + text2)); } } else { ManualLogSource log5 = Plugin.Log; if (log5 != null) { log5.LogWarning((object)"Could not retrieve Steam ID"); } } } catch (Exception ex) { ManualLogSource log6 = Plugin.Log; if (log6 != null) { log6.LogError((object)("Error generating hash: " + ex.Message)); } } } 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()); GUILayout.Space(3f); GUILayout.BeginHorizontal(Array.Empty()); GUI.enabled = !_isCheckingVersions; if (GUILayout.Button(_isCheckingVersions ? "Checking..." : "Check All Mod Versions", _buttonStyle, Array.Empty())) { 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()); GUILayout.Label(tuple.Item2 + " v" + tuple.Item3, _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) }); if (_versionResults.TryGetValue(tuple.Item1, out VersionChecker.VersionCheckResult 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()); } 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()); } 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()); } } else { GUILayout.Label("Not checked", _labelStyle, Array.Empty()); } 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 (Exception ex) { ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogDebug((object)("[DebugWindow] Player stats property iteration: " + ex.Message)); } } } } catch (Exception ex2) { ManualLogSource log5 = Plugin.Log; if (log5 != null) { log5.LogError((object)("Error logging player stats: " + ex2.Message)); } } } } public class LogViewerPanel { private class LogCaptureListener : ILogListener, IDisposable { public void LogEvent(object sender, LogEventArgs eventArgs) { OnLog(eventArgs); } public void Dispose() { } } private class LogEntry { public int Level; public string Message; public string Source; public DateTime Timestamp; } private static readonly List _entries = new List(); private static readonly object _lock = new object(); private Vector2 _scrollPosition; private int _levelFilterIndex = 1; private static readonly string[] _levelNames = new string[4] { "Debug", "Info", "Warning", "Error" }; private static bool _listenerAttached; private static readonly LogCaptureListener _captureListener = new LogCaptureListener(); public LogViewerPanel() { if (!_listenerAttached) { Logger.Listeners.Add((ILogListener)(object)_captureListener); _listenerAttached = true; } } private static void OnLog(LogEventArgs e) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Invalid comparison between Unknown and I4 //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Invalid comparison between Unknown and I4 //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 LogLevel level = e.Level; int num; if ((int)level <= 4) { if ((int)level != 2) { if ((int)level != 4) { goto IL_002f; } num = 2; } else { num = 3; } } else if ((int)level != 16) { if ((int)level != 32) { goto IL_002f; } num = 0; } else { num = 1; } goto IL_0031; IL_0031: int level2 = num; lock (_lock) { _entries.Add(new LogEntry { Level = level2, Message = (e.Data?.ToString() ?? ""), Source = e.Source.SourceName, Timestamp = DateTime.Now }); int num2 = ModConfig.MaxLogEntries?.Value ?? 500; while (_entries.Count > num2) { _entries.RemoveAt(0); } return; } IL_002f: num = 1; goto IL_0031; } public void Draw(GUIStyle boxStyle, GUIStyle buttonStyle, GUIStyle labelStyle) { //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0166: 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_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Expected O, but got Unknown //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("Level:", labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(40f) }); _levelFilterIndex = GUILayout.Toolbar(_levelFilterIndex, _levelNames, buttonStyle, Array.Empty()); if (GUILayout.Button("Export", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) })) { ExportToFile(); } GUILayout.EndHorizontal(); GUILayout.Space(5f); List list; lock (_lock) { list = new List(_entries); } _scrollPosition = GUILayout.BeginScrollView(_scrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(200f) }); int levelFilterIndex = _levelFilterIndex; foreach (LogEntry item in list) { if (item.Level >= levelFilterIndex) { Color textColor = (Color)(item.Level switch { 0 => new Color(0.6f, 0.6f, 0.6f), 1 => new Color(0.9f, 0.9f, 0.9f), 2 => new Color(1f, 0.85f, 0.3f), 3 => new Color(1f, 0.4f, 0.4f), _ => Color.white, }); GUIStyle val = new GUIStyle(labelStyle); val.normal.textColor = textColor; GUIStyle val2 = val; GUILayout.Label($"[{item.Timestamp:HH:mm:ss}] [{_levelNames[item.Level]}] [{item.Source}] {item.Message}", val2, Array.Empty()); } } GUILayout.EndScrollView(); } private static void ExportToFile() { try { string text = Path.Combine(Paths.BepInExRootPath, "LogExport.txt"); List list; lock (_lock) { list = new List(_entries); } List list2 = new List(); foreach (LogEntry item in list) { list2.Add($"[{item.Timestamp:yyyy-MM-dd HH:mm:ss}] [{_levelNames[item.Level]}] [{item.Source}] {item.Message}"); } File.WriteAllLines(text, list2); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[LogViewer] Exported {list2.Count} lines to {text}"); } } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogError((object)("[LogViewer] Export failed: " + ex.Message)); } } } } } namespace HavenDevTools.Services { public class BundleInspector { public BundleInspector() { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[BundleInspector] Initialized"); } } public List GetAllSections() { List list = new List(); 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() }; 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() }; string text = item3.GetType().GetProperty("Id")?.GetValue(item3)?.ToString() ?? ""; item2.GetType().GetProperty("Id")?.GetValue(item2)?.ToString(); List<(int, string)> list4 = TryGetResolvedAquariumItems(sMUTAssembly, text); if (list4 != null && list4.Count > 0) { foreach (var (num, text2) in list4) { museumBundleInfo.Items.Add(new MuseumItemInfo { Id = $"{text}_fish_{num}", Name = (text2 ?? $"Item {num}"), GameItemId = num, Quantity = 1 }); } } else { PropertyInfo property2 = item3.GetType().GetProperty("Items"); if (property2 != null && property2.GetValue(item3) is IList list5) { foreach (object item4 in list5) { 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; } private static List<(int GameItemId, string Name)> TryGetResolvedAquariumItems(Assembly smutAssembly, string bundleId) { if (smutAssembly == null || string.IsNullOrEmpty(bundleId)) { return null; } try { if ((smutAssembly.GetType("SunHavenMuseumUtilityTracker.Data.MuseumContent")?.GetMethod("GetResolvedAquariumItems", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(string) }, null))?.Invoke(null, new object[1] { bundleId }) is IList list && list.Count > 0) { List<(int, string)> list2 = new List<(int, string)>(); foreach (object item in list) { Type type = item.GetType(); FieldInfo field = type.GetField("Item1", BindingFlags.Instance | BindingFlags.Public); FieldInfo field2 = type.GetField("Item2", BindingFlags.Instance | BindingFlags.Public); int num = ((field != null) ? Convert.ToInt32(field.GetValue(item)) : 0); string text = ((field2 != null) ? field2.GetValue(item)?.ToString() : null); list2.Add((num, text ?? $"Item {num}")); } return list2; } } catch { } return null; } } public class MuseumSectionInfo { public string Name { get; set; } public List Bundles { get; set; } } public class MuseumBundleInfo { public string Name { get; set; } public List 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 CommandConsole { private string _input = ""; private readonly List _output = new List(); private readonly List _history = new List(); private int _historyIndex = -1; private Vector2 _outputScroll; private const int MaxOutputLines = 100; public void Draw(GUIStyle boxStyle, GUIStyle buttonStyle, GUIStyle labelStyle, GUIStyle textFieldStyle) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) GUILayout.Label("Output:", labelStyle, Array.Empty()); float num = Mathf.Min(120, 20 + _output.Count * 18); _outputScroll = GUILayout.BeginScrollView(_outputScroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(num) }); foreach (string item in _output) { GUILayout.Label(item, labelStyle, Array.Empty()); } GUILayout.EndScrollView(); GUILayout.Space(5f); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label(">", labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(12f) }); GUI.SetNextControlName("ConsoleInput"); _input = GUILayout.TextField(_input, textFieldStyle, Array.Empty()); if (GUILayout.Button("Execute", buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) })) { Execute(_input); _input = ""; } GUILayout.EndHorizontal(); GUILayout.Label("Commands: spawn <id> [qty] | tp <scene> | time.set <hour> | reload.config", labelStyle, Array.Empty()); } public void Execute(string command) { if (string.IsNullOrWhiteSpace(command)) { return; } command = command.Trim(); _history.Add(command); if (_history.Count > 50) { _history.RemoveAt(0); } _historyIndex = _history.Count; string[] array = command.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length == 0) { return; } string text = array[0].ToLowerInvariant(); try { switch (text) { case "spawn": { if (array.Length >= 2 && int.TryParse(array[1], out var result)) { int result2; int num = ((array.Length < 3 || !int.TryParse(array[2], out result2)) ? 1 : result2); ItemInspector itemInspector = Plugin.GetItemInspector(); if (itemInspector != null && itemInspector.SpawnItem(result, num)) { AddOutput($"Spawned item {result} x{num}"); } else { AddOutput($"Failed to spawn {result}"); } } else { AddOutput("Usage: spawn [qty]"); } break; } case "tp": case "teleport": if (array.Length >= 2) { string text2 = array[1]; SceneManager.LoadScene(text2); AddOutput("Loading scene: " + text2); } else { AddOutput("Usage: tp "); } break; case "time.set": { if (array.Length >= 2 && float.TryParse(array[1], out var result3)) { if (TrySetTime(result3)) { AddOutput($"Set time to {result3}"); } else { AddOutput("Could not set time"); } } else { AddOutput("Usage: time.set "); } break; } case "reload.config": ConfigReloader.ReloadHavenDevToolsConfig(); AddOutput("Config reloaded"); break; case "player.stat": if (array.Length >= 3) { if (TrySetPlayerStat(array[1], array[2])) { AddOutput("Set " + array[1] + " = " + array[2]); } else { AddOutput("Failed to set " + array[1]); } } else { AddOutput("Usage: player.stat "); } break; default: AddOutput("Unknown command: " + text + ". Try: spawn, tp, time.set, reload.config"); break; } } catch (Exception ex) { AddOutput("Error: " + ex.Message); } } private void AddOutput(string line) { _output.Add(line); if (_output.Count > 100) { _output.RemoveAt(0); } } private static bool TrySetTime(float hour) { try { Type type = ReflectionHelper.FindType("DayCycle", "Wish"); if (type == null) { return false; } Object val = Object.FindObjectOfType(type); if (val == (Object)null) { return false; } Type type2 = ((object)val).GetType(); PropertyInfo propertyInfo = type2.GetProperty("CurrentTime") ?? type2.GetProperty("currentTime"); if (propertyInfo != null && propertyInfo.CanWrite) { propertyInfo.SetValue(val, hour); return true; } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[CommandConsole] TrySetTime: " + ex.Message)); } } return false; } private static bool TrySetPlayerStat(string statName, string valueStr) { try { if ((Object)(object)Player.Instance == (Object)null) { return false; } PropertyInfo property = ((object)Player.Instance).GetType().GetProperty(statName, BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public); if (property == null || !property.CanWrite) { return false; } object value = valueStr; float result2; if (property.PropertyType == typeof(int) && int.TryParse(valueStr, out var result)) { value = result; } else if (property.PropertyType == typeof(float) && float.TryParse(valueStr, out result2)) { value = result2; } else if (property.PropertyType == typeof(bool)) { value = valueStr.Equals("true", StringComparison.OrdinalIgnoreCase) || valueStr == "1"; } property.SetValue(Player.Instance, Convert.ChangeType(value, property.PropertyType)); return true; } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[CommandConsole] TrySetPlayerStat: " + ex.Message)); } } return false; } } public static class ConfigReloader { public static void ReloadHavenDevToolsConfig() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) try { if (Plugin.ConfigFile != null) { Plugin.ConfigFile.Reload(); ModConfig.Initialize(Plugin.ConfigFile); Plugin.StaticToggleKey = ModConfig.ToggleKey.Value; Plugin.StaticOverlayToggleKey = ModConfig.OverlayToggleKey.Value; ModConfig.SyncTheVaultFullVaultInspectorToPlugin(); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[ConfigReloader] HavenDevTools config reloaded"); } } } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogError((object)("[ConfigReloader] Error: " + ex.Message)); } } } } public class CurrencyTracker { public static readonly Dictionary CurrencyItemIds = new Dictionary { { "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 GetAllVaultCurrencies() { Dictionary result = new Dictionary(); 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 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(), VaultCurrencies = new Dictionary() }; foreach (KeyValuePair 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 InventoryCurrencies { get; set; } public Dictionary VaultCurrencies { get; set; } } public class ItemInspector { private static MethodInfo _cachedAddItemMethod; private static int _addItemArgCount; public ItemInspector() { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[ItemInspector] Initialized"); } } public bool SpawnItem(int itemId, int amount = 1) { try { if ((Object)(object)Player.Instance == (Object)null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"[ItemInspector] Player.Instance is null"); } return false; } Inventory inventory = Player.Instance.Inventory; if ((Object)(object)inventory == (Object)null) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)"[ItemInspector] Player.Inventory is null"); } return false; } MethodInfo addItemMethod = GetAddItemMethod(inventory); if (addItemMethod == null) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogWarning((object)"[ItemInspector] AddItem method not found"); } return false; } if (_addItemArgCount == 3) { addItemMethod.Invoke(inventory, new object[3] { itemId, amount, true }); } else { addItemMethod.Invoke(inventory, new object[2] { itemId, amount }); } return true; } catch (Exception ex) { ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogError((object)("[ItemInspector] Spawn error: " + ex.Message)); } return false; } } private static MethodInfo GetAddItemMethod(object inventory) { if (_cachedAddItemMethod != null) { return _cachedAddItemMethod; } try { Type type = inventory.GetType(); _cachedAddItemMethod = AccessTools.Method(type, "AddItem", new Type[3] { typeof(int), typeof(int), typeof(bool) }, (Type[])null); if (_cachedAddItemMethod != null) { _addItemArgCount = 3; return _cachedAddItemMethod; } _cachedAddItemMethod = AccessTools.Method(type, "AddItem", new Type[2] { typeof(int), typeof(int) }, (Type[])null); if (_cachedAddItemMethod != null) { _addItemArgCount = 2; return _cachedAddItemMethod; } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)("[ItemInspector] GetAddItemMethod: " + ex.Message)); } } return null; } public (int id, string name)? GetHeldItem() { try { Player instance = Player.Instance; if ((Object)(object)((instance != null) ? instance.Inventory : null) == (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(type, "GetItem", new Type[1] { typeof(int) }, (Type[])null); if (methodInfo == null) { return null; } object obj = methodInfo.Invoke(inventory, new object[1] { num }); if (obj == null) { return null; } PropertyInfo propertyInfo2 = obj.GetType().GetProperty("id") ?? obj.GetType().GetProperty("ID"); if (propertyInfo2 == null) { return null; } int num2 = (int)propertyInfo2.GetValue(obj); string item = ItemSearch.GetItemName(num2) ?? $"Item {num2}"; return (num2, item); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)("[ItemInspector] GetHeldItem: " + ex.Message)); } return null; } } } 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 GetActiveRaceBonuses() { List list = new List(); 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 GetBonusesForRace(string raceName) { List list = new List(); 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 (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)("[RaceModifierTracker] Enum.Parse for race '" + raceName + "': " + ex.Message)); } 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 ex2) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("[RaceModifierTracker] Error getting bonuses for race: " + ex2.Message)); } } return list; } public List GetAllRaces() { List list = new List(); if (!Plugin.HasHavensBirthright) { return new List { "Human", "Elf", "Angel", "Demon", "Elemental", "FireElemental", "WaterElemental", "Amari", "AmariCat", "AmariDog", "AmariBird", "AmariAquatic", "AmariReptile", "Naga" }; } try { Assembly birthrightAssembly = GetBirthrightAssembly(); if (birthrightAssembly == null) { return list; } Type type = birthrightAssembly.GetType("HavensBirthright.Race"); if (type != null) { foreach (object value in Enum.GetValues(type)) { list.Add(value.ToString()); } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[RaceModifierTracker] Error getting races: " + ex.Message)); } } return list; } private Assembly GetBirthrightAssembly() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (assembly.GetName().Name == "HavensBirthright") { return assembly; } } return null; } } public class RaceBonusInfo { public string Type { get; set; } public float Value { get; set; } public bool IsPercentage { get; set; } public string Description { get; set; } public string GetFormattedValue() { if (IsPercentage) { if (!(Value >= 0f)) { return $"{Value}%"; } return $"+{Value}%"; } if (!(Value >= 0f)) { return $"{Value}"; } return $"+{Value}"; } } } namespace HavenDevTools.Integrations { public static class AzraelsModsPanel { private static int _selectedSubTab; private static Vector2 _scrollPosition; private static Vector2 _bundleScrollPosition; private static Vector2 _raceScrollPosition; private static int _selectedSectionIndex; private static int _selectedBundleIndex; private static int _selectedRaceIndex; private static Type _cachedSenpaisChestPlugin; private static MethodInfo _cachedSenpaisChestGetManager; private static Type _cachedBirthdayReminderPlugin; private static MethodInfo _cachedBirthdayReminderGetManager; private static Type _cachedSunhavenTodoPlugin; private static MethodInfo _cachedSunhavenTodoGetManager; private static Type _cachedHavensAlmanacPlugin; private static MethodInfo _cachedHavensAlmanacGetAggregator; private static readonly string[] _subTabNames = new string[7] { "Senpai's Chest", "The Vault", "S.M.U.T.", "Birthright", "Birthday", "Todo", "Almanac" }; private static IDevToolsPanel _cachedTrinketFortunePanel; public static void Draw(GUIStyle boxStyle, GUIStyle buttonStyle, GUIStyle labelStyle, GUIStyle sectionHeaderStyle) { //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) List list = new List(); List list2 = new List(); int num = 0; if (Plugin.HasSenpaisChest) { list.Add("Senpai's Chest"); list2.Add(num); } num++; if (Plugin.HasTheVault) { list.Add("The Vault"); list2.Add(num); } num++; if (Plugin.HasSMUT) { list.Add("S.M.U.T."); list2.Add(num); } num++; if (Plugin.HasHavensBirthright) { list.Add("Birthright"); list2.Add(num); } num++; if (Plugin.HasBirthdayReminder) { list.Add("Birthday"); list2.Add(num); } num++; if (Plugin.HasSunhavenTodo) { list.Add("Todo"); list2.Add(num); } num++; if (Plugin.HasHavensAlmanac) { list.Add("Almanac"); list2.Add(num); } num++; if (Plugin.HasTrinketFortune) { list.Add("Trinket Fortune"); list2.Add(num); } if (list.Count == 0) { GUILayout.Label("No Azrael's mods detected. Install SenpaisChest, TheVault, S.M.U.T., Birthright, Birthday Reminder, Todo, Almanac, or Trinket Fortune.", labelStyle, Array.Empty()); return; } int num2 = ((_selectedSubTab < list2.Count) ? list2[_selectedSubTab] : 0); _selectedSubTab = Mathf.Clamp(_selectedSubTab, 0, list.Count - 1); num2 = list2[_selectedSubTab]; _selectedSubTab = GUILayout.Toolbar(_selectedSubTab, list.ToArray(), buttonStyle, Array.Empty()); GUILayout.Space(8f); _scrollPosition = GUILayout.BeginScrollView(_scrollPosition, Array.Empty()); switch (num2) { case 0: DrawSenpaisChest(boxStyle, buttonStyle, labelStyle, sectionHeaderStyle); break; case 1: DrawTheVault(boxStyle, buttonStyle, labelStyle, sectionHeaderStyle); break; case 2: DrawSMUT(boxStyle, buttonStyle, labelStyle, sectionHeaderStyle); break; case 3: DrawBirthright(boxStyle, buttonStyle, labelStyle, sectionHeaderStyle); break; case 4: DrawBirthdayReminder(boxStyle, buttonStyle, labelStyle, sectionHeaderStyle); break; case 5: DrawTodo(boxStyle, buttonStyle, labelStyle, sectionHeaderStyle); break; case 6: DrawAlmanac(boxStyle, buttonStyle, labelStyle, sectionHeaderStyle); break; case 7: DrawTrinketFortune(boxStyle, buttonStyle, labelStyle, sectionHeaderStyle); break; } GUILayout.EndScrollView(); } private static void DrawSenpaisChest(GUIStyle box, GUIStyle button, GUIStyle label, GUIStyle sectionHeader) { GUILayout.BeginVertical(box, Array.Empty()); GUILayout.Label("Senpai's Chest", sectionHeader, Array.Empty()); try { if (_cachedSenpaisChestPlugin == null) { _cachedSenpaisChestPlugin = ReflectionHelper.FindType("Plugin", "SenpaisChest") ?? ReflectionHelper.FindType("Plugin", "SenpaiChest"); } if (_cachedSenpaisChestPlugin == null) { GUILayout.Label("SenpaisChest.Plugin not found", label, Array.Empty()); GUILayout.EndVertical(); return; } if (_cachedSenpaisChestGetManager == null) { _cachedSenpaisChestGetManager = _cachedSenpaisChestPlugin.GetMethod("GetManager", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } if (_cachedSenpaisChestGetManager == null) { GUILayout.Label("GetManager not found", label, Array.Empty()); GUILayout.EndVertical(); return; } object obj = _cachedSenpaisChestGetManager.Invoke(null, null); if (obj == null) { GUILayout.Label("Manager not loaded", label, Array.Empty()); GUILayout.EndVertical(); return; } MethodInfo method = obj.GetType().GetMethod("GetSaveData"); if (method != null) { object obj2 = method.Invoke(obj, null); if (obj2 != null) { PropertyInfo property = obj2.GetType().GetProperty("Chests"); if (property != null && property.GetValue(obj2) is IList list) { GUILayout.Label($"Smart Chests: {list.Count}", label, Array.Empty()); foreach (object item in list) { PropertyInfo? obj3 = item?.GetType().GetProperty("ChestName"); PropertyInfo propertyInfo = item?.GetType().GetProperty("ChestId"); PropertyInfo propertyInfo2 = item?.GetType().GetProperty("IsEnabled"); string text = obj3?.GetValue(item)?.ToString() ?? "?"; string text2 = propertyInfo?.GetValue(item)?.ToString() ?? "?"; bool flag = (bool)(propertyInfo2?.GetValue(item) ?? ((object)false)); GUILayout.Label(" " + (flag ? "[ON]" : "[OFF]") + " " + text + " (" + text2 + ")", label, Array.Empty()); } } } } MethodInfo method2 = obj.GetType().GetMethod("GetGroups"); if (method2 != null && method2.Invoke(obj, null) is IList list2 && list2.Count > 0) { GUILayout.Space(5f); GUILayout.Label($"Groups: {list2.Count}", label, Array.Empty()); foreach (object item2 in list2) { string text3 = (item2?.GetType().GetProperty("Name"))?.GetValue(item2)?.ToString() ?? "?"; GUILayout.Label(" - " + text3, label, Array.Empty()); } } GUILayout.Space(8f); if (GUILayout.Button("Trigger Manual Scan", button, Array.Empty())) { obj.GetType().GetMethod("ExecuteScan", new Type[2] { typeof(int), typeof(bool) })?.Invoke(obj, new object[2] { 999, false }); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[AzraelsMods] Triggered SenpaisChest manual scan"); } } } catch (Exception ex) { GUILayout.Label("Error: " + ex.Message, label, Array.Empty()); } GUILayout.EndVertical(); } private static void DrawTheVault(GUIStyle box, GUIStyle button, GUIStyle label, GUIStyle sectionHeader) { GUILayout.BeginVertical(box, Array.Empty()); GUILayout.Label("The Vault", sectionHeader, Array.Empty()); CurrencyTracker currencyTracker = Plugin.GetCurrencyTracker(); if (currencyTracker == null) { GUILayout.Label("Currency tracker not available", label, Array.Empty()); GUILayout.EndVertical(); return; } CurrencySummary summary = currencyTracker.GetSummary(); GUILayout.Label("Vault Currencies:", label, Array.Empty()); if (summary.VaultCurrencies.Count == 0) { GUILayout.Label(" (vault empty or not loaded)", label, Array.Empty()); } else { foreach (KeyValuePair vaultCurrency in summary.VaultCurrencies) { GUILayout.Label($" {vaultCurrency.Key}: {vaultCurrency.Value}", label, Array.Empty()); } } GUILayout.Space(8f); if (ModConfig.TheVaultFullVaultInspector != null) { bool value = ModConfig.TheVaultFullVaultInspector.Value; bool flag = GUILayout.Toggle(value, " Full vault inspector (zeros + Debug tab + full HUD)", label, Array.Empty()); if (flag != value) { ModConfig.TheVaultFullVaultInspector.Value = flag; } GUILayout.Label("Moved from The Vault settings; persists in com.azraelgodking.havendevtools.cfg ([The Vault] section).", label, Array.Empty()); } GUILayout.EndVertical(); } private static void DrawSMUT(GUIStyle box, GUIStyle button, GUIStyle label, GUIStyle sectionHeader) { //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginVertical(box, Array.Empty()); GUILayout.Label("S.M.U.T. - Museum Bundle Inspector", sectionHeader, Array.Empty()); BundleInspector bundleInspector = Plugin.GetBundleInspector(); if (bundleInspector == null) { GUILayout.Label("Bundle inspector not available", label, Array.Empty()); GUILayout.EndVertical(); return; } DonationStats donationStats = bundleInspector.GetDonationStats(); if (donationStats.IsLoaded) { GUILayout.Label("Character: " + donationStats.CharacterName, label, Array.Empty()); GUILayout.Label($"Progress: {donationStats.TotalDonated}/{donationStats.TotalItems} ({donationStats.CompletionPercent:F1}%)", label, Array.Empty()); } List allSections = bundleInspector.GetAllSections(); if (allSections.Count == 0) { GUILayout.EndVertical(); return; } string[] array = allSections.Select((MuseumSectionInfo s) => s.Name).ToArray(); if (_selectedSectionIndex >= allSections.Count) { _selectedSectionIndex = 0; } GUILayout.Label("Section:", label, Array.Empty()); _selectedSectionIndex = GUILayout.SelectionGrid(_selectedSectionIndex, array, 3, button, Array.Empty()); MuseumSectionInfo museumSectionInfo = allSections[_selectedSectionIndex]; if (museumSectionInfo.Bundles.Count > 0) { string[] array2 = museumSectionInfo.Bundles.Select((MuseumBundleInfo b) => b.Name).ToArray(); if (_selectedBundleIndex >= museumSectionInfo.Bundles.Count) { _selectedBundleIndex = 0; } GUILayout.Label("Bundle:", label, Array.Empty()); _selectedBundleIndex = GUILayout.SelectionGrid(_selectedBundleIndex, array2, 2, button, Array.Empty()); MuseumBundleInfo museumBundleInfo = museumSectionInfo.Bundles[_selectedBundleIndex]; GUILayout.Label("Items in " + museumBundleInfo.Name + ":", sectionHeader, Array.Empty()); _bundleScrollPosition = GUILayout.BeginScrollView(_bundleScrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(120f) }); foreach (MuseumItemInfo item in museumBundleInfo.Items) { string arg = (bundleInspector.HasDonated(item.Id) ? "[X]" : "[ ]"); string text = ((item.Quantity > 1) ? $" x{item.Quantity}" : ""); bool flag = item.GameItemId > 0; GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label($"{arg} {item.Name} (ID: {item.GameItemId})", label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(280f) }); GUI.enabled = flag; if (GUILayout.Button(flag ? ("Spawn" + text) : "—", button, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }) && flag) { Plugin.GetItemInspector()?.SpawnItem(item.GameItemId, item.Quantity); } GUI.enabled = true; if (!flag) { GUILayout.Label("(Unity)", label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) }); } GUILayout.EndHorizontal(); } GUILayout.EndScrollView(); } GUILayout.EndVertical(); } private static void DrawBirthright(GUIStyle box, GUIStyle button, GUIStyle label, GUIStyle sectionHeader) { //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginVertical(box, Array.Empty()); GUILayout.Label("Haven's Birthright - Race Modifier Tracker", sectionHeader, Array.Empty()); RaceModifierTracker raceModifierTracker = Plugin.GetRaceModifierTracker(); if (raceModifierTracker == null) { GUILayout.Label("Race tracker not available", label, Array.Empty()); GUILayout.EndVertical(); return; } GUILayout.Label("Current Race: " + raceModifierTracker.GetCurrentRace(), label, Array.Empty()); List activeRaceBonuses = raceModifierTracker.GetActiveRaceBonuses(); if (activeRaceBonuses.Count > 0) { GUILayout.Label("Active Bonuses:", label, Array.Empty()); foreach (RaceBonusInfo item in activeRaceBonuses) { GUILayout.Label(" " + item.Type + ": " + item.GetFormattedValue(), label, Array.Empty()); } } List allRaces = raceModifierTracker.GetAllRaces(); if (allRaces.Count > 0) { GUILayout.Space(5f); string[] array = allRaces.ToArray(); if (_selectedRaceIndex >= allRaces.Count) { _selectedRaceIndex = 0; } _selectedRaceIndex = GUILayout.SelectionGrid(_selectedRaceIndex, array, 4, button, Array.Empty()); List bonusesForRace = raceModifierTracker.GetBonusesForRace(allRaces[_selectedRaceIndex]); _raceScrollPosition = GUILayout.BeginScrollView(_raceScrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(100f) }); foreach (RaceBonusInfo item2 in bonusesForRace) { GUILayout.Label(" " + item2.Type + ": " + item2.GetFormattedValue(), label, Array.Empty()); } GUILayout.EndScrollView(); } GUILayout.EndVertical(); } private static void DrawBirthdayReminder(GUIStyle box, GUIStyle button, GUIStyle label, GUIStyle sectionHeader) { GUILayout.BeginVertical(box, Array.Empty()); GUILayout.Label("Birthday Reminder", sectionHeader, Array.Empty()); try { if (_cachedBirthdayReminderPlugin == null) { _cachedBirthdayReminderPlugin = ReflectionHelper.FindType("Plugin", "BirthdayReminder"); } if (_cachedBirthdayReminderPlugin == null) { GUILayout.Label("BirthdayReminder.Plugin not found", label, Array.Empty()); GUILayout.EndVertical(); return; } if (_cachedBirthdayReminderGetManager == null) { _cachedBirthdayReminderGetManager = _cachedBirthdayReminderPlugin.GetMethod("GetManager", BindingFlags.Static | BindingFlags.Public); } if (_cachedBirthdayReminderGetManager == null) { GUILayout.Label("GetManager not found", label, Array.Empty()); GUILayout.EndVertical(); return; } object obj = _cachedBirthdayReminderGetManager.Invoke(null, null); if (obj == null) { GUILayout.Label("Manager not loaded", label, Array.Empty()); GUILayout.EndVertical(); return; } object arg = obj.GetType().GetProperty("HasBirthdays")?.GetValue(obj); object arg2 = obj.GetType().GetProperty("HasUngiftedBirthdays")?.GetValue(obj); IList list = obj.GetType().GetProperty("TodaysBirthdays")?.GetValue(obj) as IList; GUILayout.Label($"Has birthdays today: {arg}", label, Array.Empty()); GUILayout.Label($"Has ungifted: {arg2}", label, Array.Empty()); if (list != null) { GUILayout.Label($"Today's birthdays: {list.Count}", label, Array.Empty()); foreach (object item in list) { PropertyInfo? obj2 = item?.GetType().GetProperty("NpcName") ?? item?.GetType().GetProperty("Name"); PropertyInfo propertyInfo = item?.GetType().GetProperty("HasBeenGifted"); string text = obj2?.GetValue(item)?.ToString() ?? "?"; bool flag = (bool)(propertyInfo?.GetValue(item) ?? ((object)false)); GUILayout.Label(" - " + text + " " + (flag ? "[Gifted]" : ""), label, Array.Empty()); } } GUILayout.Space(8f); GUILayout.BeginHorizontal(Array.Empty()); if (GUILayout.Button("Check Birthdays", button, Array.Empty())) { ReflectionHelper.InvokeStaticMethod(_cachedBirthdayReminderPlugin, "CheckBirthdays"); } if (GUILayout.Button("Manual Refresh", button, Array.Empty())) { obj.GetType().GetMethod("ManualRefresh")?.Invoke(obj, null); } if (GUILayout.Button("Send All Test Notifications", button, Array.Empty())) { ReflectionHelper.InvokeStaticMethod(_cachedBirthdayReminderPlugin, "SendAllBirthdayNotifications"); } GUILayout.EndHorizontal(); } catch (Exception ex) { GUILayout.Label("Error: " + ex.Message, label, Array.Empty()); } GUILayout.EndVertical(); } private static void DrawTodo(GUIStyle box, GUIStyle button, GUIStyle label, GUIStyle sectionHeader) { GUILayout.BeginVertical(box, Array.Empty()); GUILayout.Label("Sunhaven Todo", sectionHeader, Array.Empty()); try { if (_cachedSunhavenTodoPlugin == null) { _cachedSunhavenTodoPlugin = ReflectionHelper.FindType("Plugin", "SunhavenTodo"); } if (_cachedSunhavenTodoPlugin == null) { GUILayout.Label("SunhavenTodo.Plugin not found", label, Array.Empty()); GUILayout.EndVertical(); return; } if (_cachedSunhavenTodoGetManager == null) { _cachedSunhavenTodoGetManager = _cachedSunhavenTodoPlugin.GetMethod("GetTodoManager", BindingFlags.Static | BindingFlags.Public); } if (_cachedSunhavenTodoGetManager == null) { GUILayout.Label("GetTodoManager not found", label, Array.Empty()); GUILayout.EndVertical(); return; } object obj = _cachedSunhavenTodoGetManager.Invoke(null, null); if (obj == null) { GUILayout.Label("Manager not loaded", label, Array.Empty()); GUILayout.EndVertical(); return; } object obj2 = obj.GetType().GetMethod("GetData")?.Invoke(obj, null); int num = 0; string text = ""; if (obj2 != null) { num = (obj2.GetType().GetProperty("Items")?.GetValue(obj2) as IList)?.Count ?? 0; } text = (obj.GetType().GetProperty("CurrentCharacter")?.GetValue(obj))?.ToString() ?? "?"; string text2 = _cachedSunhavenTodoPlugin.GetMethod("GetOpenListShortcutDisplay", BindingFlags.Static | BindingFlags.Public)?.Invoke(null, null)?.ToString() ?? "Ctrl+T"; GUILayout.Label($"Tasks: {num}", label, Array.Empty()); GUILayout.Label("Character: " + text, label, Array.Empty()); GUILayout.Label("Shortcut: " + text2, label, Array.Empty()); GUILayout.Space(8f); GUILayout.BeginHorizontal(Array.Empty()); if (GUILayout.Button("Toggle UI", button, Array.Empty())) { ReflectionHelper.InvokeStaticMethod(_cachedSunhavenTodoPlugin, "ToggleUI"); } if (GUILayout.Button("Toggle HUD", button, Array.Empty())) { ReflectionHelper.InvokeStaticMethod(_cachedSunhavenTodoPlugin, "ToggleHUD"); } if (GUILayout.Button("Save Data", button, Array.Empty())) { ReflectionHelper.InvokeStaticMethod(_cachedSunhavenTodoPlugin, "SaveData"); } GUILayout.EndHorizontal(); } catch (Exception ex) { GUILayout.Label("Error: " + ex.Message, label, Array.Empty()); } GUILayout.EndVertical(); } private static void DrawAlmanac(GUIStyle box, GUIStyle button, GUIStyle label, GUIStyle sectionHeader) { GUILayout.BeginVertical(box, Array.Empty()); GUILayout.Label("Haven's Almanac", sectionHeader, Array.Empty()); try { if (_cachedHavensAlmanacPlugin == null) { _cachedHavensAlmanacPlugin = ReflectionHelper.FindType("Plugin", "HavensAlmanac"); } if (_cachedHavensAlmanacPlugin == null) { GUILayout.Label("HavensAlmanac.Plugin not found", label, Array.Empty()); GUILayout.EndVertical(); return; } if (_cachedHavensAlmanacGetAggregator == null) { _cachedHavensAlmanacGetAggregator = _cachedHavensAlmanacPlugin.GetMethod("GetDataAggregator", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } if (_cachedHavensAlmanacGetAggregator == null) { GUILayout.Label("GetDataAggregator not found (internal)", label, Array.Empty()); GUILayout.EndVertical(); return; } object obj = _cachedHavensAlmanacGetAggregator.Invoke(null, null); if (obj == null) { GUILayout.Label("Aggregator not loaded", label, Array.Empty()); GUILayout.EndVertical(); return; } PropertyInfo? property = obj.GetType().GetProperty("InstalledModCount"); PropertyInfo property2 = obj.GetType().GetProperty("HasAnyData"); int num = (int)(property?.GetValue(obj) ?? ((object)0)); bool flag = (bool)(property2?.GetValue(obj) ?? ((object)false)); GUILayout.Label($"Installed mods: {num}", label, Array.Empty()); GUILayout.Label($"Has data: {flag}", label, Array.Empty()); if (obj.GetType().GetProperty("Providers")?.GetValue(obj) is IList list && list.Count > 0) { GUILayout.Label("Providers:", label, Array.Empty()); foreach (object item in list) { PropertyInfo? obj2 = item?.GetType().GetProperty("ModName"); PropertyInfo propertyInfo = item?.GetType().GetProperty("IsReady"); string text = obj2?.GetValue(item)?.ToString() ?? "?"; bool flag2 = (bool)(propertyInfo?.GetValue(item) ?? ((object)false)); GUILayout.Label(" - " + text + " " + (flag2 ? "[Ready]" : ""), label, Array.Empty()); } } GUILayout.Space(8f); if (GUILayout.Button("Refresh All", button, Array.Empty())) { obj.GetType().GetMethod("RefreshAll")?.Invoke(obj, null); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[AzraelsMods] Refreshed Almanac data"); } } } catch (Exception ex) { GUILayout.Label("Error: " + ex.Message, label, Array.Empty()); } GUILayout.EndVertical(); } private static void DrawTrinketFortune(GUIStyle box, GUIStyle button, GUIStyle label, GUIStyle sectionHeader) { IDevToolsPanel devToolsPanel = DevToolsRegistry.Panels.FirstOrDefault((IDevToolsPanel p) => p.ModGuid == "com.azraelgodking.trinketfortune") ?? _cachedTrinketFortunePanel; if (devToolsPanel == null) { try { Type type = Type.GetType("TrinketFortune.DevTools.TrinketFortunePanel, TrinketFortune"); if (type != null) { devToolsPanel = (_cachedTrinketFortunePanel = (IDevToolsPanel)Activator.CreateInstance(type)); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)("[AzraelsMods] Trinket Fortune panel fallback: " + ex.Message)); } } } if (devToolsPanel == null) { GUILayout.BeginVertical(box, Array.Empty()); GUILayout.Label("Trinket Fortune", sectionHeader, Array.Empty()); GUILayout.Label("Trinket Fortune not loaded.", label, Array.Empty()); GUILayout.EndVertical(); return; } GUILayout.BeginVertical(box, Array.Empty()); GUILayout.Label(devToolsPanel.DisplayName, sectionHeader, Array.Empty()); GUILayout.Space(5f); try { devToolsPanel.Draw(box, button, label); } catch (Exception ex2) { GUILayout.Label("Error: " + ex2.Message, label, Array.Empty()); } GUILayout.EndVertical(); } } } namespace HavenDevTools.Config { public static class ModConfig { private static bool _theVaultInspectorHooked; private static Type _cachedTheVaultPluginType; private static MethodInfo _cachedSetTheVaultFullInspector; public static ConfigEntry ToggleKey { get; private set; } public static ConfigEntry OverlayToggleKey { get; private set; } public static ConfigEntry ShowOverlayOnStart { get; private set; } public static ConfigEntry OverlayPosition { get; private set; } public static ConfigEntry ShowPerformance { get; private set; } public static ConfigEntry MaxLogEntries { get; private set; } public static ConfigEntry LogLevelFilter { get; private set; } public static ConfigEntry CheckForUpdates { get; private set; } public static ConfigEntry TheVaultFullVaultInspector { get; private set; } public static void Initialize(ConfigFile config) { ToggleKey = config.Bind("Hotkeys", "ToggleKey", (KeyCode)292, "Key to toggle the debug window (requires authorization)"); OverlayToggleKey = config.Bind("Hotkeys", "OverlayToggleKey", (KeyCode)287, "Key to toggle the debug overlay"); ShowOverlayOnStart = config.Bind("Overlay", "ShowOnStart", false, "Show the debug overlay when the game starts"); OverlayPosition = config.Bind("Overlay", "Position", "TopRight", "Overlay position: TopLeft, TopRight, BottomLeft, BottomRight"); ShowPerformance = config.Bind("Overlay", "ShowPerformance", true, "Show FPS and memory usage in the debug overlay"); MaxLogEntries = config.Bind("LogViewer", "MaxLogEntries", 500, "Maximum number of log entries to keep in the in-game log viewer"); LogLevelFilter = config.Bind("LogViewer", "LogLevelFilter", "Info", "Minimum log level to display: Debug, Info, Warning, Error"); CheckForUpdates = config.Bind("Updates", "CheckForUpdates", true, "Check for mod updates on startup"); TheVaultFullVaultInspector = config.Bind("The Vault", "FullVaultInspector", false, "When true: The Vault lists every defined currency (including 0), adds the Debug tab with a raw vault dump, and the HUD shows all slots. Same as the former [Debug] FullVaultInspector in TheVault.cfg (moved here)."); if (!_theVaultInspectorHooked) { TheVaultFullVaultInspector.SettingChanged += delegate { SyncTheVaultFullVaultInspectorToPlugin(); }; _theVaultInspectorHooked = true; } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"Configuration initialized"); } } public static void SyncTheVaultFullVaultInspectorToPlugin() { try { if (!Plugin.HasTheVault || TheVaultFullVaultInspector == null) { return; } if ((object)_cachedTheVaultPluginType == null) { _cachedTheVaultPluginType = ReflectionHelper.FindType("Plugin", "TheVault"); } if (!(_cachedTheVaultPluginType == null)) { if ((object)_cachedSetTheVaultFullInspector == null) { _cachedSetTheVaultFullInspector = _cachedTheVaultPluginType.GetMethod("SetConfigDebugFullVaultInspector", BindingFlags.Static | BindingFlags.Public); } if (!(_cachedSetTheVaultFullInspector == null)) { _cachedSetTheVaultFullInspector.Invoke(null, new object[1] { TheVaultFullVaultInspector.Value }); } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)("[ModConfig] SyncTheVaultFullVaultInspectorToPlugin: " + ex.Message)); } } } public static OverlayPositionType GetOverlayPosition() { return OverlayPosition.Value?.ToLower() switch { "topleft" => OverlayPositionType.TopLeft, "topright" => OverlayPositionType.TopRight, "bottomleft" => OverlayPositionType.BottomLeft, "bottomright" => OverlayPositionType.BottomRight, _ => OverlayPositionType.TopRight, }; } } public enum OverlayPositionType { TopLeft, TopRight, BottomLeft, BottomRight } } namespace HavenDevTools.API { public static class DevToolsRegistry { private static readonly List _panels = new List(); private static readonly object _lock = new object(); public static IReadOnlyList Panels { get { lock (_lock) { return _panels.ToArray(); } } } public static void Register(IDevToolsPanel panel) { IDevToolsPanel panel2 = panel; if (panel2 == null) { return; } lock (_lock) { if (_panels.Exists((IDevToolsPanel p) => p.ModGuid == panel2.ModGuid)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[DevToolsRegistry] Panel for " + panel2.ModGuid + " already registered")); } return; } _panels.Add(panel2); ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)("[DevToolsRegistry] Registered panel: " + panel2.DisplayName + " (" + panel2.ModGuid + ")")); } } } public static void Unregister(string modGuid) { string modGuid2 = modGuid; lock (_lock) { _panels.RemoveAll((IDevToolsPanel p) => p.ModGuid == modGuid2); } } } public interface IDevToolsPanel { string ModGuid { get; } string DisplayName { get; } void Draw(GUIStyle boxStyle, GUIStyle buttonStyle, GUIStyle labelStyle); } }