Decompiled source of DropSingleItem v1.2.1

plugins\DropSingleItem.dll

Decompiled 10 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
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: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.2.1")]
[assembly: AssemblyInformationalVersion("1.0.0+57d9ddb874359d5fc5ab99d249522b80311a94b2")]
[assembly: AssemblyVersion("1.2.1.0")]
namespace DropSingleItem
{
	[BepInPlugin("TechGuard.DropSingleItem", "DropSingleItem", "1.2.1")]
	[BepInProcess("valheim.exe")]
	public class DropSingleItemMod : BaseUnityPlugin
	{
		private const string NAME = "DropSingleItem";

		private const string GUID = "TechGuard.DropSingleItem";

		private const string VERSION = "1.2.1";

		private readonly Harmony harmony = new Harmony("TechGuard.DropSingleItem");

		private static ConfigEntry<string> InventoryUseItemKeyCodeConfig;

		public static KeyCode InventoryUseItemKeyCode
		{
			get
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				if (Enum.TryParse<KeyCode>(InventoryUseItemKeyCodeConfig.Value, out KeyCode result))
				{
					return result;
				}
				return (KeyCode)324;
			}
		}

		public void Awake()
		{
			InventoryUseItemKeyCodeConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Input", "InventoryUseItem", "Mouse1", "Keybinding for using/consuming/equipping an item in the inventory (Mouse1 = right mouse button).\nIf this is set to anything other than Mouse1, you no longer have to hold shift to split a stack when right clicking.\nAvailable KeyCodes can be found here: https://docs.unity3d.com/ScriptReference/KeyCode.html");
			harmony.PatchAll();
		}
	}
}
namespace DropSingleItem.Patch
{
	[HarmonyPatch(typeof(InventoryGui), "Update")]
	internal class InventoryGui_Update_DropSingleOutside
	{
		public static void Postfix(InventoryGui __instance)
		{
			if (InventoryGui.IsVisible() && !((Object)(object)__instance.dragGo() == (Object)null) && ZInput.GetMouseButtonDown(1) && !Utils.PointerOverInventoryGrid(__instance))
			{
				Utils.DropOneOutside(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "OnSelectedItem")]
	internal class InventoryGui_OnSelectedItem_GrabFullStack
	{
		private const float DoubleClickThreshold = 0.3f;

		private static float LastItemClickedTime = -1f;

		public static bool Prefix(InventoryGui __instance, InventoryGrid grid, ItemData item, Vector2i pos, Modifier mod)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			if ((int)mod != 0)
			{
				return true;
			}
			bool num = LastItemClickedTime >= 0f && Time.unscaledTime - LastItemClickedTime < 0.3f;
			LastItemClickedTime = Time.unscaledTime;
			if (!num)
			{
				return true;
			}
			ItemData val = item;
			Inventory val2 = (((Object)(object)grid != (Object)null) ? grid.GetInventory() : null);
			if (val == null && __instance.dragItem() != null)
			{
				val = __instance.dragItem();
				val2 = __instance.dragInventory();
			}
			if (val == null || val2 == null)
			{
				return true;
			}
			Utils.MergeMatchingIntoSlot(__instance, val2, val);
			return false;
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "OnRightClickItem")]
	internal class InventoryGui_OnRightClickItem
	{
		public static bool Prefix(InventoryGui __instance, ref int ___m_dragAmount, InventoryGrid grid, ItemData item, Vector2i pos)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Invalid comparison between Unknown and I4
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			bool flag = (Object)(object)__instance.dragGo() != (Object)null;
			bool flag2 = (int)DropSingleItemMod.InventoryUseItemKeyCode == 324;
			bool flag3 = flag2 && Utils.IsShiftHeld();
			if (!flag2 || flag3)
			{
				if (!flag && item != null && item.m_stack > 1)
				{
					if (Utils.TrySplitStackIntoEmptySlot(grid.GetInventory(), item))
					{
						Utils.PlayMoveEffects(__instance);
					}
					return false;
				}
				if (flag3)
				{
					return false;
				}
			}
			if (!flag)
			{
				return flag2;
			}
			ItemData val = __instance.dragItem();
			if (!Utils.CanStackItem(val, item))
			{
				return false;
			}
			Inventory val2 = __instance.dragInventory();
			int num = __instance.dragAmount();
			int stack = val.m_stack;
			___m_dragAmount = 1;
			__instance.OnSelectedItem(grid, item, pos, (Modifier)0);
			num -= stack - val.m_stack;
			if (num > 0 && val != null && val2 != null && val2.ContainsItem(val))
			{
				__instance.SetupDragItem(val, val2, num);
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(InventoryGrid), "UpdateInventory")]
	internal class InventoryGrid_UpdateInventory
	{
		public static void Postfix(InventoryGrid __instance, Inventory inventory, Player player, ItemData dragItem)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Invalid comparison between Unknown and I4
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: 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)
			if ((int)DropSingleItemMod.InventoryUseItemKeyCode != 324 && dragItem == null && ZInput.GetKeyDown(DropSingleItemMod.InventoryUseItemKeyCode, true))
			{
				ItemData item = __instance.GetItem(new Vector2i(ZInput.pointerPosition));
				if (item != null && Object.op_Implicit((Object)(object)Player.m_localPlayer))
				{
					((Humanoid)Player.m_localPlayer).UseItem(inventory, item, true);
				}
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "UpdateItemDrag")]
	internal class InventoryGui_UpdateItemDrag
	{
		public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			MethodInfo method = typeof(ZInput).GetMethod("GetMouseButton", new Type[1] { typeof(int) });
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			for (int i = 1; i < list.Count; i++)
			{
				if (list[i - 1].opcode == OpCodes.Ldc_I4_1 && CodeInstructionExtensions.Calls(list[i], method))
				{
					list[i - 1] = new CodeInstruction(OpCodes.Nop, (object)null);
					list[i] = new CodeInstruction(OpCodes.Ldc_I4_S, (object)0);
				}
			}
			return list.AsEnumerable();
		}
	}
	internal class Utils
	{
		public static bool IsShiftHeld()
		{
			if (!ZInput.GetKey((KeyCode)304, true))
			{
				return ZInput.GetKey((KeyCode)303, true);
			}
			return true;
		}

		public static bool CanStackItem(ItemData a, ItemData b)
		{
			if (a == null || b == null)
			{
				return true;
			}
			if (a == b)
			{
				return false;
			}
			if (a.m_shared.m_name != b.m_shared.m_name)
			{
				return false;
			}
			if (a.m_shared.m_maxStackSize == 1 || b.m_shared.m_maxStackSize == 1)
			{
				return false;
			}
			if ((a.m_shared.m_maxQuality > 1 || b.m_shared.m_maxQuality > 1) && a.m_quality != b.m_quality)
			{
				return false;
			}
			return true;
		}

		public static void PlayMoveEffects(InventoryGui instance)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			EffectList val = instance.moveItemEffects();
			if (val != null)
			{
				val.Create(((Component)instance).transform.position, Quaternion.identity, (Transform)null, 1f, -1, ZDOID.None);
			}
		}

		public static bool TrySplitStackIntoEmptySlot(Inventory inventory, ItemData item)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			if (inventory == null || item == null || item.m_stack < 2 || !inventory.HaveEmptySlot())
			{
				return false;
			}
			Vector2i value = Traverse.Create((object)inventory).Method("FindEmptySlot", new Type[1] { typeof(bool) }, (object[])null).GetValue<Vector2i>(new object[1] { true });
			if (value.x < 0 || value.y < 0)
			{
				return false;
			}
			int num = item.m_stack / 2;
			return inventory.MoveItemToThis(inventory, item, num, value.x, value.y);
		}

		public static void MergeMatchingIntoSlot(InventoryGui gui, Inventory targetInventory, ItemData target)
		{
			if (!((Object)(object)gui == (Object)null) && targetInventory != null && target != null && !((Object)(object)Player.m_localPlayer == (Object)null))
			{
				int stack = target.m_stack;
				Container val = gui.currentContainer();
				if ((Object)(object)val != (Object)null)
				{
					MergeMatchingStacksInto(targetInventory, target, val.GetInventory());
				}
				MergeMatchingStacksInto(targetInventory, target, ((Humanoid)Player.m_localPlayer).GetInventory());
				if (target.m_stack != stack)
				{
					PlayMoveEffects(gui);
				}
				gui.SetupDragItem(null, null, 1);
				gui.UpdateCraftingPanel();
			}
		}

		private static void MergeMatchingStacksInto(Inventory targetInventory, ItemData target, Inventory source)
		{
			if (source == null || target == null || target.m_shared == null)
			{
				return;
			}
			List<ItemData> list = new List<ItemData>();
			source.GetAllItems(target.m_shared.m_name, list);
			while (list.Any() && target.m_stack < target.m_shared.m_maxStackSize)
			{
				ItemData val = list.Last();
				list.RemoveAt(list.Count - 1);
				if (CanStackItem(target, val))
				{
					targetInventory.MoveItemToThis(source, val, val.m_stack, target.m_gridPos.x, target.m_gridPos.y);
				}
			}
		}

		public static bool PointerOverInventoryGrid(InventoryGui gui)
		{
			if (!ContainsPointer((Component)(object)gui.playerGrid()))
			{
				return ContainsPointer((Component)(object)gui.containerGrid());
			}
			return true;
		}

		private static bool ContainsPointer(Component component)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)component == (Object)null)
			{
				return false;
			}
			Transform transform = component.transform;
			RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			Canvas componentInParent = component.GetComponentInParent<Canvas>();
			Camera val2 = null;
			if ((Object)(object)componentInParent != (Object)null && (int)componentInParent.renderMode != 0)
			{
				val2 = componentInParent.worldCamera;
			}
			return RectTransformUtility.RectangleContainsScreenPoint(val, Vector2.op_Implicit(ZInput.pointerPosition), val2);
		}

		public static void DropOneOutside(InventoryGui gui)
		{
			if ((Object)(object)gui == (Object)null || (Object)(object)gui.dragGo() == (Object)null)
			{
				return;
			}
			ItemData val = gui.dragItem();
			Inventory val2 = gui.dragInventory();
			if (val == null || val2 == null || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return;
			}
			int num = gui.dragAmount();
			int stack = val.m_stack;
			if (!val2.ContainsItem(val))
			{
				gui.SetupDragItem(null, null, 1);
			}
			else if (((Humanoid)Player.m_localPlayer).DropItem(val2, val, 1))
			{
				PlayMoveEffects(gui);
				num -= stack - val.m_stack;
				if (val2.ContainsItem(val) && num > 0)
				{
					gui.SetupDragItem(val, val2, num);
				}
				else
				{
					gui.SetupDragItem(null, null, 1);
				}
				gui.UpdateCraftingPanel();
			}
		}
	}
	internal static class InventoryGui_Extensions
	{
		public static void SetupDragItem(this InventoryGui instance, ItemData item, Inventory inventory, int amount)
		{
			Traverse.Create((object)instance).Method("SetupDragItem", new Type[3]
			{
				typeof(ItemData),
				typeof(Inventory),
				typeof(int)
			}, (object[])null).GetValue(new object[3] { item, inventory, amount });
		}

		public static void UpdateCraftingPanel(this InventoryGui instance, bool focusView = false)
		{
			Traverse.Create((object)instance).Method("UpdateCraftingPanel", new Type[1] { typeof(bool) }, (object[])null).GetValue(new object[1] { focusView });
		}

		public static void OnSelectedItem(this InventoryGui instance, InventoryGrid grid, ItemData item, Vector2i pos, Modifier mod)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			Traverse.Create((object)instance).Method("OnSelectedItem", new Type[4]
			{
				typeof(InventoryGrid),
				typeof(ItemData),
				typeof(Vector2i),
				typeof(Modifier)
			}, (object[])null).GetValue(new object[4] { grid, item, pos, mod });
		}

		public static EffectList moveItemEffects(this InventoryGui instance)
		{
			return Traverse.Create((object)instance).Field("m_moveItemEffects").GetValue<EffectList>();
		}

		public static GameObject dragGo(this InventoryGui instance)
		{
			return Traverse.Create((object)instance).Field("m_dragGo").GetValue<GameObject>();
		}

		public static ItemData dragItem(this InventoryGui instance)
		{
			return Traverse.Create((object)instance).Field("m_dragItem").GetValue<ItemData>();
		}

		public static Inventory dragInventory(this InventoryGui instance)
		{
			return Traverse.Create((object)instance).Field("m_dragInventory").GetValue<Inventory>();
		}

		public static int dragAmount(this InventoryGui instance)
		{
			return Traverse.Create((object)instance).Field("m_dragAmount").GetValue<int>();
		}

		public static Container currentContainer(this InventoryGui instance)
		{
			return Traverse.Create((object)instance).Field("m_currentContainer").GetValue<Container>();
		}

		public static InventoryGrid playerGrid(this InventoryGui instance)
		{
			return Traverse.Create((object)instance).Field("m_playerGrid").GetValue<InventoryGrid>();
		}

		public static InventoryGrid containerGrid(this InventoryGui instance)
		{
			return Traverse.Create((object)instance).Field("m_containerGrid").GetValue<InventoryGrid>();
		}
	}
}