Decompiled source of ReLegendQOL v0.13.0

ReLegendQOL.dll

Decompiled 4 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Google2u;
using HarmonyLib;
using Localization;
using Microsoft.CodeAnalysis;
using ReLegendQOL.Patches;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("ReLegendQOL")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.13.0.0")]
[assembly: AssemblyInformationalVersion("0.13.0")]
[assembly: AssemblyProduct("ReLegendQOL")]
[assembly: AssemblyTitle("ReLegendQOL")]
[assembly: AssemblyVersion("0.13.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 ReLegendQOL
{
	internal static class AutoLoot
	{
		private static float _nextScan;

		private static bool _warnedMultiplayer;

		internal static void Tick()
		{
			if (!Plugin.AutoLootEnabled.Value || Time.unscaledTime < _nextScan)
			{
				return;
			}
			_nextScan = Time.unscaledTime + Mathf.Max(0.05f, Plugin.AutoLootInterval.Value);
			try
			{
				Scan();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Auto-loot scan failed: " + ex));
			}
		}

		private static void Scan()
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			GameManager instance = GameManager.instance;
			PlayerHandler val = (((Object)(object)instance != (Object)null) ? instance.player : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			if (IsMultiplayer())
			{
				if (!_warnedMultiplayer)
				{
					_warnedMultiplayer = true;
					Plugin.Log.LogInfo((object)"Auto-loot is disabled in multiplayer sessions.");
				}
				return;
			}
			ItemDrop[] array = Object.FindObjectsOfType<ItemDrop>();
			if (array == null || array.Length == 0)
			{
				return;
			}
			Vector3 position = ((Component)val).transform.position;
			float num = Mathf.Max(0.5f, Plugin.AutoLootRadius.Value);
			float num2 = num * num;
			int minRank = MinRank();
			Transform transform = ((Component)val).transform;
			int num3 = 0;
			foreach (ItemDrop val2 in array)
			{
				if (!Eligible(val2, minRank))
				{
					continue;
				}
				Vector3 val3 = ((Component)val2).transform.position - position;
				val3.y = 0f;
				if (!(((Vector3)(ref val3)).sqrMagnitude > num2))
				{
					val2.MoveToPlayer(transform);
					num3++;
					if (Plugin.AutoLootVerbose.Value)
					{
						Item itemSo = val2.itemSo;
						Plugin.Log.LogInfo((object)("Auto-loot pulled '" + (((Object)(object)itemSo != (Object)null) ? itemSo.itemName : "?") + "' (farmTrash=" + val2.isFarmTrash + ", wildLoot=" + val2.isWildLoot + ", tween=" + val2.itemTween + ")"));
					}
				}
			}
			if (num3 > 0 && !Plugin.AutoLootVerbose.Value)
			{
				Plugin.Log.LogInfo((object)("Auto-loot pulled " + num3 + " item(s)."));
			}
		}

		private static bool Eligible(ItemDrop drop, int minRank)
		{
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)drop == (Object)null)
			{
				return false;
			}
			if (!((Component)drop).gameObject.activeInHierarchy)
			{
				return false;
			}
			if (!((Behaviour)drop).enabled)
			{
				return false;
			}
			if (IsAttachedToPlayer(drop))
			{
				return false;
			}
			if (drop.isPicked || drop.isUsed)
			{
				return false;
			}
			if (drop.isMoveTowardTarget)
			{
				return false;
			}
			if (drop.treasureChest)
			{
				return false;
			}
			if (drop.isThrowObject || drop.itemThrowing)
			{
				return false;
			}
			if (drop.itemTween)
			{
				return false;
			}
			if (drop.isFishFood)
			{
				return false;
			}
			if (drop.isFarmTrash)
			{
				return false;
			}
			Item itemSo = drop.itemSo;
			if ((Object)(object)itemSo == (Object)null)
			{
				return false;
			}
			if (Rank(itemSo.itemRarity) < minRank)
			{
				return false;
			}
			return true;
		}

		private static bool IsAttachedToPlayer(ItemDrop drop)
		{
			try
			{
				PlayerHandler val = (((Object)(object)GameManager.instance != (Object)null) ? GameManager.instance.player : null);
				if ((Object)(object)val == (Object)null)
				{
					return false;
				}
				Transform root = ((Component)val).transform.root;
				if ((Object)(object)root == (Object)null)
				{
					return false;
				}
				return (Object)(object)((Component)drop).transform.root == (Object)(object)root;
			}
			catch
			{
				return true;
			}
		}

		private static bool IsMultiplayer()
		{
			try
			{
				MainMenuStat instance = MainMenuStat.instance;
				return (Object)(object)instance != (Object)null && instance.IsMultiplayerReady;
			}
			catch
			{
				return true;
			}
		}

		private static int MinRank()
		{
			return (Plugin.AutoLootMinRarity.Value ?? "").Trim().ToLowerInvariant() switch
			{
				"legendary" => 3, 
				"rare" => 2, 
				"uncommon" => 1, 
				"common" => 0, 
				_ => -1, 
			};
		}

		private static int Rank(ItemRarity r)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected I4, but got Unknown
			return (int)r switch
			{
				3 => 3, 
				2 => 2, 
				1 => 1, 
				0 => 0, 
				_ => -1, 
			};
		}
	}
	internal class ModEntry
	{
		public string Name;

		public string Version;

		public string Guid;

		public bool Instantiated;

		public string Description;

		public string WebsiteUrl;

		public string IconPath;

		public Texture2D Icon;

		public bool IconLoadAttempted;

		public ConfigFile Config;

		public List<ConfigEntryBase> BoolSettings = new List<ConfigEntryBase>();
	}
	internal static class ModRegistry
	{
		private static readonly Dictionary<string, Texture2D> IconCache = new Dictionary<string, Texture2D>();

		internal static List<ModEntry> Snapshot()
		{
			List<ModEntry> list = new List<ModEntry>();
			try
			{
				foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos)
				{
					PluginInfo value = pluginInfo.Value;
					if (value == null)
					{
						continue;
					}
					ModEntry modEntry = new ModEntry
					{
						Name = pluginInfo.Key,
						Version = "?",
						Guid = pluginInfo.Key,
						Instantiated = ((Object)(object)value.Instance != (Object)null)
					};
					if (value.Metadata != null)
					{
						if (!string.IsNullOrEmpty(value.Metadata.Name))
						{
							modEntry.Name = value.Metadata.Name;
						}
						if (value.Metadata.Version != null)
						{
							modEntry.Version = value.Metadata.Version.ToString();
						}
					}
					Enrich(modEntry, value);
					CollectSettings(modEntry, value);
					list.Add(modEntry);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Could not read Chainloader.PluginInfos: " + ex));
			}
			list.Sort((ModEntry a, ModEntry b) => string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase));
			return list;
		}

		private static void CollectSettings(ModEntry entry, PluginInfo info)
		{
			try
			{
				if ((Object)(object)info.Instance == (Object)null)
				{
					return;
				}
				ConfigFile config = info.Instance.Config;
				if (config == null)
				{
					return;
				}
				entry.Config = config;
				List<ConfigEntryBase> list = new List<ConfigEntryBase>();
				IDictionary silent = Reflect.GetSilent<IDictionary>(typeof(ConfigFile), "Entries", config);
				if (silent != null)
				{
					foreach (DictionaryEntry item in silent)
					{
						object? value = item.Value;
						ConfigEntryBase val = (ConfigEntryBase)((value is ConfigEntryBase) ? value : null);
						if (val != null)
						{
							list.Add(val);
						}
					}
				}
				else
				{
					foreach (ConfigDefinition key in config.Keys)
					{
						try
						{
							ConfigEntryBase val2 = config[key];
							if (val2 != null)
							{
								list.Add(val2);
							}
						}
						catch
						{
						}
					}
				}
				foreach (ConfigEntryBase item2 in list)
				{
					if (!(item2.SettingType != typeof(bool)))
					{
						entry.BoolSettings.Add(item2);
					}
				}
				entry.BoolSettings.Sort(delegate(ConfigEntryBase a, ConfigEntryBase b)
				{
					int num = string.Compare(a.Definition.Section, b.Definition.Section, StringComparison.OrdinalIgnoreCase);
					return (num != 0) ? num : string.Compare(a.Definition.Key, b.Definition.Key, StringComparison.OrdinalIgnoreCase);
				});
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not read settings for " + entry.Guid + ": " + ex.Message));
			}
		}

		private static void Enrich(ModEntry entry, PluginInfo info)
		{
			try
			{
				string text = LocateAssembly(info);
				if (string.IsNullOrEmpty(text))
				{
					return;
				}
				string directoryName = Path.GetDirectoryName(text);
				string text2 = NormalizeDir(Paths.PluginPath);
				for (int i = 0; i < 4; i++)
				{
					if (string.IsNullOrEmpty(directoryName))
					{
						break;
					}
					if (NormalizeDir(directoryName) == text2)
					{
						break;
					}
					if (EnrichFromFolder(entry, directoryName))
					{
						break;
					}
					directoryName = Path.GetDirectoryName(directoryName);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not read manifest for " + entry.Guid + ": " + ex.Message));
			}
		}

		internal static bool EnrichFromFolder(ModEntry entry, string dir)
		{
			try
			{
				if (string.IsNullOrEmpty(dir))
				{
					return false;
				}
				string path = Path.Combine(dir, "manifest.json");
				if (!File.Exists(path))
				{
					return false;
				}
				ReadManifest(entry, path);
				string text = Path.Combine(dir, "icon.png");
				if (File.Exists(text))
				{
					entry.IconPath = text;
				}
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static string NormalizeDir(string path)
		{
			if (string.IsNullOrEmpty(path))
			{
				return "";
			}
			try
			{
				return Path.GetFullPath(path).TrimEnd('\\', '/').ToLowerInvariant();
			}
			catch
			{
				return path.ToLowerInvariant();
			}
		}

		private static string LocateAssembly(PluginInfo info)
		{
			string property = Reflect.GetProperty<string>(typeof(PluginInfo), "Location", info);
			if (!string.IsNullOrEmpty(property))
			{
				return property;
			}
			if ((Object)(object)info.Instance != (Object)null)
			{
				try
				{
					return ((object)info.Instance).GetType().Assembly.Location;
				}
				catch
				{
				}
			}
			return null;
		}

		private static void ReadManifest(ModEntry entry, string path)
		{
			string json = File.ReadAllText(path);
			string text = JsonString(json, "description");
			if (!string.IsNullOrEmpty(text))
			{
				entry.Description = text;
			}
			string text2 = JsonString(json, "website_url");
			if (!string.IsNullOrEmpty(text2))
			{
				entry.WebsiteUrl = text2;
			}
			if (entry.Version == "?")
			{
				string text3 = JsonString(json, "version_number");
				if (!string.IsNullOrEmpty(text3))
				{
					entry.Version = text3;
				}
			}
		}

		internal static string JsonString(string json, string key)
		{
			if (string.IsNullOrEmpty(json) || string.IsNullOrEmpty(key))
			{
				return null;
			}
			string text = "\"" + key + "\"";
			int num = json.IndexOf(text, StringComparison.Ordinal);
			if (num < 0)
			{
				return null;
			}
			int num2 = json.IndexOf(':', num + text.Length);
			if (num2 < 0)
			{
				return null;
			}
			int i;
			for (i = num2 + 1; i < json.Length && char.IsWhiteSpace(json[i]); i++)
			{
			}
			if (i >= json.Length || json[i] != '"')
			{
				return null;
			}
			i++;
			StringBuilder stringBuilder = new StringBuilder();
			while (i < json.Length)
			{
				char c = json[i];
				switch (c)
				{
				case '\\':
				{
					if (i + 1 >= json.Length)
					{
						break;
					}
					char c2 = json[i + 1];
					switch (c2)
					{
					case 'n':
						stringBuilder.Append(' ');
						break;
					case 't':
						stringBuilder.Append(' ');
						break;
					case '"':
						stringBuilder.Append('"');
						break;
					case '\\':
						stringBuilder.Append('\\');
						break;
					case '/':
						stringBuilder.Append('/');
						break;
					case 'u':
						if (i + 5 < json.Length)
						{
							if (int.TryParse(json.Substring(i + 2, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result))
							{
								stringBuilder.Append((char)result);
							}
							i += 4;
						}
						break;
					default:
						stringBuilder.Append(c2);
						break;
					case 'r':
						break;
					}
					i += 2;
					continue;
				}
				default:
					stringBuilder.Append(c);
					i++;
					continue;
				case '"':
					break;
				}
				break;
			}
			return stringBuilder.ToString();
		}

		internal static Texture2D LoadIcon(ModEntry entry)
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			if (entry == null)
			{
				return null;
			}
			if ((Object)(object)entry.Icon != (Object)null)
			{
				return entry.Icon;
			}
			if (entry.IconLoadAttempted)
			{
				return null;
			}
			entry.IconLoadAttempted = true;
			if (string.IsNullOrEmpty(entry.IconPath))
			{
				return null;
			}
			if (IconCache.TryGetValue(entry.IconPath, out var value) && (Object)(object)value != (Object)null)
			{
				entry.Icon = value;
				return value;
			}
			try
			{
				byte[] array = File.ReadAllBytes(entry.IconPath);
				Texture2D val = new Texture2D(256, 256, (TextureFormat)4, false);
				if (!ImageConversion.LoadImage(val, array))
				{
					Object.Destroy((Object)(object)val);
					Plugin.Log.LogWarning((object)("Could not decode icon: " + entry.IconPath));
					return null;
				}
				((Texture)val).wrapMode = (TextureWrapMode)1;
				IconCache[entry.IconPath] = val;
				entry.Icon = val;
				return val;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not load icon " + entry.IconPath + ": " + ex.Message));
				return null;
			}
		}

		internal static int PluginFilesOnDisk()
		{
			try
			{
				string pluginPath = Paths.PluginPath;
				if (string.IsNullOrEmpty(pluginPath) || !Directory.Exists(pluginPath))
				{
					return -1;
				}
				return Directory.GetFiles(pluginPath, "*.dll", SearchOption.AllDirectories).Length;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not scan the plugins folder: " + ex.Message));
				return -1;
			}
		}
	}
	internal class ModsPanel : MonoBehaviour
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UnityAction <>9__29_2;

			internal void <BuildFooter>b__29_2()
			{
				Close();
			}
		}

		private const float PanelWidth = 1240f;

		private const float PanelHeight = 700f;

		private const float CardHeight = 104f;

		private const float CardGap = 10f;

		private const float ListTop = 96f;

		private const float ListBottom = 108f;

		private const float LeftPaneFraction = 0.56f;

		private const int MaxCardsPerPage = 3;

		private static ModsPanel _current;

		private GameObject _root;

		private TextMeshProUGUI _summary;

		private TextMeshProUGUI _pageLabel;

		private Transform _cardArea;

		private Transform _settingsArea;

		private TextMeshProUGUI _settingsHeader;

		private TMP_FontAsset _font;

		private readonly List<ModEntry> _mods = new List<ModEntry>();

		private readonly List<GameObject> _cards = new List<GameObject>();

		private int _page;

		private int _selected;

		internal static bool IsOpen
		{
			get
			{
				if ((Object)(object)_current != (Object)null && (Object)(object)_current._root != (Object)null)
				{
					return _current._root.activeSelf;
				}
				return false;
			}
		}

		internal static void Toggle(TMP_FontAsset font)
		{
			if (IsOpen)
			{
				Close();
			}
			else
			{
				Open(font);
			}
		}

		internal static void Open(TMP_FontAsset font)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)_current == (Object)null)
				{
					_current = new GameObject("ReLegendQOL_ModsPanel").AddComponent<ModsPanel>();
					_current._font = font;
					_current.Build();
				}
				if (!((Object)(object)_current._root == (Object)null))
				{
					if ((Object)(object)_current._font == (Object)null)
					{
						_current._font = font;
					}
					_current._page = 0;
					_current._selected = 0;
					_current.Refresh();
					_current._root.SetActive(true);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Could not open the mods panel: " + ex));
			}
		}

		internal static void Close()
		{
			if ((Object)(object)_current != (Object)null && (Object)(object)_current._root != (Object)null)
			{
				_current._root.SetActive(false);
			}
		}

		private void Update()
		{
			if (IsOpen)
			{
				if (Input.GetKeyDown((KeyCode)27))
				{
					Close();
				}
				else if (Input.GetKeyDown((KeyCode)276))
				{
					ChangePage(-1);
				}
				else if (Input.GetKeyDown((KeyCode)275))
				{
					ChangePage(1);
				}
				else if (Input.GetKeyDown((KeyCode)273))
				{
					MoveSelection(-1);
				}
				else if (Input.GetKeyDown((KeyCode)274))
				{
					MoveSelection(1);
				}
			}
		}

		private int RowsThatFit()
		{
			return Mathf.Clamp(Mathf.FloorToInt((496f + 10f) / 114f), 1, 3);
		}

		private int PageCount()
		{
			if (_mods.Count == 0)
			{
				return 1;
			}
			return Mathf.CeilToInt((float)_mods.Count / (float)RowsThatFit());
		}

		private void Build()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: 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)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Expected O, but got Unknown
			//IL_029e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0312: Unknown result type (might be due to invalid IL or missing references)
			//IL_032c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0341: Unknown result type (might be due to invalid IL or missing references)
			//IL_0356: Unknown result type (might be due to invalid IL or missing references)
			//IL_036b: Unknown result type (might be due to invalid IL or missing references)
			//IL_037f: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0409: Unknown result type (might be due to invalid IL or missing references)
			//IL_0446: Unknown result type (might be due to invalid IL or missing references)
			//IL_045b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0470: Unknown result type (might be due to invalid IL or missing references)
			//IL_0484: Unknown result type (might be due to invalid IL or missing references)
			_root = new GameObject("Canvas");
			_root.transform.SetParent(((Component)this).transform, false);
			Canvas obj = _root.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = 5000;
			CanvasScaler obj2 = _root.AddComponent<CanvasScaler>();
			obj2.uiScaleMode = (ScaleMode)1;
			obj2.referenceResolution = new Vector2(1920f, 1080f);
			_root.AddComponent<GraphicRaycaster>();
			Stretch(MakeImage("Dim", _root.transform, new Color(0f, 0f, 0f, 0.78f)).GetComponent<RectTransform>());
			GameObject val = MakeImage("Panel", _root.transform, new Color(0.09f, 0.08f, 0.11f, 0.98f));
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0.5f, 0.5f);
			component.anchorMax = new Vector2(0.5f, 0.5f);
			component.pivot = new Vector2(0.5f, 0.5f);
			component.anchoredPosition = Vector2.zero;
			component.sizeDelta = new Vector2(1240f, 700f);
			GameObject obj3 = MakeText("Title", val.transform, 32f, (TextAlignmentOptions)258);
			RectTransform component2 = obj3.GetComponent<RectTransform>();
			component2.anchorMin = new Vector2(0f, 1f);
			component2.anchorMax = new Vector2(1f, 1f);
			component2.pivot = new Vector2(0.5f, 1f);
			component2.offsetMin = new Vector2(30f, -62f);
			component2.offsetMax = new Vector2(-30f, -20f);
			((TMP_Text)obj3.GetComponent<TextMeshProUGUI>()).text = "Installed Mods";
			GameObject val2 = MakeText("Summary", val.transform, 18f, (TextAlignmentOptions)258);
			RectTransform component3 = val2.GetComponent<RectTransform>();
			component3.anchorMin = new Vector2(0f, 1f);
			component3.anchorMax = new Vector2(1f, 1f);
			component3.pivot = new Vector2(0.5f, 1f);
			component3.offsetMin = new Vector2(30f, -92f);
			component3.offsetMax = new Vector2(-30f, -64f);
			_summary = val2.GetComponent<TextMeshProUGUI>();
			GameObject val3 = new GameObject("Cards");
			val3.transform.SetParent(val.transform, false);
			RectTransform obj4 = val3.AddComponent<RectTransform>();
			obj4.anchorMin = new Vector2(0f, 0f);
			obj4.anchorMax = new Vector2(0.56f, 1f);
			obj4.offsetMin = new Vector2(24f, 108f);
			obj4.offsetMax = new Vector2(-14f, -96f);
			_cardArea = val3.transform;
			RectTransform component4 = MakeImage("Divider", val.transform, new Color(1f, 1f, 1f, 0.14f)).GetComponent<RectTransform>();
			component4.anchorMin = new Vector2(0.56f, 0f);
			component4.anchorMax = new Vector2(0.56f, 1f);
			component4.pivot = new Vector2(0.5f, 0.5f);
			component4.offsetMin = new Vector2(-1f, 100f);
			component4.offsetMax = new Vector2(1f, -92f);
			GameObject val4 = MakeText("SettingsHeader", val.transform, 20f, (TextAlignmentOptions)257);
			RectTransform component5 = val4.GetComponent<RectTransform>();
			component5.anchorMin = new Vector2(0.56f, 1f);
			component5.anchorMax = new Vector2(1f, 1f);
			component5.pivot = new Vector2(0.5f, 1f);
			component5.offsetMin = new Vector2(18f, -100f);
			component5.offsetMax = new Vector2(-24f, -66f);
			_settingsHeader = val4.GetComponent<TextMeshProUGUI>();
			RectTransform component6 = MakeScrollArea("Settings", val.transform, out _settingsArea).GetComponent<RectTransform>();
			component6.anchorMin = new Vector2(0.56f, 0f);
			component6.anchorMax = new Vector2(1f, 1f);
			component6.offsetMin = new Vector2(18f, 108f);
			component6.offsetMax = new Vector2(-24f, -130f);
			BuildFooter(val.transform);
			_root.SetActive(false);
		}

		private void BuildFooter(Transform panel)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			//IL_002d: 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_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Expected O, but got Unknown
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Expected O, but got Unknown
			RectTransform component = MakeButton("Prev", panel, "<", (UnityAction)delegate
			{
				ChangePage(-1);
			}).GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0f, 0f);
			component.anchorMax = new Vector2(0f, 0f);
			component.pivot = new Vector2(0f, 0f);
			component.anchoredPosition = new Vector2(24f, 58f);
			component.sizeDelta = new Vector2(54f, 38f);
			RectTransform component2 = MakeButton("Next", panel, ">", (UnityAction)delegate
			{
				ChangePage(1);
			}).GetComponent<RectTransform>();
			component2.anchorMin = new Vector2(0.56f, 0f);
			component2.anchorMax = new Vector2(0.56f, 0f);
			component2.pivot = new Vector2(1f, 0f);
			component2.anchoredPosition = new Vector2(-14f, 58f);
			component2.sizeDelta = new Vector2(54f, 38f);
			GameObject val = MakeText("PageLabel", panel, 17f, (TextAlignmentOptions)514);
			RectTransform component3 = val.GetComponent<RectTransform>();
			component3.anchorMin = new Vector2(0f, 0f);
			component3.anchorMax = new Vector2(0.56f, 0f);
			component3.pivot = new Vector2(0.5f, 0f);
			component3.offsetMin = new Vector2(84f, 60f);
			component3.offsetMax = new Vector2(-74f, 94f);
			_pageLabel = val.GetComponent<TextMeshProUGUI>();
			GameObject obj = MakeText("Hint", panel, 15f, (TextAlignmentOptions)513);
			RectTransform component4 = obj.GetComponent<RectTransform>();
			component4.anchorMin = new Vector2(0f, 0f);
			component4.anchorMax = new Vector2(1f, 0f);
			component4.pivot = new Vector2(0.5f, 0f);
			component4.offsetMin = new Vector2(26f, 18f);
			component4.offsetMax = new Vector2(-260f, 48f);
			((TMP_Text)obj.GetComponent<TextMeshProUGUI>()).text = "<color=#6E6878>Click a mod to see its settings. Arrows page and change selection. Changes save immediately.</color>";
			object obj2 = <>c.<>9__29_2;
			if (obj2 == null)
			{
				UnityAction val2 = delegate
				{
					Close();
				};
				<>c.<>9__29_2 = val2;
				obj2 = (object)val2;
			}
			RectTransform component5 = MakeButton("Close", panel, "Close", (UnityAction)obj2).GetComponent<RectTransform>();
			component5.anchorMin = new Vector2(1f, 0f);
			component5.anchorMax = new Vector2(1f, 0f);
			component5.pivot = new Vector2(1f, 0f);
			component5.anchoredPosition = new Vector2(-24f, 18f);
			component5.sizeDelta = new Vector2(200f, 40f);
		}

		private GameObject MakeScrollArea(string name, Transform parent, out Transform content)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Expected O, but got Unknown
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Unknown result type (might be due to invalid IL or missing references)
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0287: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			val.AddComponent<RectTransform>();
			ScrollRect obj = val.AddComponent<ScrollRect>();
			obj.horizontal = false;
			obj.vertical = true;
			obj.scrollSensitivity = 24f;
			obj.movementType = (MovementType)2;
			GameObject val2 = new GameObject("Viewport");
			val2.transform.SetParent(val.transform, false);
			RectTransform val3 = val2.AddComponent<RectTransform>();
			val3.anchorMin = Vector2.zero;
			val3.anchorMax = Vector2.one;
			val3.offsetMin = Vector2.zero;
			val3.offsetMax = new Vector2(-10f, 0f);
			val2.AddComponent<RectMask2D>();
			GameObject val4 = new GameObject("Content");
			val4.transform.SetParent(val2.transform, false);
			RectTransform val5 = val4.AddComponent<RectTransform>();
			val5.anchorMin = new Vector2(0f, 1f);
			val5.anchorMax = new Vector2(1f, 1f);
			val5.pivot = new Vector2(0.5f, 1f);
			val5.offsetMin = Vector2.zero;
			val5.offsetMax = Vector2.zero;
			val5.sizeDelta = new Vector2(0f, 0f);
			obj.viewport = val3;
			obj.content = val5;
			GameObject val6 = MakeImage("Scrollbar", val.transform, new Color(1f, 1f, 1f, 0.07f));
			RectTransform component = val6.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(1f, 0f);
			component.anchorMax = new Vector2(1f, 1f);
			component.pivot = new Vector2(1f, 0.5f);
			component.offsetMin = new Vector2(-8f, 0f);
			component.offsetMax = new Vector2(0f, 0f);
			Scrollbar val7 = val6.AddComponent<Scrollbar>();
			val7.direction = (Direction)2;
			GameObject val8 = MakeImage("SlidingArea", val6.transform, new Color(0f, 0f, 0f, 0f));
			Stretch(val8.GetComponent<RectTransform>());
			GameObject val9 = MakeImage("Handle", val8.transform, new Color(0.55f, 0.5f, 0.62f, 0.9f));
			RectTransform component2 = val9.GetComponent<RectTransform>();
			component2.anchorMin = Vector2.zero;
			component2.anchorMax = Vector2.one;
			component2.offsetMin = Vector2.zero;
			component2.offsetMax = Vector2.zero;
			component2.sizeDelta = Vector2.zero;
			component2.pivot = new Vector2(0.5f, 0.5f);
			val7.handleRect = component2;
			((Selectable)val7).targetGraphic = (Graphic)(object)val9.GetComponent<Image>();
			val7.size = 0.25f;
			obj.verticalScrollbar = val7;
			obj.verticalScrollbarVisibility = (ScrollbarVisibility)1;
			content = val4.transform;
			return val;
		}

		private void Refresh()
		{
			_mods.Clear();
			_mods.AddRange(ModRegistry.Snapshot());
			int num = 0;
			foreach (ModEntry mod in _mods)
			{
				if (mod.Instantiated)
				{
					num++;
				}
			}
			int num2 = ModRegistry.PluginFilesOnDisk();
			string text = "<b>" + num + ((num == 1) ? " mod loaded" : " mods loaded") + "</b>";
			if (_mods.Count != num)
			{
				text = text + "  of " + _mods.Count + " registered";
			}
			if (num2 >= 0 && num2 != _mods.Count)
			{
				text = text + "   <color=#9A93A6>(" + num2 + " .dll files on disk; one assembly can hold several plugins)</color>";
			}
			if ((Object)(object)_summary != (Object)null)
			{
				((TMP_Text)_summary).text = text;
			}
			_selected = Mathf.Clamp(_selected, 0, Mathf.Max(0, _mods.Count - 1));
			_page = ((_mods.Count != 0) ? (_selected / RowsThatFit()) : 0);
			RebuildCards();
			RebuildSettings();
		}

		private void ChangePage(int delta)
		{
			int num = PageCount();
			if (num > 1)
			{
				int num2 = Mathf.Clamp(_page + delta, 0, num - 1);
				if (num2 != _page)
				{
					_page = num2;
					RebuildCards();
				}
			}
		}

		private void MoveSelection(int delta)
		{
			if (_mods.Count != 0)
			{
				int num = Mathf.Clamp(_selected + delta, 0, _mods.Count - 1);
				if (num != _selected)
				{
					Select(num);
				}
			}
		}

		private void Select(int index)
		{
			if (index >= 0 && index < _mods.Count)
			{
				_selected = index;
				_page = index / RowsThatFit();
				RebuildCards();
				RebuildSettings();
			}
		}

		private void RebuildCards()
		{
			if ((Object)(object)_cardArea == (Object)null)
			{
				return;
			}
			for (int num = _cardArea.childCount - 1; num >= 0; num--)
			{
				Object.Destroy((Object)(object)((Component)_cardArea.GetChild(num)).gameObject);
			}
			_cards.Clear();
			int num2 = RowsThatFit();
			int num3 = _page * num2;
			if ((Object)(object)_pageLabel != (Object)null)
			{
				((TMP_Text)_pageLabel).text = ((_mods.Count == 0) ? "<color=#9A93A6>Nothing registered with BepInEx</color>" : ("<color=#9A93A6>Page " + (_page + 1) + " / " + PageCount() + "   -   " + _mods.Count + " total</color>"));
			}
			for (int i = 0; i < num2; i++)
			{
				int num4 = num3 + i;
				if (num4 < _mods.Count)
				{
					BuildCard(_mods[num4], i, num4);
					continue;
				}
				break;
			}
		}

		private void BuildCard(ModEntry mod, int slot, int index)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: 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_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Expected O, but got Unknown
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_040a: Unknown result type (might be due to invalid IL or missing references)
			//IL_043f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0455: Unknown result type (might be due to invalid IL or missing references)
			//IL_046b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0477: Unknown result type (might be due to invalid IL or missing references)
			//IL_0483: Unknown result type (might be due to invalid IL or missing references)
			Color color = ((index == _selected) ? new Color(0.3f, 0.34f, 0.46f, 0.95f) : new Color(1f, 1f, 1f, 0.06f));
			GameObject val = MakeImage("Card" + slot, _cardArea, color);
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0f, 1f);
			component.anchorMax = new Vector2(1f, 1f);
			component.pivot = new Vector2(0.5f, 1f);
			component.offsetMin = new Vector2(0f, 0f - (114f * (float)slot + 104f));
			component.offsetMax = new Vector2(0f, 0f - 114f * (float)slot);
			int captured = index;
			((UnityEvent)val.AddComponent<Button>().onClick).AddListener((UnityAction)delegate
			{
				Select(captured);
			});
			_cards.Add(val);
			GameObject val2 = MakeImage("Icon", val.transform, Color.white);
			RectTransform component2 = val2.GetComponent<RectTransform>();
			component2.anchorMin = new Vector2(0f, 1f);
			component2.anchorMax = new Vector2(0f, 1f);
			component2.pivot = new Vector2(0f, 1f);
			component2.anchoredPosition = new Vector2(12f, -12f);
			component2.sizeDelta = new Vector2(72f, 72f);
			Image component3 = val2.GetComponent<Image>();
			Texture2D val3 = ModRegistry.LoadIcon(mod);
			if ((Object)(object)val3 != (Object)null)
			{
				component3.sprite = Sprite.Create(val3, new Rect(0f, 0f, (float)((Texture)val3).width, (float)((Texture)val3).height), new Vector2(0.5f, 0.5f));
			}
			else
			{
				((Graphic)component3).color = new Color(0.22f, 0.2f, 0.26f, 1f);
				GameObject obj = MakeText("Initial", val2.transform, 34f, (TextAlignmentOptions)514);
				Stretch(obj.GetComponent<RectTransform>());
				((TMP_Text)obj.GetComponent<TextMeshProUGUI>()).text = (string.IsNullOrEmpty(mod.Name) ? "?" : mod.Name.Substring(0, 1).ToUpperInvariant());
			}
			GameObject obj2 = MakeText("Name", val.transform, 20f, (TextAlignmentOptions)257);
			RectTransform component4 = obj2.GetComponent<RectTransform>();
			component4.anchorMin = new Vector2(0f, 1f);
			component4.anchorMax = new Vector2(1f, 1f);
			component4.pivot = new Vector2(0.5f, 1f);
			component4.offsetMin = new Vector2(94f, -32f);
			component4.offsetMax = new Vector2(-12f, -8f);
			string text = (mod.Instantiated ? "<color=#8FD98F>*</color> " : "<color=#E08A8A>!</color> ");
			string text2 = (mod.Instantiated ? "" : "  <color=#E08A8A>(not running)</color>");
			int num = ((mod.BoolSettings != null) ? mod.BoolSettings.Count : 0);
			string text3 = ((num > 0) ? ("  <size=15><color=#9A93A6>" + num + " toggles</color></size>") : "");
			((TMP_Text)obj2.GetComponent<TextMeshProUGUI>()).text = text + "<b>" + mod.Name + "</b>  <color=#9A93A6>v" + mod.Version + "</color>" + text2 + text3;
			Transform content;
			RectTransform component5 = MakeScrollArea("DescScroll", val.transform, out content).GetComponent<RectTransform>();
			component5.anchorMin = new Vector2(0f, 0f);
			component5.anchorMax = new Vector2(1f, 1f);
			component5.offsetMin = new Vector2(94f, 8f);
			component5.offsetMax = new Vector2(-8f, -34f);
			GameObject obj3 = MakeText("Desc", content, 16f, (TextAlignmentOptions)257);
			RectTransform component6 = obj3.GetComponent<RectTransform>();
			component6.anchorMin = new Vector2(0f, 1f);
			component6.anchorMax = new Vector2(1f, 1f);
			component6.pivot = new Vector2(0.5f, 1f);
			component6.offsetMin = Vector2.zero;
			component6.offsetMax = Vector2.zero;
			TextMeshProUGUI component7 = obj3.GetComponent<TextMeshProUGUI>();
			((TMP_Text)component7).enableWordWrapping = true;
			((TMP_Text)component7).overflowMode = (TextOverflowModes)0;
			((TMP_Text)component7).text = (string.IsNullOrEmpty(mod.Description) ? "<color=#6E6878>No manifest.json found beside this mod's DLL, so no description is available.</color>" : ("<color=#C9C3D4>" + mod.Description + "</color>"));
			SizeToText(component7, component6, content);
		}

		private static void SizeToText(TextMeshProUGUI tmp, RectTransform textRt, Transform content)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				((TMP_Text)tmp).ForceMeshUpdate();
				float num = Mathf.Max(20f, ((TMP_Text)tmp).preferredHeight + 4f);
				textRt.sizeDelta = new Vector2(0f, num);
				RectTransform val = (RectTransform)(object)((content is RectTransform) ? content : null);
				if ((Object)(object)val != (Object)null)
				{
					val.sizeDelta = new Vector2(0f, num);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not size scroll content: " + ex.Message));
			}
		}

		private void RebuildSettings()
		{
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Unknown result type (might be due to invalid IL or missing references)
			//IL_0274: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e6: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_settingsArea == (Object)null)
			{
				return;
			}
			for (int num = _settingsArea.childCount - 1; num >= 0; num--)
			{
				Object.Destroy((Object)(object)((Component)_settingsArea.GetChild(num)).gameObject);
			}
			if (_mods.Count == 0 || _selected < 0 || _selected >= _mods.Count)
			{
				if ((Object)(object)_settingsHeader != (Object)null)
				{
					((TMP_Text)_settingsHeader).text = "<b>Settings</b>";
				}
				return;
			}
			ModEntry modEntry = _mods[_selected];
			List<ConfigEntryBase> list = Toggleable(modEntry);
			if ((Object)(object)_settingsHeader != (Object)null)
			{
				((TMP_Text)_settingsHeader).text = "<b>" + modEntry.Name + "</b>  <size=15><color=#9A93A6>settings</color></size>";
			}
			Transform settingsArea = _settingsArea;
			RectTransform val = (RectTransform)(object)((settingsArea is RectTransform) ? settingsArea : null);
			if (list == null || list.Count == 0)
			{
				GameObject obj = MakeText("None", _settingsArea, 16f, (TextAlignmentOptions)257);
				RectTransform component = obj.GetComponent<RectTransform>();
				component.anchorMin = new Vector2(0f, 1f);
				component.anchorMax = new Vector2(1f, 1f);
				component.pivot = new Vector2(0.5f, 1f);
				component.offsetMin = new Vector2(0f, -70f);
				component.offsetMax = Vector2.zero;
				TextMeshProUGUI component2 = obj.GetComponent<TextMeshProUGUI>();
				((TMP_Text)component2).enableWordWrapping = true;
				((TMP_Text)component2).text = (modEntry.Instantiated ? "<color=#6E6878>This mod exposes no on/off settings.</color>" : "<color=#E08A8A>This mod is registered but not running, so its settings are unavailable.</color>");
				if ((Object)(object)val != (Object)null)
				{
					val.sizeDelta = new Vector2(0f, 70f);
				}
				return;
			}
			float num2 = 0f;
			string text = null;
			for (int i = 0; i < list.Count; i++)
			{
				ConfigEntryBase val2 = list[i];
				string section = val2.Definition.Section;
				if (section != text)
				{
					text = section;
					GameObject obj2 = MakeText("S" + i, _settingsArea, 15f, (TextAlignmentOptions)513);
					RectTransform component3 = obj2.GetComponent<RectTransform>();
					component3.anchorMin = new Vector2(0f, 1f);
					component3.anchorMax = new Vector2(1f, 1f);
					component3.pivot = new Vector2(0.5f, 1f);
					component3.offsetMin = new Vector2(2f, 0f - (num2 + 26f));
					component3.offsetMax = new Vector2(0f, 0f - num2);
					((TMP_Text)obj2.GetComponent<TextMeshProUGUI>()).text = "<color=#7F8AA6><b>" + section.ToUpperInvariant() + "</b></color>";
					num2 += 26f;
				}
				BuildSettingRow(modEntry, val2, num2, 34f);
				num2 += 34f;
			}
			if ((Object)(object)val != (Object)null)
			{
				val.sizeDelta = new Vector2(0f, num2 + 8f);
			}
		}

		private static List<ConfigEntryBase> Toggleable(ModEntry mod)
		{
			List<ConfigEntryBase> list = new List<ConfigEntryBase>();
			if (mod.BoolSettings == null)
			{
				return list;
			}
			bool flag = string.Equals(mod.Guid, "com.community.relegend.qol", StringComparison.OrdinalIgnoreCase);
			for (int i = 0; i < mod.BoolSettings.Count; i++)
			{
				ConfigEntryBase val = mod.BoolSettings[i];
				if (!flag || !string.Equals(val.Definition.Section, "ModsTab", StringComparison.OrdinalIgnoreCase) || !string.Equals(val.Definition.Key, "Enabled", StringComparison.OrdinalIgnoreCase))
				{
					list.Add(val);
				}
			}
			return list;
		}

		private void BuildSettingRow(ModEntry mod, ConfigEntryBase setting, float y, float height)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Expected O, but got Unknown
			GameObject val = MakeImage("Row", _settingsArea, new Color(1f, 1f, 1f, 0.05f));
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0f, 1f);
			component.anchorMax = new Vector2(1f, 1f);
			component.pivot = new Vector2(0.5f, 1f);
			component.offsetMin = new Vector2(2f, 0f - (y + height) + 3f);
			component.offsetMax = new Vector2(-2f, 0f - y);
			GameObject obj = MakeText("L", val.transform, 16f, (TextAlignmentOptions)513);
			Stretch(obj.GetComponent<RectTransform>());
			TextMeshProUGUI component2 = obj.GetComponent<TextMeshProUGUI>();
			((TMP_Text)component2).text = RowText(setting);
			ConfigEntryBase captured = setting;
			ModEntry capturedMod = mod;
			TextMeshProUGUI capturedLabel = component2;
			((UnityEvent)val.AddComponent<Button>().onClick).AddListener((UnityAction)delegate
			{
				ToggleSetting(capturedMod, captured, capturedLabel);
			});
		}

		private static string RowText(ConfigEntryBase setting)
		{
			bool flag = false;
			try
			{
				flag = setting.BoxedValue is bool && (bool)setting.BoxedValue;
			}
			catch
			{
			}
			string text = Spaced(setting.Definition.Key);
			string text2 = (flag ? "<color=#8FD98F>[x]</color>" : "<color=#6E6878>[ ]</color>");
			string text3 = (flag ? text : ("<color=#9A93A6>" + text + "</color>"));
			string text4 = Summarise(setting);
			if (!string.IsNullOrEmpty(text4))
			{
				text4 = "  <size=13><color=#7F7A8A>" + text4 + "</color></size>";
			}
			return " " + text2 + " " + text3 + text4;
		}

		private static string Spaced(string key)
		{
			if (string.IsNullOrEmpty(key))
			{
				return "";
			}
			StringBuilder stringBuilder = new StringBuilder(key.Length + 8);
			for (int i = 0; i < key.Length; i++)
			{
				char c = key[i];
				if (i > 0 && char.IsUpper(c) && !char.IsUpper(key[i - 1]))
				{
					stringBuilder.Append(' ');
					stringBuilder.Append(char.ToLowerInvariant(c));
				}
				else
				{
					stringBuilder.Append(c);
				}
			}
			return stringBuilder.ToString();
		}

		private static string Summarise(ConfigEntryBase setting)
		{
			try
			{
				if (setting.Description == null)
				{
					return null;
				}
				string description = setting.Description.Description;
				if (string.IsNullOrEmpty(description))
				{
					return null;
				}
				description = description.Replace("\r", " ").Replace("\n", " ").Trim();
				while (description.Contains("  "))
				{
					description = description.Replace("  ", " ");
				}
				int num = description.IndexOf(". ", StringComparison.Ordinal);
				if (num > 0)
				{
					description = description.Substring(0, num);
				}
				else if (description.EndsWith("."))
				{
					description = description.Substring(0, description.Length - 1);
				}
				if (description.Length > 84)
				{
					description = description.Substring(0, 81).TrimEnd(Array.Empty<char>()) + "...";
				}
				return description;
			}
			catch
			{
				return null;
			}
		}

		private void ToggleSetting(ModEntry mod, ConfigEntryBase setting, TextMeshProUGUI label)
		{
			try
			{
				if (setting.BoxedValue is bool)
				{
					bool flag = (bool)setting.BoxedValue;
					setting.BoxedValue = !flag;
					if (mod.Config != null)
					{
						mod.Config.Save();
					}
					if ((Object)(object)label != (Object)null)
					{
						((TMP_Text)label).text = RowText(setting);
					}
					Plugin.Log.LogInfo((object)(mod.Name + ": " + setting.Definition.Section + "/" + setting.Definition.Key + " = " + !flag));
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Could not toggle " + setting.Definition.Key + " on " + mod.Name + ": " + ex));
			}
		}

		private GameObject MakeImage(string name, Transform parent, Color color)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			val.AddComponent<RectTransform>();
			((Graphic)val.AddComponent<Image>()).color = color;
			return val;
		}

		private GameObject MakeText(string name, Transform parent, float size, TextAlignmentOptions align)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			val.AddComponent<RectTransform>();
			TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>();
			if ((Object)(object)_font != (Object)null)
			{
				((TMP_Text)val2).font = _font;
			}
			((TMP_Text)val2).fontSize = size;
			((Graphic)val2).color = Color.white;
			((TMP_Text)val2).alignment = align;
			((TMP_Text)val2).richText = true;
			((Graphic)val2).raycastTarget = false;
			return val;
		}

		private GameObject MakeButton(string name, Transform parent, string label, UnityAction onClick)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = MakeImage(name, parent, new Color(0.24f, 0.22f, 0.28f, 1f));
			((UnityEvent)val.AddComponent<Button>().onClick).AddListener(onClick);
			GameObject obj = MakeText("Label", val.transform, 19f, (TextAlignmentOptions)514);
			Stretch(obj.GetComponent<RectTransform>());
			((TMP_Text)obj.GetComponent<TextMeshProUGUI>()).text = label;
			return val;
		}

		private static void Stretch(RectTransform rt)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			rt.anchorMin = Vector2.zero;
			rt.anchorMax = Vector2.one;
			rt.offsetMin = Vector2.zero;
			rt.offsetMax = Vector2.zero;
		}
	}
	[BepInPlugin("com.community.relegend.qol", "Re:Legend QOL Pack", "0.13.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string GUID = "com.community.relegend.qol";

		public const string NAME = "Re:Legend QOL Pack";

		public const string VERSION = "0.13.0";

		internal static ManualLogSource Log;

		internal static Plugin Instance;

		private Harmony _harmony;

		internal static ConfigEntry<bool> SortEnabled;

		internal static ConfigEntry<string> SortPreset;

		internal static ConfigEntry<string> SortKeys;

		internal static ConfigEntry<bool> SortEmptiesLast;

		internal static ConfigEntry<KeyboardShortcut> SortHotkey;

		internal static ConfigEntry<bool> SellEnabled;

		internal static ConfigEntry<string> SellButtonLabel;

		internal static ConfigEntry<float> SellPriceMultiplier;

		internal static ConfigEntry<bool> SellUseAmountPicker;

		internal static ConfigEntry<bool> SellEquipmentAllowed;

		internal static ConfigEntry<string> AmountPanelLabel;

		internal static ConfigEntry<bool> AutoToolEnabled;

		internal static ConfigEntry<bool> AutoToolSearchBackpack;

		internal static ConfigEntry<float> AutoToolCooldown;

		internal static ConfigEntry<bool> AutoToolStow;

		internal static ConfigEntry<bool> PoiMarkersEnabled;

		internal static ConfigEntry<bool> PoiShops;

		internal static ConfigEntry<bool> PoiServices;

		internal static ConfigEntry<float> PoiMarkerScale;

		internal static ConfigEntry<float> PoiScanInterval;

		internal static ConfigEntry<string> FaceCursorMode;

		internal static ConfigEntry<bool> QuickTransferEnabled;

		internal static ConfigEntry<bool> BeltScrollEnabled;

		internal static ConfigEntry<bool> BeltScrollInvert;

		internal static ConfigEntry<float> BeltScrollThreshold;

		internal static ConfigEntry<bool> BeltScrollRequireCtrl;

		internal static ConfigEntry<float> BeltScrollCooldown;

		internal static ConfigEntry<bool> DialogueFastEnabled;

		internal static ConfigEntry<float> DialogueSpeed;

		internal static ConfigEntry<bool> SortButtonEnabled;

		internal static ConfigEntry<string> SortButtonLabel;

		internal static ConfigEntry<float> SortButtonGap;

		internal static ConfigEntry<float> SortButtonY;

		internal static ConfigEntry<float> SortButtonWidth;

		internal static ConfigEntry<float> SortButtonStorageGap;

		internal static ConfigEntry<bool> AutoLootEnabled;

		internal static ConfigEntry<float> AutoLootRadius;

		internal static ConfigEntry<string> AutoLootMinRarity;

		internal static ConfigEntry<float> AutoLootInterval;

		internal static ConfigEntry<bool> AutoLootVerbose;

		internal static ConfigEntry<bool> FaceCursorFreezeWhileOrbiting;

		internal static ConfigEntry<string> FaceCursorAimSource;

		internal static ConfigEntry<bool> SeedInfoEnabled;

		internal static ConfigEntry<bool> ModsTabEnabled;

		internal static ConfigEntry<string> ModsTabLabel;

		internal static ConfigEntry<float> ModsTabOffsetY;

		internal static ConfigEntry<string> ModsTabPlacement;

		internal static ConfigEntry<float> ModsTabRowPadding;

		internal static ConfigEntry<KeyboardShortcut> ModsTabHotkey;

		private void Awake()
		{
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0676: Unknown result type (might be due to invalid IL or missing references)
			//IL_06b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_06be: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			SortEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Sorting", "Enabled", true, "Replace the game's inventory sort with a stable, configurable one.");
			SortPreset = ((BaseUnityPlugin)this).Config.Bind<string>("Sorting", "Preset", "TypeRarity", "Ready-made sort orders. Set to Custom to use SortOrder below instead.\n  TypeRarity    - TYPE, RARITY, NAME (default)\n  MaterialFirst - crafting materials grouped first, then TYPE, RARITY, NAME\n  RarityFirst   - RARITY, TYPE, NAME\n  Alphabetical  - NAME\n  Value         - most valuable first\n  Quantity      - biggest stacks first\n  Custom        - use SortOrder");
			SortKeys = ((BaseUnityPlugin)this).Config.Bind<string>("Sorting", "SortOrder", "TYPE,RARITY,NAME,QUANTITY", "Comma-separated sort keys, applied in order (first = most significant).\nValid keys: TYPE, SUBTYPE, RARITY, BIOME, QUANTITY, NAME, VALUE, ID.\nPrefix a key with '-' to reverse it, e.g. '-NAME' for Z-to-A.");
			SortEmptiesLast = ((BaseUnityPlugin)this).Config.Bind<bool>("Sorting", "EmptySlotsLast", true, "Push empty slots to the end of the container after sorting.");
			SortHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Sorting", "Hotkey", new KeyboardShortcut((KeyCode)114, Array.Empty<KeyCode>()), "Sorts whichever container UI is currently open. Set to 'None' to disable.");
			SellEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Sell", "Enabled", true, "Adds a Sell entry to the right-click item menu.");
			SellButtonLabel = ((BaseUnityPlugin)this).Config.Bind<string>("Sell", "ButtonLabel", "Sell", "Text shown on the Sell entry. Not localised — set this to your language.");
			SellPriceMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Sell", "PriceMultiplier", 1f, "Multiplier on the item's normal sell price. 1.0 matches the shipping bin.\nLower it (e.g. 0.75) if you want convenience to cost you something.");
			SellUseAmountPicker = ((BaseUnityPlugin)this).Config.Bind<bool>("Sell", "UseAmountPicker", true, "Reuse the game's drop-amount slider to choose how many to sell.\nWhen false, clicking Sell sells the entire stack immediately.");
			SellEquipmentAllowed = ((BaseUnityPlugin)this).Config.Bind<bool>("Sell", "AllowEquipment", true, "Allow selling equipment. Currently-equipped items can never be sold.");
			AmountPanelLabel = ((BaseUnityPlugin)this).Config.Bind<string>("Inventory", "AmountPanelLabel", "Quantity", "The quantity slider is shared by dropping and selling, so its vanilla\n'DROP QUANTITY' heading is wrong half the time. Applies to both.\nLeave blank to keep the vanilla wording.");
			AutoToolEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("AutoTool", "Enabled", true, "When holding attack near a tree or rock, put the required tool in hand\nautomatically. Holding to gather is already vanilla behaviour; the only\nthing that blocked it was having the wrong tool equipped.");
			AutoToolSearchBackpack = ((BaseUnityPlugin)this).Config.Bind<bool>("AutoTool", "SearchBackpack", true, "Also look in the backpack, not just the tool belt.");
			AutoToolCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("AutoTool", "SwapCooldown", 0.35f, "Minimum seconds between automatic tool swaps. ToolAttack runs every frame\nwhile the button is held, so this stops it fighting the swing animation\nwhen several node types are in range at once.");
			AutoToolStow = ((BaseUnityPlugin)this).Config.Bind<bool>("AutoTool", "StowWhenDone", true, "Put the tool away once nothing is left to gather nearby, restoring whatever\nwas in hand beforehand (or empty hands if nothing was).");
			PoiMarkersEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("PoiMarkers", "Enabled", true, "Add distinct minimap markers for shops and service NPCs in the current scene.");
			PoiShops = ((BaseUnityPlugin)this).Config.Bind<bool>("PoiMarkers", "Shops", true, "Mark NPCs that sell (gold).");
			PoiServices = ((BaseUnityPlugin)this).Config.Bind<bool>("PoiMarkers", "Services", true, "Mark heal, enhance, fuse, upgrade and fish-race NPCs.");
			PoiMarkerScale = ((BaseUnityPlugin)this).Config.Bind<float>("PoiMarkers", "MarkerScale", 1.35f, "Size multiplier relative to the NPC's own minimap icon.");
			PoiScanInterval = ((BaseUnityPlugin)this).Config.Bind<float>("PoiMarkers", "ScanInterval", 5f, "Seconds between rescans. NPCs move and scenes change, but scanning every\nframe would be wasteful; markers parent to the NPC so they follow it anyway.");
			FaceCursorFreezeWhileOrbiting = ((BaseUnityPlugin)this).Config.Bind<bool>("FaceCursor", "FreezeWhileOrbiting", true, "Do not turn the character while right mouse is held. Applies to continuous\nfacing only (Mode=Always) - attacks still aim correctly while orbiting, see\nAimSource. Right mouse orbits the camera in the third person mod, where\nmovement is camera-relative, so turning the body at the same time drags the\ncharacter around with the camera.");
			FaceCursorAimSource = ((BaseUnityPlugin)this).Config.Bind<string>("FaceCursor", "AimSource", "Auto", "Where an attack aims:\n  Auto          - camera direction while right mouse is held, cursor otherwise\n  Cursor        - always the cursor\n  CameraForward - always the camera direction\nWhile right mouse orbits the camera the cursor no longer says where you are\nlooking, so aiming at it fired attacks along whatever direction the body was\nleft in. Auto fixes that without changing plain clicks.");
			FaceCursorMode = ((BaseUnityPlugin)this).Config.Bind<string>("FaceCursor", "Mode", "WhileAttacking", "Fixes attacks firing along the last WASD direction instead of where you aim.\n  WhileAttacking - turn to the cursor the instant you attack (default)\n  Always         - face the cursor continuously (see below)\n  Never          - vanilla behaviour\n'Always' is experimental: this game's Animator has only a 'Walk' boolean and\nno directional blend, so there is no strafe or backpedal animation. You will\nsee a forward run while sliding sideways. Gathering is never affected.");
			SortButtonStorageGap = ((BaseUnityPlugin)this).Config.Bind<float>("SortButton", "StorageGapFromPage", 40f, "Gap between the storage Sort button's right edge and the left edge of the\npage counter. Raise it to slide the button left.");
			AutoLootEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("AutoLoot", "Enabled", true, "Pull dropped items toward you when you walk near them. Dropped items only —\nharvestable nodes are handled by AutoTool.");
			AutoLootRadius = ((BaseUnityPlugin)this).Config.Bind<float>("AutoLoot", "Radius", 4.5f, "Pickup radius in world units, measured horizontally.");
			AutoLootMinRarity = ((BaseUnityPlugin)this).Config.Bind<string>("AutoLoot", "MinimumRarity", "Any", "Lowest rarity to collect: Any, Common, Uncommon, Rare, Legendary.\n'Any' also picks up unrated items; the others exclude them.");
			AutoLootInterval = ((BaseUnityPlugin)this).Config.Bind<float>("AutoLoot", "ScanInterval", 0.2f, "Seconds between proximity scans. Lower is more responsive and more costly.");
			AutoLootVerbose = ((BaseUnityPlugin)this).Config.Bind<bool>("AutoLoot", "LogEachItem", false, "Log the name of every item auto-loot collects. Diagnostic only - turn this on\nif items appear in your inventory that you did not pick up, to see whether\nauto-loot is what collected them.");
			SeedInfoEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("SeedInfo", "Enabled", true, "Append grow time, regrow behaviour, yield and season to seed descriptions.\nRead from the generated PlantsData tables, not hardcoded.");
			BeltScrollEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("BeltScroll", "EnableExperimental", true, "Cycle the tool belt with Ctrl + mouse wheel. Drives the game's own belt-shift\nlogic, so empty slots are skipped and the selection wraps as usual.\nThe tool duplication reported against 0.12.1 was auto-loot collecting the\nplayer's own held-tool models, not this feature; fixed in 0.12.3.");
			BeltScrollRequireCtrl = ((BaseUnityPlugin)this).Config.Bind<bool>("BeltScroll", "RequireCtrl", true, "Hold left or right Ctrl while scrolling to cycle the belt. On by default so a\nplain scroll stays free for the third person camera's zoom.");
			BeltScrollCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("BeltScroll", "Cooldown", 0.12f, "Minimum seconds between belt steps. The belt's own selection has a settling\ndelay, and shifting faster than that stacks selection changes.");
			BeltScrollInvert = ((BaseUnityPlugin)this).Config.Bind<bool>("BeltScroll", "Invert", false, "Reverse the scroll direction.");
			BeltScrollThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("BeltScroll", "Threshold", 0.1f, "Wheel movement required per step. Mice report very different magnitudes per\nnotch, so movement is accumulated and this much is consumed per belt slot.\nRaise it if one flick skips several slots, lower it if scrolling feels sticky.");
			DialogueFastEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Dialogue", "FasterText", true, "Speed up the NPC dialogue typewriter effect.");
			DialogueSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Dialogue", "SpeedMultiplier", 2.5f, "How much faster than vanilla, 1 to 20. Text still reveals a character per\nframe at the top of that range rather than appearing all at once.");
			QuickTransferEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("QuickTransfer", "Enabled", true, "Shift + left click moves a stack between backpack and tool belt, or between\nbackpack and chest while a storage container is open.");
			SortButtonEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("SortButton", "Enabled", true, "Adds a Sort button to the backpack header row.");
			SortButtonLabel = ((BaseUnityPlugin)this).Config.Bind<string>("SortButton", "Label", "Sort", "Text on the Sort button. Not localised.");
			SortButtonGap = ((BaseUnityPlugin)this).Config.Bind<float>("SortButton", "GapFromGold", 40f, "Gap in reference pixels between the Sort button's right edge and the left\nedge of the gold counter. Raise it to slide the button toward BACKPACK.");
			SortButtonY = ((BaseUnityPlugin)this).Config.Bind<float>("SortButton", "OffsetY", 0f, "Vertical offset from the gold counter. Negative moves down.");
			SortButtonWidth = ((BaseUnityPlugin)this).Config.Bind<float>("SortButton", "Width", 130f, "Button width in reference pixels.");
			ModsTabRowPadding = ((BaseUnityPlugin)this).Config.Bind<float>("ModsTab", "RowPadding", 12f, "Vertical gap to keep between menu buttons when Compress respaces them.\nRows taller than the new spacing are trimmed to fit, so raise this if the\nbuttons still touch.");
			ModsTabPlacement = ((BaseUnityPlugin)this).Config.Bind<string>("ModsTab", "Placement", "Compress", "How the Mods button fits into the main menu:\n  Compress - respace every menu button evenly to fit one more (default)\n  Append   - place it below the lowest existing button\n  Manual   - offset from the lowest button using ButtonOffsetY");
			ModsTabEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("ModsTab", "Enabled", true, "Adds a Mods entry to the main menu listing what BepInEx has loaded.");
			ModsTabLabel = ((BaseUnityPlugin)this).Config.Bind<string>("ModsTab", "ButtonLabel", "MODS", "Text on the main menu button. Not localised.");
			ModsTabHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("ModsTab", "Hotkey", new KeyboardShortcut((KeyCode)291, Array.Empty<KeyCode>()), "Opens the mods panel from the main menu, whether or not the MODS button is\nshown. Set to None to disable.");
			ModsTabOffsetY = ((BaseUnityPlugin)this).Config.Bind<float>("ModsTab", "ButtonOffsetY", -60f, "Fallback vertical offset, in reference pixels, used only if the menu has no\nlayout group and the button spacing can't be measured from its siblings.\nNegative moves it down. Adjust if the button lands in the wrong place.");
			_harmony = new Harmony("com.community.relegend.qol");
			try
			{
				_harmony.PatchAll(typeof(SortPatches));
				_harmony.PatchAll(typeof(SellPatches));
				_harmony.PatchAll(typeof(MainMenuPatches));
				_harmony.PatchAll(typeof(SortButtonPatches));
				_harmony.PatchAll(typeof(AutoToolPatches));
				_harmony.PatchAll(typeof(StoragePatches));
				_harmony.PatchAll(typeof(QuickTransferPatches));
				_harmony.PatchAll(typeof(SeedInfoPatches));
				_harmony.PatchAll(typeof(BeltScrollPatches));
				_harmony.PatchAll(typeof(DialoguePatches));
				_harmony.PatchAll(typeof(FaceCursorPatches));
				_harmony.PatchAll(typeof(PoiMarkerPatches));
				Log.LogInfo((object)("Re:Legend QOL Pack 0.13.0 loaded. BepInEx " + typeof(BaseUnityPlugin).Assembly.GetName().Version?.ToString() + ", Harmony " + typeof(Harmony).Assembly.GetName().Version?.ToString() + "."));
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Patching failed, mod is inert: " + ex));
			}
		}

		internal static void SaveConfig()
		{
			try
			{
				((BaseUnityPlugin)Instance).Config.Save();
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Could not save config: " + ex));
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private void Update()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: 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)
			CheckModsHotkey();
			if (!SortEnabled.Value)
			{
				return;
			}
			KeyboardShortcut value = SortHotkey.Value;
			if ((int)((KeyboardShortcut)(ref value)).MainKey == 0)
			{
				return;
			}
			value = SortHotkey.Value;
			if (!((KeyboardShortcut)(ref value)).IsDown())
			{
				return;
			}
			try
			{
				Sorting.SortOpenContainer();
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Sort hotkey failed: " + ex));
			}
		}

		private void CheckModsHotkey()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if (ModsTabHotkey == null)
			{
				return;
			}
			KeyboardShortcut value = ModsTabHotkey.Value;
			if ((int)((KeyboardShortcut)(ref value)).MainKey == 0)
			{
				return;
			}
			value = ModsTabHotkey.Value;
			if (!((KeyboardShortcut)(ref value)).IsDown())
			{
				return;
			}
			try
			{
				MainMenuPatches.OpenPanel();
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Mods hotkey failed: " + ex));
			}
		}

		private void LateUpdate()
		{
			AutoLoot.Tick();
		}
	}
	internal struct PoiInfo
	{
		public string Name;

		public string Service;

		public Transform Anchor;
	}
	internal static class PoiMarkers
	{
		private const string MarkerName = "PoiMarker_QOL";

		private static readonly List<PoiInfo> Found = new List<PoiInfo>();

		private static float _nextScan;

		private static bool _loggedCameraSetup;

		internal static IList<PoiInfo> Current => Found;

		internal static void Tick()
		{
			if (!Plugin.PoiMarkersEnabled.Value || Time.unscaledTime < _nextScan)
			{
				return;
			}
			_nextScan = Time.unscaledTime + Mathf.Max(1f, Plugin.PoiScanInterval.Value);
			try
			{
				Scan();
				LogMinimapCameraSetup();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("POI scan failed: " + ex));
			}
		}

		private static void Scan()
		{
			Found.Clear();
			NPCInteractManager[] array = Object.FindObjectsOfType<NPCInteractManager>();
			if (array == null)
			{
				return;
			}
			int num = 0;
			foreach (NPCInteractManager val in array)
			{
				if ((Object)(object)val == (Object)null || val.isDisable)
				{
					continue;
				}
				string text = ServiceOf(val);
				if (text != null)
				{
					string name = (string.IsNullOrEmpty(val.NPCName) ? text : val.NPCName);
					Found.Add(new PoiInfo
					{
						Name = name,
						Service = text,
						Anchor = ((Component)val).transform
					});
					if (EnsureMarker(val))
					{
						num++;
					}
				}
			}
			if (num > 0)
			{
				Plugin.Log.LogInfo((object)("POI markers: " + Found.Count + " service NPCs found, " + num + " new marker(s) added."));
			}
		}

		private static string ServiceOf(NPCInteractManager npc)
		{
			if (npc.canShop && Plugin.PoiShops.Value)
			{
				return "Shop";
			}
			if (npc.canEnhance && Plugin.PoiServices.Value)
			{
				return "Enhance";
			}
			if (npc.canHeal && Plugin.PoiServices.Value)
			{
				return "Heal";
			}
			if (npc.canFuse && Plugin.PoiServices.Value)
			{
				return "Fuse";
			}
			if (npc.canUpgradeBuilding && Plugin.PoiServices.Value)
			{
				return "Upgrade";
			}
			if (npc.canFishRace && Plugin.PoiServices.Value)
			{
				return "Fish Race";
			}
			return null;
		}

		private static bool EnsureMarker(NPCInteractManager npc)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: 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_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			GameObject minimapIcon = npc.minimapIcon;
			if ((Object)(object)minimapIcon == (Object)null)
			{
				return false;
			}
			Transform val = minimapIcon.transform.parent;
			if ((Object)(object)val == (Object)null)
			{
				val = ((Component)npc).transform;
			}
			if ((Object)(object)val.Find("PoiMarker_QOL") != (Object)null)
			{
				return false;
			}
			GameObject val2 = Object.Instantiate<GameObject>(minimapIcon, val, false);
			((Object)val2).name = "PoiMarker_QOL";
			val2.transform.localPosition = minimapIcon.transform.localPosition;
			val2.transform.localScale = minimapIcon.transform.localScale * Mathf.Max(0.1f, Plugin.PoiMarkerScale.Value);
			val2.SetActive(true);
			Color color = TintFor(npc);
			SpriteRenderer[] componentsInChildren = val2.GetComponentsInChildren<SpriteRenderer>(true);
			foreach (SpriteRenderer val3 in componentsInChildren)
			{
				if ((Object)(object)val3 != (Object)null)
				{
					val3.color = color;
				}
			}
			MinimapIcon[] componentsInChildren2 = val2.GetComponentsInChildren<MinimapIcon>(true);
			foreach (MinimapIcon val4 in componentsInChildren2)
			{
				if ((Object)(object)val4 != (Object)null)
				{
					Object.Destroy((Object)(object)val4);
				}
			}
			return true;
		}

		private static Color TintFor(NPCInteractManager npc)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			if (npc.canShop)
			{
				return new Color(1f, 0.84f, 0.25f, 1f);
			}
			if (npc.canHeal)
			{
				return new Color(0.45f, 1f, 0.5f, 1f);
			}
			if (npc.canEnhance || npc.canFuse)
			{
				return new Color(0.55f, 0.7f, 1f, 1f);
			}
			return new Color(1f, 1f, 1f, 1f);
		}

		private static void LogMinimapCameraSetup()
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			if (_loggedCameraSetup)
			{
				return;
			}
			MinimapCamera instance = MinimapCamera.instance;
			if (!((Object)(object)instance == (Object)null))
			{
				Camera val = Reflect.Get<Camera>(typeof(MinimapCamera), "minimapCam", instance);
				if (!((Object)(object)val == (Object)null))
				{
					_loggedCameraSetup = true;
					Plugin.Log.LogInfo((object)("Minimap camera: orthographic=" + val.orthographic + " size=" + val.orthographicSize + " viewportRect=" + ((object)val.rect/*cast due to .constrained prefix*/).ToString() + " targetTexture=" + (((Object)(object)val.targetTexture == (Object)null) ? "none" : ((Object)val.targetTexture).name) + " cullingMask=" + val.cullingMask));
				}
			}
		}
	}
	internal static class Reflect
	{
		private static readonly Dictionary<string, FieldInfo> Cache = new Dictionary<string, FieldInfo>();

		private static readonly HashSet<string> Reported = new HashSet<string>();

		private static FieldInfo Find(Type type, string name)
		{
			string text = type.FullName + "::" + name;
			if (Cache.TryGetValue(text, out var value))
			{
				return value;
			}
			value = AccessTools.Field(type, name);
			Cache[text] = value;
			if (value == null && Reported.Add(text))
			{
				Plugin.Log.LogError((object)("Field not found: " + text + ". The game may have been updated."));
			}
			return value;
		}

		internal static T GetSilent<T>(Type type, string name, object instance)
		{
			try
			{
				FieldInfo fieldInfo = AccessTools.Field(type, name);
				if (fieldInfo == null)
				{
					PropertyInfo propertyInfo = AccessTools.Property(type, name);
					if (propertyInfo == null)
					{
						return default(T);
					}
					object value = propertyInfo.GetValue(instance, null);
					return (value is T) ? ((T)value) : default(T);
				}
				object value2 = fieldInfo.GetValue(instance);
				return (value2 is T) ? ((T)value2) : default(T);
			}
			catch
			{
				return default(T);
			}
		}

		internal static T Get<T>(Type type, string name, object instance)
		{
			FieldInfo fieldInfo = Find(type, name);
			if (fieldInfo == null)
			{
				return default(T);
			}
			try
			{
				object value = fieldInfo.GetValue(instance);
				return (value is T) ? ((T)value) : default(T);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Reading " + type.Name + "." + name + " failed: " + ex.Message));
				return default(T);
			}
		}

		internal static void Set(Type type, string name, object instance, object value)
		{
			FieldInfo fieldInfo = Find(type, name);
			if (fieldInfo == null)
			{
				return;
			}
			try
			{
				fieldInfo.SetValue(instance, value);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Writing " + type.Name + "." + name + " failed: " + ex.Message));
			}
		}

		internal static T GetProperty<T>(Type type, string name, object instance)
		{
			try
			{
				PropertyInfo propertyInfo = AccessTools.Property(type, name);
				if (propertyInfo == null)
				{
					return default(T);
				}
				object value = propertyInfo.GetValue(instance, null);
				return (value is T) ? ((T)value) : default(T);
			}
			catch
			{
				return default(T);
			}
		}

		internal static bool Invoke(Type type, string name, object instance)
		{
			MethodInfo methodInfo = AccessTools.Method(type, name, (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				Plugin.Log.LogError((object)("Method not found: " + type.FullName + "::" + name));
				return false;
			}
			try
			{
				methodInfo.Invoke(instance, null);
				return true;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Invoking " + type.Name + "." + name + " failed: " + ex.Message));
				return false;
			}
		}
	}
	internal enum SortKey
	{
		TYPE,
		SUBTYPE,
		RARITY,
		BIOME,
		QUANTITY,
		NAME,
		VALUE,
		ID,
		MATERIAL
	}
	internal static class SortPresets
	{
		internal static string Resolve(string preset, string custom)
		{
			return (preset ?? "").Trim().ToLowerInvariant() switch
			{
				"typerarity" => "TYPE,RARITY,NAME", 
				"materialfirst" => "MATERIAL,TYPE,RARITY,NAME", 
				"rarityfirst" => "RARITY,TYPE,NAME", 
				"alphabetical" => "NAME", 
				"value" => "VALUE,NAME", 
				"quantity" => "QUANTITY,NAME", 
				"custom" => custom, 
				_ => custom, 
			};
		}
	}
	internal struct SortTerm
	{
		public SortKey Key;

		public bool Reversed;
	}
	internal static class Sorting
	{
		private static string _cachedKeyString;

		private static List<SortTerm> _cachedTerms;

		internal static List<SortTerm> Terms()
		{
			string text = SortPresets.Resolve(Plugin.SortPreset.Value, Plugin.SortKeys.Value) ?? "";
			if (_cachedTerms != null && text == _cachedKeyString)
			{
				return _cachedTerms;
			}
			List<SortTerm> list = new List<SortTerm>();
			string[] array = text.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (text2.Length != 0)
				{
					bool flag = text2[0] == '-';
					if (flag || text2[0] == '+')
					{
						text2 = text2.Substring(1).Trim();
					}
					SortKey key;
					try
					{
						key = (SortKey)Enum.Parse(typeof(SortKey), text2, ignoreCase: true);
					}
					catch
					{
						Plugin.Log.LogWarning((object)("Unknown sort key '" + text2 + "' ignored."));
						continue;
					}
					list.Add(new SortTerm
					{
						Key = key,
						Reversed = flag
					});
				}
			}
			if (list.Count == 0)
			{
				list.Add(new SortTerm
				{
					Key = SortKey.TYPE
				});
				list.Add(new SortTerm
				{
					Key = SortKey.RARITY
				});
				list.Add(new SortTerm
				{
					Key = SortKey.NAME
				});
			}
			_cachedKeyString = text;
			_cachedTerms = list;
			return list;
		}

		internal static void Apply(InventoryManagerRework mgr, SlotType slotType)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			List<SlotScript> list = mgr.parentList(slotType);
			if (list == null || list.Count == 0)
			{
				return;
			}
			mgr.MergeAllSplitItem(list);
			List<SortTerm> terms = Terms();
			int count = list.Count;
			int[] array = new int[count];
			SlotScript[] items = (SlotScript[])(object)new SlotScript[count];
			for (int i = 0; i < count; i++)
			{
				array[i] = i;
				items[i] = list[i];
			}
			Comparison<int> comparison = delegate(int ia, int ib)
			{
				SlotScript val = items[ia];
				SlotScript val2 = items[ib];
				bool flag = IsEmpty(val);
				bool flag2 = IsEmpty(val2);
				if (flag || flag2)
				{
					if (flag && flag2)
					{
						return ia.CompareTo(ib);
					}
					if (!Plugin.SortEmptiesLast.Value)
					{
						return ia.CompareTo(ib);
					}
					if (!flag)
					{
						return -1;
					}
					return 1;
				}
				for (int j = 0; j < terms.Count; j++)
				{
					int num2 = CompareBy(terms[j].Key, val, val2);
					if (num2 != 0)
					{
						if (!terms[j].Reversed)
						{
							return num2;
						}
						return -num2;
					}
				}
				return ia.CompareTo(ib);
			};
			Array.Sort(array, comparison);
			for (int num = 0; num < count; num++)
			{
				list[num] = items[array[num]];
				list[num].SlotIndex = num;
			}
		}

		private static bool IsEmpty(SlotScript s)
		{
			if (s != null && !s.isEmpty)
			{
				return (Object)(object)s.slotItem == (Object)null;
			}
			return true;
		}

		private static int CompareBy(SortKey key, SlotScript a, SlotScript b)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Invalid comparison between Unknown and I4
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Invalid comparison between Unknown and I4
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			Item slotItem = a.slotItem;
			Item slotItem2 = b.slotItem;
			switch (key)
			{
			case SortKey.TYPE:
			{
				ref FinalClassType finalClassType = ref slotItem.finalClassType;
				object target2 = slotItem2.finalClassType;
				return ((Enum)Unsafe.As<FinalClassType, FinalClassType>(ref finalClassType)/*cast due to .constrained prefix*/).CompareTo(target2);
			}
			case SortKey.SUBTYPE:
			{
				Equipment val = (Equipment)(object)((slotItem is Equipment) ? slotItem : null);
				Equipment val2 = (Equipment)(object)((slotItem2 is Equipment) ? slotItem2 : null);
				if ((Object)(object)val != (Object)null && (Object)(object)val2 != (Object)null)
				{
					ref EquipmentType equipType = ref val.equipType;
					object target = val2.equipType;
					return ((Enum)Unsafe.As<EquipmentType, EquipmentType>(ref equipType)/*cast due to .constrained prefix*/).CompareTo(target);
				}
				return string.Compare(SafeSubType(slotItem), SafeSubType(slotItem2), StringComparison.OrdinalIgnoreCase);
			}
			case SortKey.RARITY:
				return RarityRank(slotItem2.itemRarity).CompareTo(RarityRank(slotItem.itemRarity));
			case SortKey.BIOME:
				return slotItem.biome.CompareTo(slotItem2.biome);
			case SortKey.QUANTITY:
				return b.ItemQuantity.CompareTo(a.ItemQuantity);
			case SortKey.NAME:
				return string.Compare(DisplayName(a), DisplayName(b), StringComparison.OrdinalIgnoreCase);
			case SortKey.VALUE:
				return SafePrice(slotItem2).CompareTo(SafePrice(slotItem));
			case SortKey.ID:
				return a.ItemId.CompareTo(b.ItemId);
			case SortKey.MATERIAL:
			{
				bool flag = (int)slotItem.finalClassType == 2;
				bool flag2 = (int)slotItem2.finalClassType == 2;
				if (flag == flag2)
				{
					return 0;
				}
				if (!flag)
				{
					return 1;
				}
				return -1;
			}
			default:
				return 0;
			}
		}

		private static string SafeSubType(Item i)
		{
			try
			{
				return i.GetSubType() ?? "";
			}
			catch
			{
				return "";
			}
		}

		private static float SafePrice(Item i)
		{
			try
			{
				return i.GetFinalPrice();
			}
			catch
			{
				return i.sellPrice;
			}
		}

		private static string DisplayName(SlotScript s)
		{
			if (!string.IsNullOrEmpty(s.ItemName))
			{
				return s.ItemName;
			}
			if ((Object)(object)s.slotItem != (Object)null && !string.IsNullOrEmpty(s.slotItem.itemName))
			{
				return s.slotItem.itemName;
			}
			return "";
		}

		private static int RarityRank(ItemRarity r)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected I4, but got Unknown
			return (int)r switch
			{
				3 => 3, 
				2 => 2, 
				1 => 1, 
				0 => 0, 
				_ => -1, 
			};
		}

		internal static void SortOpenContainer()
		{
			StorageWidgetRework val = Object.FindObjectOfType<StorageWidgetRework>();
			if ((Object)(object)val != (Object)null && ((Component)val).gameObject.activeInHierarchy && Reflect.Invoke(typeof(StorageWidgetRework), "Sort", val))
			{
				return;
			}
			InventoryManagerRework instance = InventoryManagerRework.instance;
			if (!((Object)(object)instance == (Object)null))
			{
				InventoryWidget inventoryUI = instance.inventoryUI;
				if ((Object)(object)inventoryUI != (Object)null && ((Component)inventoryUI).gameObject.activeInHierarchy)
				{
					inventoryUI.Sort();
				}
			}
		}
	}
}
namespace ReLegendQOL.Patches
{
	[HarmonyPatch]
	internal static class AutoToolPatches
	{
		private static float _nextAllowedSwap;

		private static SlotScript _restoreTo;

		private static bool _hasRestore;

		[HarmonyPatch(typeof(AttackPlayer), "ToolAttack")]
		[HarmonyPrefix]
		private static void ToolAttack_Prefix(AttackPlayer __instance)
		{
			if (!Plugin.AutoToolEnabled.Value)
			{
				return;
			}
			try
			{
				EquipRequiredTool(__instance);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Auto tool select failed: " + ex));
			}
		}

		private unsafe static void EquipRequiredTool(AttackPlayer attack)
		{
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Invalid comparison between Unknown and I4
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			if (attack.isAttacking || Reflect.Get<bool>(typeof(AttackPlayer), "isMining", attack) || Time.unscaledTime < _nextAllowedSwap)
			{
				return;
			}
			PlayerHandler val = Reflect.Get<PlayerHandler>(typeof(AttackPlayer), "Hero", attack);
			if ((Object)(object)val == (Object)null)
			{
				GameManager instance = GameManager.instance;
				val = (((Object)(object)instance != (Object)null) ? instance.player : null);
			}
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			CollisionPlayer collision = val.Collision;
			EquipmentPlayer equipment = val.Equipment;
			if ((Object)(object)collision == (Object)null || (Object)(object)equipment == (Object)null)
			{
				return;
			}
			List<MineObjectDetector> targetTree = collision.targetTree;
			if (targetTree == null || CountLive(targetTree) == 0)
			{
				Restore(equipment);
				return;
			}
			for (int i = 0; i < targetTree.Count; i++)
			{
				MineObjectDetector val2 = targetTree[i];
				if (!((Object)(object)val2 == (Object)null) && val2.isAlive && equipment.isCurrentlyHolding(val2.requireTool))
				{
					return;
				}
			}
			for (int j = 0; j < targetTree.Count; j++)
			{
				MineObjectDetector val3 = targetTree[j];
				if ((Object)(object)val3 == (Object)null || !val3.isAlive)
				{
					continue;
				}
				ToolType requireTool = val3.requireTool;
				if ((int)requireTool == 10)
				{
					continue;
				}
				SlotScript val4 = FindTool(requireTool);
				if (val4 == null)
				{
					continue;
				}
				InventoryManagerRework instance2 = InventoryManagerRework.instance;
				if (!((Object)(object)instance2 == (Object)null))
				{
					if (!_hasRestore)
					{
						_restoreTo = equipment.currentlyHolding;
						_hasRestore = true;
					}
					instance2.HoldThis(val4);
					_nextAllowedSwap = Time.unscaledTime + Mathf.Max(0f, Plugin.AutoToolCooldown.Value);
					Plugin.Log.LogInfo((object)("Auto-equipped " + val4.ItemName + " for " + ((object)(*(ToolType*)(&requireTool))/*cast due to .constrained prefix*/).ToString() + "."));
				}
				break;
			}
		}

		private static int CountLive(List<MineObjectDetector> nodes)
		{
			int num = 0;
			for (int i = 0; i < nodes.Count; i++)
			{
				if ((Object)(object)nodes[i] != (Object)null && nodes[i].isAlive)
				{
					num++;
				}
			}
			return num;
		}

		private static void Restore(EquipmentPlayer equipment)
		{
			if (!_hasRestore)
			{
				return;
			}
			if (!Plugin.AutoToolStow.Value)
			{
				_hasRestore = false;
				_restoreTo = null;
				return;
			}
			SlotScript val = _restoreTo;
			_restoreTo = null;
			_hasRestore = false;
			try
			{
				if (val != null && (val.isEmpty || (Object)(object)val.slotItem == (Object)null))
				{
					val = null;
				}
				if (equipment.currentlyHolding != val)
				{
					equipment.currentlyHolding = val;
					Plugin.Log.LogInfo((object)((val == null) ? "Auto-stowed the tool." : ("Restored " + val.ItemName + " to hand.")));
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not restore the previous held item: " + ex.Message));
			}
		}

		private static SlotScript FindTool(ToolType required)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			InventoryManagerRework instance = InventoryManagerRework.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return null;
			}
			SlotScript val = ScanFor(instance.parentList((SlotType)2), required);
			if (val != null)
			{
				return val;
			}
			if (Plugin.AutoToolSearchBackpack.Value)
			{
				val = ScanFor(instance.parentList((SlotType)1), required);
			}
			return val;
		}

		private static SlotScript ScanFor(List<SlotScript> slots, ToolType required)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			if (slots == null)
			{
				return null;
			}
			for (int i = 0; i < slots.Count; i++)
			{
				SlotScript val = slots[i];
				if (val != null && !val.isEmpty && !((Object)(object)val.slotItem == (Object)null))
				{
					Item slotItem = val.slotItem;
					ToolItem val2 = (ToolItem)(object)((slotItem is ToolItem) ? slotItem : null);
					if (!((Object)(object)val2 == (Object)null) && val2.toolType == required)
					{
						return val;
					}
				}
			}
			return null;
		}
	}
	[HarmonyPatch]
	internal static class BeltScrollPatches
	{
		private enum MethodResult
		{
			True,
			False,
			Missing
		}

		private static float _accumulated;

		private static int _handledFrame = -1;

		private static float _nextAllowed;

		[HarmonyPatch(typeof(BeltWidget), "Update")]
		[HarmonyPostfix]
		private static void Update_Postfix(BeltWidget __instance)
		{
			if (!Plugin.BeltScrollEnabled.Value)
			{
				return;
			}
			try
			{
				Cycle(__instance);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Belt scroll failed: " + ex));
			}
		}

		private static void Cycle(BeltWidget widget)
		{
			if (_handledFrame == Time.frameCount)
			{
				return;
			}
			if (IsBlocked(widget))
			{
				_accumulated = 0f;
				return;
			}
			if (Plugin.BeltScrollRequireCtrl.Value && !Input.GetKey((KeyCode)306) && !Input.GetKey((KeyCode)305))
			{
				_accumulated = 0f;
				return;
			}
			float axisRaw = Input.GetAxisRaw("Mouse ScrollWheel");
			if (Mathf.Approximately(axisRaw, 0f) || Time.unscaledTime < _nextAllowed)
			{
				return;
			}
			_accumulated += axisRaw;
			float num = Mathf.Max(0.01f, Plugin.BeltScrollThreshold.Value);
			if (!(Mathf.Abs(_accumulated) < num))
			{
				bool flag = _accumulated > 0f;
				if (Plugin.BeltScrollInvert.Value)
				{
					flag = !flag;
				}
				_accumulated = 0f;
				_handledFrame = Time.frameCount;
				_nextAllowed = Time.unscaledTime + Mathf.Max(0f, Plugin.BeltScrollCooldown.Value);
				Reflect.Invoke(typeof(BeltWidget), flag ? "ShiftSelectedRight" : "ShiftSelectedLeft", widget);
			}
		}

		private static bool IsBlocked(BeltWidget widget)
		{
			try
			{
				if (Reflect.Get<bool>(typeof(BeltWidget), "toDisableInput", widget))
				{
					return true;
				}
				MainUI instance = MainUI.instance;
				if ((Object)(object)instance == (Object)null || instance.ConditionChecking())
				{
					return true;
				}
				MethodResult methodResult = Invoke(widget, "ConditionCheck");
				if (methodResult == MethodResult.Missing)
				{
					return false;
				}
				return methodResult == MethodResult.True;
			}
			catch
			{
				return true;
			}
		}

		private static MethodResult Invoke(BeltWidget widget, string name)
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(BeltWidget), name, (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				return MethodResult.Missing;
			}
			object obj = methodInfo.Invoke(widget, null);
			if (!(obj is bool))
			{
				return MethodResult.Missing;
			}
			if (!(bool)obj)
			{
				return MethodResult.False;
			}
			return MethodResult.True;
		}
	}
	[HarmonyPatch]
	internal static class DialoguePatches
	{
		[HarmonyPatch(typeof(NPCChatManager), "DisplayTextWithTimeDelay")]
		[HarmonyPrefix]
		private static void DisplayTextWithTimeDelay_Prefix(ref float _delayTime)
		{
			if (!Plugin.DialogueFastEnabled.Value)
			{
				return;
			}
			try
			{
				float num = Mathf.Clamp(Plugin.DialogueSpeed.Value, 1f, 20f);
				_delayTime /= num;
				if (_delayTime < 0f)
				{
					_delayTime = 0f;
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Dialogue speed failed: " + ex));
			}
		}
	}
	[HarmonyPatch]
	internal static class FaceCursorPatches
	{
		private static Camera _camera;

		[HarmonyPatch(typeof(AttackPlayer), "LeftAttack")]
		[HarmonyPrefix]
		private static void LeftAttack_Prefix(AttackPlayer __instance)
		{
			TryFace(__instance);
		}

		[HarmonyPatch(typeof(AttackPlayer), "RightAttack")]
		[HarmonyPrefix]
		private static void RightAttack_Prefix(AttackPlayer __instance)
		{
			TryFace(__instance);
		}

		[HarmonyPatch(typeof(MovementPlayer), "MovementDirection")]
		[HarmonyPostfix]
		private static void MovementDirection_Postfix()
		{
			if (!(Mode() != "always") && ShouldFaceContinuously())
			{
				GameManager instance = GameManager.instance;
				PlayerHandler val = (((Object)(object)instance != (Object)null) ? instance.player : null);
				if ((Object)(object)val != (Object)null)
				{
					Face(val);
				}
			}
		}

		private static string Mode()
		{
			string value = Plugin.FaceCursorMode.Value;
			if (!string.IsNullOrEmpty(value))
			{
				return value.Trim().ToLowerInvariant();
			}
			return "whileattacking";
		}

		private static bool ShouldFaceContinuously()
		{
			if (!Plugin.FaceCursorFreezeWhileOrbiting.Value)
			{
				return true;
			}
			return !Input.GetMouseButton(1);
		}

		private static void TryFace(AttackPlayer attack)
		{
			if (Mode() == "never")
			{
				return;
			}
			try
			{
				PlayerHandler val = Reflect.Get<PlayerHandler>(typeof(AttackPlayer), "Hero", attack);
				if ((Object)(object)val == (Object)null)
				{
					GameManager instance = GameManager.instance;
					val = (((Object)(object)instance != (Object)null) ? instance.player : null);
				}
				if (!((Object)(object)val == (Object)null))
				{
					Face(val);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Face-cursor failed: " + ex));
			}
		}

		private static void Face(PlayerHandler hero)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (ShouldFace(hero) && AimDirection(hero, out var flat))
			{
				((Component)hero).t