Decompiled source of SlotAnchor v0.1.2

BepInEx/plugins/SlotAnchor/SlotAnchor.dll

Decompiled 17 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[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("SlotAnchor")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.2.0")]
[assembly: AssemblyInformationalVersion("0.1.2")]
[assembly: AssemblyProduct("SlotAnchor")]
[assembly: AssemblyTitle("SlotAnchor")]
[assembly: AssemblyVersion("0.1.2.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 SlotAnchor
{
	public static class Instrumentation
	{
		public static IEnumerable<CodeInstruction> ListReads(IEnumerable<CodeInstruction> src, FieldInfo field, MethodInfo getAll, MethodInfo replacement)
		{
			int count = 0;
			foreach (CodeInstruction item in src)
			{
				if ((item.opcode == OpCodes.Ldfld && object.Equals(item.operand, field)) || CodeInstructionExtensions.Calls(item, getAll))
				{
					item.opcode = OpCodes.Call;
					item.operand = replacement;
					count++;
				}
				yield return item;
			}
			if (count == 0)
			{
				throw new InvalidOperationException("Inventory list pattern missing");
			}
		}

		public static IEnumerable<CodeInstruction> EmptySlots(IEnumerable<CodeInstruction> src, MethodInfo getAt, MethodInfo replacement)
		{
			int count = 0;
			foreach (CodeInstruction item in src)
			{
				if (CodeInstructionExtensions.Calls(item, getAt))
				{
					item.opcode = OpCodes.Call;
					item.operand = replacement;
					count++;
				}
				yield return item;
			}
			if (count != 2)
			{
				throw new InvalidOperationException("FindEmptySlot changed; expected 2 probes, got " + count);
			}
		}
	}
	public static class MethodLookup
	{
		public static MethodInfo Exact(Type type, string name, params string[] parameters)
		{
			MethodInfo[] array = (from m in type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
				where m.Name == name && (from p in m.GetParameters()
					select p.ParameterType.FullName).SequenceEqual<string>(parameters)
				select m).ToArray();
			if (array.Length != 1)
			{
				throw new MissingMethodException(type.FullName, name + "(" + string.Join(",", parameters) + "): expected one match, found " + array.Length);
			}
			return array[0];
		}

		public static MethodInfo[] InventoryLoadMethods(Type inventory)
		{
			return new MethodInfo[2]
			{
				Exact(inventory, "Load", "ZPackage"),
				Exact(inventory, "Load", "ZPackage", "System.Boolean")
			};
		}
	}
	internal static class Overlay
	{
		private static Type imageType;

		private static Sprite lockSprite;

		private static bool failed;

		private static readonly Color Cyan = new Color(0.25f, 0.85f, 0.95f, 0.8f);

		private static Component Image(string name, Transform parent, Vector2 min, Vector2 max, Vector2 offsetMin, Vector2 offsetMax, Color color)
		{
			//IL_0014: 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)
			//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_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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_003a: 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_0042: 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)
			GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
			RectTransform val2 = (RectTransform)val.transform;
			((Transform)val2).SetParent(parent, false);
			val2.anchorMin = min;
			val2.anchorMax = max;
			val2.offsetMin = offsetMin;
			val2.offsetMax = offsetMax;
			Component obj = val.AddComponent(imageType);
			Set(obj, "color", color);
			Set(obj, "raycastTarget", false);
			return obj;
		}

		private static void Set(object obj, string p, object v)
		{
			obj.GetType().GetProperty(p).SetValue(obj, v, null);
		}

		private static void Init()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			imageType = Type.GetType("UnityEngine.UI.Image, UnityEngine.UI", throwOnError: true);
			Texture2D val = new Texture2D(16, 20, (TextureFormat)4, false);
			((Texture)val).filterMode = (FilterMode)0;
			for (int i = 0; i < 20; i++)
			{
				for (int j = 0; j < 16; j++)
				{
					bool flag = j >= 2 && j <= 13 && i >= 1 && i <= 11;
					bool flag2 = i >= 11 && i <= 18 && j >= 4 && j <= 11 && (j <= 5 || j >= 10 || i >= 17);
					bool flag3 = j >= 7 && j <= 8 && i >= 4 && i <= 8;
					val.SetPixel(j, i, (Color)(((flag || flag2) && !flag3) ? new Color(1f, 0.8f, 0.25f, 1f) : Color.clear));
				}
			}
			val.Apply();
			lockSprite = Sprite.Create(val, new Rect(0f, 0f, 16f, 20f), new Vector2(0.5f, 0.5f));
		}

		public static void Draw(InventoryGrid grid)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: 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_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: 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_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Expected O, but got Unknown
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: 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_01bb: 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)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_028f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			if (failed)
			{
				return;
			}
			try
			{
				Inventory inventory = grid.GetInventory();
				if (inventory == null)
				{
					return;
				}
				if (imageType == null)
				{
					Init();
				}
				RuleBook ruleBook = Plugin.Rules(inventory);
				IList list = (IList)Plugin.Field(grid, "m_elements");
				for (int i = 0; i < list.Count; i++)
				{
					Component val = (Component)list[i];
					object pos = Plugin.Call(grid, "GetElementPos", val);
					int num = Plugin.X(pos);
					int num2 = Plugin.Y(pos);
					string value;
					bool num3 = ruleBook.Slots.TryGetValue(RuleBook.Key(num, num2), out value);
					Transform val2 = val.transform.Find("SlotAnchorOverlay");
					if (!num3)
					{
						if (Object.op_Implicit((Object)(object)val2))
						{
							((Component)val2).gameObject.SetActive(false);
						}
						continue;
					}
					if (!Object.op_Implicit((Object)(object)val2))
					{
						RectTransform val3 = (RectTransform)new GameObject("SlotAnchorOverlay", new Type[1] { typeof(RectTransform) }).transform;
						((Transform)val3).SetParent(val.transform, false);
						val3.anchorMin = Vector2.zero;
						val3.anchorMax = Vector2.one;
						val3.offsetMin = new Vector2(2f, 2f);
						val3.offsetMax = new Vector2(-2f, -2f);
						val2 = (Transform)val3;
						Image("Ghost", val2, Vector2.zero, Vector2.one, new Vector2(6f, 6f), new Vector2(-6f, -6f), new Color(1f, 1f, 1f, 0.25f));
						Image("Top", val2, new Vector2(0f, 1f), Vector2.one, new Vector2(0f, -2f), Vector2.zero, Cyan);
						Image("Bottom", val2, Vector2.zero, new Vector2(1f, 0f), Vector2.zero, new Vector2(0f, 2f), Cyan);
						Image("Left", val2, Vector2.zero, new Vector2(0f, 1f), Vector2.zero, new Vector2(2f, 0f), Cyan);
						Image("Right", val2, new Vector2(1f, 0f), Vector2.one, new Vector2(-2f, 0f), Vector2.zero, Cyan);
						Set(Image("Lock", val2, new Vector2(1f, 1f), Vector2.one, new Vector2(-17f, -21f), new Vector2(-1f, -1f), Color.white), "sprite", lockSprite);
					}
					((Component)val2).gameObject.SetActive(true);
					val2.SetAsLastSibling();
					Transform val4 = val2.Find("Ghost");
					bool flag = inventory.GetItemAt(num, num2) == null;
					((Component)val4).gameObject.SetActive(flag);
					if (flag && Object.op_Implicit((Object)(object)ObjectDB.instance))
					{
						GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(value);
						ItemDrop val5 = (Object.op_Implicit((Object)(object)itemPrefab) ? itemPrefab.GetComponent<ItemDrop>() : null);
						Set(((Component)val4).GetComponent(imageType), "sprite", Object.op_Implicit((Object)(object)val5) ? val5.m_itemData.GetIcon() : null);
						((Component)val4).gameObject.SetActive((Object)(object)val5 != (Object)null);
					}
				}
			}
			catch (Exception ex)
			{
				failed = true;
				Debug.LogError((object)("Slot Anchor overlay failed: " + ex));
			}
		}
	}
	[BepInPlugin("cz.misaweb.valheim.slotanchor", "Slot Anchor", "0.1.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInIncompatibility("com.Azura.slotlock")]
	public sealed class Plugin : BaseUnityPlugin
	{
		private sealed class Cache
		{
			public string Raw;

			public RuleBook Book;
		}

		public const string Id = "cz.misaweb.valheim.slotanchor";

		public const string QssId = "goldenrevolver.quick_stack_store";

		internal static Plugin Self;

		internal static bool Ready;

		internal static int Manual;

		internal static int Loading;

		private ConfigEntry<KeyboardShortcut> hotkey;

		private Harmony harmony;

		internal static readonly FieldInfo ItemsField = AccessTools.Field(typeof(Inventory), "m_inventory");

		private static readonly FieldInfo PosField = AccessTools.Field(typeof(ItemData), "m_gridPos");

		private static readonly ConditionalWeakTable<Inventory, Container> Owners = new ConditionalWeakTable<Inventory, Container>();

		private static readonly ConditionalWeakTable<Inventory, Cache> CacheTable = new ConditionalWeakTable<Inventory, Cache>();

		internal const string DataKey = "cz.misaweb.valheim.slotanchor.rules.v1";

		internal static readonly ItemData ReservedMarker = new ItemData();

		private void Awake()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			Self = this;
			hotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("1. Controls", "Lock key", new KeyboardShortcut((KeyCode)106, Array.Empty<KeyCode>()), "Zamknout/odemknout policko pod mysi. Pouze v otevrenem inventari. Zamek chrani pred automatickymi operacemi; rucni presuny jsou povolene.");
		}

		private void Start()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			harmony = new Harmony("cz.misaweb.valheim.slotanchor");
			try
			{
				PluginInfo info;
				bool num = Chainloader.PluginInfos.TryGetValue("goldenrevolver.quick_stack_store", out info);
				bool flag = StartupPlan.Install(num, num ? info.Metadata.Version.ToString() : null, InstallCore, delegate
				{
					InstallQss(((object)info.Instance).GetType().Assembly);
				});
				Ready = true;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Slot Anchor 0.1.2 READY. " + (flag ? "Quick Stack 1.4.16 integration installed." : "Standalone mode; Quick Stack is not installed.") + " Key: " + ((object)hotkey.Value/*cast due to .constrained prefix*/).ToString()));
			}
			catch (Exception ex)
			{
				Ready = false;
				harmony.UnpatchSelf();
				((BaseUnityPlugin)this).Logger.LogError((object)("Slot Anchor DISABLED; no locks are active: " + ex));
			}
		}

		private void OnDestroy()
		{
			Ready = false;
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}

		internal static object Field(object o, string n)
		{
			return AccessTools.Field(o.GetType(), n).GetValue(o);
		}

		internal static object Call(object o, string n, params object[] a)
		{
			MethodInfo? methodInfo = AccessTools.GetDeclaredMethods(o.GetType()).FirstOrDefault((MethodInfo x) => x.Name == n && x.GetParameters().Length == a.Length && x.GetParameters().Select((ParameterInfo p, int i) => a[i] == null || p.ParameterType.IsInstanceOfType(a[i])).All((bool result) => result));
			if (methodInfo == null)
			{
				throw new MissingMethodException(o.GetType().FullName, n + " with compatible arguments");
			}
			return methodInfo.Invoke(o, a);
		}

		internal static int X(object pos)
		{
			return (int)Field(pos, "x");
		}

		internal static int Y(object pos)
		{
			return (int)Field(pos, "y");
		}

		internal static object Pos(ItemData item)
		{
			return PosField.GetValue(item);
		}

		internal static string Identity(ItemData item)
		{
			if (!Object.op_Implicit((Object)(object)item.m_dropPrefab))
			{
				return item.m_shared.m_name;
			}
			return ((Object)item.m_dropPrefab).name;
		}

		internal static List<ItemData> Items(Inventory inv)
		{
			return (List<ItemData>)ItemsField.GetValue(inv);
		}

		internal static void Register(Container c)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			Inventory val = (Inventory)Field(c, "m_inventory");
			if (val != null)
			{
				Owners.Remove(val);
				Owners.Add(val, c);
			}
		}

		private static object Zdo(Container c)
		{
			object obj = Field(c, "m_nview");
			if (obj != null)
			{
				return Call(obj, "GetZDO");
			}
			return null;
		}

		internal static string ReadRaw(Inventory inv)
		{
			Player localPlayer = Player.m_localPlayer;
			if (Object.op_Implicit((Object)(object)localPlayer) && inv == ((Humanoid)localPlayer).GetInventory())
			{
				if (!((Dictionary<string, string>)Field(localPlayer, "m_customData")).TryGetValue("cz.misaweb.valheim.slotanchor.rules.v1", out var value))
				{
					return "";
				}
				return value;
			}
			if (Owners.TryGetValue(inv, out var value2) && Object.op_Implicit((Object)(object)value2))
			{
				object obj = Zdo(value2);
				if (obj != null)
				{
					return (string)Call(obj, "GetString", "cz.misaweb.valheim.slotanchor.rules.v1", "");
				}
			}
			return "";
		}

		internal static RuleBook Rules(Inventory inv)
		{
			if (inv == null)
			{
				return new RuleBook();
			}
			string text = ReadRaw(inv);
			Cache value = CacheTable.GetValue(inv, (Inventory _) => new Cache());
			if (value.Book == null || value.Raw != text)
			{
				value.Book = RuleBook.Decode(text);
				value.Raw = text;
			}
			return value.Book;
		}

		private static bool Save(Inventory inv, RuleBook rules)
		{
			string text = rules.Encode();
			Player localPlayer = Player.m_localPlayer;
			if (Object.op_Implicit((Object)(object)localPlayer) && inv == ((Humanoid)localPlayer).GetInventory())
			{
				((Dictionary<string, string>)Field(localPlayer, "m_customData"))["cz.misaweb.valheim.slotanchor.rules.v1"] = text;
				return true;
			}
			if (!Owners.TryGetValue(inv, out var value) || !Object.op_Implicit((Object)(object)value))
			{
				return false;
			}
			object obj = Field(value, "m_nview");
			if (obj == null || !(bool)Call(obj, "IsOwner"))
			{
				Message("Truhla ještě není připravená. Zkus J znovu.");
				return false;
			}
			object obj2 = Zdo(value);
			if (obj2 == null)
			{
				return false;
			}
			Call(obj2, "Set", "cz.misaweb.valheim.slotanchor.rules.v1", text);
			return true;
		}

		internal static bool Locked(Inventory inv, ItemData item)
		{
			object pos = Pos(item);
			return Rules(inv).Locked(X(pos), Y(pos));
		}

		internal static List<ItemData> UnlockedItems(Inventory inv)
		{
			List<ItemData> list = Items(inv);
			if (!Ready || Loading > 0)
			{
				return list;
			}
			RuleBook rules = Rules(inv);
			if (rules.Slots.Count == 0)
			{
				return list;
			}
			return list.Where(delegate(ItemData i)
			{
				object pos = Pos(i);
				return !rules.Locked(X(pos), Y(pos));
			}).ToList();
		}

		internal static List<ItemData> StackCandidates(Inventory inv)
		{
			if (Manual <= 0)
			{
				return UnlockedItems(inv);
			}
			return Items(inv);
		}

		internal static ItemData EmptyProbe(Inventory inv, int x, int y)
		{
			ItemData itemAt = inv.GetItemAt(x, y);
			if (itemAt == null && Ready && Loading == 0 && Rules(inv).Locked(x, y))
			{
				return ReservedMarker;
			}
			return itemAt;
		}

		internal static void Message(string text)
		{
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false);
			}
		}

		private void Update()
		{
			//IL_002e: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Expected O, but got Unknown
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Expected O, but got Unknown
			if (!Ready || !Object.op_Implicit((Object)(object)InventoryGui.instance) || !InventoryGui.IsVisible() || !Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				return;
			}
			try
			{
				KeyboardShortcut value = hotkey.Value;
				if (!((KeyboardShortcut)(ref value)).IsDown() || TextInputActive())
				{
					return;
				}
				InventoryGui instance = InventoryGui.instance;
				if (Field(instance, "m_dragItem") != null)
				{
					return;
				}
				Container val = (Container)Field(instance, "m_currentContainer");
				if (Object.op_Implicit((Object)(object)val))
				{
					Register(val);
				}
				InventoryGrid[] array = (InventoryGrid[])(object)new InventoryGrid[2]
				{
					instance.m_playerGrid,
					(InventoryGrid)Field(instance, "m_containerGrid")
				};
				foreach (InventoryGrid val2 in array)
				{
					if (!Object.op_Implicit((Object)(object)val2) || !((Component)val2).gameObject.activeInHierarchy)
					{
						continue;
					}
					object obj = Call(val2, "GetHoveredElement");
					if (obj == null)
					{
						continue;
					}
					object pos = Call(val2, "GetElementPos", obj);
					int num = X(pos);
					int num2 = Y(pos);
					if (num < 0 || num2 < 0)
					{
						break;
					}
					Inventory inventory = val2.GetInventory();
					if (inventory == null)
					{
						break;
					}
					RuleBook ruleBook = RuleBook.Decode(ReadRaw(inventory));
					string key = RuleBook.Key(num, num2);
					bool flag = ruleBook.Slots.Remove(key);
					if (!flag)
					{
						ItemData itemAt = inventory.GetItemAt(num, num2);
						if (itemAt == null)
						{
							Message("Nejdřív vlož do políčka předmět.");
							break;
						}
						ruleBook.Slots[key] = Identity(itemAt);
					}
					if (Save(inventory, ruleBook))
					{
						Message(flag ? "Políčko odemčeno" : "Políčko uzamčeno — pouze ruční přesuny");
					}
					break;
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Lock input failed: " + ex));
			}
		}

		private static bool TextInputActive()
		{
			if (Object.op_Implicit((Object)(object)Chat.instance) && Chat.instance.HasFocus())
			{
				return true;
			}
			object obj = Type.GetType("UnityEngine.GUIUtility, UnityEngine.IMGUIModule")?.GetProperty("keyboardControl")?.GetValue(null, null);
			if (obj is int && (int)obj != 0)
			{
				return true;
			}
			foreach (PluginInfo value in Chainloader.PluginInfos.Values)
			{
				BaseUnityPlugin instance = value.Instance;
				if (Object.op_Implicit((Object)(object)instance))
				{
					PropertyInfo propertyInfo = AccessTools.Property(((object)instance).GetType(), "DisplayingWindow");
					if (propertyInfo != null && propertyInfo.PropertyType == typeof(bool) && (bool)propertyInfo.GetValue(instance, null))
					{
						return true;
					}
				}
			}
			Type type = AccessTools.TypeByName("UnityEngine.EventSystems.EventSystem");
			object obj2 = type?.GetProperty("current")?.GetValue(null, null);
			GameObject val = (GameObject)((obj2 == null) ? null : /*isinst with value type is only supported in some contexts*/);
			if (Object.op_Implicit((Object)(object)val) && (Object.op_Implicit((Object)(object)val.GetComponent("TMP_InputField")) || Object.op_Implicit((Object)(object)val.GetComponent("InputField"))))
			{
				return true;
			}
			string[] array = new string[4] { "Chat", "Console", "TextInput", "Menu" };
			for (int i = 0; i < array.Length; i++)
			{
				Type type2 = AccessTools.TypeByName(array[i]);
				MethodInfo methodInfo = ((type2 == null) ? null : AccessTools.Method(type2, "IsVisible", Type.EmptyTypes, (Type[])null));
				if (methodInfo != null && methodInfo.IsStatic && methodInfo.ReturnType == typeof(bool) && (bool)methodInfo.Invoke(null, null))
				{
					return true;
				}
			}
			return false;
		}

		private void Patch(MethodBase target, string pre = null, string post = null, string trans = null, string fin = null)
		{
			if (target == null)
			{
				throw new MissingMethodException("Required patch target missing");
			}
			harmony.Patch(target, H(pre), H(post), H(trans), H(fin), (HarmonyMethod)null);
			static HarmonyMethod H(string n)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: Expected O, but got Unknown
				if (n != null)
				{
					return new HarmonyMethod(typeof(Patches), n, (Type[])null);
				}
				return null;
			}
		}

		private void InstallCore()
		{
			Patch(AccessTools.Method(typeof(Container), "Awake", (Type[])null, (Type[])null), null, "ContainerAwake");
			MethodInfo[] array = MethodLookup.InventoryLoadMethods(typeof(Inventory));
			foreach (MethodInfo target in array)
			{
				Patch(target, "LoadEnter", null, null, "LoadExit");
			}
			Patch(AccessTools.Method(typeof(Inventory), "FindEmptySlot", (Type[])null, (Type[])null), null, null, "EmptySlots");
			Patch(AccessTools.Method(typeof(Inventory), "FindFreeStackItem", (Type[])null, (Type[])null), null, null, "StackReads");
			Patch(AccessTools.Method(typeof(Inventory), "FindFreeStackSpace", (Type[])null, (Type[])null), null, null, "StackReads");
			Patch(AccessTools.Method(typeof(Inventory), "AddItem", new Type[5]
			{
				typeof(ItemData),
				typeof(int),
				typeof(int),
				typeof(int),
				typeof(bool)
			}, (Type[])null), "AddAt");
			Type fieldType = PosField.FieldType;
			Patch(AccessTools.Method(typeof(Inventory), "AddItem", new Type[2]
			{
				typeof(ItemData),
				fieldType
			}, (Type[])null), "AddPos");
			Patch(AccessTools.Method(typeof(InventoryGrid), "DropItem", (Type[])null, (Type[])null), "Drop");
			string[] array2 = new string[4] { "OnSelectedItem", "OnRightClickItem", "OnDropOutside", "OnReleasedItem" };
			foreach (string text in array2)
			{
				Patch(AccessTools.Method(typeof(InventoryGui), text, (Type[])null, (Type[])null), "ManualEnter", null, null, "ManualExit");
			}
			Patch(AccessTools.Method(typeof(Container), "RPC_TakeAllResponse", (Type[])null, (Type[])null), "AutoEnter", null, null, "AutoExit");
			Patch(AccessTools.Method(typeof(Inventory), "MoveAll", (Type[])null, (Type[])null), null, null, "MoveAllReads");
			Patch(AccessTools.Method(typeof(Inventory), "StackAll", (Type[])null, (Type[])null), null, null, "FilterReads");
			Patch(AccessTools.Method(typeof(InventoryGrid), "UpdateGui", (Type[])null, (Type[])null), null, "Draw");
		}

		private void InstallQss(Assembly a)
		{
			string[] array = new string[6] { "SortModule.SortInternal", "QuickStackModule.DoQuickStack", "RestockModule.DoRestock", "RestockModule.RestockFromThisContainer", "StoreTakeAllModule.MoveAllItemsInOrder", "TrashModule.QuickTrash" };
			foreach (string text in array)
			{
				string[] array2 = text.Split('.');
				MethodInfo target = AccessTools.Method(a.GetType("QuickStackStore." + array2[0], throwOnError: true), array2[1], (Type[])null, (Type[])null);
				Patch(target, (text == "SortModule.SortInternal") ? "ValidateSort" : null, null, "FilterReads");
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Protected QSS " + text));
			}
			Patch(AccessTools.Method(a.GetType("QuickStackStore.SortModule", throwOnError: true), "GetAllowedSlots", (Type[])null, (Type[])null), null, "AllowedSlots");
		}
	}
	internal static class Patches
	{
		private static int auto;

		public static void ContainerAwake(Container __instance)
		{
			Plugin.Register(__instance);
		}

		public static void ManualEnter(out int __state)
		{
			__state = Plugin.Manual;
			Plugin.Manual++;
		}

		public static void ManualExit(int __state)
		{
			Plugin.Manual = __state;
		}

		public static void LoadEnter(out int __state)
		{
			__state = Plugin.Loading;
			Plugin.Loading++;
		}

		public static void LoadExit(int __state)
		{
			Plugin.Loading = __state;
		}

		public static void AutoEnter(out int __state)
		{
			__state = auto;
			auto++;
		}

		public static void AutoExit(int __state)
		{
			auto = __state;
		}

		public static List<ItemData> MoveAllItems(Inventory inv)
		{
			if (auto <= 0)
			{
				return Plugin.Items(inv);
			}
			return Plugin.UnlockedItems(inv);
		}

		private static IEnumerable<CodeInstruction> ReplaceReads(IEnumerable<CodeInstruction> src, string method, Type type)
		{
			return Instrumentation.ListReads(src, Plugin.ItemsField, AccessTools.Method(typeof(Inventory), "GetAllItems", Type.EmptyTypes, (Type[])null), AccessTools.Method(type, method, (Type[])null, (Type[])null));
		}

		public static IEnumerable<CodeInstruction> FilterReads(IEnumerable<CodeInstruction> src)
		{
			return ReplaceReads(src, "UnlockedItems", typeof(Plugin));
		}

		public static IEnumerable<CodeInstruction> StackReads(IEnumerable<CodeInstruction> src)
		{
			return ReplaceReads(src, "StackCandidates", typeof(Plugin));
		}

		public static IEnumerable<CodeInstruction> MoveAllReads(IEnumerable<CodeInstruction> src)
		{
			return ReplaceReads(src, "MoveAllItems", typeof(Patches));
		}

		public static IEnumerable<CodeInstruction> EmptySlots(IEnumerable<CodeInstruction> src)
		{
			return Instrumentation.EmptySlots(src, AccessTools.Method(typeof(Inventory), "GetItemAt", (Type[])null, (Type[])null), AccessTools.Method(typeof(Plugin), "EmptyProbe", (Type[])null, (Type[])null));
		}

		public static bool ValidateSort(object[] __args)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			if (!Plugin.Ready)
			{
				return true;
			}
			Inventory val = (Inventory)__args[0];
			HashSet<string> hashSet = new HashSet<string>();
			foreach (ItemData item in Plugin.Items(val))
			{
				object pos = Plugin.Pos(item);
				int num = Plugin.X(pos);
				int num2 = Plugin.Y(pos);
				if (num < 0 || num2 < 0 || num >= val.GetWidth() || num2 >= val.GetHeight() || !hashSet.Add(RuleBook.Key(num, num2)))
				{
					Plugin.Message("Třídění zastaveno: inventář obsahuje neplatné nebo překrývající se pozice.");
					return false;
				}
			}
			return true;
		}

		public static void AllowedSlots(object[] __args, object __result, MethodBase __originalMethod)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			if (!Plugin.Ready)
			{
				return;
			}
			Inventory val = (Inventory)__args[0];
			IList list = (IList)__result;
			HashSet<string> hashSet = new HashSet<string>(Plugin.Rules(val).Slots.Keys);
			if (__args[2] != null)
			{
				MethodInfo methodInfo = AccessTools.Method(__originalMethod.DeclaringType, "ShouldSortItem", (Type[])null, (Type[])null);
				foreach (ItemData item in Plugin.Items(val))
				{
					if (!(bool)methodInfo.Invoke(null, new object[5]
					{
						item,
						__args[2],
						val.GetHeight(),
						val.GetWidth(),
						__args[1]
					}))
					{
						object pos = Plugin.Pos(item);
						hashSet.Add(RuleBook.Key(Plugin.X(pos), Plugin.Y(pos)));
					}
				}
			}
			for (int num = list.Count - 1; num >= 0; num--)
			{
				if (hashSet.Contains(RuleBook.Key(Plugin.X(list[num]), Plugin.Y(list[num]))))
				{
					list.RemoveAt(num);
				}
			}
		}

		private static bool MayAdd(Inventory inv, ItemData item, int x, int y)
		{
			if (!Plugin.Ready || Plugin.Loading > 0)
			{
				return true;
			}
			RuleBook ruleBook = Plugin.Rules(inv);
			if (!ruleBook.Locked(x, y))
			{
				return true;
			}
			if (Plugin.Manual > 0)
			{
				return ruleBook.Accepts(x, y, Plugin.Identity(item));
			}
			return false;
		}

		public static bool AddAt(Inventory __instance, object[] __args, ref bool __result)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			if (MayAdd(__instance, (ItemData)__args[0], (int)__args[2], (int)__args[3]))
			{
				return true;
			}
			__result = false;
			return false;
		}

		public static bool AddPos(Inventory __instance, object[] __args, ref bool __result)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			if (MayAdd(__instance, (ItemData)__args[0], Plugin.X(__args[1]), Plugin.Y(__args[1])))
			{
				return true;
			}
			__result = false;
			return false;
		}

		public static bool Drop(InventoryGrid __instance, object[] __args, ref bool __result)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			if (!Plugin.Ready)
			{
				return true;
			}
			Inventory inv = (Inventory)__args[0];
			ItemData item = (ItemData)__args[1];
			object pos = __args[3];
			Inventory inventory = __instance.GetInventory();
			ItemData itemAt = inventory.GetItemAt(Plugin.X(pos), Plugin.Y(pos));
			object pos2 = Plugin.Pos(item);
			if (!Plugin.Rules(inventory).Accepts(Plugin.X(pos), Plugin.Y(pos), Plugin.Identity(item)) || (itemAt != null && Plugin.Identity(itemAt) != Plugin.Identity(item) && !Plugin.Rules(inv).Accepts(Plugin.X(pos2), Plugin.Y(pos2), Plugin.Identity(itemAt))))
			{
				__result = false;
				Plugin.Message("Políčko je rezervované pro jiný předmět. Odemkni ho klávesou J.");
				return false;
			}
			return true;
		}

		public static void Draw(InventoryGrid __instance)
		{
			if (Plugin.Ready)
			{
				Overlay.Draw(__instance);
			}
		}
	}
	public sealed class RuleBook
	{
		public readonly Dictionary<string, string> Slots = new Dictionary<string, string>();

		public static string Key(int x, int y)
		{
			return x.ToString(CultureInfo.InvariantCulture) + "," + y.ToString(CultureInfo.InvariantCulture);
		}

		public bool Locked(int x, int y)
		{
			return Slots.ContainsKey(Key(x, y));
		}

		public bool Accepts(int x, int y, string item)
		{
			if (Slots.TryGetValue(Key(x, y), out var value))
			{
				return value == item;
			}
			return true;
		}

		public string Encode()
		{
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, string> slot in Slots)
			{
				list.Add(slot.Key + ":" + Convert.ToBase64String(Encoding.UTF8.GetBytes(slot.Value)));
			}
			list.Sort(StringComparer.Ordinal);
			return "1|" + string.Join(";", list);
		}

		public static RuleBook Decode(string text)
		{
			RuleBook ruleBook = new RuleBook();
			if (string.IsNullOrEmpty(text))
			{
				return ruleBook;
			}
			if (!text.StartsWith("1|"))
			{
				throw new FormatException("Unknown slot rules version");
			}
			string[] array = text.Substring(2).Split(';');
			foreach (string text2 in array)
			{
				if (text2.Length != 0)
				{
					int num = text2.IndexOf(':');
					if (num < 1)
					{
						throw new FormatException("Invalid rule");
					}
					string[] array2 = text2.Substring(0, num).Split(',');
					if (array2.Length != 2 || !int.TryParse(array2[0], out var result) || !int.TryParse(array2[1], out var result2) || result < 0 || result2 < 0)
					{
						throw new FormatException("Invalid slot");
					}
					string text3 = Encoding.UTF8.GetString(Convert.FromBase64String(text2.Substring(num + 1)));
					if (text3.Length == 0)
					{
						throw new FormatException("Empty item");
					}
					ruleBook.Slots.Add(Key(result, result2), text3);
				}
			}
			return ruleBook;
		}
	}
	public static class StartupPlan
	{
		public const string SupportedQuickStack = "1.4.16";

		public static bool Install(bool hasQuickStack, string version, Action installCore, Action installQuickStack)
		{
			if (hasQuickStack && version != "1.4.16")
			{
				throw new NotSupportedException("Quick Stack " + version + " is installed; supported version is 1.4.16. Use that version or disable Quick Stack to run Slot Anchor standalone.");
			}
			installCore();
			if (hasQuickStack)
			{
				installQuickStack();
			}
			return hasQuickStack;
		}
	}
}