Decompiled source of Outfitter 6 slots v0.7.0

plugins/Tenemo.Outfitter.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Outfitter.Equip;
using Outfitter.Loadouts;
using Outfitter.Stands;
using Outfitter.Window;
using QoLMods.Catalogue;
using QoLMods.Chests;
using QoLMods.ItemMarks;
using QoLMods.Kit;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Outfitter
{
	internal static class Eaqs
	{
		internal static class Json
		{
			internal static List<string> Strings(string json)
			{
				List<string> list = new List<string>();
				if (string.IsNullOrEmpty(json))
				{
					return list;
				}
				int i = 0;
				Skip(json, ref i);
				if (i >= json.Length || json[i] != '[')
				{
					return list;
				}
				i++;
				while (true)
				{
					Skip(json, ref i);
					if (i >= json.Length || json[i] == ']')
					{
						return list;
					}
					string text = ReadString(json, ref i);
					if (text == null)
					{
						break;
					}
					list.Add(text);
					Skip(json, ref i);
					if (i < json.Length && json[i] == ',')
					{
						i++;
					}
				}
				return list;
			}

			internal static Dictionary<string, string> Object(string json)
			{
				if (string.IsNullOrEmpty(json))
				{
					return null;
				}
				Dictionary<string, string> dictionary = new Dictionary<string, string>();
				int i = 0;
				Skip(json, ref i);
				if (i >= json.Length || json[i] != '{')
				{
					return null;
				}
				i++;
				while (true)
				{
					Skip(json, ref i);
					if (i >= json.Length)
					{
						return null;
					}
					if (json[i] == '}')
					{
						return dictionary;
					}
					string text = ReadString(json, ref i);
					Skip(json, ref i);
					if (text == null || i >= json.Length || json[i] != ':')
					{
						return null;
					}
					i++;
					Skip(json, ref i);
					if (i >= json.Length)
					{
						return null;
					}
					string text2;
					if (json[i] == '"')
					{
						text2 = ReadString(json, ref i);
					}
					else
					{
						int num = i;
						for (; i < json.Length && json[i] != ',' && json[i] != '}' && !char.IsWhiteSpace(json[i]); i++)
						{
						}
						text2 = json.Substring(num, i - num);
					}
					if (text2 == null)
					{
						break;
					}
					dictionary[text] = text2;
					Skip(json, ref i);
					if (i < json.Length && json[i] == ',')
					{
						i++;
					}
				}
				return null;
			}

			private static void Skip(string json, ref int i)
			{
				while (i < json.Length && char.IsWhiteSpace(json[i]))
				{
					i++;
				}
			}

			private static string ReadString(string json, ref int i)
			{
				if (i >= json.Length || json[i] != '"')
				{
					return null;
				}
				StringBuilder stringBuilder = new StringBuilder();
				i++;
				while (i < json.Length)
				{
					char c = json[i];
					switch (c)
					{
					case '"':
						i++;
						return stringBuilder.ToString();
					case '\\':
						if (i + 1 < json.Length)
						{
							c = json[++i];
						}
						break;
					}
					stringBuilder.Append(c);
					i++;
				}
				return null;
			}
		}

		internal const string Guid = "randyknapp.mods.equipmentandquickslots";

		private static MethodInfo getVisibleRows;

		private static MethodInfo getSlotIdsJson;

		private static MethodInfo getSlotInfoJson;

		private static bool warned;

		internal static bool Present { get; private set; }

		internal static bool Usable { get; private set; }

		internal static void Find(ManualLogSource log)
		{
			Present = false;
			Usable = false;
			if (!Chainloader.PluginInfos.TryGetValue("randyknapp.mods.equipmentandquickslots", out var value) || (Object)(object)((value != null) ? value.Instance : null) == (Object)null)
			{
				return;
			}
			Present = true;
			try
			{
				Type? type = ((object)value.Instance).GetType().Assembly.GetType("EquipmentAndQuickSlots.API", throwOnError: false);
				getVisibleRows = type?.GetMethod("GetVisibleRows", BindingFlags.Static | BindingFlags.Public, null, Type.EmptyTypes, null);
				getSlotIdsJson = type?.GetMethod("GetSlotIdsJson", BindingFlags.Static | BindingFlags.Public, null, Type.EmptyTypes, null);
				getSlotInfoJson = type?.GetMethod("GetSlotInfoJson", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(string) }, null);
				Usable = getVisibleRows != null && getVisibleRows.ReturnType == typeof(int) && getSlotIdsJson != null && getSlotIdsJson.ReturnType == typeof(string) && getSlotInfoJson != null && getSlotInfoJson.ReturnType == typeof(string);
			}
			catch (Exception ex)
			{
				Usable = false;
				if (log != null)
				{
					log.LogWarning((object)("EquipmentAndQuickSlots' interface couldn't be looked up (" + ex.Message + ")."));
				}
			}
			if (Usable)
			{
				if (log != null)
				{
					BepInPlugin metadata = value.Metadata;
					log.LogInfo((object)$"Found EquipmentAndQuickSlots {((metadata != null) ? metadata.Version : null)}: loadouts use its slots.");
				}
			}
			else if (log != null)
			{
				BepInPlugin metadata2 = value.Metadata;
				log.LogWarning((object)($"EquipmentAndQuickSlots {((metadata2 != null) ? metadata2.Version : null)} is installed, but its interface wasn't found: " + "Outfitter leaves its rows alone (items saved in its slots go to free cells)."));
			}
		}

		internal static int VisibleRows()
		{
			if (!Usable)
			{
				return -1;
			}
			try
			{
				return (int)getVisibleRows.Invoke(null, null);
			}
			catch (Exception error)
			{
				Broke(error);
				return -1;
			}
		}

		internal static void AddSlots(GridShape grid)
		{
			if (!Usable)
			{
				return;
			}
			try
			{
				foreach (string item in Json.Strings((string)getSlotIdsJson.Invoke(null, null)))
				{
					if (LoadoutText.IsSlotId(item))
					{
						Dictionary<string, string> dictionary = Json.Object((string)getSlotInfoJson.Invoke(null, new object[1] { item }));
						if (dictionary != null && dictionary.TryGetValue("active", out var value) && !(value != "true") && dictionary.TryGetValue("gridX", out var value2) && LoadoutText.TryInt(value2, out var value3) && dictionary.TryGetValue("gridY", out var value4) && LoadoutText.TryInt(value4, out var value5) && value3 >= 0 && value3 < grid.Width && value5 >= grid.Rows && value5 < grid.Height)
						{
							grid.Slots[item] = new SlotCell
							{
								X = value3,
								Y = value5,
								Quick = (dictionary.TryGetValue("isQuickSlot", out var value6) && value6 == "true"),
								Equipment = (dictionary.TryGetValue("isEquipmentSlot", out var value7) && value7 == "true")
							};
						}
					}
				}
			}
			catch (Exception error)
			{
				grid.Slots.Clear();
				Broke(error);
			}
		}

		private static void Broke(Exception error)
		{
			Usable = false;
			if (!warned)
			{
				warned = true;
				Module.Warn("EquipmentAndQuickSlots' interface stopped answering (" + error.GetBaseException().Message + "); Outfitter leaves its rows alone for the rest of the session.");
			}
		}
	}
	internal static class FoldDrawer
	{
		private static GUIStyle row;

		private static GUIStyle rowFrom;

		private static GUIStyle title;

		private static GUIStyle titleFrom;

		private static bool lookedForColours;

		private static FieldInfo changedColour;

		private static FieldInfo defaultColour;

		internal static Action<ConfigEntryBase> For(string part, List<ConfigEntryBase> settings)
		{
			return delegate(ConfigEntryBase entry)
			{
				Draw(entry, part, settings);
			};
		}

		private static void Draw(ConfigEntryBase entry, string part, List<ConfigEntryBase> settings)
		{
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			bool num = Changed(settings);
			string text = (num ? "   (changed)" : string.Empty);
			Color contentColor = GUI.contentColor;
			Color? val = ValueColour(num);
			if (val.HasValue)
			{
				Color valueOrDefault = val.GetValueOrDefault();
				GUI.contentColor = valueOrDefault;
			}
			try
			{
				if (!Folds.Live)
				{
					GUILayout.Label(part + text, TitleStyle(), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
					return;
				}
				object boxedValue = entry.BoxedValue;
				bool flag = default(bool);
				int num2;
				if (boxedValue is bool)
				{
					flag = (bool)boxedValue;
					num2 = 1;
				}
				else
				{
					num2 = 0;
				}
				bool flag2 = (byte)((uint)num2 & (flag ? 1u : 0u)) != 0;
				if (GUILayout.Button((flag2 ? "[-] " : "[+] ") + part + text, RowStyle(), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }))
				{
					entry.BoxedValue = !flag2;
				}
			}
			finally
			{
				GUI.contentColor = contentColor;
			}
		}

		private static bool Changed(List<ConfigEntryBase> settings)
		{
			foreach (ConfigEntryBase setting in settings)
			{
				if (!object.Equals(setting.BoxedValue, setting.DefaultValue))
				{
					return true;
				}
			}
			return false;
		}

		private static Color? ValueColour(bool changed)
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			if (!lookedForColours)
			{
				lookedForColours = true;
				Type obj = ((object)ManagerLink.Plugin())?.GetType();
				changedColour = obj?.GetField("_fontColorValueChanged", BindingFlags.Static | BindingFlags.Public);
				defaultColour = obj?.GetField("_fontColorValueDefault", BindingFlags.Static | BindingFlags.Public);
			}
			if (!((changed ? changedColour : defaultColour)?.GetValue(null) is ConfigEntry<Color> val))
			{
				return null;
			}
			return val.Value;
		}

		private static GUIStyle RowStyle()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			if (row == null || rowFrom != GUI.skin.button)
			{
				rowFrom = GUI.skin.button;
				row = new GUIStyle(rowFrom)
				{
					alignment = (TextAnchor)3
				};
			}
			row.fontSize = rowFrom.fontSize;
			return row;
		}

		private static GUIStyle TitleStyle()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			if (title == null || titleFrom != GUI.skin.label)
			{
				titleFrom = GUI.skin.label;
				title = new GUIStyle(titleFrom)
				{
					fontStyle = (FontStyle)1
				};
			}
			title.fontSize = titleFrom.fontSize;
			return title;
		}
	}
	internal static class Folds
	{
		private sealed class Fold
		{
			internal readonly ConfigEntry<bool> Unfolded;

			internal readonly List<ConfigurationManagerAttributes> SettingHints = new List<ConfigurationManagerAttributes>();

			internal Fold(ConfigEntry<bool> unfolded)
			{
				Unfolded = unfolded;
			}
		}

		private const string LiveManagerGuid = "_shudnal.ConfigurationManager";

		private static readonly Version LiveFrom = new Version(1, 1, 22);

		private static readonly List<Fold> folds = new List<Fold>();

		private static bool decided;

		private static bool rebuildWanted;

		internal static Action RebuildList;

		internal static bool Live { get; private set; }

		internal static void Add(ConfigEntry<bool> unfolded, IEnumerable<ConfigEntryBase> settings, string heading)
		{
			Fold fold = new Fold(unfolded);
			ConfigurationManagerAttributes configurationManagerAttributes = ModuleSettings.HintsOf((ConfigEntryBase)(object)unfolded);
			if (configurationManagerAttributes != null)
			{
				configurationManagerAttributes.Category = heading;
				configurationManagerAttributes.HideSettingName = true;
				configurationManagerAttributes.HideDefaultButton = true;
			}
			foreach (ConfigEntryBase setting in settings)
			{
				ConfigurationManagerAttributes configurationManagerAttributes2 = ModuleSettings.HintsOf(setting);
				if (configurationManagerAttributes2 != null)
				{
					configurationManagerAttributes2.Category = heading;
					fold.SettingHints.Add(configurationManagerAttributes2);
				}
			}
			folds.Add(fold);
			Apply(fold);
			unfolded.SettingChanged += delegate
			{
				Apply(fold);
				rebuildWanted |= Live && fold.Unfolded.Value;
			};
		}

		internal static void Tick()
		{
			if (!decided)
			{
				Decide(ManagerFoldsLive());
			}
			if (rebuildWanted)
			{
				rebuildWanted = false;
				try
				{
					RebuildList?.Invoke();
				}
				catch (Exception)
				{
					RebuildList = null;
				}
			}
		}

		private static void Decide(bool live)
		{
			decided = true;
			Live = live;
			foreach (Fold fold in folds)
			{
				Apply(fold);
			}
		}

		private static void Apply(Fold fold)
		{
			bool value = !Live || fold.Unfolded.Value;
			foreach (ConfigurationManagerAttributes settingHint in fold.SettingHints)
			{
				settingHint.Browsable = value;
			}
		}

		private static bool ManagerFoldsLive()
		{
			if (!Chainloader.PluginInfos.TryGetValue("_shudnal.ConfigurationManager", out var value) || value == null)
			{
				return false;
			}
			BepInPlugin metadata = value.Metadata;
			Version version = ((metadata != null) ? metadata.Version : null);
			if (version != null)
			{
				return version >= LiveFrom;
			}
			return false;
		}
	}
	internal static class GameHooks
	{
		private static FieldInfo hiddenRight;

		private static FieldInfo hiddenLeft;

		private static FieldInfo dragGo;

		internal static void Resolve(List<string> missing, List<string> missingOptional)
		{
			hiddenRight = Field(typeof(Humanoid), "m_hiddenRightItem", typeof(ItemData), missing);
			hiddenLeft = Field(typeof(Humanoid), "m_hiddenLeftItem", typeof(ItemData), missing);
			dragGo = Field(typeof(InventoryGui), "m_dragGo", typeof(GameObject), missing);
		}

		private static FieldInfo Field(Type type, string name, Type fieldType, List<string> missing)
		{
			FieldInfo fieldInfo = AccessTools.Field(type, name);
			if (fieldInfo == null || fieldInfo.FieldType != fieldType)
			{
				missing.Add(type.Name + "." + name);
				return null;
			}
			return fieldInfo;
		}

		internal static ItemData HiddenRight(Player player)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			if (!((Object)(object)player != (Object)null))
			{
				return null;
			}
			return (ItemData)hiddenRight.GetValue(player);
		}

		internal static ItemData HiddenLeft(Player player)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			if (!((Object)(object)player != (Object)null))
			{
				return null;
			}
			return (ItemData)hiddenLeft.GetValue(player);
		}

		internal static bool Dragging()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			InventoryGui instance = InventoryGui.instance;
			if ((Object)(object)instance != (Object)null)
			{
				return (Object)(GameObject)dragGo.GetValue(instance) != (Object)null;
			}
			return false;
		}

		internal static GridShape Shape(Player player)
		{
			Inventory inventory = ((Humanoid)player).GetInventory();
			GridShape gridShape = new GridShape
			{
				Width = inventory.GetWidth(),
				Height = inventory.GetHeight()
			};
			int num = (Eaqs.Usable ? Eaqs.VisibleRows() : (-1));
			if (num <= 0)
			{
				num = 4;
				string text = default(string);
				if (player.TryGetUniqueKeyValue("invrows", ref text) && LoadoutText.TryInt(text, out var value))
				{
					num = value;
				}
			}
			gridShape.Rows = Mathf.Clamp(num, 1, gridShape.Height);
			Eaqs.AddSlots(gridShape);
			return gridShape;
		}
	}
	internal static class ManagerLink
	{
		private static bool broken;

		internal static Action Rebuild()
		{
			try
			{
				return RebuildFromJotunn();
			}
			catch (Exception)
			{
				return null;
			}
		}

		internal static BaseUnityPlugin Plugin()
		{
			if (broken)
			{
				return null;
			}
			try
			{
				return PluginFromJotunn();
			}
			catch (Exception)
			{
				broken = true;
				return null;
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static Action RebuildFromJotunn()
		{
			return ConfigManagerUtils.BuildSettingList;
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static BaseUnityPlugin PluginFromJotunn()
		{
			return ConfigManagerUtils.Plugin;
		}
	}
	internal sealed class Module : QoLModule
	{
		internal const string Guid = "tenemo.outfitter";

		internal const string Name = "Outfitter";

		internal const string Version = "0.7.0";

		private static Module current;

		internal static readonly ChestUser Chests = new ChestUser("Outfitter", () => Log, Guard, () => IsOn, null, () => (Settings.Range != null) ? ChestSettings.RangeOf(Settings.Range) : 0f);

		internal const string AzuExtendedPlayerInventory = "Azumatt.AzuExtendedPlayerInventory";

		internal const string ExtraSlots = "shudnal.ExtraSlots";

		internal const string ExtendedPlayerInventory = "aedenthorn.ExtendedPlayerInventory";

		internal const string ComfyQuickSlots = "com.bruce.valheim.comfyquickslots";

		private static readonly (string Guid, string Name)[] Rivals = new(string, string)[4]
		{
			("Azumatt.AzuExtendedPlayerInventory", "AzuExtendedPlayerInventory"),
			("shudnal.ExtraSlots", "ExtraSlots"),
			("aedenthorn.ExtendedPlayerInventory", "Extended Player Inventory"),
			("com.bruce.valheim.comfyquickslots", "ComfyQuickSlots")
		};

		private const string RivalMark = "rival:";

		internal override string Id => "Outfitter";

		internal override string DisplayName => "Outfitter";

		internal override string ModuleVersion => "0.7.0";

		internal override string SingleGuid => "tenemo.outfitter";

		internal override bool OneSectionInBundle => false;

		internal override string EnabledDescription => "Turns the mod on or off. Off closes its window at once, its keys and picks do nothing, and no chest is touched; your saved loadouts stay saved. On brings it all back.";

		internal override string SwitchedOffNote => "Its window doesn't open, and no chest is touched. Saved loadouts stay saved.";

		internal override string UpdateTask => "running its window and the equip under way";

		internal override string LateUpdateTask => "drawing its marks after each frame";

		internal static ManualLogSource Log => current.Host.Log;

		internal static bool IsOn
		{
			get
			{
				if (current != null && current.Host != null)
				{
					return current.Host.IsOn;
				}
				return false;
			}
		}

		internal override IEnumerable<Action> UndoSteps
		{
			get
			{
				List<Action> list = new List<Action>();
				list.Add(LoadoutWindow.Close);
				list.Add(Popup.Close);
				list.Add(Drawer.Forget);
				list.Add(InventoryPanel.Forget);
				list.Add(Tips.Forget);
				list.Add(FoodPanel.Forget);
				list.Add(StandPanel.Forget);
				list.Add(Drag.Cancel);
				list.Add(StandMenu.Close);
				list.Add(Picks.HideFrames);
				list.Add(Outfit.Abandon);
				list.Add(ChestClaims.ReleaseHolds);
				list.AddRange(Outfitter.Stands.Stands.UndoSteps);
				return list;
			}
		}

		internal Module()
		{
			current = this;
		}

		internal static void Warn(string text)
		{
			Module module = current;
			if (module == null)
			{
				return;
			}
			ModuleHost host = module.Host;
			if (host != null)
			{
				ManualLogSource log = host.Log;
				if (log != null)
				{
					log.LogWarning((object)text);
				}
			}
		}

		internal static void Guard(string task, Action work)
		{
			current.Host.Guard(task, work);
		}

		internal override void BindSettings(ModuleSettings settings)
		{
			Settings.Bind(settings);
		}

		internal override string DescribeMissing(IList<string> missing)
		{
			List<string> list = new List<string>();
			List<string> list2 = new List<string>();
			foreach (string item in missing)
			{
				if (item.StartsWith("rival:", StringComparison.Ordinal))
				{
					list.Add(item.Substring("rival:".Length));
				}
				else
				{
					list2.Add(item);
				}
			}
			if (list.Count == 0)
			{
				return base.DescribeMissing(missing);
			}
			string text2 = string.Join(" and ", list);
			bool flag = list.Count == 1;
			string text3 = text2 + " give" + (flag ? "s" : "") + " your inventory rows or slots of " + (flag ? "its" : "their") + " own, which Outfitter doesn't know: it would take armour off those slots and put it away at every equip, so it stays off while " + text2 + " " + (flag ? "is" : "are") + " installed.";
			if (list2.Count > 0)
			{
				text3 = text3 + " The game has also changed, and these parts were not found: " + string.Join(", ", list2) + ".";
			}
			return text3 + " " + SwitchedOffNote;
		}

		internal override void Resolve(List<string> missing, List<string> missingOptional)
		{
			(string, string)[] rivals = Rivals;
			for (int i = 0; i < rivals.Length; i++)
			{
				var (key, text) = rivals[i];
				if (Chainloader.PluginInfos.TryGetValue(key, out var value) && (Object)(object)((value != null) ? value.Instance : null) != (Object)null)
				{
					missing.Add("rival:" + text);
				}
			}
			ChestHooks.Resolve(missing, Chests);
			ItemMarks.Resolve(missingOptional);
			GameHooks.Resolve(missing, missingOptional);
			Eaqs.Find(Log);
			Folds.RebuildList = ManagerLink.Rebuild();
			Outfit.Ask = Popup.Ask;
			Outfit.AskList = Popup.AskList;
			Outfit.Dismiss = Popup.CloseIf;
			Outfitter.Stands.Stands.Resolve(missing, missingOptional);
		}

		internal override void Update()
		{
			ChestClaims.Tick();
			Folds.Tick();
			Store.Tick();
			LoadoutWindow.Update();
			Outfit.Tick();
			Outfitter.Stands.Stands.Update();
		}
	}
	internal enum EquipMode
	{
		FullyReplace,
		SwapGearOnly,
		SwapGearAndAddTheRest
	}
	internal enum MissingItems
	{
		Ask,
		EquipWhatsHere,
		Cancel
	}
	internal enum MissingListLook
	{
		IconNameOnHover,
		IconAndName
	}
	internal enum WornNotInLoadout
	{
		ComesOff,
		ComesOffOnlyIntoAChest
	}
	internal enum WornUtilityNotInLoadout
	{
		KeepWearing,
		ComesOff
	}
	internal enum EquipTime
	{
		Instant,
		TheGamesOwn
	}
	internal enum ResultMessage
	{
		OneLine,
		Detailed
	}
	internal enum WhichChests
	{
		AnyChestICanOpen,
		OnlyChestsIBuilt
	}
	internal enum LeaveOne
	{
		FollowAzuCraftyBoxes,
		Always,
		Never
	}
	internal enum FetchFrom
	{
		SetUpChestsFirst,
		SetUpChestsOnly,
		AnyChest
	}
	internal enum GearQuality
	{
		SavedOrBetter,
		Exact,
		Any
	}
	internal enum PreferCopy
	{
		LeastWorn,
		MostWorn
	}
	internal enum TopUp
	{
		PerItem,
		PerSavedStack
	}
	internal enum MoreThanCount
	{
		PutAwayInFullyReplace,
		Keep,
		PutAway
	}
	internal enum PlacesKept
	{
		AsSaved,
		Anywhere
	}
	internal enum CellTaken
	{
		MoveTheOtherItem,
		UseTheNextFreeCell
	}
	internal enum QuickSlotItemsWithout
	{
		FirstFreeMainCell,
		HotbarIfFree
	}
	internal enum PickingCells
	{
		Both,
		HeldKeyAndClicks,
		ChooseCellsInTheWindow
	}
	internal enum KeptWhere
	{
		WithTheCharacter,
		OnThisPC
	}
	internal enum WindowSize
	{
		Small,
		Medium,
		Large
	}
	internal enum DrawerOpens
	{
		AsILeftIt,
		Always,
		Never,
		AlwaysMyInventory
	}
	internal enum FavouriteGear
	{
		Swaps,
		StaysWithMe
	}
	internal enum DraggedStack
	{
		OneFullStack,
		One,
		WhatTheChestsHold
	}
	internal enum DraggedGear
	{
		WhenNothingElseIsWornThere,
		Never
	}
	internal enum DrawerClick
	{
		FirstFreeCell,
		Nothing
	}
	internal static class Settings
	{
		internal const string WindowPart = "Window and keys";

		internal const string EquipPart = "Equipping";

		internal const string ChestsPart = "Chests";

		internal const string CopyPart = "Which copy";

		internal const string PlacesPart = "Places";

		internal const string SavingPart = "Saving and codes";

		internal const int OwnTop = 990;

		internal const int OwnBottom = 300;

		internal const int StandsTop = 299;

		internal const int StandsBottom = 100;

		private const string AzuCraftyBoxes = "Azumatt.AzuCraftyBoxes";

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

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

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

		internal static ConfigEntry<PickingCells> Picking { get; private set; }

		internal static ConfigEntry<WindowSize> Size { get; private set; }

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

		internal static ConfigEntry<DrawerOpens> DrawerOpening { get; private set; }

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

		internal static ConfigEntry<DraggedStack> StackDragged { get; private set; }

		internal static ConfigEntry<DraggedGear> GearDragged { get; private set; }

		internal static ConfigEntry<DrawerClick> DrawerClicks { get; private set; }

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

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

		internal static ConfigEntry<EquipMode> Mode { get; private set; }

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

		internal static ConfigEntry<MissingItems> Missing { get; private set; }

		internal static ConfigEntry<MissingListLook> MissingList { get; private set; }

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

		internal static ConfigEntry<WornNotInLoadout> NotWorn { get; private set; }

		internal static ConfigEntry<WornUtilityNotInLoadout> UtilityNotWorn { get; private set; }

		internal static ConfigEntry<FavouriteGear> GearFavourites { get; private set; }

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

		internal static ConfigEntry<int> FoodStatAtLeast { get; private set; }

		internal static ConfigEntry<EquipTime> Timing { get; private set; }

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

		internal static ConfigEntry<int> WaitSeconds { get; private set; }

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

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

		internal static ConfigEntry<ResultMessage> Result { get; private set; }

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

		internal static ConfigEntry<WhichChests> Chests { get; private set; }

		internal static ConfigEntry<LeaveOne> LeaveOneInChests { get; private set; }

		internal static ConfigEntry<FetchFrom> Fetch { get; private set; }

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

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

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

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

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

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

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

		internal static ConfigEntry<GearQuality> Quality { get; private set; }

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

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

		internal static ConfigEntry<PreferCopy> Prefer { get; private set; }

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

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

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

		internal static ConfigEntry<TopUp> TopUps { get; private set; }

		internal static ConfigEntry<MoreThanCount> Extra { get; private set; }

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

		internal static ConfigEntry<PlacesKept> Places { get; private set; }

		internal static ConfigEntry<CellTaken> Taken { get; private set; }

		internal static ConfigEntry<QuickSlotItemsWithout> QuickSlotsWithout { get; private set; }

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

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

		internal static ConfigEntry<KeptWhere> Kept { get; private set; }

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

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

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

		internal static ConfigEntry<int> FoodSlotCount { get; private set; }

		internal static int Version { get; private set; }

		internal static void Changed()
		{
			Version++;
		}

		internal static void Bind(ModuleSettings settings)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			Enabled = settings.Enabled;
			Enabled.SettingChanged += delegate
			{
				Changed();
			};
			ChestSettings.Bind(settings);
			SettingsBinder settingsBinder = new SettingsBinder(settings, 990, 300);
			settingsBinder.BeginFold("Window and keys");
			WindowKey = settingsBinder.Add<KeyboardShortcut>("Window and keys", "WindowKey", new KeyboardShortcut((KeyCode)285, Array.Empty<KeyCode>()), "Window key", "Opens and closes Outfitter's window: your loadouts, the one you pick in its places, and Equip. Escape closes it too. Only the configured modifier keys may be held.");
			PickKey = settingsBinder.Add<KeyboardShortcut>("Window and keys", "PickKey", new KeyboardShortcut((KeyCode)307, Array.Empty<KeyCode>()), "Pick cells: hold this and click", "With your inventory open, hold this key and left-click a cell to pick it for saving (again to unpick it). Right Alt is free: Shift, Ctrl and Left Alt clicks are the game's, MyLittleUI's and StoreStash's. None: no key; pick in the window instead.");
			Picking = settingsBinder.Add("Window and keys", "Picking", PickingCells.Both, "Picking the cells to save", "Both: the key above, and the window's \"Highlight cells\" in its My inventory panel (while it's on, a left click on a cell of your inventory there highlights it). HeldKeyAndClicks: only the key. ChooseCellsInTheWindow: only the window. Highlighting a loadout's own cells (to copy them) works either way.");
			Size = settingsBinder.Add("Window and keys", "WindowSize", WindowSize.Medium, "Window size", "How big the window is drawn, over the game's own GUI scale, as Add to Cart's sizes. Small: as 0.2.0 drew it. Medium (the default): a quarter bigger. Large: half as big again. Medium and Large are kept to what fits your screen (with the drawer below open, both together). The text stays sharp at every size. Changes at once.");
			Drawer = settingsBinder.Add("Window and keys", "Drawer", value: true, "Nearby items drawer", "On: \"Show nearby items\" on the window opens a panel beside it, like Add to Cart's Take tab: every item in the chests nearby (and what you carry, below), to drag into a loadout's cells and build it from what your base holds. Off: no button, no panel.");
			DrawerOpening = settingsBinder.Add("Window and keys", "DrawerOpens", DrawerOpens.AsILeftIt, "The panel beside the window opens with", "Which panel shows beside the window when it opens. AsILeftIt: the one that showed when you last closed it (or none). Always: the nearby items. AlwaysMyInventory: your inventory. Never: none.");
			DrawerCarried = settingsBinder.Add("Window and keys", "DrawerCarried", value: true, "The drawer lists what I carry", "On: what you carry shows in the drawer too, under a heading of its own, beside what the chests nearby hold.");
			StackDragged = settingsBinder.Add("Window and keys", "StackDragged", DraggedStack.OneFullStack, "A stackable dragged in comes as", "OneFullStack: as many as one stack of it holds (50 wood, 10 soups). One: one, for you to set (the scroll wheel over its cell, or the box beside the grid). WhatTheChestsHold: what the chests nearby and you hold of it, up to one stack.");
			GearDragged = settingsBinder.Add("Window and keys", "GearDragged", DraggedGear.WhenNothingElseIsWornThere, "Gear dragged in goes on", "WhenNothingElseIsWornThere: armour, a cape, a belt or a weapon dragged into a loadout is worn, unless the loadout already wears something there (the game's own rules for hands). Never: it's carried; mark it worn beside the grid. Into one of EquipmentAndQuickSlots' gear slots it's always worn.");
			DrawerClicks = settingsBinder.Add("Window and keys", "DrawerClick", DrawerClick.FirstFreeCell, "Left click on a drawer item", "FirstFreeCell: puts it in the loadout's first free cell (worn by the setting above). Nothing: only dragging puts it in.");
			InventoryPanel = settingsBinder.Add("Window and keys", "InventoryPanel", value: true, "My inventory panel", "On: \"Show my inventory\" on the window shows your own inventory beside it, as the game has it (the hotbar, your rows, EquipmentAndQuickSlots' slots): drag a cell into the loadout (that very item goes in), or highlight cells to copy them into a loadout or save them as a new one. Off: no button, no panel.");
			HoverHelp = settingsBinder.Add("Window and keys", "HoverHelp", value: true, "Hover help", "On: pointing at one of the window's buttons for a moment shows a few words on what it does. Off: none.");
			settingsBinder.EndFold();
			settingsBinder.BeginFold("Equipping");
			Mode = settingsBinder.Add("Equipping", "Mode", EquipMode.FullyReplace, "Equip mode", "FullyReplace: everything you carry that the loadout doesn't hold goes into the chests nearby, and the loadout comes in its places. SwapGearOnly: only gear changes (what you wore goes away, the loadout's gear comes); the rest of your inventory and the loadout's other items are left as they are. SwapGearAndAddTheRest: the gear changes, and the loadout's other items come too (topped up to its counts), while your own food and materials stay. With \"Ask the mode\" on, the window starts at this one.");
			AskMode = settingsBinder.Add("Equipping", "AskMode", value: true, "Ask the mode at every equip", "On: the window shows the three modes beside Equip, starting at the one above. Off: Equip uses the one above without asking.");
			Missing = settingsBinder.Add("Equipping", "Missing", MissingItems.Cancel, "Missing items", "When some of a loadout isn't in the chests nearby. Ask: a pop-up lists what's missing and offers \"Equip what's here\". EquipWhatsHere: without asking, and says what was missing. Cancel: nothing changes, and it says what's missing.");
			MissingList = settingsBinder.Add("Equipping", "MissingList", MissingListLook.IconNameOnHover, "Missing items in the pop-up", "How the pop-up lists what's missing. IconNameOnHover: each item's icon with how many and why; point at the icon for its name. IconAndName: the icon, the name, how many and why. An item with no icon shows its name.");
			KeepWornWhenMissing = settingsBinder.Add("Equipping", "KeepWornWhenMissing", value: true, "Keep wearing mine when a piece is missing", "On: when the loadout's helmet (or any piece of gear) can't be had, you keep wearing the one you have in that place, rather than being left without. Off: what you wore there goes away all the same.");
			NotWorn = settingsBinder.Add("Equipping", "WornNotInLoadout", WornNotInLoadout.ComesOff, "What I wear that the loadout doesn't", "ComesOff: when you put a loadout on, whatever you wear that it doesn't wear comes off, arrows and bolts too (the game keeps them equipped with no bow in hand), so only the loadout's gear is on; what no chest takes stays in your inventory. ComesOffOnlyIntoAChest: it comes off only when a chest takes it or the loadout puts something in its place, so away from chests you keep wearing it. Belts and trinkets follow the setting below. Either way \"Keep wearing mine when a piece is missing\" keeps yours on where the loadout's own piece can't be had, and what never goes away stays as it is (favourites while they're left alone, and in the swap modes what isn't gear by the switches in Which copy).");
			UtilityNotWorn = settingsBinder.Add("Equipping", "WornUtilityNotInLoadout", WornUtilityNotInLoadout.ComesOff, "A belt or trinket the loadout doesn't name", "KeepWearing: a belt or trinket you wear that the loadout doesn't name comes off only when a chest takes it or the loadout puts one in its place, so away from chests you keep its bonus (a Megingjord's carry weight). ComesOff: it comes off like the rest, whether or not a chest takes it (the window's weight line counts the carry weight you'd lose).");
			GearFavourites = settingsBinder.Add("Equipping", "FavouriteGear", FavouriteGear.Swaps, "My favourite gear in an equip", "Swaps: gear you marked as a favourite (StoreStash: Left Shift + right-click) comes off and goes away like any other gear when a loadout replaces it (armour, weapons, and by their switches in Which copy arrows, tools and torches), at the window and at a stand. StaysWithMe: favourite gear is one of your favourites like any other: with \"Leave my favourites alone\" (Which copy) on, it never goes away (0.3.0's way), so a loadout's own piece can go on only beside it. The rest of your favourites (food, materials) always follow that setting. Only for a loadout whose \"Favourites go too\" (beside the modes in the window) is off.");
			FavouritesGo = settingsBinder.Add("Equipping", "FavouritesGo", value: true, "Equip modes put away my favourites", "On: putting a loadout on puts your favourites (StoreStash: Left Shift + right-click) away like any other item, in all three modes: Fully replace stores every favourite the loadout doesn't hold, the swap modes your favourite gear. This is where each loadout's own \"Favourites go too\" switch (beside the modes in the window) starts; a loadout you've switched keeps its own. Off: favourites follow \"Leave my favourites alone\" (Which copy) and \"My favourite gear in an equip\" above, as in 0.4.");
			FoodStatAtLeast = settingsBinder.Add("Equipping", "FoodStatAtLeast", 3, "Food slots by stat: at least", "A food slot set to \"Its stat\" first (its rule, beside the window) takes the food it prefers as long as at least this many are nearby (or its whole count, if that's fewer), even when another food would fill its count: 3 Honey glazed chickens before 10 Cooked deer meats for a slot of 10 wanting the most Health. With fewer than this, a food that fills the count comes first. A slot set to \"Amount\" first always fills its count first.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100));
			Timing = settingsBinder.Add("Equipping", "EquipTime", EquipTime.TheGamesOwn, "Equip time", "Instant: every piece is on at once (the game's own way takes about 12.5 s for a full set of armour). TheGamesOwn: each piece goes on through the game's own queue, with its animation, one after another (a jump, a dodge or a run clears the queue, as it does in the game); taking off stays instant.");
			Effects = settingsBinder.Add("Equipping", "Effects", value: true, "Equip sound and effect", "The game's sound and flash for putting gear on. Off quietens them, though some items still play their own sound, as they do in the game.");
			WaitSeconds = settingsBinder.Add("Equipping", "WaitSeconds", 10, "Wait while I fight, up to (seconds)", "The game won't put gear on while you attack, dodge, swim, eat, or it's still changing your gear. Equip waits until you can, up to this long, then gives up and says so.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 30));
			Confirm = settingsBinder.Add("Equipping", "Confirm", value: false, "Confirm before equipping", "On: Equip asks once more, saying what will go away and what will come, before anything moves.");
			WeightWarning = settingsBinder.Add("Equipping", "WeightWarning", value: true, "Weight warning", "The window shows what you'll carry after the equip, in red when it's over your carry weight.");
			Result = settingsBinder.Add("Equipping", "Result", ResultMessage.OneLine, "Result message", "OneLine: one line at the top left (what came, what went away, what's missing). Detailed: a line for each part, and the same in the log.");
			settingsBinder.EndFold();
			settingsBinder.BeginFold("Chests");
			Range = settingsBinder.Add("Chests", "Range", 0f, "Chest range (metres)", "How far from you a chest may be for Outfitter to take from it and put into it. 0 (out of the box): the range in \"Chests (every mod)\". Another number: this mod's own range, in metres (at least 5), unless \"Use this range in every mod\" is on there (card B13).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 250f));
			settings.MovedDefault(Range, 150f, 1);
			ChestSettings.Reaches("Outfitter, Chests", "Chest range (metres)", Range);
			Chests = settingsBinder.Add("Chests", "Chests", WhichChests.AnyChestICanOpen, "Which chests", "AnyChestICanOpen: every chest you could open by hand (a friend's public chest too, never a private one or one behind a ward that isn't yours). OnlyChestsIBuilt: only chests you built. Chests the world made, gravestones and Reserve Stock's reserved chests are never used.");
			LeaveOneInChests = settingsBinder.Add("Chests", "LeaveOneInChests", LeaveOne.FollowAzuCraftyBoxes, "Leave one of each item in chests", "When taking a stackable item, leave one in each chest, so quick stack still knows where it belongs (never a lone piece of gear). FollowAzuCraftyBoxes: as AzuCraftyBoxes' own \"Leave One Item\" setting says when that mod is installed, and leave one when it isn't (as Add to Cart). Always. Never.");
			Fetch = settingsBinder.Add("Chests", "FetchFrom", FetchFrom.SetUpChestsFirst, "Take the loadout's items from", "SetUpChestsFirst: chests set up for an item (StoreStash's chest setups) before any other. SetUpChestsOnly: only those. AnyChest: every chest alike, nearest first.");
			PutSetUpFirst = settingsBinder.Add("Chests", "PutSetUpFirst", value: true, "What goes away goes to its set-up chest first", "What you take off and put away goes first to the chests set up for it (an armour chest, a weapons chest…), as StoreStash's quick stack sends it. Off: chest setups are ignored when putting away.");
			PutOverflow = settingsBinder.Add("Chests", "PutOverflow", value: true, "… what a set-up chest can't fit goes on to other chests", "On: when the chests set up for an item are full (or someone has them open), it goes to other chests. Off: it stays with you.");
			PutOthers = settingsBinder.Add("Chests", "PutOthers", value: true, "What no set-up chest takes goes to chests without a setup", "On: an item no chest is set up for goes to chests without a setup. Off: only set-up chests are used.");
			PutAnyChest = settingsBinder.Add("Chests", "PutAnyChest", value: true, "Put away into any chest with room", "On: when no chest is set up for an item and none already holds it, it goes into the nearest chest with room. Off: only into chests set up for it or already holding it; the rest stays with you. Never on the ground.");
			KeepHeld = settingsBinder.Add("Chests", "KeepHeld", value: false, "A set-up chest also takes what it already holds", "On: a set-up chest also takes items its setup doesn't name, if it already holds some. Off: a set-up chest takes only what its setup names (as StoreStash's quick stack does out of the box).");
			LeaveOthersMarked = settingsBinder.Add("Chests", "LeaveOthersMarked", value: false, "Leave chests others marked alone", "On: nothing is put into a chest another player marked as theirs with StoreStash (Left Alt + H). Taking from it isn't affected.");
			CartsAndShips = settingsBinder.Add("Chests", "CartsAndShips", value: false, "Use the chests on carts and ships", "On: a cart's or ship's chest counts like any other (claiming it takes the cart or ship over for a moment). Off: they're left alone. A ship someone else is aboard is always left alone.");
			settingsBinder.EndFold();
			settingsBinder.BeginFold("Which copy");
			Quality = settingsBinder.Add("Which copy", "GearQuality", GearQuality.Exact, "Gear quality", "SavedOrBetter: a piece of gear of the saved quality or better counts, the best one coming first. Exact: only the saved quality. Any: any quality, the best first.");
			MatchStyle = settingsBinder.Add("Which copy", "MatchStyle", value: true, "Match the style", "On: shields and capes count only in the style that was saved.");
			ExactItem = settingsBinder.Add("Which copy", "ExactItem", value: true, "This exact item", "On: gear counts only when it's the one you saved: the same maker, quality and style, and other mods' data on it (a magic item's enchantments, a gem's sockets). A friend's code knows no maker or data, so those count only for your own loadouts. Off: any copy.");
			Prefer = settingsBinder.Add("Which copy", "PreferCopy", PreferCopy.LeastWorn, "Prefer the copy that's", "Among copies of the same quality: LeastWorn (the most durable) or MostWorn (use the worn ones up first).");
			AmmoIsGear = settingsBinder.Add("Which copy", "AmmoIsGear", value: true, "Arrows and bolts count as gear", "In the swap-gear modes, gear is armour and weapons, and these when on.");
			ToolsAreGear = settingsBinder.Add("Which copy", "ToolsAreGear", value: true, "Tools count as gear", "The hammer, hoe, cultivator and pickaxes, in the swap-gear modes.");
			TorchesAreGear = settingsBinder.Add("Which copy", "TorchesAreGear", value: true, "Torches count as gear", "Torches and lanterns held in a hand, in the swap-gear modes.");
			TopUps = settingsBinder.Add("Which copy", "TopUp", TopUp.PerItem, "Topping up counts", "PerItem: a loadout with 10 carrot soups tops up to 10 in all, wherever they are. PerSavedStack: each saved stack is filled in its own cell.");
			Extra = settingsBinder.Add("Which copy", "MoreThanCount", MoreThanCount.PutAwayInFullyReplace, "More than the loadout's count", "When you carry more of an item than the loadout holds. PutAwayInFullyReplace: the extra goes away in Fully replace and stays in the other modes. Keep. PutAway.");
			LeaveFavourites = settingsBinder.Add("Which copy", "LeaveFavourites", value: true, "Leave my favourites alone", "On: items you marked as favourites (StoreStash: Left Shift + right-click) never go away, in any mode; your favourite gear follows \"My favourite gear in an equip\" (Equipping), which swaps it out of the box. Off: every favourite goes away like any other item. Only for a loadout whose \"Favourites go too\" (beside the modes in the window; out of the box by \"Equip modes put away my favourites\", Equipping) is off.");
			settingsBinder.EndFold();
			settingsBinder.BeginFold("Places");
			Places = settingsBinder.Add("Places", "PlacesKept", PlacesKept.AsSaved, "Places kept", "AsSaved: each item goes back to the cell it was saved in (rows counted from the bottom, so a bigger inventory keeps them in place; the hotbar stays the hotbar). Anywhere: items stay wherever they land.");
			Taken = settingsBinder.Add("Places", "CellTaken", CellTaken.MoveTheOtherItem, "A saved cell is taken", "MoveTheOtherItem: whatever is in an item's saved cell moves to a free cell. UseTheNextFreeCell: the item goes to the next free cell instead.");
			QuickSlotsWithout = settingsBinder.Add("Places", "QuickSlotsWithout", QuickSlotItemsWithout.FirstFreeMainCell, "Quick-slot items without EquipmentAndQuickSlots", "Where an item saved in one of EquipmentAndQuickSlots' quick slots goes while that mod isn't running. FirstFreeMainCell. HotbarIfFree: a free hotbar cell first.");
			QuickSlotsInFullyReplace = settingsBinder.Add("Places", "QuickSlotsInFullyReplace", value: false, "Fully replace puts away quick-slot items", "On: Fully replace also puts away what sits in EquipmentAndQuickSlots' quick slots when the loadout doesn't hold it. Off: what's in them stays (a loadout's own quick-slot item still takes its slot).");
			settingsBinder.EndFold();
			settingsBinder.BeginFold("Saving and codes");
			SaveOnlyPicked = settingsBinder.Add("Saving and codes", "SaveOnlyPicked", value: true, "Save only the picked cells", "On: a loadout holds the cells you picked. Off: Save takes everything you carry and wear.");
			Kept = settingsBinder.Add("Saving and codes", "KeptWhere", KeptWhere.WithTheCharacter, "Where loadouts are kept", "WithTheCharacter: in the character's own file, so they go with it to every world and server. OnThisPC: in a file on this PC (BepInEx\\config\\modprojects.outfitter.loadouts.txt), the same for all your characters.");
			HiddenAsWorn = settingsBinder.Add("Saving and codes", "HiddenAsWorn", value: true, "Weapons put away count as worn", "On: weapons you had put away (R) when saving are saved as held, so the loadout puts them in your hands.");
			ShareCodes = settingsBinder.Add("Saving and codes", "ShareCodes", value: true, "Share codes", "Copy a loadout as a code to paste to a friend (it goes to the clipboard), and paste a friend's code as a new loadout. A code is only a list: it never makes an item.");
			CodesCarryPlaces = settingsBinder.Add("Saving and codes", "CodesCarryPlaces", value: true, "Codes carry each item's place", "On: a code says where each item sits. Off: only what and how many.");
			FoodSlotCount = settingsBinder.Add("Saving and codes", "FoodSlotCount", 10, "Food slots: count at first", "How many of its food a new food slot brings (the window's \"Make a food slot\" on an empty cell; a food made into a slot keeps its own count). Change a slot's count beside the grid. At most one stack of the food comes, whatever the count.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100));
			settingsBinder.EndFold();
			Outfitter.Stands.Stands.Bind(new SettingsBinder(settings, 299, 100));
		}

		internal static ChestRules ChestRules()
		{
			return new ChestRules
			{
				Range = ChestSettings.RangeOf(Range),
				OnlyBuiltByMe = (Chests.Value == WhichChests.OnlyChestsIBuilt),
				LeaveOne = LeavesOne(),
				Skip = (CartsAndShips.Value ? null : new Func<Container, bool>(OnVehicle))
			};
		}

		internal static bool OnVehicle(Container chest)
		{
			if ((Object)(object)chest != (Object)null)
			{
				if (!((Object)(object)((Component)chest).GetComponentInParent<Vagon>() != (Object)null))
				{
					return (Object)(object)((Component)chest).GetComponentInParent<Ship>() != (Object)null;
				}
				return true;
			}
			return false;
		}

		private static bool LeavesOne()
		{
			switch (LeaveOneInChests.Value)
			{
			case LeaveOne.Always:
				return true;
			case LeaveOne.Never:
				return false;
			default:
			{
				if (!Chainloader.PluginInfos.TryGetValue("Azumatt.AzuCraftyBoxes", out var azu) || (Object)(object)azu.Instance == (Object)null)
				{
					return true;
				}
				ConfigEntryBase val = (from key in azu.Instance.Config.Keys
					where key.Key == "Leave One Item"
					select azu.Instance.Config[key]).FirstOrDefault();
				if (val != null)
				{
					return val.BoxedValue?.ToString() != "Off";
				}
				return true;
			}
			}
		}
	}
	internal sealed class SettingsBinder
	{
		private readonly ModuleSettings bound;

		private readonly int bottom;

		private int order;

		private ConfigEntry<bool> foldUnfolded;

		private List<ConfigEntryBase> foldSettings;

		internal SettingsBinder(ModuleSettings settings, int top, int bottom)
		{
			bound = settings;
			order = top;
			this.bottom = bottom;
		}

		internal void BeginFold(string part)
		{
			if (foldSettings != null)
			{
				throw new InvalidOperationException("The section \"" + part + "\" was opened before the one before it was closed.");
			}
			List<ConfigEntryBase> settings = new List<ConfigEntryBase>();
			foldUnfolded = bound.Bind(part, "Unfolded", defaultValue: false, part, NextOrder(), "Opens and closes this part of the settings in the window. It changes nothing else.", null, FoldDrawer.For(part, settings));
			foldSettings = settings;
		}

		internal void EndFold()
		{
			if (foldSettings == null)
			{
				throw new InvalidOperationException("A section was closed that was never opened.");
			}
			Folds.Add(foldUnfolded, foldSettings, bound.SectionOf("General"));
			foldUnfolded = null;
			foldSettings = null;
		}

		internal ConfigEntry<T> Add<T>(string part, string key, T value, string name, string description, AcceptableValueBase range = null, Action<ConfigEntryBase> drawer = null)
		{
			ConfigEntry<T> val = bound.Bind(part, key, value, name, NextOrder(), description, range, drawer);
			val.SettingChanged += delegate
			{
				Settings.Changed();
			};
			foldSettings?.Add((ConfigEntryBase)(object)val);
			return val;
		}

		private int NextOrder()
		{
			if (order < bottom)
			{
				throw new InvalidOperationException($"Out of setting orders: this range ends at {bottom}.");
			}
			return order--;
		}
	}
	internal static class Text
	{
		private const string Marks = "-_.,'!?()&+#";

		internal static string Plain(string text, int max)
		{
			if (string.IsNullOrEmpty(text) || max <= 0)
			{
				return string.Empty;
			}
			StringBuilder stringBuilder = new StringBuilder(Math.Min(text.Length, max));
			bool flag = false;
			foreach (char c in text)
			{
				if (char.IsLetterOrDigit(c) || "-_.,'!?()&+#".IndexOf(c) >= 0)
				{
					bool flag2 = flag && stringBuilder.Length > 0;
					if (stringBuilder.Length + ((!flag2) ? 1 : 2) > max)
					{
						break;
					}
					if (flag2)
					{
						stringBuilder.Append(' ');
					}
					flag = false;
					stringBuilder.Append(c);
				}
				else if (char.IsWhiteSpace(c))
				{
					flag = true;
				}
			}
			return stringBuilder.ToString();
		}

		internal static string PrefabName(string text)
		{
			if (string.IsNullOrEmpty(text) || text.Length > 64 || text[0] == ' ' || text[text.Length - 1] == ' ')
			{
				return null;
			}
			foreach (char c in text)
			{
				if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && (c < '0' || c > '9') && c != '_' && c != '-' && c != '.' && c != '(' && c != ')' && c != ' ')
				{
					return null;
				}
			}
			return text;
		}
	}
	[BepInPlugin("tenemo.outfitter", "Outfitter", "0.7.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInIncompatibility("modprojects.outfitter")]
	[BepInIncompatibility("modprojects.qolmods")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		private ModuleHost host;

		private void Awake()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Invalid comparison between Unknown and I4
			StandStorageLifecycle.Initialize(((BaseUnityPlugin)this).Logger);
			if ((int)SystemInfo.graphicsDeviceType != 4)
			{
				host = ModuleHost.RunAlone((BaseUnityPlugin)(object)this, new Module(), ((BaseUnityPlugin)this).Logger);
			}
		}

		private void Update()
		{
			host?.Update();
		}

		private void LateUpdate()
		{
			host?.LateUpdate();
		}
	}
}
namespace Outfitter.Window
{
	internal sealed class DragItem
	{
		internal string Prefab;

		internal int Quality = 1;

		internal int Variant;

		internal int Count = 1;

		internal ItemData Sample;

		internal Vector2i? FromCell;

		internal LoadoutItem Exact;

		internal Sprite Icon;
	}
	internal static class Drag
	{
		private static GameObject ghost;

		private static Image ghostImage;

		private static bool dropped;

		internal static Action<DragItem, Vector2i> DroppedOnCell;

		internal static Action<DragItem> DroppedElsewhere;

		internal static Action<DragItem, bool> Clicked;

		internal static DragItem Current { get; private set; }

		internal static void Begin(DragItem item, PointerEventData data)
		{
			Cancel();
			if (item != null)
			{
				Current = item;
				dropped = false;
				if ((Object)(object)ghost == (Object)null)
				{
					ghost = Ui.Box("Outfitter_Drag", Ui.CanvasRoot(), 0f, 0f, 48f, 48f);
					ghostImage = ghost.AddComponent<Image>();
					ghostImage.preserveAspect = true;
					((Graphic)ghostImage).raycastTarget = false;
					CanvasGroup obj = ghost.AddComponent<CanvasGroup>();
					obj.blocksRaycasts = false;
					obj.interactable = false;
				}
				ghostImage.sprite = item.Icon;
				((Behaviour)ghostImage).enabled = (Object)(object)item.Icon != (Object)null;
				ghost.SetActive(true);
				ghost.transform.SetAsLastSibling();
				Move(data);
			}
		}

		internal static void Move(PointerEventData data)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			Vector2 anchoredPosition = default(Vector2);
			if (!((Object)(object)ghost == (Object)null) && Current != null && data != null && RectTransformUtility.ScreenPointToLocalPointInRectangle((RectTransform)Ui.CanvasRoot(), data.position, (Camera)null, ref anchoredPosition))
			{
				RectTransform val = (RectTransform)ghost.transform;
				Vector2 val2 = default(Vector2);
				((Vector2)(ref val2))..ctor(0.5f, 0.5f);
				val.anchorMax = val2;
				val.anchorMin = val2;
				val.pivot = new Vector2(0.5f, 0.5f);
				val.anchoredPosition = anchoredPosition;
			}
		}

		internal static void DropOn(Vector2i cell)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			DragItem item = Current;
			if (item != null)
			{
				dropped = true;
				Module.Guard("dropping an item on a loadout's cell", delegate
				{
					//IL_0011: Unknown result type (might be due to invalid IL or missing references)
					DroppedOnCell?.Invoke(item, cell);
				});
			}
		}

		internal static void End()
		{
			DragItem item = Current;
			bool flag = dropped;
			Cancel();
			if (item != null && !flag)
			{
				Module.Guard("dropping an item outside the loadout", delegate
				{
					DroppedElsewhere?.Invoke(item);
				});
			}
		}

		internal static void Cancel()
		{
			Current = null;
			dropped = false;
			if ((Object)(object)ghost != (Object)null)
			{
				ghost.SetActive(false);
			}
		}
	}
	internal sealed class DragSource : MonoBehaviour, IBeginDragHandler, IEventSystemHandler, IDragHandler, IEndDragHandler
	{
		internal Func<DragItem> Make;

		public void OnBeginDrag(PointerEventData data)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if ((int)data.button != 0 || Make == null)
			{
				return;
			}
			Module.Guard("starting a drag", delegate
			{
				DragItem dragItem = Make();
				if (dragItem != null)
				{
					Drag.Begin(dragItem, data);
				}
			});
		}

		public void OnDrag(PointerEventData data)
		{
			if (Drag.Current != null)
			{
				Module.Guard("dragging", delegate
				{
					Drag.Move(data);
				});
			}
		}

		public void OnEndDrag(PointerEventData data)
		{
			if (Drag.Current != null)
			{
				Module.Guard("ending a drag", Drag.End);
			}
		}

		private void OnDisable()
		{
			if (Drag.Current != null)
			{
				Module.Guard("ending a drag", Drag.Cancel);
			}
		}
	}
	internal sealed class DropTarget : MonoBehaviour, IDropHandler, IEventSystemHandler
	{
		internal Vector2i Cell;

		public void OnDrop(PointerEventData data)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			if (Drag.Current != null)
			{
				Drag.DropOn(Cell);
			}
		}
	}
	internal sealed class WheelCatcher : MonoBehaviour, IScrollHandler, IEventSystemHandler
	{
		internal Action<int> Turned;

		public void OnScroll(PointerEventData data)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			int notches = ((data.scrollDelta.y > 0f) ? 1 : ((data.scrollDelta.y < 0f) ? (-1) : 0));
			if (notches != 0 && Turned != null)
			{
				Module.Guard("turning the wheel over a loadout's cell", delegate
				{
					Turned(notches);
				});
			}
		}
	}
	internal static class Drawer
	{
		private sealed class Thumb
		{
			internal string Key;

			internal Text Count;

			internal GameObject Star;

			internal int CountShown = -1;

			internal Image Icon;

			internal bool Grey;
		}

		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UnityAction<string> <>9__57_0;

			public static UnityAction <>9__57_1;

			public static UnityAction <>9__57_2;

			public static UnityAction<int> <>9__57_3;

			public static UnityAction<int> <>9__57_4;

			public static UnityAction<bool> <>9__57_5;

			public static Action <>9__57_6;

			public static Action<string> <>9__62_0;

			public static Func<ItemData, bool> <>9__63_0;

			public static Func<GroupOption, string> <>9__81_0;

			public static Func<SortOption, string> <>9__81_1;

			internal void <Build>b__57_0(string text)
			{
				Module.Guard("filtering the nearby items", new <>c__DisplayClass57_0
				{
					text = text
				}.<Build>b__7);
			}

			internal void <Build>b__57_1()
			{
				Module.Guard("clearing the drawer's filter", ClearQuery);
			}

			internal void <Build>b__57_2()
			{
				Module.Guard("showing every nearby item", ShowAll);
			}

			internal void <Build>b__57_3(int index)
			{
				Module.Guard("grouping the nearby items", new <>c__DisplayClass57_1
				{
					index = index
				}.<Build>b__8);
			}

			internal void <Build>b__57_4(int index)
			{
				Module.Guard("sorting the nearby items", new <>c__DisplayClass57_2
				{
					index = index
				}.<Build>b__9);
			}

			internal void <Build>b__57_5(bool on)
			{
				Module.Guard("switching favourites first", new <>c__DisplayClass57_3
				{
					on = on
				}.<Build>b__10);
			}

			internal void <Build>b__57_6()
			{
				firstBox.isOn = !firstBox.isOn;
			}

			internal void <Scan>b__62_0(string line)
			{
				Module.Log.LogInfo((object)line);
			}

			internal bool <SetUpFor>b__63_0(ItemData item)
			{
				return false;
			}

			internal string <RenderGrid>b__81_0(GroupOption option)
			{
				return option.Label;
			}

			internal string <RenderGrid>b__81_1(SortOption option)
			{
				return option.Label;
			}

			internal bool <.cctor>b__93_0(string name)
			{
				return Favorites.List.Has(name);
			}
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass57_0
		{
			public string text;

			internal void <Build>b__7()
			{
				Typed(text);
			}
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass57_1
		{
			public int index;

			internal void <Build>b__8()
			{
				GroupPicked(index);
			}
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass57_2
		{
			public int index;

			internal void <Build>b__9()
			{
				SortPicked(index);
			}
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass57_3
		{
			public bool on;

			internal void <Build>b__10()
			{
				FirstSwitched(on);
			}
		}

		internal const float Width = 640f;

		internal const float Height = 760f;

		private const float Left = 20f;

		private const float Top = 54f;

		private const float RailWidth = 170f;

		private const float RailRowHeight = 24f;

		private const float ResultsX = 198f;

		private const float ResultsWidth = 422f;

		private const float ControlsY = 90f;

		private const float GridY = 126f;

		private const float GridBottom = 670f;

		private const float CellSize = 60f;

		private const float CellGap = 6f;

		private const int Columns = 6;

		private const float SearchPause = 0.25f;

		private const float ScanEvery = 1f;

		private const float RowsPerNotch = 2f;

		private static readonly Func<string, bool> Favourite = (string name) => Favorites.List.Has(name);

		private static readonly string PlainHex = ColorUtility.ToHtmlStringRGB(Ui.Plain);

		private static readonly string QuietHex = ColorUtility.ToHtmlStringRGB(Ui.Quiet);

		private static GameObject panel;

		private static RectTransform rail;

		private static RectTransform grid;

		private static ScrollRect gridScroll;

		private static ScrollRect[] scrolls = (ScrollRect[])(object)new ScrollRect[0];

		private static InputField searchBox;

		private static Text whereText;

		private static Button clearChip;

		private static Button allChip;

		private static Dropdown groupList;

		private static Dropdown sortList;

		private static Toggle firstBox;

		private static Image hoverIcon;

		private static Text hoverName;

		private static Text hoverWhere;

		private static Text chestsText;

		private static readonly List<Thumb> Thumbs = new List<Thumb>();

		private static readonly List<string> GroupShown = new List<string>();

		private static readonly List<string> SortShown = new List<string>();

		private static List<GroupOption> groupOptions = new List<GroupOption>();

		private static List<SortOption> sortOptions = new List<SortOption>();

		private static string sortShownId = "progression";

		private static DrawerSurvey survey = new DrawerSurvey();

		private static string shownKeys;

		private static bool renderDue;

		private static bool scanDue;

		private static float nextScan;

		private static int shownSettings = -1;

		private static float searchDue = -1f;

		private static bool focusSearch;

		private static string hovered;

		private static bool hoveredOwn;

		private static object viewFor;

		private static DrawerView view;

		internal static bool Shown
		{
			get
			{
				if ((Object)(object)panel != (Object)null)
				{
					return panel.activeSelf;
				}
				return false;
			}
		}

		internal static void Build(Transform windowRoot, float x, float y)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//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_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Expected O, but got Unknown
			//IL_033b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			//IL_02df: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Expected O, but got Unknown
			//IL_03bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_04cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_059f: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0626: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)panel != (Object)null)
			{
				Object.Destroy((Object)(object)panel);
			}
			Thumbs.Clear();
			GroupShown.Clear();
			SortShown.Clear();
			survey = new DrawerSurvey();
			shownKeys = null;
			renderDue = (scanDue = (focusSearch = false));
			searchDue = -1f;
			hovered = null;
			shownSettings = -1;
			GUIManager instance = GUIManager.Instance;
			panel = instance.CreateWoodpanel(windowRoot, new Vector2(0f, 1f), new Vector2(0f, 1f), Vector2.zero, 640f, 760f, false);
			((Object)panel).name = "Outfitter_Drawer";
			Ui.Place(panel, x, y, 640f, 760f);
			Transform transform = panel.transform;
			Ui.Label(transform, "Nearby items", 20f, 12f, 300f, 34f, 22, (TextAnchor)3, Ui.Orange, bold: true);
			GameObject obj = instance.CreateInputField(transform, new Vector2(0f, 1f), new Vector2(0f, 1f), Vector2.zero, (ContentType)0, "Filter", 16, 142f, 30f);
			Ui.Place(obj, 20f, 54f, 142f, 30f);
			searchBox = obj.GetComponent<InputField>();
			searchBox.characterLimit = 40;
			searchBox.lineType = (LineType)0;
			((UnityEvent<string>)(object)searchBox.onValueChanged).AddListener((UnityAction<string>)delegate(string text)
			{
				Module.Guard("filtering the nearby items", delegate
				{
					Typed(text);
				});
			});
			Ui.Label(transform, "F", 164f, 54f, 24f, 30f, 14, (TextAnchor)4, Ui.Quiet, bold: true);
			rail = DrawerUi.Scroll("Outfitter_DrawerList", transform, 20f, 88f, 170f, 582f, out var scroll);
			DrawerUi.List(rail, 0f);
			whereText = Ui.Label(transform, string.Empty, 198f, 56f, 222f, 26f, 18, (TextAnchor)3, Ui.Quiet);
			whereText.supportRichText = true;
			whereText.resizeTextForBestFit = true;
			whereText.resizeTextMinSize = 12;
			whereText.resizeTextMaxSize = 18;
			object obj2 = <>c.<>9__57_1;
			if (obj2 == null)
			{
				UnityAction val = delegate
				{
					Module.Guard("clearing the drawer's filter", ClearQuery);
				};
				<>c.<>9__57_1 = val;
				obj2 = (object)val;
			}
			clearChip = DrawerUi.Chip(transform, 426f, 54f, 104f, 28f, (UnityAction)obj2);
			object obj3 = <>c.<>9__57_2;
			if (obj3 == null)
			{
				UnityAction val2 = delegate
				{
					Module.Guard("showing every nearby item", ShowAll);
				};
				<>c.<>9__57_2 = val2;
				obj3 = (object)val2;
			}
			allChip = DrawerUi.Chip(transform, 534f, 54f, 86f, 28f, (UnityAction)obj3);
			DrawerUi.SetChip(allChip, "Show All ×");
			((Component)clearChip).gameObject.SetActive(false);
			((Component)allChip).gameObject.SetActive(false);
			Ui.Label(transform, "Group", 198f, 90f, 46f, 30f, 15, (TextAnchor)3, Ui.Quiet);
			groupList = DrawerUi.Dropdown(transform, 244f, 90f, 128f, 30f, 220f);
			((UnityEvent<int>)(object)groupList.onValueChanged).AddListener((UnityAction<int>)delegate(int index)
			{
				Module.Guard("grouping the nearby items", delegate
				{
					GroupPicked(index);
				});
			});
			Ui.Label(transform, "Sort", 380f, 90f, 36f, 30f, 15, (TextAnchor)3, Ui.Quiet);
			sortList = DrawerUi.Dropdown(transform, 416f, 90f, 110f, 30f, 200f);
			((UnityEvent<int>)(object)sortList.onValueChanged).AddListener((UnityAction<int>)delegate(int index)
			{
				Module.Guard("sorting the nearby items", delegate
				{
					SortPicked(index);
				});
			});
			firstBox = DrawerUi.Checkbox(transform, 534f, 94f, 22f);
			firstBox.SetIsOnWithoutNotify(true);
			((UnityEvent<bool>)(object)firstBox.onValueChanged).AddListener((UnityAction<bool>)delegate(bool on)
			{
				Module.Guard("switching favourites first", delegate
				{
					FirstSwitched(on);
				});
			});
			Sprite val3 = DrawerUi.Star();
			float num = 560f;
			if ((Object)(object)val3 != (Object)null)
			{
				DrawerUi.Icon(transform, val3, num, 96f, 18f);
				num += 20f;
			}
			Text obj4 = Ui.Label(transform, ((Object)(object)val3 != (Object)null) ? "First" : "* First", num, 90f, 620f - num, 30f, 15, (TextAnchor)3, Ui.Plain);
			((Graphic)obj4).raycastTarget = true;
			Clicks clicks = ((Component)obj4).gameObject.AddComponent<Clicks>();
			clicks.Lights = false;
			clicks.OnLeft = delegate
			{
				firstBox.isOn = !firstBox.isOn;
			};
			grid = DrawerUi.Scroll("Outfitter_DrawerItems", transform, 198f, 126f, 422f, 544f, out gridScroll);
			DrawerUi.List(grid, 4f);
			scrolls = (ScrollRect[])(object)new ScrollRect[2] { gridScroll, scroll };
			hoverIcon = DrawerUi.Icon(transform, null, 20f, 676f, 40f);
			hoverName = Ui.Label(transform, string.Empty, 68f, 674f, 552f, 22f, 15, (TextAnchor)3, Ui.Plain);
			hoverName.resizeTextForBestFit = true;
			hoverName.resizeTextMinSize = 11;
			hoverName.resizeTextMaxSize = 15;
			hoverWhere = Ui.Label(transform, string.Empty, 68f, 696f, 552f, 20f, 13, (TextAnchor)3, Ui.Quiet);
			chestsText = Ui.Label(transform, string.Empty, 20f, 722f, 600f, 22f, 13, (TextAnchor)3, Ui.Quiet);
			chestsText.resizeTextForBestFit = true;
			chestsText.resizeTextMinSize = 10;
			chestsText.resizeTextMaxSize = 13;
			ViewNow().Query = string.Empty;
			panel.SetActive(false);
		}

		internal static void SetShown(bool shown)
		{
			if ((Object)(object)panel == (Object)null)
			{
				return;
			}
			shown &= Settings.Drawer.Value;
			if (panel.activeSelf == shown)
			{
				scanDue |= shown;
				return;
			}
			panel.SetActive(shown);
			hovered = null;
			focusSearch = false;
			if (shown)
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null)
				{
					scanDue = true;
					return;
				}
				Scan(localPlayer, Time.unscaledTime);
				Render();
				ScrollToTop();
			}
		}

		internal static void Refresh(Player player)
		{
			if ((Object)(object)panel == (Object)null || !panel.activeSelf || (Object)(object)player == (Object)null || Popup.Showing)
			{
				return;
			}
			if (!Settings.Drawer.Value)
			{
				SetShown(shown: false);
				return;
			}
			Keys();
			float unscaledTime = Time.unscaledTime;
			if (searchDue >= 0f && unscaledTime >= searchDue)
			{
				searchDue = -1f;
				DrawerView drawerView = ViewNow();
				if (drawerView.Query.Length > 0 && drawerView.Pick.Pick != Pick.All)
				{
					drawerView.Pick = Selection.All;
				}
				Render();
				ScrollToTop();
			}
			if (Settings.Version != shownSettings)
			{
				scanDue = true;
			}
			if (scanDue || unscaledTime >= nextScan)
			{
				Scan(player, unscaledTime);
			}
			if (renderDue && Drag.Current == null)
			{
				Render();
			}
		}

		internal static void Forget()
		{
			if ((Object)(object)panel != (Object)null)
			{
				panel.SetActive(false);
			}
			survey = new DrawerSurvey();
			DrawerItems.Forget();
			Thumbs.Clear();
			shownKeys = null;
			renderDue = (scanDue = (focusSearch = false));
			searchDue = -1f;
			hovered = null;
		}

		private static void Keys()
		{
			if (focusSearch)
			{
				focusSearch = false;
				((Selectable)searchBox).Select();
				searchBox.ActivateInputField();
			}
			else if (ZInput.GetKeyDown((KeyCode)102, false) && !Ui.Typing())
			{
				focusSearch = true;
			}
			EventSystem current = EventSystem.current;
			GameObject val = (((Object)(object)current != (Object)null) ? current.currentSelectedGameObject : null);
			if ((Object)(object)val != (Object)null && ((Object)(object)val == (Object)(object)((Component)groupList).gameObject || (Object)(object)val == (Object)(object)((Component)sortList).gameObject) && !DrawerUi.Expanded(groupList) && !DrawerUi.Expanded(sortList))
			{
				current.SetSelectedGameObject((GameObject)null);
			}
			float mouseScrollWheel = ZInput.GetMouseScrollWheel();
			if (mouseScrollWheel != 0f && !DrawerUi.Expanded(groupList) && !DrawerUi.Expanded(sortList))
			{
				DrawerUi.Wheel(mouseScrollWheel, 132f, scrolls);
			}
		}

		private static void Scan(Player player, float now)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			scanDue = false;
			nextScan = now + 1f;
			shownSettings = Settings.Version;
			if (!Biomes.Built)
			{
				Biomes.Build(delegate(string line)
				{
					Module.Log.LogInfo((object)line);
				});
			}
			ChestRules chestRules = Settings.ChestRules();
			bool flag = Settings.Fetch.Value == FetchFrom.SetUpChestsOnly;
			List<DrawerChest> list = new List<DrawerChest>();
			int num = 0;
			foreach (Container item in ChestFinder.Find(((Component)player).transform.position, chestRules, withReserved: true))
			{
				if (!chestRules.UseReserved && ChestReserve.IsReserved(item))
				{
					num++;
				}
				else if (!ChestFinder.OpenElsewhere(item) || ChestShare.CanShare(item))
				{
					Inventory inventory = item.GetInventory();
					if (inventory != null)
					{
						list.Add(new DrawerChest
						{
							Items = inventory.GetAllItems(),
							Gives = (flag ? SetUpFor(item) : null)
						});
					}
				}
			}
			bool value = Settings.DrawerCarried.Value;
			DrawerSurvey before = survey;
			survey = DrawerItems.Read(list, value ? ((Humanoid)player).GetInventory().GetAllItems() : null, Game.m_worldLevel, Favourite, chestRules.LeaveOne);
			chestsText.text = DrawerItems.ChestsLine(survey.Chests, num, chestRules.Range, value, chestRules.LeaveOne, flag);
			if (survey.Keys != shownKeys)
			{
				renderDue = true;
			}
			else if (sortShownId == "count" && CountsChanged(before, survey))
			{
				renderDue = true;
			}
			else
			{
				Paint();
			}
			if (hovered != null)
			{
				ShowHover(hovered, hoveredOwn);
			}
			else
			{
				ShowHint();
			}
		}

		private static Func<ItemData, bool> SetUpFor(Container chest)
		{
			Func<ItemData, int> fit = Setups.Reading(chest);
			if (fit != null)
			{
				return (ItemData item) => fit(item) > 0;
			}
			return (ItemData item) => false;
		}

		private static bool CountsChanged(DrawerSurvey before, DrawerSurvey after)
		{
			foreach (DrawerKind kind in after.Kinds)
			{
				DrawerKind drawerKind = before.Find(kind.Key);
				if (drawerKind == null || drawerKind.Count != kind.Count)
				{
					return true;
				}
			}
			return false;
		}

		private static DrawerView ViewNow()
		{
			object obj = (((Object)(object)Game.instance != (Object)null && Game.instance.GetPlayerProfile() != null) ? ((object)Game.instance.GetPlayerProfile()) : ((object)Player.m_localPlayer));
			if (view == null || obj != viewFor)
			{
				viewFor = obj;
				view = new DrawerView();
				if ((Object)(object)searchBox != (Object)null)
				{
					searchBox.SetTextWithoutNotify(string.Empty);
				}
				searchDue = -1f;
			}
			return view;
		}

		private static void Render()
		{
			if (!((Object)(object)rail == (Object)null) && !((Object)(object)grid == (Object)null))
			{
				if (Drag.Current != null)
				{
					renderDue = true;
					return;
				}
				renderDue = false;
				DrawerView shownView = ViewNow();
				DrawerItems.Resolve(shownView, survey);
				RenderRail(shownView);
				RenderGrid(shownView);
				shownKeys = survey.Keys;
			}
		}

		private static bool FlushSearch()
		{
			if (searchDue < 0f)
			{
				return false;
			}
			searchDue = -1f;
			DrawerView drawerView = ViewNow();
			if (drawerView.Query.Length > 0)
			{
				drawerView.Pick = Selection.All;
			}
			return true;
		}

		private static void Typed(string text)
		{
			ViewNow().Query = (text ?? string.Empty).Trim();
			searchDue = Time.unscaledTime + 0.25f;
		}

		private static void ClearQuery()
		{
			searchBox.SetTextWithoutNotify(string.Empty);
			searchDue = -1f;
			ViewNow().Query = string.Empty;
			Render();
		}

		private static void ShowAll()
		{
			FlushSearch();
			ViewNow().Pick = Selection.All;
			Render();
			ScrollToTop();
		}

		private static void GroupPicked(int index)
		{
			if (index >= 0 && index < groupOptions.Count)
			{
				ViewNow().Group = groupOptions[index].Id;
				RenderGrid(ViewNow());
			}
		}

		private static void SortPicked(int index)
		{
			if (index >= 0 && index < sortOptions.Count)
			{
				ViewNow().Sort = sortOptions[index].Id;
				RenderGrid(ViewNow());
			}
		}

		private static void FirstSwitched(bool on)
		{
			ViewNow().FavouritesFirst = on;
			RenderGrid(ViewNow());
		}

		private static void ScrollToTop()
		{
			if ((Object)(object)gridScroll != (Object)null)
			{
				gridScroll.verticalNormalizedPosition = 1f;
			}
		}

		private static void RenderRail(DrawerView shownView)
		{
			DrawerUi.Clear((Transform)(object)rail);
			foreach (DrawerRow item in DrawerItems.Rail(survey, shownView))
			{
				if (item.Heading)
				{
					Title(item);
				}
				else
				{
					Row(item, shownView);
				}
			}
		}

		private static void Title(DrawerRow row)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			Image background;
			Clicks clicks = DrawerUi.ListRow((Transform)(object)rail, 24f, out background);
			Arrow(((Component)clicks).transform, row.Open, Ui.Orange);
			Ui.Label(((Component)clicks).transform, row.Label.ToUpperInvariant(), 18f, 0f, 132f, 24f, 13, (TextAnchor)3, Ui.Orange, bold: true);
			string title = row.Label;
			clicks.OnLeft = delegate
			{
				TitleClicked(title);
			};
		}

		private static void TitleClicked(string title)
		{
			bool num = FlushSearch();
			DrawerView drawerView = ViewNow();
			if (!drawerView.Folded.Remove(title))
			{
				drawerView.Folded.Add(title);
			}
			if (num)
			{
				Render();
				ScrollToTop();
			}
			else
			{
				RenderRail(drawerView);
			}
		}

		private static void Row(DrawerRow row, DrawerView shownView)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			bool flag = shownView.Pick.Equals(row.Pick);
			Image background;
			Clicks clicks = DrawerUi.ListRow((Transform)(object)rail, 24f, out background);
			clicks.Normal = (flag ? Ui.RowPicked : Ui.RowPlain);
			clicks.Lights = !flag;
			((Graphic)background).color = clicks.Normal;
			float num = (row.Member ? 30f : 18f);
			if (row.OpenId != null)
			{
				GameObject obj = Arrow(((Component)clicks).transform, row.Open, Ui.Quiet);
				obj.GetComponent<Graphic>().raycastTarget = true;
				Clicks clicks2 = obj.AddComponent<Clicks>();
				clicks2.Lights = false;
				clicks2.OnLeft = delegate
				{
					RowClicked(row, onTwisty: true);
				};
			}
			if (row.Favourites)
			{
				Sprite val = DrawerUi.Star();
				if ((Object)(object)val != (Object)null)
				{
					DrawerUi.Icon(((Component)clicks).transform, val, num, 4f, 16f);
					num += 20f;
				}
			}
			Text obj2 = Ui.Label(((Component)clicks).transform, row.Label, num, 0f, 120f - num - 2f, 24f, row.Member ? 14 : 15, (TextAnchor)3, (row.Count == 0) ? DrawerUi.Faint : Ui.Plain);
			obj2.resizeTextForBestFit = true;
			obj2.resizeTextMinSize = 11;
			obj2.resizeTextMaxSize = (row.Member ? 14 : 15);
			Ui.Label(((Component)clicks).transform, row.Count.ToString(CultureInfo.InvariantCulture), 120f, 0f, 28f, 24f, 12, (TextAnchor)5, flag ? Ui.Plain : Ui.Quiet);
			clicks.OnLeft = delegate
			{
				RowClicked(row, onTwisty: false);
			};
		}

		private static void RowClicked(DrawerRow row, bool onTwisty)
		{
			bool flag = FlushSearch();
			DrawerView drawerView = ViewNow();
			if (row.OpenId != null && (onTwisty || drawerView.Pick.Equals(row.Pick)))
			{
				if (!drawerView.Open.Remove(row.OpenId))
				{
					drawerView.Open.Add(row.OpenId);
				}
			}
			else if (row.OpenId != null)
			{
				drawerView.Open.Add(row.OpenId);
			}
			if (!onTwisty)
			{
				drawerView.Pick = row.Pick;
				Render();
				ScrollToTop();
			}
			else if (flag)
			{
				Render();
				ScrollToTop();
			}
			else
			{
				RenderRail(drawerView);
			}
		}

		private static GameObject Arrow(Transform row, bool open, Color color)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			Sprite sprite = GUIManager.Instance.GetSprite("map_marker");
			if ((Object)(object)sprite != (Object)null)
			{
				Image obj = DrawerUi.Icon(row, sprite, 3f, 6f, 12f);
				((Graphic)obj).rectTransform.pivot = new Vector2(0.5f, 0.5f);
				((Graphic)obj).rectTransform.anchoredPosition = new Vector2(9f, -12f);
				((Transform)((Graphic)obj).rectTransform).localRotation = Quaternion.Euler(0f, 0f, open ? 180f : (-90f));
				((Graphic)obj).color = color;
				return ((Component)obj).gameObject;
			}
			return ((Component)Ui.Label(row, open ? "−" : "+", 0f, 0f, 18f, 24f, 15, (TextAnchor)4, color, bold: true)).gameObject;
		}

		private static void RenderGrid(DrawerView shownView)
		{
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			if (Drag.Current != null)
			{
				renderDue = true;
				return;
			}
			DrawerUi.Clear((Transform)(object)grid);
			Thumbs.Clear();
			DrawerShown drawerShown = DrawerItems.Results(survey, shownView);
			groupOptions = drawerShown.GroupOptions;
			sortOptions = drawerShown.SortOptions;
			sortShownId = drawerShown.SortId;
			DrawerUi.SetChoices(groupList, GroupShown, groupOptions.Select((GroupOption option) => option.Label).ToList(), drawerShown.GroupIndex);
			DrawerUi.SetChoices(sortList, SortShown, sortOptions.Select((SortOption option) => option.Label).ToList(), drawerShown.SortIndex);
			firstBox.SetIsOnWithoutNotify(shownView.FavouritesFirst);
			bool own = shownView.Pick.Equals(DrawerItems.WithYou);
			foreach (DrawerSection section in drawerShown.Sections)
			{
				Section(section, own, drawerShown.SortId);
			}
			if (drawerShown.Empty != null)
			{
				Ui.Label(DrawerUi.Row((Transform)(object)grid, 110f).transform, drawerShown.Empty, 8f, 0f, 382f, 110f, 15, (TextAnchor)0, Ui.Quiet);
			}
			whereText.text = string.Format("<b><color=#{0}>{1}</color></b>  {2} item{3}", PlainHex, drawerShown.Whole, drawerShown.Total, (drawerShown.Total == 1) ? string.Empty : "s");
			string query = shownView.Query;
			((Component)clearChip).gameObject.SetActive(query.Length > 0);
			if (query.Length > 0)
			{
				DrawerUi.SetChip(clearChip, "\"" + ((query.Length > 8) ? (query.Substring(0, 8) + "…") : query) + "\" ×");
			}
			((Component)allChip).gameObject.SetActive(drawerShown.Narrowed);
			if (hovered != null && survey.Find(hovered) == null)
			{
				hovered = null;
				ShowHint();
			}
		}

		private static void Section(DrawerSection section, bool own, string sortId)
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = DrawerUi.Row((Transform)(object)grid, 26f);
			float num = 4f;
			Sprite val2 = (section.Star ? DrawerUi.Star() : null);
			if ((Object)(object)val2 != (Object)null)
			{
				DrawerUi.Icon(val.transform, val2, num, 5f, 18f);
				num += 22f;
			}
			Ui.Label(val.transform, $"{section.Heading}  <size=12><color=#{QuietHex}>{section.Kinds.Count}</color></size>", num, 0f, 382f - num, 26f, 16, (TextAnchor)6, Ui.Orange, bold: true).supportRichText = true;
			int num2 = (section.Kinds.Count + 6 - 1) / 6;
			GameObject val3 = DrawerUi.Row((Transform)(object)grid, (float)num2 * 60f + (float)Math.Max(0, num2 - 1) * 6f);
			GridLayoutGroup obj = val3.AddComponent<GridLayoutGroup>();
			obj.cellSize = new Vector2(60f, 60f);
			obj.spacing = new Vector2(6f, 6f);
			obj.constraint = (Constraint)1;
			obj.constraintCount = 6;
			foreach (DrawerKind kind in section.Kinds)
			{
				Thumbnail(val3.transform, kind, own, sortId);
			}
		}

		private static void Thumbnail(Transform block, DrawerKind kind, bool own, string sortId)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = Ui.Box("Outfitter_DrawerItem", block, 0f, 0f, 60f, 60f, Ui.Cell);
			((Graphic)val.GetComponent<Image>()).raycastTarget = true;
			Image icon = DrawerUi.Icon(val.transform, IconOf((own && kind.Own != null) ? kind.Own : kind.Sample), 6f, 6f, 48f);
			string text = DrawerItems.FoodCorner(kind.Listing, sortId) ?? ((kind.Quality > 1) ? kind.Quality.ToString(CultureInfo.InvariantCulture) : null);
			if (text != null)
			{
				Ui.Label(val.transform, text, 3f, 1f, 54f, 18f, 13, (TextAnchor)0, Ui.Plain);
			}
			Thumb thumb = new Thumb
			{
				Key = kind.Key,
				Icon = icon
			};
			thumb.Count = Ui.Label(val.transform, string.Empty, 3f, 38f, 54f, 20f, 13, (TextAnchor)6, Ui.Plain);
			Sprite val2 = DrawerUi.Star();
			thumb.Star = (((Object)(object)val2 != (Object)null) ? ((Component)DrawerUi.Icon(val.transform, val2, 41f, 2f, 17f)).gameObject : ((Component)Ui.Label(val.transform, "*", 42f, -2f, 16f, 20f, 20, (TextAnchor)2, DrawerUi.Gold, bold: true)).gameObject);
			string key = kind.Key;
			val.AddComponent<DragSource>().Make = () => Item(key, own);
			Clicks clicks = val.AddComponent<Clicks>();
			clicks.Lights = false;
			clicks.OnLeft = delegate
			{
				Clicked(key, own, right: false);
			};
			clicks.OnRight = delegate
			{
				Clicked(key, own, right: true);
			};
			clicks.OnEnter = delegate
			{
				Hover(key, own);
			};
			clicks.OnExit = delegate
			{
				Unhover(key);
			};
			Thumbs.Add(thumb);
			Paint(thumb, kind);
		}

		private static void Paint()
		{
			foreach (Thumb thumb in Thumbs)
			{
				DrawerKind drawerKind = survey.Find(thumb.Key);
				if (drawerKind != null)
				{
					Paint(thumb, drawerKind);
				}
			}
		}

		private static void Paint(Thumb thumb, DrawerKind kind)
		{
			//IL_00a0: 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 (thumb.CountShown != kind.Count)
			{
				thumb.CountShown = kind.Count;
				thumb.Count.text = DrawerItems.Short(kind.Count);
			}
			if (thumb.Star.activeSelf != kind.Favourite)
			{
				thumb.Star.SetActive(kind.Favourite);
			}
			bool flag = kind.Count == 0;
			if ((Object)(object)thumb.Icon != (Object)null && thumb.Grey != flag)
			{
				thumb.Grey = flag;
				((Graphic)thumb.Icon).color = (Color)(flag ? new Color(1f, 1f, 1f, 0.35f) : Color.white);
			}
		}

		private static DragItem Item(string key, bool own)
		{
			DrawerKind drawerKind = survey.Find(key);
			if (drawerKind == null)
			{
				return null;
			}
			ItemData val = ((own && drawerKind.Own != null) ? drawerKind.Own : drawerKind.Sample);
			return new DragItem
			{
				Prefab = drawerKind.Prefab,
				Quality = drawerKind.Quality,
				Variant = (val?.m_variant ?? 0),
				Count = drawerKind.Count,
				Sample = val,
				Icon = IconOf(val)
			};
		}

		private static void Clicked(string key, bool own, bool right)
		{
			if (Drag.Current == null && (right || Settings.DrawerClicks.Value != DrawerClick.Nothing))
			{
				DragItem dragItem = Item(key, own);
				if (dragItem != null)
				{
					Drag.Clicked?.Invoke(dragItem, right);
				}
			}
		}

		private static void Hover(string key, bool own)
		{
			hovered = key;
			hoveredOwn = own;
			ShowHover(key, own);
		}

		private static void Unhover(string key)
		{
			if (hovered == key)
			{
				hovered = null;
				ShowHint();
			}
		}

		private static void ShowHover(string key, bool own)
		{
			DrawerKind drawerKind = survey.Find(key);
			if (drawerKind == null)
			{
				ShowHint();
				return;
			}
			hoverName.text = DrawerItems.HoverLine(drawerKind, survey.Carried);
			hoverWhere.text = DrawerItems.Describe(drawerKind.Listing);
			Sprite val = IconOf((own && drawerKind.Own != null) ? drawerKind.Own : drawerKind.Sample);
			hoverIcon.sprite = val;
			((Behaviour)hoverIcon).enabled = (Object)(object)val != (Object)null;
		}

		private static void ShowHint()
		{
			((Behaviour)hoverIcon).enabled = false;
			hoverName.text = "Drag an item onto a cell of the loadout.";
			hoverWhere.text = ((Settings.DrawerClicks.Value == DrawerClick.FirstFreeCell) ? "A click puts it in the first free cell." : string.Empty);
		}

		private static Sprite IconOf(ItemData item)
		{
			Sprite[] array = item?.m_shared?.m_icons;
			if (array == null || array.Length == 0)
			{
				return null;
			}
			return array[Mathf.Clamp(item.m_variant, 0, array.Length - 1)];
		}
	}
	internal sealed class DrawerKind
	{
		internal string Key;

		internal string Prefab;

		internal int Quality = 1;

		internal string SharedName;

		internal string Name;

		internal bool HasLevels;

		internal int InChests;

		internal int Kept;

		internal int WithHim;

		internal ItemData Sample;

		internal ItemData Own;

		internal bool Favourite;

		internal Listing Listing;

		internal int Count => InChests + WithHim;
	}
	internal sealed class DrawerChest
	{
		internal IEnumerable<ItemData> Items;

		internal Func<ItemData, bool> Gives;
	}
	internal sealed class DrawerSurvey
	{
		internal readonly List<DrawerKind> Kinds = new List<DrawerKind>();

		internal readonly Dictionary<string, DrawerKind> ByKey = new Dictionary<string, DrawerKind>();

		internal int Chests;

		internal bool Carried;

		internal string Keys = string.Empty;

		internal DrawerKind Find(string key)
		{
			if (key == null || !ByKey.TryGetValue(key, out var value))
			{
				return null;
			}
			return value;
		}
	}
	internal sealed class DrawerView
	{
		internal Selection Pick = Selection.All;

		internal string Group = "auto";

		internal string Sort = "progression";

		internal bool FavouritesFirst = true;

		internal string Query = string.Empty;

		internal readonly HashSet<string> Open = new HashSet<string>();

		internal readonly HashSet<string> Folded = new HashSet<string>();
	}
	internal sealed class DrawerRow
	{
		internal string Label;

		internal bool Heading;

		internal bool Open;

		internal Selection Pick;

		internal int Count;

		internal bool Member;

		internal string OpenId;

		internal bool Favourites;
	}
	internal sealed class DrawerSection
	{
		internal string Heading;

		internal bool Star;

		internal readonly List<DrawerKind> Kinds = new List<DrawerKind>();
	}
	internal sealed class DrawerShown
	{
		internal readonly List<DrawerSection> Sections = new List<DrawerSection>();

		internal List<GroupOption> GroupOptions;

		internal List<SortOption> SortOptions;

		internal int GroupIndex;

		internal int SortIndex;

		internal string SortId = "progression";

		internal string Whole = string.Empty;

		internal int Total;

		internal bool Narrowed;

		internal string Empty;
	}
	internal static class DrawerItems
	{
		internal const string AllLabel = "All";

		internal const string FavouritesLabel = "Favourites";

		internal const string WithYouLabel = "With you";

		internal const string YoursTitle = "Yours";

		internal const string CountSort = "count";

		internal static readonly Selection Favourites = new Selection(Pick.Favorites);

		internal static readonly Selection WithYou = Browse.ListPick(0, "With you");

		private static readonly Orders Order = Orders.Default;

		internal static Func<string, string, string, Listing> ListingOf = (string key, string name, string sharedName) => Listings.Item(Shelf.Take, key, name, sharedName, null, string.Empty, 1);

		private static readonly Dictionary<string, Listing> Made = new Dictionary<string, Listing>();

		internal static void Forget()
		{
			Made.Clear();
		}

		internal static DrawerSurvey Read(IEnumerable<IEnumerable<ItemData>> chests, IEnumerable<ItemData> carried, int worldLevel, Func<string, bool> favourite)
		{
			return Read(chests?.Select((IEnumerable<ItemData> items) => new DrawerChest
			{
				Items = items
			}), carried, worldLevel, favourite, leaveOne: false);
		}

		internal static DrawerSurvey Read(IEnumerable<DrawerChest> chests, IEnumerable<ItemData> carried, int worldLevel, Func<string, bool> favourite, bool leaveOne)
		{
			DrawerSurvey drawerSurvey = new DrawerSurvey
			{
				Carried = (carried != null)
			};
			Dictionary<(string, int), DrawerKind> byKind = new Dictionary<(string, int), DrawerKind>();
			if (chests != null)
			{
				foreach (DrawerChest chest in chests)
				{
					if (chest?.Items == null)
					{
						continue;
					}
					drawerSurvey.Chests++;
					Dictionary<(string, int), (ItemData, int)> dictionary = null;
					foreach (ItemData item in chest.Items)
					{
						if (!Usable(item) || item.m_worldLevel < worldLevel || (chest.Gives != null && !chest.Gives(item)))
						{
							continue;
						}
						if (leaveOne && item.m_shared.m_maxStackSize > 1)
						{
							string text = Outfitter.Loadouts.Capture.PrefabOf(item);
							if (!string.IsNullOrEmpty(text))
							{
								(string, int) key = (text, Math.Max(1, item.m_quality));
								dictionary = dictionary ?? new Dictionary<(string, int), (ItemData, int)>();
								dictionary[key] = (dictionary.TryGetValue(key, out var value) ? (value.Item1, value.Item2 + item.m_stack) : (item, item.m_stack));
							}
						}
						else
						{
							DrawerKind drawerKind = KindOf(drawerSurvey, byKind, item);
							if (drawerKind != null)
							{
								drawerKind.InChests += item.m_stack;
							}
						}
					}
					if (dictionary == null)
					{
						continue;
					}
					foreach (var value2 in dictionary.Values)
					{
						DrawerKind drawerKind2 = KindOf(drawerSurvey, byKind, value2.Item1);
						if (drawerKind2 != null)
						{
							drawerKind2.InChests += value2.Item2 - 1;
							drawerKind2.Kept++;
						}
					}
				}
			}
			if (carried != null)
			{
				foreach (ItemData item2 in carried)
				{
					if (!Usable(item2))
					{
						continue;
					}
					DrawerKind drawerKind3 = KindOf(drawerSurvey, byKind, item2);
					if (drawerKind3 != null)
					{
						drawerKind3.WithHim += item2.m_stack;
						if (drawerKind3.Own == null)
						{
							drawerKind3.Own = item2;
						}
					}
				}
			}
			foreach (DrawerKind kind in drawerSurvey.Kinds)
			{
				kind.Favourite = favourite?.Invoke(kind.SharedName) ?? false;
				kind.Listing = ListingFor(kind);
			}
			drawerSurvey.Keys = KeysOf(drawerSurvey);
			return drawerSurvey;
		}

		internal static bool Refavour(DrawerSurvey survey, Func<string, bool> favourite)
		{
			bool flag = false;
			foreach (DrawerKind kind in survey.Kinds)
			{
				bool flag2 = favourite?.Invoke(kind.SharedName) ?? false;
				flag |= flag2 != kind.Favourite;
				kind.Favourite = flag2;
			}
			if (flag)
			{
				survey.Keys = KeysOf(survey);
			}
			return flag;
		}

		private static string KeysOf(DrawerSurvey survey)
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (DrawerKind item in survey.Kinds.OrderBy<DrawerKind, string>((DrawerKind each) => each.Key, StringComparer.Ordinal))
			{
				stringBuilder.Append(item.Key).Append((item.WithHim > 0) ? "+" : "-").Append(item.Favourite ? "*" : "-")
					.Append('\n');
			}
			return stringBuilder.ToString();
		}

		private static bool Usable(ItemData item)
		{
			if (item?.m_shared != null)
			{
				return item.m_stack > 0;
			}
			return false;
		}

		private static DrawerKind KindOf(DrawerSurvey survey, Dictionary<(string, int), DrawerKind> byKind, ItemData item)
		{
			string text = Outfitter.Loadouts.Capture.PrefabOf(item);
			if (string.IsNullOrEmpty(text))
			{
				return null;
			}
			int num = Math.Max(1, item.m_quality);
			if (byKind.TryGetValue((text, num), out var value))
			{
				return value;
			}
			bool flag = item.m_shared.m_maxQuality > 1;
			value = new DrawerKind
			{
				Key = text + "@" + num.ToString(CultureInfo.InvariantCulture),
				Prefab = text,
				Quality = num,
				SharedName = item.m_shared.m_name,
				Name = Messages.Localize(item.m_shared.m_name) + (flag ? (", level " + num.ToString(CultureInfo.InvariantCulture)) : string.Empty),
				HasLevels = flag,
				Sample = item
			};
			byKind[(text, num)] = value;
			survey.ByKey[value.Key] = value;
			survey.Kinds.Add(value);
			return value;
		}

		private static Listing ListingFor(DrawerKind kind)
		{
			if (!Made.TryGetValue(kind.Key, out var value))
			{
				value = ListingOf(kind.Key, kind.Name, kind.SharedName);
				Made[kind.Key] = value;
			}
			return value;
		}

		internal static void Resolve(Draw