Decompiled source of PEAK Tool Belt v2.0.0

tony4twentys-PEAK Tool Belt.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using Zorro.Core;
using Zorro.Core.Serizalization;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: AssemblyTitle("PEAK Tool Belt")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("PEAK Tool Belt")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("5790c129-81b9-40c2-bbe5-e13b4d2fbd84")]
[assembly: AssemblyFileVersion("2.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.0.0.0")]
[module: UnverifiableCode]
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}
namespace PEAK_Tool_Belt
{
	[BepInPlugin("tony4twentys.PEAK_Tool_Belt", "PEAK Tool Belt", "2.0.0")]
	[BepInProcess("PEAK.exe")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "tony4twentys.PEAK_Tool_Belt";

		public const string PluginName = "PEAK Tool Belt";

		public const string PluginVersion = "2.0.0";

		public const byte EventCode = 165;

		public const string EventMagic = "tony4twentys.PEAK_Tool_Belt";

		public const int ProtocolVersion = 2;

		public ConfigEntry<KeyCode> OpenToolBelt;

		public ConfigEntry<KeyCode> MenuKey;

		public ConfigEntry<KeyCode> MenuModifier;

		public ConfigEntry<bool> RequireMenuModifier;

		public ConfigEntry<bool> ShowPauseMenuButton;

		public ConfigEntry<int> Columns;

		private Harmony _harmony;

		private bool _open;

		private int _selected = -1;

		private float _lastGrantTime;

		private string _sceneName = string.Empty;

		private bool _validScene;

		private CursorLockMode _prevLock;

		private bool _prevCursorVisible;

		private Vector2 _frozenLookValues;

		private bool _hasFrozenLook;

		private bool _loggedEmptyBelt;

		private float _canUseCachedAt = -1f;

		private bool _canUseCached;

		public static Plugin Instance { get; private set; }

		public static ManualLogSource Log { get; private set; }

		internal bool IsOpen => _open;

		internal int SelectedIndex => _selected;

		private void Awake()
		{
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Expected O, but got Unknown
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			OpenToolBelt = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "OpenToolBelt", (KeyCode)116, "Hold to open the tool belt. Hover a slot, then release to take that item.");
			MenuKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "MenuKey", (KeyCode)106, "Open the Tool Belt setup menu.");
			MenuModifier = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "MenuModifier", (KeyCode)306, "Modifier used with MenuKey when RequireMenuModifier is on. Default LeftControl (Ctrl+J).");
			RequireMenuModifier = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RequireMenuModifier", true, "If on, the setup menu needs MenuModifier + MenuKey (Ctrl+J). If off, MenuKey alone opens it.");
			ShowPauseMenuButton = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowPauseMenuButton", false, "Show a Tool Belt button on the pause menu.");
			Columns = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Columns", 5, "Belt slots per row.");
			Columns.SettingChanged += OnColumnsChanged;
			_harmony = new Harmony("tony4twentys.PEAK_Tool_Belt");
			_harmony.PatchAll(typeof(Plugin).Assembly);
			SceneManager.sceneLoaded += OnSceneLoaded;
			SceneManager.activeSceneChanged += OnActiveSceneChanged;
			BeltStore.Initialize();
			BeltPresetStore.Initialize();
			ToolBeltItems.LoadLocal();
			ToolBeltMenu.EnsureCreated();
			ToolBeltNet.Ensure();
			Scene activeScene = SceneManager.GetActiveScene();
			CheckScene(((Scene)(ref activeScene)).name);
			((MonoBehaviour)this).StartCoroutine(WaitForItemDatabase());
			Log.LogInfo((object)("PEAK Tool Belt v2.0.0 loaded. Open the menu with " + FormatMenuHotkey() + "."));
		}

		private IEnumerator WaitForItemDatabase()
		{
			float elapsed = 0f;
			while (!ToolBeltItems.DatabaseReady())
			{
				elapsed += 0.25f;
				if (elapsed > 120f)
				{
					Log.LogError((object)"Item database never loaded. Tool belt cannot list items.");
					yield break;
				}
				yield return (object)new WaitForSeconds(0.25f);
			}
			ItemCatalog.TryRefresh(includeLoadedAssets: true);
			ToolBeltItems.RefreshResolved();
			ToolBeltMenu.OnCatalogReady();
			if (_open)
			{
				ToolBeltHud.Rebuild(_selected);
			}
			Log.LogInfo((object)("Loaded " + ItemCatalog.Count + " live items for the Tool Belt menu. Belt resolved " + ToolBeltItems.VisibleCount + " slot(s)."));
			((MonoBehaviour)this).StartCoroutine(WatchForLateItems(60f));
		}

		private IEnumerator WatchForLateItems(float seconds)
		{
			float elapsed = 0f;
			while (elapsed < seconds)
			{
				yield return (object)new WaitForSeconds(2f);
				elapsed += 2f;
				int count = ItemCatalog.Count;
				try
				{
					ItemCatalog.TryRefresh(includeLoadedAssets: true);
				}
				catch
				{
				}
				if (ItemCatalog.Count > count)
				{
					Log.LogInfo((object)("Found " + (ItemCatalog.Count - count) + " more item(s) after PEAKLib/mod load (" + ItemCatalog.Count + " total)."));
					ToolBeltItems.RefreshResolved();
					ToolBeltMenu.OnCatalogReady();
					if (_open)
					{
						ToolBeltHud.Rebuild(_selected);
					}
				}
			}
		}

		private void OnDestroy()
		{
			if (Columns != null)
			{
				Columns.SettingChanged -= OnColumnsChanged;
			}
			SceneManager.sceneLoaded -= OnSceneLoaded;
			SceneManager.activeSceneChanged -= OnActiveSceneChanged;
			try
			{
				Harmony harmony = _harmony;
				if (harmony != null)
				{
					harmony.UnpatchSelf();
				}
			}
			catch
			{
			}
			try
			{
				ToolBeltMenu.DestroyInstance();
			}
			catch
			{
			}
			ToolBeltHud.DestroyHud();
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}

		private void Update()
		{
			if (ToolBeltMenu.IsOpen || ToolBeltMenu.IsListeningForHotkey)
			{
				if (_open)
				{
					Close(grantHovered: false);
				}
			}
			else if (!_validScene)
			{
				if (_open)
				{
					Close(grantHovered: false);
				}
			}
			else if (!IsHeld(OpenToolBelt))
			{
				if (_open)
				{
					Close(_selected >= 0);
				}
			}
			else if (!CanUseBeltCached() || ShouldForceClose())
			{
				if (_open)
				{
					Close(grantHovered: false);
				}
			}
			else if (ToolBeltItems.VisibleCount <= 0)
			{
				if (!_loggedEmptyBelt)
				{
					Log.LogWarning((object)"Tool belt has no resolved items. Open the setup menu and check some, or Reset defaults.");
					_loggedEmptyBelt = true;
				}
				if (_open)
				{
					Close(grantHovered: false);
				}
			}
			else
			{
				_loggedEmptyBelt = false;
				if (!_open)
				{
					Open();
				}
			}
		}

		private void LateUpdate()
		{
			if (_open)
			{
				HoldFrozenLook();
			}
		}

		internal void Open()
		{
			//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_00df: Unknown result type (might be due to invalid IL or missing references)
			if (!_validScene || !CanUseBelt() || ToolBeltItems.VisibleCount <= 0)
			{
				return;
			}
			_open = true;
			_selected = -1;
			_prevLock = Cursor.lockState;
			_prevCursorVisible = Cursor.visible;
			Cursor.lockState = (CursorLockMode)0;
			Cursor.visible = true;
			CaptureFrozenLook();
			try
			{
				MenuAccess.SetMenuWindowFlags(GUIManager.instance, blocking: true, showingCursor: true);
			}
			catch
			{
			}
			try
			{
				if (!ToolBeltHud.Show(_selected))
				{
					Log.LogWarning((object)"Tool belt HUD did not appear. Vanilla inventory slots may not be ready.");
					Close(grantHovered: false);
					return;
				}
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Tool belt HUD failed: " + ex));
				Close(grantHovered: false);
				return;
			}
			Log.LogInfo((object)("Opened tool belt (" + ToolBeltItems.VisibleCount + " item(s)). Hold " + PrettyKey(GetOpenKey()) + ", hover a slot, then release."));
		}

		internal void Close(bool grantHovered)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			int selected = _selected;
			if (_open)
			{
				_open = false;
				_hasFrozenLook = false;
				ToolBeltHud.Hide();
				Cursor.lockState = _prevLock;
				Cursor.visible = _prevCursorVisible;
				try
				{
					MenuAccess.SetMenuWindowFlags(GUIManager.instance, blocking: false, showingCursor: false);
				}
				catch
				{
				}
				if (grantHovered && selected >= 0)
				{
					TryGrant(selected);
				}
			}
		}

		internal void SelectSlot(int index)
		{
			if (!_open)
			{
				return;
			}
			if (index < 0)
			{
				_selected = -1;
				ToolBeltHud.RefreshSelection(-1);
				return;
			}
			int visibleCount = ToolBeltItems.VisibleCount;
			if (visibleCount > 0)
			{
				_selected = (index % visibleCount + visibleCount) % visibleCount;
				ToolBeltHud.RefreshSelection(_selected);
			}
		}

		internal void GrantIndex(int index)
		{
			if (_open && TryGrant(index))
			{
				if (ToolBeltItems.VisibleCount <= 0)
				{
					Close(grantHovered: false);
					return;
				}
				ClampSelection();
				ToolBeltHud.Rebuild(_selected);
			}
		}

		private bool TryGrant(int index)
		{
			if (!CanUseBelt() || ShouldForceClose())
			{
				return false;
			}
			if (Time.unscaledTime - _lastGrantTime < 0.35f)
			{
				return false;
			}
			if (!ToolBeltItems.TryGetVisible(index, out var entry))
			{
				return false;
			}
			GrantResult grantResult = ToolBeltGrant.TryGive(entry);
			if (grantResult == GrantResult.Failed)
			{
				return false;
			}
			_lastGrantTime = Time.unscaledTime;
			_selected = index;
			if (!entry.Protected && (grantResult == GrantResult.Pocket || grantResult == GrantResult.Hand))
			{
				ToolBeltItems.Consume(entry);
			}
			return true;
		}

		internal void Restock(string reason)
		{
			ToolBeltItems.Restock();
			_selected = 0;
			if (_open)
			{
				ToolBeltHud.Rebuild(_selected);
			}
			else
			{
				ToolBeltHud.DestroyHud();
			}
			Log.LogInfo((object)("Tool belt restocked (" + reason + ") with " + ToolBeltItems.VisibleCount + " item(s)."));
		}

		internal static bool CanUseBelt()
		{
			if ((Object)(object)Instance == (Object)null || !Instance._validScene)
			{
				return false;
			}
			if (!PhotonNetwork.InRoom)
			{
				return true;
			}
			if (PhotonNetwork.IsMasterClient)
			{
				return true;
			}
			return ToolBeltNet.HostModConfirmed;
		}

		private static bool CanUseBeltCached()
		{
			if ((Object)(object)Instance == (Object)null)
			{
				return false;
			}
			if (Time.unscaledTime - Instance._canUseCachedAt < 0.25f)
			{
				return Instance._canUseCached;
			}
			Instance._canUseCached = CanUseBelt();
			Instance._canUseCachedAt = Time.unscaledTime;
			return Instance._canUseCached;
		}

		internal static bool IsGameplayBlocked()
		{
			try
			{
				if (GUIManager.InPauseMenu)
				{
					return true;
				}
				if (LoadingScreenHandler.loading)
				{
					return true;
				}
			}
			catch
			{
			}
			Character localCharacter = Character.localCharacter;
			if ((Object)(object)localCharacter != (Object)null && (Object)(object)localCharacter.data != (Object)null && (localCharacter.data.dead || localCharacter.data.fullyPassedOut))
			{
				return true;
			}
			return false;
		}

		internal static int ColumnCount()
		{
			int num = (((Object)(object)Instance != (Object)null && Instance.Columns != null) ? Instance.Columns.Value : 5);
			if (num < 1)
			{
				return 1;
			}
			if (num > 10)
			{
				return 10;
			}
			return num;
		}

		private void ClampSelection()
		{
			int visibleCount = ToolBeltItems.VisibleCount;
			if (visibleCount <= 0)
			{
				_selected = 0;
			}
			else if (_selected < 0 || _selected >= visibleCount)
			{
				_selected = 0;
			}
		}

		private bool ShouldForceClose()
		{
			return IsGameplayBlocked();
		}

		private static bool IsHeld(ConfigEntry<KeyCode> entry)
		{
			//IL_0004: 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)
			if (entry != null && (int)entry.Value != 0)
			{
				return Input.GetKey(entry.Value);
			}
			return false;
		}

		private void CaptureFrozenLook()
		{
			//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)
			Character localCharacter = Character.localCharacter;
			if ((Object)(object)localCharacter == (Object)null || (Object)(object)localCharacter.data == (Object)null)
			{
				_hasFrozenLook = false;
				return;
			}
			_frozenLookValues = localCharacter.data.lookValues;
			_hasFrozenLook = true;
		}

		private void HoldFrozenLook()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			if (_hasFrozenLook)
			{
				Character localCharacter = Character.localCharacter;
				if (!((Object)(object)localCharacter == (Object)null) && !((Object)(object)localCharacter.data == (Object)null))
				{
					localCharacter.data.lookValues = _frozenLookValues;
				}
			}
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			CheckScene(((Scene)(ref scene)).name);
		}

		private void OnActiveSceneChanged(Scene previous, Scene next)
		{
			CheckScene(((Scene)(ref next)).name);
		}

		private void CheckScene(string sceneName)
		{
			if (string.IsNullOrEmpty(sceneName))
			{
				return;
			}
			string sceneName2 = _sceneName;
			bool validScene = _validScene;
			_sceneName = sceneName;
			_validScene = sceneName == "Airport" || sceneName.StartsWith("Level_", StringComparison.Ordinal);
			if (_validScene && (!validScene || !string.Equals(sceneName2, sceneName, StringComparison.Ordinal)))
			{
				Restock(sceneName);
			}
			else if (!_validScene && _open)
			{
				Close(grantHovered: false);
			}
			ToolBeltMenu.OnAfterSceneLoad();
			if (_validScene)
			{
				int count = ItemCatalog.Count;
				try
				{
					ItemCatalog.TryRefresh(includeLoadedAssets: true);
				}
				catch
				{
				}
				if (ItemCatalog.Count > count)
				{
					Log.LogInfo((object)("Found " + (ItemCatalog.Count - count) + " more item(s) after scene load (" + ItemCatalog.Count + " total)."));
				}
				ToolBeltItems.RefreshResolved();
				ToolBeltMenu.OnCatalogReady();
				((MonoBehaviour)this).StartCoroutine(WatchForLateItems(45f));
			}
		}

		internal void OnBeltListChanged()
		{
			if (_open)
			{
				ToolBeltHud.Rebuild(_selected);
			}
			else
			{
				ToolBeltHud.DestroyHud();
			}
		}

		internal bool IsMenuHotkeyDown()
		{
			//IL_0009: 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_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_0028: 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_0032: 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_003f: Invalid comparison between Unknown and I4
			//IL_002b: 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_0047: Invalid comparison between Unknown and I4
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Invalid comparison between Unknown and I4
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Invalid comparison between Unknown and I4
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Invalid comparison between Unknown and I4
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Invalid comparison between Unknown and I4
			if (ToolBeltMenu.IsListeningForHotkey)
			{
				return false;
			}
			KeyCode menuKey = GetMenuKey();
			if ((int)menuKey == 0)
			{
				return false;
			}
			if (!GetRequireMenuModifier())
			{
				return Input.GetKeyDown(menuKey);
			}
			KeyCode menuModifier = GetMenuModifier();
			if ((int)menuModifier == 0)
			{
				return Input.GetKeyDown(menuKey);
			}
			bool flag = Input.GetKey(menuModifier);
			if ((int)menuModifier == 306 || (int)menuModifier == 305)
			{
				flag = Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305);
			}
			else if ((int)menuModifier == 308 || (int)menuModifier == 307)
			{
				flag = Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307);
			}
			else if ((int)menuModifier == 304 || (int)menuModifier == 303)
			{
				flag = Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303);
			}
			if (flag)
			{
				return Input.GetKeyDown(menuKey);
			}
			return false;
		}

		private void OnColumnsChanged(object sender, EventArgs args)
		{
			if (_open)
			{
				ToolBeltHud.Rebuild(_selected);
			}
		}

		public static bool GetShowPauseMenuButton()
		{
			if ((Object)(object)Instance != (Object)null && Instance.ShowPauseMenuButton != null)
			{
				return Instance.ShowPauseMenuButton.Value;
			}
			return false;
		}

		public static void SetShowPauseMenuButton(bool enabled)
		{
			if (!((Object)(object)Instance == (Object)null) && Instance.ShowPauseMenuButton != null)
			{
				Instance.ShowPauseMenuButton.Value = enabled;
				((BaseUnityPlugin)Instance).Config.Save();
			}
		}

		public static KeyCode GetMenuKey()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)Instance != (Object)null) || Instance.MenuKey == null)
			{
				return (KeyCode)106;
			}
			return Instance.MenuKey.Value;
		}

		public static KeyCode GetMenuModifier()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)Instance != (Object)null) || Instance.MenuModifier == null)
			{
				return (KeyCode)306;
			}
			return Instance.MenuModifier.Value;
		}

		public static void SetMenuKey(KeyCode key)
		{
			//IL_0019: 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)
			if (!((Object)(object)Instance == (Object)null) && Instance.MenuKey != null && (int)key != 0)
			{
				Instance.MenuKey.Value = key;
				((BaseUnityPlugin)Instance).Config.Save();
			}
		}

		public static void SetMenuModifier(KeyCode key)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)Instance == (Object)null) && Instance.MenuModifier != null)
			{
				Instance.MenuModifier.Value = key;
				((BaseUnityPlugin)Instance).Config.Save();
			}
		}

		public static bool GetRequireMenuModifier()
		{
			if (!((Object)(object)Instance == (Object)null) && Instance.RequireMenuModifier != null)
			{
				return Instance.RequireMenuModifier.Value;
			}
			return true;
		}

		public static void SetRequireMenuModifier(bool enabled)
		{
			if (!((Object)(object)Instance == (Object)null) && Instance.RequireMenuModifier != null)
			{
				Instance.RequireMenuModifier.Value = enabled;
				((BaseUnityPlugin)Instance).Config.Save();
			}
		}

		public static KeyCode GetOpenKey()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			return Get(((Object)(object)Instance != (Object)null) ? Instance.OpenToolBelt : null, (KeyCode)116);
		}

		public static void SetOpenKey(KeyCode key)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			Set(((Object)(object)Instance != (Object)null) ? Instance.OpenToolBelt : null, key);
		}

		public static void SetColumns(int columns)
		{
			if (!((Object)(object)Instance == (Object)null) && Instance.Columns != null)
			{
				Instance.Columns.Value = Mathf.Clamp(columns, 1, 10);
				((BaseUnityPlugin)Instance).Config.Save();
			}
		}

		public static string FormatMenuHotkey()
		{
			//IL_0000: 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_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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_0024: 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_001d: Unknown result type (might be due to invalid IL or missing references)
			KeyCode menuKey = GetMenuKey();
			if (!GetRequireMenuModifier())
			{
				return PrettyKey(menuKey);
			}
			KeyCode menuModifier = GetMenuModifier();
			if ((int)menuModifier == 0)
			{
				return PrettyKey(menuKey);
			}
			return PrettyKey(menuModifier) + " + " + PrettyKey(menuKey);
		}

		public unsafe static string PrettyKey(KeyCode key)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Invalid comparison between Unknown and I4
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Invalid comparison between Unknown and I4
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Invalid comparison between Unknown and I4
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Invalid comparison between Unknown and I4
			//IL_0009: 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_0065: Invalid comparison between Unknown and I4
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Invalid comparison between Unknown and I4
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Invalid comparison between Unknown and I4
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Invalid comparison between Unknown and I4
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Expected I4, but got Unknown
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Invalid comparison between Unknown and I4
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			if ((int)key <= 32)
			{
				if ((int)key <= 8)
				{
					if ((int)key == 0)
					{
						return "None";
					}
					if ((int)key == 8)
					{
						return "Backspace";
					}
				}
				else
				{
					if ((int)key == 13)
					{
						return "Enter";
					}
					if ((int)key == 27)
					{
						return "Esc";
					}
					if ((int)key == 32)
					{
						return "Space";
					}
				}
			}
			else if ((int)key <= 91)
			{
				if ((int)key == 45)
				{
					return "-";
				}
				if ((int)key == 61)
				{
					return "=";
				}
				if ((int)key == 91)
				{
					return "[";
				}
			}
			else
			{
				if ((int)key == 93)
				{
					return "]";
				}
				if ((int)key == 127)
				{
					return "Delete";
				}
				switch (key - 303)
				{
				case 3:
					return "Left Ctrl";
				case 2:
					return "Right Ctrl";
				case 5:
					return "Left Alt";
				case 4:
					return "Right Alt";
				case 1:
					return "Left Shift";
				case 0:
					return "Right Shift";
				case 7:
					return "Left Cmd";
				case 6:
					return "Right Cmd";
				}
			}
			string text = ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString();
			if (text.StartsWith("Alpha", StringComparison.Ordinal) && text.Length == 6)
			{
				return text.Substring(5);
			}
			if (text.StartsWith("Keypad", StringComparison.Ordinal))
			{
				return "Num " + text.Substring("Keypad".Length);
			}
			return text;
		}

		private static KeyCode Get(ConfigEntry<KeyCode> entry, KeyCode fallback)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			return entry?.Value ?? fallback;
		}

		private static void Set(ConfigEntry<KeyCode> entry, KeyCode key)
		{
			//IL_0003: 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)
			if (entry != null && (int)key != 0 && !((Object)(object)Instance == (Object)null))
			{
				entry.Value = key;
				((BaseUnityPlugin)Instance).Config.Save();
			}
		}
	}
	internal sealed class CatalogItem
	{
		public ushort Id;

		public string DisplayName;

		public string PrefabName;

		public Item Prefab;
	}
	internal static class ItemCatalog
	{
		private static readonly List<CatalogItem> _items = new List<CatalogItem>();

		private static readonly Dictionary<int, CatalogItem> _byInstance = new Dictionary<int, CatalogItem>();

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

		private static readonly HashSet<string> _seenKeys = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		public static bool IsReady { get; private set; }

		public static int Count => _items.Count;

		public static IReadOnlyList<CatalogItem> Items => _items;

		public static bool TryRefresh()
		{
			return TryRefresh(includeLoadedAssets: false);
		}

		public static bool TryRefresh(bool includeLoadedAssets)
		{
			if (!TryGetDatabase(out var db) || (Object)(object)db == (Object)null)
			{
				return false;
			}
			List<Item> list = new List<Item>();
			HashSet<int> seen = new HashSet<int>();
			if (db.itemLookup != null)
			{
				foreach (KeyValuePair<ushort, Item> item2 in db.itemLookup)
				{
					Consider(list, seen, item2.Value);
				}
			}
			if (((DatabaseAsset<ItemDatabase, Item>)(object)db).Objects != null)
			{
				for (int i = 0; i < ((DatabaseAsset<ItemDatabase, Item>)(object)db).Objects.Count; i++)
				{
					Consider(list, seen, ((DatabaseAsset<ItemDatabase, Item>)(object)db).Objects[i]);
				}
			}
			if (includeLoadedAssets)
			{
				CollectLoadedItems(list, seen);
			}
			if (list.Count == 0)
			{
				return IsReady;
			}
			int num = 0;
			for (int j = 0; j < list.Count; j++)
			{
				Item val = list[j];
				if (!((Object)(object)val == (Object)null))
				{
					int instanceID = ((Object)val).GetInstanceID();
					string item = Key(val);
					if (_seenInstances.Add(instanceID) && _seenKeys.Add(item))
					{
						CatalogItem catalogItem = new CatalogItem
						{
							Id = val.itemID,
							Prefab = val,
							PrefabName = SafePrefabName(val),
							DisplayName = SafeDisplayName(val)
						};
						_items.Add(catalogItem);
						_byInstance[instanceID] = catalogItem;
						num++;
					}
				}
			}
			if (num > 0)
			{
				_items.Sort(Compare);
			}
			IsReady = _items.Count > 0;
			return IsReady;
		}

		public static bool TryResolve(ushort itemId, string prefabName, out CatalogItem item)
		{
			item = null;
			if (!string.IsNullOrEmpty(prefabName))
			{
				for (int i = 0; i < _items.Count; i++)
				{
					CatalogItem catalogItem = _items[i];
					if (catalogItem != null && string.Equals(catalogItem.PrefabName, prefabName, StringComparison.OrdinalIgnoreCase))
					{
						item = catalogItem;
						return (Object)(object)catalogItem.Prefab != (Object)null;
					}
				}
			}
			if (itemId != 0)
			{
				for (int j = 0; j < _items.Count; j++)
				{
					CatalogItem catalogItem2 = _items[j];
					if (catalogItem2 != null && catalogItem2.Id == itemId)
					{
						item = catalogItem2;
						return (Object)(object)catalogItem2.Prefab != (Object)null;
					}
				}
				Item val = default(Item);
				if (ItemDatabase.TryGetItem(itemId, ref val) && (Object)(object)val != (Object)null)
				{
					item = new CatalogItem
					{
						Id = val.itemID,
						Prefab = val,
						PrefabName = SafePrefabName(val),
						DisplayName = SafeDisplayName(val)
					};
					return true;
				}
			}
			return false;
		}

		public static string GetName(ushort id, string prefabName)
		{
			if (TryResolve(id, prefabName, out var item) && item != null)
			{
				return item.DisplayName;
			}
			if (string.IsNullOrEmpty(prefabName))
			{
				return "Item " + id;
			}
			return prefabName;
		}

		public static bool TryGetDatabase(out ItemDatabase db)
		{
			db = null;
			try
			{
				db = SingletonAsset<ItemDatabase>.Instance;
			}
			catch
			{
				try
				{
					db = SingletonAsset<ItemDatabase>.Instance;
				}
				catch
				{
					return false;
				}
			}
			return (Object)(object)db != (Object)null;
		}

		public static string SafePrefabName(Item item)
		{
			try
			{
				if ((Object)(object)item != (Object)null && (Object)(object)((Component)item).gameObject != (Object)null && !string.IsNullOrEmpty(((Object)((Component)item).gameObject).name))
				{
					string text = ((Object)((Component)item).gameObject).name;
					int num = text.IndexOf("(Clone)", StringComparison.Ordinal);
					if (num >= 0)
					{
						text = text.Substring(0, num).Trim();
					}
					return text;
				}
				if ((Object)(object)item != (Object)null && !string.IsNullOrEmpty(((Object)item).name))
				{
					return ((Object)item).name;
				}
			}
			catch
			{
			}
			return "unknown";
		}

		public static string SafeDisplayName(Item item)
		{
			try
			{
				if ((Object)(object)item != (Object)null)
				{
					try
					{
						string itemName = item.GetItemName((ItemInstanceData)null);
						if (!string.IsNullOrEmpty(itemName) && itemName.IndexOf("NAME_", StringComparison.OrdinalIgnoreCase) < 0)
						{
							return itemName;
						}
					}
					catch
					{
					}
					if (item.UIData != null && !string.IsNullOrEmpty(item.UIData.itemName))
					{
						try
						{
							string name = item.GetName();
							if (!string.IsNullOrEmpty(name) && name.IndexOf("NAME_", StringComparison.OrdinalIgnoreCase) < 0)
							{
								return name;
							}
						}
						catch
						{
						}
						return Prettify(item.UIData.itemName);
					}
				}
			}
			catch
			{
			}
			return Prettify(SafePrefabName(item));
		}

		private static void CollectLoadedItems(List<Item> found, HashSet<int> seen)
		{
			try
			{
				Item[] array = Resources.FindObjectsOfTypeAll<Item>();
				if (array != null)
				{
					for (int i = 0; i < array.Length; i++)
					{
						Consider(found, seen, array[i]);
					}
				}
			}
			catch
			{
			}
			try
			{
				List<Item> aLL_ACTIVE_ITEMS = Item.ALL_ACTIVE_ITEMS;
				if (aLL_ACTIVE_ITEMS != null)
				{
					for (int j = 0; j < aLL_ACTIVE_ITEMS.Count; j++)
					{
						Consider(found, seen, aLL_ACTIVE_ITEMS[j]);
					}
				}
			}
			catch
			{
			}
			try
			{
				List<Item> aLL_ITEMS = Item.ALL_ITEMS;
				if (aLL_ITEMS != null)
				{
					for (int k = 0; k < aLL_ITEMS.Count; k++)
					{
						Consider(found, seen, aLL_ITEMS[k]);
					}
				}
			}
			catch
			{
			}
		}

		private static void Consider(List<Item> found, HashSet<int> seen, Item item)
		{
			if (!((Object)(object)item == (Object)null) && !((Object)(object)((Component)item).gameObject == (Object)null))
			{
				int instanceID = ((Object)item).GetInstanceID();
				if (seen.Add(instanceID))
				{
					found.Add(item);
				}
			}
		}

		private static string Key(Item item)
		{
			return SafePrefabName(item).ToLowerInvariant() + "|" + (((Object)(object)item != (Object)null) ? item.itemID : 0);
		}

		private static int Compare(CatalogItem a, CatalogItem b)
		{
			int num = string.Compare(a.DisplayName, b.DisplayName, StringComparison.OrdinalIgnoreCase);
			if (num == 0)
			{
				return string.Compare(a.PrefabName, b.PrefabName, StringComparison.OrdinalIgnoreCase);
			}
			return num;
		}

		private static string Prettify(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return "Unknown";
			}
			StringBuilder stringBuilder = new StringBuilder(name.Length + 8);
			for (int i = 0; i < name.Length; i++)
			{
				char c = name[i];
				if (c == '_' || c == '-')
				{
					stringBuilder.Append(' ');
					continue;
				}
				if (i > 0 && char.IsUpper(c) && !char.IsUpper(name[i - 1]) && name[i - 1] != ' ')
				{
					stringBuilder.Append(' ');
				}
				stringBuilder.Append(c);
			}
			return stringBuilder.ToString().Trim();
		}
	}
	internal sealed class BeltPick
	{
		public ushort ItemId;

		public string PrefabName;

		public bool Protected;

		public int Count = 1;
	}
	[Serializable]
	internal sealed class SavedBeltFile
	{
		public int version = 2;

		public SavedBeltItem[] items = new SavedBeltItem[0];
	}
	[Serializable]
	internal sealed class SavedBeltItem
	{
		public int id;

		public string prefab;

		public bool oneTime;

		public bool isProtected;

		public int count = 1;
	}
	internal static class BeltStore
	{
		internal const int FileVersion = 2;

		internal const int MinCount = 1;

		internal const int MaxCount = 99;

		internal static readonly BeltPick[] Defaults = new BeltPick[4]
		{
			Pick("Binoculars", 14, isProtected: true, 1),
			Pick("Bugle", 15, isProtected: true, 1),
			Pick("Compass", 23, isProtected: true, 1),
			Pick("Guidebook", 34, isProtected: true, 1)
		};

		private static readonly List<BeltPick> _local = new List<BeltPick>();

		private static readonly List<BeltPick> _host = new List<BeltPick>();

		private static bool _useHost;

		private static bool _loaded;

		private static string _path;

		private static readonly string[] LegacyDefaultNames = new string[16]
		{
			"Binoculars", "Bugle", "Compass", "Conch", "Flare", "Frisbee", "Guidebook", "Lantern", "Megaphone", "Piton",
			"Passport", "RopeSpool", "SeagullFlag", "SportsDrink", "TrailMix", "TurtleFlag"
		};

		public static bool HostControls => _useHost;

		public static int LocalCount => _local.Count;

		public static IReadOnlyList<BeltPick> Active
		{
			get
			{
				if (!_useHost)
				{
					return _local;
				}
				return _host;
			}
		}

		public static void Initialize()
		{
			if (!_loaded)
			{
				_path = Path.Combine(Paths.ConfigPath, "tony4twentys.PEAK_Tool_Belt.items.json");
				if (!Load() || _local.Count == 0)
				{
					SeedDefaults();
					Save();
				}
				_loaded = true;
				Plugin.Log.LogInfo((object)("Belt list has " + _local.Count + " saved item(s)."));
			}
		}

		public static void ApplyHost(IList<BeltPick> picks)
		{
			_host.Clear();
			CopyInto(_host, picks);
			_useHost = true;
			ToolBeltItems.RefreshResolved();
			if ((Object)(object)Plugin.Instance != (Object)null)
			{
				Plugin.Instance.OnBeltListChanged();
			}
		}

		public static void ClearHost()
		{
			_useHost = false;
			_host.Clear();
			ToolBeltItems.RefreshResolved();
			if ((Object)(object)Plugin.Instance != (Object)null)
			{
				Plugin.Instance.OnBeltListChanged();
			}
		}

		public static bool IsOnBelt(ushort id, string prefabName)
		{
			return Find(Active, id, prefabName) != null;
		}

		public static bool IsProtected(ushort id, string prefabName)
		{
			return Find(Active, id, prefabName)?.Protected ?? false;
		}

		public static int GetCount(ushort id, string prefabName)
		{
			BeltPick beltPick = Find(Active, id, prefabName);
			if (beltPick == null)
			{
				return 1;
			}
			return ClampCount(beltPick.Count);
		}

		public static bool IsDefault(ushort id, string prefabName)
		{
			return Find(Defaults, id, prefabName) != null;
		}

		public static void SetOnBelt(CatalogItem item, bool on)
		{
			if (item == null || _useHost)
			{
				return;
			}
			BeltPick beltPick = Find(_local, item.Id, item.PrefabName);
			if (on)
			{
				if (beltPick == null)
				{
					_local.Add(new BeltPick
					{
						ItemId = item.Id,
						PrefabName = item.PrefabName,
						Protected = false,
						Count = 1
					});
					SortLocal();
				}
			}
			else if (beltPick != null)
			{
				_local.Remove(beltPick);
			}
			PersistAndRefresh();
		}

		public static void SetProtected(CatalogItem item, bool isProtected)
		{
			if (item == null || _useHost)
			{
				return;
			}
			BeltPick beltPick = Find(_local, item.Id, item.PrefabName);
			if (beltPick == null)
			{
				if (!isProtected)
				{
					return;
				}
				_local.Add(new BeltPick
				{
					ItemId = item.Id,
					PrefabName = item.PrefabName,
					Protected = true,
					Count = 1
				});
				SortLocal();
			}
			else
			{
				beltPick.Protected = isProtected;
			}
			PersistAndRefresh();
		}

		public static void SetCount(CatalogItem item, int count)
		{
			if (item != null && !_useHost)
			{
				count = ClampCount(count);
				BeltPick beltPick = Find(_local, item.Id, item.PrefabName);
				if (beltPick != null)
				{
					beltPick.Count = count;
					PersistAndRefresh();
				}
			}
		}

		public static void ResetDefaults()
		{
			if (!_useHost)
			{
				SeedDefaults();
				PersistAndRefresh();
			}
		}

		public static void ClearAll()
		{
			if (!_useHost)
			{
				_local.Clear();
				PersistAndRefresh();
			}
		}

		public static List<BeltPick> SnapshotLocal()
		{
			return Clone(_local);
		}

		public static void ReplaceLocal(IList<BeltPick> picks)
		{
			if (!_useHost)
			{
				_local.Clear();
				CopyInto(_local, picks);
				SortLocal();
				PersistAndRefresh();
			}
		}

		public static bool TryExport(string path, out string error)
		{
			error = null;
			try
			{
				if (string.IsNullOrEmpty(path))
				{
					error = "No preset path.";
					return false;
				}
				File.WriteAllText(path, BuildJson(ToFile(_local)));
				return true;
			}
			catch (Exception ex)
			{
				error = "Could not save preset: " + ex.Message;
				return false;
			}
		}

		public static bool TryImport(string path, out List<BeltPick> picks, out string error)
		{
			picks = null;
			error = null;
			try
			{
				if (string.IsNullOrEmpty(path) || !File.Exists(path))
				{
					error = "Preset file is missing.";
					return false;
				}
				if (!TryParse(File.ReadAllText(path), out picks) || picks == null)
				{
					error = "Preset file is empty or invalid.";
					return false;
				}
				return true;
			}
			catch (Exception ex)
			{
				error = "Could not load preset: " + ex.Message;
				return false;
			}
		}

		public static int ClampCount(int count)
		{
			if (count < 1)
			{
				return 1;
			}
			if (count > 99)
			{
				return 99;
			}
			return count;
		}

		private static void PersistAndRefresh()
		{
			Save();
			ToolBeltItems.RefreshResolved();
			ToolBeltNet.OnLocalSettingChanged();
			if ((Object)(object)Plugin.Instance != (Object)null)
			{
				Plugin.Instance.OnBeltListChanged();
			}
		}

		private static void SeedDefaults()
		{
			_local.Clear();
			for (int i = 0; i < Defaults.Length; i++)
			{
				BeltPick beltPick = Defaults[i];
				_local.Add(new BeltPick
				{
					ItemId = beltPick.ItemId,
					PrefabName = beltPick.PrefabName,
					Protected = beltPick.Protected,
					Count = ClampCount(beltPick.Count)
				});
			}
		}

		private static bool Load()
		{
			try
			{
				if (string.IsNullOrEmpty(_path) || !File.Exists(_path))
				{
					return false;
				}
				if (!TryParse(File.ReadAllText(_path), out var picks) || picks == null || picks.Count == 0)
				{
					return false;
				}
				_local.Clear();
				CopyInto(_local, picks);
				SavedBeltFile savedBeltFile = JsonUtility.FromJson<SavedBeltFile>(File.ReadAllText(_path));
				int num;
				if (savedBeltFile != null)
				{
					num = ((savedBeltFile.version < 2) ? 1 : 0);
					if (num != 0 && LooksLikeOriginalDefaultSet())
					{
						SeedDefaults();
					}
				}
				else
				{
					num = 0;
				}
				if (num != 0)
				{
					Save();
				}
				return _local.Count > 0;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not load belt item list: " + ex.Message));
				return false;
			}
		}

		private static bool TryParse(string json, out List<BeltPick> picks)
		{
			picks = new List<BeltPick>();
			if (string.IsNullOrEmpty(json))
			{
				return false;
			}
			SavedBeltFile savedBeltFile = JsonUtility.FromJson<SavedBeltFile>(json);
			if (savedBeltFile == null || savedBeltFile.items == null)
			{
				return false;
			}
			bool flag = savedBeltFile.version < 2;
			for (int i = 0; i < savedBeltFile.items.Length; i++)
			{
				SavedBeltItem savedBeltItem = savedBeltFile.items[i];
				if (savedBeltItem != null)
				{
					picks.Add(new BeltPick
					{
						ItemId = (ushort)((savedBeltItem.id > 0 && savedBeltItem.id <= 65535) ? ((ushort)savedBeltItem.id) : 0),
						PrefabName = (savedBeltItem.prefab ?? string.Empty),
						Protected = (flag ? (!savedBeltItem.oneTime) : savedBeltItem.isProtected),
						Count = ClampCount(savedBeltItem.count)
					});
				}
			}
			if (picks.Count <= 0)
			{
				return savedBeltFile.items.Length == 0;
			}
			return true;
		}

		private static SavedBeltFile ToFile(IList<BeltPick> picks)
		{
			int num = picks?.Count ?? 0;
			SavedBeltFile savedBeltFile = new SavedBeltFile
			{
				version = 2,
				items = new SavedBeltItem[num]
			};
			for (int i = 0; i < num; i++)
			{
				BeltPick beltPick = picks[i];
				savedBeltFile.items[i] = new SavedBeltItem
				{
					id = (beltPick?.ItemId ?? 0),
					prefab = ((beltPick != null && beltPick.PrefabName != null) ? beltPick.PrefabName : string.Empty),
					isProtected = (beltPick?.Protected ?? false),
					count = ((beltPick == null) ? 1 : ClampCount(beltPick.Count))
				};
			}
			return savedBeltFile;
		}

		private static void Save()
		{
			try
			{
				if (!string.IsNullOrEmpty(_path))
				{
					File.WriteAllText(_path, BuildJson(ToFile(_local)));
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not save belt item list: " + ex.Message));
			}
		}

		private static string BuildJson(SavedBeltFile file)
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("{");
			stringBuilder.AppendLine("    \"version\": " + 2 + ",");
			stringBuilder.AppendLine("    \"items\": [");
			SavedBeltItem[] array = ((file != null && file.items != null) ? file.items : new SavedBeltItem[0]);
			for (int i = 0; i < array.Length; i++)
			{
				SavedBeltItem savedBeltItem = array[i] ?? new SavedBeltItem();
				string value = (savedBeltItem.prefab ?? string.Empty).Replace("\\", "\\\\").Replace("\"", "\\\"");
				stringBuilder.Append("        {\"id\": ");
				stringBuilder.Append(savedBeltItem.id);
				stringBuilder.Append(", \"prefab\": \"");
				stringBuilder.Append(value);
				stringBuilder.Append("\", \"isProtected\": ");
				stringBuilder.Append(savedBeltItem.isProtected ? "true" : "false");
				stringBuilder.Append(", \"count\": ");
				stringBuilder.Append(ClampCount(savedBeltItem.count));
				stringBuilder.Append("}");
				stringBuilder.AppendLine((i < array.Length - 1) ? "," : string.Empty);
			}
			stringBuilder.AppendLine("    ]");
			stringBuilder.AppendLine("}");
			return stringBuilder.ToString();
		}

		private static BeltPick Find(IReadOnlyList<BeltPick> list, ushort id, string prefabName)
		{
			if (list == null)
			{
				return null;
			}
			if (!string.IsNullOrEmpty(prefabName))
			{
				for (int i = 0; i < list.Count; i++)
				{
					if (list[i] != null && string.Equals(list[i].PrefabName, prefabName, StringComparison.OrdinalIgnoreCase))
					{
						return list[i];
					}
				}
			}
			if (id == 0)
			{
				return null;
			}
			for (int j = 0; j < list.Count; j++)
			{
				if (list[j] != null && list[j].ItemId == id)
				{
					return list[j];
				}
			}
			return null;
		}

		private static bool LooksLikeOriginalDefaultSet()
		{
			if (_local.Count != LegacyDefaultNames.Length)
			{
				return false;
			}
			for (int i = 0; i < LegacyDefaultNames.Length; i++)
			{
				if (Find(_local, 0, LegacyDefaultNames[i]) == null)
				{
					return false;
				}
			}
			return true;
		}

		private static void SortLocal()
		{
			_local.Sort(delegate(BeltPick a, BeltPick b)
			{
				string strA = ((a != null) ? a.PrefabName : string.Empty);
				string strB = ((b != null) ? b.PrefabName : string.Empty);
				return string.Compare(strA, strB, StringComparison.OrdinalIgnoreCase);
			});
		}

		private static void CopyInto(List<BeltPick> dest, IList<BeltPick> src)
		{
			if (src == null)
			{
				return;
			}
			for (int i = 0; i < src.Count; i++)
			{
				if (src[i] != null)
				{
					dest.Add(new BeltPick
					{
						ItemId = src[i].ItemId,
						PrefabName = (src[i].PrefabName ?? string.Empty),
						Protected = src[i].Protected,
						Count = ClampCount(src[i].Count)
					});
				}
			}
		}

		private static List<BeltPick> Clone(List<BeltPick> src)
		{
			List<BeltPick> list = new List<BeltPick>(src.Count);
			CopyInto(list, src);
			return list;
		}

		private static BeltPick Pick(string prefab, ushort id, bool isProtected, int count)
		{
			return new BeltPick
			{
				PrefabName = prefab,
				ItemId = id,
				Protected = isProtected,
				Count = ClampCount(count)
			};
		}
	}
	internal static class BeltPresetStore
	{
		public const string DefaultName = "default";

		private static string _folder;

		public static string FolderPath
		{
			get
			{
				EnsureFolder();
				return _folder;
			}
		}

		public static void Initialize()
		{
			EnsureFolder();
		}

		public static List<string> ListNames()
		{
			List<string> list = new List<string>();
			EnsureFolder();
			if (string.IsNullOrEmpty(_folder) || !Directory.Exists(_folder))
			{
				return list;
			}
			try
			{
				string[] files = Directory.GetFiles(_folder, "*.json");
				for (int i = 0; i < files.Length; i++)
				{
					list.Add(Path.GetFileNameWithoutExtension(files[i]));
				}
				list.Sort(StringComparer.OrdinalIgnoreCase);
				int num = list.FindIndex(IsDefaultName);
				if (num > 0)
				{
					string item = list[num];
					list.RemoveAt(num);
					list.Insert(0, item);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Failed to list presets: " + ex.Message));
			}
			return list;
		}

		public static bool Save(string name, out string error)
		{
			error = null;
			if (BeltStore.HostControls)
			{
				error = "The host controls the belt list in this lobby.";
				return false;
			}
			string text = Sanitize(name);
			if (string.IsNullOrEmpty(text))
			{
				error = "Type a name for this preset first.";
				return false;
			}
			EnsureFolder();
			if (string.IsNullOrEmpty(_folder))
			{
				error = "Could not create the Presets folder next to the plugin.";
				return false;
			}
			if (!BeltStore.TryExport(Path.Combine(_folder, text + ".json"), out error))
			{
				return false;
			}
			Plugin.Log.LogInfo((object)("Saved belt preset " + text + " (" + BeltStore.LocalCount + " item(s))."));
			return true;
		}

		public static bool Load(string name, out string error)
		{
			error = null;
			if (BeltStore.HostControls)
			{
				error = "The host controls the belt list in this lobby.";
				return false;
			}
			string text = Sanitize(name);
			if (string.IsNullOrEmpty(text))
			{
				error = "Pick a preset to load.";
				return false;
			}
			EnsureFolder();
			if (!BeltStore.TryImport(Path.Combine(_folder ?? string.Empty, text + ".json"), out var picks, out error))
			{
				return false;
			}
			BeltStore.ReplaceLocal(picks);
			Plugin.Log.LogInfo((object)("Loaded belt preset " + text + " (" + BeltStore.LocalCount + " item(s))."));
			return true;
		}

		public static void SaveDefaultQuiet()
		{
			if (BeltStore.HostControls)
			{
				return;
			}
			try
			{
				EnsureFolder();
				if (!string.IsNullOrEmpty(_folder))
				{
					BeltStore.TryExport(Path.Combine(_folder, "default.json"), out var _);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Failed to save default preset: " + ex.Message));
			}
		}

		public static bool IsDefaultName(string name)
		{
			return string.Equals(Sanitize(name), "default", StringComparison.OrdinalIgnoreCase);
		}

		public static bool Delete(string name, out string error)
		{
			error = null;
			string text = Sanitize(name);
			if (string.IsNullOrEmpty(text))
			{
				error = "Pick a preset to delete.";
				return false;
			}
			if (IsDefaultName(text))
			{
				error = "The default preset is updated automatically when you close the menu.";
				return false;
			}
			EnsureFolder();
			string path = Path.Combine(_folder ?? string.Empty, text + ".json");
			if (!File.Exists(path))
			{
				error = "No preset named \"" + text + "\".";
				return false;
			}
			try
			{
				File.Delete(path);
				return true;
			}
			catch (Exception ex)
			{
				error = "Failed to delete preset: " + ex.Message;
				Plugin.Log.LogWarning((object)error);
				return false;
			}
		}

		public static string Sanitize(string name)
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				return string.Empty;
			}
			char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
			char[] array = name.Trim().ToCharArray();
			for (int i = 0; i < array.Length; i++)
			{
				char c = array[i];
				bool flag = c < ' ';
				if (!flag)
				{
					for (int j = 0; j < invalidFileNameChars.Length; j++)
					{
						if (c == invalidFileNameChars[j])
						{
							flag = true;
							break;
						}
					}
				}
				if (flag)
				{
					array[i] = '_';
				}
			}
			string text = new string(array).Trim();
			if (text.Length > 40)
			{
				text = text.Substring(0, 40).Trim();
			}
			return text;
		}

		private static void EnsureFolder()
		{
			if (!string.IsNullOrEmpty(_folder) && Directory.Exists(_folder))
			{
				return;
			}
			try
			{
				string location = typeof(Plugin).Assembly.Location;
				string text = (string.IsNullOrEmpty(location) ? null : Path.GetDirectoryName(location));
				if (string.IsNullOrEmpty(text))
				{
					text = Paths.PluginPath;
				}
				_folder = Path.Combine(text, "Presets");
				Directory.CreateDirectory(_folder);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Failed to create Presets folder: " + ex.Message));
			}
		}
	}
	internal sealed class BeltEntry
	{
		public ushort ItemId;

		public string PrefabName;

		public string DisplayName;

		public bool Protected;

		public int SpawnLimit;

		public int Remaining;

		public Item Prefab;
	}
	internal static class ToolBeltItems
	{
		private struct RemainingSnap
		{
			public int Limit;

			public int Left;
		}

		private static readonly List<BeltEntry> _all = new List<BeltEntry>();

		private static readonly List<BeltEntry> _visible = new List<BeltEntry>();

		public static int VisibleCount => _visible.Count;

		public static IReadOnlyList<BeltEntry> Visible => _visible;

		public static bool DatabaseReady()
		{
			if (ItemCatalog.TryGetDatabase(out var db) && (Object)(object)db != (Object)null && ((DatabaseAsset<ItemDatabase, Item>)(object)db).Objects != null)
			{
				return ((DatabaseAsset<ItemDatabase, Item>)(object)db).Objects.Count > 0;
			}
			return false;
		}

		public static bool TryGetVisible(int index, out BeltEntry entry)
		{
			if (index >= 0 && index < _visible.Count)
			{
				entry = _visible[index];
				return entry != null;
			}
			entry = null;
			return false;
		}

		public static void LoadLocal()
		{
			if (!BeltStore.HostControls)
			{
				RefreshResolved();
			}
		}

		public static void RefreshResolved()
		{
			Rebuild();
		}

		public static void Restock()
		{
			Rebuild();
			for (int i = 0; i < _all.Count; i++)
			{
				BeltEntry beltEntry = _all[i];
				if (beltEntry != null)
				{
					beltEntry.Remaining = (beltEntry.Protected ? 1 : beltEntry.SpawnLimit);
				}
			}
			RefreshVisible();
		}

		public static void Consume(BeltEntry entry)
		{
			if (entry != null && !entry.Protected)
			{
				entry.Remaining = Mathf.Max(0, entry.Remaining - 1);
				RefreshVisible();
			}
		}

		internal static string PrefabName(Item item)
		{
			return ItemCatalog.SafePrefabName(item);
		}

		internal static string DisplayName(Item item, string fallback)
		{
			string text = ItemCatalog.SafeDisplayName(item);
			if (!string.IsNullOrEmpty(text))
			{
				return text;
			}
			return fallback;
		}

		private static void Rebuild()
		{
			Dictionary<string, RemainingSnap> dictionary = new Dictionary<string, RemainingSnap>(StringComparer.OrdinalIgnoreCase);
			for (int i = 0; i < _all.Count; i++)
			{
				BeltEntry beltEntry = _all[i];
				if (beltEntry != null)
				{
					dictionary[Key(beltEntry.ItemId, beltEntry.PrefabName)] = new RemainingSnap
					{
						Limit = beltEntry.SpawnLimit,
						Left = beltEntry.Remaining
					};
				}
			}
			_all.Clear();
			IReadOnlyList<BeltPick> active = BeltStore.Active;
			for (int j = 0; j < active.Count; j++)
			{
				BeltPick beltPick = active[j];
				if (beltPick != null && ItemCatalog.TryResolve(beltPick.ItemId, beltPick.PrefabName, out var item) && item != null && !((Object)(object)item.Prefab == (Object)null))
				{
					int num = ((!beltPick.Protected) ? BeltStore.ClampCount(beltPick.Count) : 0);
					int remaining = (beltPick.Protected ? 1 : num);
					if (dictionary.TryGetValue(Key(item.Id, item.PrefabName), out var value))
					{
						int num2 = Mathf.Max(0, value.Limit - value.Left);
						remaining = (beltPick.Protected ? 1 : Mathf.Max(0, num - num2));
					}
					_all.Add(new BeltEntry
					{
						ItemId = item.Id,
						PrefabName = item.PrefabName,
						DisplayName = item.DisplayName,
						Protected = beltPick.Protected,
						SpawnLimit = num,
						Remaining = remaining,
						Prefab = item.Prefab
					});
				}
			}
			RefreshVisible();
		}

		private static void RefreshVisible()
		{
			_visible.Clear();
			for (int i = 0; i < _all.Count; i++)
			{
				BeltEntry beltEntry = _all[i];
				if (beltEntry != null && !((Object)(object)beltEntry.Prefab == (Object)null) && (beltEntry.Protected || beltEntry.Remaining > 0))
				{
					_visible.Add(beltEntry);
				}
			}
		}

		private static string Key(ushort id, string prefab)
		{
			return (prefab ?? string.Empty).ToLowerInvariant() + "|" + id;
		}
	}
	internal enum GrantResult
	{
		Failed,
		EquippedExisting,
		Recalled,
		Pocket,
		Hand
	}
	internal static class ToolBeltGrant
	{
		public static GrantResult TryGive(BeltEntry entry)
		{
			try
			{
				if (entry == null || (Object)(object)entry.Prefab == (Object)null)
				{
					return GrantResult.Failed;
				}
				Character localCharacter = Character.localCharacter;
				Player val = (((Object)(object)localCharacter != (Object)null) ? localCharacter.player : Player.localPlayer);
				if ((Object)(object)localCharacter == (Object)null || (Object)(object)val == (Object)null)
				{
					return GrantResult.Failed;
				}
				if (Plugin.IsGameplayBlocked())
				{
					return GrantResult.Failed;
				}
				if (entry.Protected)
				{
					if ((Object)(object)ToolBeltMark.FindHeld(entry) != (Object)null)
					{
						return GrantResult.EquippedExisting;
					}
					int num = ToolBeltMark.FindOwnedSlot(val, entry);
					if (num >= 0)
					{
						Equip(localCharacter, (byte)num);
						return GrantResult.EquippedExisting;
					}
					if (ToolBeltMark.HasOwnedCopy(val, entry))
					{
						return GrantResult.EquippedExisting;
					}
					Item val2 = ToolBeltMark.FindWorldCopy(entry);
					if ((Object)(object)val2 != (Object)null)
					{
						if (ToolBeltMark.CanPickup(val, entry))
						{
							try
							{
								val2.Interact(localCharacter);
								return GrantResult.Recalled;
							}
							catch (Exception ex)
							{
								Plugin.Log.LogWarning((object)("Could not pick up existing belt item: " + ex.Message));
							}
						}
						if (!ToolBeltMark.TryDestroyWorld(val2) || !ToolBeltMark.CanPickup(val, entry))
						{
							return GrantResult.Recalled;
						}
					}
				}
				int num2 = FindEmptyPocket(val);
				if (num2 >= 0 && TryPutInPocket(val, entry, num2))
				{
					SyncInventory(val);
					Equip(localCharacter, (byte)num2);
					return GrantResult.Pocket;
				}
				if (TrySpawnInHand(localCharacter, entry))
				{
					return GrantResult.Hand;
				}
				Plugin.Log.LogWarning((object)("Could not give '" + entry.DisplayName + "'."));
				return GrantResult.Failed;
			}
			catch (Exception ex2)
			{
				Plugin.Log.LogError((object)("Tool belt grant failed: " + ex2));
				return GrantResult.Failed;
			}
		}

		private static int FindEmptyPocket(Player player)
		{
			if ((Object)(object)player == (Object)null || player.itemSlots == null)
			{
				return -1;
			}
			for (int i = 0; i < player.itemSlots.Length; i++)
			{
				ItemSlot val = player.itemSlots[i];
				if (val != null && val.IsEmpty())
				{
					return i;
				}
			}
			return -1;
		}

		private static bool TryPutInPocket(Player player, BeltEntry entry, int slotIndex)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			if ((Object)(object)player == (Object)null || player.itemSlots == null || entry == null || (Object)(object)entry.Prefab == (Object)null)
			{
				return false;
			}
			if (slotIndex < 0 || slotIndex >= player.itemSlots.Length)
			{
				return false;
			}
			ItemSlot val = player.itemSlots[slotIndex];
			if (val == null || !val.IsEmpty())
			{
				return false;
			}
			ItemInstanceData val2 = new ItemInstanceData(Guid.NewGuid());
			ItemInstanceDataHandler.AddInstanceData(val2);
			ToolBeltMark.Apply(val2, entry.Protected);
			val.SetItem(entry.Prefab, val2);
			return !val.IsEmpty();
		}

		private static void Equip(Character character, byte slotId)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)character == (Object)null || character.refs == null || (Object)(object)character.refs.items == (Object)null)
			{
				return;
			}
			try
			{
				character.refs.items.EquipSlot(Optionable<byte>.Some(slotId));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not equip slot " + slotId + ": " + ex.Message));
			}
		}

		private static bool TrySpawnInHand(Character character, BeltEntry entry)
		{
			if ((Object)(object)character == (Object)null || entry == null || (Object)(object)entry.Prefab == (Object)null || character.refs == null || (Object)(object)character.refs.items == (Object)null)
			{
				return false;
			}
			string text = ToolBeltItems.PrefabName(entry.Prefab);
			if (string.IsNullOrEmpty(text))
			{
				return false;
			}
			try
			{
				ToolBeltMark.ExpectSpawn(text, entry.Protected);
				character.refs.items.SpawnItemInHand(text);
				return true;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("SpawnItemInHand failed for " + text + ": " + ex.Message));
				return false;
			}
		}

		private static void SyncInventory(Player player)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				PhotonView val = null;
				if ((Object)(object)player != (Object)null)
				{
					try
					{
						val = player.view;
					}
					catch
					{
					}
					if ((Object)(object)val == (Object)null)
					{
						try
						{
							val = ((MonoBehaviourPun)player).photonView;
						}
						catch
						{
						}
					}
				}
				if (!((Object)(object)val == (Object)null))
				{
					InventorySyncData val2 = default(InventorySyncData);
					((InventorySyncData)(ref val2))..ctor(player.itemSlots, player.backpackSlot, player.tempFullSlot);
					val.RPC("SyncInventoryRPC", (RpcTarget)1, new object[2]
					{
						IBinarySerializable.ToManagedArray<InventorySyncData>(val2),
						false
					});
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Inventory sync failed: " + ex.Message));
			}
		}
	}
	internal static class ToolBeltMark
	{
		[HarmonyPatch(typeof(Item), "Start")]
		private static class Patch_ItemStart
		{
			private static void Postfix(Item __instance)
			{
				if (!((Object)(object)__instance == (Object)null))
				{
					RestoreRemembered(__instance);
					if (PendingMatches(__instance) || IsProtectedBeltItem(__instance))
					{
						ScheduleDeferredTag(__instance);
					}
				}
			}
		}

		[HarmonyPatch(typeof(Item), "SetItemInstanceDataRPC")]
		private static class Patch_SetItemInstanceData
		{
			private static void Postfix(Item __instance)
			{
				if (!((Object)(object)__instance == (Object)null))
				{
					RestoreRemembered(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(Item), "OnStash")]
		private static class Patch_OnStash
		{
			private static void Prefix(Item __instance)
			{
				if (!((Object)(object)__instance == (Object)null) && IsProtectedBeltItem(__instance))
				{
					Apply(__instance, isProtected: true);
				}
			}
		}

		[HarmonyPatch(typeof(Item), "OnDestroy")]
		private static class Patch_OnDestroy
		{
			private static void Prefix(Item __instance)
			{
				PhotonView val = ItemView(__instance);
				if ((Object)(object)val != (Object)null)
				{
					_flagByView.Remove(val.ViewID);
				}
			}
		}

		[HarmonyPatch(typeof(Item), "Interact")]
		private static class Patch_ItemInteract
		{
			private static void Postfix(Item __instance, Character interactor)
			{
				if (!((Object)(object)__instance == (Object)null) && !((Object)(object)interactor == (Object)null) && !((Object)(object)interactor != (Object)(object)Character.localCharacter) && PendingMatches(__instance))
				{
					Apply(__instance, _pendingProtected);
					ClearPending();
				}
			}
		}

		[HarmonyPatch(typeof(CharacterItems), "DropItemRpc")]
		private static class Patch_DropItemRpc
		{
			private static bool Prefix(CharacterItems __instance, byte slotID, ItemInstanceData itemInstanceData)
			{
				try
				{
					if ((Object)(object)__instance == (Object)null || (Object)(object)__instance.character == (Object)null)
					{
						return true;
					}
					Item val = (((Object)(object)__instance.character.data != (Object)null) ? __instance.character.data.currentItem : null);
					ItemSlot val2 = (((Object)(object)__instance.character.player != (Object)null) ? __instance.character.player.GetItemSlot(slotID) : null);
					Item prefab = (((Object)(object)val != (Object)null) ? val : ((val2 != null) ? val2.prefab : null));
					if (!IsProtectedBeltItem(val) && !IsProtectedBeltItem(prefab, itemInstanceData) && (val2 == null || !IsProtectedBeltItem(val2.prefab, val2.data)))
					{
						return true;
					}
					CancelHeldProtected(__instance, slotID);
					return false;
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Protected belt drop swallow failed: " + ex.Message));
					return true;
				}
			}
		}

		[HarmonyPatch(typeof(CharacterItems), "DropItemFromSlotRPC")]
		private static class Patch_DropItemFromSlotRpc
		{
			private static bool Prefix(CharacterItems __instance, byte slotID)
			{
				//IL_0071: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if ((Object)(object)__instance == (Object)null || (Object)(object)__instance.character == (Object)null || (Object)(object)__instance.character.player == (Object)null)
					{
						return true;
					}
					ItemSlot itemSlot = __instance.character.player.GetItemSlot(slotID);
					if (itemSlot == null || itemSlot.IsEmpty() || !IsProtectedBeltItem(itemSlot.prefab, itemSlot.data))
					{
						return true;
					}
					__instance.character.player.EmptySlot(Optionable<byte>.Some(slotID), true);
					if (__instance.character.refs != null && (Object)(object)__instance.character.refs.afflictions != (Object)null)
					{
						__instance.character.refs.afflictions.UpdateWeight();
					}
					return false;
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Protected belt slot-drop swallow failed: " + ex.Message));
					return true;
				}
			}
		}

		internal static readonly DataEntryKey FlagKey = (DataEntryKey)165;

		internal static readonly DataEntryKey ActorKey = (DataEntryKey)166;

		internal const int FlagUnprotected = 1;

		internal const int FlagProtected = 2;

		private static string _pendingPrefab;

		private static bool _pendingProtected;

		private static float _pendingUntil;

		private static readonly Dictionary<int, int> _flagByView = new Dictionary<int, int>();

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

		public static void ExpectSpawn(string prefabName, bool isProtected)
		{
			_pendingPrefab = prefabName ?? string.Empty;
			_pendingProtected = isProtected;
			_pendingUntil = Time.unscaledTime + 8f;
		}

		public static void Apply(Item item, bool isProtected)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			if (!((Object)(object)item == (Object)null))
			{
				if (item.data == null)
				{
					item.data = new ItemInstanceData(Guid.NewGuid());
					ItemInstanceDataHandler.AddInstanceData(item.data);
				}
				Apply(item.data, isProtected);
				RememberView(item, isProtected);
				CopyToHolderSlot(item);
				PushItemInstanceData(item);
			}
		}

		public static void Apply(ItemInstanceData data, bool isProtected)
		{
			//IL_0005: 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)
			if (data != null)
			{
				SetInt(data, FlagKey, (!isProtected) ? 1 : 2);
				SetInt(data, ActorKey, LocalActor());
			}
		}

		public static bool IsProtectedBeltItem(Item item)
		{
			if ((Object)(object)item != (Object)null)
			{
				return ReadFlag(item.data) == 2;
			}
			return false;
		}

		public static bool IsProtectedBeltItem(Item prefab, ItemInstanceData data)
		{
			return ReadFlag(data) == 2;
		}

		public static bool IsBeltMarked(ItemInstanceData data)
		{
			int num = ReadFlag(data);
			if (num != 2)
			{
				return num == 1;
			}
			return true;
		}

		public static int FindOwnedSlot(Player player, BeltEntry entry)
		{
			if ((Object)(object)player == (Object)null || entry == null)
			{
				return -1;
			}
			int num = FindSlot(player.itemSlots, entry);
			if (num >= 0)
			{
				return num;
			}
			if (SlotMatches(player.tempFullSlot, entry))
			{
				if (player.tempFullSlot == null)
				{
					return -1;
				}
				return player.tempFullSlot.itemSlotID;
			}
			return -1;
		}

		public static bool HasOwnedCopy(Player player, BeltEntry entry)
		{
			if ((Object)(object)FindHeld(entry) != (Object)null)
			{
				return true;
			}
			if (FindOwnedSlot(player, entry) >= 0)
			{
				return true;
			}
			return HasInBackpack(player, entry);
		}

		public static Item FindHeld(BeltEntry entry)
		{
			Character localCharacter = Character.localCharacter;
			if ((Object)(object)localCharacter != (Object)null && (Object)(object)localCharacter.data != (Object)null && SameItem(localCharacter.data.currentItem, entry))
			{
				return localCharacter.data.currentItem;
			}
			return FindLive(entry, held: true, ground: false);
		}

		public static Item FindWorldCopy(BeltEntry entry)
		{
			return FindLive(entry, held: false, ground: true);
		}

		public static bool CanPickup(Player player, BeltEntry entry)
		{
			if ((Object)(object)player == (Object)null || entry == null)
			{
				return false;
			}
			try
			{
				return player.HasEmptySlot(entry.ItemId);
			}
			catch
			{
				return FindEmptyPocketIndex(player) >= 0;
			}
		}

		public static int FindEmptyPocketIndex(Player player)
		{
			if ((Object)(object)player == (Object)null || player.itemSlots == null)
			{
				return -1;
			}
			for (int i = 0; i < player.itemSlots.Length; i++)
			{
				if (player.itemSlots[i] != null && player.itemSlots[i].IsEmpty())
				{
					return i;
				}
			}
			return -1;
		}

		public static bool TryDestroyWorld(Item item)
		{
			if ((Object)(object)item == (Object)null || (Object)(object)((Component)item).gameObject == (Object)null)
			{
				return false;
			}
			try
			{
				PhotonView val = ItemView(item);
				if ((Object)(object)val != (Object)null && (val.IsMine || PhotonNetwork.IsMasterClient))
				{
					PhotonNetwork.Destroy(((Component)item).gameObject);
					return true;
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not destroy leftover belt item: " + ex.Message));
			}
			return false;
		}

		internal static bool SameItem(Item prefabOrInstance, BeltEntry entry)
		{
			if ((Object)(object)prefabOrInstance == (Object)null || entry == null)
			{
				return false;
			}
			if (entry.ItemId != 0 && prefabOrInstance.itemID == entry.ItemId)
			{
				return true;
			}
			if ((Object)(object)entry.Prefab != (Object)null && prefabOrInstance.itemID == entry.Prefab.itemID)
			{
				return true;
			}
			return string.Equals(ToolBeltItems.PrefabName(prefabOrInstance), entry.PrefabName, StringComparison.OrdinalIgnoreCase);
		}

		private static Item FindLive(BeltEntry entry, bool held, bool ground)
		{
			//IL_002f: 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_0034: 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_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			if (entry == null)
			{
				return null;
			}
			Character localCharacter = Character.localCharacter;
			List<Item> aLL_ACTIVE_ITEMS = Item.ALL_ACTIVE_ITEMS;
			if (aLL_ACTIVE_ITEMS == null)
			{
				return null;
			}
			Item result = null;
			float num = 25f;
			Vector3 val = (((Object)(object)localCharacter != (Object)null) ? localCharacter.Center : Vector3.zero);
			for (int i = 0; i < aLL_ACTIVE_ITEMS.Count; i++)
			{
				Item val2 = aLL_ACTIVE_ITEMS[i];
				if ((Object)(object)val2 == (Object)null || (Object)(object)((Component)val2).gameObject == (Object)null || !SameItem(val2, entry))
				{
					continue;
				}
				if (held)
				{
					if ((Object)(object)val2.holderCharacter == (Object)(object)localCharacter)
					{
						return val2;
					}
				}
				else
				{
					if (!ground || (int)val2.itemState != 0 || ((Object)(object)val2.holderCharacter != (Object)null && (Object)(object)val2.holderCharacter != (Object)(object)localCharacter))
					{
						continue;
					}
					if ((Object)(object)val2.lastHolderCharacter == (Object)(object)localCharacter || IsBeltMarked(val2.data))
					{
						return val2;
					}
					if (!((Object)(object)val2.lastHolderCharacter != (Object)null) && !((Object)(object)localCharacter == (Object)null))
					{
						float num2 = Vector3.Distance(val2.transform.position, val);
						if (num2 < num)
						{
							result = val2;
							num = num2;
						}
					}
				}
			}
			return result;
		}

		private static int FindSlot(ItemSlot[] slots, BeltEntry entry)
		{
			if (slots == null)
			{
				return -1;
			}
			for (int i = 0; i < slots.Length; i++)
			{
				if (SlotMatches(slots[i], entry))
				{
					return i;
				}
			}
			return -1;
		}

		private static bool HasInBackpack(Player player, BeltEntry entry)
		{
			if ((Object)(object)player == (Object)null || player.backpackSlot == null || ((ItemSlot)player.backpackSlot).IsEmpty() || ((ItemSlot)player.backpackSlot).data == null)
			{
				return false;
			}
			BackpackData val = default(BackpackData);
			if (!((ItemSlot)player.backpackSlot).data.TryGetDataEntry<BackpackData>((DataEntryKey)7, ref val) || val == null || val.itemSlots == null)
			{
				return false;
			}
			return FindSlot(val.itemSlots, entry) >= 0;
		}

		private static bool SlotMatches(ItemSlot slot, BeltEntry entry)
		{
			if (slot != null && !slot.IsEmpty() && (Object)(object)slot.prefab != (Object)null)
			{
				return SameItem(slot.prefab, entry);
			}
			return false;
		}

		private static void CopyToHolderSlot(Item item)
		{
			if ((Object)(object)item == (Object)null || item.data == null)
			{
				return;
			}
			Character holder = (((Object)(object)item.holderCharacter != (Object)null) ? item.holderCharacter : Character.localCharacter);
			ItemSlot val = FindSlotForItem(item, holder);
			if (val != null)
			{
				if (val.data == null)
				{
					val.data = item.data;
				}
				else
				{
					Apply(val.data, ReadFlag(item.data) == 2);
				}
			}
		}

		private static ItemSlot FindSlotForItem(Item item, Character holder)
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)item == (Object)null || (Object)(object)holder == (Object)null || (Object)(object)holder.player == (Object)null)
			{
				return null;
			}
			if (item.data != null && item.data.guid != Guid.Empty)
			{
				ItemSlot val = FindSlotByGuid(holder, item.data.guid);
				if (val != null)
				{
					return val;
				}
			}
			if ((Object)(object)holder.data != (Object)null && (Object)(object)holder.data.currentItem == (Object)(object)item && holder.refs != null && (Object)(object)holder.refs.items != (Object)null)
			{
				Optionable<byte> currentSelectedSlot = holder.refs.items.currentSelectedSlot;
				if (currentSelectedSlot.IsSome)
				{
					return holder.player.GetItemSlot(currentSelectedSlot.Value);
				}
			}
			return null;
		}

		private static ItemSlot FindSlotByGuid(Character holder, Guid guid)
		{
			if ((Object)(object)holder == (Object)null || (Object)(object)holder.player == (Object)null || guid == Guid.Empty)
			{
				return null;
			}
			ItemSlot val = FindSlotByGuid(holder.player.itemSlots, guid);
			if (val != null)
			{
				return val;
			}
			if (SlotHasGuid(holder.player.tempFullSlot, guid))
			{
				return holder.player.tempFullSlot;
			}
			if (holder.player.backpackSlot == null || ((ItemSlot)holder.player.backpackSlot).IsEmpty() || ((ItemSlot)holder.player.backpackSlot).data == null)
			{
				return null;
			}
			BackpackData val2 = default(BackpackData);
			if (!((ItemSlot)holder.player.backpackSlot).data.TryGetDataEntry<BackpackData>((DataEntryKey)7, ref val2) || val2 == null)
			{
				return null;
			}
			return FindSlotByGuid(val2.itemSlots, guid);
		}

		private static ItemSlot FindSlotByGuid(ItemSlot[] slots, Guid guid)
		{
			if (slots == null)
			{
				return null;
			}
			for (int i = 0; i < slots.Length; i++)
			{
				if (SlotHasGuid(slots[i], guid))
				{
					return slots[i];
				}
			}
			return null;
		}

		private static bool SlotHasGuid(ItemSlot slot, Guid guid)
		{
			if (slot != null && slot.data != null)
			{
				return slot.data.guid == guid;
			}
			return false;
		}

		private static void PushItemInstanceData(Item item)
		{
			if ((Object)(object)item == (Object)null || item.data == null)
			{
				return;
			}
			PhotonView val = ItemView(item);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			try
			{
				if ((!PhotonNetwork.InRoom || val.IsMine || PhotonNetwork.IsMasterClient) && PhotonNetwork.InRoom)
				{
					val.RPC("SetItemInstanceDataRPC", (RpcTarget)1, new object[1] { item.data });
				}
			}
			catch
			{
			}
		}

		private static void RememberView(Item item, bool isProtected)
		{
			PhotonView val = ItemView(item);
			if (!((Object)(object)val == (Object)null))
			{
				_flagByView[val.ViewID] = ((!isProtected) ? 1 : 2);
			}
		}

		private static void RestoreRemembered(Item item)
		{
			PhotonView val = ItemView(item);
			if (!((Object)(object)val == (Object)null) && _flagByView.TryGetValue(val.ViewID, out var value))
			{
				Apply(item, value == 2);
			}
		}

		private static PhotonView ItemView(Item item)
		{
			if ((Object)(object)item == (Object)null)
			{
				return null;
			}
			if ((Object)(object)((MonoBehaviourPun)item).photonView != (Object)null)
			{
				return ((MonoBehaviourPun)item).photonView;
			}
			return item.view;
		}

		private static int LocalActor()
		{
			try
			{
				if (PhotonNetwork.InRoom && PhotonNetwork.LocalPlayer != null)
				{
					return PhotonNetwork.LocalPlayer.ActorNumber;
				}
			}
			catch
			{
			}
			return 0;
		}

		private static int ReadFlag(ItemInstanceData data)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			if (data == null)
			{
				return 0;
			}
			IntItemData val = default(IntItemData);
			if (data.TryGetDataEntry<IntItemData>(FlagKey, ref val) && val != null)
			{
				return val.Value;
			}
			return 0;
		}

		private static void SetInt(ItemInstanceData data, DataEntryKey key, int value)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			if (data != null)
			{
				IntItemData val = default(IntItemData);
				if (data.TryGetDataEntry<IntItemData>(key, ref val) && val != null)
				{
					val.Value = value;
					return;
				}
				IntItemData val2 = new IntItemData();
				((DataEntryValue)val2).Init();
				val2.Value = value;
				data.RegisterEntry<IntItemData>(key, val2);
			}
		}

		private static bool PendingMatches(Item item)
		{
			if ((Object)(object)item == (Object)null || string.IsNullOrEmpty(_pendingPrefab) || Time.unscaledTime > _pendingUntil)
			{
				return false;
			}
			if (!string.Equals(ToolBeltItems.PrefabName(item), _pendingPrefab, StringComparison.OrdinalIgnoreCase) && !string.Equals(((Object)item).name, _pendingPrefab, StringComparison.OrdinalIgnoreCase))
			{
				if (!string.IsNullOrEmpty(((Object)item).name))
				{
					return ((Object)item).name.StartsWith(_pendingPrefab, StringComparison.OrdinalIgnoreCase);
				}
				return false;
			}
			return true;
		}

		private static void ClearPending()
		{
			_pendingPrefab = null;
			_pendingUntil = 0f;
		}

		private static void ScheduleDeferredTag(Item item)
		{
			if (!((Object)(object)item == (Object)null) && !((Object)(object)Plugin.Instance == (Object)null))
			{
				int instanceID = ((Object)item).GetInstanceID();
				if (_tagInFlight.Add(instanceID))
				{
					((MonoBehaviour)Plugin.Instance).StartCoroutine(DeferredTag(item, instanceID));
				}
			}
		}

		private static IEnumerator DeferredTag(Item item, int key)
		{
			yield return (object)new WaitForSeconds(0.2f);
			try
			{
				if (!((Object)(object)item == (Object)null) && (PendingMatches(item) || ReadFlag(item.data) != 0 || _flagByView.ContainsKey(((Object)(object)ItemView(item) != (Object)null) ? ItemView(item).ViewID : 0)))
				{
					bool isProtected = (PendingMatches(item) ? _pendingProtected : (ReadFlag(item.data) == 2 || IsProtectedBeltItem(item)));
					Apply(item, isProtected);
					if (PendingMatches(item))
					{
						ClearPending();
					}
				}
			}
			finally
			{
				_tagInFlight.Remove(key);
			}
		}

		private static void CancelHeldProtected(CharacterItems items, byte slotID)
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			Character character = items.character;
			Item val = (((Object)(object)character.data != (Object)null) ? character.data.currentItem : null);
			items.UnAttachEquippedItem();
			if ((Object)(object)val != (Object)null)
			{
				PhotonView val2 = ItemView(val);
				if ((Object)(object)val2 != (Object)null && (val2.IsMine || (val2.Controller != null && val2.Controller.IsMasterClient && PhotonNetwork.IsMasterClient)))
				{
					PhotonNetwork.Destroy(((Component)val).gameObject);
				}
			}
			if ((Object)(object)character.player != (Object)null)
			{
				character.player.EmptySlot(Optionable<byte>.Some(slotID), true);
			}
			items.pressedDrop = false;
			items.throwChargeLevel = 0f;
			if (character.refs != null && (Object)(object)character.refs.afflictions != (Object)null)
			{
				character.refs.afflictions.UpdateWeight();
			}
		}
	}
	internal static class ToolBeltHud
	{
		private sealed class SlotView
		{
			public int Index;

			public InventoryItemUI Ui;

			public RectTransform Rect;

			public Vector2 BaseSize;

			public ItemSlot FakeSlot;

			public string DisplayName;

			public Image Fill;

			public Image Outline;

			public Image SelectedIcon;

			public TextMeshProUGUI NameText;
		}

		private static RectTransform _root;

		private static readonly List<SlotView> _slots = new List<SlotView>();

		private static int _selected = -1;

		private static bool _loggedMissingHud;

		private static bool _loggedLayout;

		private static Vector2 _cachedSlotSize = new Vector2(72f, 72f);

		public static bool Show(int selected)
		{
			if (!EnsureRoot())
			{
				return false;
			}
			((Component)_root).gameObject.SetActive(true);
			Rebuild(selected);
			if ((Object)(object)_root != (Object)null)
			{
				return _slots.Count > 0;
			}
			return false;
		}

		public static void Hide()
		{
			if ((Object)(object)_root != (Object)null)
			{
				((Component)_root).gameObject.SetActive(false);
			}
			_selected = -1;
		}

		public static void Rebuild(int selected)
		{
			//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_004b: 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_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: 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_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			if (!EnsureRoot())
			{
				return;
			}
			ClearSlots();
			InventoryItemUI donor = GetDonor();
			if ((Object)(object)donor == (Object)null)
			{
				return;
			}
			IReadOnlyList<BeltEntry> visible = ToolBeltItems.Visible;
			int num = Plugin.ColumnCount();
			int count = visible.Count;
			int num2 = ((count > 0) ? Mathf.CeilToInt((float)count / (float)num) : 0);
			Vector2 val = (_cachedSlotSize = DonorSize(donor));
			float num3 = Mathf.Max(6f, val.x * 0.08f);
			float num4 = (float)num * val.x + (float)Mathf.Max(0, num - 1) * num3;
			float num5 = (float)num2 * val.y + (float)Mathf.Max(0, num2 - 1) * num3;
			_root.sizeDelta = new Vector2(num4, num5);
			for (int i = 0; i < count; i++)
			{
				int num6 = i / num;
				int num7 = i % num;
				float num8 = (0f - num4) * 0.5f + val.x * 0.5f + (float)num7 * (val.x + num3);
				float num9 = val.y * 0.5f + (float)(num2 - 1 - num6) * (val.y + num3);
				SlotView slotView = CreateSlot(donor, i, visible[i], new Vector2(num8, num9), val);
				if (slotView != null)
				{
					_slots.Add(slotView);
				}
			}
			PlaceAboveHotbar(donor, val);
			RefreshSelection(selected);
			LogLayout(donor, val, count);
		}

		public static void RefreshSelection(int selected)
		{
			_selected = selected;
			for (int i = 0; i < _slots.Count; i++)
			{
				ApplySelected(_slots[i], i == selected);
			}
		}

		public static void DestroyHud()
		{
			ClearSlots();
			if ((Object)(object)_root != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)_root).gameObject);
				_root = null;
			}
		}

		private static bool EnsureRoot()
		{
			//IL_008d: 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_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_root != (Object)null)
			{
				return true;
			}
			GUIManager instance = GUIManager.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.hudCanvas == (Object)null)
			{
				if (!_loggedMissingHud)
				{
					Plugin.Log.LogWarning((object)"Vanilla HUD is not ready yet.");
					_loggedMissingHud = true;
				}
				return false;
			}
			if ((Object)(object)GetDonor() == (Object)null)
			{
				if (!_loggedMissingHud)
				{
					Plugin.Log.LogWarning((object)"Vanilla inventory slots are not ready yet.");
					_loggedMissingHud = true;
				}
				return false;
			}
			GameObject val = new GameObject("ToolBeltHud", new Type[1] { typeof(RectTransform) });
			_root = val.GetComponent<RectTransform>();
			((Transform)_root).SetParent(((Component)instance.hudCanvas).transform, false);
			_root.anchorMin = new Vector2(0.5f, 0f);
			_root.anchorMax = new Vector2(0.5f, 0f);
			_root.pivot = new Vector2(0.5f, 0f);
			_root.anchoredPosition = new Vector2(0f, 180f);
			((Transform)_root).localScale = Vector3.one;
			((Transform)_root).SetAsLastSibling();
			val.SetActive(false);
			_loggedMissingHud = false;
			return true;
		}

		private static SlotView CreateSlot(InventoryItemUI donor, int index, BeltEntry entry, Vector2 anchored, Vector2 size)
		{
			//IL_0042: 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)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: 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_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Expected O, but got Unknown
			GameObject val = Object.Instantiate<GameObject>(((Component)donor).gameObject, (Transform)(object)_root, false);
			((Object)val).name = "ToolBeltSlot_" + index;
			val.SetActive(true);
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0.5f, 0f);
			component.anchorMax = new Vector2(0.5f, 0f);
			component.pivot = new Vector2(0.5f, 0.5f);
			component.anchoredPosition = anchored;
			component.sizeDelta = size;
			((Transform)component).localScale = Vector3.one;
			InventoryItemUI component2 = val.GetComponent<InventoryItemUI>();
			if ((Object)(object)component2 == (Object)null)
			{
				Object.Destroy((Object)(object)val);
				return null;
			}
			component2.isBackpack = false;
			component2.isTemporarySlot = false;
			component2.rectTransform = component;
			component2.startingSizeDelta = size;
			if ((Object)(object)component2.backpackFilledSlotsObject != (Object)null)
			{
				component2.backpackFilledSlotsObject.SetActive(false);
			}
			if ((Object)(object)component2.fuelBar != (Object)null)
			{
				component2.fuelBar.SetActive(false);
			}
			StripVanillaLayout(val);
			StripHotbarChrome(val, component2);
			EnsureHitTarget(val);
			(val.GetComponent<ToolBeltSlotPointer>() ?? val.AddComponent<ToolBeltSlotPointer>()).Index = index;
			SlotView obj = new SlotView
			{
				Index = index,
				Ui = component2,
				Rect = component,
				BaseSize = size,
				FakeSlot = new ItemSlot((byte)0),
				DisplayName = ((entry != null) ? entry.DisplayName : string.Empty),
				Fill = component2.fill,
				Outline = component2.outline,
				SelectedIcon = component2.selectedSlotIcon,
				NameText = component2.nameText
			};
			BindItem(obj, entry);
			ApplySelected(obj, selected: false);
			return obj;
		}

		private static void BindItem(SlotView view, BeltEntry entry)
		{
			if (view == null || (Object)(object)view.Ui == (Object)null)
			{
				return;
			}
			if (entry == null || (Object)(object)entry.Prefab == (Object)null)
			{
				view.Ui.Clear();
				RestoreIdleChrome(view);
				return;
			}
			view.DisplayName = entry.DisplayName;
			if ((Object)(object)view.NameText != (Object)null)
			{
				((TMP_Text)view.NameText).text = entry.DisplayName;
			}
			view.Ui._itemPrefab = entry.Prefab;
			view.Ui._itemData = null;
			try
			{
				view.FakeSlot.SetItem(entry.Prefab, (ItemInstanceData)null);
			}
			catch
			{
				view.FakeSlot.prefab = entry.Prefab;
				view.FakeSlot.data = null;
			}
			view.Ui.SetItem(view.FakeSlot);
			ForceIcon(view, entry);
			RestoreIdleChrome(view);
		}

		private static void ForceIcon(SlotView view, BeltEntry entry)
		{
			//IL_008c: 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)
			InventoryItemUI ui = view.Ui;
			if ((Object)(object)ui == (Object)null || entry == null || (Object)(object)entry.Prefab == (Object)null)
			{
				return;
			}
			Texture val = null;
			try
			{
				if (entry.Prefab.UIData != null)
				{
					val = (Texture)(object)entry.Prefab.UIData.GetIcon();
				}
			}
			catch
			{
			}
			if ((Object)(object)ui.icon != (Object)null)
			{
				if ((Object)(object)val != (Object)null)
				{
					ui.icon.texture = val;
				}
				((Behaviour)ui.icon).enabled = (Object)(object)ui.icon.texture != (Object)null;
				((Graphic)ui.icon).color = Color.white;
				((Component)ui.icon).transform.localScale = Vector3.one;
				((Graphic)ui.icon).raycastTarget = false;
			}
			if ((Object)(object)view.NameText != (Object)null)
			{
				((TMP_Text)view.NameText).text = entry.DisplayName;
				((Component)view.NameText).gameObject.SetActive(true);
				((Behaviour)view.NameText).enabled = false;
				((TMP_Text)view.NameText).overflowMode = (TextOverflowModes)0;
				((Graphic)view.NameText).raycastTarget = false;
			}
		}

		private static void RestoreIdleChrome(SlotView view)
		{
			if (view != null)
			{
				if ((Object)(object)view.Outline != (Object)null)
				{
					((Behaviour)view.Outline).enabled = true;
				}
				if ((Object)(object)view.Fill != (Object)null)
				{
					((Behaviour)view.Fill).enabled = false;
				}
				if ((Object)(object)view.SelectedIcon != (Object)null)
				{
					((Behaviour)view.SelectedIcon).enabled = false;
				}
			}
		}

		private static void ApplySelected(SlotView view, bool selected)
		{
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			if (view == null)
			{
				return;
			}
			if ((Object)(object)view.Outline != (Object)null)
			{
				((Behaviour)view.Outline).enabled = true;
			}
			if ((Object)(object)view.Fill != (Object)null)
			{
				((Behaviour)view.Fill).enabled = selected;
			}
			if ((Object)(object)view.SelectedIcon != (Object)null)
			{
				((Behaviour)view.SelectedIcon).enabled = selected;
			}
			if ((Object)(object)view.NameText != (Object)null)
			{
				if (!string.IsNullOrEmpty(view.DisplayName))
				{
					((TMP_Text)view.NameText).text = view.DisplayName;
				}
				((Component)view.NameText).gameObject.SetActive(true);
				((Behaviour)view.NameText).enabled = selected && !string.IsNullOrEmpty(((TMP_Text)view.NameText).text);
				((Graphic)view.NameText).raycastTarget = false;
			}
			if ((Object)(object)view.Rect != (Object)null)
			{
				view.Rect.sizeDelta = (selected ? (view.BaseSize * 1.2f) : view.BaseSize);
				if ((Object)(object)view.Ui != (Object)null)
				{
					view.Ui.startingSizeDelta = view.BaseSize;
				}
			}
		}

		private static void PlaceAboveHotbar(InventoryItemUI donor, Vector2 slotSize)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_root == (Object)null)
			{
				return;
			}
			float num = Mathf.Max(24f, slotSize.y * 0.35f);
			float num2 = 180f;
			RectTransform val = (RectTransform)(((Object)(object)GUIManager.instance != (Object)null && (Object)(object)GUIManager.instance.hudCanvas != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
			Rect rect;
			if ((Object)(object)donor != (Object)null && (Object)(object)donor.rectTransform != (Object)null && (Object)(object)val != (Object)null)
			{
				Vector3[] array = (Vector3[])(object)new Vector3[4];
				donor.rectTransform.GetWorldCorners(array);
				Camera val2 = CanvasCamera(val);
				Vector2 val3 = RectTransformUtility.WorldToScreenPoint(val2, (array[1] + array[2]) * 0.5f);
				Vector2 val4 = default(Vector2);
				if (RectTransformUtility.ScreenPointToLocalPointInRectangle(val, val3, val2, ref val4))
				{
					float y = val4.y;
					rect = val.rect;
					num2 = y - ((Rect)(ref rect)).yMin + num;
				}
			}
			float num3 = 120f;
			float num4;
			if (!((Object)(object)val != (Object)null))
			{
				num4 = 400f;
			}
			else
			{
				rect = val.rect;
				num4 = Mathf.Max(num3, ((Rect)(ref rect)).height - 80f);
			}
			float num5 = num4;
			num2 = Mathf.Clamp(num2, num3, num5);
			((Transform)_root).localScale = Vector3.one;
			_root.anchoredPosition = new Vector2(0f, num2);
		}

		private static Camera CanvasCamera(RectTransform canvasRt)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			Canvas val = (((Object)(object)canvasRt != (Object)null) ? ((Component)canvasRt).GetComponent<Canvas>() : null);
			if ((Object)(object)val == (Object)null || (int)val.renderMode == 0)
			{
				return null;
			}
			if (!((Object)(object)val.worldCamera != (Object)null))
			{
				return Camera.main;
			}
			return val.worldCamera;
		}

		private static void LogLayout(InventoryItemUI donor, Vector2 size, int count)
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			if (!_loggedLayout && !((Object)(object)_root == (Object)null))
			{
				_loggedLayout = true;
				Plugin.Log.LogInfo((object)("Tool belt HUD: " + count + " slots, size=" + size.x.ToString("0") + "x" + size.y.ToString("0") + ", pos=" + ((object)_root.anchoredPosition/*cast due to .constrained prefix*/).ToString() + ", donor=" + (((Object)(object)donor != (Object)null) ? ((Object)donor).name : "none")));
			}
		}

		private static InventoryItemUI GetDonor()
		{
			GUIManager instance = GUIManager.instance;
			if ((Object)(object)instance == (Object)null || instance.items == null)
			{
				return null;
			}
			for (int i = 0; i < instance.items.Length; i++)
			{
				if ((Object)(object)instance.items[i] != (Object)null)
				{
					return instance.items[i];
				}
			}
			return instance.temporaryItem;
		}

		private static Vector2 DonorSize(InventoryItemUI donor)
		{
			//IL_0022: 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_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0053: 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_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: 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_0088: Unknown result type (might be due to invalid IL or missing references)
			Vector2 result = (Vector2)((_cachedSlotSize.x >= 24f) ? _cachedSlotSize : new Vector2(72f, 72f));
			if ((Object)(object)donor != (Object)null && (Object)(object)donor.rectTransform != (Object)null)
			{
				Rect rect = donor.rectTransform.rect;
				Vector2 size = ((Rect)(ref rect)).size;
				if (size.x >= 24f && size.x <= 160f && size.y >= 24f && size.y <= 160f)
				{
					result = size;
				}
			}
			return result;
		}

		private static void StripVanillaLayout(GameObject clone)
		{
			LayoutElement component = clone.GetComponent<LayoutElement>();
			if ((Object)(object)component != (Object)null)
			{
				component.ignoreLayout = true;
			}
		}

		private static void StripHotbarChrome(GameObject clone, InventoryItemUI ui)
		{
			if ((Object)(object)clone == (Object)null)
			{
				return;
			}
			TextMeshProUGUI[] componentsInChildren = clone.GetComponentsInChildren<TextMeshProUGUI>(true);
			foreach (TextMeshProUGUI val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)ui.nameText))
				{
					((Behaviour)val).enabled = false;
					((Component)val).gameObject.SetActive(false);
				}
			}
			for (int j = 0; j < clone.transform.childCount; j++)
			{
				Transform child = clone.transform.GetChild(j);
				if (!((Object)(object)child == (Object)null))
				{
					string text = ((Object)child).name ?? string.Empty;
					if (text.IndexOf("key", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("bind", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("prompt", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("hotkey", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("shortcut", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						((Component)child).gameObject.SetActive(false);
					}
				}
			}
		}

		private static void EnsureHitTarget(GameObject clone)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid