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 Hunger Pangs v1.0.2
plugins/HungerPangs.dll
Decompiled 3 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("HungerPangs")] [assembly: AssemblyDescription("Valheim HungerPangs Mod by DrummerCraig")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("HungerPangs")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("ea00b146-e2c4-41cd-8e70-7bbada299b8e")] [assembly: AssemblyFileVersion("1.0.2.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.2.0")] namespace DrummerCraig.HungerPangs; [BepInPlugin("drummercraig.hungerpangs", "Hunger Pangs", "1.0.2")] public class HungerPangs : BaseUnityPlugin { [CompilerGenerated] private sealed class <FoodCheckLoop>d__13 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public HungerPangs <>4__this; private WaitForSeconds <wait>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <FoodCheckLoop>d__13(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <wait>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown int num = <>1__state; HungerPangs hungerPangs = <>4__this; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; hungerPangs.CheckFoods(); } else { <>1__state = -1; <wait>5__2 = new WaitForSeconds(1f); } <>2__current = <wait>5__2; <>1__state = 1; return true; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private ConfigEntry<bool> modStatus; private ConfigEntry<bool> autoEat; private ConfigEntry<bool> foodExpiryNotify; private ConfigEntry<int> autoEatPercent; private ConfigEntry<int> foodExpiryPercent; private ConfigEntry<bool> autoEatNotify; private ConfigEntry<bool> lowSupplyNotify; private ConfigEntry<int> lowSupplyCount; private readonly HashSet<string> hasShown = new HashSet<string>(); private readonly HashSet<string> seenThisTick = new HashSet<string>(); private readonly HashSet<string> lowSupplyShown = new HashSet<string>(); private Predicate<string> _notSeenThisTick; private void Awake() { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Expected O, but got Unknown modStatus = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "1. Mod Status", true, "Master toggle for the entire mod. When disabled, no auto-eating or notifications occur."); autoEat = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "2. Auto-Eat", true, "Automatically re-eat food before it expires. When disabled, the mod will only show notifications if NotificationsEnabled is on, allowing you to eat manually on cue."); autoEatPercent = ((BaseUnityPlugin)this).Config.Bind<int>("General", "3. Auto-Eat Percent", 5, new ConfigDescription("Percentage of a food's total duration remaining when it is automatically re-eaten. Food becomes eligible to re-eat at 50% remaining (when it starts blinking), so this is your window. Lower values eat later and waste less food; higher values re-eat sooner after becoming eligible. Example: 5 = eat when 5% remains (e.g. ~1.5 min of a 30-min food). Requires Auto-Eat Enabled.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 49), Array.Empty<object>())); autoEatNotify = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "4. Auto-Eat Notify", true, "Show a HUD notification when a food item is automatically eaten. Requires AutomaticallyEat."); foodExpiryNotify = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "5. Food Expiry Notify", true, "Show a HUD notification when a food item nears its expiry threshold. Useful on its own when Auto-Eat is Disabled,as a manual reminder to eat."); foodExpiryPercent = ((BaseUnityPlugin)this).Config.Bind<int>("General", "6. Food Expiry Percent", 30, new ConfigDescription("Percentage of a food's total duration remaining when the HUD notification appears. Food becomes eligible to re-eat at 50% remaining (when it starts blinking). Set this higher than Auto-Eat Percent so the notification fires before auto-eat. Example: 30 = notify when 30% remains (e.g. ~9 min of a 30-min food). Requires Notifications.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 50), Array.Empty<object>())); lowSupplyNotify = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "7. Low Supply Notify", true, "Show a HUD notification when AutomaticallyEat is enabled, a food item is consumed and the remaining count in your inventory is at or below the LowSupplyThreshold."); lowSupplyCount = ((BaseUnityPlugin)this).Config.Bind<int>("General", "8. Low Supply Count", 1, "The number of food items in your inventory for the LowSupplyNotification to appear."); _notSeenThisTick = (string key) => !seenThisTick.Contains(key); ((MonoBehaviour)this).StartCoroutine(FoodCheckLoop()); } [IteratorStateMachine(typeof(<FoodCheckLoop>d__13))] private IEnumerator FoodCheckLoop() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <FoodCheckLoop>d__13(0) { <>4__this = this }; } private void CheckFoods() { if (!modStatus.Value) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } Humanoid val = (Humanoid)(object)localPlayer; Inventory inventory = val.GetInventory(); List<Food> foods = localPlayer.GetFoods(); seenThisTick.Clear(); for (int i = 0; i < foods.Count; i++) { Food val2 = foods[i]; string name = val2.m_item.m_shared.m_name; seenThisTick.Add(name); float time = val2.m_time; float foodBurnTime = val2.m_item.m_shared.m_foodBurnTime; float num = ((foodBurnTime > 0f) ? (time / foodBurnTime * 100f) : 0f); if (!val2.CanEatAgain()) { hasShown.Remove(name); lowSupplyShown.Remove(name); continue; } if (foodExpiryNotify.Value && !hasShown.Contains(name) && num <= (float)foodExpiryPercent.Value) { string arg = Localization.instance.Localize(val2.m_item.m_shared.m_name); int num2 = Mathf.CeilToInt(time / 60f); MessageHud instance = MessageHud.instance; if (instance != null) { instance.ShowMessage((MessageType)2, $"{arg} expires in {num2} min", 0, (Sprite)null, false); } hasShown.Add(name); } if (!autoEat.Value || !(num <= (float)autoEatPercent.Value)) { continue; } ItemData item = inventory.GetItem(name, -1, false); if (item == null || !val.ConsumeItem(inventory, item, false)) { continue; } hasShown.Remove(name); if (autoEatNotify.Value) { string text = Localization.instance.Localize(val2.m_item.m_shared.m_name); MessageHud instance2 = MessageHud.instance; if (instance2 != null) { instance2.ShowMessage((MessageType)2, text + " automatically re-eaten", 0, (Sprite)null, false); } } if (!lowSupplyNotify.Value || lowSupplyCount.Value <= 0 || lowSupplyShown.Contains(name)) { continue; } int num3 = inventory.CountItems(name, -1, true); if (num3 <= lowSupplyCount.Value) { string arg2 = Localization.instance.Localize(val2.m_item.m_shared.m_name); MessageHud instance3 = MessageHud.instance; if (instance3 != null) { instance3.ShowMessage((MessageType)2, $"Low supply: {num3} {arg2} remaining", 0, (Sprite)null, false); } lowSupplyShown.Add(name); } } hasShown.RemoveWhere(_notSeenThisTick); lowSupplyShown.RemoveWhere(_notSeenThisTick); } }