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 BetterFoodMechanics v2.0.1
BetterFoodMechanics.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; 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.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [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 BetterFoodMechanics { [BepInPlugin("biznessman.BetterFoodMechanics", "BetterFoodMechanics", "2.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class BetterFoodMechanicsPlugin : BaseUnityPlugin { public const string PluginGuid = "biznessman.BetterFoodMechanics"; public const string PluginName = "BetterFoodMechanics"; public const string PluginVersion = "2.0.0"; internal static ConfigEntry<Toggle> Enabled; internal static ConfigEntry<int> Mode; internal static ConfigEntry<int> MinComfort; internal static ConfigEntry<float> DurationMultiplier; internal static ConfigEntry<Toggle> FoodBuffDegrades; internal static bool IsEnabled => Enabled.Value == Toggle.On; internal static bool IsBuffDegradeEnabled => FoodBuffDegrades.Value == Toggle.On; private void Awake() { //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) //IL_000d: Expected O, but got Unknown //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Expected O, but got Unknown //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Expected O, but got Unknown //IL_0174: Unknown result type (might be due to invalid IL or missing references) ConfigurationManagerAttributes val = new ConfigurationManagerAttributes { IsAdminOnly = true }; Enabled = ((BaseUnityPlugin)this).Config.Bind<Toggle>("1 - General", "Enabled", Toggle.On, new ConfigDescription("Turn the mod on or off. (Synced with server)", (AcceptableValueBase)null, new object[1] { val })); Mode = ((BaseUnityPlugin)this).Config.Bind<int>("2 - Cozyness", "DegradationMode", 1, new ConfigDescription("How food behaves while you rest in your base:\n0 = Frozen: food timer and buffs stop completely.\n1 = Slow: food lasts twice as long.\n2 = Scaled: more comfort = slower decay (1/2 rate at 10 comfort, 1/3 at 15, 1/4 at 20+). Ignores MinimumComfort.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 2), new object[1] { val })); MinComfort = ((BaseUnityPlugin)this).Config.Bind<int>("2 - Cozyness", "MinimumComfort", 10, new ConfigDescription("Comfort level needed for modes 0 and 1 to apply. Not used in mode 2.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(5, 25), new object[1] { val })); DurationMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Food", "FoodDurationMultiplier", 1f, new ConfigDescription("How much longer food lasts. 2 = twice as long (a 30 min food lasts 60).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), new object[1] { val })); FoodBuffDegrades = ((BaseUnityPlugin)this).Config.Bind<Toggle>("3 - Food", "FoodBuffDegrades", Toggle.On, new ConfigDescription("On: food buffs (health/stamina/eitr) fade gradually over the full duration.\nOff: buffs stay at full strength for the entire duration.", (AcceptableValueBase)null, new object[1] { val })); Enabled.SettingChanged += delegate { FoodDurationApplier.Apply(ObjectDB.instance); }; DurationMultiplier.SettingChanged += delegate { FoodDurationApplier.Apply(ObjectDB.instance); }; new Harmony("biznessman.BetterFoodMechanics").PatchAll(); } internal static float GetDecayRate(int comfort) { switch (Mode.Value) { case 0: if (comfort < MinComfort.Value) { return 1f; } return 0f; case 1: if (comfort < MinComfort.Value) { return 1f; } return 0.5f; case 2: if (comfort >= 20) { return 0.25f; } if (comfort >= 15) { return 1f / 3f; } if (comfort >= 10) { return 0.5f; } return 1f; default: return 1f; } } } public enum Toggle { Off, On } [HarmonyPatch(typeof(Player), "UpdateFood")] internal static class UpdateFoodRatePatch { [HarmonyPatch(typeof(Hud), "UpdateFood")] internal static class HudFoodTimePatch { private static readonly FieldInfo FoodRateField = AccessTools.Field(typeof(Game), "m_foodRate"); private static readonly MethodInfo DisplayRateMethod = AccessTools.Method(typeof(HudFoodTimePatch), "DisplayRate", (Type[])null, (Type[])null); public static float DisplayRate() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return 1f; } float rate = GetRate(localPlayer); if (!(rate > 0f)) { return 1f; } return rate; } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> code) { foreach (CodeInstruction ins in code) { yield return ins; if (CodeInstructionExtensions.LoadsField(ins, FoodRateField, false)) { yield return new CodeInstruction(OpCodes.Call, (object)DisplayRateMethod); yield return new CodeInstruction(OpCodes.Mul, (object)null); } } } } private static readonly FieldRef<Player, float> TimerRef = AccessTools.FieldRefAccess<Player, float>("m_foodUpdateTimer"); private static readonly FieldInfo FoodRateField = AccessTools.Field(typeof(Game), "m_foodRate"); private static float _cachedRate = 1f; private static float _nextCheck; internal static float GetRate(Player player) { if (!BetterFoodMechanicsPlugin.IsEnabled) { return 1f; } if ((Object)(object)player != (Object)(object)Player.m_localPlayer) { return 1f; } if (Time.time >= _nextCheck) { _nextCheck = Time.time + 0.5f; _cachedRate = BetterFoodMechanicsPlugin.GetDecayRate(player.GetComfortLevel()); } return _cachedRate; } private static void Prefix(Player __instance, float dt) { if (!(dt <= 0f)) { float rate = GetRate(__instance); if (!(rate >= 1f)) { float num = (float)FoodRateField.GetValue(null); TimerRef.Invoke(__instance) -= dt * num * (1f - rate); } } } } internal static class FoodDurationApplier { private static readonly Dictionary<SharedData, float> Originals = new Dictionary<SharedData, float>(); public static void Apply(ObjectDB db) { if ((Object)(object)db == (Object)null) { return; } float num = (BetterFoodMechanicsPlugin.IsEnabled ? BetterFoodMechanicsPlugin.DurationMultiplier.Value : 1f); foreach (GameObject item in db.m_items) { if ((Object)(object)item == (Object)null) { continue; } ItemDrop component = item.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null) { continue; } SharedData shared = component.m_itemData.m_shared; if (!Originals.TryGetValue(shared, out var value)) { if (shared.m_foodBurnTime <= 0f) { continue; } value = shared.m_foodBurnTime; Originals[shared] = value; } shared.m_foodBurnTime = value * num; } } } [HarmonyPatch(typeof(ObjectDB), "Awake")] internal static class ObjectDBAwakePatch { private static void Postfix(ObjectDB __instance) { FoodDurationApplier.Apply(__instance); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] internal static class ObjectDBCopyPatch { private static void Postfix(ObjectDB __instance) { FoodDurationApplier.Apply(__instance); } } [HarmonyPatch(typeof(Player), "GetTotalFoodValue")] internal static class NoDegradePatch { private static readonly FieldRef<Player, List<Food>> FoodsRef = AccessTools.FieldRefAccess<Player, List<Food>>("m_foods"); private static void Postfix(Player __instance, ref float hp, ref float stamina, ref float eitr) { if (!BetterFoodMechanicsPlugin.IsEnabled || BetterFoodMechanicsPlugin.IsBuffDegradeEnabled) { return; } foreach (Food item in FoodsRef.Invoke(__instance)) { SharedData shared = item.m_item.m_shared; hp += shared.m_food - item.m_health; stamina += shared.m_foodStamina - item.m_stamina; eitr += shared.m_foodEitr - item.m_eitr; } } } }