Decompiled source of WiresStackify v0.1.4

WiresStackify.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("WiresStackify")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+131b950bb0584d98bfd3f18de07030645be872b5")]
[assembly: AssemblyProduct("WiresStackify")]
[assembly: AssemblyTitle("WiresStackify")]
[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 WiresStackify
{
	internal enum StackAction
	{
		None,
		Sort,
		SortByWeight,
		QuickStack,
		Restock,
		QuickStackAndRestock,
		Everything
	}
	internal static class Actions
	{
		internal sealed class PanelMiddleClick : MonoBehaviour, IPointerDownHandler, IEventSystemHandler
		{
			public void OnPointerDown(PointerEventData e)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Invalid comparison between Unknown and I4
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				if ((int)e.button == 2)
				{
					Clicked(((Component)this).gameObject, e.position);
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "Awake")]
		private static class PanelClickSetup
		{
			private static void Postfix(InventoryGui __instance)
			{
				if ((Object)(object)__instance.m_dropButton != (Object)null)
				{
					Add(((Component)__instance.m_dropButton).gameObject);
				}
				if ((Object)(object)__instance.m_player != (Object)null)
				{
					Add(((Component)__instance.m_player).gameObject);
				}
				if ((Object)(object)__instance.m_container != (Object)null)
				{
					Add(((Component)__instance.m_container).gameObject);
				}
			}

			private static void Add(GameObject go)
			{
				if ((Object)(object)go.GetComponent<PanelMiddleClick>() == (Object)null)
				{
					go.AddComponent<PanelMiddleClick>();
				}
			}
		}

		[HarmonyPatch(typeof(UIInputHandler), "OnPointerDown")]
		private static class SlotMiddleClick
		{
			private static void Postfix(UIInputHandler __instance, PointerEventData eventData)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Invalid comparison between Unknown and I4
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				if ((int)eventData.button == 2 && (Object)(object)((Component)__instance).GetComponent<PanelMiddleClick>() == (Object)null)
				{
					Clicked(((Component)__instance).gameObject, eventData.position);
				}
			}
		}

		internal const float ResultDelay = 0.1f;

		private static GameObject _rustle;

		internal static void Do(StackAction action, bool chest)
		{
			Player localPlayer = Player.m_localPlayer;
			if (action == StackAction.None || (Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsTeleporting())
			{
				return;
			}
			Rustle();
			bool flag = false;
			try
			{
				switch (action)
				{
				case StackAction.Sort:
				case StackAction.SortByWeight:
				{
					bool flag2 = action == StackAction.SortByWeight;
					flag = Sorting.Run(chest, flag2 ? Sorting.Mode.Weight : Sorting.Mode.Type);
					if (flag)
					{
						ButtonFeel.Wiggle(chest, flag2 ? (-1f) : 1f);
						if (flag2)
						{
							WeightShake.Shake(chest);
						}
					}
					break;
				}
				case StackAction.QuickStack:
					flag = QuickStack.Run(localPlayer, chest) > 0;
					if (flag)
					{
						Later(((Humanoid)localPlayer).m_pickupEffects);
					}
					break;
				case StackAction.Restock:
					flag = Restock.Run(localPlayer, chest) > 0;
					if (flag)
					{
						Later(((Humanoid)localPlayer).m_dropEffects);
					}
					break;
				case StackAction.QuickStackAndRestock:
				{
					int num4 = QuickStack.Run(localPlayer, chest);
					int num5 = Restock.Run(localPlayer, chest);
					flag = num4 > 0 || num5 > 0;
					if (flag)
					{
						Later((num4 > 0) ? ((Humanoid)localPlayer).m_pickupEffects : ((Humanoid)localPlayer).m_dropEffects);
					}
					break;
				}
				case StackAction.Everything:
				{
					StackifyEffects.Used.Clear();
					int num = QuickStack.Run(localPlayer, chest);
					int num2 = Restock.Run(localPlayer, chest);
					List<Container> chests = new List<Container>(StackifyEffects.Used);
					StackifyEffects.Used.Clear();
					int num3 = Sorting.RunAll(chests, Sorting.Mode.Type);
					flag = num > 0 || num2 > 0 || num3 > 0;
					if (num > 0 || num2 > 0)
					{
						Later((num > 0) ? ((Humanoid)localPlayer).m_pickupEffects : ((Humanoid)localPlayer).m_dropEffects);
					}
					if (num3 > 0)
					{
						ButtonFeel.Wiggle(chest, 1f);
					}
					break;
				}
				}
			}
			catch (Exception ex)
			{
				StackifyPlugin.Log.LogWarning((object)("Stackify action failed: " + ex));
			}
			if (!flag)
			{
				ButtonFeel.Squeeze(chest);
			}
			StackifyButtons.RefreshHover();
		}

		internal static void DropOn(bool chest, ItemData item, Inventory from)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || item == null)
			{
				return;
			}
			Rustle();
			int num = 0;
			try
			{
				if (chest)
				{
					Container chest2 = (((Object)(object)InventoryGui.instance != (Object)null) ? StackifyPlugin.CurrentContainer.Invoke(InventoryGui.instance) : null);
					num = Restock.RunOnly(localPlayer, chest2, item);
				}
				else if (from == ((Humanoid)localPlayer).GetInventory())
				{
					num = QuickStack.Run(localPlayer, onlyThisChest: false, null, item);
				}
			}
			catch (Exception ex)
			{
				StackifyPlugin.Log.LogWarning((object)("Stackify drop failed: " + ex));
			}
			if (num > 0)
			{
				StackifyPlugin.DropDragItem();
				Later(chest ? ((Humanoid)localPlayer).m_dropEffects : ((Humanoid)localPlayer).m_pickupEffects);
			}
			else
			{
				ButtonFeel.Squeeze(chest);
			}
			StackifyButtons.RefreshHover();
		}

		internal static void Rustle()
		{
			InventoryGui instance = InventoryGui.instance;
			if ((Object)(object)_rustle == (Object)null && (Object)(object)instance != (Object)null && instance.m_closeInventoryEffects != null)
			{
				EffectData[] effectPrefabs = instance.m_closeInventoryEffects.m_effectPrefabs;
				foreach (EffectData val in effectPrefabs)
				{
					if (val != null && val.m_enabled && (Object)(object)val.m_prefab != (Object)null && (Object)(object)val.m_prefab.GetComponentInChildren<ZSFX>(true) != (Object)null)
					{
						_rustle = val.m_prefab;
						break;
					}
				}
			}
			if ((Object)(object)_rustle != (Object)null)
			{
				StackifyEffects.PlayUi(_rustle, 1.25f);
			}
		}

		internal static void Later(EffectList sound)
		{
			((MonoBehaviour)StackifyEffects.Runner.Get()).StartCoroutine(After(0.1f, delegate
			{
				//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)
				StackifyEffects.SpawnLocal(sound, StackifyEffects.Ear(), Quaternion.identity);
			}));
		}

		internal static IEnumerator After(float seconds, Action then)
		{
			yield return (object)new WaitForSecondsRealtime(seconds);
			then();
		}

		internal static StackAction ForButton(int button, bool shift)
		{
			return button switch
			{
				0 => (shift ? StackifyPlugin.ShiftLeftClick : StackifyPlugin.LeftClick).Value, 
				1 => (shift ? StackifyPlugin.ShiftRightClick : StackifyPlugin.RightClick).Value, 
				2 => (shift ? StackifyPlugin.ShiftMiddleClick : StackifyPlugin.MiddleClick).Value, 
				_ => StackAction.None, 
			};
		}

		internal static bool Shift()
		{
			if (!Input.GetKey((KeyCode)304))
			{
				return Input.GetKey((KeyCode)303);
			}
			return true;
		}

		internal static string Describe(StackAction a)
		{
			return a switch
			{
				StackAction.Sort => "sort by type", 
				StackAction.SortByWeight => "sort by weight", 
				StackAction.QuickStack => "quick stack", 
				StackAction.Restock => "restock", 
				StackAction.QuickStackAndRestock => "quick stack, restock", 
				StackAction.Everything => "quick stack, restock, sort all used", 
				_ => null, 
			};
		}

		private static void Clicked(GameObject source, Vector2 mouse)
		{
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			InventoryGui instance = InventoryGui.instance;
			if ((Object)(object)instance == (Object)null || !InventoryGui.IsVisible() || (Object)(object)source == (Object)null)
			{
				return;
			}
			StackAction value = (Shift() ? StackifyPlugin.PanelShiftMiddleClick : StackifyPlugin.PanelMiddleClick).Value;
			if (value == StackAction.None || (Object)(object)StackifyPlugin.DragGo.Invoke(instance) != (Object)null)
			{
				return;
			}
			RectTransform player = instance.m_player;
			RectTransform container = instance.m_container;
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			bool flag = (Object)(object)StackifyPlugin.CurrentContainer.Invoke(instance) != (Object)null && (Object)(object)container != (Object)null && ((Component)container).gameObject.activeInHierarchy;
			Transform transform = source.transform;
			bool flag2 = (Object)(object)instance.m_dropButton != (Object)null && (Object)(object)transform == (Object)(object)((Component)instance.m_dropButton).transform;
			int num;
			if (flag && transform.IsChildOf((Transform)(object)container))
			{
				num = 2;
			}
			else if (transform.IsChildOf((Transform)(object)player))
			{
				num = 1;
			}
			else
			{
				if (!flag2)
				{
					return;
				}
				num = ((!flag) ? 1 : ((mouse.y >= (Edge(player, top: false) + Edge(container, top: true)) * 0.5f) ? 1 : 2));
			}
			Do(value, num == 2);
		}

		private static float Edge(RectTransform r, bool top)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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)
			Vector3[] array = (Vector3[])(object)new Vector3[4];
			r.GetWorldCorners(array);
			Camera val = Cam(r);
			float num = (top ? float.MinValue : float.MaxValue);
			Vector3[] array2 = array;
			foreach (Vector3 val2 in array2)
			{
				float y = RectTransformUtility.WorldToScreenPoint(val, val2).y;
				num = (top ? Mathf.Max(num, y) : Mathf.Min(num, y));
			}
			return num;
		}

		private static bool Over(RectTransform r, Vector2 screen)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (((Component)r).gameObject.activeInHierarchy)
			{
				return RectTransformUtility.RectangleContainsScreenPoint(r, screen, Cam(r));
			}
			return false;
		}

		private static Camera Cam(RectTransform r)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			Canvas componentInParent = ((Component)r).GetComponentInParent<Canvas>();
			if (!((Object)(object)componentInParent != (Object)null) || (int)componentInParent.renderMode == 0)
			{
				return null;
			}
			return componentInParent.rootCanvas.worldCamera;
		}
	}
	internal sealed class Favorites
	{
		[HarmonyPatch(typeof(InventoryGrid), "OnLeftDown")]
		private static class LeftPatch
		{
			private static bool Prefix(InventoryGrid __instance, UIInputHandler __0)
			{
				return Click(__instance, __0, left: true);
			}
		}

		[HarmonyPatch(typeof(InventoryGrid), "OnRightDown")]
		private static class RightPatch
		{
			private static bool Prefix(InventoryGrid __instance, UIInputHandler __0)
			{
				return Click(__instance, __0, left: false);
			}
		}

		[HarmonyPatch(typeof(Inventory), "Changed")]
		private static class InventoryChangedPatch
		{
			private static void Postfix(Inventory __instance)
			{
				if ((Object)(object)Player.m_localPlayer != (Object)null && __instance == ((Humanoid)Player.m_localPlayer).GetInventory())
				{
					_version++;
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGrid), "UpdateGui")]
		private static class BorderPatch
		{
			private static void Postfix(InventoryGrid __instance, Player player)
			{
				if ((Object)(object)player == (Object)null || (Object)(object)InventoryGui.instance == (Object)null || (Object)(object)__instance != (Object)(object)InventoryGui.instance.m_playerGrid)
				{
					return;
				}
				Inventory val = GridInventory.Invoke(__instance);
				if (val != ((Humanoid)player).GetInventory())
				{
					return;
				}
				List<InventoryElement> list = GridElements.Invoke(__instance);
				if (_drawnVersion != _version || _drawnElements != list || _drawnCount != list.Count)
				{
					if (_drawnElements != list)
					{
						Frames.Clear();
					}
					_drawnVersion = _version;
					_drawnElements = list;
					_drawnCount = list.Count;
					Draw(val, list, For(player));
				}
			}
		}

		[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, ref string __result)
			{
				//IL_0045: Unknown result type (might be due to invalid IL or missing references)
				if (!crafting && StackifyPlugin.FavoriteTooltip.Value && !((Object)(object)Player.m_localPlayer == (Object)null) && item != null && For(Player.m_localPlayer).IsItemFavorited(item.m_shared))
				{
					__result = __result + "\n<color=#" + ColorUtility.ToHtmlStringRGB(StackifyPlugin.ColorItem.Value) + ">Favorited: won't be quick stacked</color>";
				}
			}
		}

		private static readonly Dictionary<long, Favorites> ByPlayer = new Dictionary<long, Favorites>();

		private static int _version;

		private readonly string _path;

		private readonly HashSet<Vector2i> _slots = new HashSet<Vector2i>();

		private readonly HashSet<string> _items = new HashSet<string>();

		private static readonly Func<InventoryGrid, GameObject, Vector2i> ButtonPos = AccessTools.MethodDelegate<Func<InventoryGrid, GameObject, Vector2i>>(AccessTools.Method(typeof(InventoryGrid), "GetButtonPos", (Type[])null, (Type[])null), (object)null, true);

		internal static readonly FieldRef<InventoryGrid, Inventory> GridInventory = AccessTools.FieldRefAccess<InventoryGrid, Inventory>("m_inventory");

		internal static readonly FieldRef<InventoryGrid, List<InventoryElement>> GridElements = AccessTools.FieldRefAccess<InventoryGrid, List<InventoryElement>>("m_elements");

		private static GameObject _click;

		private static Sprite _border;

		private static int _drawnVersion = -1;

		private static List<InventoryElement> _drawnElements;

		private static int _drawnCount;

		private const string SlotFrame = "WireStackifySlotFrame";

		private const string ItemFrame = "WireStackifyItemFrame";

		private static readonly Dictionary<InventoryElement, Image[]> Frames = new Dictionary<InventoryElement, Image[]>();

		private const string StackRing = "WireStackifyStackRing";

		private const string RestockRing = "WireStackifyRestockRing";

		private static readonly List<Image> Previewing = new List<Image>();

		private static readonly FieldRef<GuiBar, Color> BarColor = AccessTools.FieldRefAccess<GuiBar, Color>("m_originalColor");

		private static readonly Color Blue = new Color(0.376f, 0.66f, 0.897f, 1f);

		internal static Favorites For(Player p)
		{
			long playerID = p.GetPlayerID();
			if (!ByPlayer.TryGetValue(playerID, out var value))
			{
				value = (ByPlayer[playerID] = new Favorites(playerID));
			}
			return value;
		}

		internal static void MarkDirty()
		{
			_version++;
		}

		private Favorites(long id)
		{
			_path = Path.Combine(Paths.ConfigPath, "WiresStackify_favorites_" + id + ".txt");
			if (File.Exists(_path))
			{
				Load();
			}
			else if (ImportQuickStackStore(id))
			{
				Save();
			}
		}

		internal bool IsFavorited(ItemData item)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if (!_items.Contains(item.m_shared.m_name))
			{
				return _slots.Contains(item.m_gridPos);
			}
			return true;
		}

		internal bool IsItemFavorited(SharedData s)
		{
			return _items.Contains(s.m_name);
		}

		internal bool IsSlotFavorited(Vector2i pos)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return _slots.Contains(pos);
		}

		internal void ToggleSlot(Vector2i pos)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (!_slots.Remove(pos))
			{
				_slots.Add(pos);
			}
			Save();
		}

		internal void ToggleItem(SharedData s)
		{
			if (!_items.Remove(s.m_name))
			{
				_items.Add(s.m_name);
			}
			Save();
		}

		private void Load()
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				string[] array = File.ReadAllLines(_path);
				foreach (string text in array)
				{
					if (text.StartsWith("slot "))
					{
						string[] array2 = text.Split(new char[1] { ' ' });
						if (array2.Length == 3 && int.TryParse(array2[1], out var result) && int.TryParse(array2[2], out var result2))
						{
							_slots.Add(new Vector2i(result, result2));
						}
					}
					else if (text.StartsWith("item "))
					{
						_items.Add(text.Substring(5));
					}
				}
			}
			catch (Exception ex)
			{
				StackifyPlugin.Log.LogWarning((object)("Couldn't read favorites: " + ex.Message));
			}
			MarkDirty();
		}

		private void Save()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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)
			try
			{
				StringBuilder stringBuilder = new StringBuilder();
				foreach (Vector2i slot in _slots)
				{
					stringBuilder.Append("slot ").Append(slot.x).Append(' ')
						.Append(slot.y)
						.Append('\n');
				}
				foreach (string item in _items)
				{
					stringBuilder.Append("item ").Append(item).Append('\n');
				}
				File.WriteAllText(_path, stringBuilder.ToString());
			}
			catch (Exception ex)
			{
				StackifyPlugin.Log.LogWarning((object)("Couldn't save favorites: " + ex.Message));
			}
			MarkDirty();
		}

		private bool ImportQuickStackStore(long id)
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			string path = Path.Combine(Paths.ConfigPath, "QuickStackStore_player_" + id + ".dat");
			if (!File.Exists(path))
			{
				return false;
			}
			try
			{
				using (Stream serializationStream = File.OpenRead(path))
				{
					BinaryFormatter binaryFormatter = new BinaryFormatter();
					if (binaryFormatter.Deserialize(serializationStream) is List<Tuple<int, int>> list)
					{
						foreach (Tuple<int, int> item in list)
						{
							_slots.Add(new Vector2i(item.Item1, item.Item2));
						}
					}
					if (binaryFormatter.Deserialize(serializationStream) is List<string> list2)
					{
						foreach (string item2 in list2)
						{
							_items.Add(item2);
						}
					}
				}
				StackifyPlugin.Log.LogInfo((object)("Took over Quick Stack Store favorites: " + _slots.Count + " slots, " + _items.Count + " items."));
				return _slots.Count > 0 || _items.Count > 0;
			}
			catch (Exception ex)
			{
				StackifyPlugin.Log.LogWarning((object)("Couldn't read Quick Stack Store favorites: " + ex.Message));
				return false;
			}
		}

		private static bool Favoriting(InventoryGrid grid)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)InventoryGui.instance != (Object)null && (Object)(object)grid == (Object)(object)InventoryGui.instance.m_playerGrid && (Object)(object)Player.m_localPlayer != (Object)null && !((Character)Player.m_localPlayer).IsTeleporting() && (Object)(object)StackifyPlugin.DragGo.Invoke(InventoryGui.instance) == (Object)null)
			{
				if (!StackifyPlugin.Held(StackifyPlugin.FavoriteKey1.Value))
				{
					return StackifyPlugin.Held(StackifyPlugin.FavoriteKey2.Value);
				}
				return true;
			}
			return false;
		}

		private static bool Click(InventoryGrid grid, UIInputHandler handler, bool left)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: 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)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)handler == (Object)null || !Favoriting(grid))
			{
				return true;
			}
			Vector2i val = ButtonPos(grid, ((Component)handler).gameObject);
			if (val == new Vector2i(-1, -1))
			{
				return true;
			}
			Favorites favorites = For(Player.m_localPlayer);
			bool flag;
			if (!left)
			{
				favorites.ToggleSlot(val);
				flag = favorites.IsSlotFavorited(val);
			}
			else
			{
				ItemData itemAt = GridInventory.Invoke(grid).GetItemAt(val.x, val.y);
				if (itemAt == null)
				{
					return true;
				}
				favorites.ToggleItem(itemAt.m_shared);
				flag = favorites.IsItemFavorited(itemAt.m_shared);
			}
			ToggleSound(flag);
			if (flag)
			{
				List<InventoryElement> list = GridElements.Invoke(grid);
				int num = val.y * GridInventory.Invoke(grid).GetWidth() + val.x;
				if (list != null && num >= 0 && num < list.Count)
				{
					((MonoBehaviour)StackifyEffects.Runner.Get()).StartCoroutine(PopFrame(list[num], left ? "WireStackifyItemFrame" : "WireStackifySlotFrame", left ? 3f : 0f));
				}
			}
			return false;
		}

		private static void ToggleSound(bool on)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			InventoryGui instance = InventoryGui.instance;
			if ((Object)(object)_click == (Object)null && (Object)(object)instance != (Object)null && (Object)(object)instance.m_takeAllButton != (Object)null)
			{
				ButtonSfx component = ((Component)instance.m_takeAllButton).GetComponent<ButtonSfx>();
				if ((Object)(object)component != (Object)null)
				{
					_click = component.m_sfxPrefab;
				}
			}
			if ((Object)(object)_click != (Object)null)
			{
				StackifyEffects.PlayNow(_click, StackifyEffects.Ear(), Quaternion.identity, null, on ? 0.82f : 1.18f);
			}
		}

		private static IEnumerator PopFrame(InventoryElement e, string name, float inset)
		{
			yield return null;
			Image img = Frame(e, name, inset);
			if ((Object)(object)img == (Object)null)
			{
				yield break;
			}
			RectTransform r = ((Graphic)img).rectTransform;
			Color full = ((Graphic)img).color;
			float x = 0.35f;
			float v = 0f;
			for (float t = 0f; t < 0.45f; t += Time.unscaledDeltaTime)
			{
				if ((Object)(object)r == (Object)null || (Object)(object)img == (Object)null)
				{
					yield break;
				}
				float num = Mathf.Min(Time.unscaledDeltaTime, 0.05f);
				v += ((0f - x) * 420f - v * 20f) * num;
				x += v * num;
				float num2 = 1f + x;
				((Transform)r).localScale = new Vector3(num2, num2, 1f);
				Color color = ((Graphic)img).color;
				color.a = full.a * Mathf.Clamp01(t / 0.08f);
				((Graphic)img).color = color;
				if (t > 0.12f && Mathf.Abs(x) < 0.002f && Mathf.Abs(v) < 0.02f)
				{
					break;
				}
				yield return null;
			}
			if ((Object)(object)r != (Object)null)
			{
				((Transform)r).localScale = Vector3.one;
			}
			if ((Object)(object)img != (Object)null)
			{
				Color color2 = ((Graphic)img).color;
				color2.a = full.a;
				((Graphic)img).color = color2;
			}
		}

		private static void Draw(Inventory inv, List<InventoryElement> elements, Favorites fav)
		{
			//IL_0041: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			int width = inv.GetWidth();
			int height = inv.GetHeight();
			for (int i = 0; i < height; i++)
			{
				for (int j = 0; j < width; j++)
				{
					int num = i * width + j;
					if (num >= elements.Count)
					{
						break;
					}
					Show(Frame(elements[num], "WireStackifySlotFrame", 0f), fav.IsSlotFavorited(new Vector2i(j, i)), StackifyPlugin.ColorSlot.Value);
					Show(Frame(elements[num], "WireStackifyItemFrame", 3f), on: false, StackifyPlugin.ColorItem.Value);
				}
			}
			foreach (ItemData allItem in inv.GetAllItems())
			{
				if (fav.IsItemFavorited(allItem.m_shared))
				{
					int num2 = allItem.m_gridPos.y * width + allItem.m_gridPos.x;
					if (num2 >= 0 && num2 < elements.Count)
					{
						Show(Frame(elements[num2], "WireStackifyItemFrame", 3f), on: true, StackifyPlugin.ColorItem.Value);
					}
				}
			}
		}

		private static void Show(Image img, bool on, Color color)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)img == (Object)null))
			{
				if (((Graphic)img).color != color)
				{
					((Graphic)img).color = color;
				}
				if (((Behaviour)img).enabled != on)
				{
					((Behaviour)img).enabled = on;
				}
			}
		}

		private static Image Frame(InventoryElement e, string name, float inset)
		{
			if ((Object)(object)e == (Object)null || (Object)(object)e.m_queued == (Object)null)
			{
				return null;
			}
			int num = name switch
			{
				"WireStackifyStackRing" => 2, 
				"WireStackifyItemFrame" => 1, 
				"WireStackifySlotFrame" => 0, 
				_ => 3, 
			};
			if (!Frames.TryGetValue(e, out var value))
			{
				value = (Frames[e] = (Image[])(object)new Image[4]);
			}
			if ((Object)(object)value[num] != (Object)null)
			{
				return value[num];
			}
			Transform val = ((Component)e.m_queued).transform.Find(name);
			if ((Object)(object)val != (Object)null)
			{
				return value[num] = ((Component)val).GetComponent<Image>();
			}
			value[num] = MakeFrame(e, name, inset);
			return value[num];
		}

		private static Image MakeFrame(InventoryElement e, string name, float inset)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			RectTransform val2 = (RectTransform)val.transform;
			((Transform)val2).SetParent(((Component)e.m_queued).transform, false);
			val2.anchorMin = Vector2.zero;
			val2.anchorMax = Vector2.one;
			val2.offsetMin = new Vector2(inset, inset);
			val2.offsetMax = new Vector2(0f - inset, 0f - inset);
			Image component = val.GetComponent<Image>();
			Image val3 = (((Object)(object)e.m_selected != (Object)null) ? e.m_selected.GetComponentInChildren<Image>(true) : null);
			if ((Object)(object)val3 != (Object)null && (Object)(object)val3.sprite != (Object)null)
			{
				component.sprite = val3.sprite;
				component.type = val3.type;
				component.pixelsPerUnitMultiplier = val3.pixelsPerUnitMultiplier;
				component.fillCenter = false;
			}
			else
			{
				component.sprite = BorderSprite();
			}
			((Graphic)component).raycastTarget = false;
			((Behaviour)component).enabled = false;
			return component;
		}

		private static Sprite BorderSprite()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_border != (Object)null)
			{
				return _border;
			}
			float num = 3f;
			float num2 = 8f;
			Texture2D val = new Texture2D(128, 128, (TextureFormat)4, false);
			((Texture)val).wrapMode = (TextureWrapMode)1;
			Color32[] array = (Color32[])(object)new Color32[16384];
			for (int i = 0; i < 128; i++)
			{
				for (int j = 0; j < 128; j++)
				{
					float num3 = (float)j + 0.5f - 64f;
					float num4 = (float)i + 0.5f - 64f;
					float num5 = 64f;
					float num6 = Mathf.Abs(num3) - num5 + num2;
					float num7 = Mathf.Abs(num4) - num5 + num2;
					Vector2 val2 = new Vector2(Mathf.Max(num6, 0f), Mathf.Max(num7, 0f));
					float num8 = ((Vector2)(ref val2)).magnitude + Mathf.Min(Mathf.Max(num6, num7), 0f) - num2;
					float num9 = Mathf.Clamp01(0.5f - num8) * Mathf.Clamp01(num8 + num + 0.5f);
					array[i * 128 + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, (byte)(num9 * 255f));
				}
			}
			val.SetPixels32(array);
			val.Apply();
			_border = Sprite.Create(val, new Rect(0f, 0f, 128f, 128f), new Vector2(0.5f, 0.5f), 100f);
			return _border;
		}

		private static Color Yellow()
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)Hud.instance != (Object)null && (Object)(object)Hud.instance.m_staminaBar2Fast != (Object)null)
				{
					Color val = BarColor.Invoke(Hud.instance.m_staminaBar2Fast);
					if (val.a > 0f)
					{
						val.a = 1f;
						return val;
					}
				}
			}
			catch (Exception)
			{
			}
			return new Color(1f, 0.848f, 0f, 1f);
		}

		internal static string BlueHex()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return ColorUtility.ToHtmlStringRGB(Blue);
		}

		internal static string YellowHex()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return ColorUtility.ToHtmlStringRGB(Yellow());
		}

		internal static void ShowPreview(List<ItemData> stack, List<ItemData> restock)
		{
			//IL_007d: 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)
			ClearPreview();
			InventoryGui instance = InventoryGui.instance;
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.m_playerGrid == (Object)null || (Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			if (GridInventory.Invoke(instance.m_playerGrid) != inventory)
			{
				return;
			}
			List<InventoryElement> list = GridElements.Invoke(instance.m_playerGrid);
			if (list != null)
			{
				int width = inventory.GetWidth();
				if (stack != null)
				{
					Mark(stack, list, width, "WireStackifyStackRing", 0f, Yellow());
				}
				if (restock != null)
				{
					Mark(restock, list, width, "WireStackifyRestockRing", 3f, Blue);
				}
			}
		}

		private static void Mark(List<ItemData> items, List<InventoryElement> elements, int w, string ring, float inset, Color c)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			foreach (ItemData item in items)
			{
				int num = item.m_gridPos.y * w + item.m_gridPos.x;
				if (num < 0 || num >= elements.Count)
				{
					continue;
				}
				Image val = Frame(elements[num], ring, inset);
				if (!((Object)(object)val == (Object)null))
				{
					if (((Graphic)val).color != c)
					{
						((Graphic)val).color = c;
					}
					((Component)val).transform.SetAsLastSibling();
					((Behaviour)val).enabled = true;
					Previewing.Add(val);
				}
			}
		}

		internal static void ClearPreview()
		{
			foreach (Image item in Previewing)
			{
				if ((Object)(object)item != (Object)null)
				{
					((Behaviour)item).enabled = false;
				}
			}
			Previewing.Clear();
		}
	}
	internal static class NearbyChests
	{
		[HarmonyPatch(typeof(Container), "Awake")]
		private static class AwakePatch
		{
			private static void Postfix(Container __instance)
			{
				if ((Object)(object)NView.Invoke(__instance) != (Object)null)
				{
					All.Add(__instance);
				}
			}
		}

		private static readonly List<Container> All = new List<Container>();

		internal static readonly FieldRef<Container, ZNetView> NView = AccessTools.FieldRefAccess<Container, ZNetView>("m_nview");

		private static readonly FieldRef<Container, Piece> PieceOf = AccessTools.FieldRefAccess<Container, Piece>("m_piece");

		private static readonly FieldRef<Container, bool> InUseFlag = AccessTools.FieldRefAccess<Container, bool>("m_inUse");

		private static readonly FieldRef<bool> PublicServer = AccessTools.StaticFieldRefAccess<bool>(AccessTools.Field(typeof(ZNet), "m_publicServer"));

		private static readonly Func<Container, long, bool> CheckAccess = AccessTools.MethodDelegate<Func<Container, long, bool>>(AccessTools.Method(typeof(Container), "CheckAccess", (Type[])null, (Type[])null), (object)null, true);

		private static readonly int InUseKey = StringExtensionMethods.GetStableHashCode("InUse");

		private static readonly Predicate<Container> IsGone = (Container c) => (Object)(object)c == (Object)null;

		internal static List<Container> InRange(Vector3 point, float range)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			All.RemoveAll(IsGone);
			List<Container> list = new List<Container>();
			float num = range * range;
			foreach (Container item in All)
			{
				Vector3 val = point - ((Component)item).transform.position;
				if (!(((Vector3)(ref val)).sqrMagnitude >= num))
				{
					ZNetView val2 = NView.Invoke(item);
					if ((Object)(object)val2 != (Object)null && val2.HasOwner())
					{
						list.Add(item);
					}
				}
			}
			return list;
		}

		internal static List<Container> ForPouch(Player player, bool onlyThisChest, Container current, float range)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			List<Container> list = new List<Container>();
			if ((Object)(object)current != (Object)null)
			{
				list.Add(current);
			}
			if (onlyThisChest || range <= 0f || !AreaAllowed())
			{
				return list;
			}
			bool singleplayer = IsTrueSingleplayer();
			long playerID = player.GetPlayerID();
			foreach (Container item in InRange(((Component)player).transform.position, range))
			{
				if ((Object)(object)item != (Object)(object)current && CanUse(item, playerID, singleplayer))
				{
					list.Add(item);
				}
			}
			return list;
		}

		internal static bool IsTrueSingleplayer()
		{
			if (!ZNet.IsOpenServer() && !PublicServer.Invoke() && (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && !ZNet.instance.IsDedicated())
			{
				return ZNet.instance.GetConnectedPeers().Count == 0;
			}
			return false;
		}

		internal static bool AreaAllowed()
		{
			if (!IsTrueSingleplayer() && !StackifyPlugin.HasMuc)
			{
				return StackifyPlugin.MultiplayerWithoutMuc.Value;
			}
			return true;
		}

		internal static bool CanUse(Container c, long playerId, bool singleplayer)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			Player component = ((Component)NView.Invoke(c)).GetComponent<Player>();
			if ((Object)(object)component != (Object)null && (Object)(object)component != (Object)(object)Player.m_localPlayer)
			{
				return false;
			}
			if (!CheckAccess(c, playerId))
			{
				return false;
			}
			if (c.m_checkGuardStone && !PrivateArea.CheckAccess(((Component)c).transform.position, 0f, true, false))
			{
				return false;
			}
			Piece val = PieceOf.Invoke(c);
			if ((Object)(object)val != (Object)null)
			{
				if (!val.IsPlacedByPlayer() && !StackifyPlugin.NonPlayerBuilt.Value)
				{
					return false;
				}
			}
			else if (c.m_name != "piece_chest_drawer" && !StackifyPlugin.NonPhysicalContainers.Value)
			{
				return false;
			}
			if (StackifyPlugin.HasMuc)
			{
				return true;
			}
			if (!singleplayer && (Object)(object)((Component)((Component)c).transform.root).GetComponentInChildren<Ship>() != (Object)null)
			{
				return false;
			}
			return !InUse(c);
		}

		private static bool InUse(Container c)
		{
			ZDO zDO = NView.Invoke(c).GetZDO();
			if ((zDO == null || zDO.GetInt(InUseKey, 0) != 1) && !c.IsInUse())
			{
				if ((Object)(object)c.m_wagon != (Object)null)
				{
					return c.m_wagon.InUse();
				}
				return false;
			}
			return true;
		}

		internal static void Claim(Container c, bool inUse)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			ZNetView val = NView.Invoke(c);
			if (inUse)
			{
				val.ClaimOwnership();
			}
			InUseFlag.Invoke(c) = inUse;
			if (StackifyPlugin.QuietChests.Value)
			{
				val.GetZDO().Set(InUseKey, inUse ? 1 : 0, false);
			}
			else
			{
				c.SetInUse(inUse);
			}
			ZDOMan.instance.ForceSendZDO(ZNet.GetUID(), val.GetZDO().m_uid);
		}
	}
	internal static class PickupSlots
	{
		[HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData) })]
		private static class AddItemPatch
		{
			private static void Prefix(ItemData item, out ItemData __state)
			{
				__state = _adding;
				_adding = item;
			}

			private static void Finalizer(ItemData __state)
			{
				_adding = __state;
			}
		}

		[HarmonyPatch(typeof(Inventory), "FindEmptySlot")]
		private static class FindEmptySlotPatch
		{
			private static void Postfix(Inventory __instance, bool topFirst, ref Vector2i __result)
			{
				//IL_002c: 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_009d: Unknown result type (might be due to invalid IL or missing references)
				//IL_009f: Unknown result type (might be due to invalid IL or missing references)
				if (__result.x < 0)
				{
					return;
				}
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null || __instance != ((Humanoid)localPlayer).GetInventory())
				{
					return;
				}
				Favorites favorites = Favorites.For(localPlayer);
				if (!favorites.IsSlotFavorited(__result) || (_adding != null && favorites.IsItemFavorited(_adding.m_shared)))
				{
					return;
				}
				int width = __instance.GetWidth();
				int num = StackifyPlugin.MainRows(__instance, localPlayer);
				Vector2i val = default(Vector2i);
				for (int i = 0; i < num; i++)
				{
					int num2 = (topFirst ? i : (num - 1 - i));
					for (int j = 0; j < width; j++)
					{
						((Vector2i)(ref val))..ctor(j, num2);
						if (__instance.GetItemAt(j, num2) == null && !favorites.IsSlotFavorited(val))
						{
							__result = val;
							return;
						}
					}
				}
			}
		}

		private static ItemData _adding;
	}
	internal static class QuickStack
	{
		[HarmonyPatch(typeof(Container), "RPC_StackResponse")]
		private static class PlaceStacksPatch
		{
			private static bool Prefix(Container __instance, bool granted)
			{
				if (!StackifyPlugin.HoldToStack.Value)
				{
					return true;
				}
				if ((Object)(object)Player.m_localPlayer == (Object)null)
				{
					return false;
				}
				if (granted)
				{
					Run(Player.m_localPlayer, onlyThisChest: true, __instance);
				}
				else
				{
					((Character)Player.m_localPlayer).Message((MessageType)2, "$msg_inuse", 0, (Sprite)null, false);
				}
				return false;
			}
		}

		private static readonly HashSet<string> Names = new HashSet<string>();

		private static bool ShouldStack(ItemData item, Favorites fav, bool hotbar, int rows)
		{
			if (item.m_shared.m_maxStackSize > 1 && (item.m_gridPos.y > 0 || hotbar) && item.m_gridPos.y < rows)
			{
				return !fav.IsFavorited(item);
			}
			return false;
		}

		internal static List<ItemData> Candidates(Player player, ItemData only = null)
		{
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			Favorites favorites = Favorites.For(player);
			Inventory inventory = ((Humanoid)player).GetInventory();
			bool value = StackifyPlugin.QuickStackHotbar.Value;
			int num = StackifyPlugin.MainRows(inventory, player);
			List<ItemData> list = new List<ItemData>();
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (only == null)
				{
					if (ShouldStack(allItem, favorites, value, num))
					{
						list.Add(allItem);
					}
				}
				else if (allItem == only || (allItem.m_shared.m_name == only.m_shared.m_name && allItem.m_gridPos.y < num && (allItem.m_gridPos.y > 0 || value) && !favorites.IsSlotFavorited(allItem.m_gridPos)))
				{
					list.Add(allItem);
				}
			}
			return list;
		}

		internal static List<ItemData> Preview(Player player, bool onlyThisChest, out int chests, ItemData only = null)
		{
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Invalid comparison between Unknown and I4
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Invalid comparison between Unknown and I4
			chests = 0;
			List<ItemData> list = new List<ItemData>();
			if ((Object)(object)InventoryGui.instance == (Object)null)
			{
				return list;
			}
			Container val = StackifyPlugin.CurrentContainer.Invoke(InventoryGui.instance);
			if (onlyThisChest && (Object)(object)val == (Object)null)
			{
				return list;
			}
			if (only != null && !((Humanoid)player).GetInventory().ContainsItem(only))
			{
				return list;
			}
			List<ItemData> list2 = Candidates(player, only);
			if (list2.Count == 0)
			{
				return list;
			}
			HashSet<Container> hashSet = new HashSet<Container>();
			foreach (Container item in NearbyChests.ForPouch(player, onlyThisChest, val, StackifyPlugin.QuickStackRange.Value))
			{
				Inventory inventory = item.GetInventory();
				Names.Clear();
				bool flag = false;
				foreach (ItemData allItem in inventory.GetAllItems())
				{
					Names.Add(allItem.m_shared.m_name);
					if ((int)allItem.m_shared.m_itemType == 13)
					{
						flag = true;
					}
				}
				for (int num = list2.Count - 1; num >= 0; num--)
				{
					ItemData val2 = list2[num];
					if ((Names.Contains(val2.m_shared.m_name) || (flag && StackifyPlugin.TrophiesTogether.Value && (int)val2.m_shared.m_itemType == 13)) && inventory.CanAddItem(val2, -1))
					{
						list.Add(val2);
						list2.RemoveAt(num);
						hashSet.Add(item);
					}
				}
			}
			chests = hashSet.Count;
			return list;
		}

		internal static int Run(Player player, bool onlyThisChest, Container chestOverride = null, ItemData only = null)
		{
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Invalid comparison between Unknown and I4
			if (((Character)player).IsTeleporting() || (Object)(object)InventoryGui.instance == (Object)null || (Object)(object)InventoryGui.instance.m_container == (Object)null)
			{
				return 0;
			}
			if (only == null)
			{
				StackifyPlugin.DropDragItem();
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			List<ItemData> list = Candidates(player, only);
			if (list.Count == 0)
			{
				return 0;
			}
			list.Sort((ItemData a, ItemData b) => -StackifyPlugin.CompareSlotOrder(a.m_gridPos, b.m_gridPos));
			List<ItemData> list2 = null;
			if (StackifyPlugin.TrophiesTogether.Value)
			{
				list2 = new List<ItemData>();
				for (int num = list.Count - 1; num >= 0; num--)
				{
					if ((int)list[num].m_shared.m_itemType == 13)
					{
						list2.Insert(0, list[num]);
						list.RemoveAt(num);
					}
				}
			}
			int num2 = 0;
			Container val = (((Object)(object)chestOverride != (Object)null) ? chestOverride : StackifyPlugin.CurrentContainer.Invoke(InventoryGui.instance));
			List<StackifyEffects.Hit> list3 = new List<StackifyEffects.Hit>();
			foreach (Container item in NearbyChests.ForPouch(player, onlyThisChest, val, StackifyPlugin.QuickStackRange.Value))
			{
				int num3;
				if ((Object)(object)item == (Object)(object)val || StackifyPlugin.HasMuc)
				{
					num3 = IntoChest(list2, list, inventory, item.GetInventory(), changed: false);
				}
				else
				{
					NearbyChests.Claim(item, inUse: true);
					num3 = IntoChest(list2, list, inventory, item.GetInventory(), changed: false);
					NearbyChests.Claim(item, inUse: false);
				}
				if (num3 > 0)
				{
					num2 += num3;
					list3.Add(new StackifyEffects.Hit
					{
						Chest = item,
						Count = num3
					});
				}
			}
			if (num2 > 0)
			{
				StackifyPlugin.Changed(inventory);
			}
			if (num2 > 0)
			{
				StackifyButtons.Feedback(StackifyEffects.Kind.Stack, num2, onlyThisChest);
			}
			StackifyEffects.Play(StackifyEffects.Kind.Stack, list3, val, player, onlyThisChest);
			return num2;
		}

		private static int IntoChest(List<ItemData> trophies, List<ItemData> items, Inventory inv, Inventory chest, bool changed)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Invalid comparison between Unknown and I4
			int num = 0;
			List<ItemData> allItems = chest.GetAllItems();
			if (trophies != null && trophies.Count > 0)
			{
				bool flag = false;
				foreach (ItemData item in allItems)
				{
					if ((int)item.m_shared.m_itemType == 13)
					{
						flag = true;
						break;
					}
				}
				if (flag)
				{
					for (int num2 = trophies.Count - 1; num2 >= 0; num2--)
					{
						if (chest.AddItem(trophies[num2]))
						{
							inv.RemoveItem(trophies[num2]);
							trophies.RemoveAt(num2);
							num++;
						}
					}
				}
			}
			if (items.Count > 0 && allItems.Count > 0)
			{
				Names.Clear();
				foreach (ItemData item2 in allItems)
				{
					Names.Add(item2.m_shared.m_name);
				}
				for (int num3 = items.Count - 1; num3 >= 0; num3--)
				{
					ItemData val = items[num3];
					if (Names.Contains(val.m_shared.m_name) && chest.AddItem(val))
					{
						inv.RemoveItem(val);
						items.RemoveAt(num3);
						num++;
					}
				}
			}
			if (changed)
			{
				StackifyPlugin.Changed(inv);
			}
			return num;
		}
	}
	internal static class Restock
	{
		private sealed class Want
		{
			public ItemData Item;

			public int Have;

			public int Max;
		}

		private static int MaxFor(SharedData s)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Invalid comparison between Unknown and I4
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Invalid comparison between Unknown and I4
			int maxStackSize = s.m_maxStackSize;
			int num = 0;
			if ((int)s.m_itemType == 9)
			{
				num = StackifyPlugin.RestockLimitAmmo.Value;
			}
			else if ((int)s.m_itemType == 2)
			{
				num = StackifyPlugin.RestockLimitConsumables.Value;
			}
			if (num <= 0)
			{
				num = StackifyPlugin.RestockLimitGeneral.Value;
			}
			if (num <= 0)
			{
				return maxStackSize;
			}
			return Math.Min(maxStackSize, num);
		}

		private static bool ShouldRestock(ItemData item, Favorites fav, bool hotbar)
		{
			//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_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Invalid comparison between Unknown and I4
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Invalid comparison between Unknown and I4
			int num = MaxFor(item.m_shared);
			ItemType itemType = item.m_shared.m_itemType;
			if (num > 1 && num > item.m_stack && (item.m_customData == null || item.m_customData.Count == 0) && (item.m_gridPos.y > 0 || hotbar) && (!StackifyPlugin.RestockOnlyAmmoAndFood.Value || (int)itemType == 9 || (int)itemType == 2))
			{
				if (StackifyPlugin.RestockOnlyFavorites.Value)
				{
					return fav.IsFavorited(item);
				}
				return true;
			}
			return false;
		}

		private static List<Want> WantsFor(Player player, ItemData kind)
		{
			List<Want> list = new List<Want>();
			foreach (ItemData allItem in ((Humanoid)player).GetInventory().GetAllItems())
			{
				if (allItem.m_shared.m_name == kind.m_shared.m_name && allItem.m_quality == kind.m_quality && allItem.m_shared.m_maxStackSize > 1 && allItem.m_stack < allItem.m_shared.m_maxStackSize && (allItem.m_customData == null || allItem.m_customData.Count == 0))
				{
					list.Add(new Want
					{
						Item = allItem,
						Have = allItem.m_stack,
						Max = allItem.m_shared.m_maxStackSize
					});
				}
			}
			return list;
		}

		private static float Room(Player player)
		{
			return Math.Max(0f, player.GetMaxCarryWeight() - ((Humanoid)player).GetInventory().GetTotalWeight());
		}

		private static int Fits(Want want, int take, float room)
		{
			float weight = want.Item.GetWeight(1);
			if (weight <= 0f)
			{
				return take;
			}
			return Math.Min(take, (int)Math.Floor(room / weight + 0.0001f));
		}

		private static List<Want> NormalWants(Player player)
		{
			Favorites fav = Favorites.For(player);
			bool value = StackifyPlugin.RestockHotbar.Value;
			List<Want> list = new List<Want>();
			foreach (ItemData allItem in ((Humanoid)player).GetInventory().GetAllItems())
			{
				if (ShouldRestock(allItem, fav, value))
				{
					list.Add(new Want
					{
						Item = allItem,
						Have = allItem.m_stack,
						Max = MaxFor(allItem.m_shared)
					});
				}
			}
			list.Sort((Want a, Want b) => -StackifyPlugin.CompareSlotOrder(a.Item.m_gridPos, b.Item.m_gridPos));
			return list;
		}

		internal static List<ItemData> PreviewOnly(Player player, Container chest, ItemData kind, out float weight)
		{
			weight = 0f;
			if ((Object)(object)player == (Object)null || (Object)(object)chest == (Object)null || kind == null)
			{
				return new List<ItemData>();
			}
			List<Want> list = WantsFor(player, kind);
			list.Sort((Want a, Want b) => -StackifyPlugin.CompareSlotOrder(a.Item.m_gridPos, b.Item.m_gridPos));
			int containers;
			return Simulate(list, new List<Container> { chest }, Room(player), out containers, out weight);
		}

		internal static int RunOnly(Player player, Container chest, ItemData kind)
		{
			if ((Object)(object)player == (Object)null || (Object)(object)chest == (Object)null || kind == null || ((Character)player).IsTeleporting())
			{
				return 0;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			List<Want> list = WantsFor(player, kind);
			if (list.Count == 0)
			{
				return 0;
			}
			list.Sort((Want a, Want b) => -StackifyPlugin.CompareSlotOrder(a.Item.m_gridPos, b.Item.m_gridPos));
			HashSet<Vector2i> hashSet = new HashSet<Vector2i>();
			float room = Room(player);
			FromChest(list, inventory, chest.GetInventory(), hashSet, ref room, out var took);
			if (hashSet.Count > 0)
			{
				StackifyPlugin.Changed(inventory);
			}
			List<StackifyEffects.Hit> list2 = new List<StackifyEffects.Hit>();
			if (took)
			{
				list2.Add(new StackifyEffects.Hit
				{
					Chest = chest,
					Count = hashSet.Count
				});
			}
			if (hashSet.Count > 0)
			{
				StackifyButtons.Feedback(StackifyEffects.Kind.Restock, hashSet.Count, chest: true);
			}
			StackifyEffects.Play(StackifyEffects.Kind.Restock, list2, chest, player, chestButton: true);
			return hashSet.Count;
		}

		internal static int Run(Player player, bool onlyThisChest)
		{
			if (((Character)player).IsTeleporting() || (Object)(object)InventoryGui.instance == (Object)null || (Object)(object)InventoryGui.instance.m_container == (Object)null)
			{
				return 0;
			}
			StackifyPlugin.DropDragItem();
			Inventory inventory = ((Humanoid)player).GetInventory();
			List<Want> list = NormalWants(player);
			if (list.Count == 0)
			{
				return 0;
			}
			float room = Room(player);
			HashSet<Vector2i> hashSet = new HashSet<Vector2i>();
			Container val = StackifyPlugin.CurrentContainer.Invoke(InventoryGui.instance);
			List<StackifyEffects.Hit> list2 = new List<StackifyEffects.Hit>();
			foreach (Container item in NearbyChests.ForPouch(player, onlyThisChest, val, StackifyPlugin.RestockRange.Value))
			{
				if (list.Count == 0 || room <= 0f)
				{
					break;
				}
				int count = hashSet.Count;
				bool took;
				if ((Object)(object)item == (Object)(object)val || StackifyPlugin.HasMuc)
				{
					FromChest(list, inventory, item.GetInventory(), hashSet, ref room, out took);
				}
				else
				{
					NearbyChests.Claim(item, inUse: true);
					FromChest(list, inventory, item.GetInventory(), hashSet, ref room, out took);
					NearbyChests.Claim(item, inUse: false);
				}
				if (took)
				{
					list2.Add(new StackifyEffects.Hit
					{
						Chest = item,
						Count = hashSet.Count - count
					});
				}
			}
			if (hashSet.Count > 0)
			{
				StackifyPlugin.Changed(inventory);
			}
			if (hashSet.Count > 0)
			{
				StackifyButtons.Feedback(StackifyEffects.Kind.Restock, hashSet.Count, onlyThisChest);
			}
			StackifyEffects.Play(StackifyEffects.Kind.Restock, list2, val, player, onlyThisChest);
			return hashSet.Count;
		}

		private static void FromChest(List<Want> wants, Inventory inv, Inventory chest, HashSet<Vector2i> touched, ref float room, out bool took)
		{
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			took = false;
			List<ItemData> allItems = chest.GetAllItems();
			for (int num = wants.Count - 1; num >= 0; num--)
			{
				Want want = wants[num];
				for (int num2 = allItems.Count - 1; num2 >= 0; num2--)
				{
					if (num2 < allItems.Count)
					{
						ItemData val = allItems[num2];
						if ((val.m_customData == null || val.m_customData.Count <= 0) && !(val.m_shared.m_name != want.Item.m_shared.m_name) && val.m_quality == want.Item.m_quality)
						{
							int num3 = Fits(want, Math.Min(want.Max - want.Have, val.m_stack), room);
							if (num3 <= 0)
							{
								break;
							}
							want.Have += num3;
							room -= want.Item.GetWeight(num3);
							took = true;
							touched.Add(want.Item.m_gridPos);
							inv.MoveItemToThis(chest, val, num3, want.Item.m_gridPos.x, want.Item.m_gridPos.y);
							if (want.Have >= want.Max)
							{
								wants.RemoveAt(num);
								break;
							}
						}
					}
				}
			}
		}

		internal static List<ItemData> Preview(Player player, bool onlyThisChest, out int containers, out float weight)
		{
			containers = 0;
			weight = 0f;
			if ((Object)(object)InventoryGui.instance == (Object)null)
			{
				return new List<ItemData>();
			}
			Container val = StackifyPlugin.CurrentContainer.Invoke(InventoryGui.instance);
			if (onlyThisChest && (Object)(object)val == (Object)null)
			{
				return new List<ItemData>();
			}
			List<Container> chests = NearbyChests.ForPouch(player, onlyThisChest, val, StackifyPlugin.RestockRange.Value);
			return Simulate(NormalWants(player), chests, Room(player), out containers, out weight);
		}

		private static List<ItemData> Simulate(List<Want> wants, List<Container> chests, float room, out int containers, out float weight)
		{
			containers = 0;
			weight = 0f;
			List<ItemData> list = new List<ItemData>();
			if (wants.Count == 0)
			{
				return list;
			}
			foreach (Container chest in chests)
			{
				if (wants.Count == 0 || room <= 0f)
				{
					break;
				}
				Dictionary<string, int> dictionary = new Dictionary<string, int>();
				foreach (ItemData allItem in chest.GetInventory().GetAllItems())
				{
					if (allItem.m_customData == null || allItem.m_customData.Count <= 0)
					{
						string key = allItem.m_shared.m_name + "|" + allItem.m_quality;
						dictionary.TryGetValue(key, out var value);
						dictionary[key] = value + allItem.m_stack;
					}
				}
				bool flag = false;
				for (int num = wants.Count - 1; num >= 0; num--)
				{
					Want want = wants[num];
					string key2 = want.Item.m_shared.m_name + "|" + want.Item.m_quality;
					if (dictionary.TryGetValue(key2, out var value2) && value2 > 0)
					{
						int num2 = Fits(want, Math.Min(want.Max - want.Have, value2), room);
						if (num2 > 0)
						{
							dictionary[key2] = value2 - num2;
							want.Have += num2;
							float weight2 = want.Item.GetWeight(num2);
							room -= weight2;
							weight += weight2;
							flag = true;
							if (!list.Contains(want.Item))
							{
								list.Add(want.Item);
							}
							if (want.Have >= want.Max)
							{
								wants.RemoveAt(num);
							}
						}
					}
				}
				if (flag)
				{
					containers++;
				}
			}
			return list;
		}
	}
	internal static class Sorting
	{
		internal enum Mode
		{
			Type,
			Weight
		}

		[HarmonyPatch(typeof(Container), "Awake")]
		private static class RpcPatch
		{
			private static void Postfix(Container __instance)
			{
				ZNetView val = NearbyChests.NView.Invoke(__instance);
				if ((Object)(object)val == (Object)null || val.GetZDO() == null)
				{
					return;
				}
				Container c = __instance;
				val.Register<int>("WireStackify_RequestSort3", (Action<long, int>)delegate(long sender, int mode)
				{
					ZNetView val2 = NearbyChests.NView.Invoke(c);
					if ((Object)(object)val2 != (Object)null && val2.IsOwner())
					{
						Sort(c.GetInventory(), null, c.GetInventory().GetHeight(), (Mode)mode);
					}
				});
			}
		}

		private const string RpcName = "WireStackify_RequestSort3";

		private static readonly int[] TypeToCategory = new int[24]
		{
			0, 2, 4, 7, 7, 8, 10, 10, 0, 6,
			0, 10, 10, 1, 7, 7, 0, 10, 9, 7,
			7, 3, 7, 5
		};

		private static readonly FieldRef<InventoryGui, InventoryGrid> ContainerGrid = AccessTools.FieldRefAccess<InventoryGui, InventoryGrid>("m_containerGrid");

		private static GameObject _moveSound;

		private static bool _moveSearched;

		internal static bool Run(bool chest, Mode mode)
		{
			InventoryGui instance = InventoryGui.instance;
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)instance == (Object)null || (Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsTeleporting())
			{
				return false;
			}
			try
			{
				if (!chest)
				{
					return SortInventory(instance, localPlayer, mode);
				}
				Container val = StackifyPlugin.CurrentContainer.Invoke(instance);
				return (Object)(object)val != (Object)null && SortChest(instance, val, mode);
			}
			catch (Exception ex)
			{
				StackifyPlugin.Log.LogWarning((object)("Sorting failed: " + ex));
				return false;
			}
		}

		internal static int RunAll(IEnumerable<Container> chests, Mode mode)
		{
			InventoryGui instance = InventoryGui.instance;
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)instance == (Object)null || (Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsTeleporting())
			{
				return 0;
			}
			int num = 0;
			try
			{
				StackifyPlugin.DropDragItem();
				Inventory inventory = ((Humanoid)localPlayer).GetInventory();
				List<ItemData> list = Sort(inventory, Favorites.For(localPlayer), StackifyPlugin.MainRows(inventory, localPlayer), mode);
				num += list.Count;
				if (list.Count > 0)
				{
					((MonoBehaviour)StackifyEffects.Runner.Get()).StartCoroutine(Ripple(instance.m_playerGrid, list));
				}
				Container val = StackifyPlugin.CurrentContainer.Invoke(instance);
				foreach (Container chest in chests)
				{
					if ((Object)(object)chest == (Object)null)
					{
						continue;
					}
					ZNetView val2 = NearbyChests.NView.Invoke(chest);
					if ((Object)(object)val2 == (Object)null || !val2.IsValid())
					{
						continue;
					}
					if (StackifyPlugin.HasMuc || val2.IsOwner())
					{
						List<ItemData> list2 = Sort(chest.GetInventory(), null, chest.GetInventory().GetHeight(), mode);
						num += list2.Count;
						if (list2.Count > 0 && (Object)(object)chest == (Object)(object)val)
						{
							((MonoBehaviour)StackifyEffects.Runner.Get()).StartCoroutine(Ripple(ContainerGrid.Invoke(instance), list2));
						}
					}
					else
					{
						val2.InvokeRPC("WireStackify_RequestSort3", new object[1] { (int)mode });
					}
				}
			}
			catch (Exception ex)
			{
				StackifyPlugin.Log.LogWarning((object)("Sorting failed: " + ex));
			}
			if (num > 0)
			{
				Feedback(null, null);
			}
			return num;
		}

		private static bool SortInventory(InventoryGui gui, Player player, Mode mode)
		{
			StackifyPlugin.DropDragItem();
			Inventory inventory = ((Humanoid)player).GetInventory();
			List<ItemData> list = Sort(inventory, Favorites.For(player), StackifyPlugin.MainRows(inventory, player), mode);
			Feedback(gui.m_playerGrid, list);
			return list.Count > 0;
		}

		private static bool SortChest(InventoryGui gui, Container chest, Mode mode)
		{
			StackifyPlugin.DropDragItem();
			ZNetView val = NearbyChests.NView.Invoke(chest);
			if ((Object)(object)val == (Object)null || !val.IsValid())
			{
				return false;
			}
			if (StackifyPlugin.HasMuc || val.IsOwner())
			{
				List<ItemData> list = Sort(chest.GetInventory(), null, chest.GetInventory().GetHeight(), mode);
				Feedback(ContainerGrid.Invoke(gui), list);
				return list.Count > 0;
			}
			val.InvokeRPC("WireStackify_RequestSort3", new object[1] { (int)mode });
			Feedback(null, null);
			return true;
		}

		private static List<ItemData> Sort(Inventory inv, Favorites favorites, int rows, Mode mode)
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			bool flag = favorites == null || StackifyPlugin.SortHotbar.Value;
			List<ItemData> list = new List<ItemData>();
			HashSet<Vector2i> hashSet = new HashSet<Vector2i>();
			foreach (ItemData allItem in inv.GetAllItems())
			{
				if (allItem.m_gridPos.y < rows && (favorites == null || (!favorites.IsItemFavorited(allItem.m_shared) && (allItem.m_gridPos.y > 0 || flag) && !favorites.IsSlotFavorited(allItem.m_gridPos))))
				{
					list.Add(allItem);
				}
				else
				{
					hashSet.Add(allItem.m_gridPos);
				}
			}
			Dictionary<ItemData, Vector2i> dictionary = new Dictionary<ItemData, Vector2i>();
			foreach (ItemData item in list)
			{
				dictionary[item] = item.m_gridPos;
			}
			List<ItemData> list2 = new List<ItemData>();
			if (StackifyPlugin.SortMergeStacks.Value)
			{
				MergeStacks(list, inv, list2);
			}
			if (mode == Mode.Weight)
			{
				list.Sort(WeightOrder);
			}
			else
			{
				list.Sort(TypeOrder);
			}
			List<Vector2i> list3 = Slots(inv, rows, flag, favorites, hashSet);
			for (int i = 0; i < list.Count && i < list3.Count; i++)
			{
				list[i].m_gridPos = list3[i];
			}
			List<ItemData> list4 = new List<ItemData>();
			foreach (ItemData item2 in list)
			{
				if (dictionary[item2] != item2.m_gridPos)
				{
					list4.Add(item2);
				}
			}
			list4.AddRange(list2);
			if (list4.Count > 0)
			{
				StackifyPlugin.Changed(inv);
			}
			return list4;
		}

		private static List<Vector2i> Slots(Inventory inv, int h, bool hotbar, Favorites favorites, HashSet<Vector2i> kept)
		{
			//IL_0023: 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_0060: 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)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			int width = inv.GetWidth();
			int num = ((!hotbar) ? 1 : 0);
			List<Vector2i> list = new List<Vector2i>();
			for (int num2 = h - 1; num2 >= num; num2--)
			{
				for (int i = 0; i < width; i++)
				{
					list.Add(new Vector2i(i, num2));
				}
			}
			List<Vector2i> list2 = new List<Vector2i>(list.Count);
			foreach (Vector2i item in list)
			{
				if (!kept.Contains(item) && (favorites == null || !favorites.IsSlotFavorited(item)))
				{
					list2.Add(item);
				}
			}
			return list2;
		}

		private static int TypeGroup(ItemData item)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected I4, but got Unknown
			int num = (int)item.m_shared.m_itemType;
			if (num >= 0 && num < TypeToCategory.Length)
			{
				return TypeToCategory[num];
			}
			return num;
		}

		private static int TypeOrder(ItemData a, ItemData b)
		{
			int num = TypeGroup(a).CompareTo(TypeGroup(b));
			if (num == 0)
			{
				num = string.CompareOrdinal(a.m_shared.m_name, b.m_shared.m_name);
			}
			if (num == 0)
			{
				num = -a.m_quality.CompareTo(b.m_quality);
			}
			if (num == 0)
			{
				num = -a.m_stack.CompareTo(b.m_stack);
			}
			return num;
		}

		private static int WeightOrder(ItemData a, ItemData b)
		{
			int num = -a.GetWeight(-1).CompareTo(b.GetWeight(-1));
			if (num == 0)
			{
				return TypeOrder(a, b);
			}
			return num;
		}

		private static void MergeStacks(List<ItemData> items, Inventory inv, List<ItemData> merged)
		{
			Dictionary<string, List<ItemData>> dictionary = new Dictionary<string, List<ItemData>>();
			foreach (ItemData item in items)
			{
				if (item.m_stack < item.m_shared.m_maxStackSize && (item.m_customData == null || item.m_customData.Count <= 0))
				{
					string key = item.m_shared.m_name + "|" + item.m_quality;
					if (!dictionary.TryGetValue(key, out var value))
					{
						value = (dictionary[key] = new List<ItemData>());
					}
					value.Add(item);
				}
			}
			foreach (List<ItemData> value2 in dictionary.Values)
			{
				if (value2.Count <= 1)
				{
					continue;
				}
				int num = 0;
				foreach (ItemData item2 in value2)
				{
					num += item2.m_stack;
				}
				int maxStackSize = value2[0].m_shared.m_maxStackSize;
				foreach (ItemData item3 in value2)
				{
					if (num <= 0)
					{
						item3.m_stack = 0;
						inv.RemoveItem(item3);
						items.Remove(item3);
						merged.Add(item3);
					}
					else
					{
						item3.m_stack = Math.Min(maxStackSize, num);
						num -= item3.m_stack;
					}
				}
			}
		}

		private static void Feedback(InventoryGrid grid, List<ItemData> moved)
		{
			InventoryGui instance = InventoryGui.instance;
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)Player.m_localPlayer == (Object)null) && (moved == null || moved.Count != 0))
			{
				GameObject move = MoveSound(instance);
				((MonoBehaviour)StackifyEffects.Runner.Get()).StartCoroutine(Actions.After(0.1f, delegate
				{
					StackifyEffects.PlayUi(move);
				}));
				if (moved != null)
				{
					((MonoBehaviour)StackifyEffects.Runner.Get()).StartCoroutine(Ripple(grid, moved));
				}
			}
		}

		private static GameObject MoveSound(InventoryGui gui)
		{
			if ((Object)(object)_moveSound != (Object)null || _moveSearched)
			{
				return _moveSound;
			}
			_moveSearched = true;
			if (gui.m_moveItemEffects != null)
			{
				EffectData[] effectPrefabs = gui.m_moveItemEffects.m_effectPrefabs;
				foreach (EffectData val in effectPrefabs)
				{
					if (val != null && (Object)(object)val.m_prefab != (Object)null && ((Object)val.m_prefab).name == "sfx_gui_moveitem")
					{
						return _moveSound = val.m_prefab;
					}
				}
			}
			ZSFX[] array = Resources.FindObjectsOfTypeAll<ZSFX>();
			foreach (ZSFX val2 in array)
			{
				if ((Object)(object)val2 != (Object)null && ((Object)((Component)val2).gameObject).name == "sfx_gui_moveitem" && (Object)(object)((Component)val2).transform.parent == (Object)null)
				{
					return _moveSound = ((Component)val2).gameObject;
				}
			}
			StackifyPlugin.Log.LogWarning((object)"Couldn't find the game's item move sound.");
			return null;
		}

		private static IEnumerator Ripple(InventoryGrid grid, List<ItemData> moved)
		{
			int n = moved.Count;
			if (n == 0)
			{
				yield break;
			}
			float num = Mathf.Min(0.03f, 0.5f / (float)n);
			float[] at = new float[n];
			for (int i = 1; i < n; i++)
			{
				at[i] = at[i - 1] + num * Random.Range(0.6f, 1.4f);
			}
			List<RectTransform> icons = new List<RectTransform>(n);
			List<InventoryElement> list = (((Object)(object)grid != (Object)null) ? Favorites.GridElements.Invoke(grid) : null);
			Inventory val = (((Object)(object)grid != (Object)null) ? Favorites.GridInventory.Invoke(grid) : null);
			int num2 = ((val != null) ? val.GetWidth() : 0);
			foreach (ItemData item2 in moved)
			{
				RectTransform item = null;
				if (list != null && val != null && item2.m_stack > 0)
				{
					int num3 = item2.m_gridPos.y * num2 + item2.m_gridPos.x;
					if (num3 >= 0 && num3 < list.Count && (Object)(object)list[num3] != (Object)null && (Object)(object)list[num3].m_icon != (Object)null)
					{
						item = ((Graphic)list[num3].m_icon).rectTransform;
					}
				}
				icons.Add(item);
			}
			for (float t = 0f; t < at[n - 1] + 0.22f; t += Time.unscaledDeltaTime)
			{
				for (int j = 0; j < n; j++)
				{
					if (!((Object)(object)icons[j] == (Object)null))
					{
						float num4 = Mathf.Clamp01((t - at[j]) / 0.22f);
						float num5 = ((num4 <= 0f) ? 0.82f : (1f + Mathf.Sin(num4 * (float)Math.PI) * 0.12f * (1f - num4) - (1f - num4) * (1f - num4) * 0.18f));
						((Transform)icons[j]).localScale = new Vector3(num5, num5, 1f);
					}
				}
				yield return null;
			}
			foreach (RectTransform item3 in icons)
			{
				if ((Object)(object)item3 != (Object)null)
				{
					((Transform)item3).localScale = Vector3.one;
				}
			}
		}
	}
	internal static class StackifyButtons
	{
		private sealed class PendingIcon
		{
			public Image Image;

			public Color Color;

			public bool Chest;
		}

		internal sealed class ClickHandler : MonoBehaviour, IPointerDownHandler, IEventSystemHandler
		{
			public bool Chest;

			public void OnPointerDown(PointerEventData e)
			{
				//IL_0041: 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_004f: Invalid comparison between Unknown and I4
				//IL_0052: Unknown result type (might be due to invalid IL or missing references)
				//IL_0058: Invalid comparison between Unknown and I4
				InventoryGui instance = InventoryGui.instance;
				if (!((Object)(object)Player.m_localPlayer == (Object)null) && !((Object)(object)instance == (Object)null))
				{
					ItemData val = Holding(instance);
					if (val != null)
					{
						Actions.DropOn(Chest, val, DragInventory.Invoke(instance));
					}
					else
					{
						Actions.Do(Actions.ForButton(((int)e.button != 0) ? (((int)e.button == 1) ? 1 : (((int)e.button == 2) ? 2 : (-1))) : 0, Actions.Shift()), Chest);
					}
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "SetupDragItem")]
		private static class DragPatch
		{
			private static void Postfix(InventoryGui __instance)
			{
				UpdateOpen(__instance);
				RefreshHover();
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "Show")]
		private static class ShowPatch
		{
			private static void Postfix(InventoryGui __instance)
			{
				SetIcons();
				UpdateCounts();
				UpdateOpen(__instance);
			}
		}

		[HarmonyPatch(typeof(Inventory), "Changed")]
		private static class CountPatch
		{
			private static void Postfix(Inventory __instance)
			{
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)InventoryGui.instance == (Object)null))
				{
					Container val = StackifyPlugin.CurrentContainer.Invoke(InventoryGui.instance);
					if (__instance == ((Humanoid)localPlayer).GetInventory() || ((Object)(object)val != (Object)null && __instance == val.GetInventory()))
					{
						UpdateCounts();
					}
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "Awake")]
		private static class AwakePatch
		{
			private static void Postfix(InventoryGui __instance)
			{
				try
				{
					Build(__instance);
				}
				catch (Exception ex)
				{
					StackifyPlugin.Log.LogWarning((object)("Couldn't add the Stackify buttons: " + ex));
				}
			}
		}

		internal sealed class TipRefresh : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler
		{
			public bool Chest;

			public void OnPointerEnter(PointerEventData e)
			{
				Enter(Chest);
			}

			public void OnPointerExit(PointerEventData e)
			{
				Exit(Chest);
			}

			private void OnDisable()
			{
				Exit(Chest);
			}
		}

		private const string Name = "WireStackify";

		private const string Topic = "Stackify";

		private const string ChestTopic = "Stackify (Container)";

		private static readonly List<PendingIcon> Pending = new List<PendingIcon>();

		private static readonly List<KeyValuePair<Image, bool>> Icons = new List<KeyValuePair<Image, bool>>();

		private static bool _openInv;

		private static bool _openChest;

		private static Sprite _pouch;

		private static Sprite _open;

		private static Sprite _closed;

		private static bool _openTried;

		private static bool _closedTried;

		private static bool _flashInv;

		private static bool _flashChest;

		private static int _flashToken;

		private static readonly List<KeyValuePair<UITooltip, bool>> Tips = new List<KeyValuePair<UITooltip, bool>>();

		private static RectTransform _tooltipAnchor;

		private static readonly FieldRef<InventoryGui, InventoryGrid> ContainerGrid = AccessTools.FieldRefAccess<InventoryGui, InventoryGrid>("m_containerGrid");

		internal static readonly FieldRef<InventoryGui, ItemData> DragItem = AccessTools.FieldRefAccess<InventoryGui, ItemData>("m_dragItem");

		private static readonly FieldRef<InventoryGui, Inventory> DragInventory = AccessTools.FieldRefAccess<InventoryGui, Inventory>("m_dragInventory");

		private static bool _hovering;

		private static bool _hoverChest;

		private static string _previewChest = "";

		private static string _previewInv = "";

		private const float FlashTime = 0.7f;

		private static TMP_Text _invCount;

		private static TMP_Text _chestCount;

		private static readonly StackAction[] TipOrder = new StackAction[6]
		{
			StackAction.QuickStack,
			StackAction.Restock,
			StackAction.QuickStackAndRestock,
			StackAction.Sort,
			StackAction.SortByWeight,
			StackAction.Everything
		};

		private static ItemData Holding(InventoryGui gui)
		{
			if ((Object)(object)gui == (Object)null || !StackifyPlugin.DropOnPouch.Value || (Object)(object)StackifyPlugin.DragGo.Invoke(gui) == (Object)null)
			{
				return null;
			}
			return DragItem.Invoke(gui);
		}

		internal static void Feedback(StackifyEffects.Kind kind, int count, bool chest)
		{
			if (count > 0)
			{
				ButtonFeel.Result(kind, count, chest);
				Flash(chest);
			}
		}

		internal static void Enter(bool chest)
		{
			_hovering = true;
			_hoverChest = chest;
			ButtonFeel.Hover(chest, on: true);
			RefreshHover();
		}

		internal static void Exit(bool chest)
		{
			if (_hovering && _hoverChest == chest)
			{
				_hovering = false;
				ButtonFeel.Hover(chest, on: false);
				Favorites.ClearPreview();
			}
		}

		internal static void RefreshHover()
		{
			if (!_hovering)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			string text = "";
			if ((Object)(object)localPlayer != (Object)null && StackifyPlugin.HoverPreview.Value)
			{
				try
				{
					ItemData val = Holding(InventoryGui.instance);
					int chests = 0;
					bool flag = val != null && _hoverChest;
					List<ItemData> list = (flag ? null : QuickStack.Preview(localPlayer, _hoverChest, out chests, val));
					int containers = 0;
					float weight = 0f;
					List<ItemData> list2 = ((val == null) ? Restock.Preview(localPlayer, _hoverChest, out containers, out weight) : (flag ? Restock.PreviewOnly(localPlayer, StackifyPlugin.CurrentContainer.Invoke(InventoryGui.instance), val, out weight) : null));
					float num = 0f;
					if (list != null)
					{
						foreach (ItemData item in list)
						{
							num += item.GetWeight(-1);
						}
					}
					Favorites.ShowPreview(list, list2);
					if (flag && list2.Count > 0)
					{
						containers = 1;
					}
					string text2 = Favorites.YellowHex();
					string text3 = Favorites.BlueHex();
					text = "\n";
					if (list != null)
					{
						text = text + "\n" + ((list.Count == 0) ? "Quick stack: nothing" : ("Quick stack: <color=#" + text2 + ">" + Stacks(list.Count) + "</color> into " + Containers(chests) + Weight(0f - num, text2)));
					}
					if (list2 != null)
					{
						text = text + "\n" + ((list2.Count == 0) ? "Restock: nothing" : ("Restock: <color=#" + text3 + ">" + Stacks(list2.Count) + "</color> from " + Containers(containers) + Weight(weight, text3)));
					}
				}
				catch (Exception ex)
				{
					StackifyPlugin.Log.LogWarning((object)("Stackify preview failed: " + ex));
				}
			}
			else
			{
				Favorites.ClearPreview();
			}
			if (_hoverChest)
			{
				_previewChest = text;
			}
			else
			{
				_previewInv = text;
			}
			UpdateTips(_hoverChest ? 1 : 0);
		}

		private static string Stacks(int n)
		{
			if (n != 1)
			{
				return n + " stacks";
			}
			return "1 stack";
		}

		private static string Weight(float w, string hex)
		{
			if (Mathf.Abs(w) < 0.05f)
			{
				return "";
			}
			return "\n<color=#" + hex + ">" + ((w > 0f) ? "+" : "-") + Mathf.Abs(w).ToString("0.#", CultureInfo.InvariantCulture) + "</color> weight";
		}

		private static string Containers(int n)
		{
			return "<color=orange>" + n + "</color>" + ((n == 1) ? " container" : " containers");
		}

		private static void UpdateOpen(InventoryGui gui)
		{
			bool flag = false;
			bool flag2 = false;
			Player localPlayer = Player.m_localPlayer;
			ItemData val = Holding(gui);
			if (val != null && (Object)(object)localPlayer != (Object)null)
			{
				try
				{
					flag = QuickStack.Preview(localPlayer, onlyThisChest: false, out var _, val).Count > 0;
					flag2 = Restock.PreviewOnly(localPlayer, StackifyPlugin.CurrentContainer.Invoke(gui), val, out var _).Count > 0;
				}
				catch (Exception ex)
				{
					StackifyPlugin.Log.LogWarning((object)("Stackify open pouch: " + ex.Message));
				}
			}
			if (flag != _openInv)
			{
				_openInv = flag;
				Refresh(chest: false);
			}
			if (flag2 != _openChest)
			{
				_openChest = flag2;
				Refresh(chest: true);
			}
		}

		internal static void Flash(bool chest)
		{
			if (chest)
			{
				_flashChest = true;
			}
			else
			{
				_flashInv = true;
			}
			int token = ++_flashToken;
			Refresh(chest);
			((MonoBehaviour)StackifyEffects.Runner.Get()).StartCoroutine(Actions.After(0.7f, delegate
			{
				if (token == _flashToken)
				{
					_flashInv = (_flashChest = false);
					Refresh(chest: false);
					Refresh(chest: true);
				}
			}));
		}

		private static void Refresh(bool chest)
		{
			if ((Object)(object)_pouch == (Object)null)
			{
				return;
			}
			bool flag = ((!chest) ? (_openInv || _flashInv) : (_openChest || _flashChest));
			Sprite val = (flag ? OpenPouch() : Closed());
			if ((Object)(object)val == (Object)null)
			{
				val = Closed();
			}
			for (int num = Icons.Count - 1; num >= 0; num--)
			{
				Image key = Icons[num].Key;
				if ((Object)(object)key == (Object)null)
				{
					Icons.RemoveAt(num);
				}
				else if (Icons[num].Value == chest && !((Object)(object)key.sprite == (Object)(object)val))
				{
					key.sprite = val;
					ButtonFeel.Pop(chest, flag);
				}
			}
		}

		private static Sprite Closed()
		{
			if ((Object)(object)_closed != (Object)null || _closedTried || (Object)(object)_pouch == (Object)null)
			{
				if (!((Object)(object)_closed != (Object)null))
				{
					return _pouch;
				}
				return _closed;
			}
			_closedTried = true;
			_closed = LoadSprite("pouch_closed");
			if (!((Object)(object)_closed != (Object)null))
			{
				return _pouch;
			}
			return _closed;
		}

		private static Sprite OpenPouch()
		{
			if ((Object)(object)_open != (Object)null || _openTried || (Object)(object)_pouch == (Object)null)
			{
				return _open;
			}
			_openTried = true;
			_open = LoadSprite("pouch_open");
			return _open;
		}

		private static Sprite LoadSprite(string name)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("WiresStackify.Assets." + name + ".png");
				if (stream == null)
				{
					return null;
				}
				byte[] array = new byte[stream.Length];
				int num;
				for (int i = 0; i < array.Length; i += num)
				{
					num = stream.Read(array, i, array.Length - i);
					if (num <= 0)
					{
						break;
					}
				}
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
				MethodInfo method = typeof(ImageConversion).GetMethod("LoadImage", new Type[2]
				{
					typeof(Texture2D),
					typeof(byte[])
				});
				if (method == null || !(bool)method.Invoke(null, new object[2] { val, array }))
				{
					return null;
				}
				((Texture)val).wrapMode = (TextureWrapMode)1;
				if ((Object)(object)_pouch.texture != (Object)null)
				{
					((Texture)val).filterMode = ((Texture)_pouch.texture).filterMode;
				}
				Rect rect = _pouch.rect;
				Vector2 val2 = default(Vector2);
				((Vector2)(ref val2))..ctor(_pouch.pivot.x / ((Rect)(ref rect)).width, _pouch.pivot.y / ((Rect)(ref rect)).height);
				Sprite obj = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), val2, _pouch.pixelsPerUnit * (float)((Texture)val).width / ((Rect)(ref rect)).width);
				((Object)obj).name = "WireStackify_" + name;
				return obj;
			}
			catch (Exception ex)
			{
				StackifyPlugin.Log.LogWarning((object)("Couldn't load " + name + ": " + ex.Message));
				return null;
			}
		}

		private static void CursorHand(GameObject go)
		{
			try
			{
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly in assemblies)
				{
					if (!(assembly.GetName().Name != "WiresNativeCursorSupport"))
					{
						Type type = assembly.GetType("WiresNativeCursorSupport.NativeCursorApi");
						MethodInfo methodInfo = ((type != null) ? type.GetMethod("SetHand", BindingFlags.Static | BindingFlags.Public) : null);
						if (methodInfo != null)
						{
							methodInfo.Invoke(null, new object[1] { go });
						}
						break;
					}
				}
			}
			catch (Exception ex)
			{
				StackifyPlugin.Log.LogDebug((object)("Native Cursor Support hand: " + ex.Message));
			}
		}

		internal static void UpdateCounts()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			if ((Object)(object)_invCount != (Object)null)
			{
				Inventory inventory = ((Humanoid)localPlayer).GetInventory();
				int num = StackifyPlugin.MainRows(inventory, localPlayer);
				int num2 = 0;
				foreach (ItemData allItem in inventory.GetAllItems())
				{
					if (allItem.m_gridPos.y < num)
					{
						num2++;
					}
				}
				SetCount(_invCount, num2);
			}
			if ((Object)(object)_chestCount != (Object)null && (Object)(object)InventoryGui.instance != (Object)null)
			{
				Container val = StackifyPlugin.CurrentContainer.Invoke(InventoryGui.instance);
				if ((Object)(object)val != (Object)null)
				{
					SetCount(_chestCount, val.GetInventory().GetAllItems().Count);
				}
			}
		}

		private static void SetCount(TMP_Text t, int n)
		{
			string text = n.ToString();
			if (t.text != text)
			{
				t.text = text;
			}
		}

		private static void SetIcons()
		{
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			if (Pending.Count == 0)
			{
				return;
			}
			if ((Object)(object)_pouch == (Object)null && (Object)(object)Minimap.instance != (Object)null && Minimap.instance.m_locationIcons != null)
			{
				foreach (LocationSpriteData locationIcon in Minimap.instance.m_locationIcons)
				{
					if ((Object)(object)locationIcon.m_icon != (Object)null && ((Object)locationIcon.m_icon).name == "mapicon_trader")
					{
						_pouch = locationIcon.m_icon;
						break;
					}
				}
			}
			for (int num = Pending.Count - 1; num >= 0; num--)
			{
				PendingIcon pendingIcon = Pending[num];
				Sprite val = Closed();
				if ((Object)(object)pendingIcon.Image == (Object)null)
				{
					Pending.RemoveAt(num);
				}
				else if (!((Object)(object)val == (Object)null))
				{
					pendingIcon.Image.sprite = val;
					Icons.Add(new KeyValuePair<Image, bool>(pendingIcon.Image, pendingIcon.Chest));
					((Graphic)pendingIcon.Image).color = pendingIcon.Color;
					RectTransform rectTransform = ((Graphic)pendingIcon.Image).rectTransform;
					rectTransform.sizeDelta *= 1.1875f;
					ButtonFeel componentInParent = ((Component)pendingIcon.Image).GetComponentInParent<ButtonFeel>();
					if ((Object)(object)componentInParent != (Object)null)
					{
						componentInParent.IconReady();
					}
					Pending.RemoveAt(num);
				}
			}
		}

		private static void Build(InventoryGui gui)
		{
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = (RectTransform)(((Object)(object)gui.m_armor != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
			RectTransform val2 = (RectTransform)(((Object)(object)gui.m_weight != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
			RectTransform val3 = (RectTransform)(((Object)(object)gui.m_containerWeight != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
			if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null))
			{
				InventoryGrid val4 = ContainerGrid.Invoke(gui);
				_tooltipAnchor = (((Object)(object)val4 != (Object)null) ? val4.m_tooltipAnchor : null);
				UITooltip template = (((Object)(object)val4 != (Object)null && (Object)(object)val4.m_elementPrefab != (Object)null) ? val4.m_elementPrefab.GetComponent<UITooltip>() : null);
				WeightShake.Add(val2, chest: false);
				if ((Object)(object)val3 != (Object)null)
				{
					WeightShake.Add(val3, chest: true);
				}
				RectTransform val5 = Clone(val, gui.m_armor, chest: false, template);
				((Transform)val5).localPosition = (((Transform)val).localPosition + ((Transform)val2).localPosition) * 0.5f;
				if ((Object)(object)val3 != (Object)null)
				{
					((Transform)Clone(val3, gui.m_containerWeight, chest: true, template)).localPosition = ((Transform)val3).localPosition + (((Transform)val5).localPosition - ((Transform)val2).localPosition);
				}
				UpdateTips();
				((BaseUnityPlugin)StackifyPlugin.Instance).Config.SettingChanged += delegate
				{
					UpdateTips();
				};
				SetIcons();
			}
		}

		private static RectTransform Clone(RectTransform block, TMP_Text valueText, bool chest, UITooltip template)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = Object.Instantiate<GameObject>(((Component)block).gameObject, ((Transform)block).parent, false);
			((Object)val).name = "WireStackify" + (chest ? "Chest" : "Inventory");
			RectTransform val2 = (RectTransform)val.transform;
			((Transform)val2).SetSiblingIndex(((Transform)block).GetSiblingIndex() + 1);
			string text = RelativePath(valueText.transform, (Transform)(object)block);
			TMP_Text val3 = null;
			TMP_Text[] componentsInChildren = val.GetComponentsInChildren<TMP_Text>(true);
			foreach (TMP_Text val4 in componentsInChildren)
			{
				if (RelativePath(val4.transform, (Transform)(object)val2) == text)
				{
					val4.text = "";
					val3 = val4;
					if (chest)
					{
						_chestCount = val4;
					}
					else
					{
						_invCount = val4;
					}
				}
				((Graphic)val4).raycastTarget = false;
			}
			Image val5 = null;
			Image[] componentsInChildren2 = val.GetComponentsInChildren<Image>(true);
			foreach (Image val6 in componentsInChildren2)
			{
				if (((Object)val6).name.IndexOf("icon", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					val6.sprite = null;
					Pending.Add(new PendingIcon
					{
						Image = val6,
						Color = ((Graphic)val6).color,
						Chest = chest
					});
					((Graphic)val6).color = new Color(1f, 1f, 1f, 0f);
					val6.preserveAspect = true;
					((Graphic)val6).raycastTarget = false;
					val5 = val6;
				}
				else
				{
					((Graphic)val6).raycastTarget = true;
				}
			}
			GameObject val7 = new GameObject("HitArea", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			RectTransform val8 = (RectTransform)val7.transform;
			((Transform)val8).SetParent((Transform)(object)val2, false);
			((Transform)val8).SetAsLastSibling();
			val8.anchorMin = Vector2.zero;
			val8.anchorMax = Vector2.one;
			Vector2 offsetMin = (val8.offsetMax = Vector2.zero);
			val8.offsetMin = offsetMin;
			Image component = val7.GetComponent<Image>();
			((Graphic)component).color = new Color(0f, 0f, 0f, 0f);
			((Graphic)component).raycastTarget = true;
			UITooltip[] componentsInChildren3 = val.GetComponentsInChildren<UITooltip>(true);
			for (int i = 0; i < componentsInChildren3.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren3[i]);
			}
			val.AddComponent<TipRefresh>().Chest = chest;
			UITooltip val9 = val.AddComponent<UITooltip>();
			if ((Object)(object)template != (Object)null)
			{
				FieldInfo[] fields = typeof(UITooltip).GetFields(BindingFlags.Instance | BindingFlags.Public);
				foreach (FieldInfo fieldInfo in fields)
				{
					if (!fieldInfo.IsInitOnly)
					{
						fieldInfo.SetValue(val9, fieldInfo.GetValue(template));
					}
				}
			}
			val9.m_gamepadFocusObject = null;
			Tips.Add(new KeyValuePair<UITooltip, bool>(val9, chest));
			ButtonFeel buttonFeel = val.AddComponent<ButtonFeel>();
			val.AddComponent<FeelReset>().Feel = buttonFeel;
			buttonFeel.Setup(((Object)(object)val5 != (Object)null) ? ((Graphic)val5).rectTransform : null, ((Object)(object)val3 != (Object)null) ? val3.rectTransform : null, val5, chest);
			val.AddComponent<ClickHandler>().Chest = chest;
			CursorHand(val);
			return val2;
		}

		private static string NearbyLine()
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return "";
			}
			if (!NearbyChests.AreaAllowed())
			{
				return "\nNearby containers: only with Multi User Chest in multiplayer";
			}
			float num = Mathf.Max(StackifyPlugin.QuickStackRange.Value, StackifyPlugin.RestockRange.Value);
			if (num <= 0f)
			{
				return "";
			}
			bool singleplayer = NearbyChests.IsTrueSingleplayer();
			long playerID = localPlayer.GetPlayerID();
			int num2 = 0;
			foreach (Container item in NearbyChests.InRange(((Component)localPlayer).transform.position, num))
			{
				if (NearbyChests.CanUse(item, playerID, singleplayer))
				{
					num2++;
				}
			}
			return "\nContainers in range: <color=orange>" + num2 + "</color>";
		}

		private static void UpdateTips(int which = -1)
		{
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			List<KeyValuePair<string, StackAction>> list = Bindings();
			foreach (KeyValuePair<UITooltip, bool> tip in Tips)
			{
				if ((Object)(object)tip.Key == (Object)null || (which >= 0 && tip.Value != (which == 1)))
				{
					continue;
				}
				bool value = tip.Value;
				StringBuilder stringBuilder = new StringBuilder();
				StackAction[] tipOrder = TipOrder;
				foreach (StackAction stackAction in tipOrder)
				{
					string text = null;
					foreach (KeyValuePair<string, StackAction> item in list)
					{
						if (item.Value == stackAction)
						{
							text = ((text == null) ? item.Key : (text + " or " + item.Key));
						}
					}
					if (text != null)
					{
						stringBuilder.Append("\n<color=orange>").Append(text).Append("</color>: ")
							.Append(Actions.Describe(stackAction));
					}
				}
				if (StackifyPlugin.DropOnPouch.Value)
				{
					stringBuilder.Append(value ? "\n<color=orange>Click while holding an item</color>: restock held item type" : "\n<color=orange>Click while holding an item</color>: quick stack held item type");
				}
				stringBuilder.Append("\n").Append(value ? "\nOnly works in this container." : NearbyLine());
				stringBuilder.Append(value ? _previewChest : _previewInv);
				tip.Key.Set(value ? "Stackify (Container)" : "Stackify", stringBuilder.ToString().TrimStart(new char[1] { '\n' }), _tooltipAnchor, default(Vector2));
			}
		}

		private static List<KeyValuePair<string, StackAction>> Bindings()
		{
			List<KeyValuePair<string, StackAction>> list = new List<KeyValuePair<string, StackAction>>
			{
				new KeyValuePair<string, StackAction>("Left click", StackifyPlugin.LeftClick.Value),
				new KeyValuePair<string, StackAction>("Right click", StackifyPlugin.RightClick.Value),
				new KeyValuePair<string, StackAction>("Middle click", StackifyPlugin.MiddleClick.Value)
			};
			StackAction value = StackifyPlugin.ShiftLeftClick.Value;
			StackAction value2 = StackifyPlugin.ShiftRightClick.Value;
			StackAction value3 = StackifyPlugin.ShiftMiddleClick.Value;
			if (value == value2 && value2 == value3)
			{
				list.Add(new KeyValuePair<string, StackAction>("Shift + click", value));
			}
			else
			{
				list.Add(new KeyValuePair<string, StackAction>("Shift + left click", value));
				list.Add(new KeyValuePair<string, StackAction>("Shift + right click", value2));
				list.Add(new KeyValuePair<string, StackAction>("Shift + middle click", value3));
			}
			return list;
		}

		private static string RelativePath(Transform t, Transform root)
		{
			string text = "";
			while ((Object)(object)t != (Object)null && (Object)(object)t != (Object)(object)root)
			{
				text = ((Object)t).name + "/" + text;
				t = t.parent;
			}
			return text;
		}
	}
	internal sealed class ButtonFeel : MonoBehaviour
	{
		private struct Spring
		{
			public float X;

			public float V;

			public bool Settled
			{
				get
				{
					if (Mathf.Abs(X) < 0.002f)
					{
						return Mathf.Abs(V) < 0.02f;
					}
					return false;
				}
			}

			public void Step(float dt, float stiffness, float damping)
			{
				V += ((0f - X) * stiffness - V * damping) * dt;
				X += V * dt;
			}
		}

		private static readonly List<ButtonFeel> All = new List<ButtonFeel>();

		private RectTransform _icon;

		private RectTransform _label;

		private Image _iconImage;

		private TMP_Text _labelText;

		private bool _chest;

		private Vector3 _iconPos;

		private Vector3 _iconScale;

		private Color _iconColor;

		private Color _labelColor;

		private bool _hasBase;

		private bool _iconColorKnown;

		private Spring _grow;

		private Spring _hop;

		private Spring