using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("TakeAllCooked")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("TakeAllCooked")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("98f7bdb2-540a-4bcb-8ec9-144aeba4e630")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace TakeAllCooked { [BepInPlugin("petri.valheim.takeallcooked", "Take All Cooked", "1.1.0")] public class Plugin : BaseUnityPlugin { public const string ModGuid = "petri.valheim.takeallcooked"; public const string ModName = "Take All Cooked"; public const string ModVersion = "1.1.0"; internal static ManualLogSource Log; private Harmony _harmony; internal static ConfigEntry EnableMod; internal static ConfigEntry DebugLogging; internal static ConfigEntry TakeAllShortcut; internal static ConfigEntry HoverText; internal static ConfigEntry EnableNearbyStations; internal static ConfigEntry NearbyStationRadius; internal static ConfigEntry MaxNearbyStations; private void Awake() { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; EnableMod = ((BaseUnityPlugin)this).Config.Bind("General", "EnableMod", true, "Enable or disable the mod."); DebugLogging = ((BaseUnityPlugin)this).Config.Bind("General", "DebugLogging", false, "Enable debug logging."); TakeAllShortcut = ((BaseUnityPlugin)this).Config.Bind("Controls", "TakeAllShortcut", new KeyboardShortcut((KeyCode)101, (KeyCode[])(object)new KeyCode[1] { (KeyCode)304 }), "Shortcut used to take all finished outputs from cooking stations."); HoverText = ((BaseUnityPlugin)this).Config.Bind("UI", "HoverText", "Take all cooked", "Text shown in the cooking station hover prompt."); EnableNearbyStations = ((BaseUnityPlugin)this).Config.Bind("Nearby Stations", "EnableNearbyStations", true, "If enabled, the shortcut also collects finished outputs from nearby cooking stations."); NearbyStationRadius = ((BaseUnityPlugin)this).Config.Bind("Nearby Stations", "NearbyStationRadius", 4f, "Radius in meters used to find nearby cooking stations."); MaxNearbyStations = ((BaseUnityPlugin)this).Config.Bind("Nearby Stations", "MaxNearbyStations", 5, "Maximum number of cooking stations processed per shortcut press, including the hovered station."); _harmony = new Harmony("petri.valheim.takeallcooked"); _harmony.PatchAll(); Log.LogInfo((object)"Take All Cooked 1.1.0 loaded."); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } internal static void DebugLog(string message) { ConfigEntry debugLogging = DebugLogging; if (debugLogging != null && debugLogging.Value) { Log.LogInfo((object)message); } } } } namespace TakeAllCooked.Patches { [HarmonyPatch(typeof(CookingStation), "GetHoverText")] public static class CookingStationHoverTextPatch { private static void Postfix(CookingStation __instance, ref string __result) { if (Plugin.EnableMod.Value && !string.IsNullOrEmpty(__result) && HasAnyDoneItem(__instance)) { string shortcutDisplayText = GetShortcutDisplayText(); __result = __result + "\n[" + shortcutDisplayText + "] " + Plugin.HoverText.Value; } } private static bool HasAnyDoneItem(CookingStation station) { return CookingStationInteractPatch.CountDoneSlots(station) > 0; } private static string GetShortcutDisplayText() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Invalid comparison between Unknown and I4 //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) KeyboardShortcut value = Plugin.TakeAllShortcut.Value; if ((int)((KeyboardShortcut)(ref value)).MainKey == 0) { return "Unbound"; } string text = ((object)((KeyboardShortcut)(ref value)).MainKey/*cast due to .constrained prefix*/).ToString(); foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers) { text = $"{modifier}+{text}"; } return text.Replace("LeftShift", "LShift").Replace("RightShift", "RShift").Replace("LeftControl", "LCtrl") .Replace("RightControl", "RCtrl") .Replace("LeftAlt", "LAlt") .Replace("RightAlt", "RAlt"); } } [HarmonyPatch(typeof(CookingStation), "Interact")] public static class CookingStationInteractPatch { private sealed class SlotData { public string ItemName; public float CookedTime; public object Status; } private sealed class CookingStationDistance { public CookingStation Station; public float Distance; } private static readonly FieldInfo NViewField = typeof(CookingStation).GetField("m_nview", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly MethodInfo GetSlotMethod = typeof(CookingStation).GetMethod("GetSlot", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly MethodInfo IsItemDoneMethod = typeof(CookingStation).GetMethod("IsItemDone", BindingFlags.Instance | BindingFlags.NonPublic); private static bool Prefix(CookingStation __instance, Humanoid user, bool hold, bool alt, ref bool __result) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.EnableMod.Value) { return true; } if (hold || (Object)(object)user == (Object)null) { return true; } KeyboardShortcut value = Plugin.TakeAllShortcut.Value; if (!((KeyboardShortcut)(ref value)).IsPressed()) { return true; } List targetStations = GetTargetStations(__instance); int num = 0; foreach (CookingStation item in targetStations) { num += CountDoneSlots(item); } if (num <= 0) { Plugin.DebugLog("TakeAllCooked: no finished outputs found, allowing vanilla interaction."); return true; } int num2 = 0; int num3 = 0; foreach (CookingStation item2 in targetStations) { int num4 = CountDoneSlots(item2); if (num4 > 0) { num3++; int num5 = TakeAllDoneItems(item2, user, num4); num2 += num5; Plugin.DebugLog($"TakeAllCooked: removed {num5} finished output(s) from station {((Object)item2).name}."); } } Plugin.DebugLog($"TakeAllCooked: removed {num2} finished output(s) from {num3} station(s) with ready output(s)."); __result = num2 > 0; return false; } internal static int CountDoneSlots(CookingStation station) { if (station?.m_slots == null || GetSlotMethod == null || IsItemDoneMethod == null) { return 0; } int num = 0; for (int i = 0; i < station.m_slots.Length; i++) { SlotData slot = GetSlot(station, i); if (!string.IsNullOrEmpty(slot.ItemName) && IsItemDone(station, slot.ItemName)) { num++; } } return num; } internal static int TakeAllDoneItems(CookingStation station, Humanoid user, int readySlots) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) object? obj = NViewField?.GetValue(station); ZNetView val = (ZNetView)((obj is ZNetView) ? obj : null); if ((Object)(object)val == (Object)null || !val.IsValid()) { Plugin.DebugLog("TakeAllCooked: missing or invalid ZNetView."); return 0; } int num = 0; for (int i = 0; i < readySlots; i++) { int pickupAmount = GetPickupAmount(station); val.InvokeRPC("RPC_RemoveDoneItem", new object[2] { ((Component)user).transform.position, pickupAmount }); num++; } return num; } private static int GetPickupAmount(CookingStation station) { //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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return 1; } ((Character)localPlayer).RaiseSkill((SkillType)105, 0.6f); int num = 1; if ((Object)(object)InventoryGui.instance == (Object)null) { return num; } float skillFactor = ((Character)localPlayer).GetSkillFactor((SkillType)105); float num2 = skillFactor * InventoryGui.instance.m_craftBonusChance; if (Random.value < num2) { num += InventoryGui.instance.m_craftBonusAmount; DamageText instance = DamageText.instance; if (instance != null) { instance.ShowText((TextType)7, ((Component)station).transform.position + Vector3.up, "+" + InventoryGui.instance.m_craftBonusAmount, true); } InventoryGui.instance.m_craftBonusEffect.Create(((Component)station).transform.position, Quaternion.identity, (Transform)null, 1f, -1); Plugin.DebugLog("TakeAllCooked: bonus food cooking station!"); } return num; } private static SlotData GetSlot(CookingStation station, int slot) { object[] array = new object[4] { slot, null, 0f, null }; GetSlotMethod.Invoke(station, array); SlotData slotData = new SlotData(); slotData.ItemName = (array[1] as string) ?? string.Empty; slotData.CookedTime = ((array[2] is float num) ? num : 0f); slotData.Status = array[3]; return slotData; } private static bool IsItemDone(CookingStation station, string itemName) { object obj = IsItemDoneMethod.Invoke(station, new object[1] { itemName }); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } private static List GetTargetStations(CookingStation origin) { //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) List list = new List(); if ((Object)(object)origin == (Object)null) { return list; } list.Add(origin); ConfigEntry enableNearbyStations = Plugin.EnableNearbyStations; if (enableNearbyStations == null || !enableNearbyStations.Value) { return list; } float num = Mathf.Max(0f, Plugin.NearbyStationRadius.Value); int num2 = Mathf.Max(1, Plugin.MaxNearbyStations.Value); if (num <= 0f || num2 <= 1) { return list; } CookingStation[] array = Object.FindObjectsByType((FindObjectsSortMode)0); List list2 = new List(); CookingStation[] array2 = array; foreach (CookingStation val in array2) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)origin)) { float num3 = Vector3.Distance(((Component)origin).transform.position, ((Component)val).transform.position); if (!(num3 > num)) { list2.Add(new CookingStationDistance { Station = val, Distance = num3 }); } } } list2.Sort((CookingStationDistance a, CookingStationDistance b) => a.Distance.CompareTo(b.Distance)); foreach (CookingStationDistance item in list2) { if (list.Count >= num2) { break; } list.Add(item.Station); } Plugin.DebugLog($"TakeAllCooked: found {list.Count} target cooking station(s)."); return list; } } }