Decompiled source of ConfigForge v1.0.1

ConfigForge.dll

Decompiled 10 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using AskaConfigForge.Core;
using AskaShared.Game;
using AskaShared.UI;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using Fusion;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.Reflection;
using Microsoft.CodeAnalysis;
using SSSGame;
using SSSGame.UI;
using SandSailorStudio.Game;
using SandSailorStudio.Localization;
using SandSailorStudio.UI;
using SandSailorStudio.WorldGen;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.UI;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("ConfigForge")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1")]
[assembly: AssemblyInformationalVersion("1.0.1+48a86bd2e0d0ea8a6bc56ef1163f7c4fe4e9bf61")]
[assembly: AssemblyProduct("Config Forge")]
[assembly: AssemblyTitle("ConfigForge")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.1.0")]
[module: UnverifiableCode]
[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;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte flag)
		{
			Flag = flag;
		}
	}
}
namespace AskaConfigForge
{
	[HarmonyPatch(typeof(TMP_InputField), "OnCancel")]
	internal static class CancelGuard
	{
		private static bool Prefix(TMP_InputField __instance, BaseEventData eventData)
		{
			if (!TextEntry.IsEditing(__instance))
			{
				return true;
			}
			if (eventData != null)
			{
				((AbstractEventData)eventData).Use();
			}
			return false;
		}
	}
	[HarmonyPatch]
	internal static class ConfigForgeLeaveHold
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(TabGroup), "TabSelect")]
		private static bool TabSelecting(TabGroup __instance, TabButton button)
		{
			return ConfigForgeTab.AllowTabSelect(__instance, button);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(MenuManager), "CloseMenu")]
		private static bool MenuClosing(Menu menu)
		{
			return ConfigForgeTab.AllowMenuClose(menu);
		}
	}
	[HarmonyPatch]
	internal static class ConfigForgeTab
	{
		internal const string ButtonName = "ConfigForge_ModSettingsTab";

		private const string PageName = "ConfigForge_ModSettingsPage";

		private static bool _failed;

		private static bool _templateLogged;

		private static bool _toggleFailed;

		private static bool _contentFailed;

		private static TabPage _page;

		private static TabGroupControls _strip;

		private static TabButton _tab;

		private static ModSettingsContent _content;

		private static GameObject _frameSelected;

		private static GameObject[] _hiddenWhileShown;

		private static bool[] _turnedOff;

		private const float LeaveApprovalSeconds = 3f;

		private static float _leaveApprovedUntil = float.NegativeInfinity;

		internal static bool IsShowing
		{
			get
			{
				if (_content != null)
				{
					return _content.IsActive;
				}
				return false;
			}
		}

		private static bool LeaveApproved => Time.unscaledTime < _leaveApprovedUntil;

		[HarmonyPostfix]
		[HarmonyPatch(typeof(SettingsMenu), "Start")]
		private static void SettingsMenuStarted(SettingsMenu __instance)
		{
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			_content = null;
			_leaveApprovedUntil = float.NegativeInfinity;
			_strip = null;
			_tab = null;
			if (_failed || _toggleFailed)
			{
				return;
			}
			GameObject page = null;
			GameObject button = null;
			try
			{
				Add(__instance, ref page, ref button);
			}
			catch (Exception ex)
			{
				_failed = true;
				_page = null;
				_strip = null;
				_tab = null;
				_frameSelected = null;
				_hiddenWhileShown = null;
				if ((Object)(object)button != (Object)null)
				{
					Object.DestroyImmediate((Object)(object)button);
				}
				if ((Object)(object)page != (Object)null)
				{
					Object.DestroyImmediate((Object)(object)page);
				}
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(91, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("The Config Forge tab could not be built; the settings page shows only the game's own tabs: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogError(val);
			}
		}

		internal static void Tick()
		{
			_content?.Tick();
		}

		internal static bool AllowTabSelect(TabGroup group, TabButton target)
		{
			if (LeaveApproved || (Object)(object)_strip == (Object)null || (Object)(object)_tab == (Object)null || ((Il2CppObjectBase)group).Pointer != ((Il2CppObjectBase)_strip).Pointer)
			{
				return true;
			}
			if ((Object)(object)target != (Object)null && ((Il2CppObjectBase)target).Pointer == ((Il2CppObjectBase)_tab).Pointer)
			{
				return true;
			}
			if (!HoldsStagedChanges())
			{
				return true;
			}
			Hold("tab switch", delegate
			{
				((TabGroup)_strip).TabSelect(target);
			});
			return false;
		}

		internal static bool AllowMenuClose(Menu menu)
		{
			if (LeaveApproved || (Object)(object)menu == (Object)null || (Object)(object)((Il2CppObjectBase)menu).TryCast<SettingsMenu>() == (Object)null || !HoldsStagedChanges())
			{
				return true;
			}
			Hold("menu close", delegate
			{
				MenuManager.Instance.CloseMenu(menu);
			});
			return false;
		}

		private static bool HoldsStagedChanges()
		{
			if (_content != null && (Object)(object)_page != (Object)null && ((Component)_page).gameObject.activeInHierarchy)
			{
				return _content.LeaveWouldAsk;
			}
			return false;
		}

		private static void Hold(string what, Action leave)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			if (KitConfirmDialog.IsOpen)
			{
				return;
			}
			ManualLogSource log = Plugin.Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(65, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("A ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(what);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" away from the Config Forge tab is held for its staged changes.");
			}
			log.LogInfo(val);
			try
			{
				_content.LeavePageThen(approvedLeave);
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Plugin.Log;
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(60, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("The discard dialog could not open, so the leave goes ahead: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
				}
				log2.LogError(val2);
				approvedLeave();
			}
			void approvedLeave()
			{
				_leaveApprovedUntil = Time.unscaledTime + 3f;
				leave();
			}
		}

		internal static bool Escape()
		{
			if (!TakeBack())
			{
				return false;
			}
			EscapeOwner.OwnEscapePress();
			return true;
		}

		internal static bool TakeBack()
		{
			if (_content == null || !_content.IsActive)
			{
				return false;
			}
			bool flag = TextEntry.IsBlockingInput || KeyCapture.IsBlockingInput;
			bool flag2 = flag && !TextEntry.IsEditingAny && !KeyCapture.IsCapturing;
			switch (EscapeLayers.Decide(settingsOpen: true, _content.PickerOpen && !flag2, flag, _content.OnModPage))
			{
			case EscapeStep.CancelPicker:
			case EscapeStep.ReturnToList:
				_content.Back();
				break;
			case EscapeStep.EndEdit:
				if (KeyCapture.IsCapturing)
				{
					KeyCapture.Cancel();
				}
				else
				{
					TextEntry.Cancel();
				}
				break;
			default:
				return false;
			}
			return true;
		}

		internal static bool PadMove(Selectable control, bool right)
		{
			if (IsShowing)
			{
				return _content.PadMove(control, right);
			}
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(TabPage), "Show")]
		private static void PageShowing(TabPage __instance, bool value)
		{
			if (!value || (Object)(object)_page == (Object)null || ((Il2CppObjectBase)__instance).Pointer != ((Il2CppObjectBase)_page).Pointer || _content != null || _contentFailed)
			{
				return;
			}
			try
			{
				ModSettingsContent modSettingsContent = new ModSettingsContent();
				RectTransform component = ((Component)_page).GetComponent<RectTransform>();
				modSettingsContent.Build(aboveSortingOrder: ((Component)component).GetComponentInParent<Canvas>(true).rootCanvas.sortingOrder, area: component, settingsMenu: ModSettingsContent.FindSettingsMenu());
				_content = modSettingsContent;
			}
			catch (Exception e)
			{
				DropContent("built", e);
			}
		}

		private static void DropContent(string what, Exception e)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			_contentFailed = true;
			_content = null;
			RectTransform component = ((Component)_page).GetComponent<RectTransform>();
			for (int num = ((Transform)component).childCount - 1; num >= 0; num--)
			{
				Object.DestroyImmediate((Object)(object)((Component)((Transform)component).GetChild(num)).gameObject);
			}
			ManualLogSource log = Plugin.Log;
			bool flag = default(bool);
			BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(72, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("The Config Forge tab's content could not be ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(what);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("; the tab page stays empty: ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(e);
			}
			log.LogError(val);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(TabPage), "Show")]
		private static void PageShown(TabPage __instance, bool value)
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Expected O, but got Unknown
			if ((Object)(object)_page == (Object)null || ((Il2CppObjectBase)__instance).Pointer != ((Il2CppObjectBase)_page).Pointer)
			{
				return;
			}
			if (!value)
			{
				_leaveApprovedUntil = float.NegativeInfinity;
			}
			if (!_toggleFailed)
			{
				try
				{
					if ((Object)(object)_frameSelected != (Object)null)
					{
						_frameSelected.SetActive(value);
					}
					if (value)
					{
						HideForeignParts();
					}
					else
					{
						RestoreForeignParts();
					}
				}
				catch (Exception ex)
				{
					_toggleFailed = true;
					RestoreEachBestEffort();
					ManualLogSource log = Plugin.Log;
					bool flag = default(bool);
					BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(121, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("The Config Forge tab's selected frame, or the game's Apply, Discard, Reset and seed panel, could not be shown or hidden: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
					}
					log.LogError(val);
				}
			}
			ShowContent(value);
		}

		private static void ShowContent(bool value)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected O, but got Unknown
			if (_content == null)
			{
				return;
			}
			bool flag = default(bool);
			if (!value)
			{
				try
				{
					_content.Hide();
					return;
				}
				catch (Exception ex)
				{
					ManualLogSource log = Plugin.Log;
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(60, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("The Config Forge tab's content could not be hidden cleanly: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
					}
					log.LogWarning(val);
					return;
				}
			}
			try
			{
				ManualLogSource log2 = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(36, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("The Config Forge tab shown: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(_content.Enter());
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" plates.");
				}
				log2.LogInfo(val2);
			}
			catch (Exception e)
			{
				DropContent("shown", e);
			}
		}

		private static void Add(SettingsMenu menu, ref GameObject page, ref GameObject button)
		{
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Expected O, but got Unknown
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Expected O, but got Unknown
			TabGroupControls strip = menu.MainTabGroup ?? throw new InvalidOperationException("SettingsMenu.MainTabGroup, the tab strip, is not set.");
			TabButton[] source = ((IEnumerable<TabButton>)((Component)strip).GetComponentsInChildren<TabButton>(true)).Where((TabButton b) => (Object)(object)b.group != (Object)null && ((Il2CppObjectBase)b.group).Pointer == ((Il2CppObjectBase)strip).Pointer).ToArray();
			TabButton val = ((IEnumerable<TabButton>)source).FirstOrDefault((Func<TabButton, bool>)((TabButton b) => ((Object)b).name == "ConfigForge_ModSettingsTab"));
			if ((Object)(object)val != (Object)null)
			{
				_strip = strip;
				_tab = val;
				return;
			}
			TabButton[] source2 = (from b in source
				where (Object)(object)b.page != (Object)null && (Object)(object)((Il2CppObjectBase)b.page).TryCast<SettingsTabPage>() != (Object)null
				orderby b.order
				select b).ToArray();
			TabButton val2 = ((IEnumerable<TabButton>)source2).FirstOrDefault((Func<TabButton, bool>)((TabButton b) => (Object)(object)((Il2CppObjectBase)b.page).TryCast<GameplaySettingsTabPage>() != (Object)null)) ?? source2.FirstOrDefault() ?? throw new InvalidOperationException("The tab strip '" + ((Object)strip).name + "' holds no tab bound to a SettingsTabPage to clone.");
			if (!_templateLogged)
			{
				_templateLogged = true;
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(49, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("The Config Forge tab is cloned from '");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(((Object)val2).name);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("' (page '");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(((Object)val2.page).name);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("').");
				}
				log.LogInfo(val3);
			}
			TabPage page2 = val2.page;
			SettingsTabPage val4 = ((Il2CppObjectBase)page2).TryCast<SettingsTabPage>();
			GameObject[] obj = new GameObject[4]
			{
				SharedButton(val4.applyButton, "applyButton"),
				SharedButton(val4.discardButton, "discardButton"),
				SharedButton(val4.resetButton, "resetButton"),
				default(GameObject)
			};
			RectTransform seedPanel = menu.seedPanel;
			obj[3] = ((seedPanel != null) ? ((Component)seedPanel).gameObject : null);
			GameObject[] hiddenWhileShown = ((IEnumerable<GameObject>)(object)obj).Where((GameObject o) => (Object)(object)o != (Object)null).ToArray();
			Sprite modsTabGlyph = MedallionArt.ModsTabGlyph;
			string overrideDetails = ModStrings.Get("tab.mod_settings");
			page = new GameObject("ConfigForge_ModSettingsPage");
			page.SetActive(false);
			RectTransform obj2 = page.AddComponent<RectTransform>();
			Transform transform = ((Component)page2).transform;
			((Transform)obj2).SetParent(transform.parent, false);
			((Transform)obj2).SetSiblingIndex(transform.GetSiblingIndex() + 1);
			UiParts.Stretch(obj2);
			TabPage val5 = page.AddComponent<TabPage>();
			val5.AutoPosition = false;
			button = Object.Instantiate<GameObject>(((Component)val2).gameObject, ((Component)val2).transform.parent, false);
			((Object)button).name = "ConfigForge_ModSettingsTab";
			button.transform.SetSiblingIndex(source.Max((TabButton b) => ((Component)b).transform.GetSiblingIndex()) + 1);
			TabButton val6 = ((IEnumerable<TabButton>)button.GetComponents<TabButton>()).FirstOrDefault((Func<TabButton, bool>)((TabButton b) => (Object)(object)b.group != (Object)null && ((Il2CppObjectBase)b.group).Pointer == ((Il2CppObjectBase)strip).Pointer)) ?? throw new InvalidOperationException("The cloned tab has no TabButton on the strip.");
			val6.page = val5;
			int num = source.Max((TabButton b) => b.order);
			if (((TabGroup)strip).buttons != null)
			{
				Enumerator<TabButton> enumerator = ((TabGroup)strip).buttons.GetEnumerator();
				while (enumerator.MoveNext())
				{
					TabButton current = enumerator.Current;
					if ((Object)(object)current != (Object)null)
					{
						num = Math.Max(num, current.order);
					}
				}
			}
			val6.order = num + 1;
			val6.selected = false;
			TabButtonTooltip obj3 = button.GetComponent<TabButtonTooltip>() ?? throw new InvalidOperationException("The cloned tab has no TabButtonTooltip.");
			((TabButton)obj3).selected = false;
			obj3.OverrideDetails = overrideDetails;
			string[] array = new string[3] { "Icon", "Icon/Icon_Selected", "Icon_Shadow" };
			foreach (string text in array)
			{
				Image obj4 = ((Component)UiParts.Child(button.transform, text)).GetComponent<Image>() ?? throw new InvalidOperationException("The cloned tab's '" + text + "' has no Image.");
				obj4.sprite = modsTabGlyph;
				obj4.preserveAspect = true;
			}
			GameObject gameObject = ((Component)UiParts.Child(button.transform, "Frame_Selected")).gameObject;
			gameObject.SetActive(false);
			_page = val5;
			_strip = strip;
			_tab = val6;
			_frameSelected = gameObject;
			_hiddenWhileShown = hiddenWhileShown;
			_turnedOff = null;
			Plugin.Log.LogInfo((object)"The Config Forge tab added to the settings page.");
		}

		private static GameObject SharedButton(Button button, string field)
		{
			return ((button != null) ? ((Component)button).gameObject : null) ?? throw new InvalidOperationException("SettingsTabPage." + field + " is not set.");
		}

		private static void HideForeignParts()
		{
			if (_turnedOff == null && _hiddenWhileShown != null)
			{
				_turnedOff = new bool[_hiddenWhileShown.Length];
				for (int i = 0; i < _hiddenWhileShown.Length; i++)
				{
					TurnOffIfActive(i);
				}
			}
		}

		internal static void HoldForeignPartsHidden()
		{
			if (_turnedOff != null && _hiddenWhileShown != null)
			{
				for (int i = 0; i < _hiddenWhileShown.Length; i++)
				{
					TurnOffIfActive(i);
				}
			}
		}

		private static bool TurnOffIfActive(int i)
		{
			GameObject val = _hiddenWhileShown[i];
			if ((Object)(object)val == (Object)null || !val.activeSelf)
			{
				return false;
			}
			_turnedOff[i] = true;
			val.SetActive(false);
			return true;
		}

		private static void RestoreForeignParts()
		{
			if (_turnedOff != null && _hiddenWhileShown != null)
			{
				for (int i = 0; i < _hiddenWhileShown.Length; i++)
				{
					RestorePart(i);
				}
				_turnedOff = null;
			}
		}

		private static void RestorePart(int i)
		{
			GameObject val = _hiddenWhileShown[i];
			if (_turnedOff[i] && (Object)(object)val != (Object)null && !val.activeSelf)
			{
				val.SetActive(true);
			}
		}

		private static void RestoreEachBestEffort()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			if (_turnedOff == null || _hiddenWhileShown == null)
			{
				return;
			}
			bool flag = default(bool);
			for (int i = 0; i < _hiddenWhileShown.Length; i++)
			{
				try
				{
					RestorePart(i);
				}
				catch (Exception ex)
				{
					ManualLogSource log = Plugin.Log;
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(61, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("A part hidden on the Config Forge tab could not be restored: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
					}
					log.LogWarning(val);
				}
			}
			_turnedOff = null;
		}
	}
	public class ConfigForgeTool : MonoBehaviour
	{
		private void Update()
		{
			EscapeOwner.TrackEscape();
			KeyCapture.TrackClick();
			PadInput.Tick();
			if (!KitConfirmDialog.IsBlockingInput)
			{
				if (Input.GetKeyDown((KeyCode)27) && ConfigForgeTab.Escape())
				{
					ConfigForgeTab.Tick();
				}
				else if (KeyCapture.IsBlockingInput)
				{
					KeyCapture.Tick();
				}
				else if (!TextEntry.IsBlockingInput)
				{
					ConfigForgeTab.Tick();
				}
			}
		}

		private void LateUpdate()
		{
			ConfigForgeTab.HoldForeignPartsHidden();
		}
	}
	internal static class ConfigWriter
	{
		private sealed class Store : IConfigStore
		{
			private static readonly PropertyInfo OrphanedEntriesProperty = typeof(ConfigFile).GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.NonPublic);

			private readonly ConfigFile _config;

			public Store(ConfigFile config)
			{
				_config = config;
			}

			public string GetSerializedValue(string section, string key)
			{
				return Entry(section, key).GetSerializedValue();
			}

			public void SetSerializedValue(string section, string key, string value)
			{
				Entry(section, key).SetSerializedValue(value);
			}

			public void Save()
			{
				_config.Save();
			}

			public void Reload()
			{
				Dictionary<ConfigDefinition, string> dictionary = (Dictionary<ConfigDefinition, string>)(OrphanedEntriesProperty?.GetValue(_config) ?? throw new InvalidOperationException("BepInEx's ConfigFile has no OrphanedEntries to keep if the reload fails, so it was not reloaded"));
				Dictionary<ConfigDefinition, string> dictionary2 = new Dictionary<ConfigDefinition, string>(dictionary);
				try
				{
					_config.Reload();
				}
				catch
				{
					dictionary.Clear();
					foreach (KeyValuePair<ConfigDefinition, string> item in dictionary2)
					{
						dictionary[item.Key] = item.Value;
					}
					throw;
				}
			}

			private ConfigEntryBase Entry(string section, string key)
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_0012: Expected O, but got Unknown
				return _config[new ConfigDefinition(section, key)];
			}
		}

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

		public static IReadOnlyList<StagedChange> Write(ConfigFileChanges file)
		{
			ConfigFile val = ModDiscovery.FileOf(file.ConfigFileId);
			bool saveOnConfigSet = val.SaveOnConfigSet;
			val.SaveOnConfigSet = false;
			try
			{
				return ConfigWrite.Write(file.PluginGuid, new Store(val), file.Changes, delegate(string failure, Exception e)
				{
					//IL_0009: Unknown result type (might be due to invalid IL or missing references)
					//IL_000f: Expected O, but got Unknown
					ManualLogSource log = Plugin.Log;
					bool flag = default(bool);
					BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(2, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(failure);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(": ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(e);
					}
					log.LogError(val2);
				}, delegate(string failure, Exception e)
				{
					//IL_0009: Unknown result type (might be due to invalid IL or missing references)
					//IL_000f: Expected O, but got Unknown
					ManualLogSource log = Plugin.Log;
					bool flag = default(bool);
					BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(2, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(failure);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(": ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(e);
					}
					log.LogWarning(val2);
				});
			}
			finally
			{
				val.SaveOnConfigSet = saveOnConfigSet;
			}
		}

		public static ReloadResult ReloadAll(ModCatalog catalog)
		{
			List<ConfigFile> list = ModDiscovery.ConfigFiles().ToList();
			List<bool> list2 = list.Select((ConfigFile file) => file.SaveOnConfigSet).ToList();
			foreach (ConfigFile item in list)
			{
				item.SaveOnConfigSet = false;
			}
			try
			{
				return ConfigReload.Run(catalog, StoreOnDisk, delegate(string failure, Exception e)
				{
					//IL_0009: Unknown result type (might be due to invalid IL or missing references)
					//IL_000f: Expected O, but got Unknown
					ManualLogSource log = Plugin.Log;
					bool flag = default(bool);
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(2, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(failure);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(e);
					}
					log.LogWarning(val);
				});
			}
			finally
			{
				for (int num = 0; num < list.Count; num++)
				{
					list[num].SaveOnConfigSet = list2[num];
				}
			}
		}

		private static IConfigStore StoreOnDisk(string configFileId)
		{
			ConfigFile val = ModDiscovery.FileOf(configFileId);
			if (!File.Exists(val.ConfigFilePath))
			{
				return null;
			}
			return new Store(val);
		}

		public static bool Takes(SettingRow row, string text)
		{
			return ModDiscovery.ConverterKeeps(EntryOf(row).SettingType, text);
		}

		public static string Canonical(SettingRow row, string text)
		{
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Expected O, but got Unknown
			try
			{
				ConfigEntryBase val = EntryOf(row);
				object value;
				string text2 = ModDiscovery.RoundTrip(val.SettingType, text, out value);
				if (ModDiscovery.RoundTrip(val.SettingType, text2, out object value2) != text2)
				{
					return null;
				}
				return ModDiscovery.Allows(val, value2) ? text2 : null;
			}
			catch (Exception ex)
			{
				if (RefusalsLogged.Add($"{row.ConfigFileId}/{row.Section}/{row.Key}"))
				{
					ManualLogSource log = Plugin.Log;
					bool flag = default(bool);
					BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(17, 5, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(row.PluginGuid);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" '");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(row.Section);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(".");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(row.Key);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' refused \"");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(text);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("\": ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
					}
					log.LogWarning(val2);
				}
				return null;
			}
		}

		private static ConfigEntryBase EntryOf(SettingRow row)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			return ModDiscovery.FileOf(row.ConfigFileId)[new ConfigDefinition(row.Section, row.Key)];
		}
	}
	internal sealed class CustomTabs
	{
		private static readonly Dictionary<(string Dll, string Tab), bool> Held = new Dictionary<(string, string), bool>();

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

		private readonly Dictionary<string, TabButton> _buttons;

		public IReadOnlyDictionary<string, string> ByPlugin { get; }

		private CustomTabs(IReadOnlyDictionary<string, string> byPlugin, Dictionary<string, TabButton> buttons)
		{
			ByPlugin = byPlugin;
			_buttons = buttons;
		}

		public TabButton Button(string tabName)
		{
			return _buttons[tabName];
		}

		public static CustomTabs Read(TabGroup strip, IReadOnlyCollection<string> ownTabs)
		{
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected O, but got Unknown
			Dictionary<string, TabButton> dictionary = new Dictionary<string, TabButton>();
			try
			{
				List<string> list = new List<string>();
				if (strip.buttons != null)
				{
					Enumerator<TabButton> enumerator = strip.buttons.GetEnumerator();
					while (enumerator.MoveNext())
					{
						TabButton current = enumerator.Current;
						if (dictionary.TryAdd(((Object)current).name, current))
						{
							list.Add(((Object)current).name);
						}
					}
				}
				List<TabPatcher> list2 = Patchers();
				Dictionary<string, byte[]> bytes = new Dictionary<string, byte[]>();
				IReadOnlyDictionary<string, string> byPlugin = CustomTabRule.Match(list2, list, ownTabs, (string dll, string tab) => Holds(dll, tab, bytes));
				foreach (TabPatcher item in list2)
				{
					LogOnce(item, byPlugin);
				}
				return new CustomTabs(byPlugin, dictionary);
			}
			catch (Exception ex)
			{
				if (Logged.Add("failed"))
				{
					ManualLogSource log = Plugin.Log;
					bool flag = default(bool);
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(82, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("The custom settings tabs could not be read, so every mod keeps its regular plate: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
					}
					log.LogWarning(val);
				}
				return new CustomTabs(new Dictionary<string, string>(), dictionary);
			}
		}

		private static List<TabPatcher> Patchers()
		{
			MethodBase methodBase = Harmony.GetAllPatchedMethods().FirstOrDefault((MethodBase method) => method.DeclaringType == typeof(SettingsMenu) && method.Name == "Start");
			Patches val = ((methodBase == null) ? null : Harmony.GetPatchInfo(methodBase));
			if (val == null)
			{
				return new List<TabPatcher>();
			}
			Assembly own = typeof(CustomTabs).Assembly;
			ILookup<Assembly, PluginInfo> pluginsOf = ((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins.Values.Where((PluginInfo info) => info.Instance != null && !string.IsNullOrEmpty(info.Location)).ToLookup((PluginInfo info) => info.Instance.GetType().Assembly);
			return (from assembly in (from patch in val.Prefixes.Concat(val.Postfixes).Concat(val.Transpilers).Concat(val.Finalizers)
						.Concat(val.ILManipulators)
					select patch.PatchMethod?.DeclaringType?.Assembly into assembly
					where assembly != null && assembly != own
					select assembly).Distinct().ToList().Where(pluginsOf.Contains)
				select new TabPatcher(pluginsOf[assembly].First().Location, pluginsOf[assembly].Select((PluginInfo info) => info.Metadata.GUID).ToList())).ToList();
		}

		private static bool Holds(string dll, string tab, Dictionary<string, byte[]> bytes)
		{
			if (Held.TryGetValue((dll, tab), out var value))
			{
				return value;
			}
			if (!bytes.TryGetValue(dll, out byte[] value2))
			{
				value2 = (bytes[dll] = File.ReadAllBytes(dll));
			}
			return Held[(dll, tab)] = DllText.Holds(value2, tab);
		}

		private static void LogOnce(TabPatcher patcher, IReadOnlyDictionary<string, string> byPlugin)
		{
			string text = string.Join(", ", patcher.PluginGuids);
			string value;
			string text2 = (byPlugin.TryGetValue(patcher.PluginGuids[0], out value) ? $"Custom settings tab '{value}' belongs to {text}." : (text + " patches the settings page, and no tab on the strip is its own."));
			if (Logged.Add(text2))
			{
				Plugin.Log.LogInfo((object)text2);
			}
		}
	}
	[HarmonyPatch(typeof(TMP_InputField), "OnPointerDown")]
	internal static class DoubleClickSelect
	{
		private static void Prefix(TMP_InputField __instance, out bool __state)
		{
			__state = __instance.m_AllowInput && __instance.m_PointerDownClickStartTime + __instance.m_DoubleClickDelay > Time.unscaledTime;
		}

		private static void Postfix(TMP_InputField __instance, bool __state)
		{
			if (__state && TextEntry.IsEditing(__instance))
			{
				int length = __instance.text.Length;
				__instance.selectionAnchorPosition = 0;
				__instance.selectionFocusPosition = length;
				__instance.selectionStringAnchorPosition = 0;
				__instance.selectionStringFocusPosition = length;
				__instance.ForceLabelUpdate();
			}
		}
	}
	internal sealed class EntryFacts
	{
		private sealed class HeldScan
		{
			private const int MaxDepth = 3;

			private readonly Assembly _assembly;

			private readonly List<Type> _types;

			private readonly HashSet<Type> _holders;

			private readonly HashSet<object> _held = new HashSet<object>(ReferenceEqualityComparer.Instance);

			private readonly HashSet<object> _visited = new HashSet<object>(ReferenceEqualityComparer.Instance);

			private readonly HashSet<ConfigFile> _configFileSet = new HashSet<ConfigFile>(ReferenceEqualityComparer.Instance);

			internal List<ConfigFile> ConfigFiles { get; } = new List<ConfigFile>();

			internal HeldScan(Assembly assembly)
			{
				_assembly = assembly;
				_types = (from type in assembly.GetTypes()
					where !type.ContainsGenericParameters
					select type).ToList();
				_holders = new HashSet<Type>();
				bool flag;
				do
				{
					flag = false;
					foreach (Type item in _types.Where((Type type) => !_holders.Contains(type) && type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).Any((FieldInfo field) => CanHold(field.FieldType))).ToList())
					{
						flag |= _holders.Add(item);
					}
				}
				while (flag);
			}

			internal HashSet<object> EntriesHeldBy(object instance)
			{
				Expand(instance, 0);
				foreach (Type type in _types)
				{
					foreach (FieldInfo item in from field in type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
						where field.IsStatic
						select field)
					{
						Follow(item, null, 0);
					}
				}
				return _held;
			}

			private void Expand(object owner, int depth)
			{
				Type type = owner.GetType();
				while (type != null && type.Assembly == _assembly)
				{
					foreach (FieldInfo item in from field in type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
						where !field.IsStatic
						select field)
					{
						Follow(item, owner, depth);
					}
					type = type.BaseType;
				}
			}

			private void Follow(FieldInfo field, object owner, int depth)
			{
				if (CanHold(field.FieldType))
				{
					Collect(field.GetValue(owner), depth);
				}
			}

			private void Collect(object value, int depth)
			{
				if (value == null || value is string)
				{
					return;
				}
				ConfigEntryBase val = (ConfigEntryBase)((value is ConfigEntryBase) ? value : null);
				if (val == null)
				{
					ConfigFile val2 = (ConfigFile)((value is ConfigFile) ? value : null);
					if (val2 == null)
					{
						IEnumerable enumerable;
						if (!(value is IDictionary dictionary))
						{
							enumerable = value as IEnumerable;
							if (enumerable == null)
							{
								goto IL_0114;
							}
						}
						else
						{
							if (depth < 3)
							{
								{
									foreach (DictionaryEntry item in dictionary)
									{
										Collect(item.Key, depth + 1);
										Collect(item.Value, depth + 1);
									}
									return;
								}
							}
							enumerable = (IEnumerable)value;
						}
						if (depth < 3)
						{
							foreach (object item2 in enumerable)
							{
								Collect(item2, depth + 1);
							}
							return;
						}
						goto IL_0114;
					}
					AddConfigFile(val2);
					return;
				}
				_held.Add(val);
				AddConfigFile(val.ConfigFile);
				return;
				IL_0114:
				if (depth < 3 && IsHolder(value.GetType()) && _visited.Add(value))
				{
					Expand(value, depth + 1);
				}
			}

			private void AddConfigFile(ConfigFile file)
			{
				if (file != null && _configFileSet.Add(file))
				{
					ConfigFiles.Add(file);
				}
			}

			private bool CanHold(Type type)
			{
				if (typeof(Delegate).IsAssignableFrom(type) || (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Lazy<>)))
				{
					return false;
				}
				if (typeof(ConfigEntryBase).IsAssignableFrom(type) || typeof(ConfigFile).IsAssignableFrom(type) || IsHolder(type))
				{
					return true;
				}
				if (type.IsArray)
				{
					return CanHold(type.GetElementType());
				}
				if (type.IsGenericType)
				{
					return type.GetGenericArguments().Any(CanHold);
				}
				return false;
			}

			private bool IsHolder(Type type)
			{
				while (type != null && type.Assembly == _assembly)
				{
					if (_holders.Contains(type))
					{
						return true;
					}
					type = type.BaseType;
				}
				return false;
			}
		}

		private const string SettingChangedField = "SettingChanged";

		private const BindingFlags AllFields = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		private const BindingFlags InstanceField = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private const string HandlerFact = "the SettingChanged handlers of its entries";

		private const string HeldFact = "the fields that hold its entries and config files";

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

		private readonly string _pluginGuid;

		private readonly HashSet<object> _held;

		internal IReadOnlyList<ConfigFile> ConfigFiles { get; }

		private EntryFacts(string pluginGuid, HashSet<object> held, IReadOnlyList<ConfigFile> configFiles)
		{
			_pluginGuid = pluginGuid;
			_held = held;
			ConfigFiles = configFiles;
		}

		internal static EntryFacts Read(string pluginGuid, object instance)
		{
			HashSet<object> held = null;
			List<ConfigFile> configFiles = new List<ConfigFile>();
			try
			{
				HeldScan heldScan = new HeldScan(instance.GetType().Assembly);
				held = heldScan.EntriesHeldBy(instance);
				configFiles = heldScan.ConfigFiles;
			}
			catch (Exception e)
			{
				LogOnce(pluginGuid, "the fields that hold its entries and config files", Describe(e));
			}
			return new EntryFacts(pluginGuid, held, configFiles);
		}

		internal bool HasSettingChangedHandler(ConfigEntryBase entry)
		{
			try
			{
				FieldInfo field = ((object)entry).GetType().GetField("SettingChanged", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field == null)
				{
					LogOnce(_pluginGuid, "the SettingChanged handlers of its entries", ((object)entry).GetType().FullName + " has no SettingChanged field");
					return false;
				}
				return field.GetValue(entry) is Delegate obj && obj.GetInvocationList().Length != 0;
			}
			catch (Exception e)
			{
				LogOnce(_pluginGuid, "the SettingChanged handlers of its entries", Describe(e));
				return false;
			}
		}

		internal bool CopiedAndDropped(ConfigEntryBase entry)
		{
			if (_held != null)
			{
				return !_held.Contains(entry);
			}
			return false;
		}

		private static void LogOnce(string pluginGuid, string fact, string reason)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			if (Logged.Add(pluginGuid + "|" + fact))
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(68, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(pluginGuid);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": could not read ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(fact);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" by reflection, so Config Forge ignores that fact: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(reason);
				}
				log.LogWarning(val);
			}
		}

		private static string Describe(Exception e)
		{
			if (e is ReflectionTypeLoadException ex)
			{
				return ex.LoaderExceptions.FirstOrDefault((Exception inner) => inner != null)?.Message ?? e.Message;
			}
			while (e.InnerException != null)
			{
				e = e.InnerException;
			}
			return e.Message;
		}
	}
	[HarmonyPatch]
	internal static class EscapeGuard
	{
		private static int _backFrame = -1;

		private static bool _backReachedGame;

		[HarmonyPrefix]
		[HarmonyPatch(typeof(MenuShortcutsManager), "Pause_started")]
		private static bool PauseStarted()
		{
			return !EscapeOwner.OwnsEscape;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(MenuShortcutsManager), "Back_performed")]
		private static bool ShortcutsBackPerformed()
		{
			return BackReachesGame();
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(MainMenu), "Back_performed")]
		private static bool MainMenuBackPerformed()
		{
			return BackReachesGame();
		}

		private static bool BackReachesGame()
		{
			if (Time.frameCount == _backFrame)
			{
				return _backReachedGame;
			}
			_backFrame = Time.frameCount;
			_backReachedGame = KitConfirmDialog.IsOpen || (!EscapeOwner.OwnsEscape && !ConfigForgeTab.TakeBack());
			return _backReachedGame;
		}
	}
	internal static class EscapeOwner
	{
		private const float EscapeGraceSeconds = 0.3f;

		private static bool _ownedEscapeHeld;

		private static float _ownedEscapeReleasedAt = float.NegativeInfinity;

		public static bool OwnsEscape
		{
			get
			{
				if (!_ownedEscapeHeld)
				{
					return InEscapeGrace;
				}
				return true;
			}
		}

		private static bool InEscapeGrace => Time.unscaledTime - _ownedEscapeReleasedAt < 0.3f;

		public static void TrackEscape()
		{
			if (Input.GetKeyDown((KeyCode)27))
			{
				_ownedEscapeHeld = false;
				_ownedEscapeReleasedAt = float.NegativeInfinity;
			}
			if (_ownedEscapeHeld && !Input.GetKey((KeyCode)27))
			{
				_ownedEscapeHeld = false;
				_ownedEscapeReleasedAt = Time.unscaledTime;
			}
		}

		public static void OwnEscapePress()
		{
			_ownedEscapeHeld = true;
		}
	}
	internal static class KeyCapture
	{
		private static readonly KeyCode[] Modifiers;

		private static readonly KeyCode[] Scanned;

		private static readonly Func<int, bool> IsMouseButtonHeld;

		private static readonly CancellingClick Click;

		private static bool _active;

		private static object _owner;

		private static bool _shortcut;

		private static int _startedFrame;

		private static int _endedFrame;

		private static KeyCode? _loneModifier;

		private static Action<string, IReadOnlyList<string>> _captured;

		private static Action _cancelled;

		public static bool IsBlockingInput
		{
			get
			{
				if (!_active)
				{
					return Time.frameCount == _endedFrame;
				}
				return true;
			}
		}

		public static bool IsCapturing => _active;

		public static void Start(object owner, bool shortcut, Action<string, IReadOnlyList<string>> captured, Action cancelled)
		{
			Cancel();
			Click.Forget();
			_active = true;
			_owner = owner;
			_shortcut = shortcut;
			_startedFrame = Time.frameCount;
			_loneModifier = null;
			_captured = captured;
			_cancelled = cancelled;
		}

		public static bool IsCancellingClick(object owner)
		{
			return Click.IsFrom(owner);
		}

		public static void TrackClick()
		{
			Click.Track(Time.frameCount, IsMouseButtonHeld);
		}

		public static void Cancel()
		{
			if (_active)
			{
				Action cancelled = _cancelled;
				End();
				cancelled();
			}
		}

		public static void Tick()
		{
			//IL_0067: 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_00d9: 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_00df: 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_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			if (!_active || Time.frameCount == _startedFrame)
			{
				return;
			}
			if (Input.GetMouseButtonDown(1))
			{
				Finish((KeyCode)0, Enumerable.Empty<KeyCode>());
				return;
			}
			if (Input.GetMouseButtonDown(0))
			{
				Click.Cancelled(_owner, 0);
				TrackClick();
				Cancel();
				return;
			}
			if (Input.GetKeyDown((KeyCode)27))
			{
				Cancel();
				return;
			}
			KeyCode[] scanned = Scanned;
			foreach (KeyCode val in scanned)
			{
				if (Input.GetKeyDown(val))
				{
					if (!_shortcut || !Modifiers.Contains(val))
					{
						Finish(val, ((IEnumerable<KeyCode>)Modifiers).Where((Func<KeyCode, bool>)Input.GetKey));
						return;
					}
					_loneModifier = val;
				}
			}
			KeyCode? loneModifier = _loneModifier;
			if (loneModifier.HasValue)
			{
				KeyCode valueOrDefault = loneModifier.GetValueOrDefault();
				if (Input.GetKeyUp(valueOrDefault))
				{
					Finish(valueOrDefault, Enumerable.Empty<KeyCode>());
				}
			}
		}

		private unsafe static void Finish(KeyCode main, IEnumerable<KeyCode> held)
		{
			Action<string, IReadOnlyList<string>> captured = _captured;
			IReadOnlyList<string> arg = held.Select((KeyCode key) => ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString()).ToList();
			End();
			captured(((object)(*(KeyCode*)(&main))/*cast due to .constrained prefix*/).ToString(), arg);
		}

		private static void End()
		{
			_active = false;
			_owner = null;
			_endedFrame = Time.frameCount;
			_captured = null;
			_cancelled = null;
		}

		unsafe static KeyCapture()
		{
			KeyCode[] array = new KeyCode[6];
			RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			Modifiers = (KeyCode[])(object)array;
			Scanned = (from key in ((KeyCode[])Enum.GetValues(typeof(KeyCode))).Distinct()
				where (int)key != 0 && (int)key != 323 && (int)key != 324 && (int)key != 27
				where !((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString().StartsWith("Joystick", StringComparison.Ordinal)
				select key).ToArray();
			IsMouseButtonHeld = Input.GetMouseButton;
			Click = new CancellingClick();
			_endedFrame = -1;
		}
	}
	internal static class MedallionArt
	{
		private const string OwnGuidPrefix = "mugsy33.";

		private const long MaxFolderIconBytes = 2097152L;

		private const int MaxFolderIconSide = 512;

		private const int DiscSize = 128;

		private const int CheckerCells = 4;

		private static readonly Color CheckerLight = new Color(0.6f, 0.6f, 0.6f, 1f);

		private static readonly Color CheckerDark = new Color(0.3f, 0.3f, 0.3f, 1f);

		private const int GlyphInset = 18;

		private const float GlyphThreshold = 0.29411766f;

		private const float GlyphGain = 1.4f;

		private static readonly Dictionary<string, Sprite> Icons = new Dictionary<string, Sprite>();

		private static readonly Dictionary<string, Sprite> GreyIcons = new Dictionary<string, Sprite>();

		private static readonly Dictionary<string, Sprite> FolderIcons = new Dictionary<string, Sprite>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, Sprite> GreyFolderIcons = new Dictionary<string, Sprite>(StringComparer.OrdinalIgnoreCase);

		private static Sprite _disc;

		private static Sprite _modsTab;

		private static Sprite _modsTabGlyph;

		private static Sprite _reload;

		private static Sprite _checker;

		public static Sprite Disc => _disc ?? (_disc = CreateDisc());

		public static Sprite Checker => _checker ?? (_checker = CreateChecker());

		public static Sprite ModsTab
		{
			get
			{
				object obj = _modsTab;
				if (obj == null)
				{
					obj = LoadEmbedded("ModsTab.png") ?? throw new InvalidOperationException("The embedded tab tile 'ModsTab.png' is missing.");
					_modsTab = (Sprite)obj;
				}
				return (Sprite)obj;
			}
		}

		public static Sprite Reload
		{
			get
			{
				object obj = _reload;
				if (obj == null)
				{
					obj = LoadEmbedded("Reload.png") ?? throw new InvalidOperationException("The embedded reload plate art 'Reload.png' is missing.");
					_reload = (Sprite)obj;
				}
				return (Sprite)obj;
			}
		}

		public static Sprite ModsTabGlyph => _modsTabGlyph ?? (_modsTabGlyph = CreateGlyph(ModsTab.texture));

		public static Sprite FindIcon(string folder, IEnumerable<string> pluginGuids, bool greyscale)
		{
			Sprite val = FolderArt.First(folder, (string path) => FolderIcon(path, greyscale));
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			foreach (string pluginGuid in pluginGuids)
			{
				if (pluginGuid.StartsWith("mugsy33.", StringComparison.Ordinal))
				{
					Sprite val2 = (greyscale ? LoadGreyIcon(pluginGuid) : LoadIcon(pluginGuid));
					if ((Object)(object)val2 != (Object)null)
					{
						return val2;
					}
				}
			}
			return null;
		}

		private static Sprite FolderIcon(string path, bool greyscale)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Expected O, but got Unknown
			Dictionary<string, Sprite> dictionary = (greyscale ? GreyFolderIcons : FolderIcons);
			if (dictionary.TryGetValue(path, out var value))
			{
				return value;
			}
			if (!File.Exists(path))
			{
				return null;
			}
			Sprite val2;
			try
			{
				Sprite val = LoadFolderIcon(path);
				val2 = (Sprite)((greyscale && (Object)(object)val != (Object)null) ? ((object)Greyscale(val.texture)) : ((object)val));
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val3 = new BepInExWarningLogInterpolatedStringHandler(34, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("The medallion art '");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(path);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("' is not used: ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(ex.Message);
				}
				log.LogWarning(val3);
				FolderIcons.TryAdd(path, null);
				val2 = null;
			}
			dictionary[path] = val2;
			return val2;
		}

		private static Sprite LoadFolderIcon(string path)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			if (FolderIcons.TryGetValue(path, out Sprite value))
			{
				return value;
			}
			Sprite sprite;
			string text = ReadFolderIcon(path, out sprite);
			if (text != null)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(35, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("The medallion art '");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(path);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' is not used: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log.LogWarning(val);
			}
			FolderIcons[path] = sprite;
			return sprite;
		}

		private static string ReadFolderIcon(string path, out Sprite sprite)
		{
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Expected O, but got Unknown
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			sprite = null;
			byte[] array;
			try
			{
				long length = new FileInfo(path).Length;
				if (length > 2097152)
				{
					return $"it is {length} bytes, more than the {2097152} allowed";
				}
				array = File.ReadAllBytes(path);
			}
			catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException)
			{
				return "it could not be read (" + ex.Message + ")";
			}
			if (!PngHeader.TryRead(array, out var width, out var height))
			{
				return "it is not a PNG";
			}
			if (width > 512 || height > 512)
			{
				return $"it is {width} x {height}, larger than {512} x {512}";
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			if (!ImageConversion.LoadImage(val, Il2CppStructArray<byte>.op_Implicit(array)))
			{
				Object.Destroy((Object)(object)val);
				return "it is not an image Unity can decode";
			}
			sprite = Keep<Sprite>(Sprite.Create(Keep<Texture2D>(val), new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f)));
			return null;
		}

		private static Sprite LoadIcon(string guid)
		{
			if (Icons.TryGetValue(guid, out Sprite value))
			{
				return value;
			}
			Sprite val = LoadEmbedded("Icons." + guid + ".png");
			Icons[guid] = val;
			return val;
		}

		private static Sprite LoadGreyIcon(string guid)
		{
			if (GreyIcons.TryGetValue(guid, out Sprite value))
			{
				return value;
			}
			Sprite val = LoadIcon(guid);
			Sprite val2 = (((Object)(object)val == (Object)null) ? null : Greyscale(val.texture));
			GreyIcons[guid] = val2;
			return val2;
		}

		private static Sprite Greyscale(Texture2D source)
		{
			//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_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: 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_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			//IL_009f: 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)
			Il2CppStructArray<Color> pixels = source.GetPixels();
			for (int i = 0; i < ((Il2CppArrayBase<Color>)(object)pixels).Length; i++)
			{
				Color val = ((Il2CppArrayBase<Color>)(object)pixels)[i];
				float num = 0.299f * val.r + 0.587f * val.g + 0.114f * val.b;
				((Il2CppArrayBase<Color>)(object)pixels)[i] = new Color(num, num, num, val.a);
			}
			Texture2D val2 = new Texture2D(((Texture)source).width, ((Texture)source).height, (TextureFormat)4, false);
			val2.SetPixels(pixels);
			val2.Apply();
			return Keep<Sprite>(Sprite.Create(Keep<Texture2D>(val2), new Rect(0f, 0f, (float)((Texture)val2).width, (float)((Texture)val2).height), new Vector2(0.5f, 0.5f)));
		}

		private static Sprite LoadEmbedded(string name)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected O, but got Unknown
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			string text = executingAssembly.GetName().Name + "." + name;
			using Stream stream = executingAssembly.GetManifestResourceStream(text);
			if (stream == null)
			{
				return null;
			}
			using MemoryStream memoryStream = new MemoryStream();
			stream.CopyTo(memoryStream);
			byte[] array = memoryStream.ToArray();
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			if (!ImageConversion.LoadImage(val, Il2CppStructArray<byte>.op_Implicit(array)))
			{
				throw new InvalidOperationException("The embedded image '" + text + "' is not a readable PNG.");
			}
			return Keep<Sprite>(Sprite.Create(Keep<Texture2D>(val), new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f)));
		}

		private static Sprite CreateDisc()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			//IL_00cf: 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_007b: 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)
			Texture2D val = new Texture2D(128, 128, (TextureFormat)4, false);
			Color[] array = (Color[])(object)new Color[16384];
			float num = 63.5f;
			float num2 = 63f;
			for (int i = 0; i < 128; i++)
			{
				for (int j = 0; j < 128; j++)
				{
					float num3 = Mathf.Sqrt(((float)j - num) * ((float)j - num) + ((float)i - num) * ((float)i - num));
					array[i * 128 + j] = new Color(1f, 1f, 1f, Mathf.Clamp01(num2 - num3 + 0.5f));
				}
			}
			val.SetPixels(Il2CppStructArray<Color>.op_Implicit(array));
			val.Apply();
			return Keep<Sprite>(Sprite.Create(Keep<Texture2D>(val), new Rect(0f, 0f, 128f, 128f), new Vector2(0.5f, 0.5f)));
		}

		private static Sprite CreateChecker()
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			//IL_0082: 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_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(4, 4, (TextureFormat)4, false)
			{
				filterMode = (FilterMode)0,
				wrapMode = (TextureWrapMode)1
			};
			Color[] array = (Color[])(object)new Color[16];
			for (int i = 0; i < 4; i++)
			{
				for (int j = 0; j < 4; j++)
				{
					array[i * 4 + j] = (((j + i) % 2 == 0) ? CheckerLight : CheckerDark);
				}
			}
			val.SetPixels(Il2CppStructArray<Color>.op_Implicit(array));
			val.Apply();
			return Keep<Sprite>(Sprite.Create(Keep<Texture2D>(val), new Rect(0f, 0f, 4f, 4f), new Vector2(0.5f, 0.5f)));
		}

		private static Sprite CreateGlyph(Texture2D tile)
		{
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03de: Unknown result type (might be due to invalid IL or missing references)
			//IL_03eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f6: Expected O, but got Unknown
			//IL_0406: Unknown result type (might be due to invalid IL or missing references)
			//IL_0415: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_039f: 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)
			int width = ((Texture)tile).width;
			int height = ((Texture)tile).height;
			if (width <= 36 || height <= 36)
			{
				throw new InvalidOperationException($"The tab tile is {width} x {height}, too small for its {18}-texel border.");
			}
			Il2CppStructArray<Color> pixels = tile.GetPixels();
			float[] array = new float[width * height];
			for (int i = 0; i < array.Length; i++)
			{
				Color val = ((Il2CppArrayBase<Color>)(object)pixels)[i];
				array[i] = 0.299f * val.r + 0.587f * val.g + 0.114f * val.b;
			}
			bool[] array2 = new bool[width * height];
			Queue<int> queue = new Queue<int>();
			for (int j = 18; j < width - 18; j++)
			{
				queue.Enqueue(18 * width + j);
				queue.Enqueue((height - 18 - 1) * width + j);
			}
			for (int k = 18; k < height - 18; k++)
			{
				queue.Enqueue(k * width + 18);
				queue.Enqueue(k * width + width - 18 - 1);
			}
			while (queue.Count > 0)
			{
				int num = queue.Dequeue();
				if (!array2[num] && !(array[num] > 0.29411766f))
				{
					array2[num] = true;
					EnqueueNeighbours(queue, num, width, Inside);
				}
			}
			int[] array3 = new int[width * height];
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			for (int l = 0; l < array3.Length; l++)
			{
				if (array2[l] || array3[l] != 0 || !Inside(l % width, l / width))
				{
					continue;
				}
				num4++;
				int num5 = 0;
				queue.Enqueue(l);
				while (queue.Count > 0)
				{
					int num6 = queue.Dequeue();
					if (!array2[num6] && array3[num6] == 0)
					{
						array3[num6] = num4;
						num5++;
						EnqueueNeighbours(queue, num6, width, Inside);
					}
				}
				if (num5 > num3)
				{
					num2 = num4;
					num3 = num5;
				}
			}
			if (num3 == 0)
			{
				throw new InvalidOperationException("The tab tile holds no piece brighter than its stone.");
			}
			int num7 = width;
			int num8 = height;
			int num9 = -1;
			int num10 = -1;
			for (int m = 0; m < array3.Length; m++)
			{
				if (array3[m] == num2)
				{
					int val2 = m % width;
					int val3 = m / width;
					num7 = Math.Min(num7, val2);
					num9 = Math.Max(num9, val2);
					num8 = Math.Min(num8, val3);
					num10 = Math.Max(num10, val3);
				}
			}
			int num11 = num9 - num7 + 1;
			int num12 = num10 - num8 + 1;
			Color[] array4 = (Color[])(object)new Color[num11 * num12];
			for (int n = 0; n < num12; n++)
			{
				for (int num13 = 0; num13 < num11; num13++)
				{
					int num14 = (num8 + n) * width + num7 + num13;
					float num15 = Mathf.Clamp01(array[num14] * 1.4f);
					array4[n * num11 + num13] = (Color)((array3[num14] == num2) ? new Color(num15, num15, num15, 1f) : Color.clear);
				}
			}
			Texture2D val4 = new Texture2D(num11, num12, (TextureFormat)4, false);
			val4.SetPixels(Il2CppStructArray<Color>.op_Implicit(array4));
			val4.Apply();
			return Keep<Sprite>(Sprite.Create(Keep<Texture2D>(val4), new Rect(0f, 0f, (float)num11, (float)num12), new Vector2(0.5f, 0.5f)));
			bool Inside(int x, int y)
			{
				if (x >= 18 && y >= 18 && x < width - 18)
				{
					return y < height - 18;
				}
				return false;
			}
		}

		private static void EnqueueNeighbours(Queue<int> queue, int i, int width, Func<int, int, bool> inside)
		{
			int num = i % width;
			int num2 = i / width;
			if (inside(num + 1, num2))
			{
				queue.Enqueue(i + 1);
			}
			if (inside(num - 1, num2))
			{
				queue.Enqueue(i - 1);
			}
			if (inside(num, num2 + 1))
			{
				queue.Enqueue(i + width);
			}
			if (inside(num, num2 - 1))
			{
				queue.Enqueue(i - width);
			}
		}

		private static T Keep<T>(T asset) where T : Object
		{
			((Object)asset).hideFlags = (HideFlags)61;
			return asset;
		}
	}
	internal static class ModDiscovery
	{
		private const string KeyboardShortcutTypeName = "KeyboardShortcut";

		private static readonly string[] ColourTypeNames = new string[2] { "UnityEngine.Color", "UnityEngine.Color32" };

		private const string BrowsableTag = "Browsable";

		private const string IsAdvancedTag = "IsAdvanced";

		private const string BepInExName = "BepInEx";

		private const string EnglishLanguage = "english";

		private const string TableResourceSuffix = ".Strings.json";

		private static readonly Dictionary<string, TranslationTable> Tables = new Dictionary<string, TranslationTable>();

		private static readonly Dictionary<Type, NumberType> NumberTypes = new Dictionary<Type, NumberType>
		{
			[typeof(sbyte)] = NumberType.SByte,
			[typeof(byte)] = NumberType.Byte,
			[typeof(short)] = NumberType.Int16,
			[typeof(ushort)] = NumberType.UInt16,
			[typeof(int)] = NumberType.Int32,
			[typeof(uint)] = NumberType.UInt32,
			[typeof(long)] = NumberType.Int64,
			[typeof(ulong)] = NumberType.UInt64,
			[typeof(float)] = NumberType.Single,
			[typeof(double)] = NumberType.Double,
			[typeof(decimal)] = NumberType.Decimal
		};

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

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

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

		private static readonly Dictionary<string, (string Id, ConfigFile File)> Files = new Dictionary<string, (string, ConfigFile)>(StringComparer.OrdinalIgnoreCase);

		public static List<PluginSnapshot> Snapshot()
		{
			Files.Clear();
			string language = CurrentLanguage();
			List<PluginInfo> list = ((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins.Values.ToList();
			HashSet<ConfigFile> standardFiles = new HashSet<ConfigFile>((from config in list.Select(delegate(PluginInfo info)
				{
					object instance2 = info.Instance;
					object obj2 = ((instance2 is BasePlugin) ? instance2 : null);
					return (obj2 == null) ? null : ((BasePlugin)obj2).Config;
				})
				where config != null
				select config).Append(ConfigFile.CoreConfig), ReferenceEqualityComparer.Instance);
			List<PluginSnapshot> list2 = new List<PluginSnapshot>();
			foreach (PluginInfo item in list)
			{
				PluginSnapshot obj = new PluginSnapshot
				{
					Guid = item.Metadata.GUID,
					Name = item.Metadata.Name,
					Version = ((object)item.Metadata.Version).ToString(),
					DllPath = DllPathOf(item)
				};
				object instance = item.Instance;
				BasePlugin val = (BasePlugin)((instance is BasePlugin) ? instance : null);
				IReadOnlyList<ConfigFileSnapshot> configFiles;
				if (val == null)
				{
					IReadOnlyList<ConfigFileSnapshot> readOnlyList = new ConfigFileSnapshot[0];
					configFiles = readOnlyList;
				}
				else
				{
					configFiles = FilesOf(item.Metadata.GUID, val, standardFiles);
				}
				obj.ConfigFiles = configFiles;
				obj.Translations = TranslationsOf(item);
				obj.Language = language;
				list2.Add(obj);
			}
			list2.Add(new PluginSnapshot
			{
				Guid = "<BepInEx>",
				Name = "BepInEx",
				Version = ((object)Paths.BepInExVersion).ToString(),
				DllPath = null,
				ConfigFiles = new ConfigFileSnapshot[1] { FileSnapshot("<BepInEx>", ConfigFile.CoreConfig, null, isStandard: true) }
			});
			return list2;
		}

		private static IReadOnlyList<ConfigFileSnapshot> FilesOf(string pluginGuid, BasePlugin plugin, HashSet<ConfigFile> standardFiles)
		{
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Expected O, but got Unknown
			EntryFacts entryFacts = EntryFacts.Read(pluginGuid, plugin);
			List<ConfigFileSnapshot> list = new List<ConfigFileSnapshot> { FileSnapshot(pluginGuid, plugin.Config, entryFacts, isStandard: true) };
			try
			{
				List<ConfigFileSnapshot> list2 = new List<ConfigFileSnapshot>();
				foreach (ConfigFile item in entryFacts.ConfigFiles.Where((ConfigFile config) => !standardFiles.Contains(config)))
				{
					list2.Add(FileSnapshot(pluginGuid, item, entryFacts, isStandard: false));
				}
				list.AddRange(list2);
			}
			catch (Exception ex)
			{
				if (FileReadsLogged.Add(pluginGuid))
				{
					ManualLogSource log = Plugin.Log;
					bool flag = default(bool);
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(83, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(pluginGuid);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": a config file it reaches could not be read, so only its standard file is listed: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
					}
					log.LogWarning(val);
				}
			}
			return list;
		}

		public static IEnumerable<ConfigFile> ConfigFiles()
		{
			return Files.Values.Select<(string, ConfigFile), ConfigFile>(((string Id, ConfigFile File) known) => known.File);
		}

		public static ConfigFile FileOf(string configFile)
		{
			if (!Files.TryGetValue(configFile, out (string, ConfigFile) value))
			{
				throw new InvalidOperationException("The config file '" + configFile + "' is not in the last snapshot.");
			}
			return value.Item2;
		}

		private static ConfigFileSnapshot FileSnapshot(string pluginGuid, ConfigFile config, EntryFacts facts, bool isStandard)
		{
			string fullPath = Path.GetFullPath(config.ConfigFilePath);
			if (!Files.TryGetValue(fullPath, out (string, ConfigFile) value))
			{
				value = (fullPath, config);
				Files[fullPath] = value;
			}
			return new ConfigFileSnapshot
			{
				Id = value.Item1,
				Name = Path.GetFileName(value.Item1),
				IsStandard = isStandard,
				Entries = Entries(pluginGuid, value.Item2, facts)
			};
		}

		private static string CurrentLanguage()
		{
			//IL_0010: 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)
			LocalizationManager instance = LocalizationManager.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				return ((object)instance.SystemLanguage/*cast due to .constrained prefix*/).ToString();
			}
			return "english";
		}

		private static TranslationTable TranslationsOf(PluginInfo info)
		{
			if (!Tables.TryGetValue(info.Metadata.GUID, out TranslationTable value))
			{
				value = ReadTable(info);
				Tables[info.Metadata.GUID] = value;
			}
			return value;
		}

		private static TranslationTable ReadTable(PluginInfo info)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Expected O, but got Unknown
			if (info.Instance == null)
			{
				return null;
			}
			Assembly assembly = info.Instance.GetType().Assembly;
			string text = assembly.GetName().Name + ".Strings.json";
			try
			{
				using Stream stream = assembly.GetManifestResourceStream(text);
				if (stream == null)
				{
					return null;
				}
				using StreamReader streamReader = new StreamReader(stream);
				return TranslationTable.Parse(streamReader.ReadToEnd());
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(82, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(info.Metadata.GUID);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'s translation table '");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' could not be read, so its settings show as it wrote them: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				log.LogWarning(val);
				return null;
			}
		}

		private static List<ConfigEntrySnapshot> Entries(string pluginGuid, ConfigFile config, EntryFacts facts)
		{
			return config.Keys.Select((ConfigDefinition definition) => ToSnapshot(pluginGuid, definition, config[definition], facts)).ToList();
		}

		private static ConfigEntrySnapshot ToSnapshot(string pluginGuid, ConfigDefinition definition, ConfigEntryBase entry, EntryFacts facts)
		{
			ValueKind valueKind = TypeKindOf(entry);
			ValueKind valueKind2 = (IsAcceptableValueList(entry.Description.AcceptableValues) ? ValueKind.AcceptableValues : valueKind);
			NumberType numberType = ((valueKind == ValueKind.Number) ? NumberTypes[entry.SettingType] : NumberType.SByte);
			string rangeMin;
			string rangeMax;
			if (valueKind2 == ValueKind.Number)
			{
				(rangeMin, rangeMax) = Range(entry);
			}
			else
			{
				rangeMin = null;
				rangeMax = null;
			}
			DescriptionHint descriptionHint = DescriptionHint.Parse(entry.Description.Description, valueKind2, numberType);
			LogHintProblems(pluginGuid, definition, descriptionHint);
			EntryTags entryTags = ConfigTags.Read(entry.Description.Tags);
			LogTagProblems(pluginGuid, definition, entryTags);
			string text = TomlTypeConverter.ConvertToString(entry.DefaultValue, entry.SettingType);
			return new ConfigEntrySnapshot
			{
				Section = definition.Section,
				Key = definition.Key,
				Value = entry.GetSerializedValue(),
				Description = descriptionHint.Text,
				Kind = valueKind2,
				TypeKind = valueKind,
				DefaultValue = text,
				DefaultTakes = DefaultTakes(entry, text),
				AllowedValues = AllowedValues(entry, valueKind2),
				DeclaredTiming = entryTags.DeclaredTiming,
				HasSettingChangedHandler = (facts?.HasSettingChangedHandler(entry) ?? false),
				CopiedAndDropped = (facts?.CopiedAndDropped(entry) ?? false),
				Browsable = !TagSets(entry.Description, "Browsable", value: false),
				IsAdvanced = TagSets(entry.Description, "IsAdvanced", value: true),
				ReadOnly = entryTags.ReadOnly,
				DisplayName = entryTags.DispName,
				Order = entryTags.Order,
				TooltipText = entryTags.Description,
				NumberType = numberType,
				RangeMin = rangeMin,
				RangeMax = rangeMax,
				Step = descriptionHint.Step,
				HintMin = descriptionHint.Min,
				HintMax = descriptionHint.Max,
				ColourHint = descriptionHint.Colour
			};
		}

		internal static bool ConverterKeeps(Type type, string text)
		{
			try
			{
				object value;
				return RoundTrip(type, text, out value) == text;
			}
			catch (Exception)
			{
				return false;
			}
		}

		internal static string RoundTrip(Type type, string text, out object value)
		{
			value = TomlTypeConverter.ConvertToValue(text, type);
			return TomlTypeConverter.ConvertToString(value, type);
		}

		internal static bool Allows(ConfigEntryBase entry, object value)
		{
			AcceptableValueBase acceptableValues = entry.Description.AcceptableValues;
			if (acceptableValues != null)
			{
				return acceptableValues.IsValid(value);
			}
			return true;
		}

		private static bool DefaultTakes(ConfigEntryBase entry, string defaultText)
		{
			try
			{
				object value;
				return RoundTrip(entry.SettingType, defaultText, out value) == defaultText && Allows(entry, value);
			}
			catch (Exception)
			{
				return false;
			}
		}

		private static void LogHintProblems(string pluginGuid, ConfigDefinition definition, DescriptionHint hint)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			if (hint.Problems.Count != 0 && HintProblemsLogged.Add($"{pluginGuid}/{definition.Section}/{definition.Key}"))
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(37, 4, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("The [ConfigForge: ...] hint on ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(pluginGuid);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" '");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(definition.Section);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(definition.Key);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("': ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(string.Join(" ", hint.Problems));
				}
				log.LogWarning(val);
			}
		}

		private static void LogTagProblems(string pluginGuid, ConfigDefinition definition, EntryTags tags)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			if (tags.Problems.Count != 0 && TagProblemsLogged.Add($"{pluginGuid}/{definition.Section}/{definition.Key}"))
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(25, 4, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("The config tags on ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(pluginGuid);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" '");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(definition.Section);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(definition.Key);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("': ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(string.Join(" ", tags.Problems));
				}
				log.LogWarning(val);
			}
		}

		private static (string Min, string Max) Range(ConfigEntryBase entry)
		{
			AcceptableValueBase acceptableValues = entry.Description.AcceptableValues;
			if (acceptableValues == null || !((object)acceptableValues).GetType().IsGenericType || ((object)acceptableValues).GetType().GetGenericTypeDefinition() != typeof(AcceptableValueRange<>))
			{
				return (Min: null, Max: null);
			}
			Type type = ((object)acceptableValues).GetType();
			object value = type.GetProperty("MinValue").GetValue(acceptableValues);
			object value2 = type.GetProperty("MaxValue").GetValue(acceptableValues);
			return (Min: TomlTypeConverter.ConvertToString(value, entry.SettingType), Max: TomlTypeConverter.ConvertToString(value2, entry.SettingType));
		}

		private static ValueKind TypeKindOf(ConfigEntryBase entry)
		{
			if (entry.SettingType == typeof(bool))
			{
				return ValueKind.Bool;
			}
			if (entry.SettingType == typeof(KeyCode))
			{
				return ValueKind.KeyCode;
			}
			if (entry.SettingType.Name == "KeyboardShortcut")
			{
				return ValueKind.KeyboardShortcut;
			}
			if (entry.SettingType.IsEnum)
			{
				if (!entry.SettingType.IsDefined(typeof(FlagsAttribute), inherit: false))
				{
					return ValueKind.Enum;
				}
				return ValueKind.Other;
			}
			if (NumberTypes.ContainsKey(entry.SettingType))
			{
				return ValueKind.Number;
			}
			if (entry.SettingType == typeof(string))
			{
				return ValueKind.String;
			}
			if (ColourTypeNames.Contains<string>(entry.SettingType.FullName) && ConverterKeeps(entry.SettingType, TomlTypeConverter.ConvertToString(entry.DefaultValue, entry.SettingType)))
			{
				return ValueKind.Colour;
			}
			return ValueKind.Other;
		}

		private static bool IsAcceptableValueList(AcceptableValueBase acceptable)
		{
			if (acceptable != null && ((object)acceptable).GetType().IsGenericType)
			{
				return ((object)acceptable).GetType().GetGenericTypeDefinition() == typeof(AcceptableValueList<>);
			}
			return false;
		}

		private static IReadOnlyList<string> AllowedValues(ConfigEntryBase entry, ValueKind kind)
		{
			IEnumerable<object> source;
			switch (kind)
			{
			case ValueKind.KeyCode:
			case ValueKind.KeyboardShortcut:
				return Enum.GetNames(typeof(KeyCode));
			case ValueKind.AcceptableValues:
				source = ((Array)((object)entry.Description.AcceptableValues).GetType().GetProperty("AcceptableValues").GetValue(entry.Description.AcceptableValues)).Cast<object>();
				break;
			case ValueKind.Bool:
				source = new object[2] { false, true };
				break;
			case ValueKind.Enum:
				source = Enum.GetValues(entry.SettingType).Cast<object>();
				break;
			default:
				source = Enumerable.Empty<object>();
				break;
			}
			return source.Select((object value) => TomlTypeConverter.ConvertToString(value, entry.SettingType)).Distinct().ToList();
		}

		private static bool TagSets(ConfigDescription description, string name, bool value)
		{
			foreach (object item in description.Tags.Where((object tag) => tag != null))
			{
				Type type = item.GetType();
				if ((type.GetField(name, BindingFlags.Instance | BindingFlags.Public)?.GetValue(item) ?? type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public)?.GetValue(item)) is bool flag && flag == value)
				{
					return true;
				}
			}
			return false;
		}

		private static string DllPathOf(PluginInfo info)
		{
			string location = info.Location;
			if (string.IsNullOrEmpty(location))
			{
				return null;
			}
			string relativePath = Path.GetRelativePath(Paths.PluginPath, location);
			if (relativePath.StartsWith("..", StringComparison.Ordinal) || Path.IsPathRooted(relativePath))
			{
				return null;
			}
			return location;
		}
	}
	internal sealed class ModSettingsContent
	{
		private sealed class RowView
		{
			public SettingRow Row;

			public RectTransform Rect;

			public TMP_Text Value;

			public Color RestColor;

			public Transform Keycaps;

			public Image[] Pips;

			public Slider Slider;

			public TMP_InputField Field;

			public Image Swatch;

			public Selectable Stop;

			public GameObject FocusFrame;
		}

		private const int ListView = -1;

		private const int MaxPips = 10;

		private const float DisabledAlpha = 0.5f;

		private const int MostNoteLines = 6;

		private const float AdvancedButtonRowHeight = 56f;

		private const float AdvancedButtonHeight = 36f;

		private const float AdvancedButtonPadding = 20f;

		private static readonly Color WarningNoteColor = new Color(1f, 40f / 51f, 20f / 51f);

		private const float WarningNotePadding = 16f;

		private const float WarningNoteSideMargin = 40f;

		private static readonly Color ErrorNoteColor = new Color(1f, 0.41960785f, 0.41960785f);

		private const float ButtonGap = 10f;

		private const float KeycapHeight = 28f;

		private const float KeycapPadding = 8f;

		private const float KeycapGap = 6f;

		private const float KeycapMinWidth = 28f;

		private const float SliderValueWidth = 64f;

		private const float FieldHeight = 28f;

		private const float FieldTextInset = 6f;

		private const float SwatchGap = 8f;

		private const float SwatchInset = 2f;

		private static readonly Color PlainFieldFill = new Color(0f, 0f, 0f, 0.35f);

		private const float ResetLabelPadding = 16f;

		private const int Columns = 3;

		private const float PlateHeight = 104f;

		private const float PlateGap = 14f;

		private const float ViewportMargin = 20f;

		private const float NameSizeScale = 1.25f;

		private const float SubtitleMinScale = 0.6f;

		private const float TextLeft = 104f;

		private const float MedallionSize = 84f;

		private const float DiscFraction = 0.78f;

		private static readonly Color PlateFill = new Color(0.08f, 0.07f, 0.06f, 1f);

		private static readonly Color GlowHidden = new Color(1f, 1f, 1f, 0f);

		private static readonly Color SubtitleColor = new Color(0.62f, 0.69f, 0.66f);

		private static readonly Color DiscColor = new Color(0.16f, 0.24f, 0.24f, 1f);

		private static readonly Color InitialsColor = new Color(0.85f, 0.88f, 0.87f);

		private static readonly Color UnsupportedFrameColor = new Color(0.4f, 0.4f, 0.4f);

		private static readonly Color UnsupportedNameColor = new Color(28f / 51f, 28f / 51f, 28f / 51f);

		private static readonly Color UnsupportedSubtitleColor = new Color(0.47058824f, 0.47058824f, 0.47058824f);

		private static readonly Color UnsupportedDiscColor = new Color(0.16862746f, 0.16862746f, 0.16862746f, 1f);

		private const float UnsupportedMedallionAlpha = 0.6f;

		private RectTransform _area;

		private int _aboveSortingOrder;

		private TMP_Text _pageTitle;

		private ScrollRect _scroll;

		private Vector2 _scrollBottom;

		private float? _listDrop;

		private RectTransform _content;

		private GameObject _headerTemplate;

		private Color _nameColor;

		private HashSet<string> _ownTabs;

		private GameObject _plateTemplate;

		private GameObject _medallionTemplate;

		private GameObject _rowTemplate;

		private GameObject _keyRowTemplate;

		private GameObject _sliderRowTemplate;

		private Color _sliderValueColor;

		private static bool _advancedHeaderFailed;

		private TMP_Text _advancedTitle;

		private RectTransform _advancedButton;

		private readonly GameObject[] FieldTemplates = (GameObject[])(object)new GameObject[2];

		private RectTransform _picker;

		private ColorPickerController _pickerController;

		private RowView _pickerView;

		private Rgba _pickerShown;

		private StagedState _pickerBefore;

		private TMP_Text _pickerHint;

		private KitTooltip _tooltip;

		private KitNote _note;

		private GameObject _allModsButton;

		private Button _applyButton;

		private Button _resetButton;

		private float _resetBaseWidth;

		private float _resetMaxWidth;

		private float _valueFontSize;

		private Color _keyTextColor;

		private GameObject _keycapTemplate;

		private Color _keycapBorderColor;

		private Color _valueColor;

		private Color _pipColor;

		private TMP_FontAsset _titleFont;

		private ModCatalog _catalog;

		private int _view = -1;

		private ModPage _page;

		private readonly List<RowView> Rows = new List<RowView>();

		private int _hoveredRow = -1;

		private bool _invalidNoteShown;

		private readonly List<object> ContentListeners = new List<object>();

		private readonly List<object> ViewListeners = new List<object>();

		private readonly List<object> RetiredListeners = new List<object>();

		private int _listenersRetiredFrame;

		private const float FocusScrollMargin = 24f;

		private const float FocusTooltipIndent = 40f;

		private readonly Dictionary<int, Button> PlateButtons = new Dictionary<int, Button>();

		private Button _reloadPlate;

		private Button _advancedHeaderButton;

		private bool _refreshMenu;

		private Selectable _focusNext;

		private IntPtr _followed;

		private Selectable _lastStop;

		private RowView _typeNext;

		private readonly HashSet<Button> _disableOnTick = new HashSet<Button>();

		internal bool IsActive
		{
			get
			{
				if ((Object)(object)_area != (Object)null)
				{
					return ((Component)_area).gameObject.activeInHierarchy;
				}
				return false;
			}
		}

		internal bool PickerOpen => _pickerView != null;

		internal bool OnModPage => _view != -1;

		internal bool LeaveWouldAsk => LeaveRule.AsksBeforeLeaving(OnModPage, _page?.StagedChanges.Count ?? 0);

		private static bool PadMode => (int)MenuManager.CurrentInputMode != 1;

		public bool Back()
		{
			if (_pickerView != null)
			{
				ClosePicker();
				return true;
			}
			if (_view == -1)
			{
				return false;
			}
			LeavePageThen(ShowList);
			return true;
		}

		internal void LeavePageThen(Action next)
		{
			ClosePicker();
			if (!LeaveWouldAsk)
			{
				next();
				return;
			}
			_tooltip.Hide();
			_hoveredRow = -1;
			KitConfirmDialog.Ask(KitStrings.ApplyChangesMessage, _aboveSortingOrder, delegate
			{
				ApplyPage();
				if (!LeaveWouldAsk)
				{
					next();
				}
			}, next, Plugin.Log);
		}

		public void Tick()
		{
			if (Time.frameCount > _listenersRetiredFrame)
			{
				RetiredListeners.Clear();
			}
			if (_disableOnTick.Count > 0)
			{
				Button[] array = _disableOnTick.ToArray();
				_disableOnTick.Clear();
				Button[] array2 = array;
				foreach (Button val in array2)
				{
					if ((Object)(object)val != (Object)null)
					{
						((Selectable)val).interactable = false;
					}
				}
			}
			if (IsActive)
			{
				TickFocus();
			}
			if (IsActive && _view != -1)
			{
				UpdateTooltip();
				if (Input.GetMouseButtonDown(1) && _hoveredRow >= 0 && Rows[_hoveredRow].Row.IsKeyCapture && !Rows[_hoveredRow].Row.ReadOnly)
				{
					ClearKey(Rows[_hoveredRow]);
				}
				if (_pickerView != null && (Input.GetKeyDown((KeyCode)13) || Input.GetKeyDown((KeyCode)271)))
				{
					HidePicker();
				}
			}
		}

		private void ClearKey(RowView view)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			if (_page.ValueOf(view.Row) == "None")
			{
				return;
			}
			if (!_page.Stage(view.Row, "None"))
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(67, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Clearing '");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(view.Row.Section);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(view.Row.Key);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' was refused: None is not a value this setting accepts.");
				}
				log.LogWarning(val);
			}
			RefreshPage();
		}

		public int Enter()
		{
			_catalog = new ModCatalog(Paths.PluginPath, ModDiscovery.Snapshot());
			Canvas.ForceUpdateCanvases();
			UiParts.Label(_allModsButton.transform).text = ModStrings.Get("button.all_mods");
			UiParts.Label(((Component)_resetButton).transform).text = ModStrings.Get("button.reset_mod");
			ShowList();
			return _catalog.Plates.Count;
		}

		public void Hide()
		{
			KeyCapture.Cancel();
			TextEntry.Abandon();
			ClosePicker();
			_tooltip.Hide();
		}

		private void ShowList()
		{
			int view = _view;
			SetView(-1);
			_pageTitle.text = ModStrings.Get("list.title");
			KitHeader.Add(_headerTemplate, (Transform)(object)_content, ModStrings.Get("header.installed_mods"));
			FillPlates(_catalog.Plates);
			ScrollToTop();
			Button value;
			Button next = (Button)(PlateButtons.TryGetValue(view, out value) ? ((object)value) : ((object)((from p in PlateButtons
				orderby p.Key
				select p.Value).FirstOrDefault() ?? _reloadPlate)));
			FocusAfterViewChange((Selectable)(object)next);
		}

		private void ShowPage(int plateIndex)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			SetView(plateIndex);
			FitResetButton();
			_page = _catalog.Page(plateIndex);
			_pageTitle.text = _page.Name;
			AddPageRows();
			RefreshPage();
			ScrollToTop();
			FocusAfterViewChange((Selectable)(((object)FirstStop()) ?? ((object)(_advancedHeaderButton ?? _allModsButton.GetComponent<Button>()))));
			ManualLogSource log = Plugin.Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(48, 3, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Mod page shown: ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(_page.Name);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_page.Sections.Count);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" sections, ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_page.AdvancedCount);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" advanced settings.");
			}
			log.LogInfo(val);
		}

		private void AddPageRows()
		{
			if (_page.IsBepInEx)
			{
				AddPageNote(ModStrings.Get("page.bepinex_note"));
			}
			foreach (PageSection section in _page.Sections)
			{
				AddSection(section);
			}
			if (!_page.HasAdvanced)
			{
				return;
			}
			if (_advancedHeaderFailed || !TryAddAdvancedHeader())
			{
				if (!_page.AdvancedExpanded)
				{
					_page.ToggleAdvanced();
				}
				_advancedTitle = KitHeader.Add(_headerTemplate, (Transform)(object)_content, AdvancedHeaderText());
			}
			if (!_page.AdvancedExpanded)
			{
				return;
			}
			foreach (PageSection advancedSection in _page.AdvancedSections)
			{
				AddSection(advancedSection);
			}
		}

		private void AddSection(PageSection section)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			if (section.FileHeader != null)
			{
				AddBoxedLine("FileHeader", RichText.Plain(section.FileHeader), KitFieldFrame.RestColor);
			}
			KitHeader.Add(_headerTemplate, (Transform)(object)_content, section.Title);
			foreach (SettingRow row in section.Rows)
			{
				AddRow(row);
			}
		}

		private bool TryAddAdvancedHeader()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: 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_00e7: 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_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Expected O, but got Unknown
			GameObject val = null;
			try
			{
				RectTransform val2 = UiParts.NewRect("AdvancedHeader", (Transform)(object)_content);
				val = ((Component)val2).gameObject;
				val.AddComponent<LayoutElement>().preferredHeight = 56f;
				RectTransform val3 = UiParts.NewRect("Button", (Transform)(object)val2);
				Vector2 val4 = (val3.pivot = new Vector2(0.5f, 0.5f));
				Vector2 anchorMin = (val3.anchorMax = val4);
				val3.anchorMin = anchorMin;
				((Graphic)((Component)val3).gameObject.AddComponent<Image>()).color = PlainFieldFill;
				Image target = KitFieldFrame.Add((Transform)(object)val3);
				TMP_Text component = UiParts.CloneInto(KitHeader.Title(_headerTemplate).transform, (Transform)(object)val3).GetComponent<TMP_Text>();
				UiParts.StripAll(((Component)component).gameObject, "ContentSizeFitter", "LayoutElement");
				UiParts.Stretch(component.rectTransform);
				component.alignment = (TextAlignmentOptions)514;
				component.enableWordWrapping = false;
				((Graphic)component).raycastTarget = false;
				((Graphic)component).color = _nameColor;
				component.enableAutoSizing = true;
				component.fontSizeMax = component.fontSize;
				component.fontSizeMin = component.fontSize * 0.6f;
				Button val7 = FocusButton(((Component)val3).gameObject, (Graphic)(object)target, _nameColor);
				UiParts.Hook(val7, ToggleAdvancedGroup, ViewListeners);
				_advancedHeaderButton = val7;
				_advancedTitle = component;
				_advancedButton = val3;
				ShowAdvancedHeaderText();
				return true;
			}
			catch (Exception ex)
			{
				if ((Object)(object)val != (Object)null)
				{
					val.SetActive(false);
					Object.Destroy((Object)(object)val);
				}
				_advancedTitle = null;
				_advancedButton = null;
				_advancedHeaderButton = null;
				_advancedHeaderFailed = true;
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val8 = new BepInExErrorLogInterpolatedStringHandler(103, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val8).AppendLiteral("The advanced settings header could not be built; advanced settings show expanded under a plain header: ");
					((BepInExLogInterpolatedStringHandler)val8).AppendFormatted<Exception>(ex);
				}
				log.LogError(val8);
				return false;
			}
		}

		private void ShowAdvancedHeaderText()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			string text = AdvancedHeaderText();
			_advancedTitle.text = text;
			if (!((Object)(object)_advancedButton == (Object)null))
			{
				_advancedTitle.fontSize = _advancedTitle.fontSizeMax;
				float num = _advancedTitle.GetPreferredValues(text, float.PositiveInfinity, float.PositiveInfinity).x + 40f;
				Rect rect = _content.rect;
				float num2 = Mathf.Min(num, ((Rect)(ref rect)).width - 40f);
				_advancedButton.sizeDelta = new Vector2(num2, 36f);
			}
		}

		private string AdvancedHeaderText()
		{
			if (_advancedHeaderFailed)
			{
				return ModStrings.Get("page.advanced_header", _page.AdvancedCount);
			}
			if (_page.AdvancedExpanded)
			{
				return ModStrings.Get("page.advanced_hide", _page.AdvancedCount);
			}
			if (_page.HiddenChangeCount <= 0)
			{
				return ModStrings.Get("page.advanced_show", _page.AdvancedCount);
			}
			return ModStrings.Get("page.advanced_show_changed", _page.AdvancedCount, _page.HiddenChangeCount);
		}

		private void ToggleAdvancedGroup()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			_page.ToggleAdvanced();
			Vector2 anchoredPosition = _content.anchoredPosition;
			ClearContent();
			AddPageRows();
			RefreshPage();
			LayoutRebuilder.ForceRebuildLayoutImmediate(_content);
			_content.anchoredPosition = anchoredPosition;
			FocusAfterViewChange((Selectable)(object)_advancedHeaderButton);
		}

		private void AddPageNote(string text)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			AddBoxedLine("PageNote", text, WarningNoteColor);
		}

		private void AddBoxedLine(string name, string text, Color colour)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			//IL_0074: 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_00b1: Expected O, but got Unknown
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			float preferredHeight = _rowTemplate.GetComponent<LayoutElement>().preferredHeight;
			RectTransform val = UiParts.NewRect(name, (Transform)(object)_content);
			VerticalLayoutGroup val2 = ((Component)val).gameObject.AddComponent<VerticalLayoutGroup>();
			((LayoutGroup)val2).padding = new RectOffset(Mathf.RoundToInt(40f), Mathf.RoundToInt(40f), Mathf.RoundToInt(preferredHeight), Mathf.RoundToInt(preferredHeight));
			FitChildren(val2);
			RectTransform val3 = UiParts.NewRect("Box", (Transform)(object)val);
			Image obj = ((Component)val3).gameObject.AddComponent<Image>();
			((Graphic)obj).color = PlainFieldFill;
			((Graphic)obj).raycastTarget = false;
			VerticalLayoutGroup val4 = ((Component)val3).gameObject.AddComponent<VerticalLayoutGroup>();
			int num = Mathf.RoundToInt(16f);
			((LayoutGroup)val4).padding = new RectOffset(num, num, num, num);
			FitChildren(va