Decompiled source of PinVentory v1.0.0

PinVentory.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.Json;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using ProjectM;
using ProjectM.Network;
using ProjectM.UI;
using Stunlock.Core;
using Stunlock.Localization;
using Stunlock.Network;
using TMPro;
using Unity.Collections;
using Unity.Entities;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using VampireCommandFramework;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(/*Could not decode attribute arguments.*/)]
[assembly: SecurityPermission((SecurityAction)8, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : System.Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(/*Could not decode attribute arguments.*/)]
	internal sealed class RefSafetyRulesAttribute : System.Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace PinVentory
{
	[BepInPlugin("com.zeeCameLsnake.PinVentory", "PinVentory", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class PinVentoryPlugin : BasePlugin
	{
		internal enum ClientModeOption
		{
			Auto,
			ClientOnly,
			ServerOnly
		}

		public const string PluginGUID = "com.zeeCameLsnake.PinVentory";

		public const string PluginName = "PinVentory";

		public const string PluginVersion = "1.0.0";

		internal static ManualLogSource Logger;

		internal static ConfigEntry<string> PinHotkey;

		internal static ConfigEntry<string> PinCurrentAmountHotkey;

		private const string KeyAdvice = "Avoid keys and modifiers the game already uses: the game still reacts to its own key while you hold Ctrl, Shift or Alt, so both the game and PinVentory would act. Example: with the default controls, Shift opens the split stack window when you hover a stack in the inventory, so any combination with Shift opens it as well.";

		internal static ConfigEntry<float> SortWaitSeconds;

		internal static ConfigEntry<float> MoveTimeoutSeconds;

		internal static ConfigEntry<ClientModeOption> ClientMode;

		internal static ConfigEntry<bool> ShowGreeting;

		internal static ConfigEntry<bool> ShowGhostIcons;

		internal static ConfigEntry<bool> ShowSlotNumbers;

		internal static ConfigEntry<bool> ShowPinFrame;

		internal static bool ClientOnly;

		public override void Load()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			Logger = ((BasePlugin)this).Log;
			Harmony val = new Harmony("com.zeeCameLsnake.PinVentory");
			if (Application.productName == "VRisingServer")
			{
				ServerSide.Load(val);
				Logger.LogInfo((object)"PinVentory v1.0.0 server side loaded.");
				return;
			}
			ClientMode = ((BasePlugin)this).Config.Bind<ClientModeOption>("General", "Mode", ClientModeOption.Auto, "Auto (recommended): use PinVentory on the server when the server runs it, otherwise the client-only fallback.\nClientOnly: always use the client-only fallback, even if the server runs PinVentory. Quick Send and KindredLogistics are then not protected.\nServerOnly: the client part stays inactive (no hotkeys, no fallback). .pin commands go to the server as chat commands and show internal item names.\nChanges need a game restart to take effect.");
			PinHotkey = ((BasePlugin)this).Config.Bind<string>("General", "PinHotkey", "F7", "Key that pins the whole stack in the hovered inventory slot, or removes its pin. A letter, digit or F1-F12, optionally with Ctrl, Shift or Alt, e.g. F7 or Ctrl+F7.\nAvoid keys and modifiers the game already uses: the game still reacts to its own key while you hold Ctrl, Shift or Alt, so both the game and PinVentory would act. Example: with the default controls, Shift opens the split stack window when you hover a stack in the inventory, so any combination with Shift opens it as well.");
			PinCurrentAmountHotkey = ((BasePlugin)this).Config.Bind<string>("General", "PinCurrentAmountHotkey", "F8", "Key that pins the current amount in the hovered slot, or sets the amount of its pin anew. Needs PinVentory on the server. Same format as PinHotkey.\nAvoid keys and modifiers the game already uses: the game still reacts to its own key while you hold Ctrl, Shift or Alt, so both the game and PinVentory would act. Example: with the default controls, Shift opens the split stack window when you hover a stack in the inventory, so any combination with Shift opens it as well.");
			ShowGreeting = ((BasePlugin)this).Config.Bind<bool>("General", "ShowGreeting", true, "Show the server's greeting \"PinVentory is active on this server\" in the chat. When off, it is still recognised but removed from the chat. Players without the client part always see it.");
			ShowGhostIcons = ((BasePlugin)this).Config.Bind<bool>("Display", "ShowGhostIcons", true, "Show a dark grey picture of the pinned item in its slot while the slot is empty.");
			ShowSlotNumbers = ((BasePlugin)this).Config.Bind<bool>("Display", "ShowSlotNumbers", true, "Show slot numbers from 9 up in the bag, for the .pin commands. The hotbar already shows 1 to 8.");
			ShowPinFrame = ((BasePlugin)this).Config.Bind<bool>("Display", "ShowPinFrame", true, "Show a warm frame around pinned slots. It is stronger while the pinned item is missing.");
			SortWaitSeconds = ((BasePlugin)this).Config.Bind<float>("Timing", "SortWaitSeconds", 1.5f, "How long to wait for the server's sort result before applying the rules anyway. Raise this on servers with high latency.");
			MoveTimeoutSeconds = ((BasePlugin)this).Config.Bind<float>("Timing", "MoveTimeoutSeconds", 2f, "How long to wait for the server to confirm one item move before stopping.");
			if (ClientMode.Value == ClientModeOption.ServerOnly)
			{
				Logger.LogInfo((object)"PinVentory v1.0.0 client side is inactive (Mode = ServerOnly).");
				return;
			}
			ClientOnly = ClientMode.Value == ClientModeOption.ClientOnly;
			RuleStore.Load();
			ClassInjector.RegisterTypeInIl2Cpp<PinVentoryBehaviour>();
			((BasePlugin)this).AddComponent<PinVentoryBehaviour>();
			val.PatchAll(typeof(ChatCommandPatch));
			val.PatchAll(typeof(MenuPatch));
			val.PatchAll(typeof(PinVisuals));
			val.PatchAll(typeof(ChatReceivePatch));
			Logger.LogInfo((object)("PinVentory v1.0.0 client side loaded with " + RuleStore.Rules.Count + " rule(s)."));
		}
	}
	public sealed class PinRule
	{
		[field: CompilerGenerated]
		[field: DebuggerBrowsable(/*Could not decode attribute arguments.*/)]
		public int Slot
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		}

		[field: CompilerGenerated]
		[field: DebuggerBrowsable(/*Could not decode attribute arguments.*/)]
		public int ItemGuid
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		}

		[field: CompilerGenerated]
		[field: DebuggerBrowsable(/*Could not decode attribute arguments.*/)]
		public string Name
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		}
	}
	internal static class RuleStore
	{
		private static readonly string FilePath = Path.Combine(Paths.ConfigPath, "PinVentory", "rules.json");

		private static readonly JsonSerializerOptions IndentedJson = new JsonSerializerOptions
		{
			WriteIndented = true
		};

		private static readonly string OffFlagPath = Path.Combine(Paths.ConfigPath, "PinVentory", "toggled-off");

		[field: CompilerGenerated]
		[field: DebuggerBrowsable(/*Could not decode attribute arguments.*/)]
		internal static List<PinRule> Rules
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			private set;
		} = new List<PinRule>();

		[field: CompilerGenerated]
		[field: DebuggerBrowsable(/*Could not decode attribute arguments.*/)]
		internal static bool Enabled
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			private set;
		} = true;

		internal static bool Toggle()
		{
			if (Enabled)
			{
				Directory.CreateDirectory(Path.GetDirectoryName(OffFlagPath));
				File.WriteAllText(OffFlagPath, "Pinned slots are switched off in the client-only fallback (.pin toggle). Delete this file or use .pin toggle to switch them on.");
			}
			else
			{
				File.Delete(OffFlagPath);
			}
			Enabled = !File.Exists(OffFlagPath);
			return Enabled;
		}

		internal static void Load()
		{
			Enabled = !File.Exists(OffFlagPath);
			if (!File.Exists(FilePath))
			{
				return;
			}
			try
			{
				List<PinRule> val = JsonSerializer.Deserialize<List<PinRule>>(File.ReadAllText(FilePath), (JsonSerializerOptions)null);
				Rules = Enumerable.ToList<PinRule>((System.Collections.Generic.IEnumerable<PinRule>)Enumerable.OrderBy<PinRule, int>(Enumerable.Select<IGrouping<int, PinRule>, PinRule>(Enumerable.GroupBy<PinRule, int>(Enumerable.Where<PinRule>((System.Collections.Generic.IEnumerable<PinRule>)(val ?? new List<PinRule>()), (Func<PinRule, bool>)((PinRule r) => r != null && r.Slot > 0 && r.ItemGuid != 0)), (Func<PinRule, int>)((PinRule r) => r.Slot)), (Func<IGrouping<int, PinRule>, PinRule>)((IGrouping<int, PinRule> g) => Enumerable.Last<PinRule>((System.Collections.Generic.IEnumerable<PinRule>)g))), (Func<PinRule, int>)((PinRule r) => r.Slot)));
			}
			catch (System.Exception ex)
			{
				string text = FilePath + ".bad";
				File.Copy(FilePath, text, true);
				PinVentoryPlugin.Logger.LogError((object)("Could not read rules.json, saved a copy as " + text + ": " + ex.Message));
			}
		}

		internal static void Save()
		{
			Directory.CreateDirectory(Path.GetDirectoryName(FilePath));
			string text = JsonSerializer.Serialize<List<PinRule>>(Rules, IndentedJson);
			string text2 = FilePath + ".tmp";
			File.WriteAllText(text2, text);
			File.Move(text2, FilePath, true);
		}

		internal static PinRule Find(int slot)
		{
			return Enumerable.FirstOrDefault<PinRule>((System.Collections.Generic.IEnumerable<PinRule>)Rules, (Func<PinRule, bool>)((PinRule r) => r.Slot == slot));
		}

		internal static void Set(int slot, int itemGuid, string name)
		{
			Rules.RemoveAll((Predicate<PinRule>)((PinRule r) => r.Slot == slot || r.ItemGuid == itemGuid));
			Rules.Add(new PinRule
			{
				Slot = slot,
				ItemGuid = itemGuid,
				Name = name
			});
			Rules = Enumerable.ToList<PinRule>((System.Collections.Generic.IEnumerable<PinRule>)Enumerable.OrderBy<PinRule, int>((System.Collections.Generic.IEnumerable<PinRule>)Rules, (Func<PinRule, int>)((PinRule r) => r.Slot)));
			Save();
		}

		internal static bool Remove(int slot)
		{
			bool flag = Rules.RemoveAll((Predicate<PinRule>)((PinRule r) => r.Slot == slot)) > 0;
			if (flag)
			{
				Save();
			}
			return flag;
		}
	}
	internal static class GameAccess
	{
		internal const int FirstBagIndex = 8;

		internal static World GetClientWorld()
		{
			List<World> s_AllWorlds = World.s_AllWorlds;
			if (s_AllWorlds == null)
			{
				return null;
			}
			for (int i = 0; i < s_AllWorlds.Count; i++)
			{
				World val = s_AllWorlds[i];
				if (val != null && val.Name.StartsWith("Client"))
				{
					return val;
				}
			}
			return null;
		}

		internal static bool TryGetInventory(out World world, out Entity character, out Entity inventory)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: 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_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			character = Entity.Null;
			inventory = Entity.Null;
			world = GetClientWorld();
			if (world == null || !ConsoleShared.TryGetLocalCharacterInCurrentWorld(ref character, world))
			{
				return false;
			}
			return InventoryUtilities.TryGetInventoryEntity<EntityManager>(world.EntityManager, character, ref inventory, 0);
		}

		internal static string Snapshot(EntityManager em, Entity inventory)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			DynamicBuffer<InventoryBuffer> buffer = ((EntityManager)(ref em)).GetBuffer<InventoryBuffer>(inventory, true);
			StringBuilder val = new StringBuilder();
			for (int i = 0; i < buffer.Length; i++)
			{
				InventoryBuffer val2 = buffer[i];
				if (val2.Amount > 0)
				{
					val.Append(i).Append('=').Append(((PrefabGUID)(ref val2.ItemType)).GuidHash)
						.Append('x')
						.Append(val2.Amount)
						.Append(' ');
				}
			}
			return ((object)val).ToString();
		}

		internal static string GetItemName(World world, PrefabGUID item)
		{
			//IL_000f: 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)
			try
			{
				GameDataSystem existingSystemManaged = world.GetExistingSystemManaged<GameDataSystem>();
				ManagedItemData orDefault = existingSystemManaged.ManagedDataRegistry.GetOrDefault<ManagedItemData>(item, (ManagedItemData)null);
				if (orDefault != null)
				{
					string text = Localization.Get(orDefault.Name, false);
					if (!string.IsNullOrEmpty(text))
					{
						return text;
					}
				}
			}
			catch (System.Exception ex)
			{
				PinVentoryPlugin.Logger.LogWarning((object)("Name lookup failed for " + ((PrefabGUID)(ref item)).GuidHash + ": " + ex.Message));
			}
			return "Item " + ((PrefabGUID)(ref item)).GuidHash;
		}

		internal unsafe static bool TryGetNetworkId(EntityManager em, Entity entity, out NetworkId id)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			id = default(NetworkId);
			ComponentType val = default(ComponentType);
			((ComponentType)(ref val))..ctor(Il2CppType.Of<NetworkId>(), (AccessMode)1);
			if (!((EntityManager)(ref em)).HasComponent(entity, val))
			{
				return false;
			}
			id = (NetworkId)(*((EntityManager)(ref em)).GetComponentDataRawRO(entity, val.TypeIndex));
			return true;
		}

		internal static bool SendMove(World world, Entity character, int fromIndex, int toIndex)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: 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_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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_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_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: 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_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			EntityManager entityManager = world.EntityManager;
			if (!TryGetNetworkId(entityManager, character, out var id))
			{
				return false;
			}
			Entity val = ((EntityManager)(ref entityManager)).CreateEntity((ComponentType[])(object)new ComponentType[3]
			{
				ComponentType.ReadOnly<SendNetworkEventTag>(),
				ComponentType.ReadOnly<NetworkEventType>(),
				ComponentType.ReadOnly<MoveItemBetweenInventoriesEvent>()
			});
			try
			{
				((EntityManager)(ref entityManager)).SetComponentData<MoveItemBetweenInventoriesEvent>(val, new MoveItemBetweenInventoriesEvent
				{
					FromInventory = id,
					FromSlot = fromIndex,
					ToInventory = id,
					ToSlot = toIndex,
					TransferMethod = (ItemTransferMethod)0
				});
				((EntityManager)(ref entityManager)).SetComponentData<NetworkEventType>(val, new NetworkEventType
				{
					EventId = NetworkEvents.EventId_MoveItemBetweenInventoriesEvent,
					IsAdminEvent = false,
					IsDebugEvent = false
				});
			}
			catch
			{
				((EntityManager)(ref entityManager)).DestroyEntity(val);
				throw;
			}
			return true;
		}

		internal static void SendHidden(World world, string text)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: 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_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: 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_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			EntityManager entityManager = world.EntityManager;
			Entity val = ((EntityManager)(ref entityManager)).CreateEntity((ComponentType[])(object)new ComponentType[3]
			{
				ComponentType.ReadOnly<SendNetworkEventTag>(),
				ComponentType.ReadOnly<NetworkEventType>(),
				ComponentType.ReadOnly<ChatMessageEvent>()
			});
			try
			{
				((EntityManager)(ref entityManager)).SetComponentData<ChatMessageEvent>(val, new ChatMessageEvent
				{
					MessageType = (ChatMessageType)4,
					MessageText = new FixedString512Bytes("[[PinVentory]]" + text)
				});
				((EntityManager)(ref entityManager)).SetComponentData<NetworkEventType>(val, new NetworkEventType
				{
					EventId = NetworkEvents.EventId_ChatMessageEvent,
					IsAdminEvent = false,
					IsDebugEvent = false
				});
			}
			catch
			{
				((EntityManager)(ref entityManager)).DestroyEntity(val);
				throw;
			}
		}

		internal static void ShowMessage(string text)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			World clientWorld = GetClientWorld();
			if (clientWorld == null)
			{
				return;
			}
			StringBuilder val = new StringBuilder();
			string[] array = text.Split('\n', (StringSplitOptions)0);
			foreach (string text2 in array)
			{
				string text3 = ((val.Length == 0) ? text2 : (((object)val)?.ToString() + "\n" + text2));
				if (val.Length > 0 && Encoding.UTF8.GetByteCount(text3) > 440)
				{
					PostMessage(clientWorld, ((object)val).ToString());
					val.Clear();
					val.Append(text2);
				}
				else
				{
					val.Clear();
					val.Append(text3);
				}
			}
			if (val.Length > 0)
			{
				PostMessage(clientWorld, ((object)val).ToString());
			}
		}

		private static void PostMessage(World world, string text)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: 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_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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_0044: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			EntityManager entityManager = world.EntityManager;
			Entity val = ((EntityManager)(ref entityManager)).CreateEntity((ComponentType[])(object)new ComponentType[2]
			{
				ComponentType.ReadOnly<ReceiveNetworkEventTag>(),
				ComponentType.ReadOnly<ChatMessageServerEvent>()
			});
			ChatMessageServerEvent val2 = new ChatMessageServerEvent
			{
				MessageType = (ServerChatMessageType)6,
				MessageText = new FixedString512Bytes(text)
			};
			DateTimeOffset utcNow = DateTimeOffset.UtcNow;
			val2.TimeUTC = ((DateTimeOffset)(ref utcNow)).ToUnixTimeSeconds();
			((EntityManager)(ref entityManager)).SetComponentData<ChatMessageServerEvent>(val, val2);
		}
	}
	internal static class RuleApplier
	{
		private enum State
		{
			Idle,
			WaitingForSort,
			WaitingForMove
		}

		private const int MaxBagMoves = 64;

		private static State _state;

		private static string _snapshot;

		private static float _deadline;

		private static int _movesLeft;

		private static int _movesDone;

		private static string _lastMoveText;

		private static bool _closeGaps;

		internal static void OnSortClicked()
		{
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			if (!ClientLink.Active)
			{
				World world;
				Entity character;
				Entity inventory;
				if (!RuleStore.Enabled || RuleStore.Rules.Count == 0)
				{
					PinVentoryPlugin.Logger.LogInfo((object)string.Concat(new string[5]
					{
						"Sort ignored: enabled=",
						RuleStore.Enabled.ToString(),
						", rules=",
						RuleStore.Rules.Count.ToString(),
						"."
					}));
				}
				else if (!GameAccess.TryGetInventory(out world, out character, out inventory))
				{
					PinVentoryPlugin.Logger.LogWarning((object)"Sort ignored: inventory not available.");
				}
				else
				{
					_snapshot = GameAccess.Snapshot(world.EntityManager, inventory);
					_deadline = Time.unscaledTime + PinVentoryPlugin.SortWaitSeconds.Value;
					_closeGaps = true;
					_state = State.WaitingForSort;
					PinVentoryPlugin.Logger.LogInfo((object)"Waiting for the sort result.");
				}
			}
		}

		internal static void ApplyNow()
		{
			_state = State.Idle;
			_closeGaps = false;
			Begin();
		}

		internal static void Tick()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			if (_state == State.Idle)
			{
				return;
			}
			if (!GameAccess.TryGetInventory(out var world, out var _, out var inventory))
			{
				_state = State.Idle;
				return;
			}
			bool flag = GameAccess.Snapshot(world.EntityManager, inventory) != _snapshot;
			bool flag2 = Time.unscaledTime >= _deadline;
			if (_state == State.WaitingForSort && (flag || flag2))
			{
				Begin();
			}
			else if (_state == State.WaitingForMove)
			{
				if (flag)
				{
					NextMove();
				}
				else if (flag2)
				{
					_state = State.Idle;
					GameAccess.ShowMessage("[PinVentory] Stopped: the server did not confirm " + _lastMoveText + ".");
					PinVentoryPlugin.Logger.LogWarning((object)("Move not confirmed: " + _lastMoveText));
				}
			}
		}

		private static void Begin()
		{
			_movesLeft = RuleStore.Rules.Count * 2 + 64;
			_movesDone = 0;
			NextMove();
		}

		private static void NextMove()
		{
			//IL_0022: 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_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: 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_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: 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_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			_state = State.Idle;
			if (!GameAccess.TryGetInventory(out var world, out var character, out var inventory))
			{
				return;
			}
			EntityManager entityManager = world.EntityManager;
			DynamicBuffer<InventoryBuffer> buffer = ((EntityManager)(ref entityManager)).GetBuffer<InventoryBuffer>(inventory, true);
			HashSet<int> val = new HashSet<int>();
			Enumerator<PinRule> enumerator = RuleStore.Rules.GetEnumerator();
			InventoryBuffer val2;
			try
			{
				while (enumerator.MoveNext())
				{
					PinRule current = enumerator.Current;
					int num = current.Slot - 1;
					if (num >= 0 && num < buffer.Length && buffer[num].Amount > 0)
					{
						val2 = buffer[num];
						if (((PrefabGUID)(ref val2.ItemType)).GuidHash == current.ItemGuid)
						{
							val.Add(num);
						}
					}
				}
			}
			finally
			{
				((System.IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
			}
			Enumerator<PinRule> enumerator2 = RuleStore.Rules.GetEnumerator();
			try
			{
				while (enumerator2.MoveNext())
				{
					PinRule current2 = enumerator2.Current;
					int num2 = current2.Slot - 1;
					if (num2 < 0 || num2 >= buffer.Length || val.Contains(num2))
					{
						continue;
					}
					for (int i = 0; i < buffer.Length; i++)
					{
						if (!val.Contains(i) && buffer[i].Amount > 0)
						{
							val2 = buffer[i];
							if (((PrefabGUID)(ref val2.ItemType)).GuidHash == current2.ItemGuid)
							{
								SendStep(world, character, inventory, i, num2, "'" + current2.Name + "' to slot " + current2.Slot);
								return;
							}
						}
					}
				}
			}
			finally
			{
				((System.IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose();
			}
			if (!_closeGaps || !TryCloseNextGap(world, character, inventory, buffer, val))
			{
				PinVentoryPlugin.Logger.LogInfo((object)("Done with " + _movesDone + " move(s)."));
			}
		}

		private static bool TryCloseNextGap(World world, Entity character, Entity inventory, DynamicBuffer<InventoryBuffer> buffer, HashSet<int> locked)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			int num = -1;
			for (int i = 8; i < buffer.Length; i++)
			{
				if (!locked.Contains(i) && buffer[i].Amount <= 0)
				{
					num = i;
					break;
				}
			}
			if (num < 0)
			{
				return false;
			}
			for (int j = num + 1; j < buffer.Length; j++)
			{
				if (!locked.Contains(j) && buffer[j].Amount > 0)
				{
					SendStep(world, character, inventory, j, num, "an item to slot " + (num + 1));
					return true;
				}
			}
			return false;
		}

		private static void SendStep(World world, Entity character, Entity inventory, int source, int target, string description)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if (_movesLeft <= 0)
			{
				PinVentoryPlugin.Logger.LogWarning((object)"Stopped after too many moves. Did the inventory change during sorting?");
				return;
			}
			_snapshot = GameAccess.Snapshot(world.EntityManager, inventory);
			_lastMoveText = description;
			if (!GameAccess.SendMove(world, character, source, target))
			{
				PinVentoryPlugin.Logger.LogWarning((object)("Could not send move: " + _lastMoveText));
				return;
			}
			PinVentoryPlugin.Logger.LogInfo((object)string.Concat(new string[5]
			{
				"Moving ",
				_lastMoveText,
				" from slot ",
				(source + 1).ToString(),
				"."
			}));
			_movesLeft--;
			_movesDone++;
			_deadline = Time.unscaledTime + PinVentoryPlugin.MoveTimeoutSeconds.Value;
			_state = State.WaitingForMove;
		}
	}
	internal static class Pinning
	{
		internal static void ToggleHoveredSlot(bool currentAmount)
		{
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0377: Unknown result type (might be due to invalid IL or missing references)
			//IL_037c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0392: Unknown result type (might be due to invalid IL or missing references)
			//IL_0397: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b1: Unknown result type (might be due to invalid IL or missing references)
			InventorySubMenu val = PinVentoryBehaviour.RefreshPlayerMenu(PinVentoryBehaviour.KnownMenus.Count == 0);
			if ((Object)(object)val == (Object)null)
			{
				PinVentoryPlugin.Logger.LogInfo((object)"Pin key: inventory is not open.");
				return;
			}
			if (!TryGetHoveredIndex(val, out var index, out var entry))
			{
				PinVentoryPlugin.Logger.LogInfo((object)string.Concat(new string[5]
				{
					"Pin key: no slot hovered (bag ",
					((object)val.InventorySelectionGroup?.HoveredEntryIndex/*cast due to .constrained prefix*/).ToString(),
					", hotbar ",
					((object)val.ActionSlotSelectionGroup?.HoveredEntryIndex/*cast due to .constrained prefix*/).ToString(),
					")."
				}));
				return;
			}
			if (!GameAccess.TryGetInventory(out var world, out var _, out var inventory))
			{
				PinVentoryPlugin.Logger.LogWarning((object)"Pin key: inventory not available.");
				return;
			}
			EntityManager entityManager = world.EntityManager;
			DynamicBuffer<InventoryBuffer> buffer = ((EntityManager)(ref entityManager)).GetBuffer<InventoryBuffer>(inventory, true);
			if (index >= buffer.Length)
			{
				PinVentoryPlugin.Logger.LogWarning((object)string.Concat(new string[5]
				{
					"Pin key: index ",
					index.ToString(),
					" is outside the inventory (",
					buffer.Length.ToString(),
					")."
				}));
				return;
			}
			List<ValueTuple<int, int>> val2 = (ClientLink.Active ? Enumerable.ToList<ValueTuple<int, int>>(Enumerable.Select<ServerPin, ValueTuple<int, int>>((System.Collections.Generic.IEnumerable<ServerPin>)ClientLink.Pins, (Func<ServerPin, ValueTuple<int, int>>)((ServerPin p) => new ValueTuple<int, int>(p.Slot, p.ItemGuid)))) : Enumerable.ToList<ValueTuple<int, int>>(Enumerable.Select<PinRule, ValueTuple<int, int>>((System.Collections.Generic.IEnumerable<PinRule>)RuleStore.Rules, (Func<PinRule, ValueTuple<int, int>>)((PinRule r) => new ValueTuple<int, int>(r.Slot, r.ItemGuid)))));
			int num = Enumerable.FirstOrDefault<int>(Enumerable.Select<ValueTuple<int, int>, int>(Enumerable.Where<ValueTuple<int, int>>((System.Collections.Generic.IEnumerable<ValueTuple<int, int>>)val2, (Func<ValueTuple<int, int>, bool>)((ValueTuple<int, int> p) => p.Item1 == index + 1)), (Func<ValueTuple<int, int>, int>)((ValueTuple<int, int> p) => p.Item2)));
			ManualLogSource logger = PinVentoryPlugin.Logger;
			string[] obj = new string[15]
			{
				"Pin key: slot ",
				(index + 1).ToString(),
				", inventory item ",
				null,
				null,
				null,
				null,
				null,
				null,
				null,
				null,
				null,
				null,
				null,
				null
			};
			InventoryBuffer val3 = buffer[index];
			obj[3] = ((PrefabGUID)(ref val3.ItemType)).GuidHash.ToString();
			obj[4] = " x";
			val3 = buffer[index];
			obj[5] = val3.Amount.ToString();
			obj[6] = ", UI item ";
			PrefabGUID entryId = entry.EntryId;
			obj[7] = ((PrefabGUID)(ref entryId)).GuidHash.ToString();
			obj[8] = ", pin here ";
			obj[9] = ((num != 0) ? num.ToString() : "none");
			obj[10] = ", ";
			obj[11] = (ClientLink.Active ? "server" : "fallback");
			obj[12] = " pins [";
			obj[13] = string.Join(", ", Enumerable.Select<ValueTuple<int, int>, string>((System.Collections.Generic.IEnumerable<ValueTuple<int, int>>)val2, (Func<ValueTuple<int, int>, string>)((ValueTuple<int, int> p) => p.Item1 + "=" + p.Item2)));
			obj[14] = "].";
			logger.LogInfo((object)string.Concat(obj));
			InventoryBuffer slot = buffer[index];
			bool flag = slot.Amount > 0;
			entryId = entry.EntryId;
			bool flag2 = ((PrefabGUID)(ref entryId)).GuidHash != 0;
			if (flag == flag2)
			{
				if (flag)
				{
					int guidHash = ((PrefabGUID)(ref slot.ItemType)).GuidHash;
					entryId = entry.EntryId;
					if (guidHash != ((PrefabGUID)(ref entryId)).GuidHash)
					{
						goto IL_03e2;
					}
				}
				int slot2 = index + 1;
				if (ClientLink.Active)
				{
					ClientLink.Send("hotkey " + slot2 + (currentAmount ? " now" : " whole"));
					return;
				}
				if (currentAmount)
				{
					GameAccess.ShowMessage("[PinVentory] Amounts need PinVentory on the server. Use " + PinVentoryPlugin.PinHotkey.Value + " to pin the slot.");
					return;
				}
				PinRule pinRule = RuleStore.Find(slot2);
				if (pinRule != null && (!flag || pinRule.ItemGuid == ((PrefabGUID)(ref slot.ItemType)).GuidHash))
				{
					RuleStore.Remove(slot2);
					PinVentoryPlugin.Logger.LogInfo((object)("Pin key: unpinned slot " + slot2 + "."));
					GameAccess.ShowMessage(string.Concat(new string[5]
					{
						"[PinVentory] Unpinned '",
						pinRule.Name,
						"' from slot ",
						slot2.ToString(),
						"."
					}));
					return;
				}
				if (!flag)
				{
					GameAccess.ShowMessage("[PinVentory] Slot " + slot2 + " is empty. Put the item there first.");
					return;
				}
				string itemName = GameAccess.GetItemName(world, slot.ItemType);
				PinRule pinRule2 = Enumerable.FirstOrDefault<PinRule>((System.Collections.Generic.IEnumerable<PinRule>)RuleStore.Rules, (Func<PinRule, bool>)((PinRule r) => r.ItemGuid == ((PrefabGUID)(ref slot.ItemType)).GuidHash));
				RuleStore.Set(slot2, ((PrefabGUID)(ref slot.ItemType)).GuidHash, itemName);
				string text = "";
				if (pinRule2 != null)
				{
					text = text + " (moved from slot " + pinRule2.Slot + ")";
				}
				if (pinRule != null)
				{
					text = text + ", replacing '" + pinRule.Name + "'";
				}
				PinVentoryPlugin.Logger.LogInfo((object)string.Concat(new string[6]
				{
					"Pin key: pinned ",
					((PrefabGUID)(ref slot.ItemType)).GuidHash.ToString(),
					" to slot ",
					slot2.ToString(),
					text,
					"."
				}));
				GameAccess.ShowMessage(string.Concat(new string[6]
				{
					"[PinVentory] Pinned '",
					itemName,
					"' to slot ",
					slot2.ToString(),
					text,
					"."
				}));
				return;
			}
			goto IL_03e2;
			IL_03e2:
			ManualLogSource logger2 = PinVentoryPlugin.Logger;
			string[] obj2 = new string[7] { "Hovered entry ", null, null, null, null, null, null };
			entryId = entry.EntryId;
			obj2[1] = ((PrefabGUID)(ref entryId)).GuidHash.ToString();
			obj2[2] = " does not match inventory index ";
			obj2[3] = index.ToString();
			obj2[4] = " (";
			obj2[5] = ((PrefabGUID)(ref slot.ItemType)).GuidHash.ToString();
			obj2[6] = ").";
			logger2.LogWarning((object)string.Concat(obj2));
			GameAccess.ShowMessage("[PinVentory] Could not read this slot, nothing changed.");
		}

		private static bool TryGetHoveredIndex(InventorySubMenu menu, out int index, out ItemGridSelectionEntry entry)
		{
			index = -1;
			entry = null;
			GridSelectionGroup<ItemGridSelectionEntry, Data> inventorySelectionGroup = menu.InventorySelectionGroup;
			if (inventorySelectionGroup != null && inventorySelectionGroup.HoveredEntryIndex >= 0 && inventorySelectionGroup.TryGetHoveredEntry(ref entry) && (Object)(object)entry != (Object)null)
			{
				index = inventorySelectionGroup.HoveredEntryIndex + 8;
				return true;
			}
			GridSelectionGroup<ItemGridSelectionEntry, Data> actionSlotSelectionGroup = menu.ActionSlotSelectionGroup;
			if (actionSlotSelectionGroup != null && actionSlotSelectionGroup.HoveredEntryIndex >= 0 && actionSlotSelectionGroup.TryGetHoveredEntry(ref entry) && (Object)(object)entry != (Object)null)
			{
				index = actionSlotSelectionGroup.HoveredEntryIndex;
				return true;
			}
			return false;
		}
	}
	internal static class ChatCommands
	{
		private const string Help = "[PinVentory] Hover an item in your inventory and press {0} to pin it to that slot.\n.pin list - show your pinned slots\n.pin remove <slot> - remove a pin\n.pin set <slot> <item name> - pin by name\n.pin apply - move pinned items now\n.pin toggle - switch the mod on or off";

		private const int MaxListedMatches = 8;

		internal static bool IsPinCommand(string text)
		{
			return text != null && (text.Equals(".pin", (StringComparison)5) || text.StartsWith(".pin ", (StringComparison)5));
		}

		internal static void Execute(string text)
		{
			string[] array = text.Trim().Split(new char[1] { ' ' }, 3, (StringSplitOptions)1);
			string text2 = ((array.Length > 1) ? array[1].ToLowerInvariant() : "");
			if (ClientLink.Active)
			{
				ClientLink.ExecuteCommand(text2, array);
				return;
			}
			string text3 = text2;
			string text4 = text3;
			switch (<PrivateImplementationDetails>.ComputeStringHash(text4))
			{
			case 217798785u:
				if (!(text4 == "list"))
				{
					break;
				}
				List();
				return;
			case 3683784189u:
				if (!(text4 == "remove"))
				{
					break;
				}
				Remove(array);
				return;
			case 3324446467u:
				if (!(text4 == "set"))
				{
					break;
				}
				Set(array);
				return;
			case 616319547u:
				if (!(text4 == "apply"))
				{
					break;
				}
				RuleApplier.ApplyNow();
				GameAccess.ShowMessage("[PinVentory] Moving pinned items.");
				return;
			case 1076453893u:
				if (!(text4 == "toggle"))
				{
					break;
				}
				GameAccess.ShowMessage("[PinVentory] Pinned slots " + (RuleStore.Toggle() ? "on." : "off."));
				return;
			case 2453644182u:
				if (!(text4 == "auto"))
				{
					break;
				}
				goto IL_018d;
			case 993596020u:
				{
					if (!(text4 == "add"))
					{
						break;
					}
					goto IL_018d;
				}
				IL_018d:
				GameAccess.ShowMessage("[PinVentory] '.pin " + text2 + "' needs PinVentory on the server. Here, use the pin key or .pin set and click Sort.");
				return;
			}
			GameAccess.ShowMessage($"[PinVentory] Hover an item in your inventory and press {PinVentoryPlugin.PinHotkey.Value} to pin it to that slot.\n.pin list - show your pinned slots\n.pin remove <slot> - remove a pin\n.pin set <slot> <item name> - pin by name\n.pin apply - move pinned items now\n.pin toggle - switch the mod on or off");
		}

		private static void List()
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			if (RuleStore.Rules.Count == 0)
			{
				GameAccess.ShowMessage("[PinVentory] No pinned slots yet.");
				return;
			}
			World clientWorld = GameAccess.GetClientWorld();
			StringBuilder val = new StringBuilder("[PinVentory] Pinned slots (" + (RuleStore.Enabled ? "on" : "off") + "):");
			Enumerator<PinRule> enumerator = RuleStore.Rules.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					PinRule current = enumerator.Current;
					string text = ((clientWorld != null) ? GameAccess.GetItemName(clientWorld, new PrefabGUID(current.ItemGuid)) : current.Name);
					val.Append('\n').Append(current.Slot).Append(": ")
						.Append(text);
				}
			}
			finally
			{
				((System.IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
			}
			GameAccess.ShowMessage(((object)val).ToString());
		}

		private static void Remove(string[] parts)
		{
			int slot = default(int);
			if (parts.Length < 3 || !int.TryParse(parts[2].Trim(), ref slot))
			{
				GameAccess.ShowMessage("[PinVentory] Usage: .pin remove <slot>");
			}
			else
			{
				GameAccess.ShowMessage(RuleStore.Remove(slot) ? ("[PinVentory] Removed the pin from slot " + slot + ".") : ("[PinVentory] Slot " + slot + " has no pin."));
			}
		}

		private static void Set(string[] parts)
		{
			if (TryParseSet(parts, out var _, out var slot, out var match))
			{
				RuleStore.Set(slot, match.Guid, match.DisplayName);
				GameAccess.ShowMessage(string.Concat(new string[5]
				{
					"[PinVentory] Pinned '",
					match.DisplayName,
					"' to slot ",
					slot.ToString(),
					"."
				}));
			}
		}

		internal static bool TryParseSet(string[] parts, out World world, out int slot, out ItemMatch match)
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			world = null;
			slot = 0;
			match = null;
			string[] array = ((parts.Length > 2) ? parts[2].Trim().Split(new char[1] { ' ' }, 2, (StringSplitOptions)1) : new string[0]);
			if (array.Length < 2 || !int.TryParse(array[0], ref slot) || slot < 1)
			{
				GameAccess.ShowMessage("[PinVentory] Usage: .pin set <slot> <item name>");
				return false;
			}
			if (!GameAccess.TryGetInventory(out world, out var _, out var inventory))
			{
				return false;
			}
			EntityManager entityManager = world.EntityManager;
			int length = ((EntityManager)(ref entityManager)).GetBuffer<InventoryBuffer>(inventory, true).Length;
			if (slot > length)
			{
				GameAccess.ShowMessage(string.Concat(new string[5]
				{
					"[PinVentory] Slot ",
					slot.ToString(),
					" does not exist. Your inventory has ",
					length.ToString(),
					" slots."
				}));
				return false;
			}
			return TryResolveItem(world, inventory, array[1].Trim(), out match);
		}

		private static bool TryResolveItem(World world, Entity inventory, string query, out ItemMatch match)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			match = null;
			List<ItemMatch> val = ItemSearch.Find(world, inventory, query);
			if (val.Count == 1)
			{
				match = val[0];
				return true;
			}
			if (val.Count == 0)
			{
				int num = default(int);
				GameAccess.ShowMessage("[PinVentory] No item found for '" + query + "'." + (int.TryParse(query, ref num) ? " To keep an amount, use .pin add <slot> <amount>." : ""));
				return false;
			}
			StringBuilder val2 = new StringBuilder("[PinVentory] Several items match. Use the internal name:");
			System.Collections.Generic.IEnumerator<ItemMatch> enumerator = Enumerable.Take<ItemMatch>((System.Collections.Generic.IEnumerable<ItemMatch>)val, 8).GetEnumerator();
			try
			{
				while (((System.Collections.IEnumerator)enumerator).MoveNext())
				{
					ItemMatch current = enumerator.Current;
					val2.Append('\n').Append(current.DisplayName).Append(": ")
						.Append(current.InternalName);
				}
			}
			finally
			{
				((System.IDisposable)enumerator)?.Dispose();
			}
			if (val.Count > 8)
			{
				val2.Append("\n...and ").Append(val.Count - 8).Append(" more.");
			}
			GameAccess.ShowMessage(((object)val2).ToString());
			return false;
		}
	}
	internal static class ClientLink
	{
		private const string Help = "[PinVentory] The server keeps your pins. Hover an item in your inventory and press {0} to pin the whole stack, or {1} to pin the current amount.\n.pin list - show your pinned slots\n.pin add <slot> - pin the item in this slot (whole stack)\n.pin add <slot> now - pin it and keep the current amount\n.pin add <slot> <amount> - pin it and keep this amount\n.pin remove <slot> - remove a pin\n.pin set <slot> <item name> - pin an item by name, even if you do not carry it\n.pin toggle - switch pinned slots on or off\n.pin auto - switch on or off that picked-up items go to their pinned slots right away";

		private static readonly Queue<string> Inbox = new Queue<string>();

		private static List<ServerPin> _pins = new List<ServerPin>();

		private static List<ServerPin> _incoming;

		private static bool _stateKnown;

		private static bool _enabled = true;

		private static bool _auto = true;

		private static bool _helloPending;

		private static System.IntPtr _world;

		[field: CompilerGenerated]
		[field: DebuggerBrowsable(/*Could not decode attribute arguments.*/)]
		internal static bool Active
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			private set;
		}

		internal static List<ServerPin> Pins => _pins;

		internal static bool PinsEnabled => _enabled;

		internal static void OnHello()
		{
			_helloPending = true;
		}

		internal static void OnHidden(string body)
		{
			Inbox.Enqueue(body);
		}

		internal static void Tick()
		{
			World clientWorld = GameAccess.GetClientWorld();
			System.IntPtr intPtr = ((clientWorld != null) ? ((Il2CppObjectBase)clientWorld).Pointer : System.IntPtr.Zero);
			if (Active && intPtr != _world)
			{
				Reset();
				PinVentoryPlugin.Logger.LogInfo((object)"Left the server, using the client-only fallback until the next greeting.");
			}
			if (clientWorld == null)
			{
				return;
			}
			if (_helloPending && Active)
			{
				_helloPending = false;
			}
			if (_helloPending)
			{
				_helloPending = false;
				Active = true;
				_world = intPtr;
				_stateKnown = false;
				Send("ready " + 1);
				PinVentoryPlugin.Logger.LogInfo((object)"Server runs PinVentory, the server keeps the pins now.");
			}
			while (Inbox.Count > 0)
			{
				string text = Inbox.Dequeue();
				try
				{
					Handle(clientWorld, text);
				}
				catch (System.Exception ex)
				{
					PinVentoryPlugin.Logger.LogError((object)("Server message '" + text + "' failed: " + (object)ex));
				}
			}
		}

		private static void Reset()
		{
			Active = false;
			_stateKnown = false;
			_pins = new List<ServerPin>();
			_incoming = null;
			Inbox.Clear();
		}

		internal static void Send(string text)
		{
			World clientWorld = GameAccess.GetClientWorld();
			if (clientWorld != null)
			{
				GameAccess.SendHidden(clientWorld, text);
				PinVentoryPlugin.Logger.LogInfo((object)("Sent to server: " + text));
			}
		}

		private static void Handle(World world, string body)
		{
			if (!Active)
			{
				return;
			}
			string[] array = body.Split(new char[1] { ' ' }, 2);
			string text = ((array.Length > 1) ? array[1] : "");
			string text2 = array[0];
			string text3 = text2;
			if (!(text3 == "state"))
			{
				if (!(text3 == "result"))
				{
					if (!(text3 == "toggled"))
					{
						if (!(text3 == "autotoggled"))
						{
							if (text3 == "error")
							{
								GameAccess.ShowMessage("[PinVentory] The server could not read your inventory, nothing changed.");
							}
							else
							{
								PinVentoryPlugin.Logger.LogWarning((object)("Unknown server message: " + body));
							}
						}
						else
						{
							GameAccess.ShowMessage("[PinVentory] Auto-arrange " + ((text.Trim() == "1") ? "on." : "off."));
						}
					}
					else
					{
						GameAccess.ShowMessage("[PinVentory] Pinned slots " + ((text.Trim() == "1") ? "on." : "off."));
					}
					return;
				}
				PinResult pinResult = PinResult.FromWire(text);
				if (pinResult != null)
				{
					GameAccess.ShowMessage("[PinVentory] " + pinResult.Format((int guid) => GameAccess.GetItemName(world, new PrefabGUID(guid))));
				}
			}
			else
			{
				ReadState(text);
			}
		}

		private static void ReadState(string text)
		{
			string[] array = text.Split(new char[1] { ' ' }, 4);
			int num = default(int);
			int num2 = default(int);
			if (array.Length < 3 || !int.TryParse(array[1], ref num) || !int.TryParse(array[2], ref num2))
			{
				PinVentoryPlugin.Logger.LogWarning((object)("Malformed pin state: " + text));
				return;
			}
			if (num == 1)
			{
				_incoming = new List<ServerPin>();
			}
			if (_incoming == null)
			{
				return;
			}
			string text2 = ((array.Length > 3) ? array[3] : "");
			string[] array2 = text2.Split(new char[1] { ';' }, (StringSplitOptions)1);
			int slot = default(int);
			int itemGuid = default(int);
			int target = default(int);
			foreach (string text3 in array2)
			{
				string[] array3 = text3.Split(':', (StringSplitOptions)0);
				if (array3.Length == 3 && int.TryParse(array3[0], ref slot) && int.TryParse(array3[1], ref itemGuid) && int.TryParse(array3[2], ref target))
				{
					_incoming.Add(new ServerPin
					{
						Slot = slot,
						ItemGuid = itemGuid,
						Target = target
					});
				}
			}
			if (num >= num2)
			{
				_pins = _incoming;
				_incoming = null;
				_enabled = array[0].StartsWith("1", (StringComparison)4);
				_auto = array[0].Length < 2 || array[0][1] == '1';
				_stateKnown = true;
				PinVentoryPlugin.Logger.LogInfo((object)string.Concat(new string[7]
				{
					"Pin list from the server: ",
					_pins.Count.ToString(),
					" pin(s), ",
					_enabled ? "on" : "off",
					", auto-arrange ",
					_auto ? "on" : "off",
					"."
				}));
			}
		}

		internal static void ExecuteCommand(string command, string[] parts)
		{
			string text = ((parts.Length > 2) ? parts[2].Trim() : "");
			switch (<PrivateImplementationDetails>.ComputeStringHash(command))
			{
			case 217798785u:
				if (!(command == "list"))
				{
					break;
				}
				List();
				return;
			case 993596020u:
			{
				if (!(command == "add"))
				{
					break;
				}
				string[] array = text.Split(new char[1] { ' ' }, (StringSplitOptions)1);
				int num = default(int);
				if (array.Length < 1 || array.Length > 2 || !int.TryParse(array[0], ref num) || !PinAmount.TryParse((array.Length > 1) ? array[1] : "", out var target))
				{
					GameAccess.ShowMessage("[PinVentory] Usage: .pin add <slot>, .pin add <slot> now or .pin add <slot> <amount>");
				}
				else
				{
					Send("add " + num + " " + target);
				}
				return;
			}
			case 3683784189u:
			{
				if (!(command == "remove"))
				{
					break;
				}
				int num2 = default(int);
				if (!int.TryParse(text, ref num2))
				{
					GameAccess.ShowMessage("[PinVentory] Usage: .pin remove <slot>");
				}
				else
				{
					Send("remove " + num2);
				}
				return;
			}
			case 3324446467u:
			{
				if (!(command == "set"))
				{
					break;
				}
				if (ChatCommands.TryParseSet(parts, out var _, out var slot, out var match))
				{
					Send("set " + slot + " " + match.Guid);
				}
				return;
			}
			case 1076453893u:
				if (!(command == "toggle"))
				{
					break;
				}
				Send("toggle");
				return;
			case 2453644182u:
				if (!(command == "auto"))
				{
					break;
				}
				Send("auto");
				return;
			case 616319547u:
				if (!(command == "apply"))
				{
					break;
				}
				GameAccess.ShowMessage("[PinVentory] Not needed here: the server keeps pinned items in place.");
				return;
			}
			GameAccess.ShowMessage($"[PinVentory] The server keeps your pins. Hover an item in your inventory and press {PinVentoryPlugin.PinHotkey.Value} to pin the whole stack, or {PinVentoryPlugin.PinCurrentAmountHotkey.Value} to pin the current amount.\n.pin list - show your pinned slots\n.pin add <slot> - pin the item in this slot (whole stack)\n.pin add <slot> now - pin it and keep the current amount\n.pin add <slot> <amount> - pin it and keep this amount\n.pin remove <slot> - remove a pin\n.pin set <slot> <item name> - pin an item by name, even if you do not carry it\n.pin toggle - switch pinned slots on or off\n.pin auto - switch on or off that picked-up items go to their pinned slots right away");
		}

		private static void List()
		{
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Expected O, but got Unknown
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			World clientWorld = GameAccess.GetClientWorld();
			if (!_stateKnown || clientWorld == null)
			{
				Send("ready " + 1);
				GameAccess.ShowMessage("[PinVentory] Waiting for the pin list from the server, please try again in a moment.");
				return;
			}
			if (_pins.Count == 0)
			{
				GameAccess.ShowMessage("[PinVentory] No pinned slots yet.");
				return;
			}
			StringBuilder val = new StringBuilder(string.Concat(new string[5]
			{
				"[PinVentory] Pinned slots (",
				_enabled ? "on" : "off",
				", auto-arrange ",
				_auto ? "on" : "off",
				"):"
			}));
			Enumerator<ServerPin> enumerator = _pins.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					ServerPin current = enumerator.Current;
					val.Append('\n').Append(current.Slot).Append(": ")
						.Append(GameAccess.GetItemName(clientWorld, new PrefabGUID(current.ItemGuid)))
						.Append(" (keep ")
						.Append(PinResult.KeepText(current.Target))
						.Append(')');
				}
			}
			finally
			{
				((System.IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
			}
			GameAccess.ShowMessage(((object)val).ToString());
		}
	}
	internal sealed class ItemMatch
	{
		public int Guid;

		public string DisplayName;

		public string InternalName;
	}
	internal static class ItemSearch
	{
		internal static List<ItemMatch> Find(World world, Entity inventory, string query)
		{
			//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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: 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_00a2: 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_00c5: Unknown result type (might be due to invalid IL or missing references)
			List<ItemMatch> allItems = GetAllItems(world);
			int guid = default(int);
			if (int.TryParse(query, ref guid))
			{
				return Enumerable.ToList<ItemMatch>(Enumerable.Where<ItemMatch>((System.Collections.Generic.IEnumerable<ItemMatch>)allItems, (Func<ItemMatch, bool>)((ItemMatch i) => i.Guid == guid)));
			}
			List<ItemMatch> val = Enumerable.ToList<ItemMatch>(Enumerable.Where<ItemMatch>((System.Collections.Generic.IEnumerable<ItemMatch>)allItems, (Func<ItemMatch, bool>)((ItemMatch i) => i.InternalName.Equals(query, (StringComparison)5))));
			if (val.Count > 0)
			{
				return val;
			}
			HashSet<int> carriedGuids = new HashSet<int>();
			EntityManager entityManager = world.EntityManager;
			DynamicBuffer<InventoryBuffer> buffer = ((EntityManager)(ref entityManager)).GetBuffer<InventoryBuffer>(inventory, true);
			for (int num = 0; num < buffer.Length; num++)
			{
				if (buffer[num].Amount > 0)
				{
					HashSet<int> obj = carriedGuids;
					InventoryBuffer val2 = buffer[num];
					obj.Add(((PrefabGUID)(ref val2.ItemType)).GuidHash);
				}
			}
			List<ItemMatch> val3 = Enumerable.ToList<ItemMatch>(Enumerable.Where<ItemMatch>((System.Collections.Generic.IEnumerable<ItemMatch>)allItems, (Func<ItemMatch, bool>)((ItemMatch i) => carriedGuids.Contains(i.Guid))));
			List<ItemMatch>[] array = new List<ItemMatch>[2] { val3, allItems };
			foreach (List<ItemMatch> val4 in array)
			{
				List<ItemMatch> val5 = Enumerable.ToList<ItemMatch>(Enumerable.Where<ItemMatch>((System.Collections.Generic.IEnumerable<ItemMatch>)val4, (Func<ItemMatch, bool>)((ItemMatch i) => i.DisplayName.Equals(query, (StringComparison)5))));
				if (val5.Count > 0)
				{
					return val5;
				}
				List<ItemMatch> val6 = Enumerable.ToList<ItemMatch>(Enumerable.Where<ItemMatch>((System.Collections.Generic.IEnumerable<ItemMatch>)val4, (Func<ItemMatch, bool>)((ItemMatch i) => i.DisplayName.IndexOf(query, (StringComparison)5) >= 0)));
				if (val6.Count > 0)
				{
					return val6;
				}
			}
			return new List<ItemMatch>();
		}

		private unsafe static List<ItemMatch> GetAllItems(World world)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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_0059: 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_0065: 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_0075: Unknown result type (might be due to invalid IL or missing references)
			GameDataSystem existingSystemManaged = world.GetExistingSystemManaged<GameDataSystem>();
			ManagedDataRegistry managedDataRegistry = existingSystemManaged.ManagedDataRegistry;
			List<ItemMatch> val = new List<ItemMatch>();
			Enumerator<PrefabGUID, ItemData> enumerator = existingSystemManaged.ItemHashLookupMap.GetEnumerator();
			while (enumerator.MoveNext())
			{
				PrefabGUID key = enumerator.Current.Key;
				ManagedItemData orDefault = managedDataRegistry.GetOrDefault<ManagedItemData>(key, (ManagedItemData)null);
				if (orDefault != null)
				{
					FixedString128Bytes val2 = default(FixedString128Bytes);
					PrefabLookupMap prefabLookupMap = managedDataRegistry._PrefabLookupMap;
					((PrefabLookupMap)(ref prefabLookupMap)).TryGetFixedName(key, ref val2);
					string text = Localization.Get(orDefault.Name, false);
					if (!string.IsNullOrEmpty(text))
					{
						val.Add(new ItemMatch
						{
							Guid = ((PrefabGUID)(ref key)).GuidHash,
							DisplayName = text,
							InternalName = ((object)(*(FixedString128Bytes*)(&val2))/*cast due to .constrained prefix*/).ToString()
						});
					}
				}
			}
			return val;
		}
	}
	[HarmonyPatch]
	internal static class ChatCommandPatch
	{
		[HarmonyPatch(typeof(ClientChatSystem), "ParseCommand")]
		[HarmonyPrefix]
		private static bool ParseCommandPrefix(string text)
		{
			if (!ChatCommands.IsPinCommand(text))
			{
				return true;
			}
			try
			{
				ChatCommands.Execute(text);
			}
			catch (System.Exception ex)
			{
				PinVentoryPlugin.Logger.LogError((object)("Command failed: " + (object)ex));
			}
			return false;
		}
	}
	[HarmonyPatch]
	internal static class ChatReceivePatch
	{
		[HarmonyPatch(typeof(ClientChatSystem), "OnUpdate")]
		[HarmonyPrefix]
		private unsafe static void Prefix(ClientChatSystem __instance)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: 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_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Invalid comparison between Unknown and I4
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			NativeArray<Entity> val = default(NativeArray<Entity>);
			try
			{
				EntityManager entityManager = ((ComponentSystemBase)__instance).EntityManager;
				EntityQuery receiveChatMessagesQuery = __instance._ReceiveChatMessagesQuery;
				val = ((EntityQuery)(ref receiveChatMessagesQuery)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2));
				Enumerator<Entity> enumerator = val.GetEnumerator();
				while (enumerator.MoveNext())
				{
					Entity current = enumerator.Current;
					if (!((EntityManager)(ref entityManager)).HasComponent<ChatMessageServerEvent>(current))
					{
						continue;
					}
					ChatMessageServerEvent componentData = ((EntityManager)(ref entityManager)).GetComponentData<ChatMessageServerEvent>(current);
					string text = ((object)(*(FixedString512Bytes*)(&componentData.MessageText))/*cast due to .constrained prefix*/).ToString();
					if ((text.StartsWith("[[PinVentory]]", (StringComparison)4) || text.StartsWith("PinVentory is active on this server. Type .pin for help.", (StringComparison)4)) && (int)componentData.MessageType != 6)
					{
						PinVentoryPlugin.Logger.LogInfo((object)("Ignored a PinVentory text in a " + ((object)(*(ServerChatMessageType*)(&componentData.MessageType))/*cast due to .constrained prefix*/).ToString() + " message."));
					}
					else if (text.StartsWith("[[PinVentory]]", (StringComparison)4))
					{
						((EntityManager)(ref entityManager)).DestroyEntity(current);
						ClientLink.OnHidden(text.Substring("[[PinVentory]]".Length));
					}
					else if (text.StartsWith("PinVentory is active on this server. Type .pin for help.", (StringComparison)4))
					{
						if (!PinVentoryPlugin.ShowGreeting.Value)
						{
							((EntityManager)(ref entityManager)).DestroyEntity(current);
						}
						if (!PinVentoryPlugin.ClientOnly)
						{
							ClientLink.OnHello();
						}
					}
				}
			}
			catch (System.Exception ex)
			{
				PinVentoryPlugin.Logger.LogError((object)("Chat check failed: " + ex.Message));
			}
			finally
			{
				if (val.IsCreated)
				{
					val.Dispose();
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class MenuPatch
	{
		[HarmonyPatch(typeof(InventorySubMenuMapper), "InitializeUI")]
		[HarmonyPostfix]
		private static void InitializeUIPostfix(InventorySubMenu menu)
		{
			try
			{
				PinVentoryBehaviour.RememberMenu(menu);
			}
			catch (System.Exception ex)
			{
				PinVentoryPlugin.Logger.LogError((object)("Menu registration failed: " + (object)ex));
			}
		}
	}
	internal static class SortButtonHandler
	{
		private static int _lastFrame = -1;

		internal static void OnClicked()
		{
			try
			{
				if (Time.frameCount != _lastFrame)
				{
					_lastFrame = Time.frameCount;
					PinVentoryPlugin.Logger.LogInfo((object)"Sort clicked.");
					RuleApplier.OnSortClicked();
				}
			}
			catch (System.Exception ex)
			{
				PinVentoryPlugin.Logger.LogError((object)("Sort handler failed: " + (object)ex));
			}
		}
	}
	public class PinVentoryBehaviour : MonoBehaviour
	{
		private const float MenuSearchIntervalSeconds = 0.25f;

		internal static readonly List<InventorySubMenu> KnownMenus = new List<InventorySubMenu>();

		private static readonly Hotkey PinKey = new Hotkey("PinHotkey", () => PinVentoryPlugin.PinHotkey.Value);

		private static readonly Hotkey CurrentKey = new Hotkey("PinCurrentAmountHotkey", () => PinVentoryPlugin.PinCurrentAmountHotkey.Value);

		internal static InventorySubMenu PlayerMenu;

		private static UnityAction _sortAction;

		private float _nextMenuSearch;

		public PinVentoryBehaviour(System.IntPtr ptr)
			: base(ptr)
		{
		}

		public PinVentoryBehaviour()
			: base(ClassInjector.DerivedConstructorPointer<PinVentoryBehaviour>())
		{
			ClassInjector.DerivedConstructorBody((Il2CppObjectBase)(object)this);
		}

		private void LateUpdate()
		{
			try
			{
				ClientLink.Tick();
				PinVisuals.Tick();
				FindPlayerMenu();
				RuleApplier.Tick();
				CheckHotkey();
			}
			catch (System.Exception ex)
			{
				PinVentoryPlugin.Logger.LogError((object)("Update failed: " + (object)ex));
			}
		}

		private void FindPlayerMenu()
		{
			if (!(Time.unscaledTime < _nextMenuSearch))
			{
				_nextMenuSearch = Time.unscaledTime + 0.25f;
				RefreshPlayerMenu(allowScan: false);
			}
		}

		internal static void RememberMenu(InventorySubMenu menu)
		{
			if (!((Object)(object)menu == (Object)null) && !Enumerable.Any<InventorySubMenu>((System.Collections.Generic.IEnumerable<InventorySubMenu>)KnownMenus, (Func<InventorySubMenu, bool>)((InventorySubMenu m) => (Object)(object)m != (Object)null && ((Il2CppObjectBase)m).Pointer == ((Il2CppObjectBase)menu).Pointer)))
			{
				KnownMenus.Add(menu);
				PinVentoryPlugin.Logger.LogInfo((object)string.Concat(new string[5]
				{
					"Inventory menu registered (",
					((Object)menu).name,
					"), ",
					KnownMenus.Count.ToString(),
					" known."
				}));
			}
		}

		internal static InventorySubMenu RefreshPlayerMenu(bool allowScan)
		{
			KnownMenus.RemoveAll((Predicate<InventorySubMenu>)((InventorySubMenu m) => (Object)(object)m == (Object)null));
			InventorySubMenu val = FindVisible();
			if ((Object)(object)val == (Object)null && allowScan)
			{
				ScanForMenus();
				val = FindVisible();
			}
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			HookSortButton(val);
			if ((Object)(object)PlayerMenu == (Object)null || ((Il2CppObjectBase)PlayerMenu).Pointer != ((Il2CppObjectBase)val).Pointer)
			{
				PinVentoryPlugin.Logger.LogInfo((object)("Using inventory menu " + ((Object)val).name + ", sort button hooked."));
			}
			PlayerMenu = val;
			return val;
		}

		private static InventorySubMenu FindVisible()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			Enumerator<InventorySubMenu> enumerator = KnownMenus.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					InventorySubMenu current = enumerator.Current;
					if ((Object)(object)current != (Object)null && current.IsPlayerInventory && (Object)(object)current.AllSortButton != (Object)null && ((Component)current).gameObject.activeInHierarchy)
					{
						return current;
					}
				}
			}
			finally
			{
				((System.IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
			}
			return null;
		}

		private static void ScanForMenus()
		{
			Il2CppArrayBase<InventorySubMenu> val = Object.FindObjectsOfType<InventorySubMenu>();
			if (val != null && val.Length != 0)
			{
				PinVentoryPlugin.Logger.LogInfo((object)("Menu scan found " + val.Length + " inventory menu(s)."));
				for (int i = 0; i < val.Length; i++)
				{
					RememberMenu(val[i]);
				}
			}
		}

		private static void HookSortButton(InventorySubMenu menu)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			if ((Delegate)(object)_sortAction == (Delegate)null)
			{
				_sortAction = DelegateSupport.ConvertDelegate<UnityAction>((System.Delegate)new Action(SortButtonHandler.OnClicked));
			}
			ButtonClickedEvent onClick = menu.AllSortButton.onClick;
			((UnityEvent)onClick).RemoveListener(_sortAction);
			((UnityEvent)onClick).AddListener(_sortAction);
		}

		private void CheckHotkey()
		{
			bool flag = PinKey.WasPressed();
			bool flag2 = CurrentKey.WasPressed();
			if (flag || flag2)
			{
				Pinning.ToggleHoveredSlot(flag2 && !flag);
			}
		}
	}
	internal sealed class Hotkey
	{
		private const int VkControl = 17;

		private const int VkShift = 16;

		private const int VkAlt = 18;

		private readonly string _settingName;

		private readonly Func<string> _setting;

		private string _parsed;

		private int _key;

		private bool _control;

		private bool _shift;

		private bool _alt;

		private bool _wasDown;

		internal Hotkey(string settingName, Func<string> setting)
		{
			_settingName = settingName;
			_setting = setting;
		}

		[DllImport("user32.dll")]
		private static extern short GetAsyncKeyState(int key);

		private static bool IsDown(int key)
		{
			return (GetAsyncKeyState(key) & 0x8000) != 0;
		}

		internal bool WasPressed()
		{
			Parse();
			if (_key == 0)
			{
				return false;
			}
			bool flag = IsDown(_key);
			bool flag2 = flag && !_wasDown;
			_wasDown = flag;
			return flag2 && Application.isFocused && IsDown(17) == _control && IsDown(16) == _shift && IsDown(18) == _alt;
		}

		private void Parse()
		{
			string text = _setting.Invoke();
			if (text == _parsed)
			{
				return;
			}
			_parsed = text;
			_key = 0;
			_control = false;
			_shift = false;
			_alt = false;
			string[] array = (text ?? "").Split('+', (StringSplitOptions)0);
			int num = default(int);
			foreach (string text2 in array)
			{
				string text3 = text2.Trim().ToUpperInvariant();
				if (text3 == "CTRL" || text3 == "CONTROL")
				{
					_control = true;
				}
				else if (text3 == "SHIFT")
				{
					_shift = true;
				}
				else if (text3 == "ALT")
				{
					_alt = true;
				}
				else if (text3.Length == 1 && char.IsLetterOrDigit(text3[0]))
				{
					_key = text3[0];
				}
				else if (text3.Length >= 2 && text3[0] == 'F' && int.TryParse(text3.Substring(1), ref num) && num >= 1 && num <= 12)
				{
					_key = 112 + num - 1;
				}
				else
				{
					_key = 0;
				}
			}
			if (_key == 0)
			{
				PinVentoryPlugin.Logger.LogWarning((object)(_settingName + " '" + text + "' is not valid. Use a letter, digit or F1-F12 with optional Ctrl, Shift, Alt."));
			}
		}
	}
	internal static class ServerSide
	{
		internal const int FirstBagIndex = 8;

		private static bool _equipmentWarned;

		private static Dictionary<int, string> _prefabNames;

		internal static void Load(Harmony harmony)
		{
			harmony.PatchAll(typeof(ServerSortPatch));
			harmony.PatchAll(typeof(ServerQuickSendPatch));
			harmony.PatchAll(typeof(ServerConnectPatch));
			harmony.PatchAll(typeof(ServerLink));
			harmony.PatchAll(typeof(AutoArrangePatch));
			CommandRegistry.RegisterAll();
		}

		internal static World ServerWorld()
		{
			Enumerator<World> enumerator = World.s_AllWorlds.GetEnumerator();
			while (enumerator.MoveNext())
			{
				World current = enumerator.Current;
				if (current != null && current.Name == "Server")
				{
					return current;
				}
			}
			return null;
		}

		internal static bool TryGetPlayer(EntityManager em, Entity character, out ulong platformId)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			platformId = 0uL;
			if (character == Entity.Null || !((EntityManager)(ref em)).Exists(character) || !((EntityManager)(ref em)).HasComponent<PlayerCharacter>(character))
			{
				return false;
			}
			Entity userEntity = ((EntityManager)(ref em)).GetComponentData<PlayerCharacter>(character).UserEntity;
			if (userEntity == Entity.Null || !((EntityManager)(ref em)).HasComponent<User>(userEntity))
			{
				return false;
			}
			platformId = ((EntityManager)(ref em)).GetComponentData<User>(userEntity).PlatformId;
			return true;
		}

		internal static int MaxStack(PrefabGUID item)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			World obj = ServerWorld();
			GameDataSystem val = ((obj != null) ? obj.GetExistingSystemManaged<GameDataSystem>() : null);
			ItemData val2 = default(ItemData);
			if (val != null && val.ItemHashLookupMap.TryGetValue(item, ref val2))
			{
				return val2.MaxAmount;
			}
			return 0;
		}

		internal static bool IsPlainStack(InventoryBuffer entry)
		{
			//IL_0008: 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)
			return ((NetworkedEntity)(ref entry.ItemEntity)).GetEntityOnServer() == Entity.Null;
		}

		internal static bool IsEquipped(EntityManager em, Entity character, InventoryBuffer entry)
		{
			//IL_0008: 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_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			Entity entityOnServer = ((NetworkedEntity)(ref entry.ItemEntity)).GetEntityOnServer();
			if (entityOnServer == Entity.Null)
			{
				return false;
			}
			try
			{
				if (character != Entity.Null && ((EntityManager)(ref em)).Exists(character) && ((EntityManager)(ref em)).HasComponent<Equipment>(character))
				{
					Equipment componentData = ((EntityManager)(ref em)).GetComponentData<Equipment>(character);
					return ((Equipment)(ref componentData)).IsEquipped(entityOnServer);
				}
			}
			catch (System.Exception ex)
			{
				if (!_equipmentWarned)
				{
					_equipmentWarned = true;
					PinVentoryPlugin.Logger.LogWarning((object)("Could not read the character's equipment, items with their own entity stay on the hotbar: " + ex.Message));
				}
			}
			return true;
		}

		internal static string PrefabName(int guid)
		{
			//IL_0058: 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 (_prefabNames == null)
			{
				_prefabNames = new Dictionary<int, string>();
				try
				{
					World obj = ServerWorld();
					PrefabCollectionSystem val = ((obj != null) ? obj.GetExistingSystemManaged<PrefabCollectionSystem>() : null);
					if (val != null)
					{
						Enumerator<string, PrefabGUID> enumerator = val._SpawnableNameToPrefabGuidDictionary.GetEnumerator();
						while (enumerator.MoveNext())
						{
							KeyValuePair<string, PrefabGUID> current = enumerator.Current;
							Dictionary<int, string> prefabNames = _prefabNames;
							PrefabGUID value = current.Value;
							prefabNames[((PrefabGUID)(ref value)).GuidHash] = current.Key;
						}
					}
				}
				catch (System.Exception ex)
				{
					PinVentoryPlugin.Logger.LogWarning((object)("Prefab names unavailable: " + ex.Message));
				}
			}
			string text = default(string);
			return _prefabNames.TryGetValue(guid, ref text) ? text : ("Item " + guid);
		}
	}
	internal static class Protocol
	{
		internal const string Marker = "[[PinVentory]]";

		internal const int Version = 1;

		internal const string Hello = "PinVentory is active on this server. Type .pin for help.";
	}
	internal static class PinAmount
	{
		internal const string Usage = ".pin add <slot>, .pin add <slot> now or .pin add <slot> <amount>";

		internal static bool TryParse(string text, out int target)
		{
			text = (text ?? "").Trim();
			if (text.Length == 0)
			{
				target = 0;
				return true;
			}
			if (text.Equals("now", (StringComparison)5))
			{
				target = -1;
				return true;
			}
			return int.TryParse(text, ref target) && target > 0;
		}
	}
	internal sealed class PinResult
	{
		internal const string Pinned = "pinned";

		internal const string Unpinned = "unpinned";

		internal const string NoPin = "nopin";

		internal const string Empty = "empty";

		internal const string NoSlot = "noslot";

		internal string Code;

		internal int Slot;

		internal int Item;

		internal int Keep;

		internal int Replaced;

		internal bool Moved;

		internal int Size;

		internal string ToWire()
		{
			return string.Concat(new string[13]
			{
				Code,
				" ",
				Slot.ToString(),
				" ",
				Item.ToString(),
				" ",
				Keep.ToString(),
				" ",
				Replaced.ToString(),
				" ",
				(Moved ? 1 : 0).ToString(),
				" ",
				Size.ToString()
			});
		}

		internal static PinResult FromWire(string text)
		{
			string[] array = (text ?? "").Split(new char[1] { ' ' }, (StringSplitOptions)1);
			if (array.Length < 7)
			{
				return null;
			}
			PinResult pinResult = new PinResult
			{
				Code = array[0]
			};
			if (!int.TryParse(array[1], ref pinResult.Slot) || !int.TryParse(array[2], ref pinResult.Item) || !int.TryParse(array[3], ref pinResult.Keep) || !int.TryParse(array[4], ref pinResult.Replaced) || !int.TryParse(array[6], ref pinResult.Size))
			{
				return null;
			}
			pinResult.Moved = array[5] == "1";
			return pinResult;
		}

		internal static string KeepText(int keep)
		{
			return (keep == 0) ? "the whole stack" : keep.ToString();
		}

		internal string Format(Func<int, string> name)
		{
			string code = Code;
			string text = code;
			if (!(text == "pinned"))
			{
				if (!(text == "unpinned"))
				{
					if (!(text == "nopin"))
					{
						if (!(text == "empty"))
						{
							if (text == "noslot")
							{
								return string.Concat(new string[5]
								{
									"Slot ",
									Slot.ToString(),
									" does not exist. Your inventory has ",
									Size.ToString(),
									" slots."
								});
							}
							return "Unknown result '" + Code + "'.";
						}
						return "Slot " + Slot + " is empty. Put the item there first.";
					}
					return "Slot " + Slot + " has no pin.";
				}
				return string.Concat(new string[5]
				{
					"Removed the pin of ",
					name.Invoke(Item),
					" from slot ",
					Slot.ToString(),
					"."
				});
			}
			return string.Concat(new string[8]
			{
				"Pinned ",
				name.Invoke(Item),
				" to slot ",
				Slot.ToString(),
				", keeping ",
				KeepText(Keep),
				(Replaced != 0) ? (", replacing " + name.Invoke(Replaced)) : "",
				Moved ? " (pin moved)." : "."
			});
		}
	}
	public sealed class ServerPin
	{
		[field: CompilerGenerated]
		[field: DebuggerBrowsable(/*Could not decode attribute arguments.*/)]
		public int Slot
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		}

		[field: CompilerGenerated]
		[field: DebuggerBrowsable(/*Could not decode attribute arguments.*/)]
		public int ItemGuid
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		}

		[field: CompilerGenerated]
		[field: DebuggerBrowsable(/*Could not decode attribute arguments.*/)]
		public int Target
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		}
	}
	public sealed class ServerPlayerPins
	{
		[field: CompilerGenerated]
		[field: DebuggerBrowsable(/*Could not decode attribute arguments.*/)]
		public bool Enabled
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = true;

		[field: CompilerGenerated]
		[field: DebuggerBrowsable(/*Could not decode attribute arguments.*/)]
		public bool AutoArrange
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = true;

		[field: CompilerGenerated]
		[field: DebuggerBrowsable(/*Could not decode attribute arguments.*/)]
		public List<ServerPin> Pins
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = new List<ServerPin>();
	}
	internal static class ServerPinStore
	{
		private static readonly string Folder = Path.Combine(Paths.ConfigPath, "PinVentory", "players");

		private static readonly JsonSerializerOptions IndentedJson = new JsonSerializerOptions
		{
			WriteIndented = true
		};

		private static readonly Dictionary<ulong, ServerPlayerPins> Cache = new Dictionary<ulong, ServerPlayerPins>();

		internal const int WholeStack = 0;

		internal const int CurrentAmount = -1;

		internal static ServerPlayerPins Get(ulong platformId)
		{
			ServerPlayerPins result = default(ServerPlayerPins);
			if (Cache.TryGetValue(platformId, ref result))
			{
				return result;
			}
			result = new ServerPlayerPins();
			string text = Path.Combine(Folder, platformId + ".json");
			if (File.Exists(text))
			{
				try
				{
					result = JsonSerializer.Deserialize<ServerPlayerPins>(File.ReadAllText(text), (JsonSerializerOptions)null) ?? new ServerPlayerPins();
					result.Pins = Enumerable.ToList<ServerPin>((System.Collections.Generic.IEnumerable<ServerPin>)Enumerable.OrderBy<ServerPin, int>(Enumerable.Select<IGrouping<int, ServerPin>, ServerPin>(Enumerable.GroupBy<ServerPin, int>(Enumerable.Where<ServerPin>((System.Collections.Generic.IEnumerable<ServerPin>)result.Pins, (Func<ServerPin, bool>)((ServerPin p) => p != null && p.Slot > 0 && p.ItemGuid != 0)), (Func<ServerPin, int>)((ServerPin p) => p.Slot)), (Func<IGrouping<int, ServerPin>, ServerPin>)((IGrouping<int, ServerPin> g) => Enumerable.Last<ServerPin>((System.Collections.Generic.IEnumerable<ServerPin>)g))), (Func<ServerPin, int>)((ServerPin p) => p.Slot)));
				}
				catch (System.Exception ex)
				{
					File.Copy(text, text + ".bad", true);
					PinVentoryPlugin.Logger.LogError((object)("Could not read " + text + ", saved a copy as .bad: " + ex.Message));
				}
			}
			Cache[platformId] = result;
			return result;
		}

		internal static void Save(ulong platformId)
		{
			Directory.CreateDirectory(Folder);
			string text = Path.Combine(Folder, platformId + ".json");
			string text2 = text + ".tmp";
			File.WriteAllText(text2, JsonSerializer.Serialize<ServerPlayerPins>(Get(platformId), IndentedJson));
			File.Move(text2, text, true);
		}

		internal static bool HasActivePins(ulong platformId)
		{
			ServerPlayerPins serverPlayerPins = Get(platformId);
			return serverPlayerPins.Enabled && serverPlayerPins.Pins.Count > 0;
		}

		internal static PinResult Pin(ulong platformId, DynamicBuffer<InventoryBuffer> buffer, int slot, int target = 0, int item = 0)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			int num = slot - 1;
			if (num < 0 || num >= buffer.Length)
			{
				return new PinResult
				{
					Code = "noslot",
					Slot = slot,
					Size = buffer.Length
				};
			}
			bool flag = buffer[num].Amount > 0;
			if (item == 0)
			{
				if (!flag)
				{
					return new PinResult
					{
						Code = "empty",
						Slot = slot
					};
				}
				InventoryBuffer val = buffer[num];
				item = ((PrefabGUID)(ref val.ItemType)).GuidHash;
			}
			int num2 = ((target != -1) ? Math.Max(target, 0) : (Holds(buffer, slot, item) ? buffer[num].Amount : 0));
			int num3 = ServerSide.MaxStack(new PrefabGUID(item));
			if (num3 > 0 && num2 >= num3)
			{
				num2 = 0;
			}
			ServerPlayerPins serverPlayerPins = Get(platformId);
			int num4 = serverPlayerPins.Pins.RemoveAll((Predicate<ServerPin>)((ServerPin p) => p.ItemGuid == item && p.Slot != slot && !Holds(buffer, p.Slot, item)));
			ServerPin serverPin = Enumerable.FirstOrDefault<ServerPin>((System.Collections.Generic.IEnumerable<ServerPin>)serverPlayerPins.Pins, (Func<ServerPin, bool>)((ServerPin p) => p.Slot == slot && p.ItemGuid != item));
			serverPlayerPins.Pins.RemoveAll((Predicate<ServerPin>)((ServerPin p) => p.Slot == slot));
			serverPlayerPins.Pins.Add(new ServerPin
			{
				Slot = slot,
				ItemGuid = item,
				Target = num2
			});
			serverPlayerPins.Pins = Enumerable.ToList<ServerPin>((System.Collections.Generic.IEnumerable<ServerPin>)Enumerable.OrderBy<ServerPin, int>((System.Collections.Generic.IEnumerable<ServerPin>)serverPlayerPins.Pins, (Func<ServerPin, int>)((ServerPin p) => p.Slot)));
			Save(platformId);
			return new PinResult
			{
				Code = "pinned",
				Slot = slot,
				Item = item,
				Keep = num2,
				Replaced = (serverPin?.ItemGuid ?? 0),
				Moved = (num4 > 0)
			};
		}

		internal static PinResult Unpin(ulong platformId, int slot)
		{
			ServerPin serverPin = Enumerable.FirstOrDefault<ServerPin>((System.Collections.Generic.IEnumerable<ServerPin>)Get(platformId).Pins, (Func<ServerPin, bool>)((ServerPin p) => p.Slot == slot));
			if (serverPin == null)
			{
				return new PinResult
				{
					Code = "nopin",
					Slot = slot
				};
			}
			Get(platformId).Pins.Remove(serverPin);
			Save(platformId);
			return new PinResult
			{
				Code = "unpinned",
				Slot = slot,
				Item = serverPin.ItemGuid
			};
		}

		internal static PinResult Hotkey(ulong platformId, DynamicBuffer<InventoryBuffer> buffer, int slot, bool currentAmount)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: 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)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			int num = slot - 1;
			if (num < 0 || num >= buffer.Length)
			{
				return new PinResult
				{
					Code = "noslot",
					Slot = slot,
					Size = buffer.Length
				};
			}
			bool flag = buffer[num].Amount > 0;
			ServerPin serverPin = Enumerable.FirstOrDefault<ServerPin>((System.Collections.Generic.IEnumerable<ServerPin>)Get(platformId).Pins, (Func<ServerPin, bool>)((ServerPin p) => p.Slot == slot));
			if (!currentAmount && serverPin != null)
			{
				if (flag)
				{
					int itemGuid = serverPin.ItemGuid;
					InventoryBuffer val = buffer[num];
					if (itemGuid != ((PrefabGUID)(ref val.ItemType)).GuidHash)
					{
						goto IL_00d4;
					}
				}
				return Unpin(platformId, slot);
			}
			goto IL_00d4;
			IL_00d4:
			return Pin(platformId, buffer, slot, currentAmount ? (-1) : 0);
		}

		internal static List<string> StateMessages(ulong platformId)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			ServerPlayerPins serverPlayerPins = Get(platformId);
			List<string> val = new List<string>();
			StringBuilder val2 = new StringBuilder();
			Enumerator<ServerPin> enumerator = serverPlayerPins.Pins.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					ServerPin current = enumerator.Current;
					string text = string.Concat(new string[6]
					{
						current.Slot.ToString(),
						":",
						current.ItemGuid.ToString(),
						":",
						current.Target.ToString(),
						";"
					});
					if (val2.Length + text.Length > 380)
					{
						val.Add(((object)val2).ToString());
						val2.Clear();
					}
					val2.Append(text);
				}
			}
			finally
			{
				((System.IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
			}
			val.Add(((object)val2).ToString());
			List<string> val3 = new List<string>();
			for (int i = 0; i < val.Count; i++)
			{
				val3.Add(string.Concat(new string[9]
				{
					"state ",
					serverPlayerPins.Enabled ? "1" : "0",
					serverPlayerPins.AutoArrange ? "1" : "0",
					" ",
					(i + 1).ToString(),
					" ",
					val.Count.ToString(),
					" ",
					val[i]
				}));
			}
			return val3;
		}

		internal static bool Holds(DynamicBuffer<InventoryBuffer> buffer, int slot, int item)
		{
			//IL_0016: 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_002b: Unknown result type (might be due to invalid IL or missing references)
			int num = slot - 1;
			int result;
			if (num >= 0 && num < buffer.Length && buffer[num].Amount > 0)
			{
				InventoryBuffer val = buffer[num];
				result = ((((PrefabGUID)(ref val.ItemType)).GuidHash == item) ? 1 : 0);
			}
			else
			{
				result = 0;
			}
			return (byte)result != 0;
		}
	}
	internal sealed class HiddenStacks
	{
		internal readonly Entity Character;

		internal readonly Entity Inventory;

		internal readonly ulong PlatformId;

		internal readonly Dictionary<int, InventoryBuffer> BySlotIndex = new Dictionary<int, InventoryBuffer>();

		private readonly string _context;

		private HiddenStacks(Entity character, Entity inventory, ulong platformId, string context)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			Character = character;
			Inventory = inventory;
			PlatformId = platformId;
			_context = context;
		}

		internal static HiddenStacks Hide(EntityManager em, Entity character, string context, bool keepIfEmpty = false)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: 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_00dd: 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)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			Entity val = default(Entity);
			if (!ServerSide.TryGetPlayer(em, character, out var platformId) || !ServerPinStore.HasActivePins(platformId) || !InventoryUtilities.TryGetInventoryEntity<EntityManager>(em, character, ref val, 0))
			{
				return null;
			}
			HiddenStacks hiddenStacks = new HiddenStacks(character, val, platformId, context);
			DynamicBuffer<InventoryBuffer> buffer = ((EntityManager)(ref em)).GetBuffer<InventoryBuffer>(val, false);
			InventoryBuffer val2 = EmptyEntry(buffer);
			Enumerator<ServerPin> enumerator = ServerPinStore.Get(platformId).Pins.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					ServerPin current = enumerator.Current;
					int num = current.Slot - 1;
					if (ServerPinStore.Holds(buffer, current.Slot, current.ItemGuid))
					{
						InventoryBuffer val3 = buffer[num];
						int num2 = ((current.Target > 0) ? Math.Min(val3.Amount, current.Target) : val3.Amount);
						if (num2 < val3.Amount && ServerSide.IsPlainStack(val3))
						{
							InventoryBuffer val4 = val3;
							val4.Amount = num2;
							InventoryBuffer val5 = val3;
							val5.Amount = val3.Amount - num2;
							hiddenStacks.BySlotIndex[num] = val4;
							buffer[num] = val5;
						}
						else
						{
							hiddenStacks.BySlotIndex[num] = val3;
							buffer[num] = val2;
						}
					}
				}
			}
			finally
			{
				((System.IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
			}
			if (hiddenStacks.BySlotIndex.Count == 0)
			{
				return keepIfEmpty ? hiddenStacks : null;
			}
			PinVentoryPlugin.Logger.LogInfo((object)(context + ": hid " + string.Join(", ", Enumerable.Select<KeyValuePair<int, InventoryBuffer>, string>((System.Collections.Generic.IEnumerable<KeyValuePair<int, InventoryBuffer>>)hiddenStacks.BySlotIndex, (Func<KeyValuePair<int, InventoryBuffer>, string>)delegate(KeyValuePair<in