Decompiled source of SquirrelsBirthdayReminder v2.0.0
BirthdayReminder.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using BirthdayReminder.Data; using BirthdayReminder.Integration; using BirthdayReminder.UI; using HarmonyLib; using I2.Loc; using Microsoft.CodeAnalysis; using SunhavenMods.Shared; using SunhavenTodo; using SunhavenTodo.Data; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Networking; using UnityEngine.SceneManagement; using UnityEngine.UI; [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("BirthdayReminder")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+4812114e8e699e409191f5b733ae25da5b6fffab")] [assembly: AssemblyProduct("BirthdayReminder")] [assembly: AssemblyTitle("BirthdayReminder")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SunhavenMods.Shared { public static class ConfigFileHelper { public static ConfigFile CreateNamedConfig(string pluginGuid, string configFileName, Action<string> logWarning = null) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown string text = Path.Combine(Paths.ConfigPath, configFileName); string text2 = Path.Combine(Paths.ConfigPath, pluginGuid + ".cfg"); try { if (!File.Exists(text) && File.Exists(text2)) { File.Copy(text2, text); } } catch (Exception ex) { logWarning?.Invoke("[Config] Migration to " + configFileName + " failed: " + ex.Message); } return new ConfigFile(text, true); } public static bool ReplacePluginConfig(BaseUnityPlugin plugin, ConfigFile newConfig, Action<string> logWarning = null) { if ((Object)(object)plugin == (Object)null || newConfig == null) { return false; } try { Type typeFromHandle = typeof(BaseUnityPlugin); PropertyInfo property = typeFromHandle.GetProperty("Config", BindingFlags.Instance | BindingFlags.Public); if (property != null && property.CanWrite) { property.SetValue(plugin, newConfig, null); return true; } FieldInfo field = typeFromHandle.GetField("<Config>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic); if (field != null) { field.SetValue(plugin, newConfig); return true; } FieldInfo[] fields = typeFromHandle.GetFields(BindingFlags.Instance | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (fieldInfo.FieldType == typeof(ConfigFile)) { fieldInfo.SetValue(plugin, newConfig); return true; } } } catch (Exception ex) { logWarning?.Invoke("[Config] ReplacePluginConfig failed: " + ex.Message); } return false; } } public static class OvernightHookUtility { public static bool TryHookOvernightEvent(ref bool overnightHooked, ref UnityAction overnightCallback, UnityAction callback, Func<Type, object> singletonResolver, Action<string> logInfo = null, Action<string> logWarning = null) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Expected O, but got Unknown //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Expected O, but got Unknown if (overnightHooked) { return true; } try { Type type = AccessTools.TypeByName("Wish.DayCycle"); if (type != null) { FieldInfo fieldInfo = AccessTools.Field(type, "OnDayStart"); if (fieldInfo != null) { object? value = fieldInfo.GetValue(null); UnityAction val = (UnityAction)((value is UnityAction) ? value : null); overnightCallback = callback; if (val != null) { val = (UnityAction)Delegate.Remove((Delegate?)(object)val, (Delegate?)(object)overnightCallback); val = (UnityAction)Delegate.Combine((Delegate?)(object)val, (Delegate?)(object)overnightCallback); fieldInfo.SetValue(null, val); } else { fieldInfo.SetValue(null, overnightCallback); } overnightHooked = true; logInfo?.Invoke("Hooked into DayCycle.OnDayStart"); return true; } } Type type2 = AccessTools.TypeByName("Wish.UIHandler"); if (type2 == null) { return false; } object obj = singletonResolver?.Invoke(type2); if (obj == null) { return false; } FieldInfo fieldInfo2 = AccessTools.Field(type2, "OnCompleteOvernight"); if (fieldInfo2 == null) { return false; } object? value2 = fieldInfo2.GetValue(obj); UnityAction val2 = (UnityAction)((value2 is UnityAction) ? value2 : null); overnightCallback = callback; if (val2 != null) { val2 = (UnityAction)Delegate.Remove((Delegate?)(object)val2, (Delegate?)(object)overnightCallback); val2 = (UnityAction)Delegate.Combine((Delegate?)(object)val2, (Delegate?)(object)overnightCallback); fieldInfo2.SetValue(obj, val2); } else { fieldInfo2.SetValue(obj, overnightCallback); } overnightHooked = true; logInfo?.Invoke("Hooked into UIHandler.OnCompleteOvernight"); return true; } catch (Exception ex) { logWarning?.Invoke("Failed to hook overnight event: " + ex.Message); return false; } } } public static class VersionChecker { public class VersionCheckResult { public bool Success { get; set; } public bool UpdateAvailable { get; set; } public string CurrentVersion { get; set; } public string LatestVersion { get; set; } public string ModName { get; set; } public string NexusUrl { get; set; } public string Changelog { get; set; } public string ErrorMessage { get; set; } } public class ModHealthSnapshot { public string PluginGuid { get; set; } public DateTime LastCheckUtc { get; set; } public int ExceptionCount { get; set; } public string LastError { get; set; } } private class VersionCheckRunner : MonoBehaviour { private ManualLogSource _pluginLog; public void StartCheck(string pluginGuid, string currentVersion, ManualLogSource pluginLog, Action<VersionCheckResult> onComplete) { _pluginLog = pluginLog; ((MonoBehaviour)this).StartCoroutine(CheckVersionCoroutine(pluginGuid, currentVersion, onComplete)); } private void LogInfo(string message) { ManualLogSource pluginLog = _pluginLog; if (pluginLog != null) { pluginLog.LogInfo((object)("[VersionChecker] " + message)); } } private void LogWarningMsg(string message) { ManualLogSource pluginLog = _pluginLog; if (pluginLog != null) { pluginLog.LogWarning((object)("[VersionChecker] " + message)); } } private void LogErrorMsg(string message) { ManualLogSource pluginLog = _pluginLog; if (pluginLog != null) { pluginLog.LogError((object)("[VersionChecker] " + message)); } } private IEnumerator CheckVersionCoroutine(string pluginGuid, string currentVersion, Action<VersionCheckResult> onComplete) { VersionCheckResult result = new VersionCheckResult { CurrentVersion = currentVersion }; UnityWebRequest www = UnityWebRequest.Get("https://azraelgodking.github.io/SunhavenMod/versions.json"); try { www.timeout = 10; yield return www.SendWebRequest(); if ((int)www.result == 2 || (int)www.result == 3) { result.Success = false; result.ErrorMessage = "Network error: " + www.error; RecordHealthError(pluginGuid, result.ErrorMessage); LogWarningMsg(result.ErrorMessage); onComplete?.Invoke(result); Object.Destroy((Object)(object)((Component)this).gameObject); yield break; } try { string text = www.downloadHandler.text; Match match = GetModPattern(pluginGuid).Match(text); if (!match.Success) { result.Success = false; result.ErrorMessage = "Mod '" + pluginGuid + "' not found in versions.json"; RecordHealthError(pluginGuid, result.ErrorMessage); LogWarningMsg(result.ErrorMessage); onComplete?.Invoke(result); Object.Destroy((Object)(object)((Component)this).gameObject); yield break; } string value = match.Groups[1].Value; result.LatestVersion = ExtractJsonString(value, "version"); result.ModName = ExtractJsonString(value, "name"); result.NexusUrl = ExtractJsonString(value, "nexus"); result.Changelog = ExtractJsonString(value, "changelog"); if (string.IsNullOrEmpty(result.LatestVersion)) { result.Success = false; result.ErrorMessage = "Could not parse version from response"; RecordHealthError(pluginGuid, result.ErrorMessage); LogWarningMsg(result.ErrorMessage); onComplete?.Invoke(result); Object.Destroy((Object)(object)((Component)this).gameObject); yield break; } result.Success = true; result.UpdateAvailable = CompareVersions(currentVersion, result.LatestVersion) < 0; if (result.UpdateAvailable) { LogInfo("Update available for " + result.ModName + ": " + currentVersion + " -> " + result.LatestVersion); } else { LogInfo(result.ModName + " is up to date (v" + currentVersion + ")"); } } catch (Exception ex) { result.Success = false; result.ErrorMessage = "Parse error: " + ex.Message; RecordHealthError(pluginGuid, result.ErrorMessage); LogErrorMsg(result.ErrorMessage); } } finally { ((IDisposable)www)?.Dispose(); } onComplete?.Invoke(result); Object.Destroy((Object)(object)((Component)this).gameObject); } private string ExtractJsonString(string json, string key) { Match match = ExtractFieldRegex.Match(json); while (match.Success) { if (string.Equals(match.Groups["key"].Value, key, StringComparison.Ordinal)) { return match.Groups["value"].Value; } match = match.NextMatch(); } return null; } } private const string VersionsUrl = "https://azraelgodking.github.io/SunhavenMod/versions.json"; private static readonly Dictionary<string, ModHealthSnapshot> HealthByPluginGuid = new Dictionary<string, ModHealthSnapshot>(StringComparer.OrdinalIgnoreCase); private static readonly object HealthLock = new object(); private static readonly Dictionary<string, Regex> ModPatternCache = new Dictionary<string, Regex>(StringComparer.Ordinal); private static readonly object ModPatternCacheLock = new object(); private static readonly Regex ExtractFieldRegex = new Regex("\"(?<key>[^\"]+)\"\\s*:\\s*(?:\"(?<value>[^\"]*)\"|null)", RegexOptions.Compiled); public static void CheckForUpdate(string pluginGuid, string currentVersion, ManualLogSource logger = null, Action<VersionCheckResult> onComplete = null) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) TouchHealth(pluginGuid); VersionCheckRunner versionCheckRunner = new GameObject("VersionChecker").AddComponent<VersionCheckRunner>(); Object.DontDestroyOnLoad((Object)(object)((Component)versionCheckRunner).gameObject); SceneRootSurvivor.TryRegisterPersistentRunnerGameObject(((Component)versionCheckRunner).gameObject); versionCheckRunner.StartCheck(pluginGuid, currentVersion, logger, onComplete); } public static ModHealthSnapshot GetHealthSnapshot(string pluginGuid) { if (string.IsNullOrWhiteSpace(pluginGuid)) { return null; } lock (HealthLock) { if (!HealthByPluginGuid.TryGetValue(pluginGuid, out ModHealthSnapshot value)) { return null; } return new ModHealthSnapshot { PluginGuid = value.PluginGuid, LastCheckUtc = value.LastCheckUtc, ExceptionCount = value.ExceptionCount, LastError = value.LastError }; } } public static int CompareVersions(string v1, string v2) { if (string.IsNullOrEmpty(v1) || string.IsNullOrEmpty(v2)) { return 0; } v1 = v1.TrimStart('v', 'V'); v2 = v2.TrimStart('v', 'V'); int num = v1.IndexOfAny(new char[2] { '-', '+' }); if (num >= 0) { v1 = v1.Substring(0, num); } int num2 = v2.IndexOfAny(new char[2] { '-', '+' }); if (num2 >= 0) { v2 = v2.Substring(0, num2); } string[] array = v1.Split(new char[1] { '.' }); string[] array2 = v2.Split(new char[1] { '.' }); int num3 = Math.Max(array.Length, array2.Length); for (int i = 0; i < num3; i++) { int result; int num4 = ((i < array.Length && int.TryParse(array[i], out result)) ? result : 0); int result2; int num5 = ((i < array2.Length && int.TryParse(array2[i], out result2)) ? result2 : 0); if (num4 < num5) { return -1; } if (num4 > num5) { return 1; } } return 0; } private static void TouchHealth(string pluginGuid) { if (string.IsNullOrWhiteSpace(pluginGuid)) { return; } lock (HealthLock) { if (!HealthByPluginGuid.TryGetValue(pluginGuid, out ModHealthSnapshot value)) { value = new ModHealthSnapshot { PluginGuid = pluginGuid }; HealthByPluginGuid[pluginGuid] = value; } value.LastCheckUtc = DateTime.UtcNow; } } private static void RecordHealthError(string pluginGuid, string errorMessage) { if (string.IsNullOrWhiteSpace(pluginGuid)) { return; } lock (HealthLock) { if (!HealthByPluginGuid.TryGetValue(pluginGuid, out ModHealthSnapshot value)) { value = new ModHealthSnapshot { PluginGuid = pluginGuid }; HealthByPluginGuid[pluginGuid] = value; } value.LastCheckUtc = DateTime.UtcNow; value.ExceptionCount++; value.LastError = errorMessage; } } private static Regex GetModPattern(string pluginGuid) { lock (ModPatternCacheLock) { if (!ModPatternCache.TryGetValue(pluginGuid, out Regex value)) { value = new Regex("\"" + Regex.Escape(pluginGuid) + "\"\\s*:\\s*\\{([^}]+)\\}", RegexOptions.Compiled | RegexOptions.Singleline); ModPatternCache[pluginGuid] = value; } return value; } } } public static class VersionCheckerExtensions { public static void NotifyUpdateAvailable(this VersionChecker.VersionCheckResult result, ManualLogSource logger = null) { if (!result.UpdateAvailable) { return; } string text = result.ModName + " update available: v" + result.LatestVersion; try { Type type = ReflectionHelper.FindWishType("NotificationStack"); if (type != null) { Type type2 = ReflectionHelper.FindType("SingletonBehaviour`1", "Wish"); if (type2 != null) { object obj = type2.MakeGenericType(type).GetProperty("Instance")?.GetValue(null); if (obj != null) { MethodInfo method = type.GetMethod("SendNotification", new Type[5] { typeof(string), typeof(int), typeof(int), typeof(bool), typeof(bool) }); if (method != null) { method.Invoke(obj, new object[5] { text, 0, 1, false, true }); return; } } } } } catch (Exception ex) { if (logger != null) { logger.LogWarning((object)("Failed to send native notification: " + ex.Message)); } } if (logger != null) { logger.LogWarning((object)("[UPDATE AVAILABLE] " + text)); } if (!string.IsNullOrEmpty(result.NexusUrl) && logger != null) { logger.LogWarning((object)("Download at: " + result.NexusUrl)); } } } public static class SceneRootSurvivor { private static readonly object Lock = new object(); private static readonly List<string> NoKillSubstrings = new List<string>(); private static Harmony _harmony; public static void TryRegisterPersistentRunnerGameObject(GameObject go) { if (!((Object)(object)go == (Object)null)) { TryAddNoKillListSubstring(((Object)go).name); } } public static void TryAddNoKillListSubstring(string nameSubstring) { if (string.IsNullOrEmpty(nameSubstring)) { return; } lock (Lock) { bool flag = false; for (int i = 0; i < NoKillSubstrings.Count; i++) { if (string.Equals(NoKillSubstrings[i], nameSubstring, StringComparison.OrdinalIgnoreCase)) { flag = true; break; } } if (!flag) { NoKillSubstrings.Add(nameSubstring); } } EnsurePatched(); } private static void EnsurePatched() { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown //IL_00a3: Expected O, but got Unknown if (_harmony != null) { return; } lock (Lock) { if (_harmony == null) { MethodInfo methodInfo = AccessTools.Method(typeof(Scene), "GetRootGameObjects", Type.EmptyTypes, (Type[])null); if (!(methodInfo == null)) { string text = typeof(SceneRootSurvivor).Assembly.GetName().Name ?? "Unknown"; Harmony val = new Harmony("SunhavenMods.SceneRootSurvivor." + text); val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(SceneRootSurvivor), "OnGetRootGameObjectsPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _harmony = val; } } } } private static void OnGetRootGameObjectsPostfix(ref GameObject[] __result) { if (__result == null || __result.Length == 0) { return; } List<string> list; lock (Lock) { if (NoKillSubstrings.Count == 0) { return; } list = new List<string>(NoKillSubstrings); } List<GameObject> list2 = new List<GameObject>(__result); for (int i = 0; i < list.Count; i++) { string noKill = list[i]; list2.RemoveAll((GameObject a) => (Object)(object)a != (Object)null && ((Object)a).name.IndexOf(noKill, StringComparison.OrdinalIgnoreCase) >= 0); } __result = list2.ToArray(); } } public static class ReflectionHelper { public static readonly BindingFlags AllBindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy; public static Type FindType(string typeName, params string[] namespaces) { Type type = AccessTools.TypeByName(typeName); if (type != null) { return type; } for (int i = 0; i < namespaces.Length; i++) { type = AccessTools.TypeByName(namespaces[i] + "." + typeName); if (type != null) { return type; } } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { type = assembly.GetTypes().FirstOrDefault((Type t) => t.Name == typeName || t.FullName == typeName); if (type != null) { return type; } } catch (ReflectionTypeLoadException) { } } return null; } public static Type FindWishType(string typeName) { return FindType(typeName, "Wish"); } public static object GetStaticValue(Type type, string memberName) { if (type == null) { return null; } try { PropertyInfo property = type.GetProperty(memberName, AllBindingFlags); if (property != null && property.GetMethod != null && property.GetIndexParameters().Length == 0) { return property.GetValue(null); } } catch (AmbiguousMatchException) { return null; } FieldInfo field = type.GetField(memberName, AllBindingFlags); if (field != null) { return field.GetValue(null); } return null; } public static object GetSingletonInstance(Type type) { if (type == null) { return null; } string[] array = new string[5] { "Instance", "instance", "_instance", "Singleton", "singleton" }; foreach (string memberName in array) { object staticValue = GetStaticValue(type, memberName); if (staticValue != null) { return staticValue; } } return null; } public static object GetInstanceValue(object instance, string memberName) { if (instance == null) { return null; } Type type = instance.GetType(); while (type != null) { PropertyInfo property = type.GetProperty(memberName, AllBindingFlags); if (property != null && property.GetMethod != null) { return property.GetValue(instance); } FieldInfo field = type.GetField(memberName, AllBindingFlags); if (field != null) { return field.GetValue(instance); } type = type.BaseType; } return null; } public static bool SetInstanceValue(object instance, string memberName, object value) { if (instance == null) { return false; } Type type = instance.GetType(); while (type != null) { PropertyInfo property = type.GetProperty(memberName, AllBindingFlags); if (property != null && property.SetMethod != null) { property.SetValue(instance, value); return true; } FieldInfo field = type.GetField(memberName, AllBindingFlags); if (field != null) { field.SetValue(instance, value); return true; } type = type.BaseType; } return false; } public static object InvokeMethod(object instance, string methodName, params object[] args) { if (instance == null) { return null; } Type type = instance.GetType(); Type[] array = args?.Select((object a) => a?.GetType() ?? typeof(object)).ToArray() ?? Type.EmptyTypes; MethodInfo methodInfo = AccessTools.Method(type, methodName, array, (Type[])null); if (methodInfo == null) { methodInfo = type.GetMethod(methodName, AllBindingFlags); } if (methodInfo == null) { return null; } return methodInfo.Invoke(instance, args); } public static object InvokeStaticMethod(Type type, string methodName, params object[] args) { if (type == null) { return null; } Type[] array = args?.Select((object a) => a?.GetType() ?? typeof(object)).ToArray() ?? Type.EmptyTypes; MethodInfo methodInfo = AccessTools.Method(type, methodName, array, (Type[])null); if (methodInfo == null) { methodInfo = type.GetMethod(methodName, AllBindingFlags); } if (methodInfo == null) { return null; } return methodInfo.Invoke(null, args); } public static FieldInfo[] GetAllFields(Type type) { if (type == null) { return Array.Empty<FieldInfo>(); } FieldInfo[] fields = type.GetFields(AllBindingFlags); IEnumerable<FieldInfo> second; if (!(type.BaseType != null) || !(type.BaseType != typeof(object))) { second = Enumerable.Empty<FieldInfo>(); } else { IEnumerable<FieldInfo> allFields = GetAllFields(type.BaseType); second = allFields; } return fields.Concat(second).Distinct().ToArray(); } public static PropertyInfo[] GetAllProperties(Type type) { if (type == null) { return Array.Empty<PropertyInfo>(); } PropertyInfo[] properties = type.GetProperties(AllBindingFlags); IEnumerable<PropertyInfo> second; if (!(type.BaseType != null) || !(type.BaseType != typeof(object))) { second = Enumerable.Empty<PropertyInfo>(); } else { IEnumerable<PropertyInfo> allProperties = GetAllProperties(type.BaseType); second = allProperties; } return (from p in properties.Concat(second) group p by p.Name into g select g.First()).ToArray(); } public static T TryGetValue<T>(object instance, string memberName, T defaultValue = default(T)) { try { object instanceValue = GetInstanceValue(instance, memberName); if (instanceValue is T result) { return result; } if (instanceValue != null && typeof(T).IsAssignableFrom(instanceValue.GetType())) { return (T)instanceValue; } return defaultValue; } catch { return defaultValue; } } } public static class TextInputFocusGuard { private const float DefaultPollIntervalSeconds = 0.25f; private static float _nextPollTime = -1f; private static bool _cachedDefer; private static bool _tmpTypeLookupDone; private static Type _tmpInputFieldType; private static bool _qcLookupDone; private static Type _qcType; private static PropertyInfo _qcInstanceProp; private static PropertyInfo _qcIsActiveProp; private static FieldInfo _qcIsActiveField; public static bool ShouldDeferModHotkeys(ManualLogSource debugLog = null, float pollIntervalSeconds = 0.25f) { float realtimeSinceStartup = Time.realtimeSinceStartup; if (realtimeSinceStartup < _nextPollTime) { return _cachedDefer; } _nextPollTime = realtimeSinceStartup + Mathf.Max(0.05f, pollIntervalSeconds); bool flag = false; try { if (GUIUtility.keyboardControl != 0) { flag = true; } if (!flag) { EventSystem current = EventSystem.current; GameObject val = ((current != null) ? current.currentSelectedGameObject : null); if ((Object)(object)val != (Object)null) { if ((Object)(object)val.GetComponent<InputField>() != (Object)null) { flag = true; } else if (TryGetTmpInputField(val)) { flag = true; } } } if (!flag && IsQuantumConsoleActive(debugLog)) { flag = true; } } catch (Exception ex) { if (debugLog != null) { debugLog.LogDebug((object)("[TextInputFocusGuard] " + ex.Message)); } } _cachedDefer = flag; return flag; } private static bool TryGetTmpInputField(GameObject go) { if (!_tmpTypeLookupDone) { _tmpTypeLookupDone = true; _tmpInputFieldType = AccessTools.TypeByName("TMPro.TMP_InputField"); } if (_tmpInputFieldType == null) { return false; } return (Object)(object)go.GetComponent(_tmpInputFieldType) != (Object)null; } private static bool IsQuantumConsoleActive(ManualLogSource debugLog) { try { if (!_qcLookupDone) { _qcLookupDone = true; _qcType = AccessTools.TypeByName("QFSW.QC.QuantumConsole"); if (_qcType != null) { _qcInstanceProp = AccessTools.Property(_qcType, "Instance"); _qcIsActiveProp = AccessTools.Property(_qcType, "IsActive"); _qcIsActiveField = AccessTools.Field(_qcType, "isActive") ?? AccessTools.Field(_qcType, "_isActive"); } } if (_qcType == null) { return false; } object obj = _qcInstanceProp?.GetValue(null); if (obj == null) { return false; } if (_qcIsActiveProp != null && _qcIsActiveProp.PropertyType == typeof(bool)) { return (bool)_qcIsActiveProp.GetValue(obj); } if (_qcIsActiveField != null && _qcIsActiveField.FieldType == typeof(bool)) { return (bool)_qcIsActiveField.GetValue(obj); } } catch (Exception ex) { if (debugLog != null) { debugLog.LogDebug((object)("[TextInputFocusGuard] Quantum Console focus check failed: " + ex.Message)); } } return false; } } internal static class MinimalJsonParser { internal static void WriteJsonString(StringBuilder sb, string value) { sb.Append('"'); if (value != null) { foreach (char c in value) { switch (c) { case '"': sb.Append("\\\""); break; case '\\': sb.Append("\\\\"); break; case '\n': sb.Append("\\n"); break; case '\r': sb.Append("\\r"); break; case '\t': sb.Append("\\t"); break; case '\b': sb.Append("\\b"); break; case '\f': sb.Append("\\f"); break; default: sb.Append(c); break; } } } sb.Append('"'); } internal static void SkipWhitespace(string json, ref int pos) { while (pos < json.Length && char.IsWhiteSpace(json[pos])) { pos++; } } internal static object ParseValue(string json, ref int pos) { SkipWhitespace(json, ref pos); if (pos >= json.Length) { return null; } char c = json[pos]; switch (c) { case '"': return ParseString(json, ref pos); case '{': return ParseObject(json, ref pos); case '[': return ParseArray(json, ref pos); case 't': return ParseLiteral(json, ref pos, "true", true); case 'f': return ParseLiteral(json, ref pos, "false", false); case 'n': return ParseLiteral(json, ref pos, "null", null); default: if (!char.IsDigit(c)) { return null; } goto case '-'; case '-': return ParseNumber(json, ref pos); } } internal static Dictionary<string, object> ParseObject(string json, ref int pos) { SkipWhitespace(json, ref pos); if (pos >= json.Length || json[pos] != '{') { return null; } pos++; Dictionary<string, object> dictionary = new Dictionary<string, object>(); SkipWhitespace(json, ref pos); if (pos < json.Length && json[pos] == '}') { pos++; return dictionary; } while (pos < json.Length) { SkipWhitespace(json, ref pos); string text = ParseString(json, ref pos); if (text == null) { break; } SkipWhitespace(json, ref pos); if (pos >= json.Length || json[pos] != ':') { break; } pos++; SkipWhitespace(json, ref pos); dictionary[text] = ParseValue(json, ref pos); SkipWhitespace(json, ref pos); if (pos >= json.Length || json[pos] != ',') { break; } pos++; } SkipWhitespace(json, ref pos); if (pos < json.Length && json[pos] == '}') { pos++; } return dictionary; } internal static List<object> ParseArray(string json, ref int pos) { SkipWhitespace(json, ref pos); if (pos >= json.Length || json[pos] != '[') { return null; } pos++; List<object> list = new List<object>(); SkipWhitespace(json, ref pos); if (pos < json.Length && json[pos] == ']') { pos++; return list; } while (pos < json.Length) { SkipWhitespace(json, ref pos); list.Add(ParseValue(json, ref pos)); SkipWhitespace(json, ref pos); if (pos >= json.Length || json[pos] != ',') { break; } pos++; } SkipWhitespace(json, ref pos); if (pos < json.Length && json[pos] == ']') { pos++; } return list; } internal static string ParseString(string json, ref int pos) { SkipWhitespace(json, ref pos); if (pos >= json.Length || json[pos] != '"') { return null; } pos++; StringBuilder stringBuilder = new StringBuilder(); while (pos < json.Length) { char c = json[pos]; if (c == '\\' && pos + 1 < json.Length) { pos++; switch (json[pos]) { case '"': stringBuilder.Append('"'); break; case '\\': stringBuilder.Append('\\'); break; case '/': stringBuilder.Append('/'); break; case 'n': stringBuilder.Append('\n'); break; case 'r': stringBuilder.Append('\r'); break; case 't': stringBuilder.Append('\t'); break; case 'b': stringBuilder.Append('\b'); break; case 'f': stringBuilder.Append('\f'); break; case 'u': { if (pos + 4 < json.Length && ushort.TryParse(json.Substring(pos + 1, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result)) { pos += 4; if (result >= 55296 && result <= 56319 && pos + 5 < json.Length && json[pos] == '\\' && json[pos + 1] == 'u' && ushort.TryParse(json.Substring(pos + 2, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result2) && result2 >= 56320 && result2 <= 57343) { stringBuilder.Append(char.ConvertFromUtf32(char.ConvertToUtf32((char)result, (char)result2))); pos += 6; } else { stringBuilder.Append((char)result); } } else { stringBuilder.Append('u'); } break; } default: stringBuilder.Append(json[pos]); break; } pos++; } else { if (c == '"') { pos++; return stringBuilder.ToString(); } stringBuilder.Append(c); pos++; } } return stringBuilder.ToString(); } internal static object ParseNumber(string json, ref int pos) { int num = pos; bool flag = false; if (pos < json.Length && json[pos] == '-') { pos++; } while (pos < json.Length && char.IsDigit(json[pos])) { pos++; } if (pos < json.Length && json[pos] == '.') { flag = true; pos++; while (pos < json.Length && char.IsDigit(json[pos])) { pos++; } } if (pos < json.Length && (json[pos] == 'e' || json[pos] == 'E')) { flag = true; pos++; if (pos < json.Length && (json[pos] == '+' || json[pos] == '-')) { pos++; } while (pos < json.Length && char.IsDigit(json[pos])) { pos++; } } string s = json.Substring(num, pos - num); if (flag && double.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return result; } if (!flag && long.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2)) { return result2; } return 0L; } internal static object ParseLiteral(string json, ref int pos, string literal, object result) { if (pos + literal.Length <= json.Length && json.Substring(pos, literal.Length) == literal) { pos += literal.Length; return result; } pos++; return null; } internal static int ToInt(object val) { if (val is long num) { return (int)num; } if (val is double num2) { return (int)num2; } if (val is int) { return (int)val; } return 0; } } public static class ModLocalization { private static readonly string[] SupportedLanguageCodes = new string[16] { "en", "da", "de", "es", "fr", "it", "ja", "ko", "nl", "pt", "pt-BR", "ru", "sv", "zh-CN", "zh-TW", "uk" }; private static readonly Dictionary<string, string> LanguageAlias = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) { { "pt-br", "pt-BR" }, { "pt_br", "pt-BR" }, { "zh-cn", "zh-CN" }, { "zh_cn", "zh-CN" }, { "zh-tw", "zh-TW" }, { "zh_tw", "zh-TW" } }; private static string _modId; private static Dictionary<string, Dictionary<string, string>> _tables; private static ManualLogSource _log; private static bool _initialized; public static string CurrentLanguage { get; private set; } = "en"; public static event Action<string> LanguageChanged { add { LanguageChangeWatcher.LanguageChanged += value; } remove { LanguageChangeWatcher.LanguageChanged -= value; } } public static void Init(string modId, Dictionary<string, Dictionary<string, string>> tables, Harmony harmony, ManualLogSource log) { _modId = modId ?? string.Empty; _tables = tables ?? new Dictionary<string, Dictionary<string, string>>(); _log = log; _initialized = true; RefreshCurrentLanguage(); LanguageChangeWatcher.EnsurePatched(harmony); } internal static void OnGameLanguageChanged(string languageCode) { if (!_initialized) { return; } string text = NormalizeLanguageCode(languageCode); if (!string.Equals(CurrentLanguage, text, StringComparison.OrdinalIgnoreCase)) { CurrentLanguage = text; ManualLogSource log = _log; if (log != null) { log.LogDebug((object)("[" + _modId + "] Language changed to " + CurrentLanguage)); } } } public static void RefreshCurrentLanguage() { try { string currentLanguageCode = LocalizationManager.CurrentLanguageCode; if (!string.IsNullOrWhiteSpace(currentLanguageCode)) { CurrentLanguage = NormalizeLanguageCode(currentLanguageCode); } } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)("[" + _modId + "] Failed to read LocalizationManager.CurrentLanguageCode: " + ex.Message)); } CurrentLanguage = "en"; } } public static string T(string key) { if (!TryT(key, out string value)) { return key; } return value; } public static string T(string key, params object[] args) { string text = T(key); if (args == null || args.Length == 0) { return text; } try { return string.Format(CultureInfo.InvariantCulture, text, args); } catch (FormatException ex) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)("[" + _modId + "] Format failed for key '" + key + "': " + ex.Message)); } return text; } } public static bool TryT(string key, out string value) { value = null; if (string.IsNullOrEmpty(key)) { return false; } if (_tables == null || !_tables.TryGetValue(key, out Dictionary<string, string> value2) || value2 == null) { return false; } if (TryGetForLanguage(value2, CurrentLanguage, out value)) { return true; } if (!string.Equals(CurrentLanguage, "en", StringComparison.OrdinalIgnoreCase) && TryGetForLanguage(value2, "en", out value)) { return true; } return false; } private static bool TryGetForLanguage(Dictionary<string, string> translations, string languageCode, out string value) { value = null; if (translations == null) { return false; } string text = NormalizeLanguageCode(languageCode); if (translations.TryGetValue(text, out value) && !string.IsNullOrEmpty(value)) { return true; } foreach (KeyValuePair<string, string> translation in translations) { if (string.Equals(translation.Key, text, StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(translation.Value)) { value = translation.Value; return true; } } return false; } public static string NormalizeLanguageCode(string code) { if (string.IsNullOrWhiteSpace(code)) { return "en"; } string text = code.Trim(); if (LanguageAlias.TryGetValue(text, out string value)) { return value; } string[] supportedLanguageCodes = SupportedLanguageCodes; foreach (string text2 in supportedLanguageCodes) { if (string.Equals(text2, text, StringComparison.OrdinalIgnoreCase)) { return text2; } } return "en"; } public static Dictionary<string, Dictionary<string, string>> ParseStringsJson(string json) { Dictionary<string, Dictionary<string, string>> dictionary = new Dictionary<string, Dictionary<string, string>>(StringComparer.Ordinal); if (string.IsNullOrWhiteSpace(json)) { return dictionary; } int pos = 0; Dictionary<string, object> dictionary2 = MinimalJsonParser.ParseObject(json, ref pos); if (dictionary2 == null) { return dictionary; } foreach (KeyValuePair<string, object> item in dictionary2) { if (!(item.Value is Dictionary<string, object> dictionary3)) { continue; } Dictionary<string, string> dictionary4 = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair<string, object> item2 in dictionary3) { if (item2.Value is string value) { dictionary4[NormalizeLanguageCode(item2.Key)] = value; } } if (dictionary4.Count > 0) { dictionary[item.Key] = dictionary4; } } return dictionary; } public static Dictionary<string, Dictionary<string, string>> LoadEmbeddedStrings(Assembly assembly, string resourceName, ManualLogSource log = null) { try { using Stream stream = assembly.GetManifestResourceStream(resourceName); if (stream == null) { if (log != null) { log.LogError((object)("Localization resource not found: " + resourceName)); } return new Dictionary<string, Dictionary<string, string>>(); } using StreamReader streamReader = new StreamReader(stream, Encoding.UTF8); return ParseStringsJson(streamReader.ReadToEnd()); } catch (Exception ex) { if (log != null) { log.LogError((object)("Failed to load localization resource '" + resourceName + "': " + ex.Message)); } return new Dictionary<string, Dictionary<string, string>>(); } } public static void Shutdown() { _initialized = false; _tables = null; _modId = null; _log = null; CurrentLanguage = "en"; } } public static class LanguageChangeWatcher { private static bool _patched; public static event Action<string> LanguageChanged; public static void EnsurePatched(Harmony harmony) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown if (_patched || harmony == null) { return; } try { MethodInfo methodInfo = AccessTools.Method(typeof(LanguageChangeWatcher), "OnSetLanguageAndCode", (Type[])null, (Type[])null); harmony.Patch((MethodBase)AccessTools.Method(typeof(LocalizationManager), "SetLanguageAndCode", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _patched = true; } catch (Exception innerException) { throw new InvalidOperationException("Failed to patch LocalizationManager.SetLanguageAndCode", innerException); } } private static void OnSetLanguageAndCode(string languageName, string languageCode) { string text = ModLocalization.NormalizeLanguageCode(string.IsNullOrWhiteSpace(languageCode) ? LocalizationManager.CurrentLanguageCode : languageCode); ModLocalization.OnGameLanguageChanged(text); LanguageChangeWatcher.LanguageChanged?.Invoke(text); } } public static class LocalizationBootstrap { public static void Init(string pluginGuid, Harmony harmony, ManualLogSource log, Assembly assembly = null) { if ((object)assembly == null) { assembly = Assembly.GetCallingAssembly(); } Dictionary<string, Dictionary<string, string>> tables = ModLocalization.LoadEmbeddedStrings(assembly, pluginGuid + ".Localization.strings.json"); ModLocalization.Init(pluginGuid, tables, harmony, log); } } } namespace BirthdayReminder { [BepInPlugin("com.azraelgodking.squirrelsbirthdayreminder", "A Squirrel's Birthday Reminder", "2.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { [CompilerGenerated] private static class <>O { public static UnityAction <0>__OnOvernightComplete; public static Func<Type, object> <1>__GetSingletonInstance; } private static BirthdayManager _staticManager; private static BirthdayHUD _staticHUD; private static GameObject _hudObject; private static float _staticHUDPositionX = -1f; private static float _staticHUDPositionY = -1f; private static TodoIntegration _todoIntegration; private ConfigEntry<bool> _enabled; private ConfigEntry<float> _hudPositionX; private ConfigEntry<float> _hudPositionY; private ConfigEntry<KeyCode> _toggleKey; private ConfigEntry<bool> _showGiftHints; private ConfigEntry<bool> _useNativeNotifications; private ConfigEntry<bool> _debugMode; private ConfigEntry<bool> _checkForUpdates; private ConfigEntry<float> _uiScale; private static float _staticUIScale = 1f; private static string _currentCharacterName; private static bool _isCharacterLoaded; private BirthdayManager _manager; private BirthdayHUD _hud; private Harmony _harmony; private bool _applicationQuitting; private static bool _overnightHooked = false; private static UnityAction _overnightCallback; private static GameObject _persistentRunner; private static PersistentRunner _persistentRunnerComponent; private static KeyCode _staticToggleKey = (KeyCode)98; private static bool _staticDebugMode = false; private static bool _staticUseNativeNotifications = true; private static bool _staticEnabled = true; private static Type _notificationStackType; private static PropertyInfo _notificationStackInstance; private static MethodInfo _sendNotificationMethod; private static bool _notificationSystemInitialized = false; public static Plugin Instance { get; private set; } public static ManualLogSource Log { get; private set; } public static ConfigFile ConfigFile { get; private set; } public static KeyCode StaticToggleKey => _staticToggleKey; public static bool StaticDebugMode => _staticDebugMode; public static bool StaticUseNativeNotifications => _staticUseNativeNotifications; public static bool StaticEnabled => _staticEnabled; public static string CurrentCharacter => _currentCharacterName; public static bool IsCharacterLoaded => _isCharacterLoaded; private void Awake() { Instance = this; Log = ((BaseUnityPlugin)this).Logger; ConfigFile = CreateNamedConfig(); ConfigFileHelper.ReplacePluginConfig((BaseUnityPlugin)(object)this, ConfigFile, (Action<string>)Log.LogWarning); Log.LogInfo((object)"Loading A Squirrel's Birthday Reminder v2.0.0"); BindConfiguration(); if (!_enabled.Value) { Log.LogInfo((object)"A Squirrel's Birthday Reminder is disabled in config. Skipping initialization."); return; } CreatePersistentRunner(); InitializeManager(); ApplyPatches(); InitializeIntegrations(); SceneManager.sceneLoaded += OnSceneLoaded; if (_checkForUpdates.Value) { VersionChecker.CheckForUpdate("com.azraelgodking.squirrelsbirthdayreminder", "2.0.0", Log, delegate(VersionChecker.VersionCheckResult result) { result.NotifyUpdateAvailable(Log); }); } Log.LogInfo((object)"A Squirrel's Birthday Reminder loaded successfully!"); } private void BindConfiguration() { //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: 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) //IL_01fd: Expected O, but got Unknown _enabled = ConfigFile.Bind<bool>("General", "Enabled", true, "Enable birthday reminders"); _staticEnabled = _enabled.Value; _enabled.SettingChanged += delegate { _staticEnabled = _enabled.Value; }; _hudPositionX = ConfigFile.Bind<float>("HUD", "PositionX", -1f, "HUD X position (-1 for default)"); _staticHUDPositionX = _hudPositionX.Value; _hudPositionY = ConfigFile.Bind<float>("HUD", "PositionY", -1f, "HUD Y position (-1 for default)"); _staticHUDPositionY = _hudPositionY.Value; _toggleKey = ConfigFile.Bind<KeyCode>("Hotkeys", "ToggleKey", (KeyCode)98, "Key to toggle the birthday HUD (with Ctrl)"); _staticToggleKey = _toggleKey.Value; _toggleKey.SettingChanged += delegate { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) _staticToggleKey = _toggleKey.Value; }; _showGiftHints = ConfigFile.Bind<bool>("General", "ShowGiftHints", true, "Show gift preferences in the birthday reminder"); _useNativeNotifications = ConfigFile.Bind<bool>("General", "UseNativeNotifications", true, "Show birthday notifications using the game's native notification system"); _debugMode = ConfigFile.Bind<bool>("Debug", "DebugMode", false, "Enable debug mode for testing (Ctrl+Shift+B to add test birthday)"); _staticDebugMode = _debugMode.Value; _debugMode.SettingChanged += delegate { _staticDebugMode = _debugMode.Value; }; _staticUseNativeNotifications = _useNativeNotifications.Value; _useNativeNotifications.SettingChanged += delegate { _staticUseNativeNotifications = _useNativeNotifications.Value; }; _checkForUpdates = ConfigFile.Bind<bool>("Updates", "CheckForUpdates", true, "Check for mod updates on startup"); _uiScale = ConfigFile.Bind<float>("Display", "UIScale", 1f, new ConfigDescription("Scale factor for the birthday HUD (1.0 = default, 1.5 = 50% larger)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 2.5f), Array.Empty<object>())); _staticUIScale = Mathf.Clamp(_uiScale.Value, 0.5f, 2.5f); _uiScale.SettingChanged += delegate { _staticUIScale = Mathf.Clamp(_uiScale.Value, 0.5f, 2.5f); _staticHUD?.SetScale(_staticUIScale); }; } private static ConfigFile CreateNamedConfig() { return ConfigFileHelper.CreateNamedConfig("com.azraelgodking.squirrelsbirthdayreminder", "BirthdayReminder.cfg", delegate(string message) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)message); } }); } 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("BirthdayReminder_PersistentRunner"); Object.DontDestroyOnLoad((Object)(object)_persistentRunner); ((Object)_persistentRunner).hideFlags = (HideFlags)61; SceneRootSurvivor.TryRegisterPersistentRunnerGameObject(_persistentRunner); _persistentRunnerComponent = _persistentRunner.AddComponent<PersistentRunner>(); Log.LogInfo((object)"[PersistentRunner] Created"); } } private void InitializeManager() { _manager = new BirthdayManager(); _staticManager = _manager; } private void InitializeIntegrations() { try { if (Chainloader.PluginInfos.ContainsKey("com.azraelgodking.sunhaventodo")) { _todoIntegration = new TodoIntegration(_staticManager); } else { Log.LogInfo((object)"[Integrations] SunhavenTodo not found - birthday todos disabled"); } } catch (Exception ex) { Log.LogWarning((object)("[Integrations] Error initializing: " + ex.Message)); } } private void ApplyPatches() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Expected O, but got Unknown _harmony = new Harmony("com.azraelgodking.squirrelsbirthdayreminder"); LocalizationBootstrap.Init("com.azraelgodking.squirrelsbirthdayreminder", _harmony, Log); try { Type type = AccessTools.TypeByName("Wish.Player"); if (type != null) { MethodInfo methodInfo = AccessTools.Method(type, "InitializeAsOwner", (Type[])null, (Type[])null); if (methodInfo != null) { MethodInfo methodInfo2 = AccessTools.Method(typeof(PlayerPatches), "OnPlayerInitialized", (Type[])null, (Type[])null); _harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)"Applied player initialization patch"); } else { Log.LogWarning((object)"Could not find Player.InitializeAsOwner — birthday player hook inactive"); } } else { Log.LogWarning((object)"Could not find Wish.Player — birthday player hook inactive"); } } catch (Exception ex) { Log.LogWarning((object)("Failed to apply player init patch: " + ex.Message)); return; } try { Type type2 = AccessTools.TypeByName("Wish.NPCAI"); Type type3 = AccessTools.TypeByName("Wish.Item"); if (type2 != null && type3 != null) { MethodInfo methodInfo3 = AccessTools.Method(type2, "Gift", new Type[1] { type3 }, (Type[])null); if (methodInfo3 != null) { MethodInfo methodInfo4 = AccessTools.Method(typeof(GiftPatches), "OnGiftGiven", (Type[])null, (Type[])null); _harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(methodInfo4), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)"Applied gift tracking patch (NPCAI.Gift)"); } else { Log.LogWarning((object)"Could not find NPCAI.Gift(Item) — gift tracking disabled"); _harmony.UnpatchSelf(); } } else { Log.LogWarning((object)"Could not find NPCAI or Wish.Item — gift tracking disabled"); _harmony.UnpatchSelf(); } } catch (Exception ex2) { Log.LogWarning((object)("Failed to apply gift patch (rolling back Harmony): " + ex2.Message)); _harmony.UnpatchSelf(); } } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { Log.LogDebug((object)("[BirthdayReminder] Scene loaded: " + ((Scene)(ref scene)).name)); if (((Scene)(ref scene)).name == "MainMenu" || ((Scene)(ref scene)).name == "Bootstrap") { Log.LogInfo((object)"[BirthdayReminder] Main menu detected - hiding HUD and resetting state"); _staticHUD?.Hide(); _isCharacterLoaded = false; _currentCharacterName = null; } else { EnsureUIComponentsExist(); } } public static void ResetOvernightHook() { _overnightHooked = false; _overnightCallback = null; ManualLogSource log = Log; if (log != null) { log.LogInfo((object)"[BirthdayReminder] Overnight hook reset"); } } public static void TryHookOvernightEvent() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown object obj = <>O.<0>__OnOvernightComplete; if (obj == null) { UnityAction val = OnOvernightComplete; <>O.<0>__OnOvernightComplete = val; obj = (object)val; } OvernightHookUtility.TryHookOvernightEvent(ref _overnightHooked, ref _overnightCallback, (UnityAction)obj, GetSingletonInstance, delegate(string message) { ManualLogSource log = Log; if (log != null) { log.LogInfo((object)message); } }, delegate(string message) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)message); } }); } private static void OnOvernightComplete() { ManualLogSource log = Log; if (log != null) { log.LogInfo((object)"[BirthdayReminder] Day started - checking for birthdays"); } _staticManager?.CheckTodaysBirthdays(); if (_staticManager != null && _staticManager.HasBirthdays) { EnsureUIComponentsExist(); _staticHUD?.Show(); SendAllBirthdayNotifications(); return; } _staticHUD?.Hide(); ManualLogSource log2 = Log; if (log2 != null) { log2.LogInfo((object)"[BirthdayReminder] No birthdays today - HUD hidden"); } } public static void EnsureUIComponentsExist() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Expected O, but got Unknown try { if ((Object)(object)_persistentRunner == (Object)null || (Object)(object)_persistentRunnerComponent == (Object)null) { ManualLogSource log = Log; if (log != null) { log.LogInfo((object)"[EnsureUI] Recreating PersistentRunner..."); } _persistentRunner = new GameObject("BirthdayReminder_PersistentRunner"); Object.DontDestroyOnLoad((Object)(object)_persistentRunner); ((Object)_persistentRunner).hideFlags = (HideFlags)61; SceneRootSurvivor.TryRegisterPersistentRunnerGameObject(_persistentRunner); _persistentRunnerComponent = _persistentRunner.AddComponent<PersistentRunner>(); ManualLogSource log2 = Log; if (log2 != null) { log2.LogInfo((object)"[EnsureUI] PersistentRunner recreated"); } } if ((Object)(object)_staticHUD == (Object)null) { ManualLogSource log3 = Log; if (log3 != null) { log3.LogInfo((object)"[EnsureUI] Creating BirthdayHUD..."); } _hudObject = new GameObject("BirthdayReminder_HUD"); Object.DontDestroyOnLoad((Object)(object)_hudObject); _staticHUD = _hudObject.AddComponent<BirthdayHUD>(); _staticHUD.Initialize(_staticManager); _staticHUD.SetScale(_staticUIScale); if (_staticHUDPositionX >= 0f && _staticHUDPositionY >= 0f) { _staticHUD.SetPosition(_staticHUDPositionX, _staticHUDPositionY); } _staticHUD.OnPositionChanged = delegate(float x, float y) { _staticHUDPositionX = x; _staticHUDPositionY = y; Plugin instance = Instance; if (instance != null) { ConfigEntry<float> hudPositionX = instance._hudPositionX; if (hudPositionX != null) { ((ConfigEntryBase)hudPositionX).SetSerializedValue(x.ToString()); } } Plugin instance2 = Instance; if (instance2 != null) { ConfigEntry<float> hudPositionY = instance2._hudPositionY; if (hudPositionY != null) { ((ConfigEntryBase)hudPositionY).SetSerializedValue(y.ToString()); } } }; ManualLogSource log4 = Log; if (log4 != null) { log4.LogInfo((object)"[EnsureUI] BirthdayHUD created"); } } if ((Object)(object)Instance != (Object)null) { Instance._hud = _staticHUD; } } catch (Exception ex) { ManualLogSource log5 = Log; if (log5 != null) { log5.LogError((object)("[EnsureUI] Error: " + ex.Message)); } } } public static BirthdayManager GetManager() { return _staticManager; } public static BirthdayHUD GetHUD() { return _staticHUD; } public static TodoIntegration GetTodoIntegration() { return _todoIntegration; } private static void InitializeNotificationSystem() { if (_notificationSystemInitialized) { return; } _notificationSystemInitialized = true; try { _notificationStackType = AccessTools.TypeByName("Wish.NotificationStack"); if (_notificationStackType == null) { ManualLogSource log = Log; if (log != null) { log.LogDebug((object)"[Notifications] NotificationStack type not found"); } return; } Type type = AccessTools.TypeByName("Wish.SingletonBehaviour`1"); if (type != null) { _notificationStackInstance = type.MakeGenericType(_notificationStackType).GetProperty("Instance", BindingFlags.Static | BindingFlags.Public); } _sendNotificationMethod = AccessTools.Method(_notificationStackType, "SendNotification", new Type[5] { typeof(string), typeof(int), typeof(int), typeof(bool), typeof(bool) }, (Type[])null); if (_sendNotificationMethod != null) { ManualLogSource log2 = Log; if (log2 != null) { log2.LogInfo((object)"[Notifications] Native notification system initialized"); } } else { ManualLogSource log3 = Log; if (log3 != null) { log3.LogDebug((object)"[Notifications] SendNotification method not found"); } } } catch (Exception ex) { ManualLogSource log4 = Log; if (log4 != null) { log4.LogDebug((object)("[Notifications] Error initializing: " + ex.Message)); } } } public static void SendBirthdayNotification(string npcName, int itemId = 0) { if (!_staticUseNativeNotifications) { return; } InitializeNotificationSystem(); if (_sendNotificationMethod == null || _notificationStackInstance == null) { ManualLogSource log = Log; if (log != null) { log.LogDebug((object)"[Notifications] Cannot send - system not available"); } return; } try { object value = _notificationStackInstance.GetValue(null); if (value == null) { ManualLogSource log2 = Log; if (log2 != null) { log2.LogDebug((object)"[Notifications] NotificationStack instance is null"); } return; } string text = "It's " + npcName + "'s birthday today!"; _sendNotificationMethod.Invoke(value, new object[5] { text, itemId, 1, false, true }); ManualLogSource log3 = Log; if (log3 != null) { log3.LogInfo((object)("[Notifications] Sent birthday notification for " + npcName)); } } catch (Exception ex) { ManualLogSource log4 = Log; if (log4 != null) { log4.LogDebug((object)("[Notifications] Error sending notification: " + ex.Message)); } } } public static void SendAllBirthdayNotifications() { if (!_staticUseNativeNotifications || _staticManager == null || !_staticManager.HasBirthdays) { return; } foreach (BirthdayDisplayInfo todaysBirthday in _staticManager.TodaysBirthdays) { if (!todaysBirthday.HasBeenGifted) { SendBirthdayNotification(todaysBirthday.NPCName); } } } private static object GetSingletonInstance(Type targetType) { try { Type type = AccessTools.TypeByName("Wish.SingletonBehaviour`1"); if (type != null) { return AccessTools.Property(type.MakeGenericType(targetType), "Instance")?.GetValue(null); } return AccessTools.Property(targetType, "Instance")?.GetValue(null); } catch (Exception ex) { ManualLogSource log = Log; if (log != null) { log.LogDebug((object)("[BirthdayReminder] GetSingletonInstance: " + ex.Message)); } return null; } } public static void CheckBirthdays() { _staticManager?.CheckTodaysBirthdays(); } public static void OnCharacterChanged(string newCharacterName) { if (_currentCharacterName != newCharacterName) { ManualLogSource log = Log; if (log != null) { log.LogInfo((object)("[BirthdayReminder] Character changed: " + (_currentCharacterName ?? "None") + " -> " + newCharacterName)); } _currentCharacterName = newCharacterName; _staticManager?.ResetForNewCharacter(newCharacterName); _todoIntegration?.Reset(); _staticHUD?.Hide(); _isCharacterLoaded = true; } } private void DebugAddTestBirthday() { Log.LogInfo((object)"[DEBUG] Adding test birthday..."); EnsureUIComponentsExist(); _staticManager?.DebugAddTestBirthday("Test NPC", "Loves: Diamonds, Gold"); if (_staticManager != null && _staticManager.HasBirthdays) { _staticHUD?.Show(); Log.LogInfo((object)"[DEBUG] Test birthday added and HUD shown"); } } private void DebugRefreshBirthdays() { Log.LogInfo((object)"[DEBUG] Ctrl+Shift+R pressed - Manual refresh triggered"); EnsureUIComponentsExist(); _staticManager?.ManualRefresh(); Log.LogInfo((object)$"[DEBUG] Found {_staticManager?.TodaysBirthdays.Count ?? 0} birthdays"); _staticHUD?.Show(); } private void DebugClearBirthdays() { Log.LogInfo((object)"[DEBUG] Clearing all birthdays..."); _staticManager?.DebugClearBirthdays(); _staticHUD?.Hide(); Log.LogInfo((object)"[DEBUG] Birthdays cleared and HUD hidden"); } private void DebugLoadAllBirthdays() { Log.LogInfo((object)"[DEBUG] Loading all NPC birthdays..."); EnsureUIComponentsExist(); _staticManager?.DebugLoadAllBirthdays(); if (_staticManager != null && _staticManager.HasBirthdays) { _staticHUD?.Show(); Log.LogInfo((object)$"[DEBUG] Loaded {_staticManager.TodaysBirthdays.Count} birthdays"); } } private void OnDestroy() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) SceneManager.sceneLoaded -= OnSceneLoaded; _todoIntegration?.Dispose(); _todoIntegration = null; 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 + ")")); } } Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private void OnApplicationQuit() { _applicationQuitting = true; } } public static class PlayerPatches { private static string _lastCharacterName; public static void OnPlayerInitialized(object __instance) { try { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[PlayerPatches] Player initialized - checking character..."); } string characterName = GetCharacterName(__instance); if (_lastCharacterName != characterName) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)("[PlayerPatches] Character: " + characterName)); } Plugin.OnCharacterChanged(characterName); _lastCharacterName = characterName; } Plugin.EnsureUIComponentsExist(); Plugin.ResetOvernightHook(); Plugin.TryHookOvernightEvent(); Plugin.GetManager()?.CheckTodaysBirthdays(); BirthdayManager manager = Plugin.GetManager(); if (manager != null && manager.HasBirthdays) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)$"[PlayerPatches] Found {manager.TodaysBirthdays.Count} birthdays - showing HUD"); } Plugin.GetHUD()?.Show(); return; } ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogInfo((object)"[PlayerPatches] No birthdays found today - HUD will not show automatically"); } ManualLogSource log5 = Plugin.Log; if (log5 != null) { log5.LogInfo((object)"[PlayerPatches] Use Ctrl+Alt+B to add a test birthday for testing"); } } catch (Exception ex) { ManualLogSource log6 = Plugin.Log; if (log6 != null) { log6.LogError((object)("Error in OnPlayerInitialized: " + ex.Message)); } } } private static string GetCharacterName(object player) { try { Type type = AccessTools.TypeByName("Wish.GameSave"); if (type != null) { Type type2 = AccessTools.TypeByName("Wish.SingletonBehaviour`1"); if (type2 != null) { object obj = AccessTools.Property(type2.MakeGenericType(type), "Instance")?.GetValue(null); if (obj != null) { object obj2 = AccessTools.Property(type, "CurrentSave")?.GetValue(obj); if (obj2 != null) { object obj3 = AccessTools.Property(obj2.GetType(), "characterData")?.GetValue(obj2); if (obj3 != null) { string text = AccessTools.Property(obj3.GetType(), "characterName")?.GetValue(obj3) as string; if (!string.IsNullOrEmpty(text)) { return text; } } } } } } if (player != null) { string text2 = AccessTools.Property(player.GetType(), "playerName")?.GetValue(player) as string; if (!string.IsNullOrEmpty(text2)) { return text2; } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("Failed to get character name: " + ex.Message)); } } return "Unknown"; } } public static class GiftPatches { public static void OnGiftGiven(object __instance, object __0) { try { if (__instance == null) { return; } Type type = __instance.GetType(); string npcName = (AccessTools.Property(type, "OriginalName") ?? AccessTools.Property(type, "ActualNPCName") ?? AccessTools.Property(type, "NPCName") ?? AccessTools.Property(type, "npcName") ?? AccessTools.Property(type, "Name"))?.GetValue(__instance)?.ToString(); if (string.IsNullOrEmpty(npcName)) { return; } string normalizedNpcName = NormalizeNpcName(npcName); if (string.IsNullOrEmpty(normalizedNpcName)) { return; } BirthdayManager manager = Plugin.GetManager(); if (manager == null || !manager.HasBirthdays) { return; } BirthdayDisplayInfo birthdayDisplayInfo = manager.TodaysBirthdays.Find((BirthdayDisplayInfo b) => string.Equals(NormalizeNpcName(b.NPCName), normalizedNpcName, StringComparison.OrdinalIgnoreCase) || string.Equals(b.NPCName, npcName, StringComparison.OrdinalIgnoreCase) || (b.NPCName != null && b.NPCName.Contains("+" + npcName))); if (birthdayDisplayInfo != null && !birthdayDisplayInfo.HasBeenGifted) { manager.MarkGifted(normalizedNpcName); manager.TryRecordLovedGift(normalizedNpcName, __0); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[BirthdayReminder] Marked " + normalizedNpcName + " as gifted on their birthday!")); } Plugin.GetTodoIntegration()?.OnGiftGiven(normalizedNpcName); } } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("Error tracking gift: " + ex.Message)); } } } private static string NormalizeNpcName(string npcName) { if (string.IsNullOrWhiteSpace(npcName)) { return ""; } List<string> list = (from p in npcName.Split(new char[1] { '+' }, StringSplitOptions.RemoveEmptyEntries) select p.Trim() into p where !string.IsNullOrEmpty(p) select p).Distinct<string>(StringComparer.OrdinalIgnoreCase).ToList(); if (list.Count == 0) { return npcName.Trim(); } if (list.Count == 1) { return list[0]; } return string.Join("+", list); } } public class PersistentRunner : MonoBehaviour { private void Update() { CheckHotkeys(); } private void CheckHotkeys() { //IL_00b5: 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_021c: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.StaticEnabled || TextInputFocusGuard.ShouldDeferModHotkeys(Plugin.Log)) { return; } bool flag = Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305); bool flag2 = Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303); bool flag3 = Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307); if (flag && !flag2 && !flag3 && Input.GetKeyDown(Plugin.StaticToggleKey)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[PersistentRunner] Ctrl+B pressed - toggling HUD"); } Plugin.EnsureUIComponentsExist(); Plugin.GetHUD()?.Toggle(); } if (flag && flag3 && !flag2 && Input.GetKeyDown(Plugin.StaticToggleKey)) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)"[PersistentRunner] Ctrl+Alt+B pressed - adding test birthday"); } Plugin.EnsureUIComponentsExist(); Plugin.GetManager()?.DebugAddTestBirthday("Test NPC", "Loves: Diamonds, Gold"); BirthdayHUD hUD = Plugin.GetHUD(); BirthdayManager manager = Plugin.GetManager(); if (manager != null && manager.HasBirthdays && (Object)(object)hUD != (Object)null) { ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)$"[PersistentRunner] Showing HUD - birthdays: {Plugin.GetManager()?.TodaysBirthdays?.Count}"); } hUD.Show(); ManualLogSource log4 = Plugin.Log; if (log4 != null) { log4.LogInfo((object)$"[PersistentRunner] HUD visible: {hUD.IsVisible}"); } } else { ManualLogSource log5 = Plugin.Log; if (log5 != null) { log5.LogWarning((object)$"[PersistentRunner] Cannot show HUD - manager: {Plugin.GetManager() != null}, hud: {(Object)(object)hUD != (Object)null}"); } } } if (flag && flag3 && !flag2 && Input.GetKeyDown((KeyCode)97)) { ManualLogSource log6 = Plugin.Log; if (log6 != null) { log6.LogInfo((object)"[PersistentRunner] Ctrl+Alt+A pressed - loading all birthdays"); } Plugin.EnsureUIComponentsExist(); Plugin.GetManager()?.DebugLoadAllBirthdays(); } if (Plugin.StaticDebugMode && flag && flag2 && !flag3 && Input.GetKeyDown(Plugin.StaticToggleKey)) { Plugin.EnsureUIComponentsExist(); Plugin.GetManager()?.DebugAddTestBirthday("Test NPC", "Loves: Diamonds, Gold"); } if (Plugin.StaticDebugMode && flag && flag2 && Input.GetKeyDown((KeyCode)114)) { ManualLogSource log7 = Plugin.Log; if (log7 != null) { log7.LogInfo((object)"[PersistentRunner] Ctrl+Shift+R pressed - Manual refresh"); } Plugin.EnsureUIComponentsExist(); Plugin.GetManager()?.ManualRefresh(); Plugin.GetHUD()?.Show(); } if (Plugin.StaticDebugMode && flag && flag2 && Input.GetKeyDown((KeyCode)99)) { ManualLogSource log8 = Plugin.Log; if (log8 != null) { log8.LogInfo((object)"[PersistentRunner] Ctrl+Shift+C pressed - Clearing birthdays"); } Plugin.GetManager()?.DebugClearBirthdays(); Plugin.GetHUD()?.Hide(); } if (Plugin.StaticDebugMode && flag && flag2 && Input.GetKeyDown((KeyCode)97)) { ManualLogSource log9 = Plugin.Log; if (log9 != null) { log9.LogInfo((object)"[PersistentRunner] Ctrl+Shift+A pressed - loading all birthdays"); } Plugin.EnsureUIComponentsExist(); Plugin.GetManager()?.DebugLoadAllBirthdays(); } if (Plugin.StaticDebugMode && flag && flag2 && Input.GetKeyDown((KeyCode)108)) { ManualLogSource log10 = Plugin.Log; if (log10 != null) { log10.LogInfo((object)"[PersistentRunner] Ctrl+Shift+L pressed - dumping Lynn's NPC info..."); } Plugin.EnsureUIComponentsExist(); Plugin.GetManager()?.DebugDumpNPCInfo(); } } 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.squirrelsbirthdayreminder"; public const string PLUGIN_NAME = "A Squirrel's Birthday Reminder"; public const string PLUGIN_VERSION = "2.0.0"; } } namespace BirthdayReminder.UI { public class BirthdayHUD : MonoBehaviour { private const int WINDOW_ID = 98770; private const int GIFT_WINDOW_ID = 98771; private const float BASE_WINDOW_WIDTH = 320f; private const float BASE_MIN_HEIGHT = 100f; private const float BASE_MAX_HEIGHT = 500f; private const float BASE_HEADER_HEIGHT = 28f; private const float BASE_ITEM_HEIGHT = 65f; private const float BASE_GIFT_WINDOW_WIDTH = 300f; private const float BASE_GIFT_WINDOW_HEIGHT = 400f; private float _scale = 1f; private BirthdayManager _manager; private bool _isVisible; private Rect _windowRect; private float _showTimer; private const float AUTO_HIDE_DELAY = 15f; private bool _showGiftPopup; private Rect _giftPopupRect; private BirthdayDisplayInfo _selectedNPC; private Vector2 _giftScrollPosition; public Action<float, float> OnPositionChanged; private readonly Color _bgColor = new Color(0.18f, 0.14f, 0.12f, 0.95f); private readonly Color _headerColor = new Color(0.75f, 0.35f, 0.45f, 1f); private readonly Color _borderColor = new Color(0.85f, 0.65f, 0.5f, 1f); private readonly Color _textLight = new Color(0.95f, 0.92f, 0.88f); private readonly Color _textDark = new Color(0.25f, 0.2f, 0.15f); private readonly Color _giftedColor = new Color(0.5f, 0.85f, 0.5f); private readonly Color _ungiftedColor = new Color(1f, 0.75f, 0.3f); private readonly Color _hintColor = new Color(0.75f, 0.7f, 0.65f); private readonly Color _lovedColor = new Color(0.95f, 0.45f, 0.55f); private readonly Color _likedColor = new Color(0.55f, 0.7f, 0.95f); private readonly Color _universalColor = new Color(0.85f, 0.75f, 0.45f); private bool _stylesInitialized; private GUIStyle _windowStyle; private GUIStyle _headerStyle; private GUIStyle _nameStyle; private GUIStyle _giftedStyle; private GUIStyle _hintStyle; private GUIStyle _closeButtonStyle; private GUIStyle _moreButtonStyle; private GUIStyle _giftItemStyle; private GUIStyle _sectionHeaderStyle; private GUIStyle _universalItemStyle; private GUIStyle _statusMessageStyle; private GUIStyle _itemBoxStyle; private GUIStyle _statusGiftedStyle; private GUIStyle _statusUngiftedStyle; private GUIStyle _nameGiftedStyle; private GUIStyle _nameUngiftedStyle; private GUIStyle _lovedSectionStyle; private GUIStyle _likedSectionStyle; private GUIStyle _universalSubHeaderStyle; private GUIStyle _lovedBulletStyle; private GUIStyle _likedBulletStyle; private GUIStyle _universalBulletStyle; private Texture2D _windowBackground; private Texture2D _headerBackground; private Texture2D _itemBackground; private Texture2D _separatorTex; private float WindowWidth => 320f * _scale; private float MinHeight => 100f * _scale; private float MaxHeight => 500f * _scale; private float HeaderHeight => 28f * _scale; private float ItemHeight => 65f * _scale; private float GiftWindowWidth => 300f * _scale; private float GiftWindowHeight => 400f * _scale; public bool IsVisible => _isVisible; private int ScaledFont(int baseSize) { return Mathf.Max(8, Mathf.RoundToInt((float)baseSize * _scale)); } private float Scaled(float value) { return value * _scale; } private int ScaledInt(float value) { return Mathf.RoundToInt(value * _scale); } private void Awake() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) _windowRect = new Rect(100f, 100f, WindowWidth, MinHeight); _isVisible = false; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[BirthdayHUD] Awake called - isVisible set to false (waiting for player init)"); } } public void Initialize(BirthdayManager manager) { //IL_00dc: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) _manager = manager; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[BirthdayHUD] Initialize called, manager: {manager != null}, screen: ({Screen.width}x{Screen.height})"); } if (Screen.width > 0 && Screen.height > 0) { _windowRect = new Rect((float)Screen.width - WindowWidth - Scaled(20f), Scaled(80f), WindowWidth, MinHeight); ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)$"[BirthdayHUD] Default position set to ({((Rect)(ref _windowRect)).x}, {((Rect)(ref _windowRect)).y})"); } } else { _windowRect = new Rect(100f, 100f, WindowWidth, MinHeight); ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)"[BirthdayHUD] Using fallback position (100, 100) - screen not ready"); } } if (_manager != null) { _manager.OnBirthdaysUpdated += OnBirthdaysUpdated; } } public void SetPosition(float x, float y) { if (Screen.width > 0 && Screen.height > 0) { if (x >= 0f) { ((Rect)(ref _windowRect)).x = Mathf.Clamp(x, 0f, (float)Screen.width - ((Rect)(ref _windowRect)).width); } if (y >= 0f) { ((Rect)(ref _windowRect)).y = Mathf.Clamp(y, 0f, (float)Screen.height - ((Rect)(ref _windowRect)).height); } } } public (float x, float y) GetPosition() { return (x: ((Rect)(ref _windowRect)).x, y: ((Rect)(ref _windowRect)).y); } public void SetScale(float scale) { _scale = Mathf.Clamp(scale, 0.5f, 2.5f); _stylesInitialized = false; EnsureOnScreen(); } public void Show() { _isVisible = true; _showTimer = 0f; EnsureOnScreen(); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[BirthdayHUD] Show() called - isVisible: {_isVisible}, pos: ({((Rect)(ref _windowRect)).x}, {((Rect)(ref _windowRect)).y}), screen: ({Screen.width}x{Screen.height}), birthdays: {(_manager?.TodaysBirthdays?.Count).GetValueOrDefault()}"); } } private void EnsureOnScreen() { if (Screen.width <= 0 || Screen.height <= 0) { return; } if (((Rect)(ref _windowRect)).x < 0f || ((Rect)(ref _windowRect)).y < 0f || ((Rect)(ref _windowRect)).x > (float)(Screen.width - 50) || ((Rect)(ref _windowRect)).y > (float)(Screen.height - 50)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"[BirthdayHUD] Resetting position - was ({((Rect)(ref _windowRect)).x}, {((Rect)(ref _windowRect)).y})"); } ((Rect)(ref _windowRect)).x = (float)Screen.width - WindowWidth - Scaled(20f); ((Rect)(ref _windowRect)).y = Scaled(80f); } ((Rect)(ref _windowRect)).x = Mathf.Clamp(((Rect)(ref _windowRect)).x, 0f, (float)Screen.width - ((Rect)(ref _windowRect)).width); ((Rect)(ref _windowRect)).y = Mathf.Clamp(((Rect)(ref _windowRect)).y, 0f, (float)Screen.height - ((Rect)(ref _windowRect)).height); } public void Hide() { _isVisible = false; } public void Toggle() { if (_isVisible) { Hide(); } else { Show(); } } private void OnBirthdaysUpdated() { if (_manager != null && _manager.HasBirthdays) { Show(); } else { Hide(); } } private void Update() { _manager?.CheckForDateChange(Time.unscaledDeltaTime); if (!_isVisible) { return; } _manager?.UpdateStatusMessage(Time.unscaledDeltaTime); if (_manager != null && !_manager.HasUngiftedBirthdays) { _showTimer += Time.unscaledDeltaTime; if (_showTimer >= 15f) { Hide(); } } else { _showTimer = 0f; } } private void OnGUI() { //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00db: 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_00fc: Expected O, but got Unknown //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Expected O, but got Unknown //IL_01b5: 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) if (_isVisible && !GameModalUiGuard.ShouldSuppressBirthdayImGui()) { if (!_stylesInitialized) { InitializeStyles(); } int num = ((_manager != null && _manager.TodaysBirthdays != null) ? _manager.TodaysBirthdays.Count : 0); float num2 = HeaderHeight + Scaled(12f); num2 = ((num != 0) ? (num2 + (float)num * ItemHeight) : (num2 + Scaled(40f))); num2 += Scaled(16f); ((Rect)(ref _windowRect)).width = WindowWidth; ((Rect)(ref _windowRect)).height = Mathf.Clamp(num2, MinHeight, MaxHeight); Rect windowRect = _windowRect; DrawShadow(_windowRect, 4); GUI.depth = -800; _windowRect = GUI.Window(98770, _windowRect, new WindowFunction(DrawWindow), "", _windowStyle); ((Rect)(ref _windowRect)).x = Mathf.Clamp(((Rect)(ref _windowRect)).x, 0f, (float)Screen.width - ((Rect)(ref _windowRect)).width); ((Rect)(ref _windowRect)).y = Mathf.Clamp(((Rect)(ref _windowRect)).y, 0f, (float)Screen.height - ((Rect)(ref _windowRect)).height); if (_showGiftPopup && _selectedNPC != null) { DrawShadow(_giftPopupRect, 4); GUI.depth = -900; _giftPopupRect = GUI.Window(98771, _giftPopupRect, new WindowFunction(DrawGiftPopup), "", _windowStyle); ((Rect)(ref _giftPopupRect)).x = Mathf.Clamp(((Rect)(ref _giftPopupRect)).x, 0f, (float)Screen.width - ((Rect)(ref _giftPopupRect)).width); ((Rect)(ref _giftPopupRect)).y = Mathf.Clamp(((Rect)(ref _giftPopupRect)).y, 0f, (float)Screen.height - ((Rect)(ref _giftPopupRect)).height); } if (Math.Abs(((Rect)(ref _windowRect)).x - ((Rect)(ref windowRect)).x) > 0.1f || Math.Abs(((Rect)(ref _windowRect)).y - ((Rect)(ref windowRect)).y) > 0.1f) { OnPositionChanged?.Invoke(((Rect)(ref _windowRect)).x, ((Rect)(ref _windowRect)).y); } } } private void DrawShadow(Rect rect, int offset) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) Color color = default(Color); ((Color)(ref color))..ctor(0f, 0f, 0f, 0.3f); Rect val = new Rect(((Rect)(ref rect)).x + (float)offset, ((Rect)(ref rect)).y + (float)offset, ((Rect)(ref rect)).width, ((Rect)(ref rect)).height); GUI.color = color; GUI.DrawTexture(val, (Texture)(object)Texture2D.whiteTexture); GUI.color = Color.white; } private void DrawWindow(int windowId) { //IL_00f1: Unknown result type (might be due to invalid IL or missing references) DrawBorder(((Rect)(ref _windowRect)).width, ((Rect)(ref _windowRect)).height, Mathf.Max(1, ScaledInt(2f))); GUILayout.BeginVertical(Array.Empty<GUILayoutOption>()); int num = ((_manager != null && _manager.TodaysBirthdays != null) ? _manager.TodaysBirthdays.Count : 0); string text = _manager?.CurrentDateFormatted ?? ""; string text2 = ((num <= 1) ? ModLocalization.T("birthday.hud.title.one") : ModLocalization.T("birthday.hud.title.many")); string title = (string.IsNullOrEmpty(text) ? text2 : (text2 + " - " + text)); DrawHeader(title, ((Rect)(ref _windowRect)).width); DrawBirthdays(); GUILayout.EndVertical(); GUI.DragWindow(new Rect(0f, 0f, ((Rect)(ref _windowRect)).width - Scaled(24f), HeaderHeight)); } private void DrawBorder(float width, float height, int borderSize) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) GUI.color = _borderColor; GUI.DrawTexture(new Rect(0f, 0f, width, (float)borderSize), (Texture)(object)Texture2D.whiteTexture); GUI.DrawTexture(new Rect(0f, height - (float)borderSize, width, (float)borderSize), (Texture)(object)Texture2D.whiteTexture); GUI.DrawTexture(new Rect(0f, 0f, (float)borderSize, height), (Texture)(object)Texture2D.whiteTexture); GUI.DrawTexture(new Rect(width - (float)borderSize, 0f, (float)borderSize, height), (Texture)(object)Texture2D.whiteTexture); GUI.color = Color.white; } private void DrawHeader(string title, float width) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) Rect val = default(Rect); ((Rect)(ref val))..ctor(0f, 0f, width, HeaderHeight); if ((Object)(object)_headerBackground != (Object)null) { GUI.DrawTexture(val, (Texture)(object)_headerBackground); } GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Space(Scaled(10f)); GUILayout.Label("[*]", _headerStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(Scaled(24f)), GUILayout.Height(HeaderHeight) }); GUILayout.Label(title, _headerStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(HeaderHeight) }); GUILayout.FlexibleSpace(); if (GUILayout.Button("X", _closeButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(Scaled(24f)), GUILayout.Height(Scaled(24f)) })) { Hide(); } GUILayout.Space(Scaled(6f)); GUILayout.EndHorizontal(); } private void DrawBirthdays() { GUILayout.Space(Scaled(6f)); if (_manager != null && _manager.HasStatusMessage) { GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.FlexibleSpace(); GUILayout.Label(_manager.StatusMessage, _statusMessageStyle, Array.Empty<GUILayoutOption>()); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.Space(Scaled(4f)); } if (_manager == null || _manager.TodaysBirthdays == null || _manager.TodaysBirthdays.Count == 0) { GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.FlexibleSpace(); GUILayout.Label(ModLocalization.T("birthday.hud.noBirthdays"), _hintStyle, Array.Empty<GUILayoutOption>()); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); } else { foreach (BirthdayDisplayInfo todaysBirthday in _manager.TodaysBirthdays) { DrawBirthdayItem(todaysBirthday); } } GUILayout.Space(Scaled(6f)); } private void DrawBirthdayItem(BirthdayDisplayInfo birthday) { GUILayout.BeginVertical(_itemBoxStyle, Array.Empty<GUILayoutOption>()); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUIStyle val = (birthday.HasBeenGifted ? _statusGiftedStyle : _statusUngiftedStyle); GUILayout.Label(birthday.HasBeenGifted ? "[OK]" : "[!!]", val, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(Scaled(40f)) }); GUILayout.BeginVertical(Array.Empty<GUILayoutOption>()); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUIStyle val2 = (birthday.HasBeenGifted ? _nameGiftedStyle : _nameUngiftedStyle); GUILayout.Label(birthday.NPCName, val2, Array.Empty<GUILayoutOption>()); GUILayout.FlexibleSpace(); if ((birthday.AllLovedGifts.Count > 0 || birthday.AllLikedGifts.Count > 0) && GUILayout.Button(ModLocalization.T("birthday.hud.gifts"), _moreButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(Scaled(50f)), GUILayout.Height(Scaled(20f)) })) { OpenGiftPopup(birthday); } GUILayout.EndHorizontal(); if (!birthday.HasBeenGifted && !string.IsNullOrEmpty(birthday.GiftHint)) { GUILayout.Space(Scaled(2f)); GUILayout.Label(birthday.GiftHint, _hintStyle, Array.Empty<GUILayoutOption>()); } GUILayout.EndVertical(); GUILayout.EndHorizontal(); GUILayout.EndVertical(); } private void OpenGiftPopup(BirthdayDisplayInfo birthday) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) _selectedNPC = birthday; _showGiftPopup = true; _giftScrollPosition = Vector2.zero; _giftPopupRect = new Rect(((Rect)(ref _windowRect)).x + ((Rect)(ref _windowRect)).width + Scaled(10f), ((Rect)(ref _windowRect)).y, GiftWindowWidth, GiftWindowHeight); if (((Rect)(ref _giftPopupRect)).x + GiftWindowWidth > (float)Screen.width) { ((Rect)(ref _giftPopupRect)).x = ((Rect)(ref _windowRect)).x - GiftWindowWidth - Scaled(10f); } } private void DrawGiftPopup(int windowId) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0149: 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_0174: 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_0274: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_02ae: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_037d: Unknown result type (might be due to invalid IL or missing references) //IL_02fa: Unknown result type (might be due to invalid IL or missing references) //IL_031e: Unknown result type (might be due to invalid IL or missing references) DrawBorder(GiftWindowWidth, GiftWindowHeight, ScaledInt(2f)); GUILayout.BeginVertical(Array.Empty<GUILayoutOption>()); Rect val = default(Rect); ((Rect)(ref val))..ctor(0f, 0f, GiftWindowWidth, HeaderHeight); if ((Object)(object)_headerBackground != (Object)null) { GUI.DrawTexture(val, (Texture)(object)_headerBackground); } GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Space(Scaled(10f)); GUILayout.Label(ModLocalization.T("birthday.gift.title", _selectedNPC.NPCName), _headerStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(HeaderHeight) }); GUILayout.FlexibleSpace(); if (GUILayout.Button("X", _closeButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(Scaled(24f)), GUILayout.Height(Scaled(24f)) })) { _showGiftPopup = false; _selectedNPC = null; } GUILayout.Space(Scaled(6f)); GUILayout.EndHorizontal(); _giftScrollPosition = GUILayout.BeginScrollView(_giftScrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(GiftWindowHeight - HeaderHeight - Scaled(10f)) }); GUILayout.Space(Scaled(6f)); DrawSectionHeader(ModLocalization.T("birthday.gift.loved").ToUpperInvariant(), _lovedColor); GUILayout.Space(Scaled(4f)); foreach (string allLovedGift in _selectedNPC.AllLovedGifts) { DrawGiftItem(allLovedGift, _lovedColor); } if (BirthdayCache.UniversalLoved.Count > 0) { GUILayout.Space(Scaled(4f)); DrawSubHeader(ModLocalization.T("birthday.gift.universalLoved"), _universalColor); foreach (string item in BirthdayCache.UniversalLoved) { DrawGiftItem(item, _universalColor); } } GUILayout.Space(Scaled(8f)); DrawSeparator(); GUILayout.Space(Scaled(8f)); DrawSectionHeader(ModLocalization.T("birthday.gift.liked").ToUpperInvariant(), _likedColor); GUILayout.Space(Scaled(4f)); foreach (string allLikedGift in _selectedNPC.AllLikedGifts) { DrawGiftItem(allLikedGift, _likedColor); } if (BirthdayCache.UniversalLiked.Count > 0) { GUILayout.Space(Scaled(4f)); DrawSubHeader(ModLocalization.T("birthday.gift.universalLiked"), _universalColor); foreach (string item2 in BirthdayCache.UniversalLiked) { DrawGiftItem(item2, _universalColor); } } GUILayout.Space(Scaled(10f)); GUILayout.EndScrollView(); GUILayout.EndVertical(); GUI.DragWindow(new Rect(0f, 0f, GiftWindowWidth - Scaled(24f), HeaderHeight)); } private void DrawSectionHeader(string text, Color color) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001c: 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_0033: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Space(Scaled(8f)); GUIStyle val = ((color == _lovedColor) ? _lovedSectionStyle : ((!(color == _likedColor)) ? _sectionHeaderStyle : _likedSectionStyle)); GUILayout.Label(text, val, Array.Empty<GUILayoutOption>()); GUILayout.EndHorizontal(); } private void DrawSubHeader(string text, Color color) { GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Space(Scaled(12f)); GUILayout.Label(text, _universalSubHeaderStyle, Array.Empty<GUILayoutOption>()); GUILayout.EndHorizontal(); } private void DrawGiftItem(string gift, Color bulletColor) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001c: 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_0033: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Space(Scaled(16f)); GUIStyle val = ((bulletColor == _lovedColor) ? _lovedBulletStyle : ((!(bulletColor == _likedColor)) ? _universalBulletStyle : _likedBulletStyle)); GUILayout.Label("•", val, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(Scaled(12f)) }); GUILayout.Label(gift, _giftItemStyle, Array.Empty<GUILayoutOption>()); GUILayout.EndHorizontal(); } private void DrawSeparator() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_008c: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Space(Scaled(20f)); float num = GiftWindowWidth - Scaled(40f); Rect rect = GUILayoutUtility.GetRect(num, 1f); GUI.color = new Color(_borderColor.r, _borderColor.g, _borderColor.b, 0.4f); GUI.DrawTexture(new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).y, num, 1f), (Texture)(object)Texture2D.whiteTexture); GUI.color = Color.white; GUILayout.EndHorizontal(); } private void InitializeStyles() { if (_stylesInitialized) { return; } try { CreateTextures(); CreateStyles(); _stylesInitialized = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"[BirthdayHUD] Styles initialized successfully"); } } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogError((object)("[BirthdayHUD] Failed to in