Decompiled source of AutoStash v1.1.0

AutoStash.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
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.Events;
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("dbendu")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (c) 2026 dbendu")]
[assembly: AssemblyDescription("Stashes inventory items into nearby Valheim chests according to per-chest filters.")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0+0ef9b901c8c828bd9d7a7efbc329903aa2c5b519")]
[assembly: AssemblyProduct("Auto Stash")]
[assembly: AssemblyTitle("AutoStash")]
[assembly: AssemblyVersion("1.1.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 AutoStash
{
	internal sealed class ItemCategory
	{
		private readonly string _english;

		private readonly string _russian;

		internal string Id { get; }

		internal Func<SharedData, bool> Matches { get; }

		internal string Title => Text.T(_english, _russian);

		internal ItemCategory(string id, string english, string russian, Func<SharedData, bool> matches)
		{
			Id = id;
			_english = english;
			_russian = russian;
			Matches = matches;
		}
	}
	internal static class ItemCategories
	{
		internal static readonly ItemCategory[] All = new ItemCategory[10]
		{
			new ItemCategory("materials", "Materials", "Материалы", (SharedData s) => (int)s.m_itemType == 1),
			new ItemCategory("food", "Food", "Еда", (SharedData s) => (int)s.m_itemType == 2 && (s.m_food > 0f || s.m_foodStamina > 0f || s.m_foodEitr > 0f)),
			new ItemCategory("potions", "Meads", "Зелья", (SharedData s) => (int)s.m_itemType == 2),
			new ItemCategory("trophies", "Trophies", "Трофеи", (SharedData s) => (int)s.m_itemType == 13),
			new ItemCategory("fish", "Fish", "Рыба", (SharedData s) => (int)s.m_itemType == 21),
			new ItemCategory("weapons", "Weapons", "Оружие", delegate(SharedData s)
			{
				ItemType[] array = new ItemType[5];
				RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
				return Is(s, (ItemType[])(object)array);
			}),
			new ItemCategory("armor", "Armor", "Броня", delegate(SharedData s)
			{
				ItemType[] array = new ItemType[8];
				RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
				return Is(s, (ItemType[])(object)array);
			}),
			new ItemCategory("ammo", "Ammo", "Боеприпасы", (SharedData s) => Is(s, (ItemType)9, (ItemType)23)),
			new ItemCategory("tools", "Tools", "Инструменты", (SharedData s) => Is(s, (ItemType)19, (ItemType)15)),
			new ItemCategory("misc", "Other", "Прочее", (SharedData s) => true)
		};

		internal static ItemCategory Of(SharedData shared)
		{
			if (shared != null)
			{
				return All.First((ItemCategory c) => c.Matches(shared));
			}
			return null;
		}

		internal static int IndexOf(ItemCategory category)
		{
			return Array.IndexOf(All, category);
		}

		internal static bool Exists(string id)
		{
			return All.Any((ItemCategory c) => c.Id == id);
		}

		private static bool Is(SharedData shared, params ItemType[] types)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			return types.Contains(shared.m_itemType);
		}
	}
	internal sealed class ChestFilter
	{
		internal const int RankPicked = 0;

		internal const int RankCategory = 1;

		internal const int RankNone = -1;

		private const int MaxItems = 512;

		private const int MaxNameLength = 128;

		internal readonly HashSet<string> Items = new HashSet<string>(StringComparer.Ordinal);

		internal readonly HashSet<string> Categories = new HashSet<string>(StringComparer.Ordinal);

		internal bool IsEmpty
		{
			get
			{
				if (Items.Count == 0)
				{
					return Categories.Count == 0;
				}
				return false;
			}
		}

		internal int Count => Items.Count + Categories.Count;

		internal ChestFilter Copy()
		{
			ChestFilter chestFilter = new ChestFilter();
			chestFilter.Items.UnionWith(Items);
			chestFilter.Categories.UnionWith(Categories);
			return chestFilter;
		}

		internal int Rank(ItemData item)
		{
			string prefab = PrefabName(item);
			return Rank(prefab, item.m_shared);
		}

		internal int Rank(string prefab, SharedData shared)
		{
			if (prefab != null && Items.Contains(prefab))
			{
				return 0;
			}
			ItemCategory itemCategory = ItemCategories.Of(shared);
			if (itemCategory == null || !Categories.Contains(itemCategory.Id))
			{
				return -1;
			}
			return 1;
		}

		internal static string PrefabName(ItemData item)
		{
			if (item == null || !Object.op_Implicit((Object)(object)item.m_dropPrefab))
			{
				return null;
			}
			return ((Object)item.m_dropPrefab).name;
		}

		internal static bool ValidName(string name)
		{
			if (!string.IsNullOrEmpty(name) && name.Length <= 128 && name.IndexOf(',') < 0 && name.IndexOf('|') < 0)
			{
				return !name.Any(char.IsControl);
			}
			return false;
		}

		internal string Encode()
		{
			if (Items.Count > 512 || !Items.All(ValidName) || !Categories.All(ItemCategories.Exists))
			{
				throw new InvalidOperationException(Text.T("The filter has too many or invalid entries.", "В фильтре слишком много или некорректные записи."));
			}
			if (IsEmpty)
			{
				return "";
			}
			return string.Join(",", Categories.OrderBy<string, string>((string c) => c, StringComparer.Ordinal)) + "|" + string.Join(",", Items.OrderBy<string, string>((string i) => i, StringComparer.Ordinal));
		}

		internal static ChestFilter Decode(string raw)
		{
			ChestFilter chestFilter = new ChestFilter();
			if (string.IsNullOrEmpty(raw))
			{
				return chestFilter;
			}
			int num = raw.IndexOf('|');
			string obj = ((num >= 0) ? raw.Substring(0, num) : raw);
			string text = ((num >= 0) ? raw.Substring(num + 1) : "");
			string[] array = obj.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			foreach (string text2 in array)
			{
				if (ItemCategories.Exists(text2))
				{
					chestFilter.Categories.Add(text2);
				}
			}
			array = text.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			foreach (string text3 in array)
			{
				if (ValidName(text3) && chestFilter.Items.Count < 512)
				{
					chestFilter.Items.Add(text3);
				}
			}
			return chestFilter;
		}
	}
	internal static class FilterStore
	{
		internal const string ZdoKey = "AutoStash.Filter.v1";

		private static string _lastRaw;

		private static ChestFilter _lastFilter;

		internal static bool Eligible(Container chest)
		{
			if (Object.op_Implicit((Object)(object)chest) && chest.GetInventory() != null && Object.op_Implicit((Object)(object)((Component)chest).GetComponentInParent<Piece>()) && !Object.op_Implicit((Object)(object)((Component)chest).GetComponent<TombStone>()))
			{
				return !chest.m_autoDestroyEmpty;
			}
			return false;
		}

		internal static ZNetView NetView(Container chest)
		{
			if (!Object.op_Implicit((Object)(object)chest))
			{
				return null;
			}
			return GameAccess.NetView.Invoke(chest);
		}

		internal static string Raw(Container chest)
		{
			ZNetView val = NetView(chest);
			if (!Object.op_Implicit((Object)(object)val) || !val.IsValid())
			{
				return "";
			}
			return val.GetZDO().GetString("AutoStash.Filter.v1", "");
		}

		internal static ChestFilter Load(Container chest)
		{
			string text = Raw(chest);
			if (text != _lastRaw)
			{
				_lastFilter = ChestFilter.Decode(text);
				_lastRaw = text;
			}
			return _lastFilter;
		}

		internal static bool CanEdit(Container chest, out string reason)
		{
			//IL_004b: 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)
			Player localPlayer = Player.m_localPlayer;
			ZNetView val = NetView(chest);
			if (!Eligible(chest) || !Object.op_Implicit((Object)(object)localPlayer) || ((Character)localPlayer).IsDead() || (Object)(object)GameAccess.OpenedChest() != (Object)(object)chest)
			{
				reason = Text.T("Open the chest to edit its filter.", "Откройте сундук, чтобы настроить фильтр.");
				return false;
			}
			if (Vector3.Distance(((Component)localPlayer).transform.position, ((Component)chest).transform.position) > 5f)
			{
				reason = Text.T("Move closer to the chest.", "Подойдите ближе к сундуку.");
				return false;
			}
			if (!Object.op_Implicit((Object)(object)val) || !val.IsValid() || !val.IsOwner())
			{
				reason = Text.T("The chest is busy. Reopen it and try again.", "Сундук занят. Откройте его заново и попробуйте ещё раз.");
				return false;
			}
			reason = "";
			return true;
		}

		internal static bool Save(Container chest, ChestFilter filter, string expected, out string message)
		{
			if (!CanEdit(chest, out message))
			{
				return false;
			}
			if (Raw(chest) != expected)
			{
				message = Text.T("Someone else changed this filter. Reopen the chest to see it.", "Кто-то уже изменил этот фильтр. Откройте сундук заново.");
				return false;
			}
			try
			{
				NetView(chest).GetZDO().Set("AutoStash.Filter.v1", filter.Encode());
				message = "";
				return true;
			}
			catch (Exception ex)
			{
				message = ex.Message;
				return false;
			}
		}
	}
	internal sealed class FilterPanel
	{
		private sealed class Entry
		{
			internal string Prefab;

			internal SharedData Shared;

			internal Sprite Icon;

			internal string Name;

			internal string Search;

			internal ItemCategory Category;

			internal GameObject Cell;

			internal Image Background;
		}

		private const float Width = 780f;

		private const float Height = 620f;

		private const float CellSize = 56f;

		private const float CellGap = 6f;

		private const int Columns = 11;

		private static readonly Color CellIdle = new Color(0.12f, 0.09f, 0.06f, 0.95f);

		private static readonly Color CellPicked = new Color(0.86f, 0.62f, 0.18f, 1f);

		private static readonly Color CellCategory = new Color(0.28f, 0.5f, 0.3f, 1f);

		private static readonly Color CategoryOn = new Color(1f, 0.8f, 0.4f);

		private static readonly Color ErrorColor = new Color(1f, 0.5f, 0.4f);

		private readonly UiKit _kit;

		private readonly List<Entry> _entries = new List<Entry>();

		private readonly List<KeyValuePair<ItemCategory, Button>> _categoryButtons = new List<KeyValuePair<ItemCategory, Button>>();

		private GameObject _canvas;

		private RectTransform _panel;

		private ScrollRect _scroll;

		private Container _chest;

		private string _expected;

		private ChestFilter _draft;

		private TMP_InputField _search;

		private TMP_Text _showLabel;

		private TMP_Text _info;

		private TMP_Text _status;

		private bool _acceptedOnly;

		private Entry _hovered;

		internal bool IsOpen => Object.op_Implicit((Object)(object)_canvas);

		internal FilterPanel(UiKit kit)
		{
			_kit = kit;
		}

		internal void Open(Container chest)
		{
			if (IsOpen)
			{
				return;
			}
			if (!FilterStore.CanEdit(chest, out var reason))
			{
				Player localPlayer = Player.m_localPlayer;
				if (localPlayer != null)
				{
					((Character)localPlayer).Message((MessageType)2, reason, 0, (Sprite)null, false);
				}
				return;
			}
			_chest = chest;
			_expected = FilterStore.Raw(chest);
			_draft = FilterStore.Load(chest).Copy();
			_acceptedOnly = false;
			_hovered = null;
			UITooltip.HideTooltip();
			_kit.Capture(InventoryGui.instance);
			Build();
		}

		internal void Tick()
		{
			if (IsOpen)
			{
				InventoryGui instance = InventoryGui.instance;
				Player localPlayer = Player.m_localPlayer;
				if (!Plugin.Enabled.Value || !Object.op_Implicit((Object)(object)instance) || !((Component)instance.m_container).gameObject.activeInHierarchy || (Object)(object)GameAccess.OpenedChest() != (Object)(object)_chest || !Object.op_Implicit((Object)(object)localPlayer) || ((Character)localPlayer).IsDead())
				{
					Close();
				}
				else if (BackPressed())
				{
					Close();
				}
			}
		}

		internal void Close()
		{
			if (Object.op_Implicit((Object)(object)_canvas))
			{
				Object.Destroy((Object)(object)_canvas);
				InputBlock.MarkClosed();
			}
			_canvas = null;
			_chest = null;
			_hovered = null;
			_entries.Clear();
			_categoryButtons.Clear();
		}

		private static bool BackPressed()
		{
			InputBlock.Polling = true;
			try
			{
				return ZInput.GetKeyDown((KeyCode)27, false) || ZInput.GetButtonDown("JoyButtonB");
			}
			finally
			{
				InputBlock.Polling = false;
			}
		}

		private void Build()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: 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_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: 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_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0305: Expected O, but got Unknown
			//IL_03b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c3: Expected O, but got Unknown
			//IL_0403: Unknown result type (might be due to invalid IL or missing references)
			//IL_040d: Expected O, but got Unknown
			//IL_0484: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ce: Expected O, but got Unknown
			//IL_0505: Unknown result type (might be due to invalid IL or missing references)
			//IL_050f: Expected O, but got Unknown
			//IL_0546: Unknown result type (might be due to invalid IL or missing references)
			//IL_0550: Expected O, but got Unknown
			_canvas = new GameObject("AutoStashCanvas", new Type[4]
			{
				typeof(RectTransform),
				typeof(Canvas),
				typeof(CanvasScaler),
				typeof(GraphicRaycaster)
			});
			Canvas component = _canvas.GetComponent<Canvas>();
			component.renderMode = (RenderMode)0;
			Canvas componentInParent = ((Component)InventoryGui.instance).GetComponentInParent<Canvas>();
			component.sortingOrder = (Object.op_Implicit((Object)(object)componentInParent) ? (componentInParent.sortingOrder + 120) : 1020);
			CanvasScaler component2 = _canvas.GetComponent<CanvasScaler>();
			component2.uiScaleMode = (ScaleMode)1;
			component2.referenceResolution = new Vector2(1280f, 800f);
			component2.matchWidthOrHeight = 1f;
			UiKit.Stretch(((Graphic)UiKit.AddImage("Backdrop", _canvas.transform, new Color(0f, 0f, 0f, 0.7f))).rectTransform);
			Image val = UiKit.AddImage("Panel", _canvas.transform, _kit.PanelColor);
			val.sprite = _kit.PanelSprite;
			val.type = _kit.PanelType;
			_panel = ((Graphic)val).rectTransform;
			RectTransform panel = _panel;
			RectTransform panel2 = _panel;
			RectTransform panel3 = _panel;
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(0.5f, 0.5f);
			panel3.pivot = val2;
			Vector2 anchorMin = (panel2.anchorMax = val2);
			panel.anchorMin = anchorMin;
			_panel.anchoredPosition = Vector2.zero;
			_panel.sizeDelta = new Vector2(780f, 620f);
			_kit.AddText((Transform)(object)_panel, Text.T("Chest filter", "Фильтр сундука"), 24f, 16f, 732f, 32f, 24f);
			TMP_Text obj = _kit.AddText((Transform)(object)_panel, Text.T("The chest accepts the picked items and everything in the picked categories. Press " + Plugin.StashKeyName() + " near it to stash.", "Сундук принимает выбранные предметы и всё из выбранных категорий. Нажмите " + Plugin.StashKeyName() + " рядом, чтобы разложить вещи."), 24f, 48f, 732f, 24f, 15f);
			obj.enableAutoSizing = true;
			obj.fontSizeMin = 11f;
			obj.fontSizeMax = 15f;
			_kit.AddText((Transform)(object)_panel, Text.T("Categories (include items found later):", "Категории (включая предметы, найденные позже):"), 24f, 78f, 732f, 24f, 17f);
			for (int i = 0; i < ItemCategories.All.Length; i++)
			{
				ItemCategory category = ItemCategories.All[i];
				Button value = _kit.AddButton((Transform)(object)_panel, category.Title, 24f + (float)(i % 5) * 148f, 106f + (float)(i / 5) * 38f, 140f, 32f, (UnityAction)delegate
				{
					ToggleCategory(category);
				});
				_categoryButtons.Add(new KeyValuePair<ItemCategory, Button>(category, value));
			}
			_search = _kit.AddInput((Transform)(object)_panel, Text.T("Search items…", "Поиск предметов…"), 24f, 188f, 330f, 34f, 40);
			((UnityEvent<string>)(object)_search.onValueChanged).AddListener((UnityAction<string>)delegate
			{
				ApplyVisibility(resetScroll: true);
			});
			_showLabel = ((Component)_kit.AddButton((Transform)(object)_panel, "", 362f, 188f, 180f, 34f, (UnityAction)delegate
			{
				_acceptedOnly = !_acceptedOnly;
				Refresh();
				ResetScroll();
			})).GetComponentInChildren<TMP_Text>();
			_kit.AddButton((Transform)(object)_panel, Text.T("Add chest contents", "Добавить содержимое"), 550f, 188f, 206f, 34f, new UnityAction(AddChestContents));
			BuildGrid();
			_info = _kit.AddText((Transform)(object)_panel, "", 24f, 530f, 732f, 24f, 16f);
			_status = _kit.AddText((Transform)(object)_panel, "", 24f, 554f, 732f, 22f, 14f);
			((Graphic)_status).color = ErrorColor;
			_kit.AddButton((Transform)(object)_panel, Text.T("Clear all", "Очистить"), 24f, 580f, 150f, 34f, (UnityAction)delegate
			{
				_draft.Items.Clear();
				_draft.Categories.Clear();
				_status.text = "";
				Refresh();
			});
			_kit.AddButton((Transform)(object)_panel, Text.T("Cancel", "Отмена"), 536f, 580f, 105f, 34f, new UnityAction(Close));
			_kit.AddButton((Transform)(object)_panel, Text.T("Save", "Сохранить"), 651f, 580f, 105f, 34f, new UnityAction(Save));
			Refresh();
		}

		private void BuildGrid()
		{
			//IL_0044: 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)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected O, but got Unknown
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: 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)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: 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_0119: Expected O, but got Unknown
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = UiKit.AddRect("Items", (Transform)(object)_panel, 24f, 232f, 716f, 290f);
			((Graphic)((Component)val).gameObject.AddComponent<Image>()).color = new Color(0f, 0f, 0f, 0.35f);
			((Component)val).gameObject.AddComponent<RectMask2D>();
			RectTransform val2 = (RectTransform)new GameObject("Content", new Type[1] { typeof(RectTransform) }).transform;
			((Transform)val2).SetParent((Transform)(object)val, false);
			val2.anchorMin = new Vector2(0f, 1f);
			val2.anchorMax = Vector2.one;
			val2.pivot = new Vector2(0.5f, 1f);
			val2.anchoredPosition = Vector2.zero;
			val2.sizeDelta = Vector2.zero;
			GridLayoutGroup obj = ((Component)val2).gameObject.AddComponent<GridLayoutGroup>();
			obj.cellSize = new Vector2(56f, 56f);
			obj.spacing = new Vector2(6f, 6f);
			((LayoutGroup)obj).padding = new RectOffset(8, 8, 8, 8);
			obj.constraint = (Constraint)1;
			obj.constraintCount = 11;
			((LayoutGroup)obj).childAlignment = (TextAnchor)1;
			((Component)val2).gameObject.AddComponent<ContentSizeFitter>().verticalFit = (FitMode)2;
			_scroll = ((Component)val).gameObject.AddComponent<ScrollRect>();
			_scroll.horizontal = false;
			_scroll.vertical = true;
			_scroll.movementType = (MovementType)2;
			_scroll.inertia = false;
			_scroll.scrollSensitivity = 40f;
			_scroll.viewport = val;
			_scroll.content = val2;
			RectTransform val3 = UiKit.AddRect("Scrollbar", (Transform)(object)_panel, 744f, 232f, 12f, 290f);
			((Graphic)((Component)val3).gameObject.AddComponent<Image>()).color = new Color(0f, 0f, 0f, 0.5f);
			RectTransform val4 = UiKit.AddRect("Area", (Transform)(object)val3, 0f, 0f, 0f, 0f);
			UiKit.Stretch(val4);
			Image val5 = UiKit.AddImage("Handle", (Transform)(object)val4, new Color(0.85f, 0.65f, 0.35f, 0.9f));
			UiKit.Stretch(((Graphic)val5).rectTransform);
			Scrollbar val6 = ((Component)val3).gameObject.AddComponent<Scrollbar>();
			val6.handleRect = ((Graphic)val5).rectTransform;
			((Selectable)val6).targetGraphic = (Graphic)(object)val5;
			val6.direction = (Direction)2;
			_scroll.verticalScrollbar = val6;
			_scroll.verticalScrollbarVisibility = (ScrollbarVisibility)0;
			foreach (Entry item in Catalog())
			{
				AddCell((Transform)(object)val2, item);
				_entries.Add(item);
			}
		}

		private void AddCell(Transform content, Entry entry)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Expected O, but got Unknown
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Item", new Type[5]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image),
				typeof(Button),
				typeof(HoverRelay)
			});
			val.transform.SetParent(content, false);
			Image component = val.GetComponent<Image>();
			((Graphic)component).color = CellIdle;
			Button component2 = val.GetComponent<Button>();
			((Selectable)component2).transition = (Transition)0;
			Navigation navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)0;
			((Selectable)component2).navigation = navigation;
			((UnityEvent)component2.onClick).AddListener((UnityAction)delegate
			{
				ToggleItem(entry);
			});
			HoverRelay component3 = val.GetComponent<HoverRelay>();
			component3.Entered = delegate
			{
				SetHovered(entry);
			};
			component3.Exited = delegate
			{
				if (_hovered == entry)
				{
					SetHovered(null);
				}
			};
			if (Object.op_Implicit((Object)(object)entry.Icon))
			{
				Image obj = UiKit.AddImage("Icon", val.transform, Color.white);
				UiKit.Stretch(((Graphic)obj).rectTransform, 5f);
				obj.sprite = entry.Icon;
				obj.preserveAspect = true;
				((Graphic)obj).raycastTarget = false;
			}
			else
			{
				TMP_Text obj2 = _kit.AddText(val.transform, entry.Name, 0f, 0f, 0f, 0f, 10f);
				UiKit.Stretch(obj2.rectTransform, 3f);
				obj2.alignment = (TextAlignmentOptions)514;
				obj2.textWrappingMode = (TextWrappingModes)1;
			}
			entry.Cell = val;
			entry.Background = component;
		}

		private List<Entry> Catalog()
		{
			Player localPlayer = Player.m_localPlayer;
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			AddPresent(hashSet, _chest.GetInventory());
			if (Object.op_Implicit((Object)(object)localPlayer))
			{
				AddPresent(hashSet, ((Humanoid)localPlayer).GetInventory());
			}
			Dictionary<string, Entry> dictionary = new Dictionary<string, Entry>(StringComparer.Ordinal);
			ObjectDB instance = ObjectDB.instance;
			if (Object.op_Implicit((Object)(object)instance))
			{
				foreach (GameObject item in instance.m_items)
				{
					ItemDrop val = (Object.op_Implicit((Object)(object)item) ? item.GetComponent<ItemDrop>() : null);
					SharedData val2 = ((Object.op_Implicit((Object)(object)val) && val.m_itemData != null) ? val.m_itemData.m_shared : null);
					if (val2 != null && !string.IsNullOrEmpty(val2.m_name) && val2.m_icons != null && val2.m_icons.Length != 0 && Object.op_Implicit((Object)(object)val2.m_icons[0]) && ChestFilter.ValidName(((Object)item).name) && !dictionary.ContainsKey(((Object)item).name) && (Plugin.ShowUndiscovered.Value || _draft.Items.Contains(((Object)item).name) || hashSet.Contains(((Object)item).name) || (Object.op_Implicit((Object)(object)localPlayer) && localPlayer.IsMaterialKnown(val2.m_name))))
					{
						string text = Text.Localize(val2.m_name);
						dictionary[((Object)item).name] = new Entry
						{
							Prefab = ((Object)item).name,
							Shared = val2,
							Icon = val2.m_icons[0],
							Name = text,
							Search = (text + " " + ((Object)item).name).ToLowerInvariant(),
							Category = ItemCategories.Of(val2)
						};
					}
				}
			}
			foreach (string item2 in _draft.Items)
			{
				if (!dictionary.ContainsKey(item2))
				{
					dictionary[item2] = new Entry
					{
						Prefab = item2,
						Name = item2,
						Search = item2.ToLowerInvariant()
					};
				}
			}
			return dictionary.Values.OrderBy((Entry e) => (e.Category == null) ? int.MaxValue : ItemCategories.IndexOf(e.Category)).ThenBy<Entry, string>((Entry e) => e.Name, StringComparer.CurrentCultureIgnoreCase).ToList();
		}

		private static void AddPresent(HashSet<string> present, Inventory inventory)
		{
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				string text = ChestFilter.PrefabName(allItem);
				if (text != null)
				{
					present.Add(text);
				}
			}
		}

		private int Rank(Entry entry)
		{
			return _draft.Rank(entry.Prefab, entry.Shared);
		}

		private void ToggleItem(Entry entry)
		{
			if (!_draft.Items.Remove(entry.Prefab))
			{
				_draft.Items.Add(entry.Prefab);
			}
			_status.text = "";
			if (_acceptedOnly)
			{
				ApplyVisibility(resetScroll: false);
			}
			else
			{
				RefreshCell(entry);
			}
			UpdateInfo();
		}

		private void ToggleCategory(ItemCategory category)
		{
			if (!_draft.Categories.Remove(category.Id))
			{
				_draft.Categories.Add(category.Id);
			}
			_status.text = "";
			Refresh();
		}

		private void AddChestContents()
		{
			int num = 0;
			foreach (ItemData allItem in _chest.GetInventory().GetAllItems())
			{
				string text = ChestFilter.PrefabName(allItem);
				if (text != null && ChestFilter.ValidName(text) && _draft.Items.Add(text))
				{
					num++;
				}
			}
			_status.text = ((_chest.GetInventory().NrOfItems() == 0) ? Text.T("The chest is empty.", "Сундук пуст.") : ((num == 0) ? Text.T("Everything in the chest is already picked.", "Всё содержимое сундука уже выбрано.") : ""));
			Refresh();
		}

		private void SetHovered(Entry entry)
		{
			Entry hovered = _hovered;
			_hovered = entry;
			if (hovered != null)
			{
				RefreshCell(hovered);
			}
			if (entry != null)
			{
				RefreshCell(entry);
			}
			UpdateInfo();
		}

		private void Refresh()
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: 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)
			if (!Object.op_Implicit((Object)(object)_panel))
			{
				return;
			}
			foreach (KeyValuePair<ItemCategory, Button> categoryButton in _categoryButtons)
			{
				bool flag = _draft.Categories.Contains(categoryButton.Key.Id);
				((Graphic)((Selectable)categoryButton.Value).image).color = (flag ? CategoryOn : _kit.ButtonColor);
				TMP_Text componentInChildren = ((Component)categoryButton.Value).GetComponentInChildren<TMP_Text>();
				((Graphic)componentInChildren).color = (flag ? Color.white : UiKit.TextColor);
				componentInChildren.fontStyle = (FontStyles)(flag ? 1 : 0);
			}
			_showLabel.text = (_acceptedOnly ? Text.T("Showing: accepted", "Показаны: принимаемые") : Text.T("Showing: all", "Показаны: все"));
			ApplyVisibility(resetScroll: false);
			UpdateInfo();
		}

		private void ApplyVisibility(bool resetScroll)
		{
			string text = (Object.op_Implicit((Object)(object)_search) ? _search.text : "").Trim().ToLowerInvariant();
			foreach (Entry entry in _entries)
			{
				bool flag = (text.Length == 0 || entry.Search.Contains(text)) && (!_acceptedOnly || Rank(entry) != -1);
				if (entry.Cell.activeSelf != flag)
				{
					entry.Cell.SetActive(flag);
				}
				if (!flag && _hovered == entry)
				{
					_hovered = null;
				}
				RefreshCell(entry);
			}
			if (resetScroll)
			{
				ResetScroll();
			}
			UpdateInfo();
		}

		private void ResetScroll()
		{
			if (Object.op_Implicit((Object)(object)_scroll))
			{
				_scroll.verticalNormalizedPosition = 1f;
			}
		}

		private void RefreshCell(Entry entry)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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_0036: 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)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			Color val = (Color)(Rank(entry) switch
			{
				1 => CellCategory, 
				0 => CellPicked, 
				_ => CellIdle, 
			});
			((Graphic)entry.Background).color = ((entry == _hovered) ? Color.Lerp(val, Color.white, 0.3f) : val);
		}

		private void UpdateInfo()
		{
			if (Object.op_Implicit((Object)(object)_info))
			{
				if (_hovered != null)
				{
					int num = Rank(_hovered);
					string text = ((_hovered.Category != null) ? _hovered.Category.Title : "");
					string text2 = num switch
					{
						1 => Text.T("accepted via \"" + text + "\" (click to pick it too)", "принимается через «" + text + "» (нажмите, чтобы выбрать отдельно)"), 
						0 => Text.T("accepted, picked (click to remove)", "принимается, выбран (нажмите, чтобы убрать)"), 
						_ => Text.T("not accepted (click to add)", "не принимается (нажмите, чтобы добавить)"), 
					};
					_info.text = _hovered.Name + ": " + text2;
				}
				else
				{
					int count = _draft.Items.Count;
					int count2 = _draft.Categories.Count;
					_info.text = (_draft.IsEmpty ? Text.T("The chest accepts nothing yet. Pick categories or click items.", "Пока сундук ничего не принимает. Выберите категории или нажмите на предметы.") : Text.T($"Picked items: {count}. Categories: {count2}.", $"Выбрано предметов: {count}. Категорий: {count2}."));
				}
			}
		}

		private void Save()
		{
			if (IsOpen)
			{
				if (FilterStore.Save(_chest, _draft, _expected, out var message))
				{
					Close();
				}
				else
				{
					_status.text = message;
				}
			}
		}
	}
	internal sealed class LockMarker : MonoBehaviour
	{
		internal const string ObjectName = "AutoStashLock";

		private const float FrameWidth = 2f;

		private Image[] _edges;

		internal static LockMarker Create(Transform element)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: 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_0036: Expected O, but got Unknown
			//IL_0037: 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_004e: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: 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_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: 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_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: 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_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: 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)
			GameObject val = new GameObject("AutoStashLock", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(element, false);
			RectTransform val2 = (RectTransform)val.transform;
			val2.anchorMin = Vector2.zero;
			val2.anchorMax = Vector2.one;
			Vector2 offsetMin = (val2.offsetMax = Vector2.zero);
			val2.offsetMin = offsetMin;
			LockMarker lockMarker = val.AddComponent<LockMarker>();
			lockMarker._edges = (Image[])(object)new Image[4]
			{
				Edge((Transform)(object)val2, "Top", new Vector2(0f, 1f), Vector2.one, new Vector2(0f, -2f), Vector2.zero),
				Edge((Transform)(object)val2, "Bottom", Vector2.zero, new Vector2(1f, 0f), Vector2.zero, new Vector2(0f, 2f)),
				Edge((Transform)(object)val2, "Left", Vector2.zero, new Vector2(0f, 1f), Vector2.zero, new Vector2(2f, 0f)),
				Edge((Transform)(object)val2, "Right", new Vector2(1f, 0f), Vector2.one, new Vector2(-2f, 0f), Vector2.zero)
			};
			return lockMarker;
		}

		internal void Apply(Color color)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			Image[] edges = _edges;
			for (int i = 0; i < edges.Length; i++)
			{
				((Graphic)edges[i]).color = color;
			}
		}

		private static Image Edge(Transform parent, string name, Vector2 anchorMin, Vector2 anchorMax, Vector2 offsetMin, Vector2 offsetMax)
		{
			//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_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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_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_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: 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)
			GameObject val = new GameObject(name, new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			val.transform.SetParent(parent, false);
			RectTransform val2 = (RectTransform)val.transform;
			val2.anchorMin = anchorMin;
			val2.anchorMax = anchorMax;
			val2.offsetMin = offsetMin;
			val2.offsetMax = offsetMax;
			Image component = val.GetComponent<Image>();
			((Graphic)component).raycastTarget = false;
			return component;
		}
	}
	[BepInPlugin("dbendu.AutoStash", "Auto Stash", "1.1.0")]
	[BepInProcess("valheim.exe")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Guid = "dbendu.AutoStash";

		public const string Name = "Auto Stash";

		public const string Version = "1.1.0";

		private static readonly KeyCode[] ExclusiveModifiers;

		private readonly Harmony _harmony = new Harmony("dbendu.AutoStash");

		internal static ManualLogSource Log { get; private set; }

		internal static ConfigEntry<bool> Enabled { get; private set; }

		internal static ConfigEntry<KeyboardShortcut> StashKey { get; private set; }

		internal static ConfigEntry<float> Radius { get; private set; }

		internal static ConfigEntry<KeyCode> LockModifier { get; private set; }

		internal static ConfigEntry<bool> ProtectFromPlaceStacks { get; private set; }

		internal static ConfigEntry<Color> FrameColor { get; private set; }

		internal static ConfigEntry<bool> InventoryButton { get; private set; }

		internal static ConfigEntry<bool> ShowUndiscovered { get; private set; }

		internal static StashUi Ui { get; private set; }

		private void Awake()
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable chest filters, stashing and locked slots.");
			StashKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "StashKey", new KeyboardShortcut((KeyCode)122, Array.Empty<KeyCode>()), "Key that puts inventory items into nearby chests whose filter accepts them. Alt/Ctrl must not be held unless they are part of the shortcut.");
			Radius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Radius", 10f, new ConfigDescription("Chests farther than this many metres from the player are ignored.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 50f), Array.Empty<object>()));
			LockModifier = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Locked slots", "ToggleModifier", (KeyCode)308, "Hold this key and left-click an inventory slot to lock or unlock it. Items in locked slots are never stashed.");
			ProtectFromPlaceStacks = ((BaseUnityPlugin)this).Config.Bind<bool>("Locked slots", "ProtectFromPlaceStacks", true, "Also keep locked slots out of the game's own \"Place stacks\" action.");
			FrameColor = ((BaseUnityPlugin)this).Config.Bind<Color>("Locked slots", "FrameColor", new Color(1f, 0.62f, 0.2f, 1f), "Colour of the frame drawn around locked slots.");
			InventoryButton = ((BaseUnityPlugin)this).Config.Bind<bool>("Interface", "InventoryButton", true, "Show a Stash button next to the inventory.");
			ShowUndiscovered = ((BaseUnityPlugin)this).Config.Bind<bool>("Interface", "ShowUndiscoveredItems", false, "List every item in the filter editor, not only items this character has discovered.");
			Ui = new StashUi();
			_harmony.PatchAll(typeof(Plugin).Assembly);
		}

		private void Update()
		{
			try
			{
				Ui?.Tick();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Filter window closed after an error: " + ex));
				Ui?.ClosePanel();
			}
			try
			{
				Stasher.Tick();
				if (Enabled.Value && StashKeyPressed())
				{
					Stasher.Begin();
				}
			}
			catch (Exception ex2)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Stashing stopped after an error: " + ex2));
				Stasher.Abort();
			}
		}

		private void OnDestroy()
		{
			_harmony.UnpatchSelf();
			Stasher.Abort();
			Ui?.Dispose();
			Ui = null;
		}

		private static bool StashKeyPressed()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: 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_0078: 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_0084: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = StashKey.Value;
			if ((int)((KeyboardShortcut)(ref value)).MainKey == 0 || !ZInput.GetKeyDown(((KeyboardShortcut)(ref value)).MainKey, false))
			{
				return false;
			}
			List<KeyCode> list = new List<KeyCode>(((KeyboardShortcut)(ref value)).Modifiers);
			foreach (KeyCode item in list)
			{
				if (!ZInput.GetKey(item, false))
				{
					return false;
				}
			}
			KeyCode[] exclusiveModifiers = ExclusiveModifiers;
			foreach (KeyCode val in exclusiveModifiers)
			{
				if (!list.Contains(val) && ZInput.GetKey(val, false))
				{
					return false;
				}
			}
			return CanStashNow();
		}

		private static bool CanStashNow()
		{
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer) || ((Character)localPlayer).IsDead() || ((Character)localPlayer).IsTeleporting() || ((Character)localPlayer).InCutscene())
			{
				return false;
			}
			if ((Object.op_Implicit((Object)(object)Chat.instance) && Chat.instance.HasFocus()) || Console.IsVisible() || TextInput.IsVisible() || Menu.IsVisible() || StoreGui.IsVisible() || Minimap.IsOpen() || (Object.op_Implicit((Object)(object)TextViewer.instance) && TextViewer.instance.IsVisible()) || PlayerCustomizaton.IsBarberGuiVisible() || GameCamera.InFreeFly() || (Object.op_Implicit((Object)(object)Hud.instance) && Object.op_Implicit((Object)(object)Hud.instance.m_buildUi) && Hud.instance.m_buildUi.SearchFieldFocused))
			{
				return false;
			}
			if (!TextFieldFocused())
			{
				if (Ui != null)
				{
					return !Ui.PanelOpen;
				}
				return true;
			}
			return false;
		}

		private static bool TextFieldFocused()
		{
			GameObject val = (Object.op_Implicit((Object)(object)EventSystem.current) ? EventSystem.current.currentSelectedGameObject : null);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return false;
			}
			TMP_InputField component = val.GetComponent<TMP_InputField>();
			InputField component2 = val.GetComponent<InputField>();
			if (!Object.op_Implicit((Object)(object)component) || !component.isFocused)
			{
				if (Object.op_Implicit((Object)(object)component2))
				{
					return component2.isFocused;
				}
				return false;
			}
			return true;
		}

		internal unsafe static string KeyName(KeyCode key)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected I4, but got Unknown
			switch (key - 303)
			{
			case 4:
			case 5:
				return "Alt";
			case 2:
			case 3:
				return "Ctrl";
			case 0:
			case 1:
				return "Shift";
			default:
				return ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString();
			}
		}

		internal static string StashKeyName()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = StashKey.Value;
			List<string> list = new List<string>();
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers)
			{
				list.Add(KeyName(modifier));
			}
			list.Add(KeyName(((KeyboardShortcut)(ref value)).MainKey));
			return string.Join("+", list);
		}

		static Plugin()
		{
			KeyCode[] array = new KeyCode[6];
			RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			ExclusiveModifiers = (KeyCode[])(object)array;
		}
	}
	internal static class GameAccess
	{
		internal static readonly FieldRef<InventoryGui, Container> CurrentContainer = AccessTools.FieldRefAccess<InventoryGui, Container>("m_currentContainer");

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

		internal static readonly FieldRef<InventoryGui, GameObject> DragObject = AccessTools.FieldRefAccess<InventoryGui, GameObject>("m_dragGo");

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

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

		internal static readonly FieldRef<Inventory, List<ItemData>> Items = AccessTools.FieldRefAccess<Inventory, List<ItemData>>("m_inventory");

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

		private static readonly MethodInfo InventoryChanged = AccessTools.Method(typeof(Inventory), "Changed", (Type[])null, (Type[])null);

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

		internal static Container OpenedChest()
		{
			InventoryGui instance = InventoryGui.instance;
			if (!Object.op_Implicit((Object)(object)instance))
			{
				return null;
			}
			return CurrentContainer.Invoke(instance);
		}

		internal static void Changed(Inventory inventory)
		{
			InventoryChanged.Invoke(inventory, new object[2] { false, false });
		}

		internal static void Reload(Container chest)
		{
			ContainerLoad.Invoke(chest, Array.Empty<object>());
		}
	}
	internal static class Text
	{
		internal static bool Russian
		{
			get
			{
				if (Localization.instance != null)
				{
					return Localization.instance.GetSelectedLanguage() == "Russian";
				}
				return false;
			}
		}

		internal static string T(string english, string russian)
		{
			if (!Russian)
			{
				return english;
			}
			return russian;
		}

		internal static string Plural(int count, string one, string few, string many)
		{
			int num = Math.Abs(count) % 100;
			int num2 = num % 10;
			if (num > 10 && num < 20)
			{
				return many;
			}
			switch (num2)
			{
			case 1:
				return one;
			default:
				return many;
			case 2:
			case 3:
			case 4:
				return few;
			}
		}

		internal static string Localize(string token)
		{
			if (Localization.instance == null)
			{
				return token;
			}
			return Localization.instance.Localize(token);
		}
	}
	internal static class InputBlock
	{
		private static int _lastActiveFrame = -10;

		internal static bool Polling;

		internal static bool Active
		{
			get
			{
				if (Polling)
				{
					return false;
				}
				if (Plugin.Ui != null && Plugin.Ui.PanelOpen)
				{
					_lastActiveFrame = Time.frameCount;
					return true;
				}
				return Time.frameCount <= _lastActiveFrame + 1;
			}
		}

		internal static void MarkClosed()
		{
			_lastActiveFrame = Time.frameCount;
		}
	}
	[HarmonyPatch]
	internal static class ZInputButtonPatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			string[] array = new string[3] { "GetButton", "GetButtonDown", "GetButtonUp" };
			foreach (string text in array)
			{
				yield return AccessTools.Method(typeof(ZInput), text, new Type[1] { typeof(string) }, (Type[])null);
			}
		}

		[HarmonyPriority(0)]
		private static void Postfix(ref bool __result)
		{
			if (InputBlock.Active)
			{
				__result = false;
			}
		}
	}
	[HarmonyPatch]
	internal static class ZInputKeyPatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			string[] array = new string[3] { "GetKey", "GetKeyDown", "GetKeyUp" };
			foreach (string text in array)
			{
				yield return AccessTools.Method(typeof(ZInput), text, new Type[2]
				{
					typeof(KeyCode),
					typeof(bool)
				}, (Type[])null);
			}
		}

		[HarmonyPriority(0)]
		private static void Postfix(KeyCode key, ref bool __result)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Invalid comparison between Unknown and I4
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Invalid comparison between Unknown and I4
			if (InputBlock.Active && ((int)key < 323 || (int)key > 329))
			{
				__result = false;
			}
		}
	}
	internal static class SlotLocks
	{
		private const string DataKey = "AutoStash.LockedSlots.v1";

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

		private static Player _player;

		private static string _raw;

		private static HashSet<int> _locked = new HashSet<int>();

		private static int Key(Vector2i pos)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			return pos.y * 1000 + pos.x;
		}

		private static HashSet<int> Current()
		{
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer))
			{
				return Empty;
			}
			localPlayer.m_customData.TryGetValue("AutoStash.LockedSlots.v1", out var value);
			value = value ?? "";
			if ((Object)(object)localPlayer != (Object)(object)_player || value != _raw)
			{
				_player = localPlayer;
				_raw = value;
				_locked = Parse(value);
			}
			return _locked;
		}

		private static HashSet<int> Parse(string raw)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			HashSet<int> hashSet = new HashSet<int>();
			string[] array = raw.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(',');
				if (array2.Length == 2 && int.TryParse(array2[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && int.TryParse(array2[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2) && result >= 0 && result < 1000 && result2 >= 0 && result2 < 1000)
				{
					hashSet.Add(Key(new Vector2i(result, result2)));
				}
			}
			return hashSet;
		}

		internal static bool IsLocked(Vector2i pos)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			return Current().Contains(Key(pos));
		}

		internal static bool Lockable(Vector2i pos)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: 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_0045: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer))
			{
				return false;
			}
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			if (pos.x >= 0 && pos.y >= 0 && pos.x < inventory.GetWidth() && pos.y < ExtraSlotsCompat.PlayerRows(inventory))
			{
				return !ExtraSlotsCompat.IsSlot(pos);
			}
			return false;
		}

		internal static bool Protects(ItemData item)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			if (item != null && IsLocked(item.m_gridPos))
			{
				return Lockable(item.m_gridPos);
			}
			return false;
		}

		internal static void Toggle(Vector2i pos)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer))
			{
				return;
			}
			HashSet<int> hashSet = new HashSet<int>(Current());
			if (!hashSet.Remove(Key(pos)))
			{
				hashSet.Add(Key(pos));
			}
			List<string> list = new List<string>();
			foreach (int item in hashSet)
			{
				list.Add((item % 1000).ToString(CultureInfo.InvariantCulture) + "," + (item / 1000).ToString(CultureInfo.InvariantCulture));
			}
			list.Sort(StringComparer.Ordinal);
			if (list.Count == 0)
			{
				localPlayer.m_customData.Remove("AutoStash.LockedSlots.v1");
			}
			else
			{
				localPlayer.m_customData["AutoStash.LockedSlots.v1"] = string.Join(";", list);
			}
		}

		internal static bool ModifierHeld()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: 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_0010: 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_0021: Invalid comparison between Unknown and I4
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Invalid comparison between Unknown and I4
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Invalid comparison between Unknown and I4
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			KeyCode value = Plugin.LockModifier.Value;
			if ((int)value == 0)
			{
				return false;
			}
			if (ZInput.GetKey(value, false))
			{
				return true;
			}
			KeyCode val = (KeyCode)(((int)value == 308) ? 307 : (((int)value == 306) ? 305 : (((int)value == 304) ? 303 : 0)));
			if ((int)val != 0)
			{
				return ZInput.GetKey(val, false);
			}
			return false;
		}

		internal static void UpdateOverlays(InventoryGrid grid)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			bool value = Plugin.Enabled.Value;
			Color value2 = Plugin.FrameColor.Value;
			foreach (InventoryElement item in GameAccess.Elements.Invoke(grid))
			{
				if (!Object.op_Implicit((Object)(object)item))
				{
					continue;
				}
				bool flag = value && IsLocked(item.Position) && Lockable(item.Position);
				Transform val = ((Component)item).transform.Find("AutoStashLock");
				LockMarker lockMarker = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponent<LockMarker>() : null);
				if (!Object.op_Implicit((Object)(object)lockMarker))
				{
					if (!flag)
					{
						continue;
					}
					lockMarker = LockMarker.Create(((Component)item).transform);
				}
				if (((Component)lockMarker).gameObject.activeSelf != flag)
				{
					((Component)lockMarker).gameObject.SetActive(flag);
				}
				if (flag)
				{
					lockMarker.Apply(value2);
				}
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "OnSelectedItem")]
	internal static class LockClickPatch
	{
		[HarmonyPriority(800)]
		private static bool Prefix(InventoryGui __instance, InventoryGrid grid, Vector2i pos)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Enabled.Value || (Object)(object)grid != (Object)(object)__instance.m_playerGrid || Object.op_Implicit((Object)(object)GameAccess.DragObject.Invoke(__instance)) || !SlotLocks.ModifierHeld() || !SlotLocks.Lockable(pos))
			{
				return true;
			}
			SlotLocks.Toggle(pos);
			__instance.m_moveItemEffects.Create(((Component)__instance).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
			return false;
		}
	}
	[HarmonyPatch(typeof(InventoryGrid), "UpdateGui")]
	internal static class LockOverlayPatch
	{
		private static void Postfix(InventoryGrid __instance)
		{
			InventoryGui instance = InventoryGui.instance;
			if (Object.op_Implicit((Object)(object)instance) && (Object)(object)__instance == (Object)(object)instance.m_playerGrid)
			{
				SlotLocks.UpdateOverlays(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(Inventory), "StackAll")]
	internal static class PlaceStacksPatch
	{
		private static Inventory _inventory;

		private static readonly List<KeyValuePair<int, ItemData>> Hidden = new List<KeyValuePair<int, ItemData>>();

		private static void Prefix(Inventory fromInventory)
		{
			Restore();
			Player localPlayer = Player.m_localPlayer;
			if (!Plugin.Enabled.Value || !Plugin.ProtectFromPlaceStacks.Value || !Object.op_Implicit((Object)(object)localPlayer) || fromInventory != ((Humanoid)localPlayer).GetInventory())
			{
				return;
			}
			List<ItemData> list = GameAccess.Items.Invoke(fromInventory);
			for (int num = list.Count - 1; num >= 0; num--)
			{
				ItemData val = list[num];
				if (SlotLocks.Protects(val) && !((Humanoid)localPlayer).IsItemEquiped(val))
				{
					Hidden.Add(new KeyValuePair<int, ItemData>(num, val));
					list.RemoveAt(num);
				}
			}
			if (Hidden.Count > 0)
			{
				_inventory = fromInventory;
			}
		}

		private static Exception Finalizer(Exception __exception)
		{
			Restore();
			return __exception;
		}

		private static void Restore()
		{
			Inventory inventory = _inventory;
			if (inventory == null)
			{
				Hidden.Clear();
				return;
			}
			_inventory = null;
			List<ItemData> list = GameAccess.Items.Invoke(inventory);
			for (int num = Hidden.Count - 1; num >= 0; num--)
			{
				KeyValuePair<int, ItemData> keyValuePair = Hidden[num];
				if (!list.Contains(keyValuePair.Value))
				{
					list.Insert(Math.Min(keyValuePair.Key, list.Count), keyValuePair.Value);
				}
			}
			Hidden.Clear();
			try
			{
				GameAccess.Changed(inventory);
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("Could not refresh the inventory after Place stacks: " + ex.Message));
				}
			}
		}
	}
	internal static class ExtraSlotsCompat
	{
		internal const string Guid = "shudnal.ExtraSlots";

		private static bool _initialized;

		private static Func<ItemData, bool> _isItemInSlot;

		private static Func<Vector2i, bool> _isGridPositionASlot;

		private static Func<int> _playerRows;

		private static void Init()
		{
			if (_initialized)
			{
				return;
			}
			_initialized = true;
			if (!Chainloader.PluginInfos.TryGetValue("shudnal.ExtraSlots", out var value) || !Object.op_Implicit((Object)(object)value.Instance))
			{
				return;
			}
			try
			{
				Type type = ((object)value.Instance).GetType().Assembly.GetType("ExtraSlots.API");
				if (type == null)
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogWarning((object)"ExtraSlots API not found; its slots are not recognised.");
					}
					return;
				}
				MethodInfo methodInfo = AccessTools.Method(type, "IsItemInSlot", new Type[1] { typeof(ItemData) }, (Type[])null);
				MethodInfo methodInfo2 = AccessTools.Method(type, "IsGridPositionASlot", new Type[1] { typeof(Vector2i) }, (Type[])null);
				MethodInfo methodInfo3 = AccessTools.Method(type, "GetInventoryHeightPlayer", Type.EmptyTypes, (Type[])null);
				_isItemInSlot = ((methodInfo != null) ? ((Func<ItemData, bool>)Delegate.CreateDelegate(typeof(Func<ItemData, bool>), methodInfo)) : null);
				_isGridPositionASlot = ((methodInfo2 != null) ? ((Func<Vector2i, bool>)Delegate.CreateDelegate(typeof(Func<Vector2i, bool>), methodInfo2)) : null);
				_playerRows = ((methodInfo3 != null) ? ((Func<int>)Delegate.CreateDelegate(typeof(Func<int>), methodInfo3)) : null);
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("ExtraSlots integration unavailable: " + ex.Message));
				}
			}
		}

		internal static bool IsItemInSlot(ItemData item)
		{
			Init();
			try
			{
				return _isItemInSlot != null && _isItemInSlot(item);
			}
			catch
			{
				return false;
			}
		}

		internal static bool IsSlot(Vector2i pos)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			Init();
			try
			{
				return _isGridPositionASlot != null && _isGridPositionASlot(pos);
			}
			catch
			{
				return false;
			}
		}

		internal static int PlayerRows(Inventory inventory)
		{
			Init();
			int height = inventory.GetHeight();
			try
			{
				int num = ((_playerRows != null) ? _playerRows() : height);
				return (num > 0) ? Math.Min(num, height) : height;
			}
			catch
			{
				return height;
			}
		}
	}
	internal static class Stasher
	{
		private sealed class Target
		{
			internal Container Chest;

			internal float Distance;

			internal ChestFilter Filter;
		}

		private sealed class Session
		{
			internal readonly List<Target> Ready = new List<Target>();

			internal readonly Dictionary<Container, Target> Requested = new Dictionary<Container, Target>();

			internal readonly Dictionary<Container, Target> Granted = new Dictionary<Container, Target>();

			internal float Deadline;

			internal int Unavailable;
		}

		private const float TimeoutSeconds = 3f;

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

		private static Session _session;

		internal static void Register(Container chest)
		{
			Chests.Add(chest);
		}

		internal static void Abort()
		{
			_session = null;
		}

		internal static void Begin()
		{
			Player localPlayer = Player.m_localPlayer;
			if (_session != null || !Object.op_Implicit((Object)(object)localPlayer))
			{
				return;
			}
			long playerID = Game.instance.GetPlayerProfile().GetPlayerID();
			int inUse;
			List<Target> targets = FindTargets(localPlayer, playerID, out inUse);
			if (targets.Count == 0)
			{
				((Character)localPlayer).Message((MessageType)2, (inUse > 0) ? Text.T("The chests nearby are in use.", "Сундуки рядом заняты другими игроками.") : Text.T("No chests with a filter nearby.", "Рядом нет сундуков с фильтром."), 0, (Sprite)null, false);
				return;
			}
			if (!Candidates(localPlayer).Any((ItemData item) => targets.Any((Target t) => t.Filter.Rank(item) != -1)))
			{
				((Character)localPlayer).Message((MessageType)2, Text.T("Nothing to stash.", "Нечего раскладывать."), 0, (Sprite)null, false);
				return;
			}
			Session session = new Session
			{
				Deadline = Time.unscaledTime + 3f,
				Unavailable = inUse
			};
			foreach (Target item in targets)
			{
				ZNetView val = FilterStore.NetView(item.Chest);
				if (val.IsOwner())
				{
					session.Ready.Add(item);
				}
				else if (!val.GetZDO().HasOwner())
				{
					val.ClaimOwnership();
					session.Ready.Add(item);
				}
				else
				{
					session.Requested[item.Chest] = item;
				}
			}
			_session = session;
			foreach (Container item2 in session.Requested.Keys.ToList())
			{
				FilterStore.NetView(item2).InvokeRPC("RPC_RequestStack", new object[1] { playerID });
			}
			Tick();
		}

		internal static void Tick()
		{
			Session session = _session;
			if (session == null)
			{
				return;
			}
			foreach (KeyValuePair<Container, Target> item in session.Granted.ToList())
			{
				ZNetView val = FilterStore.NetView(item.Key);
				if (!Object.op_Implicit((Object)(object)item.Key) || !Object.op_Implicit((Object)(object)val) || !val.IsValid())
				{
					session.Granted.Remove(item.Key);
				}
				else if (val.IsOwner())
				{
					session.Granted.Remove(item.Key);
					session.Ready.Add(item.Value);
				}
			}
			if ((session.Requested.Count <= 0 && session.Granted.Count <= 0) || !(Time.unscaledTime < session.Deadline))
			{
				session.Unavailable += session.Requested.Count + session.Granted.Count;
				_session = null;
				Execute(session);
			}
		}

		internal static bool OnStackResponse(Container chest, bool granted)
		{
			Session session = _session;
			if (session == null || !session.Requested.TryGetValue(chest, out var value))
			{
				return false;
			}
			session.Requested.Remove(chest);
			if (granted)
			{
				session.Granted[chest] = value;
			}
			else
			{
				session.Unavailable++;
			}
			return true;
		}

		private static List<Target> FindTargets(Player player, long playerId, out int inUse)
		{
			//IL_000f: 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)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			inUse = 0;
			List<Target> list = new List<Target>();
			Vector3 position = ((Component)player).transform.position;
			float value = Plugin.Radius.Value;
			Chests.RemoveWhere((Container c) => !Object.op_Implicit((Object)(object)c));
			foreach (Container chest in Chests)
			{
				if (!((Component)chest).gameObject.activeInHierarchy)
				{
					continue;
				}
				float num = Vector3.Distance(position, ((Component)chest).transform.position);
				if (num > value || !FilterStore.Eligible(chest))
				{
					continue;
				}
				ZNetView val = FilterStore.NetView(chest);
				if (!Object.op_Implicit((Object)(object)val) || !val.IsValid())
				{
					continue;
				}
				ChestFilter chestFilter = FilterStore.Load(chest);
				if (!chestFilter.IsEmpty && CanAccess(chest, playerId))
				{
					if (!val.IsOwner() && val.GetZDO().GetInt(ZDOVars.s_inUse, 0) == 1)
					{
						inUse++;
						continue;
					}
					list.Add(new Target
					{
						Chest = chest,
						Distance = num,
						Filter = chestFilter
					});
				}
			}
			return list;
		}

		private static bool CanAccess(Container chest, long playerId)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: 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_000e: 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_002f: Invalid comparison between Unknown and I4
			if (chest.m_checkGuardStone && !PrivateArea.CheckAccess(((Component)chest).transform.position, 0f, false, false))
			{
				return false;
			}
			PrivacySetting privacy = chest.m_privacy;
			if ((int)privacy != 0)
			{
				if ((int)privacy == 2)
				{
					return true;
				}
				return false;
			}
			Piece component = ((Component)chest).GetComponent<Piece>();
			if (Object.op_Implicit((Object)(object)component))
			{
				return component.GetCreator() == playerId;
			}
			return false;
		}

		private static List<ItemData> Candidates(Player player)
		{
			Inventory inventory = ((Humanoid)player).GetInventory();
			int num = ExtraSlotsCompat.PlayerRows(inventory);
			InventoryGui instance = InventoryGui.instance;
			ItemData val = (Object.op_Implicit((Object)(object)instance) ? GameAccess.DragItem.Invoke(instance) : null);
			ItemData val2 = (Object.op_Implicit((Object)(object)instance) ? GameAccess.SplitItem.Invoke(instance) : null);
			List<ItemData> list = new List<ItemData>();
			foreach (ItemData item in inventory.GetAllItemsInGridOrder())
			{
				if (item != null && !item.m_equipped && !((Humanoid)player).IsItemEquiped(item) && !item.m_shared.m_questItem && item != val && item != val2 && item.m_gridPos.y < num && !ExtraSlotsCompat.IsItemInSlot(item) && !SlotLocks.Protects(item))
				{
					list.Add(item);
				}
			}
			return list;
		}

		private static void Execute(Session session)
		{
			//IL_0292: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer) || ((Character)localPlayer).IsDead())
			{
				return;
			}
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			List<Target> list = new List<Target>();
			foreach (Target item2 in session.Ready)
			{
				ZNetView val = FilterStore.NetView(item2.Chest);
				if (!Object.op_Implicit((Object)(object)item2.Chest) || !Object.op_Implicit((Object)(object)val) || !val.IsValid() || !val.IsOwner())
				{
					session.Unavailable++;
					continue;
				}
				GameAccess.Reload(item2.Chest);
				item2.Filter = FilterStore.Load(item2.Chest);
				list.Add(item2);
			}
			int num = 0;
			int num2 = 0;
			HashSet<Container> hashSet = new HashSet<Container>();
			foreach (ItemData item in Candidates(localPlayer))
			{
				List<Target> list2 = (from t in list
					select new
					{
						Target = t,
						Rank = t.Filter.Rank(item)
					} into t
					where t.Rank != -1
					orderby t.Rank, (!t.Target.Chest.GetInventory().ContainsItemByName(item.m_shared.m_name)) ? 1 : 0, t.Target.Distance
					select t.Target).ToList();
				if (list2.Count == 0)
				{
					continue;
				}
				foreach (Target item3 in list2)
				{
					int num3 = Move(inventory, item3.Chest.GetInventory(), item);
					if (num3 > 0)
					{
						num += num3;
						hashSet.Add(item3.Chest);
					}
					if (!inventory.ContainsItem(item))
					{
						break;
					}
				}
				if (inventory.ContainsItem(item))
				{
					num2 += item.m_stack;
				}
			}
			if (num > 0)
			{
				GameAccess.Changed(inventory);
				if (Object.op_Implicit((Object)(object)InventoryGui.instance))
				{
					InventoryGui.instance.m_moveItemEffects.Create(((Component)localPlayer).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
				}
			}
			((Character)localPlayer).Message((MessageType)2, Report(num, hashSet.Count, num2, session.Unavailable), 0, (Sprite)null, false);
		}

		private static int Move(Inventory from, Inventory to, ItemData item)
		{
			if (!HasRoom(to, item))
			{
				return 0;
			}
			int stack = item.m_stack;
			if (to.AddItem(item))
			{
				from.RemoveItem(item);
				return stack;
			}
			return stack - item.m_stack;
		}

		private static bool HasRoom(Inventory inventory, ItemData item)
		{
			if (inventory.HaveEmptySlot())
			{
				return true;
			}
			if (item.m_shared.m_maxStackSize <= 1)
			{
				return false;
			}
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (allItem.m_shared.m_name == item.m_shared.m_name && allItem.m_quality == item.m_quality && allItem.m_worldLevel == item.m_worldLevel && allItem.m_stack < allItem.m_shared.m_maxStackSize)
				{
					return true;
				}
			}
			return false;
		}

		private static string Report(int moved, int chests, int left, int unavailable)
		{
			List<string> list = new List<string>();
			if (moved > 0)
			{
				list.Add(Text.T($"Stashed {moved} item(s) in {chests} chest(s).", string.Format("Разложено {0} {1} по {2} {3}.", moved, Text.Plural(moved, "предмет", "предмета", "предметов"), chests, Text.Plural(chests, "сундуку", "сундукам", "сундукам"))));
			}
			if (left > 0)
			{
				list.Add(Text.T($"No room left for {left} item(s).", $"Не хватило места ещё для {left} шт."));
			}
			if (unavailable > 0)
			{
				list.Add(Text.T("Some chests are in use by other players.", "Часть сундуков занята другими игроками."));
			}
			if (list.Count == 0)
			{
				list.Add(Text.T("Nothing to stash.", "Нечего раскладывать."));
			}
			return string.Join("\n", list);
		}
	}
	[HarmonyPatch(typeof(Container), "Awake")]
	internal static class ContainerRegisterPatch
	{
		private static void Postfix(Container __instance)
		{
			if (__instance.GetInventory() != null)
			{
				Stasher.Register(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(Container), "RPC_StackResponse")]
	internal static class StackResponsePatch
	{
		[HarmonyPriority(800)]
		private static bool Prefix(Container __instance, bool granted)
		{
			return !Stasher.OnStackResponse(__instance, granted);
		}
	}
	internal sealed class StashUi : IDisposable
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static UnityAction <0>__Begin;
		}

		private readonly UiKit _kit = new UiKit();

		private readonly FilterPanel _panel;

		private Button _filterButton;

		private TMP_Text _filterLabel;

		private Button _stashButton;

		private TMP_Text _stashLabel;

		private string _stashTextKey;

		internal bool PanelOpen => _panel.IsOpen;

		internal StashUi()
		{
			_panel = new FilterPanel(_kit);
		}

		internal void Tick()
		{
			InventoryGui instance = InventoryGui.instance;
			if (Object.op_Implicit((Object)(object)instance) && (!Object.op_Implicit((Object)(object)_filterButton) || !Object.op_Implicit((Object)(object)_stashButton)))
			{
				_kit.Capture(instance);
				if (!Object.op_Implicit((Object)(object)_filterButton) && Object.op_Implicit((Object)(object)instance.m_container))
				{
					CreateFilterButton(instance);
				}
				if (!Object.op_Implicit((Object)(object)_stashButton) && Object.op_Implicit((Object)(object)instance.m_player))
				{
					CreateStashButton(instance);
				}
			}
			bool value = Plugin.Enabled.Value;
			if (Object.op_Implicit((Object)(object)_filterButton))
			{
				Container chest = GameAccess.OpenedChest();
				bool flag = value && FilterStore.Eligible(chest);
				if (((Component)_filterButton).gameObject.activeSelf != flag)
				{
					((Component)_filterButton).gameObject.SetActive(flag);
				}
				if (flag)
				{
					int count = FilterStore.Load(chest).Count;
					string text = Text.T("Filter", "Фильтр") + ((count > 0) ? (" (" + count + ")") : "");
					if (_filterLabel.text != text)
					{
						_filterLabel.text = text;
					}
				}
			}
			if (Object.op_Implicit((Object)(object)_stashButton))
			{
				bool flag2 = value && Plugin.InventoryButton.Value;
				if (((Component)_stashButton).gameObject.activeSelf != flag2)
				{
					((Component)_stashButton).gameObject.SetActive(flag2);
				}
				if (flag2)
				{
					UpdateStashTexts();
				}
			}
			_panel.Tick();
		}

		internal void ClosePanel()
		{
			_panel.Close();
		}

		public void Dispose()
		{
			_panel.Close();
			if (Object.op_Implicit((Object)(object)_filterButton))
			{
				Object.Destroy((Object)(object)((Component)_filterButton).gameObject);
			}
			if (Object.op_Implicit((Object)(object)_stashButton))
			{
				Object.Destroy((Object)(object)((Component)_stashButton).gameObject);
			}
		}

		private void CreateFilterButton(InventoryGui gui)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			//IL_0057: 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_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: 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)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			_filterButton = _kit.AddButton((Transform)(object)gui.m_container, "", 0f, 0f, 140f, 36f, (UnityAction)delegate
			{
				_panel.Open(GameAccess.OpenedChest());
			});
			((Object)_filterButton).name = "AutoStashFilterButton";
			RectTransform val = (RectTransform)((Component)_filterButton).transform;
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(1f, 0f);
			val.anchorMax = val2;
			val.anchorMin = val2;
			val.pivot = Vector2.one;
			val.anchoredPosition = new Vector2(-8f, -6f);
			_filterLabel = ((Component)_filterButton).GetComponentInChildren<TMP_Text>();
		}

		private void CreateStashButton(InventoryGui gui)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: 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_0041: Expected O, but got Unknown
			UiKit kit = _kit;
			RectTransform player = gui.m_player;
			object obj = <>O.<0>__Begin;
			if (obj == null)
			{
				UnityAction val = Stasher.Begin;
				<>O.<0>__Begin = val;
				obj = (object)val;
			}
			_stashButton = kit.AddButton((Transform)(object)player, "", 0f, 0f, 100f, 36f, (UnityAction)obj);
			((Object)_stashButton).name = "AutoStashButton";
			RectTransform val2 = (RectTransform)((Component)_stashButton).transform;
			Vector2 val3 = default(Vector2);
			((Vector2)(ref val3))..ctor(1f, 0.5f);
			val2.anchorMax = val3;
			val2.anchorMin = val3;
			val2.pivot = new Vector2(0f, 0.5f);
			val2.anchoredPosition = new Vector2(-8f, -6f);
			_stashLabel = ((Component)_stashButton).GetComponentInChildren<TMP_Text>();
			_stashTextKey = null;
		}

		private void UpdateStashTexts()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			string text = Plugin.StashKeyName();
			string text2 = Plugin.KeyName(Plugin.LockModifier.Value);
			float value = Plugin.Radius.Value;
			string text3 = Text.Russian + "|" + text + "|" + text2 + "|" + value + "|" + Object.op_Implicit((Object)(object)_kit.TooltipPrefab);
			if (!(text3 == _stashTextKey))
			{
				_stashTextKey = text3;
				_stashLabel.text = Text.T("Stash", "Разложить") + " (" + text + ")";
				_kit.AddTooltip(((Component)_stashButton).gameObject, Text.T("Stash to chests", "Разложить по сундукам"), Text.T($"Moves items into chests within {value:0} m whose filter accepts them. Key: {text}.\n{text2}+click a slot to lock it: locked slots are never stashed.", $"Переносит вещи в сундуки в радиусе {value:0} м, если их фильтр принимает эти вещи. Клавиша: {text}.\n{text2}+клик по слоту блокирует его: вещи из заблокированных слотов не раскладываются."));
			}
		}
	}
	internal sealed class UiKit
	{
		internal static readonly Color TextColor = new Color(1f, 0.85f, 0.57f);

		internal TMP_FontAsset Font;

		internal Sprite ButtonSprite;

		internal Type ButtonType = (Type)1;

		internal Color ButtonColor = new Color(0.29f, 0.2f, 0.13f);

		internal Sprite PanelSprite;

		internal Type PanelType = (Type)1;

		internal Color PanelColor = new Color(0.16f, 0.11f, 0.08f, 0.97f);

		internal GameObject TooltipPrefab;

		internal void Capture(InventoryGui gui)
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)gui))
			{
				return;
			}
			if (Object.op_Implicit((Object)(object)gui.m_containerName) && Object.op_Implicit((Object)(object)gui.m_containerName.font))
			{
				Font = gui.m_containerName.font;
			}
			Image val = (Object.op_Implicit((Object)(object)gui.m_takeAllButton) ? ((Selectable)gui.m_takeAllButton).image : null);
			if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.sprite))
			{
				ButtonSprite = val.sprite;
				ButtonType = val.type;
				ButtonColor = ((Graphic)val).color;
			}
			Image val2 = (Object.op_Implicit((Object)(object)gui.m_container) ? ((Component)gui.m_container).GetComponent<Image>() : null);
			if (Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val2.sprite))
			{
				PanelSprite = val2.sprite;
				PanelType = val2.type;
				PanelColor = ((Graphic)val2).color;
			}
			if (!Object.op_Implicit((Object)(object)TooltipPrefab) && Object.op_Implicit((Object)(object)gui.m_playerGrid) && Object.op_Implicit((Object)(object)gui.m_playerGrid.m_elementPrefab))
			{
				InventoryElement component = gui.m_playerGrid.m_elementPrefab.GetComponent<InventoryElement>();
				if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.m_tooltip) && Object.op_Implicit((Object)(object)component.m_tooltip.m_tooltipPrefab))
				{
					TooltipPrefab = component.m_tooltip.m_tooltipPrefab;
				}
			}
			if (Object.op_Implicit((Object)(object)TooltipPrefab))
			{
				return;
			}
			UITooltip[] componentsInChildren = ((Component)gui).GetComponentsInChildren<UITooltip>(true);
			foreach (UITooltip val3 in componentsInChildren)
			{
				if (Object.op_Implicit((Object)(object)val3.m_tooltipPrefab))
				{
					TooltipPrefab = val3.m_tooltipPrefab;
					break;
				}
			}
		}

		internal static RectTransform AddRect(string name, Transform parent, float x, float y, float width, float height)
		{
			//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_002b: 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_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: 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_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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_0052: 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_005c: 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)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(parent, false);
			RectTransform val2 = (RectTransform)val.transform;
			Vector2 val3 = default(Vector2);
			((Vector2)(ref val3))..ctor(0f, 1f);
			val2.pivot = val3;
			Vector2 anchorMin = (val2.anchorMax = val3);
			val2.anchorMin = anchorMin;
			val2.anchoredPosition = new Vector2(x, 0f - y);
			val2.sizeDelta = new Vector2(width, height);
			return val2;
		}

		internal static Image AddImage(string name, Transform parent, Color color)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			Image obj = ((Component)AddRect(name, parent, 0f, 0f, 0f, 0f)).gameObject.AddComponent<Image>();
			((Graphic)obj).color = color;
			return obj;
		}

		internal static void Stretch(RectTransform rect, float inset = 0f)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: 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_003d: Unknown result type (might be due to invalid IL or missing references)
			rect.anchorMin = Vector2.zero;
			rect.anchorMax = Vector2.one;
			rect.pivot = new Vector2(0.5f, 0.5f);
			rect.offsetMin = new Vector2(inset, inset);
			rect.offsetMax = new Vector2(0f - inset, 0f - inset);
		}

		internal TMP_Text AddText(Transform parent, string value, float x, float y, float width, float height, float size)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			TextMeshProUGUI val = ((Component)AddRect("Text", parent, x, y, width, height)).gameObject.AddComponent<TextMeshProUGUI>();
			if (Object.op_Implicit((Object)(object)Font))
			{
				((TMP_Text)val).font = Font;
			}
			((TMP_Text)val).text = value;
			((TMP_Text)val).fontSize = size;
			((Graphic)val).color = TextColor;
			((TMP_Text)val).richText = false;
			((Graphic)val).raycastTarget = false;
			((TMP_Text)val).alignment = (TextAlignmentOptions)4097;
			((TMP_Text)val).overflowMode = (TextOverflowModes)1;
			return (TMP_Text)(object)val;
		}

		internal Button AddButton(Transform parent, string label, float x, float y, float width, float height, UnityAction action)
		{
			//IL_002d: 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)
			RectTransform val = AddRect("Button", parent, x, y, width, height);
			Image val2 = ((Component)val).gameObject.AddComponent<Image>();
			val2.sprite = ButtonSprite;
			val2.type = ButtonType;
			((Graphic)val2).color = ButtonColor;
			Button obj = ((Component)val).gameObject.AddComponent<Button>();
			((Selectable)obj).targetGraphic = (Graphic)(object)val2;
			((UnityEvent)obj.onClick).AddListener(action);
			TMP_Text obj2 = AddText((Transform)(object)val, label, 6f, 0f, width - 12f, height, 18f);
			obj2.alignment = (TextAlignmentOptions)514;
			obj2.enableAutoSizing = true;
			obj2.fontSizeMin = 11f;
			obj2.fontSizeMax = 18f;
			return obj;
		}

		internal TMP_InputField AddInput(Transform parent, string placeholder, float x, float y, float width, float height, int limit)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = AddRect("Input", parent, x, y, width, height);
			Image val2 = ((Component)val).gameObject.AddComponent<Image>();
			((Graphic)val2).color = new Color(0.08f, 0.06f, 0.04f);
			TMP_InputField obj = ((Component)val).gameObject.AddComponent<TMP_InputField>();
			((Selectable)obj).targetGraphic = (Graphic)(object)val2;
			obj.characterLimit = limit;
			obj.lineType = (LineType)0;
			RectTransform val3 = AddRect("Viewport", (Transform)(object)val, 8f, 0f, width - 16f, height);
			((Component)val3).gameObject.AddComponent<RectMask2D>();
			TMP_Text val4 = AddText((Transform)(object)val3, "", 0f, 0f, width - 16f, height, 18f);
			val4.overflowMode = (TextOverflowModes)0;
			TMP_Text val5 = AddText((Transform)(object)val3, placeholder, 0f, 0f, width - 16f, height, 18f);
			((Graphic)val5).color = Color.gray;
			obj.textViewport = val3;
			obj.textComponent = val4;
			obj.placeholder = (Graphic)(object)val5;
			return obj;
		}

		internal void AddTooltip(GameObject target, string topic, string text)
		{
			if (Object.op_Implicit((Object)(object)TooltipPrefab))
			{
				UITooltip val = target.GetComponent<UITooltip>();
				if (!Object.op_Implicit((Object)(object)val))
				{
					val = target.AddComponent<UITooltip>();
				}
				val.m_tooltipPrefab = TooltipPrefab;
				val.m_topic = topic;
				val.m_text = text;
			}
		}
	}
	internal sealed class HoverRelay : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler
	{
		internal Action Entered;

		internal Action Exited;

		public void OnPointerEnter(PointerEventData eventData)
		{
			Entered?.Invoke();
		}

		public void OnPointerExit(PointerEventData eventData)
		{
			Exited?.Invoke();
		}
	}
}