Please disclose if your mod was created primarily using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of NagMessages v1.0.1
NagMessages.dll
Decompiled 2 years agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("NagMessages")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Riintouge")] [assembly: AssemblyProduct("NagMessages")] [assembly: AssemblyCopyright("Copyright © 2023")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("7f021c97-1954-4a61-83ad-7bb4be2e18ef")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.1.0")] namespace NagMessages; [BepInPlugin("com.riintouge.nagmessages", "Nag Messages", "1.0.1")] [BepInProcess("valheim.exe")] public class NagMessages : BaseUnityPlugin { private class NagArgs { public double delay; public bool force; public Coroutine self; } [HarmonyPatch(typeof(MessageHud))] private class MessageHudPatch { internal const double MessageTTL = 4.0; private static string CurrentMessage = null; private static double MinimumTimeOfNextMessage = 0.0; private static readonly LinkedList<string> PendingMessages = new LinkedList<string>(); [HarmonyPatch("ShowMessage")] [HarmonyPrefix] private static bool ShowMessagePrefix(ref MessageType type, ref string text) { if ((int)type != 2) { return true; } if (Utility.IsNullOrWhiteSpace(text)) { if (PendingMessages.Count > 0) { text = PendingMessages.First(); PendingMessages.RemoveFirst(); } CurrentMessage = text; return true; } double timeAsDouble = Time.timeAsDouble; if (!IsEnabled.Value || !QueueCenterMessages.Value || timeAsDouble >= MinimumTimeOfNextMessage) { MinimumTimeOfNextMessage = timeAsDouble + 4.0; CurrentMessage = text; return true; } if (text.CompareTo(CurrentMessage) == 0) { return false; } if (!PendingMessages.Contains(text)) { PendingMessages.AddLast(text); ((MonoBehaviour)Instance).StartCoroutine("ShowNextMessage", (object)(float)(MinimumTimeOfNextMessage - timeAsDouble)); MinimumTimeOfNextMessage += 4.0; } return false; } } [HarmonyPatch(typeof(Game))] private class GamePatch { private static bool FirstSpawnPending; [HarmonyPatch("FixedUpdate")] [HarmonyPrefix] private static void FixedUpdatePrefix(ref bool ___m_firstSpawn) { if (___m_firstSpawn) { FirstSpawnPending = true; } } [HarmonyPatch("UpdateRespawn")] [HarmonyPostfix] private static void UpdateRespawnPostfix() { if (FirstSpawnPending && Object.op_Implicit((Object)(object)Player.m_localPlayer)) { FirstSpawnPending = false; Instance.NagAboutPower(8.0, force: true); Instance.NagAboutHunger(12.0, force: true); } } } [HarmonyPatch(typeof(Player))] private class PlayerPatch { [HarmonyPatch("ActivateGuardianPower")] [HarmonyPrefix] private static void ActivateGuardianPowerPrefix(ref Player __instance, out float __state) { __state = __instance.m_guardianPowerCooldown; } [HarmonyPatch("ActivateGuardianPower")] [HarmonyPostfix] private static void ActivateGuardianPowerPostfix(ref Player __instance, ref StatusEffect ___m_guardianSE, ref float __state) { if (__instance.m_guardianPowerCooldown != __state && Object.op_Implicit((Object)(object)___m_guardianSE)) { StatusEffect statusEffect = ((Character)__instance).GetSEMan().GetStatusEffect(___m_guardianSE.NameHash()); if (Object.op_Implicit((Object)(object)statusEffect)) { Instance.NagAboutPower(statusEffect.GetRemaningTime(), force: true); } } } [HarmonyPatch("SetGuardianPower")] [HarmonyPostfix] private static void SetGuardianPowerPostfix() { Instance.NagAboutPower(); } [HarmonyPatch("SetMaxEitr")] [HarmonyPrefix] private static void SetMaxEitrPrefix(ref Player __instance, float eitr) { float maxEitr = ((Character)__instance).GetMaxEitr(); if (IsEnabled.Value && eitr < maxEitr && eitr <= (float)EitrThreshold.Value && maxEitr > (float)EitrThreshold.Value) { ((Character)__instance).Message((MessageType)2, "Your maximum eitr is getting too low!", 0, (Sprite)null); } } [HarmonyPatch("SetMaxHealth")] [HarmonyPrefix] private static void SetMaxHealthPrefix(ref Player __instance, float health) { float maxHealth = ((Character)__instance).GetMaxHealth(); if (IsEnabled.Value && health < maxHealth && health <= (float)HealthThreshold.Value && maxHealth > (float)HealthThreshold.Value) { ((Character)__instance).Message((MessageType)2, "Your maximum health is getting too low!", 0, (Sprite)null); } } [HarmonyPatch("SetMaxStamina")] [HarmonyPrefix] private static void SetMaxStaminaPrefix(ref Player __instance, float stamina) { float maxStamina = ((Character)__instance).GetMaxStamina(); if (IsEnabled.Value && stamina < maxStamina && stamina <= (float)StaminaThreshold.Value && maxStamina > (float)StaminaThreshold.Value) { ((Character)__instance).Message((MessageType)2, "Your maximum stamina is getting too low!", 0, (Sprite)null); } } [HarmonyPatch("UpdateFood")] [HarmonyPrefix] private static void UpdateFoodPrefix(ref List<Food> ___m_foods, out int __state) { __state = ___m_foods.Count; } [HarmonyPatch("UpdateFood")] [HarmonyPostfix] private static void UpdateFoodPostfix(ref List<Food> ___m_foods, ref int __state) { if (___m_foods.Count == 0 && __state > 0) { Instance.NagAboutHunger(); } } } private readonly int BonemassPowerNameHash = "GP_Bonemass".GetHashCode(); private readonly int EikthyrPowerNameHash = "GP_Eikthyr".GetHashCode(); private readonly int ModerPowerNameHash = "GP_Moder".GetHashCode(); private readonly int TheElderPowerNameHash = "GP_TheElder".GetHashCode(); private readonly int TheQueenPowerNameHash = "GP_Queen".GetHashCode(); private readonly int YagluthPowerNameHash = "GP_Yagluth".GetHashCode(); private static List<Coroutine> PowerNagCoroutines = new List<Coroutine>(); internal static double MinTimeOfNextPowerNag = 0.0; private static List<Coroutine> HungerNagCoroutines = new List<Coroutine>(); internal static double MinTimeOfNextHungerNag = 0.0; public static NagMessages Instance = null; public static ConfigEntry<bool> IsEnabled; public static ConfigEntry<bool> LoadOnStart; public static ConfigEntry<bool> QueueCenterMessages; public static ConfigEntry<bool> AllowBonemass; public static ConfigEntry<bool> AllowEikthyr; public static ConfigEntry<bool> AllowModer; public static ConfigEntry<bool> AllowTheElder; public static ConfigEntry<bool> AllowTheQueen; public static ConfigEntry<bool> AllowYagluth; public static ConfigEntry<int> PowerNagFrequency; private static int LastPowerNagFrequency; public static ConfigEntry<int> EitrThreshold; public static ConfigEntry<int> HealthThreshold; public static ConfigEntry<int> HungerNagFrequency; private static int LastHungerNagFrequency; public static ConfigEntry<int> StaminaThreshold; private readonly Harmony Harmony = new Harmony("com.riintouge.nagmessages"); public void NagAboutPower() { NagAboutPower((float)PowerNagFrequency.Value * 60f, force: false); } public void NagAboutPower(double delay, bool force) { NagArgs nagArgs = new NagArgs { delay = delay, force = force }; Coroutine item = (nagArgs.self = ((MonoBehaviour)Instance).StartCoroutine(CoNagAboutPower(nagArgs))); PowerNagCoroutines.Add(item); } private IEnumerator CoNagAboutPower(NagArgs args) { yield return (object)new WaitForSecondsRealtime(1f); if (args.delay > 1.0) { yield return (object)new WaitForSecondsRealtime((float)args.delay); } Instance.NagAboutPower(args); } private void NagAboutPower(NagArgs args) { Player localPlayer = Player.m_localPlayer; if (!IsEnabled.Value || !Object.op_Implicit((Object)(object)localPlayer)) { return; } double timeAsDouble = Time.timeAsDouble; if (!args.force && timeAsDouble < MinTimeOfNextPowerNag) { ((MonoBehaviour)Instance).StopCoroutine(args.self); PowerNagCoroutines.Remove(args.self); if (PowerNagCoroutines.Count == 0) { NagAboutPower(MinTimeOfNextPowerNag - timeAsDouble, force: false); } return; } int hashCode = localPlayer.GetGuardianPowerName().GetHashCode(); if ((AllowBonemass.Value || hashCode != BonemassPowerNameHash) && (AllowEikthyr.Value || hashCode != EikthyrPowerNameHash) && (AllowModer.Value || hashCode != ModerPowerNameHash) && (AllowTheElder.Value || hashCode != TheElderPowerNameHash) && (AllowTheQueen.Value || hashCode != TheQueenPowerNameHash) && (AllowYagluth.Value || hashCode != YagluthPowerNameHash)) { return; } ((Character)localPlayer).Message((MessageType)2, "Change your forsaken power!", 0, (Sprite)null); MinTimeOfNextPowerNag = timeAsDouble + (double)((float)PowerNagFrequency.Value * 60f); foreach (Coroutine powerNagCoroutine in PowerNagCoroutines) { ((MonoBehaviour)Instance).StopCoroutine(powerNagCoroutine); } PowerNagCoroutines.Clear(); NagAboutPower(); } public void NagAboutHunger() { NagAboutHunger((float)HungerNagFrequency.Value * 60f, force: false); } public void NagAboutHunger(double delay, bool force) { NagArgs nagArgs = new NagArgs { delay = delay, force = force }; Coroutine item = (nagArgs.self = ((MonoBehaviour)Instance).StartCoroutine(CoNagAboutHunger(nagArgs))); HungerNagCoroutines.Add(item); } private IEnumerator CoNagAboutHunger(NagArgs args) { yield return (object)new WaitForSecondsRealtime(1f); if (args.delay > 1.0) { yield return (object)new WaitForSecondsRealtime((float)args.delay); } Instance.NagAboutHunger(args); } private void NagAboutHunger(NagArgs args) { Player localPlayer = Player.m_localPlayer; if (!IsEnabled.Value || !Object.op_Implicit((Object)(object)localPlayer)) { return; } double timeAsDouble = Time.timeAsDouble; if (!args.force && timeAsDouble < MinTimeOfNextHungerNag) { ((MonoBehaviour)Instance).StopCoroutine(args.self); HungerNagCoroutines.Remove(args.self); if (HungerNagCoroutines.Count == 0) { NagAboutHunger(MinTimeOfNextHungerNag - timeAsDouble, force: false); } } else { if (localPlayer.GetFoods().Count != 0) { return; } ((Character)localPlayer).Message((MessageType)2, "Your stomach is growling", 0, (Sprite)null); MinTimeOfNextHungerNag = timeAsDouble + (double)((float)HungerNagFrequency.Value * 60f); foreach (Coroutine hungerNagCoroutine in HungerNagCoroutines) { ((MonoBehaviour)Instance).StopCoroutine(hungerNagCoroutine); } HungerNagCoroutines.Clear(); NagAboutHunger(); } } public IEnumerator ShowNextMessage(float seconds) { yield return (object)new WaitForSecondsRealtime(seconds); if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && Object.op_Implicit((Object)(object)MessageHud.instance)) { MessageHud.instance.ShowMessage((MessageType)2, (string)null, 0, (Sprite)null); } } private void Awake() { IsEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("0 - Core", "Enable", true, "Whether this plugin has any effect when loaded."); LoadOnStart = ((BaseUnityPlugin)this).Config.Bind<bool>("0 - Core", "LoadOnStart", true, "Whether this plugin loads on game start."); QueueCenterMessages = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "QueueCenterMessages", true, "Whether front-and-center messages will be queued for display. Provided for compatibility."); AllowBonemass = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Forsaken Powers", "AllowBonemass", true, "If false, periodically nag the player to switch powers."); AllowEikthyr = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Forsaken Powers", "AllowEikthyr", true, "If false, periodically nag the player to switch powers."); AllowModer = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Forsaken Powers", "AllowModer", true, "If false, periodically nag the player to switch powers."); AllowTheElder = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Forsaken Powers", "AllowTheElder", true, "If false, periodically nag the player to switch powers."); AllowTheQueen = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Forsaken Powers", "AllowTheQueen", true, "If false, periodically nag the player to switch powers."); AllowYagluth = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Forsaken Powers", "AllowYagluth", true, "If false, periodically nag the player to switch powers."); PowerNagFrequency = ((BaseUnityPlugin)this).Config.Bind<int>("2 - Forsaken Powers", "PowerNagFrequency", 3, "Minimum time in minutes between forsaken power nag messages."); EitrThreshold = ((BaseUnityPlugin)this).Config.Bind<int>("3 - Food Effects", "EitrThreshold", 35, "Warn the player when their maximum eitr drops to or below this amount."); HealthThreshold = ((BaseUnityPlugin)this).Config.Bind<int>("3 - Food Effects", "HealthThreshold", 0, "Warn the player when their maximum health drops to or below this amount."); HungerNagFrequency = ((BaseUnityPlugin)this).Config.Bind<int>("3 - Food Effects", "HungerNagFrequency", 3, "Minimum time in minutes between hunger nag messages."); StaminaThreshold = ((BaseUnityPlugin)this).Config.Bind<int>("3 - Food Effects", "StaminaThreshold", 0, "Warn the player when their maximum stamina drops to or below this amount."); if (LoadOnStart.Value) { Instance = this; Harmony.PatchAll(); LastHungerNagFrequency = HungerNagFrequency.Value; ((BaseUnityPlugin)this).Config.SettingChanged += Config_SettingChanged; } } private void Config_SettingChanged(object sender, SettingChangedEventArgs e) { if (e.ChangedSetting == AllowBonemass || e.ChangedSetting == AllowEikthyr || e.ChangedSetting == AllowModer || e.ChangedSetting == AllowTheElder || e.ChangedSetting == AllowTheQueen || e.ChangedSetting == AllowYagluth) { if (!(bool)e.ChangedSetting.BoxedValue) { NagAboutPower(); } } else if (e.ChangedSetting == PowerNagFrequency) { int num = PowerNagFrequency.Value - LastPowerNagFrequency; double num2 = (double)num * 60.0; if (num > 0) { MinTimeOfNextPowerNag += num2; } else if (num < 0) { double timeAsDouble = Time.timeAsDouble; num2 = Math.Abs(num2); if (MinTimeOfNextPowerNag - num2 < timeAsDouble) { MinTimeOfNextPowerNag = timeAsDouble + (double)PowerNagFrequency.Value * 60.0; } else { MinTimeOfNextPowerNag -= num2; } NagAboutPower(); } LastPowerNagFrequency = PowerNagFrequency.Value; } else { if (e.ChangedSetting != HungerNagFrequency) { return; } int num3 = HungerNagFrequency.Value - LastHungerNagFrequency; double num4 = (double)num3 * 60.0; if (num3 > 0) { MinTimeOfNextHungerNag += num4; } else if (num3 < 0) { double timeAsDouble2 = Time.timeAsDouble; num4 = Math.Abs(num4); if (MinTimeOfNextHungerNag - num4 < timeAsDouble2) { MinTimeOfNextHungerNag = timeAsDouble2 + (double)HungerNagFrequency.Value * 60.0; } else { MinTimeOfNextHungerNag -= num4; } NagAboutHunger(); } LastHungerNagFrequency = HungerNagFrequency.Value; } } }