Decompiled source of Restock v0.1.0

plugins/Restock.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Restock")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Restock")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: AssemblyFileVersion("0.1.0")]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
namespace Restock
{
	internal enum SelectionMode
	{
		Click,
		Hover,
		Both
	}
	[BepInPlugin("orax.Restock", "Restock", "0.1.0")]
	internal class Restock : BaseUnityPlugin
	{
		public const string PluginGUID = "orax.Restock";

		public const string PluginName = "Restock";

		public const string PluginVersion = "0.1.0";

		private const string MessageHint = " Leave it empty to disable the message.";

		internal static ManualLogSource Log { get; private set; }

		internal static Restock Instance { get; private set; }

		internal ConfigEntry<KeyboardShortcut> Hotkey { get; private set; }

		internal ConfigEntry<string> MessageNothingSelected { get; private set; }

		internal ConfigEntry<string> MessageNoMatchingItems { get; private set; }

		internal ConfigEntry<string> MessageNoSpace { get; private set; }

		internal ConfigEntry<string> MessageTooHeavy { get; private set; }

		internal ConfigEntry<bool> DeselectAfterRestock { get; private set; }

		internal ConfigEntry<SelectionMode> ItemSelectionMode { get; private set; }

		private void Awake()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			Hotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Input", "Hotkey", new KeyboardShortcut((KeyCode)114, (KeyCode[])(object)new KeyCode[1] { (KeyCode)304 }), "Key combination pressed while a container is open to pull the items matching the selected one into the player inventory. The main key is written first and the modifiers after it: R + LeftShift is the combination Shift + R. A single key (B) works too, and None disables the hotkey.");
			DeselectAfterRestock = ((BaseUnityPlugin)this).Config.Bind<bool>("Behaviour", "DeselectAfterRestock", true, "Put the selection down when the restock key is pressed, whatever the outcome: the item stays where it was and the next press needs a new selection. Set it to false to keep the selection and press the key again right away.");
			ItemSelectionMode = ((BaseUnityPlugin)this).Config.Bind<SelectionMode>("Behaviour", "SelectionMode", SelectionMode.Both, "How the item to restock is picked. Click: the item selected with a plain left click. Hover: the item under the mouse cursor when the key is pressed, no click needed. Both: the hovered item when there is one, otherwise the clicked one.");
			MessageNothingSelected = ((BaseUnityPlugin)this).Config.Bind<string>("Messages", "NothingSelected", "Restock: select an item first", "Shown when the hotkey is pressed without a hovered or selected item. Leave it empty to disable the message.");
			MessageNoMatchingItems = ((BaseUnityPlugin)this).Config.Bind<string>("Messages", "NoMatchingItems", "Restock: no matching items in the container", "Shown when the container holds no item identical to the selected one. Leave it empty to disable the message.");
			MessageNoSpace = ((BaseUnityPlugin)this).Config.Bind<string>("Messages", "NoSpace", "Restock: not enough room in your inventory", "Shown when the transfer stops because your inventory has no room left. Leave it empty to disable the message.");
			MessageTooHeavy = ((BaseUnityPlugin)this).Config.Bind<string>("Messages", "TooHeavy", "Restock: that would make you overburdened", "Shown when the transfer stops because it would exceed your maximum carry weight. Leave it empty to disable the message.");
			ManualLogSource log = Log;
			KeyboardShortcut value = Hotkey.Value;
			log.LogInfo((object)("Restock 0.1.0 loaded (hotkey: " + ((KeyboardShortcut)(ref value)).Serialize() + ")"));
		}

		internal bool IsHotkeyPressed()
		{
			//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)
			KeyboardShortcut value = Hotkey.Value;
			return ((KeyboardShortcut)(ref value)).IsDown();
		}

		private void Update()
		{
			Restocker.Update();
		}
	}
	internal static class Restocker
	{
		private enum Result
		{
			Moved,
			NothingSelected,
			NoMatchingItems,
			NoSpace,
			TooHeavy,
			Cancelled
		}

		private static InventoryGui _boundGui;

		private static Container _boundContainer;

		private static ItemData _selected;

		internal static void Update()
		{
			InventoryGui instance = InventoryGui.instance;
			if ((Object)(object)instance == (Object)null)
			{
				ResetState();
				return;
			}
			if (_boundGui != instance)
			{
				Rebind(instance);
			}
			Container currentContainer = instance.m_currentContainer;
			if (_boundContainer != currentContainer)
			{
				_boundContainer = currentContainer;
				_selected = null;
			}
			if ((Object)(object)currentContainer == (Object)null || InventoryGui.WaitForStack() || ((Object)(object)instance.m_splitDialog != (Object)null && instance.m_splitDialog.IsActive) || Console.IsVisible() || TextInput.IsVisible() || ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus()) || !Restock.Instance.IsHotkeyPressed())
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsTeleporting())
			{
				return;
			}
			try
			{
				Result result = RestockFromContainer(instance, localPlayer, currentContainer);
				if (result != Result.Moved && result != Result.Cancelled)
				{
					string text = Message(result);
					if (!string.IsNullOrEmpty(text))
					{
						((Character)localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false);
					}
				}
				if (result != Result.Cancelled && result != Result.NothingSelected && (Object)(object)Restock.Instance != (Object)null && Restock.Instance.DeselectAfterRestock.Value)
				{
					DropSelection(instance);
				}
			}
			catch (Exception arg)
			{
				Restock.Log.LogError((object)$"Restock failed: {arg}");
			}
		}

		private static Result RestockFromContainer(InventoryGui gui, Player player, Container container)
		{
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			_selected = ResolveSelection(gui, player, container);
			if (_selected == null)
			{
				return Result.NothingSelected;
			}
			if (!container.IsOwner())
			{
				Restock.Log.LogWarning((object)"Restock: container is not owned by this player, cancelled");
				return Result.Cancelled;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			Inventory inventory2 = container.GetInventory();
			if (inventory == null || inventory2 == null)
			{
				return Result.Cancelled;
			}
			List<ItemData> list = inventory2.GetAllItems().FindAll((ItemData item) => item != null && item.m_stack > 0 && item.IsSameType(_selected));
			if (list.Count == 0)
			{
				return Result.NoMatchingItems;
			}
			int num = 0;
			int num2 = 0;
			bool flag = false;
			foreach (ItemData item in new List<ItemData>(inventory.GetAllItems()))
			{
				if (flag || num2 >= list.Count)
				{
					break;
				}
				if (!item.IsSameType(_selected))
				{
					continue;
				}
				while (num2 < list.Count && item.m_stack < item.m_shared.m_maxStackSize)
				{
					ItemData val = list[num2];
					int num3 = AllowedUnits(player, inventory, val);
					if (num3 <= 0)
					{
						flag = true;
						break;
					}
					int amount = Math.Min(Math.Min(item.m_shared.m_maxStackSize - item.m_stack, val.m_stack), num3);
					int num4 = Transfer(inventory, inventory2, val, amount, item.m_gridPos);
					if (num4 <= 0)
					{
						break;
					}
					num += num4;
					if (val.m_stack <= 0)
					{
						num2++;
					}
				}
			}
			while (num2 < list.Count && !flag)
			{
				Vector2i val2 = FindFreeSlot(inventory, _selected);
				if (val2.x < 0)
				{
					break;
				}
				ItemData val3 = list[num2];
				int num5 = AllowedUnits(player, inventory, val3);
				if (num5 <= 0)
				{
					flag = true;
					break;
				}
				int amount2 = Math.Min(Math.Min(val3.m_shared.m_maxStackSize, val3.m_stack), num5);
				int num6 = Transfer(inventory, inventory2, val3, amount2, val2);
				if (num6 <= 0)
				{
					break;
				}
				num += num6;
				if (val3.m_stack <= 0)
				{
					num2++;
				}
			}
			if (num <= 0)
			{
				if (!flag)
				{
					return Result.NoSpace;
				}
				return Result.TooHeavy;
			}
			ReleaseStaleDrag(gui);
			gui.m_moveItemEffects.Create(((Component)gui).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
			Restock.Log.LogInfo((object)($"Restocked {num} x {_selected.m_shared.m_name} " + "from '" + inventory2.GetName() + "'"));
			return Result.Moved;
		}

		private static ItemData ResolveSelection(InventoryGui gui, Player player, Container container)
		{
			Restock instance = Restock.Instance;
			SelectionMode selectionMode = ((!((Object)(object)instance == (Object)null)) ? instance.ItemSelectionMode.Value : SelectionMode.Click);
			if (selectionMode == SelectionMode.Click)
			{
				return _selected;
			}
			ItemData val = FindHoveredItem(gui.ContainerGrid, container.GetInventory());
			if (val == null)
			{
				val = FindHoveredItem(gui.m_playerGrid, ((Humanoid)player).GetInventory());
			}
			if (val != null)
			{
				return val;
			}
			if (selectionMode != SelectionMode.Hover)
			{
				return _selected;
			}
			return null;
		}

		private static ItemData FindHoveredItem(InventoryGrid grid, Inventory inventory)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//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)
			//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_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)grid == (Object)null || inventory == null)
			{
				return null;
			}
			foreach (InventoryElement element in grid.m_elements)
			{
				if (!((Object)(object)element == (Object)null))
				{
					RectTransform elementRectTransform = element.GetElementRectTransform();
					Vector2 val = Vector2.op_Implicit(((Transform)elementRectTransform).InverseTransformPoint(ZInput.pointerPosition));
					Rect rect = elementRectTransform.rect;
					if (((Rect)(ref rect)).Contains(val))
					{
						Vector2i position = element.Position;
						return inventory.GetItemAt(position.x, position.y);
					}
				}
			}
			return null;
		}

		private static int AllowedUnits(Player player, Inventory inventory, ItemData item)
		{
			float weight = item.GetWeight(1);
			if (weight <= 0f)
			{
				return int.MaxValue;
			}
			float maxCarryWeight = player.GetMaxCarryWeight();
			float num = maxCarryWeight - inventory.GetTotalWeight();
			if (num <= 0f)
			{
				return 0;
			}
			double num2 = num / weight;
			if (num2 >= 2147483647.0)
			{
				return int.MaxValue;
			}
			int num3 = (int)num2;
			while (num3 > 0 && inventory.GetTotalWeight() + weight * (float)num3 > maxCarryWeight)
			{
				num3--;
			}
			return num3;
		}

		private static int Transfer(Inventory to, Inventory from, ItemData source, int amount, Vector2i pos)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if (amount <= 0)
			{
				return 0;
			}
			int stack = source.m_stack;
			to.MoveItemToThis(from, source, amount, pos.x, pos.y);
			return Math.Max(0, stack - source.m_stack);
		}

		private static Vector2i FindFreeSlot(Inventory inventory, ItemData selected)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Invalid comparison between Unknown and I4
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Invalid comparison between Unknown and I4
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Invalid comparison between Unknown and I4
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Invalid comparison between Unknown and I4
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Invalid comparison between Unknown and I4
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			bool flag = selected.IsWeapon() || (int)selected.m_shared.m_itemType == 19 || (int)selected.m_shared.m_itemType == 5 || (int)selected.m_shared.m_itemType == 18 || (int)selected.m_shared.m_itemType == 16 || (int)selected.m_shared.m_itemType == 24;
			int num = inventory.GetHeight() - 1;
			for (int i = 0; i <= num; i++)
			{
				int num2 = (flag ? i : (num - i));
				for (int j = 0; j < inventory.GetWidth(); j++)
				{
					if (inventory.GetItemAt(j, num2) == null)
					{
						return new Vector2i(j, num2);
					}
				}
			}
			return new Vector2i(-1, -1);
		}

		private static void DropSelection(InventoryGui gui)
		{
			_selected = null;
			ClearDrag(gui);
		}

		private static void ClearDrag(InventoryGui gui)
		{
			if ((Object)(object)gui.m_dragGo != (Object)null)
			{
				Object.Destroy((Object)(object)gui.m_dragGo);
				gui.m_dragGo = null;
			}
			gui.m_dragItem = null;
			gui.m_dragInventory = null;
			gui.m_dragAmount = 0;
		}

		private static void ReleaseStaleDrag(InventoryGui gui)
		{
			ItemData dragItem = gui.m_dragItem;
			if (dragItem != null && gui.m_dragInventory != null && !gui.m_dragInventory.ContainsItem(dragItem))
			{
				ClearDrag(gui);
			}
		}

		private static void Rebind(InventoryGui gui)
		{
			if ((Object)(object)_boundGui != (Object)null && _boundGui != gui)
			{
				Unhook(_boundGui);
			}
			_boundGui = gui;
			_selected = null;
			Hook(gui);
		}

		private static void Hook(InventoryGui gui)
		{
			if ((Object)(object)gui.m_playerGrid != (Object)null)
			{
				InventoryGrid playerGrid = gui.m_playerGrid;
				playerGrid.m_onSelected = (Action<InventoryGrid, ItemData, Vector2i, Modifier>)Delegate.Remove(playerGrid.m_onSelected, new Action<InventoryGrid, ItemData, Vector2i, Modifier>(OnItemSelected));
				InventoryGrid playerGrid2 = gui.m_playerGrid;
				playerGrid2.m_onSelected = (Action<InventoryGrid, ItemData, Vector2i, Modifier>)Delegate.Combine(playerGrid2.m_onSelected, new Action<InventoryGrid, ItemData, Vector2i, Modifier>(OnItemSelected));
			}
			if ((Object)(object)gui.ContainerGrid != (Object)null)
			{
				InventoryGrid containerGrid = gui.ContainerGrid;
				containerGrid.m_onSelected = (Action<InventoryGrid, ItemData, Vector2i, Modifier>)Delegate.Remove(containerGrid.m_onSelected, new Action<InventoryGrid, ItemData, Vector2i, Modifier>(OnItemSelected));
				InventoryGrid containerGrid2 = gui.ContainerGrid;
				containerGrid2.m_onSelected = (Action<InventoryGrid, ItemData, Vector2i, Modifier>)Delegate.Combine(containerGrid2.m_onSelected, new Action<InventoryGrid, ItemData, Vector2i, Modifier>(OnItemSelected));
			}
		}

		private static void Unhook(InventoryGui gui)
		{
			if ((Object)(object)gui.m_playerGrid != (Object)null)
			{
				InventoryGrid playerGrid = gui.m_playerGrid;
				playerGrid.m_onSelected = (Action<InventoryGrid, ItemData, Vector2i, Modifier>)Delegate.Remove(playerGrid.m_onSelected, new Action<InventoryGrid, ItemData, Vector2i, Modifier>(OnItemSelected));
			}
			if ((Object)(object)gui.ContainerGrid != (Object)null)
			{
				InventoryGrid containerGrid = gui.ContainerGrid;
				containerGrid.m_onSelected = (Action<InventoryGrid, ItemData, Vector2i, Modifier>)Delegate.Remove(containerGrid.m_onSelected, new Action<InventoryGrid, ItemData, Vector2i, Modifier>(OnItemSelected));
			}
		}

		private static void ResetState()
		{
			if ((Object)(object)_boundGui != (Object)null)
			{
				Unhook(_boundGui);
			}
			_boundGui = null;
			_boundContainer = null;
			_selected = null;
		}

		private static void OnItemSelected(InventoryGrid grid, ItemData item, Vector2i pos, Modifier modifier)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			if ((int)modifier == 0)
			{
				_selected = item;
			}
		}

		private static string Message(Result result)
		{
			Restock instance = Restock.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return string.Empty;
			}
			return result switch
			{
				Result.NothingSelected => instance.MessageNothingSelected.Value, 
				Result.NoMatchingItems => instance.MessageNoMatchingItems.Value, 
				Result.NoSpace => instance.MessageNoSpace.Value, 
				Result.TooHeavy => instance.MessageTooHeavy.Value, 
				_ => string.Empty, 
			};
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}