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 MasterCookingFixes v1.1.2
MasterCookingFixes.dll
Decompiled 11 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; 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: AssemblyCompany("MasterCookingFixes")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("MasterCookingFixes")] [assembly: AssemblyTitle("MasterCookingFixes")] [assembly: AssemblyVersion("1.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 MasterCookingFixes { [BepInPlugin("pieter.valheim.mastercookingfixes", "MasterCooking Fixes", "1.1.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { private struct Factors { public float Health; public float Stamina; public float Regen; public float Eitr; public float Duration; public bool Any { get { if (Health == 1f && Stamina == 1f && Regen == 1f && Eitr == 1f) { return Duration != 1f; } return true; } } } private sealed class Original { public float Food; public float Stamina; public float Eitr; public float Regen; } [HarmonyPatch(typeof(Player), "EatFood")] private static class EatFoodPatch { private static void Prefix(Player __instance, ItemData item, out List<SharedData> __state) { __state = new List<SharedData>(); if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer && item != null) { Boost(item.m_shared, Current(), __state); } } private static void Postfix(Player __instance, ItemData item, bool __result, List<Food> ___m_foods) { if (!__result || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || item?.m_shared == null) { return; } float duration = Current().Duration; if (duration == 1f) { return; } foreach (Food ___m_food in ___m_foods) { if (___m_food.m_item?.m_shared?.m_name == item.m_shared.m_name && ___m_food.m_time > 0f) { ___m_food.m_time *= duration; } } } private static Exception Finalizer(Exception __exception, List<SharedData> __state) { Restore(__state); return __exception; } } [HarmonyPatch(typeof(Player), "UpdateFood")] private static class UpdateFoodPatch { private static void Prefix(Player __instance, List<Food> ___m_foods, out List<SharedData> __state) { __state = new List<SharedData>(); if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || ___m_foods == null) { return; } Factors f = Current(); if (!f.Any) { return; } foreach (Food ___m_food in ___m_foods) { Boost(___m_food?.m_item?.m_shared, f, __state); } } private static Exception Finalizer(Exception __exception, List<SharedData> __state) { Restore(__state); return __exception; } } [HarmonyPatch(typeof(Player), "GetTotalFoodValue")] private static class TotalFoodPatch { private static void Postfix(Player __instance, List<Food> ___m_foods, ref float hp, ref float stamina, ref float eitr) { if (!_disableDecay.Value || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || ___m_foods == null || ___m_foods.Count == 0) { return; } Factors factors = Current(); foreach (Food ___m_food in ___m_foods) { SharedData val = ___m_food?.m_item?.m_shared; if (val != null) { hp += Boosted(OriginalFood(val), factors.Health) - ___m_food.m_health; stamina += Boosted(OriginalStamina(val), factors.Stamina) - ___m_food.m_stamina; eitr += Boosted(OriginalEitr(val), factors.Eitr) - ___m_food.m_eitr; } } } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] private static class DoCraftingPatch { private static void Prefix(InventoryGui __instance, Player player, out int __state) { __state = -1; _craftingFood = false; _cookingRaised = false; ItemData val = CraftRecipe.Invoke(__instance)?.m_item?.m_itemData; if (!((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer) && IsFood(val?.m_shared)) { _craftingFood = true; __state = ((Humanoid)player).GetInventory().CountItems(val.m_shared.m_name, -1, true); } } private static void Postfix(InventoryGui __instance, Player player, int __state) { if (_logXp.Value) { ItemData val = CraftRecipe.Invoke(__instance)?.m_item?.m_itemData; _log.LogInfo((object)($"[XP] DoCrafting {val?.m_shared?.m_name}: food={_craftingFood} raised={_cookingRaised} " + $"before={__state} after={((val == null || (Object)(object)player == (Object)null) ? (-1) : ((Humanoid)player).GetInventory().CountItems(val.m_shared.m_name, -1, true))} " + "lcfspExecuting=" + LcfspExecuting())); } if (_craftingFood && !_cookingRaised && __state >= 0 && !((Object)(object)player == (Object)null)) { ItemData val2 = CraftRecipe.Invoke(__instance)?.m_item?.m_itemData; if (val2 != null && ((Humanoid)player).GetInventory().CountItems(val2.m_shared.m_name, -1, true) > __state) { ((Character)player).RaiseSkill((SkillType)105, (float)((!MultiCrafting.Invoke(__instance)) ? 1 : __instance.m_multiCraftAmount)); } } } private static Exception Finalizer(Exception __exception) { _craftingFood = false; _cookingRaised = false; return __exception; } } [HarmonyPatch(typeof(Player), "RaiseSkill")] private static class RaiseSkillPatch { [HarmonyPriority(800)] private static void Prefix(Player __instance, ref SkillType skill) { if (_craftingFood && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { skill = (SkillType)105; _cookingRaised = true; } } } [HarmonyPatch(typeof(Player), "RaiseSkill")] private static class RaiseSkillLogPatch { [HarmonyPriority(0)] private static void Prefix(Player __instance, SkillType skill, float value) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 if (_logXp.Value && (int)skill == 105 && (Object)(object)__instance == (Object)(object)Player.m_localPlayer) { _log.LogInfo((object)$"[XP] Player.RaiseSkill Cooking value={value:0.##} craftingFood={_craftingFood}"); } } } [HarmonyPatch(typeof(Skills), "RaiseSkill")] private static class SkillsRaiseLogPatch { private static void Postfix(Skills __instance, SkillType skillType) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 if (_logXp.Value && (int)skillType == 105) { Skill value = Traverse.Create((object)__instance).Method("GetSkill", new object[1] { (object)(SkillType)105 }).GetValue<Skill>(); if (value != null) { _log.LogInfo((object)$"[XP] Cooking now level {value.m_level:0} + {value.m_accumulator:0.##} XP"); } } } } [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(ItemData), typeof(int), typeof(bool), typeof(float), typeof(int), typeof(bool) })] private static class TooltipPatch { private static void Postfix(ItemData item, bool crafting, bool appending, ref string __result) { if (appending || string.IsNullOrEmpty(__result) || (Object)(object)Player.m_localPlayer == (Object)null) { return; } SharedData val = item?.m_shared; if (IsFood(val)) { Factors factors = Current(); if (factors.Any) { __result = Line(__result, "(\\$item_food_health: <color=#ff8080ff>)([^<]*)(</color>)", OriginalFood(val), factors.Health, crafting); __result = Line(__result, "(\\$item_food_stamina: <color=#ffff80ff>)([^<]*)(</color>)", OriginalStamina(val), factors.Stamina, crafting); __result = Line(__result, "(\\$item_food_eitr: <color=#9090ffff>)([^<]*)(</color>)", OriginalEitr(val), factors.Eitr, crafting); __result = RegenLine(__result, Boosted_.TryGetValue(val, out var value) ? value.Regen : val.m_foodRegen, factors.Regen, crafting); __result = DurationLine(__result, val.m_foodBurnTime, factors.Duration, crafting); } } } private static string Number(float v) { return v.ToString("0.#", CultureInfo.InvariantCulture); } private static string Bonus(string text) { return " <color=#80ff80ff>+" + text + "</color>"; } private static string Line(string tooltip, string pattern, float value, float factor, bool crafting) { if (value <= 0f || factor == 1f) { return tooltip; } float num = Boosted(value, factor); string replacement = (crafting ? (Number(value) + "</color>" + Bonus(Number(num - value))) : (Number(num) + "</color>")); return new Regex(pattern).Replace(tooltip, (Match m) => m.Groups[1].Value + replacement, 1); } private static string RegenLine(string tooltip, float value, float factor, bool crafting) { if (value <= 0f || factor == 1f) { return tooltip; } float num = Boosted(value, factor); string replacement = (crafting ? (Number(value) + " hp/tick</color>" + Bonus(Number(num - value))) : (Number(num) + " hp/tick</color>")); return new Regex("(\\$item_food_regen: <color=orange>)([^<]*)( hp/tick</color>)").Replace(tooltip, (Match m) => m.Groups[1].Value + replacement, 1); } private static string DurationLine(string tooltip, float burnTime, float factor, bool crafting) { if (burnTime <= 0f || factor == 1f) { return tooltip; } float num = burnTime * factor; string replacement = (crafting ? (ItemData.GetDurationString(burnTime) + "</color>" + Bonus(ItemData.GetDurationString(num - burnTime))) : (ItemData.GetDurationString(num) + "</color>")); return new Regex("(\\$item_food_duration: <color=orange>)([^<]*)(</color>)").Replace(tooltip, (Match m) => m.Groups[1].Value + replacement, 1); } } public const string Guid = "pieter.valheim.mastercookingfixes"; public const string Name = "MasterCooking Fixes"; public const string Version = "1.1.2"; private const string MasterCookingGuid = "com.ruijven.mastercooking"; private static ConfigEntry<float> _health; private static ConfigEntry<float> _stamina; private static ConfigEntry<float> _regen; private static ConfigEntry<float> _eitr; private static ConfigEntry<float> _duration; private static ConfigEntry<bool> _disableDecay; private static ConfigEntry<bool> _logXp; private static ManualLogSource _log; private static readonly Dictionary<SharedData, Original> Boosted_ = new Dictionary<SharedData, Original>(); private static readonly FieldRef<InventoryGui, Recipe> CraftRecipe = AccessTools.FieldRefAccess<InventoryGui, Recipe>("m_craftRecipe"); private static readonly FieldRef<InventoryGui, bool> MultiCrafting = AccessTools.FieldRefAccess<InventoryGui, bool>("m_multiCrafting"); private static bool _craftingFood; private static bool _cookingRaised; private void Awake() { //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Expected O, but got Unknown Type type = AccessTools.TypeByName("MasterCooking.MasterCookingPlugin"); _health = Entry<float>(type, "HealthFactor"); _stamina = Entry<float>(type, "StaminaFactor"); _regen = Entry<float>(type, "RegenFactor"); _eitr = Entry<float>(type, "EitrFactor"); _duration = Entry<float>(type, "DurationFactor"); _disableDecay = Entry<bool>(type, "DisableStatDecay"); if (_health == null || _stamina == null || _regen == null || _eitr == null || _duration == null || _disableDecay == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"Disabled, MasterCooking's settings were not found."); return; } _log = ((BaseUnityPlugin)this).Logger; _logXp = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Log Cooking XP", false, "Writes every crafted food and Cooking XP gain to the BepInEx log."); Harmony val = new Harmony("pieter.valheim.mastercookingfixes"); string[] array = new string[3] { "EatFood", "UpdateFood", "GetTotalFoodValue" }; foreach (string text in array) { val.Unpatch((MethodBase)AccessTools.Method(typeof(Player), text, (Type[])null, (Type[])null), (HarmonyPatchType)0, "com.ruijven.mastercooking"); } val.PatchAll(typeof(Plugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Replaced MasterCooking's food hooks; regen and tooltips include the Cooking bonus; crafting food trains Cooking."); } private static ConfigEntry<T> Entry<T>(Type type, string field) { if (!(type == null)) { return AccessTools.Field(type, field)?.GetValue(null) as ConfigEntry<T>; } return null; } private static Factors Current() { Player localPlayer = Player.m_localPlayer; float num = (((Object)(object)localPlayer == (Object)null) ? 0f : Mathf.Clamp01(((Character)localPlayer).GetSkillLevel((SkillType)105) / 100f)); return new Factors { Health = 1f + num * (_health.Value - 1f), Stamina = 1f + num * (_stamina.Value - 1f), Regen = 1f + num * (_regen.Value - 1f), Eitr = 1f + num * (_eitr.Value - 1f), Duration = 1f + num * (_duration.Value - 1f) }; } private static bool IsFood(SharedData s) { if (s != null) { if (!(s.m_food > 0f) && !(s.m_foodStamina > 0f)) { return s.m_foodEitr > 0f; } return true; } return false; } private static float Boosted(float value, float factor) { return Mathf.Round(value * factor * 10f) / 10f; } private static void Boost(SharedData s, Factors f, List<SharedData> owned) { if (IsFood(s) && !Boosted_.ContainsKey(s)) { Boosted_[s] = new Original { Food = s.m_food, Stamina = s.m_foodStamina, Eitr = s.m_foodEitr, Regen = s.m_foodRegen }; s.m_food = Boosted(s.m_food, f.Health); s.m_foodStamina = Boosted(s.m_foodStamina, f.Stamina); s.m_foodEitr = Boosted(s.m_foodEitr, f.Eitr); s.m_foodRegen = Boosted(s.m_foodRegen, f.Regen); owned.Add(s); } } private static void Restore(List<SharedData> owned) { if (owned == null) { return; } foreach (SharedData item in owned) { if (Boosted_.TryGetValue(item, out var value)) { item.m_food = value.Food; item.m_foodStamina = value.Stamina; item.m_foodEitr = value.Eitr; item.m_foodRegen = value.Regen; Boosted_.Remove(item); } } } private static float OriginalFood(SharedData s) { if (!Boosted_.TryGetValue(s, out var value)) { return s.m_food; } return value.Food; } private static float OriginalStamina(SharedData s) { if (!Boosted_.TryGetValue(s, out var value)) { return s.m_foodStamina; } return value.Stamina; } private static float OriginalEitr(SharedData s) { if (!Boosted_.TryGetValue(s, out var value)) { return s.m_foodEitr; } return value.Eitr; } private static string LcfspExecuting() { Type type = AccessTools.TypeByName("LocalCraftFromStoragePrime.PaymentAction"); FieldInfo fieldInfo = ((type == null) ? null : AccessTools.Field(type, "Executing")); if (!(fieldInfo == null)) { return (fieldInfo.GetValue(null) != null).ToString(); } return "n/a"; } } }