Decompiled source of SafeQuickStack v1.0.1

Dupo_SafeQuickStack.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Dupo_SafeQuickStack")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1+e88e032ed8c63866f512c923cec834943bfc538c")]
[assembly: AssemblyProduct("Dupo_SafeQuickStack")]
[assembly: AssemblyTitle("Dupo_SafeQuickStack")]
[assembly: AssemblyVersion("1.0.1.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 Dupo.SafeQuickStack
{
	[BepInPlugin("dupo.SafeQuickStack", "Dupo_SafeQuickStack", "1.0.1")]
	public class Plugin : BaseUnityPlugin
	{
		internal static class QuickStack
		{
			[HarmonyPatch(typeof(Container), "RPC_StackResponse")]
			private static class StackResponsePatch
			{
				private static bool Prefix(Container __instance, bool granted)
				{
					if (!Pending.Contains(__instance))
					{
						return true;
					}
					OnResponse(__instance, granted);
					return false;
				}
			}

			internal static ConfigEntry<KeyboardShortcut> Hotkey;

			internal static ConfigEntry<float> Range;

			internal static ConfigEntry<bool> KeepHotbar;

			internal static ConfigEntry<bool> IncludeNonStackable;

			internal static ConfigEntry<bool> PlayerBuiltOnly;

			internal static ConfigEntry<bool> IncludeCartsAndShips;

			private const float GrantSettleDelay = 0.25f;

			private const float RequestTimeout = 3f;

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

			private static readonly MethodInfo LoadMethod = AccessTools.Method(typeof(Container), "Load", (Type[])null, (Type[])null);

			private static readonly HashSet<Container> Pending = new HashSet<Container>();

			private static float _requestTime;

			private static int _movedItems;

			private static int _filledChests;

			private static int _refusedChests;

			internal static void Bind(ConfigFile config)
			{
				//IL_001b: 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_0062: Expected O, but got Unknown
				Hotkey = config.Bind<KeyboardShortcut>("2 - Quick Stack", "Hotkey", new KeyboardShortcut((KeyCode)103, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Key that moves the items from your inventory into nearby chests that already contain the same item.");
				Range = config.Bind<float>("2 - Quick Stack", "Range", 10f, new ConfigDescription("Maximum distance from you to a chest, in meters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), Array.Empty<object>()));
				KeepHotbar = config.Bind<bool>("2 - Quick Stack", "Keep Hotbar Items", true, "Never move the items in your hotbar (the first inventory row, keys 1-8).");
				IncludeNonStackable = config.Bind<bool>("2 - Quick Stack", "Include Non-Stackable Items", false, "Also move items that do not stack, such as weapons, tools and armor, when a chest has the same one. Equipped items are never moved.");
				PlayerBuiltOnly = config.Bind<bool>("2 - Quick Stack", "Player-Built Chests Only", true, "Only use chests built by a player. Skips chests found in dungeons and villages.");
				IncludeCartsAndShips = config.Bind<bool>("2 - Quick Stack", "Include Carts and Ships", false, "Also use the storage of carts and ships.");
			}

			internal static void Update()
			{
				//IL_0051: Unknown result type (might be due to invalid IL or missing references)
				//IL_0056: Unknown result type (might be due to invalid IL or missing references)
				if (Pending.Count > 0 && Time.time - _requestTime > 3f)
				{
					Debug($"QuickStack: {Pending.Count} chest(s) did not answer, giving up");
					Pending.Clear();
					ShowSummary();
				}
				KeyboardShortcut value = Hotkey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown() && CanUseHotkeys() && Pending.Count <= 0)
				{
					Start(Player.m_localPlayer);
				}
			}

			private static void Start(Player player)
			{
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: 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)
				_movedItems = 0;
				_filledChests = 0;
				_refusedChests = 0;
				_requestTime = Time.time;
				Inventory inventory = ((Humanoid)player).GetInventory();
				Vector3 position = ((Component)player).transform.position;
				float value = Range.Value;
				List<Container> list = new List<Container>();
				Container[] array = Object.FindObjectsByType<Container>((FindObjectsSortMode)0);
				foreach (Container val in array)
				{
					if (IsCandidate(val, inventory, position, value))
					{
						list.Add(val);
					}
				}
				Debug($"QuickStack: requesting {list.Count} chest(s)");
				if (list.Count == 0)
				{
					ShowSummary();
					return;
				}
				foreach (Container item in list)
				{
					Pending.Add(item);
				}
				foreach (Container item2 in list)
				{
					item2.StackAll();
				}
			}

			private static bool IsCandidate(Container container, Inventory playerInventory, Vector3 position, float range)
			{
				//IL_003e: 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_00d0: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)container == (Object)null || container.GetInventory() == null)
				{
					return false;
				}
				ZNetView val = NViewRef.Invoke(container);
				if ((Object)(object)val == (Object)null || !val.IsValid())
				{
					return false;
				}
				if (container.GetInventory() == playerInventory)
				{
					return false;
				}
				if (Vector3.Distance(position, ((Component)container).transform.position) > range)
				{
					return false;
				}
				if ((Object)(object)((Component)container).GetComponentInParent<TombStone>() != (Object)null)
				{
					return false;
				}
				if (!IncludeCartsAndShips.Value && ((Object)(object)container.m_wagon != (Object)null || (Object)(object)((Component)container).GetComponentInParent<Vagon>() != (Object)null || (Object)(object)((Component)container).GetComponentInParent<Ship>() != (Object)null))
				{
					return false;
				}
				if (PlayerBuiltOnly.Value)
				{
					Piece componentInParent = ((Component)container).GetComponentInParent<Piece>();
					if ((Object)(object)componentInParent == (Object)null || !componentInParent.IsPlacedByPlayer())
					{
						return false;
					}
				}
				if (container.m_checkGuardStone && !PrivateArea.CheckAccess(((Component)container).transform.position, 0f, false, false))
				{
					return false;
				}
				foreach (ItemData allItem in playerInventory.GetAllItems())
				{
					if (CanMove(allItem) && container.GetInventory().ContainsItemByName(allItem.m_shared.m_name))
					{
						return true;
					}
				}
				return false;
			}

			private static bool CanMove(ItemData item)
			{
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null || ((Humanoid)localPlayer).IsItemEquiped(item))
				{
					return false;
				}
				if (KeepHotbar.Value && item.m_gridPos.y == 0)
				{
					return false;
				}
				if (SlotLocks.IsLocked(item.m_gridPos))
				{
					return false;
				}
				if (!IncludeNonStackable.Value && item.m_shared.m_maxStackSize <= 1)
				{
					return false;
				}
				return true;
			}

			private static void OnResponse(Container container, bool granted)
			{
				if (!granted)
				{
					Debug("QuickStack: " + ((Object)container).name + " refused (in use or private)");
					_refusedChests++;
					Finish(container);
				}
				else
				{
					((MonoBehaviour)Instance).StartCoroutine(StackWhenSettled(container));
				}
			}

			private static IEnumerator StackWhenSettled(Container container)
			{
				yield return (object)new WaitForSeconds(0.25f);
				Player localPlayer = Player.m_localPlayer;
				ZNetView val = (((Object)(object)container != (Object)null) ? NViewRef.Invoke(container) : null);
				if ((Object)(object)localPlayer == (Object)null || (Object)(object)val == (Object)null || !val.IsValid() || !val.IsOwner())
				{
					Debug("QuickStack: chest lost or no longer ours, skipped");
					if ((Object)(object)container != (Object)null)
					{
						_refusedChests++;
					}
					Finish(container);
					yield break;
				}
				LoadMethod.Invoke(container, null);
				int num = MoveItems(((Humanoid)localPlayer).GetInventory(), container.GetInventory());
				if (num > 0)
				{
					_movedItems += num;
					_filledChests++;
					InventoryGui instance = InventoryGui.instance;
					if (instance != null)
					{
						instance.m_moveItemEffects.Create(((Component)container).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
					}
				}
				Debug($"QuickStack: moved {num} item(s) into {((Object)container).name}");
				Finish(container);
			}

			private static int MoveItems(Inventory from, Inventory to)
			{
				int num = 0;
				foreach (ItemData item in new List<ItemData>(from.GetAllItems()))
				{
					if (CanMove(item) && to.ContainsItemByName(item.m_shared.m_name))
					{
						int stack = item.m_stack;
						if (to.AddItem(item))
						{
							from.RemoveItem(item);
							num += stack;
						}
						else
						{
							num += stack - item.m_stack;
						}
					}
				}
				return num;
			}

			private static void Finish(Container container)
			{
				if (Pending.Remove(container) && Pending.Count == 0)
				{
					ShowSummary();
				}
			}

			private static void ShowSummary()
			{
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null))
				{
					string text = ((_movedItems > 0) ? $"Quick Stack: {_movedItems} item(s) into {_filledChests} chest(s)" : "Quick Stack: nothing to stack");
					if (_refusedChests > 0)
					{
						string text2 = ((_refusedChests == 1) ? "1 chest" : $"{_refusedChests} chests");
						text = text + "\n<color=#FF9933><b>" + text2 + " in use by another player: skipped</b></color>";
					}
					((Character)localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false);
				}
			}
		}

		internal static class SlotLocks
		{
			internal enum IconPosition
			{
				Center,
				Left,
				Right,
				TopLeft,
				TopRight,
				BottomLeft,
				BottomRight
			}

			[HarmonyPatch(typeof(InventoryGui), "OnSelectedItem")]
			private static class SelectItemPatch
			{
				private static bool Prefix(InventoryGui __instance, InventoryGrid grid, Vector2i pos)
				{
					//IL_001a: 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_0042: 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)
					if (!Active() || (Object)(object)grid != (Object)(object)__instance.m_playerGrid || !ZInput.GetKey(LockKey.Value, true))
					{
						return true;
					}
					if (DragItemRef.Invoke(__instance) != null)
					{
						return true;
					}
					if (pos.x < 0 || pos.y < 0)
					{
						return true;
					}
					Toggle(pos);
					return false;
				}
			}

			[HarmonyPatch(typeof(InventoryGrid), "UpdateGui")]
			private static class UpdateGuiPatch
			{
				private static void Postfix(InventoryGrid __instance, Player player)
				{
					//IL_0054: Unknown result type (might be due to invalid IL or missing references)
					//IL_00af: Unknown result type (might be due to invalid IL or missing references)
					//IL_00b9: Expected O, but got Unknown
					if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || __instance.GetInventory() != ((Humanoid)player).GetInventory())
					{
						return;
					}
					bool flag = Active();
					foreach (InventoryElement item in ElementsRef.Invoke(__instance))
					{
						if ((Object)(object)item == (Object)null)
						{
							continue;
						}
						bool flag2 = flag && IsLocked(item.Position);
						Transform val = ((Component)item).transform.Find("SafeQuickStack_Lock");
						if ((Object)(object)val == (Object)null)
						{
							if (!flag2)
							{
								continue;
							}
							val = CreateIcon(((Component)item).transform);
						}
						if (((Component)val).gameObject.activeSelf != flag2)
						{
							((Component)val).gameObject.SetActive(flag2);
						}
						if (flag2)
						{
							PlaceIcon((RectTransform)val);
						}
					}
				}
			}

			internal static ConfigEntry<KeyCode> LockKey;

			internal static ConfigEntry<IconPosition> LockIconPosition;

			private const string CustomDataKey = "dupo.SafeQuickStack.LockedSlots";

			private const string IconName = "SafeQuickStack_Lock";

			private static readonly HashSet<int> Locked = new HashSet<int>();

			private static Player _loadedFor;

			private static Sprite _lockSprite;

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

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

			internal static void Bind(ConfigFile config)
			{
				LockKey = config.Bind<KeyCode>("3 - Slot Locks", "Lock Key", (KeyCode)308, "Hold this key and left-click a slot of your inventory to lock or unlock it. Quick Stack never moves the items in a locked slot.");
				LockIconPosition = config.Bind<IconPosition>("3 - Slot Locks", "Lock Icon Position", IconPosition.Center, "Where the padlock is drawn on a locked slot. Center = over the middle of the item icon, Left/Right = middle of the left/right edge. TopRight covers the quality level of upgraded items, TopLeft covers the hotbar numbers.");
			}

			private static int Key(int x, int y)
			{
				return y * 1000 + x;
			}

			private static void EnsureLoaded()
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)(object)_loadedFor)
				{
					return;
				}
				_loadedFor = localPlayer;
				Locked.Clear();
				if ((Object)(object)localPlayer == (Object)null || !localPlayer.m_customData.TryGetValue("dupo.SafeQuickStack.LockedSlots", out var value))
				{
					return;
				}
				string[] array = value.Split(';');
				for (int i = 0; i < array.Length; i++)
				{
					string[] array2 = array[i].Split(',');
					if (array2.Length == 2 && int.TryParse(array2[0], out var result) && int.TryParse(array2[1], out var result2))
					{
						Locked.Add(Key(result, result2));
					}
				}
			}

			private static void Save()
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null)
				{
					return;
				}
				List<string> list = new List<string>();
				foreach (int item in Locked)
				{
					list.Add($"{item % 1000},{item / 1000}");
				}
				if (list.Count == 0)
				{
					localPlayer.m_customData.Remove("dupo.SafeQuickStack.LockedSlots");
				}
				else
				{
					localPlayer.m_customData["dupo.SafeQuickStack.LockedSlots"] = string.Join(";", list);
				}
			}

			internal static bool IsLocked(Vector2i pos)
			{
				//IL_000a: 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)
				EnsureLoaded();
				return Locked.Contains(Key(pos.x, pos.y));
			}

			private static void Toggle(Vector2i pos)
			{
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_003a: 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)
				EnsureLoaded();
				int item = Key(pos.x, pos.y);
				if (!Locked.Remove(item))
				{
					Locked.Add(item);
				}
				Save();
				Debug(string.Format("SlotLocks: slot {0},{1} {2}", pos.x, pos.y, Locked.Contains(item) ? "locked" : "unlocked"));
			}

			private static bool Active()
			{
				return Enabled.Value;
			}

			private static Transform CreateIcon(Transform slot)
			{
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Unknown result type (might be due to invalid IL or missing references)
				//IL_003d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0048: 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_005d: Unknown result type (might be due to invalid IL or missing references)
				//IL_006c: Expected O, but got Unknown
				//IL_006c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0083: Unknown result type (might be due to invalid IL or missing references)
				GameObject val = new GameObject("SafeQuickStack_Lock", new Type[2]
				{
					typeof(RectTransform),
					typeof(Image)
				});
				RectTransform val2 = (RectTransform)val.transform;
				((Transform)val2).SetParent(slot, false);
				val2.pivot = new Vector2(0.5f, 0.5f);
				val2.sizeDelta = new Vector2(18f, 18f);
				PlaceIcon(val2);
				Image component = val.GetComponent<Image>();
				component.sprite = GetLockSprite();
				((Graphic)component).raycastTarget = false;
				val.transform.SetAsLastSibling();
				return val.transform;
			}

			private static void PlaceIcon(RectTransform rect)
			{
				//IL_0100: Unknown result type (might be due to invalid IL or missing references)
				//IL_0105: Unknown result type (might be due to invalid IL or missing references)
				//IL_012b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0130: Unknown result type (might be due to invalid IL or missing references)
				//IL_0149: Unknown result type (might be due to invalid IL or missing references)
				//IL_014e: Unknown result type (might be due to invalid IL or missing references)
				//IL_013a: Unknown result type (might be due to invalid IL or missing references)
				//IL_013b: Unknown result type (might be due to invalid IL or missing references)
				//IL_013c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0142: Unknown result type (might be due to invalid IL or missing references)
				//IL_0157: Unknown result type (might be due to invalid IL or missing references)
				Vector2 val = default(Vector2);
				Vector2 zero = default(Vector2);
				switch (LockIconPosition.Value)
				{
				case IconPosition.Right:
					((Vector2)(ref val))..ctor(1f, 0.5f);
					((Vector2)(ref zero))..ctor(-6f, 0f);
					break;
				case IconPosition.TopLeft:
					((Vector2)(ref val))..ctor(0f, 1f);
					((Vector2)(ref zero))..ctor(6f, -6f);
					break;
				case IconPosition.TopRight:
					((Vector2)(ref val))..ctor(1f, 1f);
					((Vector2)(ref zero))..ctor(-6f, -6f);
					break;
				case IconPosition.BottomLeft:
					((Vector2)(ref val))..ctor(0f, 0f);
					((Vector2)(ref zero))..ctor(6f, 6f);
					break;
				case IconPosition.BottomRight:
					((Vector2)(ref val))..ctor(1f, 0f);
					((Vector2)(ref zero))..ctor(-6f, 6f);
					break;
				case IconPosition.Center:
					((Vector2)(ref val))..ctor(0.5f, 0.5f);
					zero = Vector2.zero;
					break;
				default:
					((Vector2)(ref val))..ctor(0f, 0.5f);
					((Vector2)(ref zero))..ctor(6f, 0f);
					break;
				}
				if (rect.anchorMin != val)
				{
					Vector2 anchorMin = (rect.anchorMax = val);
					rect.anchorMin = anchorMin;
				}
				if (rect.anchoredPosition != zero)
				{
					rect.anchoredPosition = zero;
				}
			}

			private static Sprite GetLockSprite()
			{
				//IL_0109: Unknown result type (might be due to invalid IL or missing references)
				//IL_010e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0115: Unknown result type (might be due to invalid IL or missing references)
				//IL_011c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0123: 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_014c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0156: Expected O, but got Unknown
				//IL_0063: Unknown result type (might be due to invalid IL or missing references)
				//IL_0068: Unknown result type (might be due to invalid IL or missing references)
				//IL_0081: Unknown result type (might be due to invalid IL or missing references)
				//IL_007e: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
				//IL_0082: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b0: 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)
				if ((Object)(object)_lockSprite != (Object)null)
				{
					return _lockSprite;
				}
				Color val = default(Color);
				((Color)(ref val))..ctor(1f, 0.82f, 0.25f, 1f);
				Color val2 = default(Color);
				((Color)(ref val2))..ctor(0.08f, 0.06f, 0.03f, 1f);
				Color[] array = (Color[])(object)new Color[1024];
				for (int i = 0; i < 32; i++)
				{
					for (int j = 0; j < 32; j++)
					{
						Color val3 = Color.clear;
						if (InShape(j, i))
						{
							val3 = (InKeyhole(j, i) ? val2 : val);
						}
						else
						{
							for (int k = -2; k <= 2; k++)
							{
								if (val3.a != 0f)
								{
									break;
								}
								for (int l = -2; l <= 2; l++)
								{
									if (l * l + k * k <= 5 && InShape(j + l, i + k))
									{
										val3 = val2;
										break;
									}
								}
							}
						}
						array[i * 32 + j] = val3;
					}
				}
				Texture2D val4 = new Texture2D(32, 32, (TextureFormat)4, false)
				{
					filterMode = (FilterMode)1,
					wrapMode = (TextureWrapMode)1
				};
				val4.SetPixels(array);
				val4.Apply();
				_lockSprite = Sprite.Create(val4, new Rect(0f, 0f, 32f, 32f), new Vector2(0.5f, 0.5f));
				return _lockSprite;
				static bool InKeyhole(int x, int y)
				{
					if (x < 15 || x > 16 || y < 6 || y > 11)
					{
						return Mathf.Pow((float)x - 15.5f, 2f) + Mathf.Pow((float)y - 11f, 2f) <= 3.5f;
					}
					return true;
				}
				static bool InShape(int x, int y)
				{
					if (x >= 7 && x <= 24 && y >= 3 && y <= 16)
					{
						if (x == 7 || x == 24)
						{
							if (y != 3)
							{
								return y != 16;
							}
							return false;
						}
						return true;
					}
					if (y > 16)
					{
						float num = (float)x - 15.5f;
						float num2 = (float)y - 16f;
						float num3 = Mathf.Sqrt(num * num + num2 * num2);
						if (num3 >= 5f)
						{
							return num3 <= 8.5f;
						}
						return false;
					}
					return false;
				}
			}
		}

		public const string ModGuid = "dupo.SafeQuickStack";

		public const string ModName = "Dupo_SafeQuickStack";

		public const string ModVersion = "1.0.1";

		internal static ManualLogSource Log;

		internal static Plugin Instance;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<bool> DebugLog;

		private readonly Harmony _harmony = new Harmony("dupo.SafeQuickStack");

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Enabled", true, "Turns the mod on or off (Quick Stack, slot locks and the padlock icons).");
			DebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Debug Log", false, "Write extra diagnostic lines to BepInEx/LogOutput.log.");
			QuickStack.Bind(((BaseUnityPlugin)this).Config);
			SlotLocks.Bind(((BaseUnityPlugin)this).Config);
			_harmony.PatchAll(typeof(Plugin).Assembly);
			Log.LogInfo((object)"Dupo_SafeQuickStack 1.0.1 loaded");
		}

		private void Update()
		{
			if (Enabled.Value)
			{
				QuickStack.Update();
			}
		}

		internal static bool CanUseHotkeys()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || ((Character)localPlayer).IsTeleporting())
			{
				return false;
			}
			if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus())
			{
				return false;
			}
			if (Console.IsVisible() || TextInput.IsVisible() || Menu.IsVisible() || Minimap.InTextInput())
			{
				return false;
			}
			if ((Object)(object)Hud.instance != (Object)null && (Object)(object)Hud.instance.m_buildUi != (Object)null && Hud.instance.m_buildUi.SearchFieldFocused)
			{
				return false;
			}
			return true;
		}

		private void OnDestroy()
		{
			_harmony.UnpatchSelf();
		}

		internal static void Debug(string message)
		{
			if (DebugLog != null && DebugLog.Value)
			{
				Log.LogInfo((object)message);
			}
		}
	}
}