Please disclose if any significant portion of your mod was created 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 AutoNosh v0.5.0
plugins/AutoNosh.dll
Decompiled 18 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn.Configs; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; [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: IgnoresAccessChecksTo("assembly_guiutils")] [assembly: IgnoresAccessChecksTo("assembly_utils")] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: AssemblyCompany("RAGEmedia")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Smart auto-eat for food only, with profile-based selection, a cycle key, and an AFK pause.")] [assembly: AssemblyFileVersion("0.5.0.0")] [assembly: AssemblyInformationalVersion("0.5.0")] [assembly: AssemblyProduct("AutoNosh")] [assembly: AssemblyTitle("AutoNosh")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.5.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] internal sealed class IsReadOnlyAttribute : Attribute { } [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 AutoNosh { internal static class AfkTracker { private static float _lastActiveTime = Time.time; internal static float IdleSeconds => Time.time - _lastActiveTime; internal static void NoteActivity() { _lastActiveTime = Time.time; } } internal static class FoodAutoEater { private static readonly HashSet<Food> WarnedExpiring = new HashSet<Food>(); private static bool _warnedNoFood; internal static void TryAutoEat(Player player) { List<Food> activeFoods = player.GetFoods(); WarnedExpiring.IntersectWith(activeFoods); if (AutoNoshPlugin.NotifyExpiring.Value) { foreach (Food item in activeFoods) { if (IsDueForReplacement(item) && WarnedExpiring.Add(item)) { ((Character)player).Message((MessageType)2, "AutoNosh: " + item.m_item.m_shared.m_name + " is running low", 0, (Sprite)null, false); } } } bool num = activeFoods.Count < 3; bool flag = activeFoods.Any(IsDueForReplacement); if (!num && !flag) { return; } List<ItemData> list = (from i in GetFoodCandidates(player) where CanEatNow(activeFoods, i) select i).ToList(); if (list.Count == 0) { if (AutoNoshPlugin.NotifyFallback.Value && !_warnedNoFood) { _warnedNoFood = true; ((Character)player).Message((MessageType)2, "AutoNosh: no food to eat", 0, (Sprite)null, false); } return; } _warnedNoFood = false; FoodProfile value = AutoNoshPlugin.FoodProfileConfig.Value; bool isNormalPick; string missingFocusName; ItemData val = PickFood(value, (from f in activeFoods.Where(IsDueForReplacement) orderby f.m_time select f).FirstOrDefault()?.m_item, list, out isNormalPick, out missingFocusName); if (!((Humanoid)player).ConsumeItem(((Humanoid)player).GetInventory(), val, false)) { return; } string name = val.m_shared.m_name; string text = null; if (isNormalPick) { if (AutoNoshPlugin.NotifyEating.Value) { text = "AutoNosh: eating " + name; } } else if (AutoNoshPlugin.NotifyFallback.Value) { string text2 = (string.IsNullOrEmpty(missingFocusName) ? "no matching food" : ("no " + missingFocusName + " food")); text = "AutoNosh: " + text2 + ", eating next best: " + name; } string text3 = BuildLowStockWarning(player, value, val); if (text3 != null) { text = ((text == null) ? ("AutoNosh: " + text3) : (text + "\n" + text3)); } if (text != null) { ((Character)player).Message((MessageType)2, text, 0, (Sprite)null, false); } AutoNoshPlugin.LogVerbose($"Auto-ate {name} (profile {value}, normal pick: {isNormalPick})"); } private static ItemData PickFood(FoodProfile profile, ItemData target, List<ItemData> eatable, out bool isNormalPick, out string missingFocusName) { if (profile == FoodProfile.None) { return PickForNoneProfile(target, eatable, out isNormalPick, out missingFocusName); } List<ItemData> list = eatable.Where((ItemData i) => FoodProfiles.Matches(profile, i)).ToList(); if (list.Count > 0) { isNormalPick = true; missingFocusName = ""; FoodWeights weights = FoodProfiles.GetWeights(profile); return list.OrderByDescending((ItemData i) => ScoreCandidate(i, weights)).First(); } isNormalPick = false; missingFocusName = FoodProfiles.FocusName(profile); return PickByFallbackPriority(eatable); } private static ItemData PickForNoneProfile(ItemData target, List<ItemData> eatable, out bool isNormalPick, out string missingFocusName) { missingFocusName = ""; if (target == null) { isNormalPick = true; return PickByFallbackPriority(eatable); } if (!AutoNoshPlugin.PreferBetterSameTypeFood.Value) { ItemData val = ((IEnumerable<ItemData>)eatable).FirstOrDefault((Func<ItemData, bool>)((ItemData i) => i.m_shared.m_name == target.m_shared.m_name)); if (val != null) { isNormalPick = true; return val; } } FoodStatKind dominant = FoodProfiles.Classify(target); List<ItemData> list = eatable.Where((ItemData i) => FoodProfiles.Classify(i) == dominant).ToList(); if (list.Count > 0) { isNormalPick = true; return list.OrderByDescending((ItemData i) => ScoreCandidate(i, FoodProfiles.WeightsForStat(dominant))).First(); } isNormalPick = false; missingFocusName = FoodProfiles.StatKindName(dominant); return PickByFallbackPriority(eatable); } private static string BuildLowStockWarning(Player player, FoodProfile profile, ItemData eaten) { int value = AutoNoshPlugin.LowFoodWarningCount.Value; if (value <= 0) { return null; } string name = eaten.m_shared.m_name; int num = ((Humanoid)player).GetInventory().CountItems(name, -1, false); if (num > value) { return null; } string text = ((num == 0) ? ("that was your last " + name) : $"{name}: {num} left"); if (!AutoNoshPlugin.NotifyNextFood.Value) { return text; } HashSet<string> otherActive = new HashSet<string>(from f in player.GetFoods() select f.m_item.m_shared.m_name into n where n != name select n); List<ItemData> list = (from i in GetFoodCandidates(player) where i.m_shared.m_name != name && !otherActive.Contains(i.m_shared.m_name) select i).ToList(); if (list.Count == 0) { return text + ", no other food to fall back on"; } bool isNormalPick; string missingFocusName; ItemData val = PickFood(profile, eaten, list, out isNormalPick, out missingFocusName); return text + ", then " + val.m_shared.m_name; } private static ItemData PickByFallbackPriority(List<ItemData> eatable) { FoodStatKind[] fallbackOrder = FoodProfiles.GetFallbackOrder(AutoNoshPlugin.FallbackPriorityConfig.Value); foreach (FoodStatKind kind in fallbackOrder) { List<ItemData> list = eatable.Where((ItemData item) => FoodProfiles.QualifiesFor(item, kind)).ToList(); if (list.Count > 0) { return list.OrderByDescending((ItemData item) => ScoreCandidate(item, FoodProfiles.WeightsForStat(kind))).First(); } } return eatable.OrderByDescending((ItemData item) => ScoreCandidate(item, FoodProfiles.BalancedWeights)).First(); } private static float ScoreCandidate(ItemData item, FoodWeights weights) { return FoodProfiles.Score(item, weights, AutoNoshPlugin.ConsiderFeastDuration.Value); } private static List<ItemData> GetFoodCandidates(Player player) { return ((Humanoid)player).GetInventory().GetAllItemsOfType((ItemType)2, false).Where(IsFood) .ToList(); } private static bool CanEatNow(List<Food> activeFoods, ItemData item) { foreach (Food activeFood in activeFoods) { if (activeFood.m_item.m_shared.m_name == item.m_shared.m_name) { return IsDueForReplacement(activeFood); } } if (activeFoods.Any(IsDueForReplacement)) { return true; } return activeFoods.Count < 3; } private static bool IsDueForReplacement(Food food) { if (!food.CanEatAgain()) { return false; } float foodBurnTime = food.m_item.m_shared.m_foodBurnTime; if (foodBurnTime <= 0f) { return true; } return food.m_time / foodBurnTime <= AutoNoshPlugin.EatThresholdPercent.Value / 100f; } private static bool IsFood(ItemData item) { SharedData shared = item.m_shared; if (!(shared.m_food > 0f) && !(shared.m_foodStamina > 0f)) { return shared.m_foodEitr > 0f; } return true; } } public enum FoodProfile { Balanced, None, HeavyStamina, MassiveHealth, EitrMagic, MagicHealth } internal enum FoodStatKind { Health, Stamina, Eitr, Balanced } public enum FallbackPriority { HealthStaminaEitr, HealthEitrStamina, StaminaHealthEitr, StaminaEitrHealth, EitrHealthStamina, EitrStaminaHealth } internal readonly struct FoodWeights { internal readonly float Health; internal readonly float Stamina; internal readonly float Eitr; internal FoodWeights(float health, float stamina, float eitr) { Health = health; Stamina = stamina; Eitr = eitr; } } internal static class FoodProfiles { internal static readonly FoodWeights BalancedWeights = new FoodWeights(1f, 1f, 1f); internal static FoodWeights GetWeights(FoodProfile profile) { return profile switch { FoodProfile.HeavyStamina => new FoodWeights(0.3f, 2f, 0.3f), FoodProfile.MassiveHealth => new FoodWeights(2f, 0.3f, 0.3f), FoodProfile.EitrMagic => new FoodWeights(0.2f, 0.2f, 2.5f), FoodProfile.MagicHealth => new FoodWeights(1.5f, 0.2f, 1.5f), _ => BalancedWeights, }; } internal static bool Matches(FoodProfile profile, ItemData item) { SharedData shared = item.m_shared; switch (profile) { case FoodProfile.HeavyStamina: return shared.m_foodStamina > 0f; case FoodProfile.MassiveHealth: return shared.m_food > 0f; case FoodProfile.EitrMagic: case FoodProfile.MagicHealth: return shared.m_foodEitr > 0f; default: return true; } } internal static float Score(ItemData item, FoodWeights weights, bool considerDuration) { SharedData shared = item.m_shared; float num = shared.m_food * weights.Health + shared.m_foodStamina * weights.Stamina + shared.m_foodEitr * weights.Eitr; if (!considerDuration) { return num; } return num * shared.m_foodBurnTime; } internal static string FocusName(FoodProfile profile) { switch (profile) { case FoodProfile.HeavyStamina: return "Stamina"; case FoodProfile.MassiveHealth: return "Health"; case FoodProfile.EitrMagic: case FoodProfile.MagicHealth: return "Eitr"; default: return ""; } } internal static FoodProfile Next(FoodProfile current) { FoodProfile[] array = (FoodProfile[])Enum.GetValues(typeof(FoodProfile)); int num = Array.IndexOf(array, current); return array[(num + 1) % array.Length]; } internal static FoodStatKind Classify(ItemData item) { SharedData shared = item.m_shared; if (shared.m_food < shared.m_foodEitr / 2f && shared.m_foodStamina < shared.m_foodEitr / 2f) { return FoodStatKind.Eitr; } if (shared.m_foodStamina < shared.m_food / 2f) { return FoodStatKind.Health; } if (shared.m_food < shared.m_foodStamina / 2f) { return FoodStatKind.Stamina; } return FoodStatKind.Balanced; } internal static bool QualifiesFor(ItemData item, FoodStatKind kind) { FoodStatKind foodStatKind = Classify(item); if (foodStatKind == kind) { return true; } if (foodStatKind != FoodStatKind.Balanced) { return false; } SharedData shared = item.m_shared; return kind switch { FoodStatKind.Health => shared.m_food > 0f, FoodStatKind.Stamina => shared.m_foodStamina > 0f, FoodStatKind.Eitr => shared.m_foodEitr > 0f, _ => false, }; } internal static FoodWeights WeightsForStat(FoodStatKind kind) { return kind switch { FoodStatKind.Stamina => GetWeights(FoodProfile.HeavyStamina), FoodStatKind.Eitr => GetWeights(FoodProfile.EitrMagic), FoodStatKind.Health => GetWeights(FoodProfile.MassiveHealth), _ => BalancedWeights, }; } internal static string StatKindName(FoodStatKind kind) { return kind switch { FoodStatKind.Stamina => "Stamina", FoodStatKind.Eitr => "Eitr", FoodStatKind.Balanced => "Balanced", _ => "Health", }; } internal static FoodStatKind[] GetFallbackOrder(FallbackPriority priority) { return priority switch { FallbackPriority.HealthEitrStamina => new FoodStatKind[3] { FoodStatKind.Health, FoodStatKind.Eitr, FoodStatKind.Stamina }, FallbackPriority.StaminaHealthEitr => new FoodStatKind[3] { FoodStatKind.Stamina, FoodStatKind.Health, FoodStatKind.Eitr }, FallbackPriority.StaminaEitrHealth => new FoodStatKind[3] { FoodStatKind.Stamina, FoodStatKind.Eitr, FoodStatKind.Health }, FallbackPriority.EitrHealthStamina => new FoodStatKind[3] { FoodStatKind.Eitr, FoodStatKind.Health, FoodStatKind.Stamina }, FallbackPriority.EitrStaminaHealth => new FoodStatKind[3] { FoodStatKind.Eitr, FoodStatKind.Stamina, FoodStatKind.Health }, _ => new FoodStatKind[3] { FoodStatKind.Health, FoodStatKind.Stamina, FoodStatKind.Eitr }, }; } } [BepInPlugin("com.ragemedia.autonosh", "AutoNosh", "0.5.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class AutoNoshPlugin : BaseUnityPlugin { public const string PluginGuid = "com.ragemedia.autonosh"; public const string PluginName = "AutoNosh"; public const string PluginVersion = "0.5.0"; internal const string CycleProfileButtonName = "AutoNosh_CycleProfile"; internal static AutoNoshPlugin Instance; internal static ConfigEntry<bool> VerboseLogging; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<float> CheckIntervalSeconds; internal static ConfigEntry<float> EatThresholdPercent; internal static ConfigEntry<FoodProfile> FoodProfileConfig; internal static ConfigEntry<KeyCode> CycleProfileKey; internal static ConfigEntry<bool> PreferBetterSameTypeFood; internal static ConfigEntry<FallbackPriority> FallbackPriorityConfig; internal static ConfigEntry<bool> ConsiderFeastDuration; internal static ConfigEntry<bool> AfkPauseEnabled; internal static ConfigEntry<float> AfkThresholdMinutes; internal static ConfigEntry<bool> NotifyEating; internal static ConfigEntry<bool> NotifyExpiring; internal static ConfigEntry<bool> NotifyFallback; internal static ConfigEntry<int> LowFoodWarningCount; internal static ConfigEntry<bool> NotifyNextFood; private readonly Harmony _harmony = new Harmony("com.ragemedia.autonosh"); private void Awake() { Instance = this; BindConfig(); RegisterKeybind(); _harmony.PatchAll(Assembly.GetExecutingAssembly()); VerifyPatches(); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private void BindConfig() { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected O, but got Unknown //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Expected O, but got Unknown //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Expected O, but got Unknown VerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "VerboseLogging", false, "Log detailed per-event output. Noisy; for debugging only."); Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master toggle for auto-eating."); CheckIntervalSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "CheckIntervalSeconds", 2f, new ConfigDescription("How often to re-check whether a food slot needs refilling.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 10f), Array.Empty<object>())); EatThresholdPercent = ((BaseUnityPlugin)this).Config.Bind<float>("General", "EatThresholdPercent", 50f, new ConfigDescription("Auto-eat when a food's remaining time drops to this percent of its total duration. 50 (default) acts the moment the game allows a top-up at all; lower it to wait longer and let food run closer to empty first. The game itself never allows a top-up above 50%, so values here only ever narrow that window, never widen it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), Array.Empty<object>())); FoodProfileConfig = ((BaseUnityPlugin)this).Config.Bind<FoodProfile>("Profile", "FoodProfile", FoodProfile.Balanced, "Which stat this favors when picking a replacement food. Balanced picks the highest total food value; None keeps whatever you're already eating (see PreferBetterSameTypeFood); the rest favor stamina, health, or eitr food. All fall back to FallbackPriority when nothing in your inventory fits."); CycleProfileKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Profile", "CycleProfileKey", (KeyCode)285, "Key that cycles FoodProfile to the next preset in game."); PreferBetterSameTypeFood = ((BaseUnityPlugin)this).Config.Bind<bool>("Profile", "PreferBetterSameTypeFood", false, "Only affects the None profile. False (default): re-eat the exact same food you already had whenever it's available. True: eat the best food of the same kind (fork color: red health, yellow stamina, blue eitr, white balanced) instead, even if it's a different item you have."); FallbackPriorityConfig = ((BaseUnityPlugin)this).Config.Bind<FallbackPriority>("Profile", "FallbackPriority", FallbackPriority.HealthStaminaEitr, "Stat category order to try when a profile (or None with nothing of the same kind left) can't find a matching food - picks the best food from the first category that has anything available."); ConsiderFeastDuration = ((BaseUnityPlugin)this).Config.Bind<bool>("Profile", "ConsiderFeastDuration", false, "False (default): pick by peak stat value only, so a food's numbers are compared the same way whether it lasts 20 minutes or 50. True: weight by peak value times duration, which can make a longer-lasting feast with lower peak stats win over a shorter, higher-peak food that needs re-eating sooner."); AfkPauseEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("AFK", "AfkPauseEnabled", true, "Stop auto-eating while the player has been idle for AfkThresholdMinutes. Food already active keeps decaying normally either way."); AfkThresholdMinutes = ((BaseUnityPlugin)this).Config.Bind<float>("AFK", "AfkThresholdMinutes", 5f, new ConfigDescription("Minutes of no input before auto-eating pauses.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f), Array.Empty<object>())); NotifyEating = ((BaseUnityPlugin)this).Config.Bind<bool>("Notifications", "NotifyEating", true, "Show a message when AutoNosh eats a food that matches your active profile."); NotifyExpiring = ((BaseUnityPlugin)this).Config.Bind<bool>("Notifications", "NotifyExpiring", true, "Show a message once when an active food drops to EatThresholdPercent remaining, whether or not a replacement is found."); NotifyFallback = ((BaseUnityPlugin)this).Config.Bind<bool>("Notifications", "NotifyFallback", true, "Show a message when no inventory food matches your active profile's focus stat and AutoNosh eats the next-best food instead, or when it can't find any food to eat at all."); LowFoodWarningCount = ((BaseUnityPlugin)this).Config.Bind<int>("Notifications", "LowFoodWarningCount", 3, new ConfigDescription("After AutoNosh eats a food, warn when you have this many or fewer of it left in your inventory. 0 turns the warning off.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 50), Array.Empty<object>())); NotifyNextFood = ((BaseUnityPlugin)this).Config.Bind<bool>("Notifications", "NotifyNextFood", true, "Add to the low-food warning which food AutoNosh will eat in that slot once you run out, or that there's nothing left to fall back on."); } private void RegisterKeybind() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown InputManager.Instance.AddButton("com.ragemedia.autonosh", new ButtonConfig { Name = "AutoNosh_CycleProfile", Config = CycleProfileKey, HintToken = "$autonosh_cycle_profile" }); } private void VerifyPatches() { List<MethodBase> list = _harmony.GetPatchedMethods().ToList(); LogInfo($"Harmony bound {list.Count} target(s):"); foreach (MethodBase item in list) { LogInfo(" bound " + item.DeclaringType?.FullName + "." + item.Name); } int num = 0; foreach (Type item2 in from t in Assembly.GetExecutingAssembly().GetTypes() where t.GetCustomAttributes(typeof(HarmonyPatch), inherit: true).Any() select t) { List<HarmonyMethod> list2 = (from HarmonyPatch a in item2.GetCustomAttributes(typeof(HarmonyPatch), inherit: true) select ((HarmonyAttribute)a).info).ToList(); HarmonyMethod val; try { val = HarmonyMethod.Merge(list2); } catch (Exception ex) { LogError(" UNRESOLVED " + item2.Name + ": could not merge patch attributes: " + ex.Message); num++; continue; } if (!(val?.declaringType == null) && !string.IsNullOrEmpty(val.methodName) && AccessTools.Method(val.declaringType, val.methodName, val.argumentTypes, (Type[])null) == null) { num++; LogError(" UNRESOLVED " + item2.Name + " -> " + val.declaringType.Name + "." + val.methodName + " does not exist. This patch will never run. The game version likely changed; re-check the method against the decompiled source."); } } if (num > 0) { LogError(string.Format("{0}: {1} patch target(s) failed to resolve. ", "AutoNosh", num) + "This mod is loaded but not fully functional."); } else if (list.Count == 0) { LogWarning("AutoNosh: loaded, but bound zero patches. Expected if this mod only adds content via Jotunn."); } else { LogInfo("AutoNosh v0.5.0 ready."); } } internal static void LogInfo(string msg) { ((BaseUnityPlugin)Instance).Logger.LogInfo((object)("[AutoNosh] " + msg)); } internal static void LogWarning(string msg) { ((BaseUnityPlugin)Instance).Logger.LogWarning((object)("[AutoNosh] " + msg)); } internal static void LogError(string msg) { ((BaseUnityPlugin)Instance).Logger.LogError((object)("[AutoNosh] " + msg)); } internal static void LogVerbose(string msg) { if (VerboseLogging != null && VerboseLogging.Value) { ((BaseUnityPlugin)Instance).Logger.LogInfo((object)("[AutoNosh] " + msg)); } } } } namespace AutoNosh.Patches { [HarmonyPatch(typeof(Player), "SetControls")] internal static class PlayerSetControlsPatch { private static void Postfix(Player __instance, Vector3 movedir, bool attack, bool attackHold, bool secondaryAttack, bool secondaryAttackHold, bool block, bool blockHold, bool jump, bool crouch, bool dodge) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && (movedir != Vector3.zero || attack || attackHold || secondaryAttack || secondaryAttackHold || block || blockHold || jump || crouch || dodge)) { AfkTracker.NoteActivity(); } } } [HarmonyPatch(typeof(Player), "Update")] internal static class PlayerUpdatePatch { private static float _nextEatCheck; private static void Postfix(Player __instance) { if (!Player.m_localPlayerExists || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } if (ZInput.GetButtonDown("AutoNosh_CycleProfile")) { CycleProfile(__instance); } if (AutoNoshPlugin.Enabled.Value && !(Time.time < _nextEatCheck)) { _nextEatCheck = Time.time + AutoNoshPlugin.CheckIntervalSeconds.Value; if (AutoNoshPlugin.AfkPauseEnabled.Value && AfkTracker.IdleSeconds >= AutoNoshPlugin.AfkThresholdMinutes.Value * 60f) { AutoNoshPlugin.LogVerbose($"Skipping auto-eat, idle {AfkTracker.IdleSeconds:0}s."); } else if (((Character)__instance).GetSEMan().GetStatusEffects().Any((StatusEffect se) => se is SE_Puke)) { AutoNoshPlugin.LogVerbose("Skipping auto-eat, player is feeling sick."); } else { FoodAutoEater.TryAutoEat(__instance); } } } private static void CycleProfile(Player player) { FoodProfile foodProfile = FoodProfiles.Next(AutoNoshPlugin.FoodProfileConfig.Value); AutoNoshPlugin.FoodProfileConfig.Value = foodProfile; AutoNoshPlugin.LogVerbose($"Food profile cycled to {foodProfile}."); ((Character)player).Message((MessageType)2, $"AutoNosh: {foodProfile}", 0, (Sprite)null, false); } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }