Decompiled source of TakeAllCooked v1.1.0

TakeAllCooked.dll

Decompiled 4 days ago
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<bool> EnableMod;

		internal static ConfigEntry<bool> DebugLogging;

		internal static ConfigEntry<KeyboardShortcut> TakeAllShortcut;

		internal static ConfigEntry<string> HoverText;

		internal static ConfigEntry<bool> EnableNearbyStations;

		internal static ConfigEntry<float> NearbyStationRadius;

		internal static ConfigEntry<int> 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<bool>("General", "EnableMod", true, "Enable or disable the mod.");
			DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugLogging", false, "Enable debug logging.");
			TakeAllShortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("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<string>("UI", "HoverText", "Take all cooked", "Text shown in the cooking station hover prompt.");
			EnableNearbyStations = ((BaseUnityPlugin)this).Config.Bind<bool>("Nearby Stations", "EnableNearbyStations", true, "If enabled, the shortcut also collects finished outputs from nearby cooking stations.");
			NearbyStationRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Nearby Stations", "NearbyStationRadius", 4f, "Radius in meters used to find nearby cooking stations.");
			MaxNearbyStations = ((BaseUnityPlugin)this).Config.Bind<int>("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<bool> 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[<color=yellow><b>" + shortcutDisplayText + "</b></color>] " + 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<CookingStation> 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<CookingStation> 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<CookingStation> list = new List<CookingStation>();
			if ((Object)(object)origin == (Object)null)
			{
				return list;
			}
			list.Add(origin);
			ConfigEntry<bool> 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<CookingStation>((FindObjectsSortMode)0);
			List<CookingStationDistance> list2 = new List<CookingStationDistance>();
			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;
		}
	}
}