using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("HungryViking")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+b8af4abbc73174f01d114297ef8542d09d49fb04")] [assembly: AssemblyProduct("HungryViking")] [assembly: AssemblyTitle("HungryViking")] [assembly: AssemblyVersion("1.0.0.0")] namespace HungryViking; public class FoodMonitor { private class SlotState { public bool WarningFired; } private readonly HungryVikingMod _mod; public static readonly FieldRef> FoodsRef = AccessTools.FieldRefAccess>("m_foods"); private readonly Dictionary _states = new Dictionary(); private readonly HashSet _prevNames = new HashSet(); private int _prevFoodCount = -1; public int CurrentFoodCount { get; private set; } public float WorstSlotUrgency { get; private set; } public event Action OnWarning; public event Action OnStarving; public FoodMonitor(HungryVikingMod mod) { _mod = mod; } public static void ClearFoods(Player player) { FoodsRef.Invoke(player).Clear(); } public static string DrainFood(Player player, int zeroBasedIdx, float seconds) { List list = FoodsRef.Invoke(player); if (zeroBasedIdx >= list.Count) { return $"Slot {zeroBasedIdx + 1} is empty."; } Food val = list[zeroBasedIdx]; val.m_time = Mathf.Max(0f, val.m_time - seconds); return string.Format("Slot {0} ({1}): {2:F0}s remaining.", zeroBasedIdx + 1, val.m_item?.m_shared?.m_name ?? "?", val.m_time); } public static string DrainAllFoods(Player player, float seconds) { List list = FoodsRef.Invoke(player); foreach (Food item in list) { item.m_time = Mathf.Max(0f, item.m_time - seconds); } return $"Drained {seconds}s from {list.Count} slot(s)."; } public static string SetFoodTime(Player player, int zeroBasedIdx, float seconds) { List list = FoodsRef.Invoke(player); if (zeroBasedIdx >= list.Count) { return $"Slot {zeroBasedIdx + 1} is empty."; } Food val = list[zeroBasedIdx]; val.m_time = Mathf.Max(0f, seconds); return string.Format("Slot {0} ({1}): set to {2:F0}s.", zeroBasedIdx + 1, val.m_item?.m_shared?.m_name ?? "?", val.m_time); } public static string GetFoodStatus(Player player) { List list = FoodsRef.Invoke(player); if (list.Count == 0) { return "No active food buffs."; } StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < list.Count; i++) { Food val = list[i]; stringBuilder.AppendLine(string.Format(" Slot {0}: {1} {2:F0}s remaining", i + 1, val.m_item?.m_shared?.m_name ?? "unknown", val.m_time)); } return stringBuilder.ToString().TrimEnd(Array.Empty()); } public void Tick(float dt) { List list = FoodsRef.Invoke(Player.m_localPlayer); if (CurrentFoodCount == 0 && list.Count > 0) { HungryVikingMod.Log.LogInfo((object)$"HungryViking: tracking {list.Count} food slot(s)"); } CurrentFoodCount = list.Count; HashSet hashSet = new HashSet(); foreach (Food item in list) { if (item?.m_item?.m_shared != null) { hashSet.Add(item.m_item.m_shared.m_name); } } foreach (string item2 in hashSet) { if (!_prevNames.Contains(item2)) { _states.Remove(item2); } } bool num = _prevFoodCount == -1; bool flag = CurrentFoodCount < _prevFoodCount; if ((num || flag) && CurrentFoodCount < 3) { this.OnStarving?.Invoke(); } float num2 = 0f; float value = _mod.HungerThreshold.Value; foreach (Food item3 in list) { if (item3?.m_item?.m_shared == null) { continue; } string name = item3.m_item.m_shared.m_name; if (!_states.TryGetValue(name, out var value2)) { value2 = new SlotState(); _states[name] = value2; } float time = item3.m_time; if (time < value) { num2 = Mathf.Max(num2, 1f - time / value); if (!value2.WarningFired) { value2.WarningFired = true; this.OnWarning?.Invoke(); } } else { value2.WarningFired = false; } } WorstSlotUrgency = num2; _prevFoodCount = CurrentFoodCount; _prevNames.Clear(); foreach (string item4 in hashSet) { _prevNames.Add(item4); } } } public class HungerStatusEffect : StatusEffect { public static HungerStatusEffect Create() { HungerStatusEffect hungerStatusEffect = ScriptableObject.CreateInstance(); ((StatusEffect)hungerStatusEffect).m_name = "Hungry"; ((StatusEffect)hungerStatusEffect).m_icon = LoadIcon(); ((StatusEffect)hungerStatusEffect).m_ttl = 0f; return hungerStatusEffect; } private static Sprite LoadIcon() { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) Assembly executingAssembly = Assembly.GetExecutingAssembly(); string text = Array.Find(executingAssembly.GetManifestResourceNames(), (string n) => n.EndsWith("status_icon.png")); if (text != null) { using Stream stream = executingAssembly.GetManifestResourceStream(text); byte[] array = new byte[stream.Length]; stream.Read(array, 0, array.Length); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); if (LoadImage(val, array)) { return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), (float)((Texture)val).width); } } HungryVikingMod.Log.LogWarning((object)"HungryViking: icon.png resource not found, using fallback icon."); return BuildFallbackIcon(); } private static bool LoadImage(Texture2D tex, byte[] bytes) { try { MethodInfo methodInfo = Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule")?.GetMethod("LoadImage", new Type[2] { typeof(Texture2D), typeof(byte[]) }); return methodInfo != null && (bool)methodInfo.Invoke(null, new object[2] { tex, bytes }); } catch { return false; } } private static Sprite BuildFallbackIcon() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false); float num = 32f; Color val2 = default(Color); ((Color)(ref val2))..ctor(1f, 0.65f, 0.1f, 1f); Color val3 = default(Color); ((Color)(ref val3))..ctor(0.35f, 0.15f, 0f, 0.9f); for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { float num2 = ((float)j + 0.5f - num) / (num * 0.88f); float num3 = ((float)i + 0.5f - num) / (num * 0.8f); if (num2 * num2 + num3 * num3 >= 1f) { val.SetPixel(j, i, Color.clear); continue; } float num4 = Mathf.Sin(num2 * (float)Math.PI * 2.5f) * 0.12f - 0.15f; float num5 = Mathf.Abs(num3 - num4); val.SetPixel(j, i, (num5 < 0.1f) ? val3 : val2); } } val.Apply(); return Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f), 64f); } } [BepInPlugin("DeathMonger.HungryViking", "Hungry Viking", "1.1.0")] [BepInProcess("valheim.exe")] public class HungryVikingMod : BaseUnityPlugin { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__37_0; public static ConsoleEvent <>9__37_1; public static ConsoleEvent <>9__37_2; public static ConsoleEvent <>9__37_3; public static ConsoleEvent <>9__37_4; public static ConsoleEvent <>9__37_5; internal void b__37_0(ConsoleEventArgs _) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { FoodMonitor.ClearFoods(localPlayer); Log.LogInfo((object)"hv_clearfood: all food buffs removed."); } } internal void b__37_1(ConsoleEventArgs args) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { if (args.Length < 2 || !TryParseSlot(args[1], out var zeroBasedIndex)) { Log.LogInfo((object)"Usage: hv_drainfood <1|2|3> [seconds]"); return; } float result; float seconds = ((args.Length >= 3 && float.TryParse(args[2], out result)) ? result : 60f); Log.LogInfo((object)FoodMonitor.DrainFood(localPlayer, zeroBasedIndex, seconds)); } } internal void b__37_2(ConsoleEventArgs args) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { float result; float seconds = ((args.Length >= 2 && float.TryParse(args[1], out result)) ? result : 60f); Log.LogInfo((object)FoodMonitor.DrainAllFoods(localPlayer, seconds)); } } internal void b__37_3(ConsoleEventArgs args) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { if (args.Length < 3 || !TryParseSlot(args[1], out var zeroBasedIndex) || !float.TryParse(args[2], out var result)) { Log.LogInfo((object)"Usage: hv_setfoodtime <1|2|3> "); } else { Log.LogInfo((object)FoodMonitor.SetFoodTime(localPlayer, zeroBasedIndex, result)); } } } internal void b__37_4(ConsoleEventArgs _) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { Log.LogInfo((object)FoodMonitor.GetFoodStatus(localPlayer)); } } internal void b__37_5(ConsoleEventArgs _) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } List statusEffects = ((Character)localPlayer).GetSEMan().GetStatusEffects(); if (statusEffects.Count == 0) { Log.LogInfo((object)"No active status effects."); return; } StringBuilder stringBuilder = new StringBuilder(); foreach (StatusEffect item in statusEffects) { stringBuilder.AppendLine($" \"{item.m_name}\" hash={item.NameHash()}"); } stringBuilder.AppendLine($" HaveStatusEffect(SmokedHash={-1612278721}) = {((Character)localPlayer).GetSEMan().HaveStatusEffect(-1612278721)}"); Log.LogInfo((object)stringBuilder.ToString().TrimEnd(Array.Empty())); } } public const string ModGuid = "DeathMonger.HungryViking"; private readonly Harmony harmony = new Harmony("DeathMonger.HungryViking"); public ConfigEntry Enabled; public ConfigEntry ShowStatusIcon; public ConfigEntry HungerThreshold; public ConfigEntry VignetteIntensity; public ConfigEntry VignetteExtent; public ConfigEntry SmokedVignetteIntensity; public ConfigEntry SmokedVignetteExtent; public ConfigEntry PoisonedVignetteIntensity; public ConfigEntry PoisonedVignetteExtent; private FoodMonitor _foodMonitor; private VignetteOverlay _vignette; private SmokedOverlay _smokedOverlay; private SmokedOverlay _poisonedOverlay; private HungerStatusEffect _statusEffect; private StatusEffect _activeStatusEffect; private Player _statusEffectPlayer; private const int SmokedHash = -1612278721; private const int PoisonedHash = 0; private bool _smokedTestActive; private bool _poisonedTestActive; private bool _hungerTestActive; private float _hungerPreviewTimer; private float _smokedPreviewTimer; private float _poisonedPreviewTimer; private Dictionary _migrationCache; public static HungryVikingMod Instance { get; private set; } public static ManualLogSource Log => ((BaseUnityPlugin)Instance).Logger; public string HungerMessage { get; private set; } = ""; private void Awake() { //IL_0064: Unknown result type (might be due to invalid IL or missing references) Instance = this; InitConfig(); harmony.PatchAll(); _vignette = ((Component)this).gameObject.AddComponent(); _smokedOverlay = ((Component)this).gameObject.AddComponent(); _poisonedOverlay = ((Component)this).gameObject.AddComponent(); _poisonedOverlay.SetLabelBaseColor(new Color(0.2f, 0.75f, 0.2f, 1f)); _foodMonitor = new FoodMonitor(this); _statusEffect = HungerStatusEffect.Create(); _foodMonitor.OnWarning += delegate { ((BaseUnityPlugin)this).Logger.LogInfo((object)"HungryViking: entered hunger window"); }; _foodMonitor.OnStarving += delegate { ((BaseUnityPlugin)this).Logger.LogInfo((object)"HungryViking: slot expired"); }; VignetteIntensity.SettingChanged += delegate { _hungerPreviewTimer = 2f; }; VignetteExtent.SettingChanged += delegate { _hungerPreviewTimer = 2f; }; SmokedVignetteIntensity.SettingChanged += delegate { _smokedPreviewTimer = 2f; }; SmokedVignetteExtent.SettingChanged += delegate { _smokedPreviewTimer = 2f; }; PoisonedVignetteIntensity.SettingChanged += delegate { _poisonedPreviewTimer = 2f; }; PoisonedVignetteExtent.SettingChanged += delegate { _poisonedPreviewTimer = 2f; }; InitCommands(); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Hungry Viking loaded. HungerThreshold={HungerThreshold.Value}s Intensity={VignetteIntensity.Value}"); } private void InitCommands() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected O, but got Unknown //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Expected O, but got Unknown //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Expected O, but got Unknown //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Expected O, but got Unknown //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Expected O, but got Unknown //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Expected O, but got Unknown //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Expected O, but got Unknown object obj = <>c.<>9__37_0; if (obj == null) { ConsoleEvent val = delegate { Player localPlayer6 = Player.m_localPlayer; if (!((Object)(object)localPlayer6 == (Object)null)) { FoodMonitor.ClearFoods(localPlayer6); Log.LogInfo((object)"hv_clearfood: all food buffs removed."); } }; <>c.<>9__37_0 = val; obj = (object)val; } new ConsoleCommand("hv_clearfood", "[Hungry Viking] Instantly removes all food buffs.", (ConsoleEvent)obj, true, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj2 = <>c.<>9__37_1; if (obj2 == null) { ConsoleEvent val2 = delegate(ConsoleEventArgs args) { Player localPlayer5 = Player.m_localPlayer; if (!((Object)(object)localPlayer5 == (Object)null)) { if (args.Length < 2 || !TryParseSlot(args[1], out var zeroBasedIndex2)) { Log.LogInfo((object)"Usage: hv_drainfood <1|2|3> [seconds]"); } else { float result3; float seconds2 = ((args.Length >= 3 && float.TryParse(args[2], out result3)) ? result3 : 60f); Log.LogInfo((object)FoodMonitor.DrainFood(localPlayer5, zeroBasedIndex2, seconds2)); } } }; <>c.<>9__37_1 = val2; obj2 = (object)val2; } new ConsoleCommand("hv_drainfood", "[Hungry Viking] hv_drainfood [seconds=60] — subtracts seconds from one food slot.", (ConsoleEvent)obj2, true, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj3 = <>c.<>9__37_2; if (obj3 == null) { ConsoleEvent val3 = delegate(ConsoleEventArgs args) { Player localPlayer4 = Player.m_localPlayer; if (!((Object)(object)localPlayer4 == (Object)null)) { float result2; float seconds = ((args.Length >= 2 && float.TryParse(args[1], out result2)) ? result2 : 60f); Log.LogInfo((object)FoodMonitor.DrainAllFoods(localPlayer4, seconds)); } }; <>c.<>9__37_2 = val3; obj3 = (object)val3; } new ConsoleCommand("hv_drainfoods", "[Hungry Viking] hv_drainfoods [seconds=60] — subtracts seconds from all food slots.", (ConsoleEvent)obj3, true, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj4 = <>c.<>9__37_3; if (obj4 == null) { ConsoleEvent val4 = delegate(ConsoleEventArgs args) { Player localPlayer3 = Player.m_localPlayer; if (!((Object)(object)localPlayer3 == (Object)null)) { if (args.Length < 3 || !TryParseSlot(args[1], out var zeroBasedIndex) || !float.TryParse(args[2], out var result)) { Log.LogInfo((object)"Usage: hv_setfoodtime <1|2|3> "); } else { Log.LogInfo((object)FoodMonitor.SetFoodTime(localPlayer3, zeroBasedIndex, result)); } } }; <>c.<>9__37_3 = val4; obj4 = (object)val4; } new ConsoleCommand("hv_setfoodtime", "[Hungry Viking] hv_setfoodtime — sets a slot to exactly X seconds remaining.", (ConsoleEvent)obj4, true, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj5 = <>c.<>9__37_4; if (obj5 == null) { ConsoleEvent val5 = delegate { Player localPlayer2 = Player.m_localPlayer; if (!((Object)(object)localPlayer2 == (Object)null)) { Log.LogInfo((object)FoodMonitor.GetFoodStatus(localPlayer2)); } }; <>c.<>9__37_4 = val5; obj5 = (object)val5; } new ConsoleCommand("hv_foodstatus", "[Hungry Viking] Prints the name and remaining time of each food slot.", (ConsoleEvent)obj5, true, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj6 = <>c.<>9__37_5; if (obj6 == null) { ConsoleEvent val6 = delegate { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { List statusEffects = ((Character)localPlayer).GetSEMan().GetStatusEffects(); if (statusEffects.Count == 0) { Log.LogInfo((object)"No active status effects."); } else { StringBuilder stringBuilder = new StringBuilder(); foreach (StatusEffect item in statusEffects) { stringBuilder.AppendLine($" \"{item.m_name}\" hash={item.NameHash()}"); } stringBuilder.AppendLine($" HaveStatusEffect(SmokedHash={-1612278721}) = {((Character)localPlayer).GetSEMan().HaveStatusEffect(-1612278721)}"); Log.LogInfo((object)stringBuilder.ToString().TrimEnd(Array.Empty())); } } }; <>c.<>9__37_5 = val6; obj6 = (object)val6; } new ConsoleCommand("hv_selist", "[Hungry Viking] Lists all active status effects on the local player with their name hashes.", (ConsoleEvent)obj6, true, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); new ConsoleCommand("hv_testhunger", "[Hungry Viking] Toggles the hunger vignette on/off for visual testing. Also triggers automatically for 2 seconds when Intensity or Extent config values change.", (ConsoleEvent)delegate { _hungerTestActive = !_hungerTestActive; Log.LogInfo((object)("hv_testhunger: hunger overlay " + (_hungerTestActive ? "ON" : "OFF"))); }, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); new ConsoleCommand("hv_testsmoked", "[Hungry Viking] Toggles the smoked vignette overlay on/off for visual testing.", (ConsoleEvent)delegate { _smokedTestActive = !_smokedTestActive; Log.LogInfo((object)("hv_testsmoked: smoked overlay " + (_smokedTestActive ? "ON" : "OFF"))); }, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); new ConsoleCommand("hv_testpoisoned", "[Hungry Viking] Toggles the poisoned vignette overlay on/off for visual testing.", (ConsoleEvent)delegate { _poisonedTestActive = !_poisonedTestActive; Log.LogInfo((object)("hv_testpoisoned: poisoned overlay " + (_poisonedTestActive ? "ON" : "OFF"))); }, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } private static bool TryParseSlot(string s, out int zeroBasedIndex) { if (int.TryParse(s, out var result) && result >= 1 && result <= 3) { zeroBasedIndex = result - 1; return true; } zeroBasedIndex = -1; return false; } private void InitConfig() { //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Expected O, but got Unknown //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Expected O, but got Unknown //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Expected O, but got Unknown //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Expected O, but got Unknown //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Expected O, but got Unknown //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Expected O, but got Unknown Enabled = ((BaseUnityPlugin)this).Config.Bind("General", "Enabled", true, "Enable or disable all Hungry Viking effects."); ShowStatusIcon = ((BaseUnityPlugin)this).Config.Bind("Hunger", "Show Status Icon", MigrateBool("General", "Show Status Icon", fallback: true), "Show the Hunger status icon in the HUD alongside Rested, Shelter, etc."); HungerThreshold = ((BaseUnityPlugin)this).Config.Bind("Hunger", "Hunger Threshold (seconds)", MigrateFloat("General", "Hunger Threshold (seconds)", 90f), "Seconds remaining on a food buff when the warning begins. Vignette and label fade in from here."); VignetteIntensity = ((BaseUnityPlugin)this).Config.Bind("Hunger", "Vignette Intensity", MigrateFloat("General", "Vignette Intensity", 0.2f), new ConfigDescription("Maximum vignette edge opacity. 0 = off, 1 = fully opaque.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); VignetteExtent = ((BaseUnityPlugin)this).Config.Bind("Hunger", "Vignette Extent", MigrateFloat("General", "Vignette Extent", 0.5f), new ConfigDescription("How far the vignette extends from the screen edge toward the center. 0 = not visible, 1 = covers the full screen.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); SmokedVignetteIntensity = ((BaseUnityPlugin)this).Config.Bind("Smoked", "Vignette Intensity", 0.25f, new ConfigDescription("Maximum opacity of the center smoke vignette. 0 = off, 1 = fully opaque.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); SmokedVignetteExtent = ((BaseUnityPlugin)this).Config.Bind("Smoked", "Vignette Extent", 1f, new ConfigDescription("How far from the screen center the smoke vignette reaches. 0 = invisible, 1 = covers the full screen.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); PoisonedVignetteIntensity = ((BaseUnityPlugin)this).Config.Bind("Poisoned", "Vignette Intensity", 0.25f, new ConfigDescription("Maximum opacity of the center poison vignette. 0 = off, 1 = fully opaque.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); PoisonedVignetteExtent = ((BaseUnityPlugin)this).Config.Bind("Poisoned", "Vignette Extent", 0.55f, new ConfigDescription("How far from the screen center the poison vignette reaches. 0 = invisible, 1 = covers the full screen.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); ((BaseUnityPlugin)this).Config.Save(); } private string MigrateRaw(string section, string key) { if (_migrationCache == null) { _migrationCache = new Dictionary(StringComparer.OrdinalIgnoreCase); if (File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath)) { string text = null; string[] array = File.ReadAllLines(((BaseUnityPlugin)this).Config.ConfigFilePath); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); if (text2.StartsWith("[") && text2.EndsWith("]")) { text = text2.Substring(1, text2.Length - 2).Trim(); } else if (text != null && !text2.StartsWith("#") && !text2.StartsWith("//")) { int num = text2.IndexOf('='); if (num >= 0) { _migrationCache[text + "/" + text2.Substring(0, num).Trim()] = text2.Substring(num + 1).Trim(); } } } } } if (!_migrationCache.TryGetValue(section + "/" + key, out var value)) { return null; } return value; } private float MigrateFloat(string section, string key, float fallback) { string text = MigrateRaw(section, key); if (text == null || !float.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return fallback; } return result; } private bool MigrateBool(string section, string key, bool fallback) { string text = MigrateRaw(section, key); if (text == null || !bool.TryParse(text, out var result)) { return fallback; } return result; } private void Update() { //IL_0066: 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) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) if (!Enabled.Value || (Object)(object)Player.m_localPlayer == (Object)null) { if ((Object)(object)_activeStatusEffect != (Object)null && (Object)(object)Player.m_localPlayer != (Object)null) { ((Character)Player.m_localPlayer).GetSEMan().RemoveStatusEffect(_activeStatusEffect.NameHash(), false); } _activeStatusEffect = null; _vignette.SetBase(0f, Color.black); _vignette.SetHungerLabel(null); _smokedOverlay.SetBase(0f, Color.white); _smokedOverlay.SetLabel(null); _poisonedOverlay.SetBase(0f, Color.white); _poisonedOverlay.SetLabel(null); return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)(object)_statusEffectPlayer) { _activeStatusEffect = null; _statusEffectPlayer = localPlayer; } _vignette.SetInnerBoundary(1f - VignetteExtent.Value); _foodMonitor.Tick(Time.deltaTime); bool flag = _foodMonitor.CurrentFoodCount < 3; float num = (flag ? 1f : _foodMonitor.WorstSlotUrgency); if (_hungerPreviewTimer > 0f) { _hungerPreviewTimer -= Time.deltaTime; } int num2; float num3; if (!_hungerTestActive) { num2 = ((_hungerPreviewTimer > 0f) ? 1 : 0); if (num2 == 0) { num3 = num; goto IL_0183; } } else { num2 = 1; } num3 = 1f; goto IL_0183; IL_0183: float num4 = num3; if (num4 > 0f) { _vignette.SetBase(VignetteIntensity.Value * num4, new Color(1f, 0.8f, 0.15f)); } else { _vignette.SetBase(0f, Color.black); } string text = null; if (((uint)num2 | (flag ? 1u : 0u)) != 0) { text = "You are hungry."; } else if (num >= 0.5f) { text = "You are getting hungry."; } else if (num > 0f) { text = "You are starting to feel hungry."; } _vignette.SetHungerLabel(text, num4); UpdateSmokedOverlay(localPlayer); UpdatePoisonedOverlay(localPlayer); HungerMessage = (flag ? "Hungry" : "Getting Hungry"); bool flag2 = (num > 0f || flag) && ShowStatusIcon.Value; if (flag2 && (Object)(object)_activeStatusEffect == (Object)null) { _activeStatusEffect = ((Character)localPlayer).GetSEMan().AddStatusEffect((StatusEffect)(object)_statusEffect, false, 0, 0f); } else if (!flag2 && (Object)(object)_activeStatusEffect != (Object)null) { ((Character)localPlayer).GetSEMan().RemoveStatusEffect(_activeStatusEffect.NameHash(), false); _activeStatusEffect = null; } } private void UpdateSmokedOverlay(Player player) { //IL_00aa: 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) if (_smokedPreviewTimer > 0f) { _smokedPreviewTimer -= Time.deltaTime; } bool num = _smokedTestActive || _smokedPreviewTimer > 0f || ((Character)player).GetSEMan().HaveStatusEffect(-1612278721); _smokedOverlay.SetOuterBoundary(SmokedVignetteExtent.Value); if (num) { _smokedOverlay.SetBase(SmokedVignetteIntensity.Value, new Color(0.85f, 0.85f, 0.85f)); _smokedOverlay.SetLabel("You can't breathe in the smoke!", 1f); } else { _smokedOverlay.SetBase(0f, Color.white); _smokedOverlay.SetLabel(null); } } private void UpdatePoisonedOverlay(Player player) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) if (_poisonedPreviewTimer > 0f) { _poisonedPreviewTimer -= Time.deltaTime; } bool num = _poisonedTestActive || _poisonedPreviewTimer > 0f; _poisonedOverlay.SetOuterBoundary(PoisonedVignetteExtent.Value); if (num) { _poisonedOverlay.SetBase(PoisonedVignetteIntensity.Value, new Color(0.2f, 0.8f, 0.2f)); _poisonedOverlay.SetLabel("You are poisoned.", 1f); } else { _poisonedOverlay.SetBase(0f, Color.white); _poisonedOverlay.SetLabel(null); } } private void OnDestroy() { harmony.UnpatchSelf(); } } public class SmokedOverlay : MonoBehaviour { private RawImage _image; private Text _label; private float _urgency; private static readonly Color LabelRedColor = new Color(1f, 0f, 0f, 1f); private Color _labelBaseColor = new Color(0.7f, 0.7f, 0.7f, 1f); private float _baseAlpha; private float _smoothedBase; private Color _baseColor; private float _labelPhase; private float _outerBoundary = 0.55f; private void Awake() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Expected O, but got Unknown //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_018e: 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_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("HungryViking_SmokedVignette"); Object.DontDestroyOnLoad((Object)(object)val); Canvas obj = val.AddComponent(); obj.renderMode = (RenderMode)0; obj.sortingOrder = 99; GameObject val2 = new GameObject("Image"); val2.transform.SetParent(val.transform, false); _image = val2.AddComponent(); _image.texture = (Texture)(object)BuildVignetteTexture(64, _outerBoundary); ((Graphic)_image).raycastTarget = false; ((Graphic)_image).color = Color.clear; RectTransform val3 = (RectTransform)val2.transform; val3.anchorMin = Vector2.zero; val3.anchorMax = Vector2.one; val3.offsetMin = Vector2.zero; val3.offsetMax = Vector2.zero; GameObject val4 = new GameObject("SmokedLabel"); val4.transform.SetParent(val.transform, false); _label = val4.AddComponent(); _label.text = ""; _label.font = Resources.GetBuiltinResource("Arial.ttf"); _label.fontSize = 22; _label.fontStyle = (FontStyle)1; _label.alignment = (TextAnchor)1; ((Graphic)_label).color = _labelBaseColor; ((Graphic)_label).raycastTarget = false; ((Component)_label).gameObject.SetActive(false); RectTransform val5 = (RectTransform)val4.transform; val5.anchorMin = new Vector2(0f, 1f); val5.anchorMax = new Vector2(1f, 1f); val5.pivot = new Vector2(0.5f, 1f); val5.offsetMin = new Vector2(0f, -100f); val5.offsetMax = new Vector2(0f, -70f); } public void SetLabelBaseColor(Color color) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) _labelBaseColor = color; } public void SetBase(float alpha, Color color) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) _baseAlpha = alpha; _baseColor = color; } private void Update() { //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) float num = ((_baseAlpha > _smoothedBase) ? Time.deltaTime : (Time.deltaTime * 0.5f)); _smoothedBase = Mathf.MoveTowards(_smoothedBase, _baseAlpha, num); float num2 = 0f; if (_urgency > 0f) { float num3 = Mathf.Lerp(0.2f, 1f, _urgency); _labelPhase = (_labelPhase + num3 * (float)Math.PI * 2f * Time.deltaTime) % ((float)Math.PI * 2f); num2 = (Mathf.Sin(_labelPhase) + 1f) * 0.5f; } float num4 = 1f - _urgency * 0.5f; float num5 = _smoothedBase * Mathf.Lerp(num4, 1f, num2); ((Graphic)_image).color = (Color)((num5 < 0.005f) ? Color.clear : new Color(_baseColor.r, _baseColor.g, _baseColor.b, num5)); if (((Component)_label).gameObject.activeSelf) { ((Graphic)_label).color = Color.Lerp(_labelBaseColor, LabelRedColor, num2 * _urgency); } } public void SetOuterBoundary(float value) { if (!Mathf.Approximately(_outerBoundary, value)) { _outerBoundary = value; Texture texture = _image.texture; _image.texture = (Texture)(object)BuildVignetteTexture(64, _outerBoundary); Object.Destroy((Object)(object)texture); } } public void SetLabel(string text, float urgency = 0f) { _urgency = urgency; if (string.IsNullOrEmpty(text)) { ((Component)_label).gameObject.SetActive(false); return; } _label.text = text; ((Component)_label).gameObject.SetActive(true); } private static Texture2D BuildVignetteTexture(int size, float extent) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Expected O, but got Unknown //IL_00ee: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(size, size, (TextureFormat)4, false); float num = (float)size * 0.5f; float num2; float num3; if (extent >= 0.5f) { num2 = (extent - 0.5f) * 0.5f; num3 = 0f; } else { num2 = 0f; num3 = 1f - 2f * extent; } float num4 = Mathf.Max(1f - num3, 0.001f); for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { float num5 = ((float)j + 0.5f - num) / num; float num6 = ((float)i + 0.5f - num) / num; float num7 = Mathf.Max(Mathf.Abs(num5), Mathf.Abs(num6)); float num8; if (num7 < num3) { num8 = 0f; } else { float num9 = Mathf.Clamp01((num7 - num3) / num4); float num10 = num9 * num9 * (3f - 2f * num9); num8 = Mathf.Lerp(num2, 1f, num10); } val.SetPixel(j, i, new Color(1f, 1f, 1f, num8)); } } val.Apply(); return val; } } public class VignetteOverlay : MonoBehaviour { private RawImage _image; private Text _hungerLabel; private float _hungerUrgency; private static readonly Color LabelBaseColor = new Color(1f, 0.35f, 0.1f, 1f); private static readonly Color LabelRedColor = new Color(1f, 0f, 0f, 1f); private float _baseAlpha; private Color _baseColor; private float _labelPhase; private float _innerBoundary = 0.82f; private void Awake() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Expected O, but got Unknown //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: 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_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("HungryViking_Vignette"); Object.DontDestroyOnLoad((Object)(object)val); Canvas obj = val.AddComponent(); obj.renderMode = (RenderMode)0; obj.sortingOrder = 100; GameObject val2 = new GameObject("Image"); val2.transform.SetParent(val.transform, false); _image = val2.AddComponent(); _image.texture = (Texture)(object)BuildVignetteTexture(64, _innerBoundary); ((Graphic)_image).raycastTarget = false; ((Graphic)_image).color = Color.clear; RectTransform val3 = (RectTransform)val2.transform; val3.anchorMin = Vector2.zero; val3.anchorMax = Vector2.one; val3.offsetMin = Vector2.zero; val3.offsetMax = Vector2.zero; GameObject val4 = new GameObject("HungerLabel"); val4.transform.SetParent(val.transform, false); _hungerLabel = val4.AddComponent(); _hungerLabel.text = ""; _hungerLabel.font = Resources.GetBuiltinResource("Arial.ttf"); _hungerLabel.fontSize = 22; _hungerLabel.fontStyle = (FontStyle)1; _hungerLabel.alignment = (TextAnchor)1; ((Graphic)_hungerLabel).color = new Color(1f, 0.35f, 0.1f, 1f); ((Graphic)_hungerLabel).raycastTarget = false; ((Component)_hungerLabel).gameObject.SetActive(false); RectTransform val5 = (RectTransform)val4.transform; val5.anchorMin = new Vector2(0f, 1f); val5.anchorMax = new Vector2(1f, 1f); val5.pivot = new Vector2(0.5f, 1f); val5.offsetMin = new Vector2(0f, -70f); val5.offsetMax = new Vector2(0f, -40f); } public void SetBase(float alpha, Color color) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) _baseAlpha = alpha; _baseColor = color; } private void Update() { //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) float num = 0f; if (_hungerUrgency > 0f) { float num2 = Mathf.Lerp(0.2f, 1f, _hungerUrgency); _labelPhase = (_labelPhase + num2 * (float)Math.PI * 2f * Time.deltaTime) % ((float)Math.PI * 2f); num = (Mathf.Sin(_labelPhase) + 1f) * 0.5f; } float num3 = 1f - _hungerUrgency * 0.5f; float num4 = _baseAlpha * Mathf.Lerp(num3, 1f, num); ((Graphic)_image).color = (Color)((num4 < 0.005f) ? Color.clear : new Color(_baseColor.r, _baseColor.g, _baseColor.b, num4)); if (((Component)_hungerLabel).gameObject.activeSelf) { ((Graphic)_hungerLabel).color = Color.Lerp(LabelBaseColor, LabelRedColor, num * _hungerUrgency); } } public void SetInnerBoundary(float value) { if (!Mathf.Approximately(_innerBoundary, value)) { _innerBoundary = value; Texture texture = _image.texture; _image.texture = (Texture)(object)BuildVignetteTexture(64, _innerBoundary); Object.Destroy((Object)(object)texture); } } public void SetHungerLabel(string text, float urgency = 0f) { _hungerUrgency = urgency; if (string.IsNullOrEmpty(text)) { ((Component)_hungerLabel).gameObject.SetActive(false); return; } _hungerLabel.text = text; ((Component)_hungerLabel).gameObject.SetActive(true); } private static Texture2D BuildVignetteTexture(int size, float innerBoundary) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Expected O, but got Unknown //IL_0093: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(size, size, (TextureFormat)4, false); float num = (float)size * 0.5f; float num2 = Mathf.Max(1f - innerBoundary, 0.001f); for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { float num3 = ((float)j + 0.5f - num) / num; float num4 = ((float)i + 0.5f - num) / num; float num5 = Mathf.Clamp01((Mathf.Max(Mathf.Abs(num3), Mathf.Abs(num4)) - innerBoundary) / num2); float num6 = num5 * num5 * (3f - 2f * num5); val.SetPixel(j, i, new Color(1f, 1f, 1f, num6)); } } val.Apply(); return val; } }