Decompiled source of HexQuickStackStorage v1.4.4

Plugins/HexQuickStackStorage.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using HexQuickStackStorage.Components;
using HexQuickStackStorage.Services;
using HexQuickStackStorage.UI;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
using ServerSync;
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: AssemblyTitle("HexQuickStackStorage")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("HexQuickStackStorage")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("dfffd921-4f13-41b7-9dd6-fed57ea5fb5c")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace HexQuickStackStorage
{
	internal enum ContainerAccessModeEnum
	{
		CharacterOwned,
		Accessible
	}
	[BepInPlugin("com.hex.quickstackstorage", "HexQuickStackStorage", "1.4.4")]
	public class Plugin : BaseUnityPlugin
	{
		internal const string PluginGuid = "com.hex.quickstackstorage";

		private const string PluginName = "HexQuickStackStorage";

		private const string PluginVersion = "1.4.4";

		private static readonly ConfigSync ConfigSync = new ConfigSync("com.hex.quickstackstorage")
		{
			DisplayName = "HexQuickStackStorage",
			CurrentVersion = "1.4.4",
			MinimumRequiredVersion = "1.4.4"
		};

		private const KeyCode DefaultTrashModifierKey = (KeyCode)304;

		private const KeyCode DefaultFavoriteModifierKey = (KeyCode)306;

		private ConfigEntry<float> _searchRadius;

		private ConfigEntry<KeyboardShortcut> _quickStackShortcut;

		private ConfigEntry<KeyCode> _trashModifierKey;

		private ConfigEntry<KeyCode> _favoriteModifierKey;

		private ConfigEntry<bool> _enableChestAutoSorting;

		private ConfigEntry<bool> _enableAutoStoreTrophies;

		private ConfigEntry<ContainerAccessModeEnum> _containerAccessMode;

		private ConfigEntry<bool> _enableDeleteConfirmation;

		private ConfigEntry<bool> _lockConfiguration;

		private ConfigEntry<bool> _enableTrashFeature;

		private Harmony _harmonyInstance;

		private bool _isValidatingModifierKeys;

		private bool _modifierValidationMessagePending;

		internal static Plugin Instance { get; private set; }

		internal static ManualLogSource Log { get; private set; }

		internal static float SearchRadius
		{
			get
			{
				if (Instance?._searchRadius == null)
				{
					return 25f;
				}
				return Instance._searchRadius.Value;
			}
		}

		internal static KeyboardShortcut QuickStackShortcut
		{
			get
			{
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				if (Instance?._quickStackShortcut == null)
				{
					return new KeyboardShortcut((KeyCode)112, Array.Empty<KeyCode>());
				}
				return Instance._quickStackShortcut.Value;
			}
		}

		internal static KeyCode TrashModifierKey
		{
			get
			{
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				if (Instance?._trashModifierKey == null)
				{
					return (KeyCode)304;
				}
				return Instance._trashModifierKey.Value;
			}
		}

		internal static KeyCode FavoriteModifierKey
		{
			get
			{
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				if (Instance?._favoriteModifierKey == null)
				{
					return (KeyCode)306;
				}
				return Instance._favoriteModifierKey.Value;
			}
		}

		internal static bool EnableChestAutoSorting
		{
			get
			{
				if (Instance?._enableChestAutoSorting != null)
				{
					return Instance._enableChestAutoSorting.Value;
				}
				return false;
			}
		}

		internal static bool EnableAutoStoreTrophies
		{
			get
			{
				if (Instance?._enableAutoStoreTrophies != null)
				{
					return Instance._enableAutoStoreTrophies.Value;
				}
				return false;
			}
		}

		internal static ContainerAccessModeEnum ContainerAccessMode
		{
			get
			{
				if (Instance?._containerAccessMode == null)
				{
					return ContainerAccessModeEnum.CharacterOwned;
				}
				return Instance._containerAccessMode.Value;
			}
		}

		internal static bool EnableDeleteConfirmation
		{
			get
			{
				if (Instance?._enableDeleteConfirmation != null)
				{
					return Instance._enableDeleteConfirmation.Value;
				}
				return false;
			}
		}

		internal static bool EnableTrashFeature
		{
			get
			{
				if (Instance?._enableTrashFeature != null)
				{
					return Instance._enableTrashFeature.Value;
				}
				return false;
			}
		}

		private void Awake()
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			_lockConfiguration = ((BaseUnityPlugin)this).Config.Bind<bool>("Server", "LockConfiguration", false, "Locks synchronized configuration settings to the server's values.");
			ConfigSync.AddLockingConfigEntry<bool>(_lockConfiguration);
			_searchRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Chests", "SearchRadius", 25f, new ConfigDescription("The radius in which to search for nearby containers when quick stacking.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 150f), Array.Empty<object>()));
			ConfigSync.AddConfigEntry<float>(_searchRadius);
			_quickStackShortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Chests", "QuickStackShortcut", new KeyboardShortcut((KeyCode)112, Array.Empty<KeyCode>()), "Keyboard shortcut used to quick stack nearby containers.");
			_trashModifierKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Inventory", "TrashModifierKey", (KeyCode)304, "Modifier key held while right-clicking an item to mark or unmark it as trash.");
			_favoriteModifierKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Inventory", "FavoriteModifierKey", (KeyCode)306, "Modifier key held while right-clicking an item to favorite or unfavorite it.");
			_enableChestAutoSorting = ((BaseUnityPlugin)this).Config.Bind<bool>("Chests", "EnableChestAutoSorting", false, "Automatically sort a chest when it is opened.");
			ConfigSync.AddConfigEntry<bool>(_enableChestAutoSorting);
			_enableAutoStoreTrophies = ((BaseUnityPlugin)this).Config.Bind<bool>("Chests", "EnableAutoStoreTrophies", false, "Automatically store trophies when quick stacking into containers that already contain any trophy.");
			ConfigSync.AddConfigEntry<bool>(_enableAutoStoreTrophies);
			_containerAccessMode = ((BaseUnityPlugin)this).Config.Bind<ContainerAccessModeEnum>("Chests", "ContainerAccessMode", ContainerAccessModeEnum.CharacterOwned, "Controls which containers Quick Stack can use. CharacterOwned only uses containers created by the current character. Accessible allows any public container the character can access.");
			ConfigSync.AddConfigEntry<ContainerAccessModeEnum>(_containerAccessMode);
			_enableDeleteConfirmation = ((BaseUnityPlugin)this).Config.Bind<bool>("Inventory", "EnableDeleteConfirmation", true, "Enable a confirmation dialog when deleting items marked as trash.");
			_enableTrashFeature = ((BaseUnityPlugin)this).Config.Bind<bool>("Inventory", "EnableTrashFeature", true, "Enable the trash feature, allowing items to be marked as trash and deleted. If disabled the trash tab on the player inventory will be removed.. Requires game restart.");
			_trashModifierKey.SettingChanged += OnModifierKeyChanged;
			_favoriteModifierKey.SettingChanged += OnModifierKeyChanged;
			ValidateModifierKeys();
			TrashService.Initialize();
			FavoriteService.Initialize();
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			_harmonyInstance = new Harmony("com.hex.quickstackstorage");
			_harmonyInstance.PatchAll(executingAssembly);
			Log.LogInfo((object)"HexQuickStackStorage v1.4.4 loaded.");
		}

		private void Update()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				if (_modifierValidationMessagePending)
				{
					ShowModifierValidationMessage(localPlayer);
				}
				if (IsShortcutDown(_quickStackShortcut.Value) && !Console.IsVisible() && !TextInput.IsVisible() && !Menu.IsVisible() && !((Object)(object)InventoryUiController.GetCurrentContainer() != (Object)null))
				{
					QuickStackService.QuickStack(localPlayer);
				}
			}
		}

		internal static void SetDeleteConfirmationEnabled(bool enabled)
		{
			if (Instance?._enableDeleteConfirmation != null)
			{
				Instance._enableDeleteConfirmation.Value = enabled;
			}
		}

		private void OnDestroy()
		{
			if (_trashModifierKey != null)
			{
				_trashModifierKey.SettingChanged -= OnModifierKeyChanged;
			}
			if (_favoriteModifierKey != null)
			{
				_favoriteModifierKey.SettingChanged -= OnModifierKeyChanged;
			}
			Harmony harmonyInstance = _harmonyInstance;
			if (harmonyInstance != null)
			{
				harmonyInstance.UnpatchSelf();
			}
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogInfo((object)"HexQuickStackStorage v1.4.4 unloaded.");
			}
			Log = null;
			Instance = null;
		}

		private void OnModifierKeyChanged(object sender, EventArgs e)
		{
			ValidateModifierKeys();
		}

		private void ValidateModifierKeys()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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_003f: Invalid comparison between Unknown and I4
			if (!_isValidatingModifierKeys && _trashModifierKey.Value == _favoriteModifierKey.Value)
			{
				_isValidatingModifierKeys = true;
				_favoriteModifierKey.Value = (KeyCode)(((int)_trashModifierKey.Value == 306) ? 304 : 306);
				_isValidatingModifierKeys = false;
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null)
				{
					_modifierValidationMessagePending = true;
				}
				else
				{
					ShowModifierValidationMessage(localPlayer);
				}
			}
		}

		private void ShowModifierValidationMessage(Player player)
		{
			((Character)player).Message((MessageType)2, "Trash and Favorite modifier keys cannot be the same. Favorite modifier has been reset.", 0, (Sprite)null, false);
			_modifierValidationMessagePending = false;
		}

		private static bool IsShortcutDown(KeyboardShortcut shortcut)
		{
			//IL_0002: 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)
			if (!ZInput.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey, true))
			{
				return false;
			}
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers)
			{
				if (!ZInput.GetKey(modifier, true))
				{
					return false;
				}
			}
			return true;
		}
	}
	internal static class ContainerService
	{
		private static readonly MethodInfo CheckAccessMethod = AccessTools.Method(typeof(Container), "CheckAccess", (Type[])null, (Type[])null);

		private static readonly FieldInfo PieceField = AccessTools.Field(typeof(Container), "m_piece");

		internal static List<Container> GetNearbyContainers(Player player)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			List<Container> list = new List<Container>();
			if ((Object)(object)player == (Object)null || (Object)(object)Game.instance == (Object)null)
			{
				return list;
			}
			Collider[] array = Physics.OverlapSphere(((Component)player).transform.position, Plugin.SearchRadius);
			HashSet<Container> hashSet = new HashSet<Container>();
			Collider[] array2 = array;
			foreach (Collider val in array2)
			{
				if (!((Object)(object)val == (Object)null))
				{
					Container componentInParent = ((Component)val).GetComponentInParent<Container>();
					if (!((Object)(object)componentInParent == (Object)null) && hashSet.Add(componentInParent) && CanUseContainer(componentInParent))
					{
						list.Add(componentInParent);
					}
				}
			}
			return list;
		}

		internal static bool CanUseContainer(Container container)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)container == (Object)null || (Object)(object)Game.instance == (Object)null)
			{
				return false;
			}
			PlayerProfile playerProfile = Game.instance.GetPlayerProfile();
			if (playerProfile == null)
			{
				return false;
			}
			if (container.m_checkGuardStone && !PrivateArea.CheckAccess(((Component)container).transform.position, 0f, true, false))
			{
				return false;
			}
			long playerID = playerProfile.GetPlayerID();
			switch (Plugin.ContainerAccessMode)
			{
			case ContainerAccessModeEnum.CharacterOwned:
				return WasCreatedByPlayer(container, playerID);
			case ContainerAccessModeEnum.Accessible:
				if (!IsWorldGeneratedChest(container))
				{
					return CheckAccess(container, playerID);
				}
				return false;
			default:
				return false;
			}
		}

		internal static bool WasCreatedByPlayer(Container container, long playerId)
		{
			if ((Object)(object)container == (Object)null)
			{
				return false;
			}
			Piece componentInParent = ((Component)container).GetComponentInParent<Piece>();
			if ((Object)(object)componentInParent == (Object)null)
			{
				return false;
			}
			return componentInParent.GetCreator() == playerId;
		}

		private static bool IsWorldGeneratedChest(Container container)
		{
			if ((Object)(object)container == (Object)null || PieceField == null)
			{
				return false;
			}
			object? value = PieceField.GetValue(container);
			Piece val = (Piece)((value is Piece) ? value : null);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			return !val.IsPlacedByPlayer();
		}

		private static bool CheckAccess(Container container, long playerId)
		{
			if ((Object)(object)container == (Object)null || CheckAccessMethod == null)
			{
				return false;
			}
			return (bool)CheckAccessMethod.Invoke(container, new object[1] { playerId });
		}
	}
	internal static class FavoriteService
	{
		private const string FavoriteFileName = "HexQuickStackStorage.favorites.txt";

		private static readonly HashSet<string> FavoriteItemNames = new HashSet<string>(StringComparer.Ordinal);

		private static string FavoriteFilePath => Path.Combine(Paths.ConfigPath, "HexQuickStackStorage.favorites.txt");

		internal static void Initialize()
		{
			LoadFavoriteItems();
		}

		internal static bool IsFavorite(ItemData item)
		{
			if (item == null || item.m_shared == null)
			{
				return false;
			}
			return FavoriteItemNames.Contains(item.m_shared.m_name);
		}

		internal static void Favorite(ItemData item)
		{
			if (item != null && item.m_shared != null && FavoriteItemNames.Add(item.m_shared.m_name))
			{
				SaveFavoriteItems();
			}
		}

		internal static void Unfavorite(ItemData item)
		{
			if (item != null && item.m_shared != null && FavoriteItemNames.Remove(item.m_shared.m_name))
			{
				SaveFavoriteItems();
			}
		}

		private static void LoadFavoriteItems()
		{
			FavoriteItemNames.Clear();
			if (!File.Exists(FavoriteFilePath))
			{
				return;
			}
			string[] array = File.ReadAllLines(FavoriteFilePath);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (!string.IsNullOrEmpty(text))
				{
					FavoriteItemNames.Add(text);
				}
			}
		}

		private static void SaveFavoriteItems()
		{
			Directory.CreateDirectory(Paths.ConfigPath);
			List<string> list = new List<string>(FavoriteItemNames);
			list.Sort(StringComparer.Ordinal);
			File.WriteAllLines(FavoriteFilePath, list);
		}
	}
	internal static class InventorySortService
	{
		internal static void SortPlayerInventory()
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				Inventory inventory = ((Humanoid)localPlayer).GetInventory();
				if (inventory != null)
				{
					int vanillaInventoryHeight = GetVanillaInventoryHeight(localPlayer);
					Sort(inventory, vanillaInventoryHeight, isPlayerInventory: true);
				}
			}
		}

		internal static void SortContainer(Container container)
		{
			if (!((Object)(object)container == (Object)null))
			{
				Inventory inventory = container.GetInventory();
				if (inventory != null)
				{
					Sort(inventory, inventory.GetHeight(), isPlayerInventory: false);
				}
			}
		}

		private static void Sort(Inventory inventory, int validHeight, bool isPlayerInventory)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			List<ItemData> allItems = inventory.GetAllItems();
			if (allItems == null || allItems.Count <= 1)
			{
				return;
			}
			int width = inventory.GetWidth();
			if (width <= 0 || validHeight <= 0)
			{
				return;
			}
			List<ItemData> list = new List<ItemData>(allItems.Count);
			HashSet<(int, int)> hashSet = new HashSet<(int, int)>();
			foreach (ItemData item in allItems)
			{
				if (item != null && item.m_shared != null && IsPositionWithinBounds(item.m_gridPos, width, validHeight))
				{
					if (isPlayerInventory && item.m_equipped)
					{
						hashSet.Add((item.m_gridPos.x, item.m_gridPos.y));
					}
					else if (isPlayerInventory && ItemStateService.IsHotbarItem(item))
					{
						hashSet.Add((item.m_gridPos.x, item.m_gridPos.y));
					}
					else if (isPlayerInventory && FavoriteService.IsFavorite(item))
					{
						hashSet.Add((item.m_gridPos.x, item.m_gridPos.y));
					}
					else
					{
						list.Add(item);
					}
				}
			}
			list.Sort(CompareItems);
			ConsolidateStacks(inventory, list);
			list.Sort(CompareItems);
			int num = 0;
			for (int i = (isPlayerInventory ? 1 : 0); i < validHeight; i++)
			{
				if (num >= list.Count)
				{
					break;
				}
				for (int j = 0; j < width; j++)
				{
					if (num >= list.Count)
					{
						break;
					}
					if (!hashSet.Contains((j, i)))
					{
						list[num].m_gridPos = new Vector2i(j, i);
						num++;
					}
				}
			}
			InventoryOperationsService.NotifyChanged(inventory);
		}

		private static void ConsolidateStacks(Inventory inventory, List<ItemData> items)
		{
			for (int i = 0; i < items.Count; i++)
			{
				ItemData val = items[i];
				if (val == null || val.m_shared == null || val.m_shared.m_maxStackSize <= 1)
				{
					continue;
				}
				int num = i + 1;
				while (num < items.Count)
				{
					ItemData val2 = items[num];
					if (!CanStackTogether(val, val2))
					{
						num++;
						continue;
					}
					int num2 = val.m_shared.m_maxStackSize - val.m_stack;
					if (num2 <= 0)
					{
						break;
					}
					int num3 = Math.Min(num2, val2.m_stack);
					val.m_stack += num3;
					val2.m_stack -= num3;
					if (val2.m_stack <= 0)
					{
						inventory.RemoveItem(val2);
						items.RemoveAt(num);
					}
					else
					{
						num++;
					}
				}
			}
		}

		private static bool CanStackTogether(ItemData targetItem, ItemData sourceItem)
		{
			if (targetItem == null || sourceItem == null || targetItem.m_shared == null || sourceItem.m_shared == null)
			{
				return false;
			}
			if (targetItem == sourceItem)
			{
				return false;
			}
			if (targetItem.m_shared.m_name != sourceItem.m_shared.m_name)
			{
				return false;
			}
			if (targetItem.m_quality != sourceItem.m_quality)
			{
				return false;
			}
			if (targetItem.m_worldLevel != sourceItem.m_worldLevel)
			{
				return false;
			}
			return targetItem.m_stack < targetItem.m_shared.m_maxStackSize;
		}

		private static int GetVanillaInventoryHeight(Player player)
		{
			string s = default(string);
			if (player.TryGetUniqueKeyValue("invrows", ref s) && int.TryParse(s, out var result))
			{
				return Mathf.Clamp(result, 0, 9);
			}
			return 4;
		}

		private static bool IsPositionWithinBounds(Vector2i position, int width, int height)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: 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)
			if (position.x >= 0 && position.x < width && position.y >= 0)
			{
				return position.y < height;
			}
			return false;
		}

		private static int CompareItems(ItemData firstItem, ItemData secondItem)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			ref ItemType itemType = ref firstItem.m_shared.m_itemType;
			object target = secondItem.m_shared.m_itemType;
			int num = ((Enum)Unsafe.As<ItemType, ItemType>(ref itemType)/*cast due to .constrained prefix*/).CompareTo(target);
			if (num != 0)
			{
				return num;
			}
			num = string.Compare(firstItem.m_shared.m_name, secondItem.m_shared.m_name, StringComparison.Ordinal);
			if (num != 0)
			{
				return num;
			}
			num = secondItem.m_quality.CompareTo(firstItem.m_quality);
			if (num != 0)
			{
				return num;
			}
			return secondItem.m_stack.CompareTo(firstItem.m_stack);
		}
	}
	internal static class ItemStateService
	{
		internal static void ToggleFavorite(Player player, ItemData item)
		{
			if (!((Object)(object)player == (Object)null) && item != null && item.m_shared != null)
			{
				if (FavoriteService.IsFavorite(item))
				{
					FavoriteService.Unfavorite(item);
					return;
				}
				TrashService.Unmark(item);
				FavoriteService.Favorite(item);
			}
		}

		internal static void ToggleTrash(Player player, ItemData item)
		{
			if (!((Object)(object)player == (Object)null) && item != null && item.m_shared != null && TrashService.IsVanillaInventoryItem(player, item))
			{
				if (IsHotbarItem(item))
				{
					((Character)player).Message((MessageType)2, "Hotbar items cannot be marked as trash.", 0, (Sprite)null, false);
					return;
				}
				if (item.m_equipped)
				{
					((Character)player).Message((MessageType)2, "Equipped items cannot be marked as trash.", 0, (Sprite)null, false);
					return;
				}
				if (TrashService.IsMarked(item))
				{
					TrashService.Unmark(item);
					return;
				}
				FavoriteService.Unfavorite(item);
				TrashService.Mark(item);
			}
		}

		internal static bool CanDelete(ItemData item)
		{
			if (item == null)
			{
				return false;
			}
			if (item.m_equipped)
			{
				return false;
			}
			if (IsHotbarItem(item))
			{
				return false;
			}
			if (FavoriteService.IsFavorite(item))
			{
				return false;
			}
			return true;
		}

		internal static bool IsHotbarItem(ItemData item)
		{
			if (item != null)
			{
				return item.m_gridPos.y == 0;
			}
			return false;
		}
	}
	internal static class QuickStackService
	{
		private const int DefaultVanillaInventoryRows = 4;

		private static readonly FieldInfo ContainerNViewField = typeof(Container).GetField("m_nview", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		internal static void QuickStack(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (inventory == null)
			{
				return;
			}
			int vanillaInventoryHeight = GetVanillaInventoryHeight(player);
			List<ItemData> quickStackableItems = GetQuickStackableItems(player, inventory, vanillaInventoryHeight);
			if (quickStackableItems.Count == 0)
			{
				return;
			}
			List<Container> nearbyContainers = ContainerService.GetNearbyContainers(player);
			bool flag = false;
			foreach (Container item in nearbyContainers)
			{
				if (QuickStackIntoContainer(item, quickStackableItems, inventory, allowInUse: false))
				{
					flag = true;
				}
				if (quickStackableItems.Count == 0)
				{
					break;
				}
			}
			if (flag)
			{
				((Character)player).Message((MessageType)1, "Items auto stacked", 0, (Sprite)null, false);
			}
		}

		internal static void QuickStack(Player player, Container container)
		{
			if ((Object)(object)player == (Object)null || (Object)(object)container == (Object)null)
			{
				return;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (inventory != null)
			{
				int vanillaInventoryHeight = GetVanillaInventoryHeight(player);
				List<ItemData> quickStackableItems = GetQuickStackableItems(player, inventory, vanillaInventoryHeight);
				if (quickStackableItems.Count != 0 && QuickStackIntoContainer(container, quickStackableItems, inventory, allowInUse: true))
				{
					((Character)player).Message((MessageType)1, "Items auto stacked", 0, (Sprite)null, false);
				}
			}
		}

		private static bool QuickStackIntoContainer(Container container, List<ItemData> quickStackableItems, Inventory playerInventory, bool allowInUse)
		{
			if ((Object)(object)container == (Object)null)
			{
				return false;
			}
			ZNetView containerNView = GetContainerNView(container);
			if ((Object)(object)containerNView == (Object)null || !containerNView.IsValid())
			{
				return false;
			}
			if (!allowInUse && IsContainerInUse(container, containerNView))
			{
				return false;
			}
			containerNView.ClaimOwnership();
			Inventory inventory = container.GetInventory();
			if (inventory == null)
			{
				return false;
			}
			bool flag = !allowInUse;
			if (flag)
			{
				SetContainerInUse(containerNView, isInUse: true);
			}
			try
			{
				return QuickStackItems(quickStackableItems, playerInventory, inventory);
			}
			finally
			{
				if (flag)
				{
					SetContainerInUse(containerNView, isInUse: false);
				}
			}
		}

		private static List<ItemData> GetQuickStackableItems(Player player, Inventory playerInventory, int vanillaHeight)
		{
			List<ItemData> list = new List<ItemData>();
			foreach (ItemData allItem in playerInventory.GetAllItems())
			{
				if (allItem != null && allItem.m_gridPos.y >= 0 && allItem.m_gridPos.y < vanillaHeight && !ItemStateService.IsHotbarItem(allItem) && !((Humanoid)player).IsItemEquiped(allItem) && !FavoriteService.IsFavorite(allItem) && (!IsTrophy(allItem) || Plugin.EnableAutoStoreTrophies))
				{
					list.Add(allItem);
				}
			}
			return list;
		}

		private static bool QuickStackItems(List<ItemData> quickStackableItems, Inventory playerInventory, Inventory containerInventory)
		{
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			bool flag = false;
			for (int num = quickStackableItems.Count - 1; num >= 0; num--)
			{
				ItemData val = quickStackableItems[num];
				if (val == null)
				{
					quickStackableItems.RemoveAt(num);
				}
				else
				{
					bool num2 = IsTrophy(val);
					bool flag2 = containerInventory.ContainsItemByName(val.m_shared.m_name);
					bool flag3 = num2 && containerInventory.GetAllItems().Exists(IsTrophy);
					if (flag2 || flag3)
					{
						while (val.m_stack > 0)
						{
							ItemData val2 = InventoryOperationsService.FindFreeStackItem(containerInventory, val);
							if (val2 == null)
							{
								break;
							}
							int num3 = val2.m_shared.m_maxStackSize - val2.m_stack;
							int num4 = Mathf.Min(val.m_stack, num3);
							val2.m_stack += num4;
							val.m_stack -= num4;
							flag = true;
						}
						while (val.m_stack > 0)
						{
							Vector2i val3 = InventoryOperationsService.FindEmptySlot(containerInventory, val);
							if (val3.x < 0)
							{
								break;
							}
							int num5 = Mathf.Min(val.m_stack, val.m_shared.m_maxStackSize);
							ItemData val4 = val.Clone();
							val4.m_stack = num5;
							val4.m_gridPos = val3;
							containerInventory.GetAllItems().Add(val4);
							val.m_stack -= num5;
							flag = true;
						}
						if (val.m_stack == 0)
						{
							playerInventory.RemoveItem(val);
							quickStackableItems.RemoveAt(num);
						}
					}
				}
			}
			if (flag)
			{
				InventoryOperationsService.NotifyChanged(playerInventory);
				InventoryOperationsService.NotifyChanged(containerInventory);
			}
			return flag;
		}

		private static ZNetView GetContainerNView(Container container)
		{
			if ((Object)(object)container == (Object)null || ContainerNViewField == null)
			{
				return null;
			}
			object? value = ContainerNViewField.GetValue(container);
			return (ZNetView)((value is ZNetView) ? value : null);
		}

		private static bool IsContainerInUse(Container container, ZNetView nview)
		{
			if (container.IsInUse() || ((Object)(object)container.m_wagon != (Object)null && container.m_wagon.InUse()))
			{
				return true;
			}
			ZDO zDO = nview.GetZDO();
			if (zDO == null)
			{
				return false;
			}
			return zDO.GetInt(ZDOVars.s_inUse, 0) == 1;
		}

		private static void SetContainerInUse(ZNetView nview, bool isInUse)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			ZDO zDO = nview.GetZDO();
			if (zDO != null)
			{
				zDO.Set(ZDOVars.s_inUse, isInUse ? 1 : 0, false);
				ZDOMan.instance.ForceSendZDO(ZNet.GetUID(), zDO.m_uid);
			}
		}

		private static int GetVanillaInventoryHeight(Player player)
		{
			string s = default(string);
			if (player.TryGetUniqueKeyValue("invrows", ref s) && int.TryParse(s, out var result))
			{
				return Mathf.Clamp(result, 0, 9);
			}
			return 4;
		}

		private static bool IsTrophy(ItemData item)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			if (item == null)
			{
				return false;
			}
			return (int)(item.m_shared?.m_itemType).GetValueOrDefault() == 13;
		}
	}
	internal static class TrashService
	{
		private const string JunkFileName = "HexQuickStackStorage.junk.txt";

		private static readonly HashSet<string> JunkItemNames = new HashSet<string>(StringComparer.Ordinal);

		private static readonly FieldInfo DragItemField = AccessTools.Field(typeof(InventoryGui), "m_dragItem");

		private static readonly FieldInfo DragInventoryField = AccessTools.Field(typeof(InventoryGui), "m_dragInventory");

		private static readonly FieldInfo DragAmountField = AccessTools.Field(typeof(InventoryGui), "m_dragAmount");

		private static readonly MethodInfo SetupDragItemMethod = AccessTools.Method(typeof(InventoryGui), "SetupDragItem", (Type[])null, (Type[])null);

		private static string JunkFilePath => Path.Combine(Paths.ConfigPath, "HexQuickStackStorage.junk.txt");

		internal static void Initialize()
		{
			LoadJunkItems();
		}

		internal static bool IsMarked(ItemData item)
		{
			if (item == null || item.m_shared == null)
			{
				return false;
			}
			return JunkItemNames.Contains(item.m_shared.m_name);
		}

		internal static void Mark(ItemData item)
		{
			if (item != null && item.m_shared != null && JunkItemNames.Add(item.m_shared.m_name))
			{
				SaveJunkItems();
			}
		}

		internal static void Unmark(ItemData item)
		{
			if (item != null && item.m_shared != null && JunkItemNames.Remove(item.m_shared.m_name))
			{
				SaveJunkItems();
			}
		}

		internal static void DeleteDraggedItem(InventoryGui inventoryGui, Player player)
		{
			if ((Object)(object)inventoryGui == (Object)null || (Object)(object)player == (Object)null)
			{
				return;
			}
			object? obj = DragItemField?.GetValue(inventoryGui);
			ItemData val = (ItemData)((obj is ItemData) ? obj : null);
			object? obj2 = DragInventoryField?.GetValue(inventoryGui);
			Inventory val2 = (Inventory)((obj2 is Inventory) ? obj2 : null);
			if (val == null || val2 == null)
			{
				return;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (val2 != inventory || !IsVanillaInventoryItem(player, val))
			{
				return;
			}
			if (!ItemStateService.CanDelete(val))
			{
				ShowProtectedItemMessage(player);
				return;
			}
			int num = Mathf.Min((!(DragAmountField != null)) ? 1 : ((int)DragAmountField.GetValue(inventoryGui)), val.m_stack);
			if (val2.RemoveItem(val, num))
			{
				SetupDragItemMethod?.Invoke(inventoryGui, new object[3] { null, null, 1 });
				ShowItemsDeletedMessage(player);
			}
		}

		internal static void DeleteMarkedItems(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (inventory == null)
			{
				return;
			}
			List<ItemData> list = new List<ItemData>(inventory.GetAllItems());
			bool flag = false;
			bool flag2 = false;
			foreach (ItemData item in list)
			{
				if (item != null && item.m_shared != null && IsMarked(item) && IsVanillaInventoryItem(player, item))
				{
					if (!ItemStateService.CanDelete(item))
					{
						flag = true;
					}
					else if (inventory.RemoveItem(item))
					{
						flag2 = true;
					}
				}
			}
			if (flag)
			{
				ShowProtectedItemMessage(player);
			}
			if (flag2)
			{
				ShowItemsDeletedMessage(player);
			}
		}

		internal static bool IsVanillaInventoryItem(Player player, ItemData item)
		{
			if ((Object)(object)player == (Object)null || item == null)
			{
				return false;
			}
			int vanillaInventoryHeight = GetVanillaInventoryHeight(player);
			if (item.m_gridPos.y >= 0)
			{
				return item.m_gridPos.y < vanillaInventoryHeight;
			}
			return false;
		}

		private static int GetVanillaInventoryHeight(Player player)
		{
			string s = default(string);
			if (player.TryGetUniqueKeyValue("invrows", ref s) && int.TryParse(s, out var result))
			{
				return Mathf.Clamp(result, 0, 9);
			}
			return 4;
		}

		private static void LoadJunkItems()
		{
			JunkItemNames.Clear();
			if (!File.Exists(JunkFilePath))
			{
				return;
			}
			string[] array = File.ReadAllLines(JunkFilePath);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (!string.IsNullOrEmpty(text))
				{
					JunkItemNames.Add(text);
				}
			}
		}

		private static void SaveJunkItems()
		{
			Directory.CreateDirectory(Paths.ConfigPath);
			List<string> list = new List<string>(JunkItemNames);
			list.Sort(StringComparer.Ordinal);
			File.WriteAllLines(JunkFilePath, list);
		}

		private static void ShowItemsDeletedMessage(Player player)
		{
			((Character)player).Message((MessageType)2, "Items Deleted", 0, (Sprite)null, false);
		}

		private static void ShowProtectedItemMessage(Player player)
		{
			((Character)player).Message((MessageType)2, "Can't delete equipped, hotbar, or favorited items.", 0, (Sprite)null, false);
		}
	}
}
namespace HexQuickStackStorage.Components
{
	internal sealed class QuickStackTooltipComponent : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler
	{
		private const string TooltipText = "Quick Stack is unavailable while a container is open.";

		private GameObject _tooltipObject;

		private bool _tooltipEnabled;

		internal bool TooltipEnabled
		{
			get
			{
				return _tooltipEnabled;
			}
			set
			{
				_tooltipEnabled = value;
				if (!_tooltipEnabled)
				{
					HideTooltip();
				}
			}
		}

		public void OnPointerEnter(PointerEventData eventData)
		{
			if (TooltipEnabled)
			{
				ShowTooltip();
			}
		}

		public void OnPointerExit(PointerEventData eventData)
		{
			HideTooltip();
		}

		private void ShowTooltip()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: 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_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_tooltipObject != (Object)null))
			{
				GameObject val = new GameObject("com.hex.quickstackstorage.QuickStackTooltip", new Type[3]
				{
					typeof(RectTransform),
					typeof(CanvasRenderer),
					typeof(Image)
				});
				val.transform.SetParent(((Component)this).transform.parent, false);
				_tooltipObject = val;
				RectTransform component = val.GetComponent<RectTransform>();
				component.sizeDelta = new Vector2(360f, 40f);
				((Transform)component).position = ((Component)this).transform.position + new Vector3(0f, 45f, 0f);
				Image component2 = val.GetComponent<Image>();
				((Graphic)component2).color = new Color(0f, 0f, 0f, 0.9f);
				((Graphic)component2).raycastTarget = false;
				TMP_Text componentInChildren = ((Component)this).GetComponentInChildren<TMP_Text>(true);
				if ((Object)(object)componentInChildren == (Object)null)
				{
					Object.Destroy((Object)(object)val);
					_tooltipObject = null;
					return;
				}
				GameObject obj = Object.Instantiate<GameObject>(((Component)componentInChildren).gameObject, val.transform);
				((Object)obj).name = "com.hex.quickstackstorage.QuickStackTooltip.Text";
				RectTransform component3 = obj.GetComponent<RectTransform>();
				component3.anchorMin = Vector2.zero;
				component3.anchorMax = Vector2.one;
				component3.offsetMin = new Vector2(8f, 4f);
				component3.offsetMax = new Vector2(-8f, -4f);
				((Transform)component3).localScale = Vector3.one;
				TMP_Text component4 = obj.GetComponent<TMP_Text>();
				component4.text = "Quick Stack is unavailable while a container is open.";
				component4.fontSize = 16f;
				component4.fontStyle = (FontStyles)0;
				component4.alignment = (TextAlignmentOptions)514;
				((Graphic)component4).raycastTarget = false;
				component4.text = "Quick Stack is unavailable while a container is open.";
				component4.fontSize = 16f;
				component4.fontStyle = (FontStyles)0;
				component4.alignment = (TextAlignmentOptions)514;
				((Graphic)component4).raycastTarget = false;
			}
		}

		private void HideTooltip()
		{
			if (!((Object)(object)_tooltipObject == (Object)null))
			{
				Object.Destroy((Object)(object)_tooltipObject);
				_tooltipObject = null;
			}
		}

		private void OnDisable()
		{
			HideTooltip();
		}
	}
}
namespace HexQuickStackStorage.UI
{
	internal class DialogDragHandler : MonoBehaviour, IBeginDragHandler, IEventSystemHandler, IDragHandler
	{
		private RectTransform _target;

		private Vector2 _pointerOffset;

		internal void Initialize(RectTransform target)
		{
			_target = target;
		}

		public void OnBeginDrag(PointerEventData eventData)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: 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)
			if (!((Object)(object)_target == (Object)null))
			{
				Transform parent = ((Transform)_target).parent;
				RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null);
				Vector2 val2 = default(Vector2);
				if (!((Object)(object)val == (Object)null) && RectTransformUtility.ScreenPointToLocalPointInRectangle(val, eventData.position, eventData.pressEventCamera, ref val2))
				{
					_pointerOffset = _target.anchoredPosition - val2;
				}
			}
		}

		public void OnDrag(PointerEventData eventData)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: 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)
			if (!((Object)(object)_target == (Object)null))
			{
				Transform parent = ((Transform)_target).parent;
				RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null);
				Vector2 val2 = default(Vector2);
				if (!((Object)(object)val == (Object)null) && RectTransformUtility.ScreenPointToLocalPointInRectangle(val, eventData.position, eventData.pressEventCamera, ref val2))
				{
					_target.anchoredPosition = val2 + _pointerOffset;
				}
			}
		}
	}
	internal static class DialogUiController
	{
		private static GameObject _deleteConfirmationDialog;

		private static Toggle _dontShowAgainToggle;

		internal static void ShowDeleteConfirmation(InventoryGui inventoryGui, UnityAction onConfirm)
		{
			if ((Object)(object)inventoryGui == (Object)null)
			{
				Plugin.Log.LogWarning((object)"InventoryGui is null. Unable to show delete confirmation.");
				return;
			}
			if ((Object)(object)Menu.instance == (Object)null || (Object)(object)Menu.instance.m_logoutDialog == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Could not find Valheim logout confirmation dialog.");
				return;
			}
			if ((Object)(object)_deleteConfirmationDialog == (Object)null)
			{
				_deleteConfirmationDialog = Object.Instantiate<GameObject>(((Component)Menu.instance.m_logoutDialog).gameObject, ((Component)inventoryGui).transform);
				((Object)_deleteConfirmationDialog).name = "com.hex.quickstackstorage.DeleteConfirmation";
				ConfigureDeleteConfirmationDialog();
			}
			if ((Object)(object)_dontShowAgainToggle != (Object)null)
			{
				_dontShowAgainToggle.isOn = false;
			}
			ConfigureDeleteConfirmationActions(onConfirm);
			_deleteConfirmationDialog.SetActive(true);
			_deleteConfirmationDialog.transform.SetAsLastSibling();
		}

		private static void ConfigureDeleteConfirmationDialog()
		{
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Expected O, but got Unknown
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Expected O, but got Unknown
			if ((Object)(object)_deleteConfirmationDialog == (Object)null)
			{
				return;
			}
			Transform val = _deleteConfirmationDialog.transform.Find("dialog");
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Could not find dialog on delete confirmation.");
				return;
			}
			Transform obj = val.Find("Quit");
			TMP_Text val2 = ((obj != null) ? ((Component)obj).GetComponent<TMP_Text>() : null);
			Transform obj2 = val.Find("Button_yes");
			Button val3 = ((obj2 != null) ? ((Component)obj2).GetComponent<Button>() : null);
			Transform obj3 = val.Find("Button_no");
			Button val4 = ((obj3 != null) ? ((Component)obj3).GetComponent<Button>() : null);
			if ((Object)(object)val2 != (Object)null)
			{
				val2.text = "Delete items?";
			}
			if ((Object)(object)val3 != (Object)null)
			{
				val3.onClick = new ButtonClickedEvent();
			}
			if ((Object)(object)val4 != (Object)null)
			{
				val4.onClick = new ButtonClickedEvent();
				SetButtonText(((Component)val4).gameObject, "Cancel");
			}
			RectTransform val5 = (RectTransform)(object)((val is RectTransform) ? val : null);
			if ((Object)(object)val5 != (Object)null)
			{
				DialogDragHandler dialogDragHandler = ((Component)val).gameObject.GetComponent<DialogDragHandler>();
				if ((Object)(object)dialogDragHandler == (Object)null)
				{
					dialogDragHandler = ((Component)val).gameObject.AddComponent<DialogDragHandler>();
				}
				dialogDragHandler.Initialize(val5);
			}
			CreateDontShowAgainToggle(val, val2, val3, val4);
		}

		private static void ConfigureDeleteConfirmationActions(UnityAction onConfirm)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Expected O, but got Unknown
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Expected O, but got Unknown
			Transform val = _deleteConfirmationDialog.transform.Find("dialog");
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Transform obj = val.Find("Button_yes");
			Button val2 = ((obj != null) ? ((Component)obj).GetComponent<Button>() : null);
			Transform obj2 = val.Find("Button_no");
			Button val3 = ((obj2 != null) ? ((Component)obj2).GetComponent<Button>() : null);
			if ((Object)(object)val2 != (Object)null)
			{
				val2.onClick = new ButtonClickedEvent();
				((UnityEvent)val2.onClick).AddListener((UnityAction)delegate
				{
					if ((Object)(object)_dontShowAgainToggle != (Object)null && _dontShowAgainToggle.isOn)
					{
						Plugin.SetDeleteConfirmationEnabled(enabled: false);
					}
					HideDeleteConfirmation();
					UnityAction obj3 = onConfirm;
					if (obj3 != null)
					{
						obj3.Invoke();
					}
				});
			}
			if ((Object)(object)val3 != (Object)null)
			{
				val3.onClick = new ButtonClickedEvent();
				((UnityEvent)val3.onClick).AddListener(new UnityAction(HideDeleteConfirmation));
			}
		}

		private static void HideDeleteConfirmation()
		{
			if ((Object)(object)_deleteConfirmationDialog != (Object)null)
			{
				_deleteConfirmationDialog.SetActive(false);
			}
		}

		private static void SetButtonText(GameObject buttonObject, string text)
		{
			TMP_Text componentInChildren = buttonObject.GetComponentInChildren<TMP_Text>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.text = text;
				componentInChildren.alignment = (TextAlignmentOptions)514;
				return;
			}
			Text componentInChildren2 = buttonObject.GetComponentInChildren<Text>(true);
			if ((Object)(object)componentInChildren2 != (Object)null)
			{
				componentInChildren2.text = text;
				componentInChildren2.alignment = (TextAnchor)4;
			}
		}

		private static void CreateDontShowAgainToggle(Transform dialog, TMP_Text textTemplate, Button yesButton, Button cancelButton)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Expected O, but got Unknown
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_028a: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c6: 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_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0317: Unknown result type (might be due to invalid IL or missing references)
			//IL_0323: Unknown result type (might be due to invalid IL or missing references)
			//IL_0339: Unknown result type (might be due to invalid IL or missing references)
			//IL_0345: Unknown result type (might be due to invalid IL or missing references)
			//IL_035b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0367: Unknown result type (might be due to invalid IL or missing references)
			//IL_0373: 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_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_dontShowAgainToggle != (Object)null)
			{
				return;
			}
			if ((Object)(object)textTemplate == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Could not find Valheim text template for delete confirmation toggle.");
				return;
			}
			GameObject val = new GameObject("com.hex.quickstackstorage.DontShowAgainToggle", new Type[2]
			{
				typeof(RectTransform),
				typeof(Toggle)
			});
			val.transform.SetParent(dialog, false);
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0.5f, 0.5f);
			component.anchorMax = new Vector2(0.5f, 0.5f);
			component.pivot = new Vector2(0.5f, 0.5f);
			component.sizeDelta = new Vector2(290f, 30f);
			float num = -80f;
			Rect rect;
			if ((Object)(object)yesButton != (Object)null)
			{
				Transform transform = ((Component)yesButton).transform;
				RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
				if ((Object)(object)val2 != (Object)null)
				{
					float y = val2.anchoredPosition.y;
					rect = val2.rect;
					num = y - ((Rect)(ref rect)).height * 0.5f;
				}
			}
			else if ((Object)(object)cancelButton != (Object)null)
			{
				Transform transform2 = ((Component)cancelButton).transform;
				RectTransform val3 = (RectTransform)(object)((transform2 is RectTransform) ? transform2 : null);
				if ((Object)(object)val3 != (Object)null)
				{
					float y2 = val3.anchoredPosition.y;
					rect = val3.rect;
					num = y2 - ((Rect)(ref rect)).height * 0.5f;
				}
			}
			component.anchoredPosition = new Vector2(0f, num - 25f);
			_dontShowAgainToggle = val.GetComponent<Toggle>();
			_dontShowAgainToggle.isOn = false;
			GameObject val4 = new GameObject("com.hex.quickstackstorage.DontShowAgainToggle.CheckboxBackground", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val4.transform.SetParent(val.transform, false);
			RectTransform component2 = val4.GetComponent<RectTransform>();
			component2.anchorMin = new Vector2(0f, 0.5f);
			component2.anchorMax = new Vector2(0f, 0.5f);
			component2.pivot = new Vector2(0f, 0.5f);
			component2.anchoredPosition = Vector2.zero;
			component2.sizeDelta = new Vector2(20f, 20f);
			Image component3 = val4.GetComponent<Image>();
			((Graphic)component3).color = new Color(0.15f, 0.15f, 0.15f, 1f);
			GameObject val5 = new GameObject("com.hex.quickstackstorage.DontShowAgainToggle.Checkmark", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val5.transform.SetParent(val4.transform, false);
			RectTransform component4 = val5.GetComponent<RectTransform>();
			component4.anchorMin = Vector2.zero;
			component4.anchorMax = Vector2.one;
			component4.offsetMin = new Vector2(4f, 4f);
			component4.offsetMax = new Vector2(-4f, -4f);
			Image component5 = val5.GetComponent<Image>();
			((Graphic)component5).color = Color.white;
			((Selectable)_dontShowAgainToggle).targetGraphic = (Graphic)(object)component3;
			_dontShowAgainToggle.graphic = (Graphic)(object)component5;
			GameObject obj = Object.Instantiate<GameObject>(((Component)textTemplate).gameObject, val.transform);
			((Object)obj).name = "com.hex.quickstackstorage.DontShowAgainToggle.Label";
			RectTransform component6 = obj.GetComponent<RectTransform>();
			if ((Object)(object)component6 != (Object)null)
			{
				component6.anchorMin = Vector2.zero;
				component6.anchorMax = Vector2.one;
				component6.pivot = new Vector2(0.5f, 0.5f);
				component6.anchoredPosition = Vector2.zero;
				component6.offsetMin = new Vector2(30f, 0f);
				component6.offsetMax = Vector2.zero;
				((Transform)component6).localScale = Vector3.one;
			}
			TMP_Text component7 = obj.GetComponent<TMP_Text>();
			if ((Object)(object)component7 != (Object)null)
			{
				component7.text = "Don't show this confirmation again.";
				component7.fontSize = 16f;
				component7.fontStyle = (FontStyles)0;
				component7.alignment = (TextAlignmentOptions)4097;
				((Graphic)component7).raycastTarget = false;
			}
		}
	}
	internal static class InventoryUiController
	{
		private const string SortButtonName = "com.hex.quickstackstorage.SortButton";

		private const string QuickStackButtonName = "com.hex.quickstackstorage.QuickStackButton";

		private const string ContainerSortButtonName = "com.hex.quickstackstorage.ContainerSortButton";

		private const string TrashButtonName = "com.hex.quickstackstorage.TrashButton";

		private const float ButtonSize = 36f;

		private const float ButtonSpacing = 4f;

		private const float TrashIconSize = 32f;

		private const float TrashIconXOffset = 4f;

		private const float TrashIconYOffset = 0f;

		private static readonly FieldInfo CurrentContainerField = AccessTools.Field(typeof(InventoryGui), "m_currentContainer");

		private static readonly FieldInfo DragItemField = AccessTools.Field(typeof(InventoryGui), "m_dragItem");

		private static InventoryGui _inventoryGui;

		private static Button _quickStackButton;

		private static QuickStackTooltipComponent _quickStackTooltip;

		internal static void Initialize(InventoryGui inventoryGui)
		{
			if (!((Object)(object)inventoryGui == (Object)null))
			{
				_inventoryGui = inventoryGui;
				CreateButtons();
			}
		}

		internal static Container GetCurrentContainer()
		{
			if ((Object)(object)_inventoryGui == (Object)null)
			{
				return null;
			}
			object? obj = CurrentContainerField?.GetValue(_inventoryGui);
			return (Container)((obj is Container) ? obj : null);
		}

		internal static void SetContainerSortButtonVisible(bool visible)
		{
			if ((Object)(object)_inventoryGui == (Object)null || (Object)(object)_inventoryGui.m_stackAllButton == (Object)null)
			{
				return;
			}
			Transform parent = ((Component)_inventoryGui.m_stackAllButton).transform.parent;
			if (!((Object)(object)parent == (Object)null))
			{
				Transform val = parent.Find("com.hex.quickstackstorage.ContainerSortButton");
				if ((Object)(object)val != (Object)null)
				{
					((Component)val).gameObject.SetActive(visible);
				}
			}
		}

		internal static void SetQuickStackButtonInteractable(bool interactable)
		{
			if ((Object)(object)_quickStackButton != (Object)null)
			{
				((Selectable)_quickStackButton).interactable = interactable;
			}
			if ((Object)(object)_quickStackTooltip != (Object)null)
			{
				_quickStackTooltip.TooltipEnabled = !interactable;
			}
		}

		private static void CreateButtons()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Expected O, but got Unknown
			if ((Object)(object)_inventoryGui == (Object)null || (Object)(object)_inventoryGui.m_player == (Object)null || (Object)(object)_inventoryGui.m_takeAllButton == (Object)null)
			{
				return;
			}
			Button takeAllButton = _inventoryGui.m_takeAllButton;
			CreateActionButton(takeAllButton, "com.hex.quickstackstorage.SortButton", "S", 0, new UnityAction(OnSortClicked));
			_quickStackButton = CreateActionButton(takeAllButton, "com.hex.quickstackstorage.QuickStackButton", "Q", 1, new UnityAction(OnQuickStackClicked));
			if ((Object)(object)_quickStackButton != (Object)null)
			{
				_quickStackTooltip = ((Component)_quickStackButton).GetComponent<QuickStackTooltipComponent>();
				if ((Object)(object)_quickStackTooltip == (Object)null)
				{
					_quickStackTooltip = ((Component)_quickStackButton).gameObject.AddComponent<QuickStackTooltipComponent>();
				}
			}
			CreateContainerSortButton();
			if (Plugin.EnableTrashFeature)
			{
				CreateTrashButton(new UnityAction(OnTrashClicked));
			}
		}

		private static Button CreateActionButton(Button template, string buttonName, string text, int index, UnityAction onClick)
		{
			Transform val = ((Component)_inventoryGui.m_player).transform.Find(buttonName);
			if ((Object)(object)val != (Object)null)
			{
				return ((Component)val).GetComponent<Button>();
			}
			GameObject val2 = Object.Instantiate<GameObject>(((Component)template).gameObject, ((Component)_inventoryGui.m_player).transform);
			((Object)val2).name = buttonName;
			Button component = val2.GetComponent<Button>();
			if ((Object)(object)component == (Object)null)
			{
				Object.Destroy((Object)(object)val2);
				return null;
			}
			((UnityEventBase)component.onClick).RemoveAllListeners();
			((UnityEvent)component.onClick).AddListener(onClick);
			SetButtonText(val2, text);
			StyleActionButton(val2);
			PositionActionButton(val2, index);
			val2.SetActive(true);
			return component;
		}

		private static Button CreateContainerSortButton()
		{
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Expected O, but got Unknown
			if ((Object)(object)_inventoryGui == (Object)null || (Object)(object)_inventoryGui.m_stackAllButton == (Object)null)
			{
				return null;
			}
			Button stackAllButton = _inventoryGui.m_stackAllButton;
			Transform parent = ((Component)stackAllButton).transform.parent;
			if ((Object)(object)parent == (Object)null)
			{
				return null;
			}
			Transform val = parent.Find("com.hex.quickstackstorage.ContainerSortButton");
			if ((Object)(object)val != (Object)null)
			{
				return ((Component)val).GetComponent<Button>();
			}
			GameObject val2 = Object.Instantiate<GameObject>(((Component)stackAllButton).gameObject, parent);
			((Object)val2).name = "com.hex.quickstackstorage.ContainerSortButton";
			Button component = val2.GetComponent<Button>();
			if ((Object)(object)component == (Object)null)
			{
				Object.Destroy((Object)(object)val2);
				return null;
			}
			((UnityEventBase)component.onClick).RemoveAllListeners();
			((UnityEvent)component.onClick).AddListener(new UnityAction(OnContainerSortClicked));
			SetButtonText(val2, "S");
			PositionContainerSortButton(val2, ((Component)stackAllButton).gameObject);
			val2.SetActive(false);
			return component;
		}

		private static Button CreateTrashButton(UnityAction onClick)
		{
			if (!Plugin.EnableTrashFeature)
			{
				return null;
			}
			Transform val = FindChildRecursive(((Component)_inventoryGui).transform, "com.hex.quickstackstorage.TrashButton");
			if ((Object)(object)val != (Object)null)
			{
				return ((Component)val).GetComponent<Button>();
			}
			RectTransform val2 = FindStatusTab("armor");
			RectTransform val3 = FindStatusTab("weight");
			if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null)
			{
				return null;
			}
			GameObject val4 = Object.Instantiate<GameObject>(((Component)val3).gameObject, ((Transform)val3).parent);
			((Object)val4).name = "com.hex.quickstackstorage.TrashButton";
			RectTransform component = val4.GetComponent<RectTransform>();
			Transform val5 = val4.transform.Find("weight_icon");
			Transform val6 = val4.transform.Find("weight_text");
			if ((Object)(object)val6 != (Object)null)
			{
				((Component)val6).gameObject.SetActive(false);
			}
			if ((Object)(object)val5 != (Object)null)
			{
				((Component)val5).gameObject.SetActive(false);
			}
			CreateTrashIcon(val4.transform);
			Button val7 = val4.GetComponent<Button>();
			if ((Object)(object)val7 == (Object)null)
			{
				val7 = val4.AddComponent<Button>();
			}
			Image component2 = val4.GetComponent<Image>();
			if ((Object)(object)component2 != (Object)null)
			{
				((Selectable)val7).targetGraphic = (Graphic)(object)component2;
			}
			((UnityEventBase)val7.onClick).RemoveAllListeners();
			((UnityEvent)val7.onClick).AddListener(onClick);
			PositionTrashButton(component, val2, val3);
			int siblingIndex = Mathf.Min(((Transform)val2).GetSiblingIndex(), ((Transform)val3).GetSiblingIndex());
			((Transform)component).SetSiblingIndex(siblingIndex);
			val4.SetActive(true);
			return val7;
		}

		private static void CreateTrashIcon(Transform parent)
		{
			//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_0036: 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_0060: 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_0089: 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_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: 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_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_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("com.hex.quickstackstorage.TrashIcon", new Type[1] { typeof(RectTransform) });
			RectTransform component = val.GetComponent<RectTransform>();
			((Transform)component).SetParent(parent, false);
			component.anchorMin = new Vector2(0.5f, 0.5f);
			component.anchorMax = new Vector2(0.5f, 0.5f);
			component.pivot = new Vector2(0.5f, 0.5f);
			component.sizeDelta = new Vector2(32f, 32f);
			component.anchoredPosition = new Vector2(4f, 0f);
			RectTransform component2 = CreateIconPart(val.transform, "com.hex.quickstackstorage.TrashIcon.Body").GetComponent<RectTransform>();
			component2.anchorMin = new Vector2(0.2f, 0.1f);
			component2.anchorMax = new Vector2(0.8f, 0.7f);
			component2.offsetMin = Vector2.zero;
			component2.offsetMax = Vector2.zero;
			RectTransform component3 = CreateIconPart(val.transform, "com.hex.quickstackstorage.TrashIcon.Lid").GetComponent<RectTransform>();
			component3.anchorMin = new Vector2(0.1f, 0.74f);
			component3.anchorMax = new Vector2(0.9f, 0.84f);
			component3.offsetMin = Vector2.zero;
			component3.offsetMax = Vector2.zero;
			RectTransform component4 = CreateIconPart(val.transform, "com.hex.quickstackstorage.TrashIcon.Handle").GetComponent<RectTransform>();
			component4.anchorMin = new Vector2(0.36f, 0.85f);
			component4.anchorMax = new Vector2(0.64f, 0.96f);
			component4.offsetMin = Vector2.zero;
			component4.offsetMax = Vector2.zero;
			CreateTrashSlot(val.transform, 0.35f);
			CreateTrashSlot(val.transform, 0.5f);
			CreateTrashSlot(val.transform, 0.65f);
		}

		private static GameObject CreateIconPart(Transform parent, string name)
		{
			//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_0033: 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_005f: Expected O, but got Unknown
			GameObject val = new GameObject(name, new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			((Transform)val.GetComponent<RectTransform>()).SetParent(parent, false);
			Image component = val.GetComponent<Image>();
			((Graphic)component).color = new Color(0.72f, 0.72f, 0.72f, 1f);
			((Graphic)component).raycastTarget = false;
			return val;
		}

		private static void CreateTrashSlot(Transform parent, float x)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("com.hex.quickstackstorage.TrashIcon.Slot", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			RectTransform component = val.GetComponent<RectTransform>();
			((Transform)component).SetParent(parent, false);
			component.anchorMin = new Vector2(x, 0.18f);
			component.anchorMax = new Vector2(x, 0.6f);
			component.sizeDelta = new Vector2(2f, 0f);
			Image component2 = val.GetComponent<Image>();
			((Graphic)component2).color = new Color(0.2f, 0.2f, 0.2f, 1f);
			((Graphic)component2).raycastTarget = false;
		}

		private static void PositionTrashButton(RectTransform trashRect, RectTransform armorRect, RectTransform weightRect)
		{
			//IL_001e: 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_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)trashRect == (Object)null) && !((Object)(object)armorRect == (Object)null) && !((Object)(object)weightRect == (Object)null))
			{
				trashRect.anchorMin = weightRect.anchorMin;
				trashRect.anchorMax = weightRect.anchorMax;
				trashRect.pivot = weightRect.pivot;
				trashRect.sizeDelta = weightRect.sizeDelta;
				Vector3 position = (((Transform)armorRect).position + ((Transform)weightRect).position) * 0.5f;
				((Transform)trashRect).position = position;
			}
		}

		private static void PositionContainerSortButton(GameObject buttonObject, GameObject templateObject)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: 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_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: 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)
			RectTransform component = buttonObject.GetComponent<RectTransform>();
			RectTransform component2 = templateObject.GetComponent<RectTransform>();
			if (!((Object)(object)component == (Object)null) && !((Object)(object)component2 == (Object)null))
			{
				component.anchorMin = component2.anchorMin;
				component.anchorMax = component2.anchorMax;
				component.pivot = new Vector2(0.5f, 0.5f);
				component.sizeDelta = new Vector2(36f, 36f);
				float x = component2.anchoredPosition.x;
				Rect rect = component2.rect;
				float num = x - ((Rect)(ref rect)).width * component2.pivot.x;
				component.anchoredPosition = new Vector2(num - 4f - 18f, component2.anchoredPosition.y);
			}
		}

		private static RectTransform FindStatusTab(string namePart)
		{
			RectTransform[] componentsInChildren = ((Component)_inventoryGui).GetComponentsInChildren<RectTransform>(true);
			foreach (RectTransform val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && ((Object)val).name.IndexOf(namePart, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return val;
				}
			}
			return null;
		}

		private static Transform FindChildRecursive(Transform parent, string childName)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			if ((Object)(object)parent == (Object)null)
			{
				return null;
			}
			foreach (Transform item in parent)
			{
				Transform val = item;
				if (((Object)val).name == childName)
				{
					return val;
				}
				Transform val2 = FindChildRecursive(val, childName);
				if ((Object)(object)val2 != (Object)null)
				{
					return val2;
				}
			}
			return null;
		}

		private static void SetButtonText(GameObject buttonObject, string text)
		{
			TMP_Text componentInChildren = buttonObject.GetComponentInChildren<TMP_Text>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.text = text;
				componentInChildren.alignment = (TextAlignmentOptions)514;
				return;
			}
			Text componentInChildren2 = buttonObject.GetComponentInChildren<Text>(true);
			if ((Object)(object)componentInChildren2 != (Object)null)
			{
				componentInChildren2.text = text;
				componentInChildren2.alignment = (TextAnchor)4;
			}
		}

		private static void StyleActionButton(GameObject buttonObject)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			RectTransform component = buttonObject.GetComponent<RectTransform>();
			if (!((Object)(object)component == (Object)null))
			{
				component.sizeDelta = new Vector2(36f, 36f);
				Image component2 = buttonObject.GetComponent<Image>();
				if ((Object)(object)component2 != (Object)null)
				{
					component2.type = (Type)1;
				}
			}
		}

		private static void PositionActionButton(GameObject buttonObject, int index)
		{
			//IL_0035: 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_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: 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_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			RectTransform component = buttonObject.GetComponent<RectTransform>();
			RectTransform component2 = ((Component)_inventoryGui.m_player).GetComponent<RectTransform>();
			if (!((Object)(object)component == (Object)null) && !((Object)(object)component2 == (Object)null))
			{
				component.anchorMin = new Vector2(0f, 1f);
				component.anchorMax = new Vector2(0f, 1f);
				component.pivot = new Vector2(0f, 1f);
				Rect rect = component2.rect;
				float num = ((Rect)(ref rect)).width + 8f + (float)index * 40f;
				rect = component2.rect;
				float num2 = 0f - ((Rect)(ref rect)).height + 36f;
				component.anchoredPosition = new Vector2(num, num2);
			}
		}

		private static void OnSortClicked()
		{
			if (!((Object)(object)Player.m_localPlayer == (Object)null))
			{
				InventorySortService.SortPlayerInventory();
			}
		}

		private static void OnContainerSortClicked()
		{
			Container currentContainer = GetCurrentContainer();
			if (!((Object)(object)currentContainer == (Object)null))
			{
				InventorySortService.SortContainer(currentContainer);
			}
		}

		private static void OnQuickStackClicked()
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				QuickStackService.QuickStack(localPlayer);
			}
		}

		private static void OnTrashClicked()
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Expected O, but got Unknown
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Expected O, but got Unknown
			if (!Plugin.EnableTrashFeature)
			{
				return;
			}
			Player player = Player.m_localPlayer;
			if (!((Object)(object)player == (Object)null) && !((Object)(object)_inventoryGui == (Object)null))
			{
				UnityAction val = ((!(DragItemField?.GetValue(_inventoryGui) is ItemData)) ? ((UnityAction)delegate
				{
					TrashService.DeleteMarkedItems(player);
				}) : ((UnityAction)delegate
				{
					TrashService.DeleteDraggedItem(_inventoryGui, player);
				}));
				if (Plugin.EnableDeleteConfirmation)
				{
					DialogUiController.ShowDeleteConfirmation(_inventoryGui, val);
				}
				else
				{
					val.Invoke();
				}
			}
		}
	}
	internal static class InventoryBorderRenderer
	{
		private const float BorderThickness = 2f;

		private static readonly FieldInfo ElementsField = AccessTools.Field(typeof(InventoryGrid), "m_elements");

		internal static void Refresh(InventoryGrid grid, string borderName, Color borderColor, Func<ItemData, bool> shouldShowBorder)
		{
			//IL_007a: 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)
			if ((Object)(object)grid == (Object)null || grid.GetInventory() == null || shouldShowBorder == null)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || grid.GetInventory() != ((Humanoid)localPlayer).GetInventory() || !(ElementsField?.GetValue(grid) is List<InventoryElement> list))
			{
				return;
			}
			int width = grid.GetInventory().GetWidth();
			foreach (InventoryElement item in list)
			{
				if (!((Object)(object)item == (Object)null))
				{
					SetBorderVisible(item, borderName, borderColor, visible: false);
				}
			}
			foreach (ItemData allItem in grid.GetInventory().GetAllItems())
			{
				if (allItem == null || !shouldShowBorder(allItem))
				{
					continue;
				}
				int num = allItem.m_gridPos.y * width + allItem.m_gridPos.x;
				if (num >= 0 && num < list.Count)
				{
					InventoryElement val = list[num];
					if ((Object)(object)val != (Object)null)
					{
						SetBorderVisible(val, borderName, borderColor, visible: true);
					}
				}
			}
		}

		private static void SetBorderVisible(InventoryElement element, string borderName, Color borderColor, bool visible)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			Transform val = ((Component)element).transform.Find(borderName);
			GameObject val2 = (((Object)(object)val != (Object)null) ? ((Component)val).gameObject : null);
			if ((Object)(object)val2 == (Object)null && visible)
			{
				val2 = CreateBorder(((Component)element).transform, borderName, borderColor);
			}
			if ((Object)(object)val2 != (Object)null)
			{
				val2.SetActive(visible);
			}
		}

		private static GameObject CreateBorder(Transform parent, string borderName, Color borderColor)
		{
			//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_0029: 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_003f: 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_0054: 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)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: 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_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: 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_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Expected O, but got Unknown
			GameObject val = new GameObject(borderName, new Type[1] { typeof(RectTransform) });
			RectTransform component = val.GetComponent<RectTransform>();
			((Transform)component).SetParent(parent, false);
			component.anchorMin = Vector2.zero;
			component.anchorMax = Vector2.one;
			component.offsetMin = Vector2.zero;
			component.offsetMax = Vector2.zero;
			CreateEdge(val.transform, "Top", new Vector2(0f, 1f), new Vector2(1f, 1f), new Vector2(0f, -2f), Vector2.zero, borderColor);
			CreateEdge(val.transform, "Bottom", new Vector2(0f, 0f), new Vector2(1f, 0f), Vector2.zero, new Vector2(0f, 2f), borderColor);
			CreateEdge(val.transform, "Left", new Vector2(0f, 0f), new Vector2(0f, 1f), Vector2.zero, new Vector2(2f, 0f), borderColor);
			CreateEdge(val.transform, "Right", new Vector2(1f, 0f), new Vector2(1f, 1f), new Vector2(-2f, 0f), Vector2.zero, borderColor);
			((Transform)component).SetAsLastSibling();
			return val;
		}

		private static void CreateEdge(Transform parent, string name, Vector2 anchorMin, Vector2 anchorMax, Vector2 offsetMin, Vector2 offsetMax, Color borderColor)
		{
			//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_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			RectTransform component = val.GetComponent<RectTransform>();
			((Transform)component).SetParent(parent, false);
			component.anchorMin = anchorMin;
			component.anchorMax = anchorMax;
			component.offsetMin = offsetMin;
			component.offsetMax = offsetMax;
			Image component2 = val.GetComponent<Image>();
			((Graphic)component2).color = borderColor;
			((Graphic)component2).raycastTarget = false;
		}
	}
}
namespace HexQuickStackStorage.Services
{
	internal static class InventoryOperationsService
	{
		private static readonly MethodInfo ChangedMethod = typeof(Inventory).GetMethod("Changed", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[2]
		{
			typeof(bool),
			typeof(bool)
		}, null);

		private static readonly MethodInfo FindFreeStackItemMethod = typeof(Inventory).GetMethod("FindFreeStackItem", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[3]
		{
			typeof(string),
			typeof(int),
			typeof(int)
		}, null);

		private static readonly MethodInfo FindEmptySlotMethod = typeof(Inventory).GetMethod("FindEmptySlot", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[1] { typeof(bool) }, null);

		private static readonly MethodInfo TopFirstMethod = typeof(Inventory).GetMethod("TopFirst", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[1] { typeof(ItemData) }, null);

		private static readonly object[] ChangedArguments = new object[2] { false, false };

		internal static void NotifyChanged(Inventory inventory)
		{
			if (inventory != null)
			{
				ChangedMethod?.Invoke(inventory, ChangedArguments);
			}
		}

		internal static ItemData FindFreeStackItem(Inventory inventory, ItemData item)
		{
			if (inventory == null || item == null || FindFreeStackItemMethod == null)
			{
				return null;
			}
			object? obj = FindFreeStackItemMethod.Invoke(inventory, new object[3]
			{
				item.m_shared.m_name,
				item.m_quality,
				item.m_worldLevel
			});
			return (ItemData)((obj is ItemData) ? obj : null);
		}

		internal static Vector2i FindEmptySlot(Inventory inventory, ItemData item)
		{
			//IL_0022: 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)
			if (inventory == null || item == null || FindEmptySlotMethod == null || TopFirstMethod == null)
			{
				return new Vector2i(-1, -1);
			}
			bool flag = (bool)TopFirstMethod.Invoke(inventory, new object[1] { item });
			return (Vector2i)FindEmptySlotMethod.Invoke(inventory, new object[1] { flag });
		}
	}
}
namespace HexQuickStackStorage.Patches
{
	[HarmonyPatch(typeof(Container))]
	internal static class ContainerPatch
	{
		[HarmonyPatch("RPC_OpenResponse")]
		[HarmonyPostfix]
		private static void RPC_OpenResponsePostfix(Container __instance, bool granted)
		{
			if (granted && Plugin.EnableChestAutoSorting)
			{
				InventorySortService.SortContainer(__instance);
			}
		}

		[HarmonyPatch("RPC_StackResponse")]
		[HarmonyPrefix]
		private static bool RPC_StackResponsePrefix(Container __instance, bool granted)
		{
			if (!granted)
			{
				return true;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return false;
			}
			QuickStackService.QuickStack(localPlayer, __instance);
			return false;
		}
	}
	[HarmonyPatch]
	internal static class InventoryGridPatch
	{
		[HarmonyPatch(typeof(InventoryGui), "OnRightClickItem")]
		[HarmonyPrefix]
		private static bool OnRightClickItemPrefix(InventoryGrid grid, ItemData item)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)grid == (Object)null || item == null)
			{
				return true;
			}
			if (grid.GetInventory() != ((Humanoid)localPlayer).GetInventory())
			{
				return true;
			}
			if (!TrashService.IsVanillaInventoryItem(localPlayer, item))
			{
				return true;
			}
			if (Plugin.EnableTrashFeature && ZInput.GetKey(Plugin.TrashModifierKey, true))
			{
				ItemStateService.ToggleTrash(localPlayer, item);
				RefreshItemStateBorders(grid);
				return false;
			}
			if (ZInput.GetKey(Plugin.FavoriteModifierKey, true))
			{
				ItemStateService.ToggleFavorite(localPlayer, item);
				RefreshItemStateBorders(grid);
				return false;
			}
			return true;
		}

		[HarmonyPatch(typeof(InventoryGrid), "UpdateGui")]
		[HarmonyPostfix]
		private static void UpdateGuiPostfix(InventoryGrid __instance)
		{
			RefreshItemStateBorders(__instance);
		}

		private static void RefreshItemStateBorders(InventoryGrid grid)
		{
			//IL_002b: 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_0069: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.EnableTrashFeature)
			{
				InventoryBorderRenderer.Refresh(grid, "HexTrashBorder", Color.red, TrashService.IsMarked);
			}
			else
			{
				InventoryBorderRenderer.Refresh(grid, "HexTrashBorder", Color.red, (ItemData item) => false);
			}
			InventoryBorderRenderer.Refresh(grid, "HexFavoriteBorder", new Color(1f, 0.75f, 0f), FavoriteService.IsFavorite);
		}
	}
	[HarmonyPatch]
	internal static class InventoryGuiPatch
	{
		[HarmonyPatch(typeof(InventoryGui), "Awake")]
		[HarmonyPostfix]
		private static void AwakePostfix(InventoryGui __instance)
		{
			InventoryUiController.Initialize(__instance);
		}

		[HarmonyPatch(typeof(InventoryGui), "OnStackAll")]
		[HarmonyPrefix]
		private static bool OnStackAllPrefix()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return true;
			}
			Container currentContainer = InventoryUiController.GetCurrentContainer();
			if ((Object)(object)currentContainer == (Object)null)
			{
				return true;
			}
			QuickStackService.QuickStack(localPlayer, currentContainer);
			return false;
		}

		[HarmonyPatch(typeof(InventoryGui), "Show")]
		[HarmonyPostfix]
		private static void ShowPostfix(Container container)
		{
			bool num = (Object)(object)container != (Object)null;
			InventoryUiController.SetContainerSortButtonVisible(num);
			InventoryUiController.SetQuickStackButtonInteractable(!num);
		}

		[HarmonyPatch(typeof(InventoryGui), "CloseContainer")]
		[HarmonyPostfix]
		private static void CloseContainerPostfix()
		{
			InventoryUiController.SetContainerSortButtonVisible(visible: false);
			InventoryUiController.SetQuickStackButtonInteractable(interactable: true);
		}
	}
}
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 ServerSync
{
	[PublicAPI]
	internal abstract class OwnConfigEntryBase
	{
		public object? LocalBaseValue;

		public bool SynchronizedConfig = true;

		public abstract ConfigEntryBase BaseConfig { get; }
	}
	[PublicAPI]
	internal class SyncedConfigEntry<T>(ConfigEntry<T> sourceConfig) : OwnConfigEntryBase()
	{
		public readonly ConfigEntry<T> SourceConfig = sourceConfig;

		public override ConfigEntryBase BaseConfig => (ConfigEntryBase)(object)SourceConfig;

		public T Value
		{
			get
			{
				return SourceConfig.Value;
			}
			set
			{
				SourceConfig.Value = value;
			}
		}

		public void AssignLocalValue(T value)
		{
			if (LocalBaseValue == null)
			{
				Value = value;
			}
			else
			{
				LocalBaseValue = value;
			}
		}
	}
	internal abstract class CustomSyncedValueBase
	{
		public object? LocalBaseValue;

		public readonly string Identifier;

		public readonly Type Type;

		private object? boxedValue;

		protected bool localIsOwner;

		public readonly int Priority;

		public object? BoxedValue
		{
			get
			{
				return boxedValue;
			}
			set
			{
				boxedValue = value;
				this.ValueChanged?.Invoke();
			}
		}

		public event Action? ValueChanged;

		protected CustomSyncedValueBase(ConfigSync configSync, string identifier, Type type, int priority)
		{
			Priority = priority;
			Identifier = identifier;
			Type = type;
			configSync.AddCustomValue(this);
			localIsOwner = configSync.IsSourceOfTruth;
			configSync.SourceOfTruthChanged += delegate(bool truth)
			{
				localIsOwner = truth;
			};
		}
	}
	[PublicAPI]
	internal sealed class CustomSyncedValue<T> : CustomSyncedValueBase
	{
		public T Value
		{
			get
			{
				return (T)base.BoxedValue;
			}
			set
			{
				base.BoxedValue = value;
			}
		}

		public CustomSyncedValue(ConfigSync configSync, string identifier, T value = default(T), int priority = 0)
			: base(configSync, identifier, typeof(T), priority)
		{
			Value = value;
		}

		public void AssignLocalValue(T value)
		{
			if (localIsOwner)
			{
				Value = value;
			}
			else
			{
				LocalBaseValue = value;
			}
		}
	}
	internal class ConfigurationManagerAttributes
	{
		[UsedImplicitly]
		public bool? ReadOnly = false;
	}
	[PublicAPI]
	internal class ConfigSync
	{
		[HarmonyPatch(typeof(ZRpc), "HandlePackage")]
		private static class SnatchCurrentlyHandlingRPC
		{
			public static ZRpc? currentRpc;

			[HarmonyPrefix]
			private static void Prefix(ZRpc __instance)
			{
				currentRpc = __instance;
			}
		}

		[HarmonyPatch(typeof(ZNet), "Awake")]
		internal static class RegisterRPCPatch
		{
			[HarmonyPostfix]
			private static void Postfix(ZNet __instance)
			{
				isServer = __instance.IsServer();
				foreach (ConfigSync configSync2 in configSyncs)
				{
					ZRoutedRpc.instance.Register<ZPackage>(configSync2.Name + " ConfigSync", (Action<long, ZPackage>)configSync2.RPC_FromOtherClientConfigSync);
					if (isServer)
					{
						configSync2.InitialSyncDone = true;
						Debug.Log((object)("Registered '" + configSync2.Name + " ConfigSync' RPC - waiting for incoming connections"));
					}
				}
				if (isServer)
				{
					((MonoBehaviour)__instance).StartCoroutine(WatchAdminListChanges());
				}
				static void SendAdmin(List<ZNetPeer> peers, bool isAdmin)
				{
					ZPackage package = ConfigsToPackage(null, null, new PackageEntry[1]
					{
						new PackageEntry
						{
							section = "Internal",
							key = "lockexempt",
							type = typeof(bool),
							value = isAdmin
						}
					});
					ConfigSync configSync = configSyncs.First();
					if (configSync != null)
					{
						((MonoBehaviour)ZNet.instance).StartCoroutine(configSync.sendZPackage(peers, package));
					}
				}
				static IEnumerator WatchAdminListChanges()
				{
					MethodInfo listContainsId = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null);
					SyncedList adminList = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance);
					List<string> CurrentList = new List<string>(adminList.GetList());
					while (true)
					{
						yield return (object)new WaitForSeconds(30f);
						if (!adminList.GetList().SequenceEqual(CurrentList))
						{
							CurrentList = new List<string>(adminList.GetList());
							List<ZNetPeer> adminPeer = ZNet.instance.GetPeers().Where(delegate(ZNetPeer p)
							{
								string hostName = p.m_rpc.GetSocket().GetHostName();
								return ((object)listContainsId == null) ? adminList.Contains(hostName) : ((bool)listContainsId.Invoke(ZNet.instance, new object[2] { adminList, hostName }));
							}).ToList();
							List<ZNetPeer> nonAdminPeer = ZNet.instance.GetPeers().Except(adminPeer).ToList();
							SendAdmin(nonAdminPeer, isAdmin: false);
							SendAdmin(adminPeer, isAdmin: true);
						}
					}
				}
			}
		}

		[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
		private static class RegisterClientRPCPatch
		{
			[HarmonyPostfix]
			private static void Postfix(ZNet __instance, ZNetPeer peer)
			{
				if (__instance.IsServer())
				{
					return;
				}
				foreach (ConfigSync configSync in configSyncs)
				{
					peer.m_rpc.Register<ZPackage>(configSync.Name + " ConfigSync", (Action<ZRpc, ZPackage>)configSync.RPC_FromServerConfigSync);
				}
			}
		}

		private class ParsedConfigs
		{
			public readonly Dictionary<OwnConfigEntryBase, object?> configValues = new Dictionary<OwnConfigEntryBase, object>();

			public readonly Dictionary<CustomSyncedValueBase, object?> customValues = new Dictionary<CustomSyncedValueBase, object>();
		}

		[HarmonyPatch(typeof(ZNet), "Shutdown")]
		private class ResetConfigsOnShutdown
		{
			[HarmonyPostfix]
			private static void Postfix()
			{
				ProcessingServerUpdate = true;
				foreach (ConfigSync configSync in configSyncs)
				{
					configSync.resetConfigsFromServer();
					configSync.IsSourceOfTruth = true;
					configSync.InitialSyncDone = false;
				}
				ProcessingServerUpdate = false;
			}
		}

		[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
		private class SendConfigsAfterLogin
		{
			private class BufferingSocket : ZPlayFabSocket, ISocket
			{
				public volatile bool finished = false;

				public volatile int versionMatchQueued = -1;

				public readonly List<ZPackage> Package = new List<ZPackage>();

				public readonly ISocket Original;

				public BufferingSocket(ISocket original)
				{
					Original = original;
					((ZPlayFabSocket)this)..ctor();
				}

				public bool IsConnected()
				{
					return Original.IsConnected();
				}

				public ZPackage Recv()
				{
					return Original.Recv();
				}

				public int GetSendQueueSize()
				{
					return Original.GetSendQueueSize();
				}

				public int GetCurrentSendRate()
				{
					return Original.GetCurrentSendRate();
				}

				public bool IsHost()
				{
					return Original.IsHost();
				}

				public void Dispose()
				{
					Original.Dispose();
				}

				public bool GotNewData()
				{
					return Original.GotNewData();
				}

				public void Close()
				{
					Original.Close();
				}

				public string GetEndPointString()
				{
					return Original.GetEndPointString();
				}

				public void GetAndResetStats(out int totalSent, out int totalRecv)
				{
					Original.GetAndResetStats(ref totalSent, ref totalRecv);
				}

				public void GetConnectionQuality(out float localQuality, out float remoteQuality, out int ping, out float outByteSec, out float inByteSec)
				{
					Original.GetConnectionQuality(ref localQuality, ref remoteQuality, ref ping, ref outByteSec, ref inByteSec);
				}

				public ISocket Accept()
				{
					return Original.Accept();
				}

				public int GetHostPort()
				{
					return Original.GetHostPort();
				}

				public bool Flush()
				{
					return Original.Flush();
				}

				public string GetHostName()
				{
					return Original.GetHostName();
				}

				public void VersionMatch()
				{
					if (finished)
					{
						Original.VersionMatch();
					}
					else
					{
						versionMatchQueued = Package.Count;
					}
				}

				public void Send(ZPackage pkg)
				{
					//IL_0057: Unknown result type (might be due to invalid IL or missing references)
					//IL_005d: Expected O, but got Unknown
					int pos = pkg.GetPos();
					pkg.SetPos(0);
					int num = pkg.ReadInt();
					if ((num == StringExtensionMethods.GetStableHashCode("PeerInfo") || num == StringExtensionMethods.GetStableHashCode("RoutedRPC") || num == StringExtensionMethods.GetStableHashCode("ZDOData")) && !finished)
					{
						ZPackage val = new ZPackage(pkg.GetArray());
						val.SetPos(pos);
						Package.Add(val);
					}
					else
					{
						pkg.SetPos(pos);
						Original.Send(pkg);
					}
				}
			}

			[HarmonyPriority(800)]
			[HarmonyPrefix]
			private static void Prefix(ref Dictionary<Assembly, BufferingSocket>? __state, ZNet __instance, ZRpc rpc)
			{
				//IL_0078: Unknown result type (might be due to invalid IL or missing references)
				//IL_007e: Invalid comparison between Unknown and I4
				if (!__instance.IsServer())
				{
					return;
				}
				BufferingSocket bufferingSocket = new BufferingSocket(rpc.GetSocket());
				AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc, bufferingSocket);
				object? obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc });
				ZNetPeer val = (ZNetPeer)((obj is ZNetPeer) ? obj : null);
				if (val != null && (int)ZNet.m_onlineBackend > 0)
				{
					FieldInfo fieldInfo = AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket");
					object? value = fieldInfo.GetValue(val);
					ZPlayFabSocket val2 = (ZPlayFabSocket)((value is ZPlayFabSocket) ? value : null);
					if (val2 != null)
					{
						typeof(ZPlayFabSocket).GetField("m_remotePlayerId").SetValue(bufferingSocket, val2.m_remotePlayerId);
					}
					fieldInfo.SetValue(val, bufferingSocket);
				}
				if (__state == null)
				{
					__state = new Dictionary<Assembly, BufferingSocket>();
				}
				__state[Assembly.GetExecutingAssembly()] = bufferingSocket;
			}

			[HarmonyPostfix]
			private static void Postfix(Dictionary<Assembly, BufferingSocket> __state, ZNet __instance, ZRpc rpc)
			{
				ZNetPeer peer;
				if (__instance.IsServer())
				{
					object obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc });
					peer = (ZNetPeer)((obj is ZNetPeer) ? obj : null);
					if (peer == null)
					{
						SendBufferedData();
					}
					else
					{
						((MonoBehaviour)__instance).StartCoroutine(sendAsync());
					}
				}
				void SendBufferedData()
				{
					if (rpc.GetSocket() is BufferingSocket bufferingSocket)
					{
						AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc, bufferingSocket.Original);
						object? obj2 = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc });
						ZNetPeer val = (ZNetPeer)((obj2 is ZNetPeer) ? obj2 : null);
						if (val != null)
						{
							AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket").SetValue(val, bufferingSocket.Ori