Decompiled source of ModConfigs v1.1.1

ModConfigs.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
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.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GUIFramework;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using Valheim.SettingsGui;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: IgnoresAccessChecksTo("assembly_guiutils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: AssemblyCompany("ModConfigs")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.1.0")]
[assembly: AssemblyInformationalVersion("1.1.1")]
[assembly: AssemblyProduct("ModConfigs")]
[assembly: AssemblyTitle("ModConfigs")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.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;
		}
	}
}
namespace ModdedWolfsConfigs
{
	public static class ModdedWolfsConfigsAPI
	{
		public static void OpenConfigPanel()
		{
			ConfigPanelOpener.Open();
		}
	}
	public sealed class ConfigurationManagerAttributes
	{
		public bool? Browsable;

		public bool? IsAdminOnly;

		public bool? IsAdvanced;

		public int? Order;

		public string DispName;

		public string Description;

		public string Category;

		public bool? ReadOnly;

		public bool? HideDefaultButton;

		public object DefaultValue;

		public bool? ShowRangeAsPercent;

		public bool? HideSettingName;
	}
	internal static class ClientLocalBindings
	{
		internal static bool IsBinding(ConfigEntryBase entry)
		{
			if (entry == null)
			{
				return false;
			}
			Type settingType = entry.SettingType;
			if (settingType == null)
			{
				return false;
			}
			if (settingType == typeof(KeyCode) || settingType == typeof(KeyboardShortcut))
			{
				return true;
			}
			return (settingType.FullName ?? string.Empty).IndexOf("KeyboardShortcut", StringComparison.OrdinalIgnoreCase) >= 0;
		}
	}
	internal static class ConfigApply
	{
		internal static event Action<ConfigEntryBase> LocalChanged;

		internal static void PersistAfterLocalChange(ConfigEntryBase entry)
		{
			if (entry == null)
			{
				return;
			}
			try
			{
				ConfigFile configFile = entry.ConfigFile;
				if (configFile != null)
				{
					configFile.Save();
				}
			}
			catch (Exception ex)
			{
				ModdedWolfsConfigsPlugin.Log.LogWarning((object)("Failed to save config: " + ex.Message));
			}
			ConfigDiscovery.RefreshRuntimeValues(entry.ConfigFile);
			try
			{
				ConfigApply.LocalChanged?.Invoke(entry);
			}
			catch (Exception ex2)
			{
				ModdedWolfsConfigsPlugin.Log.LogWarning((object)("Config change listener failed: " + ex2.Message));
			}
		}
	}
	internal sealed class DiscoveredPlugin
	{
		public string Guid;

		public string Name;

		public string Version;

		public BaseUnityPlugin Plugin;

		public List<DiscoveredSection> Sections = new List<DiscoveredSection>();
	}
	internal sealed class DiscoveredSection
	{
		public string Name;

		public List<ConfigEntryBase> Entries = new List<ConfigEntryBase>();
	}
	internal static class ConfigDiscovery
	{
		private sealed class ReferenceComparer<T> : IEqualityComparer<T> where T : class
		{
			internal static readonly ReferenceComparer<T> Instance = new ReferenceComparer<T>();

			public bool Equals(T x, T y)
			{
				return x == y;
			}

			public int GetHashCode(T obj)
			{
				return RuntimeHelpers.GetHashCode(obj);
			}
		}

		private static readonly HashSet<string> HiddenConfigKeys = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "LastSelectedModGuid", "ShowMenuButton" };

		private static readonly Dictionary<ConfigFile, MethodInfo> RuntimeRefreshers = new Dictionary<ConfigFile, MethodInfo>(ReferenceComparer<ConfigFile>.Instance);

		private static bool _loggedHiddenKeyFilter;

		private static List<DiscoveredPlugin> _cache;

		private static bool _cacheValid;

		private static bool _cachedHideSelf;

		private static bool _cachedShowAdvanced;

		internal static void InvalidateCache()
		{
			_cacheValid = false;
			_cache = null;
		}

		internal static bool IsHiddenConfigKey(string key)
		{
			if (!string.IsNullOrEmpty(key))
			{
				return HiddenConfigKeys.Contains(key);
			}
			return false;
		}

		internal static bool ShouldRenderEntry(ConfigEntryBase entry)
		{
			if (((entry != null) ? entry.Definition : null) == (ConfigDefinition)null)
			{
				return false;
			}
			return !IsHiddenConfigKey(entry.Definition.Key);
		}

		internal static List<DiscoveredPlugin> Discover()
		{
			bool flag = ModdedWolfsConfigsPlugin.HideSelfFromList != null && ModdedWolfsConfigsPlugin.HideSelfFromList.Value;
			bool flag2 = ModdedWolfsConfigsPlugin.ShowAdvancedSettings != null && ModdedWolfsConfigsPlugin.ShowAdvancedSettings.Value;
			if (_cacheValid && _cache != null && _cachedHideSelf == flag && _cachedShowAdvanced == flag2)
			{
				return _cache;
			}
			List<DiscoveredPlugin> result = (_cache = DiscoverUncached());
			_cacheValid = true;
			_cachedHideSelf = flag;
			_cachedShowAdvanced = flag2;
			return result;
		}

		private static List<DiscoveredPlugin> DiscoverUncached()
		{
			List<DiscoveredPlugin> list = new List<DiscoveredPlugin>();
			IEnumerable<KeyValuePair<string, PluginInfo>> enumerable;
			try
			{
				enumerable = Chainloader.PluginInfos.Where(delegate(KeyValuePair<string, PluginInfo> p)
				{
					PluginInfo value5 = p.Value;
					return ((value5 != null) ? value5.Metadata : null) != null;
				}).OrderBy<KeyValuePair<string, PluginInfo>, string>((KeyValuePair<string, PluginInfo> p) => p.Value.Metadata.Name ?? p.Value.Metadata.GUID ?? p.Key ?? string.Empty, StringComparer.OrdinalIgnoreCase).ToList();
			}
			catch (Exception ex)
			{
				ModdedWolfsConfigsPlugin.Log.LogWarning((object)("ConfigDiscovery: failed to enumerate plugins: " + ex.Message));
				return list;
			}
			HashSet<ConfigFile> hashSet = new HashSet<ConfigFile>(ReferenceComparer<ConfigFile>.Instance);
			foreach (KeyValuePair<string, PluginInfo> item in enumerable)
			{
				try
				{
					PluginInfo value = item.Value;
					object obj;
					if (value == null)
					{
						obj = null;
					}
					else
					{
						BaseUnityPlugin instance = value.Instance;
						obj = ((instance != null) ? instance.Config : null);
					}
					ConfigFile val = (ConfigFile)obj;
					if (val != null)
					{
						hashSet.Add(val);
					}
				}
				catch
				{
				}
			}
			Dictionary<BaseUnityPlugin, List<ConfigFile>> dictionary = MapAssemblyConfigFiles(enumerable, hashSet);
			foreach (KeyValuePair<string, PluginInfo> item2 in enumerable)
			{
				PluginInfo value2 = item2.Value;
				string text = item2.Key ?? "(unknown)";
				try
				{
					if (((value2 != null) ? value2.Metadata : null) == null)
					{
						continue;
					}
					text = ((!string.IsNullOrEmpty(value2.Metadata.Name)) ? (value2.Metadata.Name + " (" + value2.Metadata.GUID + ")") : (value2.Metadata.GUID ?? item2.Key ?? "(unknown)"));
					BaseUnityPlugin instance2 = value2.Instance;
					if ((Object)(object)instance2 == (Object)null || (ModdedWolfsConfigsPlugin.HideSelfFromList.Value && value2.Metadata.GUID == "ModdedWolf.ModConfigs"))
					{
						continue;
					}
					List<ConfigFile> list2 = CollectConfigFiles(instance2, hashSet);
					if (dictionary.TryGetValue(instance2, out var value3))
					{
						foreach (ConfigFile item3 in value3)
						{
							if (!list2.Contains(item3))
							{
								list2.Add(item3);
							}
						}
					}
					if (list2.Count == 0)
					{
						continue;
					}
					Dictionary<string, DiscoveredSection> dictionary2 = new Dictionary<string, DiscoveredSection>(StringComparer.OrdinalIgnoreCase);
					HashSet<ConfigEntryBase> hashSet2 = new HashSet<ConfigEntryBase>(ReferenceComparer<ConfigEntryBase>.Instance);
					foreach (ConfigFile item4 in list2)
					{
						foreach (ConfigDefinition key in item4.Keys)
						{
							if (key == (ConfigDefinition)null)
							{
								continue;
							}
							if (IsHiddenConfigKey(key.Key))
							{
								if (!_loggedHiddenKeyFilter && value2.Metadata.GUID == "ModdedWolf.ModConfigs")
								{
									_loggedHiddenKeyFilter = true;
									ModdedWolfsConfigsPlugin.Log.LogInfo((object)("ConfigDiscovery: hiding internal key '" + key.Key + "' from UI (still stored in cfg)."));
								}
								continue;
							}
							ConfigEntryBase val2 = item4[key];
							if (!(((val2 != null) ? val2.Definition : null) == (ConfigDefinition)null) && hashSet2.Add(val2) && IsBrowsable(val2))
							{
								string text2 = key.Section ?? string.Empty;
								if (!dictionary2.TryGetValue(text2, out var value4))
								{
									value4 = (dictionary2[text2] = new DiscoveredSection
									{
										Name = text2
									});
								}
								value4.Entries.Add(val2);
							}
						}
					}
					if (dictionary2.Count == 0)
					{
						continue;
					}
					DiscoveredPlugin discoveredPlugin = new DiscoveredPlugin
					{
						Guid = (value2.Metadata.GUID ?? item2.Key ?? string.Empty),
						Name = (value2.Metadata.Name ?? value2.Metadata.GUID ?? item2.Key ?? "Unknown"),
						Version = (value2.Metadata.Version?.ToString() ?? ""),
						Plugin = instance2
					};
					foreach (DiscoveredSection item5 in dictionary2.Values.OrderByDescending(SectionHasBinding).ThenByDescending((DiscoveredSection s) => string.Equals(s.Name, "General", StringComparison.OrdinalIgnoreCase)).ThenBy<DiscoveredSection, string>((DiscoveredSection s) => s.Name ?? string.Empty, StringComparer.OrdinalIgnoreCase))
					{
						item5.Entries = item5.Entries.OrderByDescending(ClientLocalBindings.IsBinding).ThenByDescending(GetOrder).ThenBy<ConfigEntryBase, string>(delegate(ConfigEntryBase e)
						{
							ConfigDefinition definition = e.Definition;
							return ((definition != null) ? definition.Key : null) ?? string.Empty;
						}, StringComparer.OrdinalIgnoreCase)
							.ToList();
						discoveredPlugin.Sections.Add(item5);
					}
					list.Add(discoveredPlugin);
				}
				catch (Exception ex2)
				{
					ModdedWolfsConfigsPlugin.Log.LogWarning((object)("ConfigDiscovery: skipped plugin '" + text + "': " + ex2.Message));
				}
			}
			return list;
		}

		private static List<ConfigFile> CollectConfigFiles(BaseUnityPlugin plugin, HashSet<ConfigFile> builtInConfigs)
		{
			List<ConfigFile> list = new List<ConfigFile>();
			HashSet<ConfigFile> hashSet = new HashSet<ConfigFile>(ReferenceComparer<ConfigFile>.Instance);
			ConfigFile config = plugin.Config;
			if (config != null && hashSet.Add(config))
			{
				list.Add(config);
			}
			for (Type type = ((object)plugin).GetType(); type != null && type != typeof(BaseUnityPlugin); type = type.BaseType)
			{
				FieldInfo[] fields;
				try
				{
					fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
				catch
				{
					continue;
				}
				FieldInfo[] array = fields;
				foreach (FieldInfo fieldInfo in array)
				{
					ConfigFile val = null;
					try
					{
						object obj2 = (fieldInfo.IsStatic ? null : plugin);
						if (typeof(ConfigFile).IsAssignableFrom(fieldInfo.FieldType))
						{
							object? value = fieldInfo.GetValue(obj2);
							val = (ConfigFile)((value is ConfigFile) ? value : null);
						}
						else if (typeof(ConfigEntryBase).IsAssignableFrom(fieldInfo.FieldType))
						{
							object? value2 = fieldInfo.GetValue(obj2);
							object? obj3 = ((value2 is ConfigEntryBase) ? value2 : null);
							val = ((obj3 != null) ? ((ConfigEntryBase)obj3).ConfigFile : null);
						}
					}
					catch
					{
						continue;
					}
					if (val != null && !builtInConfigs.Contains(val) && hashSet.Add(val))
					{
						list.Add(val);
					}
				}
			}
			return list;
		}

		private static Dictionary<BaseUnityPlugin, List<ConfigFile>> MapAssemblyConfigFiles(IEnumerable<KeyValuePair<string, PluginInfo>> plugins, HashSet<ConfigFile> builtInConfigs)
		{
			Dictionary<BaseUnityPlugin, List<ConfigFile>> dictionary = new Dictionary<BaseUnityPlugin, List<ConfigFile>>(ReferenceComparer<BaseUnityPlugin>.Instance);
			Dictionary<Assembly, List<BaseUnityPlugin>> dictionary2 = new Dictionary<Assembly, List<BaseUnityPlugin>>();
			foreach (KeyValuePair<string, PluginInfo> plugin in plugins)
			{
				BaseUnityPlugin val;
				try
				{
					PluginInfo value = plugin.Value;
					val = ((value != null) ? value.Instance : null);
				}
				catch
				{
					continue;
				}
				if (!((Object)(object)val == (Object)null))
				{
					Assembly assembly = ((object)val).GetType().Assembly;
					if (!dictionary2.TryGetValue(assembly, out var value2))
					{
						value2 = (dictionary2[assembly] = new List<BaseUnityPlugin>());
					}
					value2.Add(val);
				}
			}
			foreach (KeyValuePair<Assembly, List<BaseUnityPlugin>> item in dictionary2)
			{
				List<ConfigFile> list2;
				try
				{
					list2 = ScanAssemblyStaticConfigFiles(item.Key);
				}
				catch (Exception ex)
				{
					ModdedWolfsConfigsPlugin.Log.LogWarning((object)("ConfigDiscovery: failed to scan " + item.Key.GetName().Name + ": " + ex.Message));
					continue;
				}
				if (list2.Count == 0)
				{
					continue;
				}
				MethodInfo methodInfo = null;
				bool flag = false;
				foreach (ConfigFile item2 in list2)
				{
					if (builtInConfigs.Contains(item2))
					{
						continue;
					}
					BaseUnityPlugin val2 = ((item.Value.Count == 1) ? item.Value[0] : MatchOwnerByFileName(item.Value, item2));
					if ((Object)(object)val2 == (Object)null)
					{
						continue;
					}
					if (!dictionary.TryGetValue(val2, out var value3))
					{
						value3 = (dictionary[val2] = new List<ConfigFile>());
					}
					if (!value3.Contains(item2))
					{
						value3.Add(item2);
					}
					if (!flag)
					{
						methodInfo = FindRuntimeRefresher(item.Key);
						flag = true;
					}
					if (methodInfo != null)
					{
						lock (RuntimeRefreshers)
						{
							RuntimeRefreshers[item2] = methodInfo;
						}
					}
				}
			}
			return dictionary;
		}

		private static List<ConfigFile> ScanAssemblyStaticConfigFiles(Assembly assembly)
		{
			List<ConfigFile> list = new List<ConfigFile>();
			HashSet<ConfigFile> hashSet = new HashSet<ConfigFile>(ReferenceComparer<ConfigFile>.Instance);
			foreach (Type loadableType in GetLoadableTypes(assembly))
			{
				FieldInfo[] fields;
				try
				{
					if (loadableType == null || loadableType.ContainsGenericParameters || typeof(BaseUnityPlugin).IsAssignableFrom(loadableType) || loadableType.IsDefined(typeof(CompilerGeneratedAttribute), inherit: false))
					{
						continue;
					}
					fields = loadableType.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					goto IL_0076;
				}
				catch
				{
				}
				continue;
				IL_0076:
				FieldInfo[] array = fields;
				foreach (FieldInfo fieldInfo in array)
				{
					ConfigFile val = null;
					try
					{
						if (typeof(ConfigFile).IsAssignableFrom(fieldInfo.FieldType))
						{
							object? value = fieldInfo.GetValue(null);
							val = (ConfigFile)((value is ConfigFile) ? value : null);
						}
						else if (typeof(ConfigEntryBase).IsAssignableFrom(fieldInfo.FieldType))
						{
							object? value2 = fieldInfo.GetValue(null);
							object? obj2 = ((value2 is ConfigEntryBase) ? value2 : null);
							val = ((obj2 != null) ? ((ConfigEntryBase)obj2).ConfigFile : null);
						}
					}
					catch
					{
						continue;
					}
					if (val != null && hashSet.Add(val))
					{
						list.Add(val);
					}
				}
			}
			return list;
		}

		private static IEnumerable<Type> GetLoadableTypes(Assembly assembly)
		{
			try
			{
				return assembly.GetTypes();
			}
			catch (ReflectionTypeLoadException ex)
			{
				return ex.Types.Where((Type t) => t != null);
			}
			catch
			{
				return Array.Empty<Type>();
			}
		}

		private static BaseUnityPlugin MatchOwnerByFileName(List<BaseUnityPlugin> owners, ConfigFile file)
		{
			string text;
			try
			{
				text = Path.GetFileNameWithoutExtension(file.ConfigFilePath) ?? string.Empty;
			}
			catch
			{
				return null;
			}
			BaseUnityPlugin val = null;
			foreach (BaseUnityPlugin owner in owners)
			{
				PluginInfo info = owner.Info;
				BepInPlugin val2 = ((info != null) ? info.Metadata : null);
				if (val2 != null)
				{
					if (string.Equals(text, val2.Name, StringComparison.OrdinalIgnoreCase) || string.Equals(text, val2.GUID, StringComparison.OrdinalIgnoreCase))
					{
						return owner;
					}
					if ((Object)(object)val == (Object)null && !string.IsNullOrEmpty(val2.Name) && text.IndexOf(val2.Name, StringComparison.OrdinalIgnoreCase) >= 0)
					{
						val = owner;
					}
				}
			}
			return val;
		}

		private static MethodInfo FindRuntimeRefresher(Assembly assembly)
		{
			MethodInfo methodInfo = null;
			foreach (Type loadableType in GetLoadableTypes(assembly))
			{
				MethodInfo method;
				try
				{
					if (loadableType == null || loadableType.ContainsGenericParameters)
					{
						continue;
					}
					method = loadableType.GetMethod("getValues", BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
					goto IL_0044;
				}
				catch
				{
				}
				continue;
				IL_0044:
				if (!(method == null))
				{
					if (methodInfo != null)
					{
						return null;
					}
					methodInfo = method;
				}
			}
			return methodInfo;
		}

		internal static void RefreshRuntimeValues(ConfigFile file)
		{
			if (file == null)
			{
				return;
			}
			MethodInfo value;
			lock (RuntimeRefreshers)
			{
				if (!RuntimeRefreshers.TryGetValue(file, out value))
				{
					return;
				}
			}
			try
			{
				value.Invoke(null, null);
			}
			catch (Exception ex)
			{
				ModdedWolfsConfigsPlugin.Log.LogWarning((object)("ConfigDiscovery: " + value.DeclaringType?.FullName + "." + value.Name + " failed: " + (ex.InnerException?.Message ?? ex.Message)));
			}
		}

		private static bool IsBrowsable(ConfigEntryBase entry)
		{
			if (((entry != null) ? entry.Definition : null) == (ConfigDefinition)null)
			{
				return false;
			}
			if (IsHiddenConfigKey(entry.Definition.Key))
			{
				return false;
			}
			ConfigDescription description = entry.Description;
			object[] array = ((description != null) ? description.Tags : null);
			if (array == null)
			{
				return true;
			}
			foreach (object obj in array)
			{
				if (obj == null)
				{
					continue;
				}
				if (obj is ConfigurationManagerAttributes { Browsable: var browsable } configurationManagerAttributes)
				{
					if (browsable == false)
					{
						return false;
					}
					if (configurationManagerAttributes.IsAdvanced == true && !ModdedWolfsConfigsPlugin.ShowAdvancedSettings.Value)
					{
						return false;
					}
					continue;
				}
				PropertyInfo property = obj.GetType().GetProperty("Browsable", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null && property.PropertyType == typeof(bool?) && (bool?)property.GetValue(obj, null) == false)
				{
					return false;
				}
				PropertyInfo property2 = obj.GetType().GetProperty("IsAdvanced", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property2 != null && property2.PropertyType == typeof(bool?) && (bool?)property2.GetValue(obj, null) == true && !ModdedWolfsConfigsPlugin.ShowAdvancedSettings.Value)
				{
					return false;
				}
			}
			return true;
		}

		private static bool SectionHasBinding(DiscoveredSection section)
		{
			if (section?.Entries == null)
			{
				return false;
			}
			for (int i = 0; i < section.Entries.Count; i++)
			{
				if (ClientLocalBindings.IsBinding(section.Entries[i]))
				{
					return true;
				}
			}
			return false;
		}

		private static int GetOrder(ConfigEntryBase entry)
		{
			object obj;
			if (entry == null)
			{
				obj = null;
			}
			else
			{
				ConfigDescription description = entry.Description;
				obj = ((description != null) ? description.Tags : null);
			}
			object[] array = (object[])obj;
			if (array == null)
			{
				return 0;
			}
			foreach (object obj2 in array)
			{
				if (obj2 is ConfigurationManagerAttributes configurationManagerAttributes && configurationManagerAttributes.Order.HasValue)
				{
					return configurationManagerAttributes.Order.Value;
				}
				PropertyInfo propertyInfo = obj2?.GetType().GetProperty("Order", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (propertyInfo != null && propertyInfo.PropertyType == typeof(int?))
				{
					int? num = (int?)propertyInfo.GetValue(obj2, null);
					if (num.HasValue)
					{
						return num.Value;
					}
				}
				FieldInfo fieldInfo = obj2?.GetType().GetField("Order", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (fieldInfo != null && fieldInfo.FieldType == typeof(int?))
				{
					int? num2 = (int?)fieldInfo.GetValue(obj2);
					if (num2.HasValue)
					{
						return num2.Value;
					}
				}
			}
			return 0;
		}

		internal static string GetDisplayName(ConfigEntryBase entry)
		{
			object obj;
			if (entry == null)
			{
				obj = null;
			}
			else
			{
				ConfigDescription description = entry.Description;
				obj = ((description != null) ? description.Tags : null);
			}
			object[] array = (object[])obj;
			if (array != null)
			{
				for (int i = 0; i < array.Length; i++)
				{
					if (array[i] is ConfigurationManagerAttributes configurationManagerAttributes && !string.IsNullOrEmpty(configurationManagerAttributes.DispName))
					{
						return configurationManagerAttributes.DispName;
					}
					PropertyInfo propertyInfo = array[i]?.GetType().GetProperty("DispName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (propertyInfo != null && propertyInfo.PropertyType == typeof(string))
					{
						string text = propertyInfo.GetValue(array[i], null) as string;
						if (!string.IsNullOrEmpty(text))
						{
							return text;
						}
					}
					FieldInfo fieldInfo = array[i]?.GetType().GetField("DispName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (fieldInfo != null && fieldInfo.FieldType == typeof(string))
					{
						string text2 = fieldInfo.GetValue(array[i]) as string;
						if (!string.IsNullOrEmpty(text2))
						{
							return text2;
						}
					}
				}
			}
			object obj2;
			if (entry == null)
			{
				obj2 = null;
			}
			else
			{
				ConfigDefinition definition = entry.Definition;
				obj2 = ((definition != null) ? definition.Key : null);
			}
			if (obj2 == null)
			{
				obj2 = string.Empty;
			}
			return (string)obj2;
		}
	}
	internal static class ConfigEntryAccess
	{
		internal static bool IsReadOnly(ConfigEntryBase entry)
		{
			object obj;
			if (entry == null)
			{
				obj = null;
			}
			else
			{
				ConfigDescription description = entry.Description;
				obj = ((description != null) ? description.Tags : null);
			}
			object[] array = (object[])obj;
			if (array == null || array.Length == 0)
			{
				return false;
			}
			bool? flag = null;
			bool? flag2 = null;
			foreach (object obj2 in array)
			{
				if (obj2 == null)
				{
					continue;
				}
				if (obj2 is ConfigurationManagerAttributes configurationManagerAttributes)
				{
					if (configurationManagerAttributes.ReadOnly.HasValue)
					{
						flag = configurationManagerAttributes.ReadOnly;
					}
					if (configurationManagerAttributes.IsAdminOnly.HasValue)
					{
						flag2 = configurationManagerAttributes.IsAdminOnly;
					}
					continue;
				}
				bool? nullableBoolProperty = GetNullableBoolProperty(obj2, "ReadOnly");
				if (nullableBoolProperty.HasValue)
				{
					flag = nullableBoolProperty;
				}
				bool? nullableBoolProperty2 = GetNullableBoolProperty(obj2, "IsAdminOnly");
				if (nullableBoolProperty2.HasValue)
				{
					flag2 = nullableBoolProperty2;
				}
			}
			if (flag.HasValue)
			{
				return flag.Value;
			}
			return flag2 == true;
		}

		internal static bool HidesSettingName(ConfigEntryBase entry)
		{
			object obj;
			if (entry == null)
			{
				obj = null;
			}
			else
			{
				ConfigDescription description = entry.Description;
				obj = ((description != null) ? description.Tags : null);
			}
			object[] array = (object[])obj;
			if (array == null)
			{
				return false;
			}
			foreach (object obj2 in array)
			{
				if (obj2 != null)
				{
					if (obj2 is ConfigurationManagerAttributes configurationManagerAttributes && configurationManagerAttributes.HideSettingName == true)
					{
						return true;
					}
					if (GetNullableBoolMember(obj2, "HideSettingName") == true)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static bool? GetNullableBoolProperty(object tag, string name)
		{
			return GetNullableBoolMember(tag, name);
		}

		private static bool? GetNullableBoolMember(object tag, string name)
		{
			Type type = tag.GetType();
			PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (property != null && property.PropertyType == typeof(bool?))
			{
				return (bool?)property.GetValue(tag, null);
			}
			FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null && field.FieldType == typeof(bool?))
			{
				return (bool?)field.GetValue(tag);
			}
			return null;
		}
	}
	internal static class GlobalPresetStore
	{
		internal const int SlotCount = 5;

		private const string FileName = "_Global.txt";

		private static bool _loaded;

		private static int _active;

		private static readonly Dictionary<string, string>[] Slots = new Dictionary<string, string>[6];

		private static readonly string[] Names = new string[6];

		private static readonly string[] Descs = new string[6];

		private static string FilePath => Path.Combine(PresetStore.FolderPath, "_Global.txt");

		internal static event Action Changed;

		internal static int GetActive()
		{
			EnsureLoaded();
			return _active;
		}

		internal static void SetActive(int slot)
		{
			EnsureLoaded();
			_active = (PresetStore.IsValidSlot(slot) ? slot : 0);
			WriteAndNotify();
		}

		internal static bool HasSlot(int slot)
		{
			EnsureLoaded();
			if (PresetStore.IsValidSlot(slot))
			{
				return Slots[slot] != null;
			}
			return false;
		}

		internal static string GetName(int slot)
		{
			EnsureLoaded();
			if (!PresetStore.IsValidSlot(slot))
			{
				return null;
			}
			return Names[slot];
		}

		internal static string GetDescription(int slot)
		{
			EnsureLoaded();
			if (!PresetStore.IsValidSlot(slot))
			{
				return null;
			}
			return Descs[slot];
		}

		internal static string DisplayName(int slot)
		{
			string name = GetName(slot);
			if (!string.IsNullOrWhiteSpace(name))
			{
				return name;
			}
			return "Preset " + slot;
		}

		internal static void SetMeta(int slot, string name, string description)
		{
			EnsureLoaded();
			if (PresetStore.IsValidSlot(slot))
			{
				Names[slot] = PresetStore.CleanMeta(name, 20);
				Descs[slot] = PresetStore.CleanMeta(description, 120);
				WriteAndNotify();
			}
		}

		internal static void Delete(int slot)
		{
			EnsureLoaded();
			if (PresetStore.IsValidSlot(slot))
			{
				Slots[slot] = null;
				ConfigEntry<bool> keepGlobalPresetLabel = ModdedWolfsConfigsPlugin.KeepGlobalPresetLabel;
				if (keepGlobalPresetLabel == null || !keepGlobalPresetLabel.Value)
				{
					Names[slot] = null;
					Descs[slot] = null;
				}
				if (_active == slot)
				{
					_active = 0;
				}
				WriteAndNotify();
				ModdedWolfsConfigsPlugin.Log.LogInfo((object)$"Deleted global preset {slot}.");
			}
		}

		internal static void Capture(int slot)
		{
			EnsureLoaded();
			if (!PresetStore.IsValidSlot(slot))
			{
				return;
			}
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal);
			HashSet<ConfigFile> hashSet = new HashSet<ConfigFile>();
			List<DiscoveredPlugin> list = ConfigDiscovery.Discover();
			for (int i = 0; i < list.Count; i++)
			{
				DiscoveredPlugin plugin = list[i];
				foreach (ConfigEntryBase item in PresetStore.EnumerateEntries(plugin))
				{
					try
					{
						dictionary[KeyFor(plugin, item)] = item.GetSerializedValue() ?? string.Empty;
						if (item.ConfigFile != null)
						{
							hashSet.Add(item.ConfigFile);
						}
					}
					catch (Exception ex)
					{
						ModdedWolfsConfigsPlugin.Log.LogWarning((object)$"Global preset capture skipped {item.Definition}: {ex.Message}");
					}
				}
			}
			foreach (ConfigFile item2 in hashSet)
			{
				try
				{
					item2.Save();
				}
				catch (Exception ex2)
				{
					ModdedWolfsConfigsPlugin.Log.LogWarning((object)("Failed to save config: " + ex2.Message));
				}
			}
			Slots[slot] = dictionary;
			_active = slot;
			WriteAndNotify();
			ModdedWolfsConfigsPlugin.Log.LogInfo((object)$"Saved {dictionary.Count} setting(s) from {list.Count} mod(s) to global preset {slot}.");
		}

		internal static void Apply(int slot)
		{
			EnsureLoaded();
			if (!HasSlot(slot))
			{
				return;
			}
			Dictionary<string, string> dictionary = Slots[slot];
			Dictionary<ConfigFile, bool> dictionary2 = new Dictionary<ConfigFile, bool>();
			int num = 0;
			try
			{
				List<DiscoveredPlugin> list = ConfigDiscovery.Discover();
				for (int i = 0; i < list.Count; i++)
				{
					DiscoveredPlugin plugin = list[i];
					foreach (ConfigEntryBase item in PresetStore.EnumerateEntries(plugin))
					{
						if (!dictionary.TryGetValue(KeyFor(plugin, item), out var value))
						{
							continue;
						}
						ConfigFile configFile = item.ConfigFile;
						if (configFile != null && !dictionary2.ContainsKey(configFile))
						{
							dictionary2[configFile] = configFile.SaveOnConfigSet;
							configFile.SaveOnConfigSet = false;
						}
						try
						{
							if (!string.Equals(item.GetSerializedValue(), value, StringComparison.Ordinal))
							{
								item.SetSerializedValue(value);
							}
							num++;
						}
						catch (Exception ex)
						{
							ModdedWolfsConfigsPlugin.Log.LogWarning((object)$"Global preset apply skipped {item.Definition}: {ex.Message}");
						}
					}
				}
			}
			finally
			{
				foreach (KeyValuePair<ConfigFile, bool> item2 in dictionary2)
				{
					item2.Key.SaveOnConfigSet = item2.Value;
					try
					{
						item2.Key.Save();
					}
					catch (Exception ex2)
					{
						ModdedWolfsConfigsPlugin.Log.LogWarning((object)("Failed to save config: " + ex2.Message));
					}
					ConfigDiscovery.RefreshRuntimeValues(item2.Key);
				}
			}
			_active = slot;
			WriteAndNotify();
			ModdedWolfsConfigsPlugin.Log.LogInfo((object)$"Loaded global preset {slot} ({num} setting(s)).");
		}

		internal static bool IsModified(int slot)
		{
			if (!HasSlot(slot))
			{
				return false;
			}
			Dictionary<string, string> dictionary = Slots[slot];
			List<DiscoveredPlugin> list = ConfigDiscovery.Discover();
			for (int i = 0; i < list.Count; i++)
			{
				DiscoveredPlugin plugin = list[i];
				foreach (ConfigEntryBase item in PresetStore.EnumerateEntries(plugin))
				{
					if (dictionary.TryGetValue(KeyFor(plugin, item), out var value))
					{
						string a;
						try
						{
							a = item.GetSerializedValue() ?? string.Empty;
						}
						catch
						{
							continue;
						}
						if (!string.Equals(a, value, StringComparison.Ordinal))
						{
							return true;
						}
					}
				}
			}
			return false;
		}

		private static string KeyFor(DiscoveredPlugin plugin, ConfigEntryBase entry)
		{
			return plugin.Guid + "\t" + PresetStore.KeyFor(entry);
		}

		private static void EnsureLoaded()
		{
			if (_loaded)
			{
				return;
			}
			_loaded = true;
			string filePath = FilePath;
			if (!File.Exists(filePath))
			{
				return;
			}
			try
			{
				Dictionary<string, string> dictionary = null;
				string[] array = File.ReadAllLines(filePath, Encoding.UTF8);
				for (int i = 0; i < array.Length; i++)
				{
					string text = array[i].TrimEnd(new char[1] { '\r' });
					if (text.Length == 0)
					{
						continue;
					}
					if (text.StartsWith("active=", StringComparison.OrdinalIgnoreCase))
					{
						int.TryParse(text.Substring(7), out var result);
						_active = (PresetStore.IsValidSlot(result) ? result : 0);
					}
					else
					{
						if (PresetStore.TryParseMetaLine(text, Names, Descs))
						{
							continue;
						}
						if (text.StartsWith("[Preset", StringComparison.OrdinalIgnoreCase) && text.EndsWith("]"))
						{
							dictionary = null;
							if (int.TryParse(text.Substring(7, text.Length - 8), out var result2) && PresetStore.IsValidSlot(result2))
							{
								dictionary = new Dictionary<string, string>(StringComparer.Ordinal);
								Slots[result2] = dictionary;
							}
						}
						else if (dictionary != null)
						{
							string[] array2 = text.Split(new char[1] { '\t' });
							if (array2.Length == 4)
							{
								dictionary[PresetStore.Unescape(array2[0]) + "\t" + PresetStore.Unescape(array2[1]) + "\t" + PresetStore.Unescape(array2[2])] = PresetStore.Unescape(array2[3]);
							}
						}
					}
				}
			}
			catch (Exception ex)
			{
				ModdedWolfsConfigsPlugin.Log.LogWarning((object)("Failed to read global presets: " + ex.Message));
			}
		}

		private static void WriteAndNotify()
		{
			Write();
			try
			{
				GlobalPresetStore.Changed?.Invoke();
			}
			catch (Exception ex)
			{
				ModdedWolfsConfigsPlugin.Log.LogWarning((object)("Global preset listener failed: " + ex.Message));
			}
		}

		private static void Write()
		{
			try
			{
				string filePath = FilePath;
				Directory.CreateDirectory(Path.GetDirectoryName(filePath));
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.Append("active=").Append(_active).Append('\n');
				PresetStore.AppendMetaLines(stringBuilder, Names, Descs);
				for (int i = 1; i <= 5; i++)
				{
					Dictionary<string, string> dictionary = Slots[i];
					if (dictionary == null)
					{
						continue;
					}
					stringBuilder.Append("[Preset").Append(i).Append("]\n");
					foreach (KeyValuePair<string, string> item in dictionary)
					{
						string[] array = item.Key.Split(new char[1] { '\t' }, 3);
						if (array.Length == 3)
						{
							stringBuilder.Append(PresetStore.Escape(array[0])).Append('\t').Append(PresetStore.Escape(array[1]))
								.Append('\t')
								.Append(PresetStore.Escape(array[2]))
								.Append('\t')
								.Append(PresetStore.Escape(item.Value))
								.Append('\n');
						}
					}
				}
				File.WriteAllText(filePath, stringBuilder.ToString(), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
			}
			catch (Exception ex)
			{
				ModdedWolfsConfigsPlugin.Log.LogWarning((object)("Failed to write global presets: " + ex.Message));
			}
		}
	}
	internal static class PresetStore
	{
		private sealed class ModPresets
		{
			public int Active;

			public readonly Dictionary<string, string>[] Slots = new Dictionary<string, string>[6];

			public readonly string[] Names = new string[6];

			public readonly string[] Descs = new string[6];
		}

		internal const int SlotCount = 5;

		private const string FolderName = "ModdedWolf.ModConfigs.Presets";

		internal const int NameMaxLength = 20;

		internal const int DescriptionMaxLength = 120;

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

		internal static string FolderPath => Path.Combine(Paths.ConfigPath, "ModdedWolf.ModConfigs.Presets");

		internal static int GetActive(string guid)
		{
			return Load(guid)?.Active ?? 0;
		}

		internal static void SetActive(string guid, int slot)
		{
			ModPresets modPresets = Load(guid);
			if (modPresets != null)
			{
				modPresets.Active = (IsValidSlot(slot) ? slot : 0);
				Write(guid, modPresets);
			}
		}

		internal static bool HasSlot(string guid, int slot)
		{
			ModPresets modPresets = Load(guid);
			if (modPresets != null && IsValidSlot(slot))
			{
				return modPresets.Slots[slot] != null;
			}
			return false;
		}

		internal static string GetName(string guid, int slot)
		{
			ModPresets modPresets = Load(guid);
			if (modPresets == null || !IsValidSlot(slot))
			{
				return null;
			}
			return modPresets.Names[slot];
		}

		internal static string GetDescription(string guid, int slot)
		{
			ModPresets modPresets = Load(guid);
			if (modPresets == null || !IsValidSlot(slot))
			{
				return null;
			}
			return modPresets.Descs[slot];
		}

		internal static string DisplayName(string guid, int slot)
		{
			string name = GetName(guid, slot);
			if (!string.IsNullOrWhiteSpace(name))
			{
				return name;
			}
			return "Preset " + slot;
		}

		internal static void SetMeta(string guid, int slot, string name, string description)
		{
			ModPresets modPresets = Load(guid);
			if (modPresets != null && IsValidSlot(slot))
			{
				modPresets.Names[slot] = CleanMeta(name, 20);
				modPresets.Descs[slot] = CleanMeta(description, 120);
				Write(guid, modPresets);
			}
		}

		internal static string CleanMeta(string value, int maxLength)
		{
			if (string.IsNullOrWhiteSpace(value))
			{
				return null;
			}
			string text = value.Replace('\r', ' ').Replace('\n', ' ').Replace('\t', ' ')
				.Trim();
			if (text.Length <= maxLength)
			{
				return text;
			}
			return text.Substring(0, maxLength);
		}

		internal static bool TryParseMetaLine(string line, string[] names, string[] descs)
		{
			if (line.IndexOf('\t') >= 0)
			{
				return false;
			}
			string[] array;
			int num;
			if (line.StartsWith("name", StringComparison.OrdinalIgnoreCase))
			{
				array = names;
				num = 4;
			}
			else
			{
				if (!line.StartsWith("desc", StringComparison.OrdinalIgnoreCase))
				{
					return false;
				}
				array = descs;
				num = 4;
			}
			int num2 = line.IndexOf('=');
			if (num2 <= num || !int.TryParse(line.Substring(num, num2 - num), out var result) || !IsValidSlot(result))
			{
				return false;
			}
			string text = Unescape(line.Substring(num2 + 1));
			array[result] = ((text.Length > 0) ? text : null);
			return true;
		}

		internal static void AppendMetaLines(StringBuilder sb, string[] names, string[] descs)
		{
			for (int i = 1; i <= 5; i++)
			{
				if (!string.IsNullOrEmpty(names[i]))
				{
					sb.Append("name").Append(i).Append('=')
						.Append(Escape(names[i]))
						.Append('\n');
				}
				if (!string.IsNullOrEmpty(descs[i]))
				{
					sb.Append("desc").Append(i).Append('=')
						.Append(Escape(descs[i]))
						.Append('\n');
				}
			}
		}

		internal static void Delete(string guid, int slot)
		{
			ModPresets modPresets = Load(guid);
			if (modPresets != null && IsValidSlot(slot))
			{
				modPresets.Slots[slot] = null;
				if (modPresets.Active == slot)
				{
					modPresets.Active = 0;
				}
				Write(guid, modPresets);
				ModdedWolfsConfigsPlugin.Log.LogInfo((object)$"Deleted preset {slot} for {guid}.");
			}
		}

		internal static void Capture(DiscoveredPlugin plugin, int slot)
		{
			if (plugin == null || !IsValidSlot(slot))
			{
				return;
			}
			ModPresets modPresets = Load(plugin.Guid);
			if (modPresets == null)
			{
				return;
			}
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal);
			foreach (ConfigEntryBase item in EnumerateEntries(plugin))
			{
				try
				{
					dictionary[KeyFor(item)] = item.GetSerializedValue() ?? string.Empty;
				}
				catch (Exception ex)
				{
					ModdedWolfsConfigsPlugin.Log.LogWarning((object)$"Preset capture skipped {item.Definition}: {ex.Message}");
				}
			}
			modPresets.Slots[slot] = dictionary;
			modPresets.Active = slot;
			Write(plugin.Guid, modPresets);
			ModdedWolfsConfigsPlugin.Log.LogInfo((object)$"Saved {dictionary.Count} setting(s) to preset {slot} for {plugin.Name}.");
		}

		internal static void Apply(DiscoveredPlugin plugin, int slot)
		{
			if (plugin == null || !IsValidSlot(slot))
			{
				return;
			}
			ModPresets modPresets = Load(plugin.Guid);
			Dictionary<string, string> dictionary = ((modPresets != null) ? modPresets.Slots[slot] : null);
			if (dictionary == null)
			{
				return;
			}
			Dictionary<ConfigFile, bool> dictionary2 = new Dictionary<ConfigFile, bool>();
			int num = 0;
			try
			{
				foreach (ConfigEntryBase item in EnumerateEntries(plugin))
				{
					if (!dictionary.TryGetValue(KeyFor(item), out var value))
					{
						continue;
					}
					ConfigFile configFile = item.ConfigFile;
					if (configFile != null && !dictionary2.ContainsKey(configFile))
					{
						dictionary2[configFile] = configFile.SaveOnConfigSet;
						configFile.SaveOnConfigSet = false;
					}
					try
					{
						if (!string.Equals(item.GetSerializedValue(), value, StringComparison.Ordinal))
						{
							item.SetSerializedValue(value);
						}
						num++;
					}
					catch (Exception ex)
					{
						ModdedWolfsConfigsPlugin.Log.LogWarning((object)$"Preset apply skipped {item.Definition}: {ex.Message}");
					}
				}
			}
			finally
			{
				foreach (KeyValuePair<ConfigFile, bool> item2 in dictionary2)
				{
					item2.Key.SaveOnConfigSet = item2.Value;
					try
					{
						item2.Key.Save();
					}
					catch (Exception ex2)
					{
						ModdedWolfsConfigsPlugin.Log.LogWarning((object)("Failed to save config: " + ex2.Message));
					}
					ConfigDiscovery.RefreshRuntimeValues(item2.Key);
				}
			}
			modPresets.Active = slot;
			Write(plugin.Guid, modPresets);
			ModdedWolfsConfigsPlugin.Log.LogInfo((object)$"Loaded preset {slot} ({num} setting(s)) for {plugin.Name}.");
		}

		internal static bool IsModified(DiscoveredPlugin plugin, int slot)
		{
			if (plugin == null || !IsValidSlot(slot))
			{
				return false;
			}
			ModPresets modPresets = Load(plugin.Guid);
			Dictionary<string, string> dictionary = ((modPresets != null) ? modPresets.Slots[slot] : null);
			if (dictionary == null)
			{
				return false;
			}
			foreach (ConfigEntryBase item in EnumerateEntries(plugin))
			{
				if (dictionary.TryGetValue(KeyFor(item), out var value))
				{
					string a;
					try
					{
						a = item.GetSerializedValue() ?? string.Empty;
					}
					catch
					{
						continue;
					}
					if (!string.Equals(a, value, StringComparison.Ordinal))
					{
						return true;
					}
				}
			}
			return false;
		}

		internal static IEnumerable<ConfigEntryBase> EnumerateEntries(DiscoveredPlugin plugin)
		{
			for (int s = 0; s < plugin.Sections.Count; s++)
			{
				List<ConfigEntryBase> entries = plugin.Sections[s].Entries;
				for (int e = 0; e < entries.Count; e++)
				{
					ConfigEntryBase val = entries[e];
					if (!(((val != null) ? val.Definition : null) == (ConfigDefinition)null) && !ConfigDiscovery.IsHiddenConfigKey(val.Definition.Key) && !ConfigEntryAccess.IsReadOnly(val))
					{
						yield return val;
					}
				}
			}
		}

		internal static bool IsValidSlot(int slot)
		{
			if (slot >= 1)
			{
				return slot <= 5;
			}
			return false;
		}

		internal static string KeyFor(ConfigEntryBase entry)
		{
			return (entry.Definition.Section ?? string.Empty) + "\t" + entry.Definition.Key;
		}

		private static string PathFor(string guid)
		{
			StringBuilder stringBuilder = new StringBuilder(guid.Length);
			char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
			foreach (char c in guid)
			{
				stringBuilder.Append((Array.IndexOf(invalidFileNameChars, c) >= 0) ? '_' : c);
			}
			return Path.Combine(FolderPath, stringBuilder?.ToString() + ".txt");
		}

		private static ModPresets Load(string guid)
		{
			if (string.IsNullOrEmpty(guid))
			{
				return null;
			}
			if (Cache.TryGetValue(guid, out var value))
			{
				return value;
			}
			ModPresets modPresets = new ModPresets();
			Cache[guid] = modPresets;
			string path = PathFor(guid);
			if (!File.Exists(path))
			{
				return modPresets;
			}
			try
			{
				Dictionary<string, string> dictionary = null;
				string[] array = File.ReadAllLines(path, Encoding.UTF8);
				for (int i = 0; i < array.Length; i++)
				{
					string text = array[i].TrimEnd(new char[1] { '\r' });
					if (text.Length == 0)
					{
						continue;
					}
					if (text.StartsWith("active=", StringComparison.OrdinalIgnoreCase))
					{
						int.TryParse(text.Substring(7), out var result);
						modPresets.Active = (IsValidSlot(result) ? result : 0);
					}
					else
					{
						if (TryParseMetaLine(text, modPresets.Names, modPresets.Descs))
						{
							continue;
						}
						if (text.StartsWith("[Preset", StringComparison.OrdinalIgnoreCase) && text.EndsWith("]"))
						{
							dictionary = null;
							if (int.TryParse(text.Substring(7, text.Length - 8), out var result2) && IsValidSlot(result2))
							{
								dictionary = new Dictionary<string, string>(StringComparer.Ordinal);
								modPresets.Slots[result2] = dictionary;
							}
						}
						else if (dictionary != null)
						{
							string[] array2 = text.Split(new char[1] { '\t' });
							if (array2.Length == 3)
							{
								dictionary[Unescape(array2[0]) + "\t" + Unescape(array2[1])] = Unescape(array2[2]);
							}
						}
					}
				}
			}
			catch (Exception ex)
			{
				ModdedWolfsConfigsPlugin.Log.LogWarning((object)("Failed to read presets for " + guid + ": " + ex.Message));
			}
			return modPresets;
		}

		private static void Write(string guid, ModPresets presets)
		{
			try
			{
				string path = PathFor(guid);
				Directory.CreateDirectory(Path.GetDirectoryName(path));
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.Append("active=").Append(presets.Active).Append('\n');
				AppendMetaLines(stringBuilder, presets.Names, presets.Descs);
				for (int i = 1; i <= 5; i++)
				{
					Dictionary<string, string> dictionary = presets.Slots[i];
					if (dictionary == null)
					{
						continue;
					}
					stringBuilder.Append("[Preset").Append(i).Append("]\n");
					foreach (KeyValuePair<string, string> item in dictionary)
					{
						int num = item.Key.IndexOf('\t');
						string value = ((num >= 0) ? item.Key.Substring(0, num) : string.Empty);
						string value2 = ((num >= 0) ? item.Key.Substring(num + 1) : item.Key);
						stringBuilder.Append(Escape(value)).Append('\t').Append(Escape(value2))
							.Append('\t')
							.Append(Escape(item.Value))
							.Append('\n');
					}
				}
				File.WriteAllText(path, stringBuilder.ToString(), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
			}
			catch (Exception ex)
			{
				ModdedWolfsConfigsPlugin.Log.LogWarning((object)("Failed to write presets for " + guid + ": " + ex.Message));
			}
		}

		internal static string Escape(string value)
		{
			if (string.IsNullOrEmpty(value))
			{
				return string.Empty;
			}
			return value.Replace("\\", "\\\\").Replace("\t", "\\t").Replace("\r", "\\r")
				.Replace("\n", "\\n");
		}

		internal static string Unescape(string value)
		{
			if (string.IsNullOrEmpty(value) || value.IndexOf('\\') < 0)
			{
				return value ?? string.Empty;
			}
			StringBuilder stringBuilder = new StringBuilder(value.Length);
			for (int i = 0; i < value.Length; i++)
			{
				char c = value[i];
				if (c != '\\' || i + 1 >= value.Length)
				{
					stringBuilder.Append(c);
					continue;
				}
				char c2 = value[++i];
				switch (c2)
				{
				case 't':
					stringBuilder.Append('\t');
					break;
				case 'r':
					stringBuilder.Append('\r');
					break;
				case 'n':
					stringBuilder.Append('\n');
					break;
				default:
					stringBuilder.Append(c2);
					break;
				}
			}
			return stringBuilder.ToString();
		}
	}
	internal static class SessionSnapshot
	{
		private static readonly Dictionary<ConfigEntryBase, string> Values = new Dictionary<ConfigEntryBase, string>();

		internal static void Begin()
		{
			Values.Clear();
			List<DiscoveredPlugin> list = ConfigDiscovery.Discover();
			for (int i = 0; i < list.Count; i++)
			{
				foreach (ConfigEntryBase item in PresetStore.EnumerateEntries(list[i]))
				{
					try
					{
						Values[item] = item.GetSerializedValue() ?? string.Empty;
					}
					catch (Exception ex)
					{
						ModdedWolfsConfigsPlugin.Log.LogWarning((object)$"Snapshot skipped {item.Definition}: {ex.Message}");
					}
				}
			}
		}

		internal static void Commit()
		{
			Values.Clear();
		}

		internal static int Revert()
		{
			if (Values.Count == 0)
			{
				return 0;
			}
			Dictionary<ConfigFile, bool> dictionary = new Dictionary<ConfigFile, bool>();
			int num = 0;
			try
			{
				foreach (KeyValuePair<ConfigEntryBase, string> value in Values)
				{
					ConfigEntryBase key = value.Key;
					if (key == null || ConfigEntryAccess.IsReadOnly(key))
					{
						continue;
					}
					try
					{
						if (!string.Equals(key.GetSerializedValue(), value.Value, StringComparison.Ordinal))
						{
							ConfigFile configFile = key.ConfigFile;
							if (configFile != null && !dictionary.ContainsKey(configFile))
							{
								dictionary[configFile] = configFile.SaveOnConfigSet;
								configFile.SaveOnConfigSet = false;
							}
							key.SetSerializedValue(value.Value);
							num++;
						}
					}
					catch (Exception ex)
					{
						ModdedWolfsConfigsPlugin.Log.LogWarning((object)$"Cancel could not restore {key.Definition}: {ex.Message}");
					}
				}
			}
			finally
			{
				foreach (KeyValuePair<ConfigFile, bool> item in dictionary)
				{
					item.Key.SaveOnConfigSet = item.Value;
					try
					{
						item.Key.Save();
					}
					catch (Exception ex2)
					{
						ModdedWolfsConfigsPlugin.Log.LogWarning((object)("Failed to save config: " + ex2.Message));
					}
					ConfigDiscovery.RefreshRuntimeValues(item.Key);
				}
				Values.Clear();
			}
			if (num > 0)
			{
				ModdedWolfsConfigsPlugin.Log.LogInfo((object)$"Cancel restored {num} setting(s).");
			}
			return num;
		}
	}
	internal static class PauseMenuButton
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static UnityAction <0>__Open;
		}

		internal static void Refresh()
		{
			try
			{
				bool flag = ModdedWolfsConfigsPlugin.ShowMainMenuButton == null || ModdedWolfsConfigsPlugin.ShowMainMenuButton.Value;
				bool flag2 = ModdedWolfsConfigsPlugin.ShowPauseMenuButton == null || ModdedWolfsConfigsPlugin.ShowPauseMenuButton.Value;
				if ((Object)(object)FejdStartup.instance != (Object)null)
				{
					Transform val = (((Object)(object)FejdStartup.instance.m_menuList != (Object)null) ? FejdStartup.instance.m_menuList.transform : null);
					SetupFromHierarchy(FindMenuEntries(val), flag);
					if ((Object)(object)val != (Object)null)
					{
						FejdStartup.instance.m_menuButtons = ((Component)val).GetComponentsInChildren<Button>(false);
					}
					if (!flag)
					{
						HideNamedUnder(((Component)FejdStartup.instance).transform);
					}
				}
				if ((Object)(object)Menu.instance != (Object)null)
				{
					SetupPauseMenu(flag2);
					if (!flag2)
					{
						HideNamedUnder(((Component)Menu.instance).transform);
					}
				}
			}
			catch (Exception ex)
			{
				ModdedWolfsConfigsPlugin.Log.LogWarning((object)("Failed to refresh menu button: " + ex.Message));
			}
		}

		internal static bool IsModConfigsControlActive()
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected O, but got Unknown
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)EventSystem.current == (Object)null)
			{
				return false;
			}
			if (IsNamedModButton(EventSystem.current.currentSelectedGameObject))
			{
				return true;
			}
			if (Input.GetMouseButton(0) || Input.GetMouseButtonUp(0))
			{
				PointerEventData val = new PointerEventData(EventSystem.current)
				{
					position = Vector2.op_Implicit(Input.mousePosition)
				};
				List<RaycastResult> list = new List<RaycastResult>();
				EventSystem.current.RaycastAll(val, list);
				for (int i = 0; i < list.Count; i++)
				{
					RaycastResult val2 = list[i];
					if (IsNamedModButton(((RaycastResult)(ref val2)).gameObject))
					{
						return true;
					}
				}
			}
			return false;
		}

		private static bool IsNamedModButton(GameObject go)
		{
			if ((Object)(object)go == (Object)null)
			{
				return false;
			}
			Transform val = go.transform;
			while ((Object)(object)val != (Object)null)
			{
				if (((Object)val).name == "ModdedWolfsConfigs")
				{
					return true;
				}
				val = val.parent;
			}
			return false;
		}

		private static void SetupPauseMenu(bool show)
		{
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			Menu instance = Menu.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			Button val = instance.m_settingsButton;
			Transform val2 = null;
			if ((Object)(object)val != (Object)null)
			{
				val2 = ((Component)val).transform.parent;
			}
			if ((Object)(object)val2 == (Object)null && (Object)(object)instance.menuEntriesParent != (Object)null)
			{
				val2 = (Transform)(object)instance.menuEntriesParent;
			}
			if ((Object)(object)val2 == (Object)null)
			{
				val2 = FindMenuEntries(instance.m_menuDialog);
			}
			if ((Object)(object)val == (Object)null && (Object)(object)val2 != (Object)null)
			{
				val = FindSettingsButtonUnder(val2);
			}
			if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null))
			{
				Button val3 = EnsureModButton(val2, val);
				ApplyLabel(((Component)val3).gameObject);
				RewireClick(val3);
				((Component)val3).gameObject.SetActive(show);
				object obj;
				if (!((Object)(object)instance.m_logoutButton != (Object)null))
				{
					Navigation navigation = ((Selectable)val).navigation;
					Selectable selectOnDown = ((Navigation)(ref navigation)).selectOnDown;
					obj = ((selectOnDown is Button) ? selectOnDown : null);
				}
				else
				{
					obj = instance.m_logoutButton;
				}
				Button nextButton = (Button)obj;
				WireNavigation(val, val3, nextButton, show);
			}
		}

		private static void SetupFromHierarchy(Transform menuEntries, bool show)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)menuEntries == (Object)null)
			{
				return;
			}
			Button val = FindSettingsButtonUnder(menuEntries);
			if (!((Object)(object)val == (Object)null))
			{
				Button val2 = EnsureModButton(menuEntries, val);
				ApplyLabel(((Component)val2).gameObject);
				RewireClick(val2);
				((Component)val2).gameObject.SetActive(show);
				Navigation navigation = ((Selectable)val).navigation;
				Selectable selectOnDown = ((Navigation)(ref navigation)).selectOnDown;
				Button val3 = (Button)(object)((selectOnDown is Button) ? selectOnDown : null);
				if ((Object)(object)val3 != (Object)null && ((Object)val3).name == "ModdedWolfsConfigs")
				{
					navigation = ((Selectable)val3).navigation;
					Selectable selectOnDown2 = ((Navigation)(ref navigation)).selectOnDown;
					val3 = (Button)(object)((selectOnDown2 is Button) ? selectOnDown2 : null);
				}
				WireNavigation(val, val2, val3, show);
			}
		}

		private static Button EnsureModButton(Transform parent, Button settingsButton)
		{
			Transform val = parent.Find("ModdedWolfsConfigs");
			GameObject val2 = (((Object)(object)val != (Object)null) ? ((Component)val).gameObject : null);
			if ((Object)(object)val2 == (Object)null)
			{
				val2 = Object.Instantiate<GameObject>(((Component)settingsButton).gameObject, parent);
				((Object)val2).name = "ModdedWolfsConfigs";
				val2.transform.SetSiblingIndex(((Component)settingsButton).transform.GetSiblingIndex() + 1);
			}
			Button component = val2.GetComponent<Button>();
			if ((Object)(object)component == (Object)null)
			{
				throw new InvalidOperationException("Cloned Mod Configs control is missing a Button.");
			}
			return component;
		}

		private static void RewireClick(Button button)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			if ((Object)(object)button == (Object)null)
			{
				return;
			}
			button.onClick = new ButtonClickedEvent();
			ButtonClickedEvent onClick = button.onClick;
			object obj = <>O.<0>__Open;
			if (obj == null)
			{
				UnityAction val = ConfigPanelOpener.Open;
				<>O.<0>__Open = val;
				obj = (object)val;
			}
			((UnityEvent)onClick).AddListener((UnityAction)obj);
			EventTrigger[] componentsInChildren = ((Component)button).GetComponentsInChildren<EventTrigger>(true);
			foreach (EventTrigger val2 in componentsInChildren)
			{
				if (!((Object)(object)val2 == (Object)null) && val2.triggers != null)
				{
					val2.triggers.RemoveAll((Entry entry) => entry != null && ((int)entry.eventID == 4 || (int)entry.eventID == 15));
				}
			}
		}

		private static void ApplyLabel(GameObject menuButton)
		{
			TMP_Text componentInChildren = menuButton.GetComponentInChildren<TMP_Text>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.text = "Mod Configs";
			}
			Text componentInChildren2 = menuButton.GetComponentInChildren<Text>(true);
			if ((Object)(object)componentInChildren2 != (Object)null)
			{
				componentInChildren2.text = "Mod Configs";
			}
		}

		private static Button FindSettingsButtonUnder(Transform menuEntries)
		{
			Transform val = menuEntries.Find("Settings");
			if ((Object)(object)val == (Object)null)
			{
				for (int i = 0; i < menuEntries.childCount; i++)
				{
					Transform child = menuEntries.GetChild(i);
					if ((Object)(object)child != (Object)null && ((Object)child).name.IndexOf("Settings", StringComparison.OrdinalIgnoreCase) >= 0 && ((Object)child).name != "ModdedWolfsConfigs")
					{
						val = child;
						break;
					}
				}
			}
			if (!((Object)(object)val != (Object)null))
			{
				return null;
			}
			return ((Component)val).GetComponent<Button>();
		}

		private static Transform FindMenuEntries(Transform root)
		{
			if ((Object)(object)root == (Object)null)
			{
				return null;
			}
			Transform val = root.Find("MenuEntries");
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if ((Object)(object)componentsInChildren[i] != (Object)null && ((Object)componentsInChildren[i]).name == "MenuEntries")
				{
					return componentsInChildren[i];
				}
			}
			return null;
		}

		private static void HideNamedUnder(Transform root)
		{
			if ((Object)(object)root == (Object)null)
			{
				return;
			}
			Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if ((Object)(object)componentsInChildren[i] != (Object)null && ((Object)componentsInChildren[i]).name == "ModdedWolfsConfigs")
				{
					((Component)componentsInChildren[i]).gameObject.SetActive(false);
				}
			}
		}

		private static void WireNavigation(Button settingsButton, Button modButton, Button nextButton, bool show)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)settingsButton == (Object)null || (Object)(object)modButton == (Object)null)
			{
				return;
			}
			if ((Object)(object)nextButton != (Object)null && ((Object)nextButton).name == "ModdedWolfsConfigs")
			{
				Navigation navigation = ((Selectable)nextButton).navigation;
				Selectable selectOnDown = ((Navigation)(ref navigation)).selectOnDown;
				nextButton = (Button)(object)((selectOnDown is Button) ? selectOnDown : null);
			}
			Navigation navigation2 = ((Selectable)settingsButton).navigation;
			Navigation navigation3 = ((Selectable)modButton).navigation;
			if (show)
			{
				((Navigation)(ref navigation2)).selectOnDown = (Selectable)(object)modButton;
				((Navigation)(ref navigation3)).selectOnUp = (Selectable)(object)settingsButton;
				((Navigation)(ref navigation3)).selectOnDown = (Selectable)(object)nextButton;
				((Navigation)(ref navigation3)).mode = (Mode)4;
				((Selectable)modButton).navigation = navigation3;
				if ((Object)(object)nextButton != (Object)null)
				{
					Navigation navigation4 = ((Selectable)nextButton).navigation;
					((Navigation)(ref navigation4)).selectOnUp = (Selectable)(object)modButton;
					((Selectable)nextButton).navigation = navigation4;
				}
			}
			else if ((Object)(object)nextButton != (Object)null)
			{
				((Navigation)(ref navigation2)).selectOnDown = (Selectable)(object)nextButton;
				Navigation navigation5 = ((Selectable)nextButton).navigation;
				((Navigation)(ref navigation5)).selectOnUp = (Selectable)(object)settingsButton;
				((Selectable)nextButton).navigation = navigation5;
			}
			((Selectable)settingsButton).navigation = navigation2;
		}
	}
	[BepInPlugin("ModdedWolf.ModConfigs", "Mod Configs", "1.1.1")]
	public class ModdedWolfsConfigsPlugin : BaseUnityPlugin
	{
		public const string GUID = "ModdedWolf.ModConfigs";

		private const string LegacyGuid = "ModdedWolf.ModdedWolfsConfigs";

		public const string NAME = "Mod Configs";

		public const string VERSION = "1.1.1";

		internal const string MenuButtonName = "ModdedWolfsConfigs";

		internal const string MenuButtonCaption = "Mod Configs";

		internal const string PanelTitle = "Mod Configs";

		internal static ConfigEntry<bool> ShowMainMenuButton;

		internal static ConfigEntry<bool> ShowPauseMenuButton;

		internal static ConfigEntry<bool> ShowAdvancedSettings;

		internal static ConfigEntry<bool> HideSelfFromList;

		internal static ConfigEntry<bool> RememberLastMod;

		internal static ConfigEntry<bool> KeepGlobalPresetLabel;

		internal const string LastSelectedModGuidKey = "LastSelectedModGuid";

		internal static ConfigEntry<string> LastSelectedModGuid;

		private Harmony _harmony;

		internal static ModdedWolfsConfigsPlugin Instance { get; private set; }

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Expected O, but got Unknown
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			TryMigrateLegacyConfigFile();
			ShowMainMenuButton = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowMainMenuButton", false, "Show Mod Configs on the main menu (title screen).");
			ShowPauseMenuButton = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowPauseMenuButton", true, "Show Mod Configs on the in-game pause menu.");
			TryMigrateLegacyShowMenuButton();
			ShowAdvancedSettings = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowAdvancedSettings", true, "Show settings marked as advanced (ConfigurationManagerAttributes.IsAdvanced).");
			HideSelfFromList = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "HideSelfFromList", false, "Hide this mod's own settings from the in-game config panel.");
			RememberLastMod = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RememberLastMod", true, "When enabled, reopen Mod Configs on the last mod you had selected.");
			KeepGlobalPresetLabel = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "KeepGlobalPresetLabel", false, "When deleting a global preset, keep its name and description.");
			LastSelectedModGuid = ((BaseUnityPlugin)this).Config.Bind<string>("General", "LastSelectedModGuid", "", new ConfigDescription("GUID of the last mod opened in Mod Configs (remembered between sessions).", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Browsable = false
				}
			}));
			ShowMainMenuButton.SettingChanged += delegate
			{
				PauseMenuButton.Refresh();
			};
			ShowPauseMenuButton.SettingChanged += delegate
			{
				PauseMenuButton.Refresh();
			};
			ShowAdvancedSettings.SettingChanged += delegate
			{
				ConfigDiscovery.InvalidateCache();
			};
			HideSelfFromList.SettingChanged += delegate
			{
				ConfigDiscovery.InvalidateCache();
			};
			ConfigPanelOpener.DiscardPool();
			_harmony = new Harmony("ModdedWolf.ModConfigs");
			_harmony.PatchAll();
			Log.LogInfo((object)"Mod Configs v1.1.1 loaded (client configs).");
		}

		private void TryMigrateLegacyConfigFile()
		{
			try
			{
				string configPath = Paths.ConfigPath;
				string text = Path.Combine(configPath, "ModdedWolf.ModConfigs.cfg");
				string text2 = Path.Combine(configPath, "ModdedWolf.ModdedWolfsConfigs.cfg");
				if (File.Exists(text2) && !File.Exists(text))
				{
					File.Copy(text2, text);
					Log.LogInfo((object)"Migrated config from ModdedWolf.ModdedWolfsConfigs.cfg to ModdedWolf.ModConfigs.cfg");
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Legacy config migration failed: " + ex.Message));
			}
		}

		private void TryMigrateLegacyShowMenuButton()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			try
			{
				ConfigDefinition val = new ConfigDefinition("General", "ShowMenuButton");
				if (((BaseUnityPlugin)this).Config.ContainsKey(val))
				{
					if (!((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowMenuButton", true, "Deprecated. Use ShowMainMenuButton / ShowPauseMenuButton.").Value)
					{
						ShowMainMenuButton.Value = false;
						ShowPauseMenuButton.Value = true;
					}
					((BaseUnityPlugin)this).Config.Remove(val);
					((BaseUnityPlugin)this).Config.Save();
				}
			}
			catch
			{
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	[HarmonyPatch(typeof(Menu), "Start")]
	internal static class Menu_Start_Patch
	{
		private static void Postfix()
		{
			PauseMenuButton.Refresh();
		}
	}
	[HarmonyPatch(typeof(Menu), "UpdateNavigation")]
	internal static class Menu_UpdateNavigation_Patch
	{
		private static void Postfix()
		{
			PauseMenuButton.Refresh();
		}
	}
	[HarmonyPatch(typeof(Menu), "OnSettings")]
	internal static class Menu_OnSettings_Patch
	{
		private static bool Prefix()
		{
			if (!PauseMenuButton.IsModConfigsControlActive())
			{
				return true;
			}
			ConfigPanelOpener.Open();
			return false;
		}
	}
	[HarmonyPatch(typeof(FejdStartup), "Start")]
	internal static class FejdStartup_Start_Patch
	{
		private static void Postfix()
		{
			PauseMenuButton.Refresh();
		}
	}
	[HarmonyPatch(typeof(FejdStartup), "SetupGui")]
	internal static class FejdStartup_SetupGui_Patch
	{
		private static void Postfix()
		{
			PauseMenuButton.Refresh();
		}
	}
	[HarmonyPatch(typeof(Settings), "OnDestroy")]
	internal static class Settings_OnDestroy_Patch
	{
		private static void Postfix(Settings __instance)
		{
			ConfigPanelOpener.ForgetInstance(__instance);
			ModConfigPanel.ForgetInitialized(__instance);
			PauseMenuButton.Refresh();
		}
	}
	internal static class SettingsConversionPatches
	{
		[HarmonyPatch(typeof(Settings), "Awake")]
		internal static class SettingsAwakePatch
		{
			private static void Prefix(Settings __instance)
			{
				if (ConfigPanelOpener.IsOpening)
				{
					ConfigPanelOpener.MarkInstance(__instance);
				}
			}

			private static void Postfix(Settings __instance)
			{
				if (ShouldConvert(__instance))
				{
					ModConfigPanel.ConvertSettingsInstance(__instance);
					ModConfigPanel.EnforceConvertedLayout(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(Settings), "OnInputLayoutChanged")]
		internal static class SettingsInputLayoutPatch
		{
			private static void Postfix(Settings __instance)
			{
				if (!ShouldConvert(__instance) || __instance.m_tabKeyHints == null)
				{
					return;
				}
				for (int i = 0; i < __instance.m_tabKeyHints.Length; i++)
				{
					if ((Object)(object)__instance.m_tabKeyHints[i] != (Object)null)
					{
						__instance.m_tabKeyHints[i].SetActive(false);
					}
				}
			}
		}

		[HarmonyPatch(typeof(Settings), "InitializeTabs")]
		internal static class SettingsInitializeTabsPatch
		{
			private static bool Prefix(Settings __instance)
			{
				if (!ShouldConvert(__instance))
				{
					return true;
				}
				ConfigPanelOpener.MarkInstance(__instance);
				ModConfigPanel.ConvertSettingsInstance(__instance);
				ModConfigPanel.EnforceConvertedLayout(__instance);
				return false;
			}
		}

		[HarmonyPatch(typeof(Settings), "OnBack")]
		internal static class SettingsOnBackPatch
		{
			private static bool Prefix(Settings __instance)
			{
				if (ConfigPanelOpener.IsOurInstance(__instance) && (KeybindCapture.TryCancelListen() || KeybindCapture.HandledBackThisFrame || KeybindCapture.CommittedThisFrame || ModConfigTab.BackHandledThisFrame))
				{
					return false;
				}
				if (ConfigPanelOpener.IsOurInstance(__instance) && ModPicker.TryCloseOpenList())
				{
					return false;
				}
				if (ConfigPanelOpener.IsOurInstance(__instance) && PresetEditDialog.IsOpen)
				{
					PresetEditDialog.Close();
					return false;
				}
				if (ConfigPanelOpener.IsOurInstance(__instance) && ModConfigTab.TryConsumeBack())
				{
					return false;
				}
				if (ConfigPanelOpener.IsOurInstance(__instance))
				{
					try
					{
						if (SessionSnapshot.Revert() > 0)
						{
							ModConfigTab.MarkOpenInstanceStale();
						}
					}
					catch (Exception ex)
					{
						ModdedWolfsConfigsPlugin.Log.LogWarning((object)("Cancel failed to restore settings: " + ex.Message));
					}
				}
				if (ConfigPanelOpener.SoftClose(__instance))
				{
					return false;
				}
				return HandleCloseIfBroken(__instance);
			}
		}

		[HarmonyPatch(typeof(Settings), "OnOk")]
		internal static class SettingsOnOkPatch
		{
			private static bool Prefix(Settings __instance)
			{
				if (ConfigPanelOpener.IsOurInstance(__instance))
				{
					if (KeybindCapture.IsListening || KeybindCapture.CommittedThisFrame || PresetEditDialog.IsOpen || ModPicker.IsAnyOpen)
					{
						return false;
					}
					SessionSnapshot.Commit();
				}
				if (ConfigPanelOpener.SoftClose(__instance))
				{
					return false;
				}
				return HandleCloseIfBroken(__instance);
			}
		}

		private static bool ShouldConvert(Settings settings)
		{
			if (!ConfigPanelOpener.IsOpening)
			{
				return ConfigPanelOpener.IsOurInstance(settings);
			}
			return true;
		}

		private static bool HandleCloseIfBroken(Settings settings)
		{
			if (!ConfigPanelOpener.IsOurInstance(settings))
			{
				return true;
			}
			List<ISettingsTab> settingsTabs = settings.SettingsTabs;
			if (settingsTabs != null && settingsTabs.Count > 0)
			{
				return true;
			}
			ForceClose(settings);
			return false;
		}

		private static void ForceClose(Settings settings)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)settings == (Object)null)
			{
				return;
			}
			try
			{
				if ((Object)(object)Menu.instance != (Object)null && (Object)(object)Menu.instance.m_settingsInstance == (Object)(object)((Component)settings).gameObject)
				{
					Menu.instance.m_settingsInstance = null;
					Menu.instance.m_closeMenuState = (CloseMenuState)2;
				}
				Object.Destroy((Object)(object)((Component)settings).gameObject);
			}
			catch (Exception ex)
			{
				ModdedWolfsConfigsPlugin.Log.LogWarning((object)("Failed to force-close Mod Configs: " + ex.Message));
			}
		}
	}
	internal static class ConfigPanelOpener
	{
		private static readonly HashSet<int> PendingInstanceIds = new HashSet<int>();

		private static readonly FieldInfo SettingsInstanceField = typeof(Settings).GetField("m_instance", BindingFlags.Static | BindingFlags.NonPublic);

		private static Settings _pooledSettings;

		private static GameObject _pooledGo;

		internal static bool IsOpening { get; private set; }

		internal static void MarkInstance(Settings settings)
		{
			if (!((Object)(object)settings == (Object)null))
			{
				PendingInstanceIds.Add(((Object)settings).GetInstanceID());
			}
		}

		internal static bool IsOurInstance(Settings settings)
		{
			if ((Object)(object)settings == (Object)null)
			{
				return false;
			}
			return PendingInstanceIds.Contains(((Object)settings).GetInstanceID());
		}

		internal static void ForgetInstance(Settings settings)
		{
			if (!((Object)(object)settings == (Object)null))
			{
				PendingInstanceIds.Remove(((Object)settings).GetInstanceID());
				if ((Object)(object)_pooledSettings != (Object)null && _pooledSettings == settings)
				{
					_pooledSettings = null;
					_pooledGo = null;
				}
			}
		}

		internal static void Open()
		{
			try
			{
				if ((Object)(object)Settings.instance != (Object)null || TryOpenPooled())
				{
					return;
				}
				GameObject val = FindSettingsPrefab();
				if ((Object)(object)val == (Object)null)
				{
					ModdedWolfsConfigsPlugin.Log.LogWarning((object)"Could not find Settings prefab (Menu / FejdStartup). Cannot open config panel.");
					return;
				}
				Transform val2 = null;
				if ((Object)(object)Menu.instance != (Object)null)
				{
					val2 = ((Component)Menu.instance).transform;
				}
				else if ((Object)(object)FejdStartup.instance != (Object)null)
				{
					val2 = ((Component)FejdStartup.instance).transform;
				}
				IsOpening = true;
				GameObject val3 = Object.Instantiate<GameObject>(val, val2);
				IsOpening = false;
				Settings val4 = (((Object)(object)val3 != (Object)null) ? val3.GetComponent<Settings>() : null);
				if ((Object)(object)val4 != (Object)null)
				{
					MarkInstance(val4);
					RememberPool(val4);
					ModConfigPanel.ConvertSettingsInstance(val4);
					ModConfigPanel.EnforceConvertedLayout(val4);
				}
				BindMenuState(val3);
				ModdedWolfsConfigsPlugin.Log.LogInfo((object)"Opened ModdedWolf's Configs panel.");
			}
			catch (Exception arg)
			{
				IsOpening = false;
				ModdedWolfsConfigsPlugin.Log.LogWarning((object)$"Failed to open config panel: {arg}");
			}
		}

		internal static bool SoftClose(Settings settings)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)settings == (Object)null || !IsOurInstance(settings))
			{
				return false;
			}
			try
			{
				RememberPool(settings);
				if ((Object)(object)Menu.instance != (Object)null && (Object)(object)Menu.instance.m_settingsInstance == (Object)(object)((Component)settings).gameObject)
				{
					Menu.instance.m_settingsInstance = null;
					Menu.instance.m_closeMenuState = (CloseMenuState)2;
				}
				ClearSettingsSingleton(settings);
				((Component)settings).gameObject.SetActive(false);
				PauseMenuButton.Refresh();
				ModdedWolfsConfigsPlugin.Log.LogInfo((object)"Soft-closed ModdedWolf's Configs panel (pooled).");
				return true;
			}
			catch (Exception ex)
			{
				ModdedWolfsConfigsPlugin.Log.LogWarning((object)("Soft-close failed: " + ex.Message));
				return false;
			}
		}

		private static bool TryOpenPooled()
		{
			if ((Object)(object)_pooledSettings == (Object)null || (Object)(object)_pooledGo == (Object)null)
			{
				return false;
			}
			if (!Object.op_Implicit((Object)(object)_pooledSettings))
			{
				_pooledSettings = null;
				_pooledGo = null;
				return false;
			}
			MarkInstance(_pooledSettings);
			if (_pooledGo.activeSelf)
			{
				_pooledGo.SetActive(false);
			}
			SetSettingsSingleton(_pooledSettings);
			ModConfigPanel.PreparePooledReopen(_pooledSettings);
			_pooledGo.SetActive(true);
			ModConfigPanel.WirePooledNavigation(_pooledSettings);
			BindMenuState(_pooledGo);
			ModdedWolfsConfigsPlugin.Log.LogInfo((object)"Reopened pooled ModdedWolf's Configs panel.");
			return true;
		}

		internal static void DiscardPool()
		{
			if ((Object)(object)_pooledGo != (Object)null)
			{
				try
				{
					if ((Object)(object)_pooledSettings != (Object)null)
					{
						ForgetInstance(_pooledSettings);
						ModConfigPanel.ForgetInitialized(_pooledSettings);
					}
					Object.Destroy((Object)(object)_pooledGo);
				}
				catch (Exception ex)
				{
					ModdedWolfsConfigsPlugin.Log.LogWarning((object)("Failed to discard pooled panel: " + ex.Message));
				}
			}
			_pooledSettings = null;
			_pooledGo = null;
		}

		private static void RememberPool(Settings settings)
		{
			if (!((Object)(object)settings == (Object)null))
			{
				_pooledSettings = settings;
				_pooledGo = ((Component)settings).gameObject;
			}
		}

		private static void BindMenuState(GameObject instance)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Menu.instance != (Object)null && (Object)(object)instance != (Object)null)
			{
				Menu.instance.m_settingsInstance = instance;
				Menu.instance.m_closeMenuState = (CloseMenuState)0;
			}
		}

		private static void SetSettingsSingleton(Settings settings)
		{
			if (SettingsInstanceField != null)
			{
				SettingsInstanceField.SetValue(null, settings);
			}
		}

		private static void ClearSettingsSingleton(Settings settings)
		{
			if (!(SettingsInstanceField == null))
			{
				object? value = SettingsInstanceField.GetValue(null);
				Settings val = (Settings)((value is Settings) ? value : null);
				if ((Object)(object)val == (Object)null || val == settings)
				{
					SettingsInstanceField.SetValue(null, null);
				}
			}
		}

		private static GameObject FindSettingsPrefab()
		{
			if ((Object)(object)Menu.instance != (Object)null && (Object)(object)Menu.instance.m_settingsPrefab != (Object)null)
			{
				return Menu.instance.m_settingsPrefab;
			}
			if ((Object)(object)FejdStartup.instance != (Object)null && (Object)(object)FejdStartup.instance.m_settingsPrefab != (Object)null)
			{
				return FejdStartup.instance.m_settingsPrefab;
			}
			return null;
		}
	}
	internal static class GamepadSupport
	{
		private const string ButtonY = "JoyButtonY";

		private const string ButtonX = "JoyButtonX";

		private static bool _footerLogged;

		private static readonly Vector3[] CornerBuffer = (Vector3[])(object)new Vector3[4];

		internal static string RenameButton { get; private set; } = "JoyButtonY";

		internal static bool IsActive
		{
			get
			{
				try
				{
					return ZInput.IsGamepadActive();
				}
				catch
				{
					return false;
				}
			}
		}

		internal static bool GetButtonDown(string name)
		{
			try
			{
				return ZInput.GetButtonDown(name);
			}
			catch
			{
				return false;
			}
		}

		internal static void Select(Selectable selectable)
		{
			if (!((Object)(object)selectable == (Object)null) && ((Behaviour)selectable).isActiveAndEnabled && !((Object)(object)EventSystem.current == (Object)null))
			{
				EventSystem.current.SetSelectedGameObject(((Component)selectable).gameObject);
			}
		}

		internal static bool IsSelectedUnder(Transform root)
		{
			GameObject val = (((Object)(object)EventSystem.current != (Object)null) ? EventSystem.current.currentSelectedGameObject : null);
			if ((Object)(object)val != (Object)null && (Object)(object)root != (Object)null)
			{
				return val.transform.IsChildOf(root);
			}
			return false;
		}

		internal static void LinkVertical(IList<Selectable> items)
		{
			//IL_0064: 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_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			if (items == null)
			{
				return;
			}
			List<Selectable> list = new List<Selectable>(items.Count);
			for (int i = 0; i < items.Count; i++)
			{
				if ((Object)(object)items[i] != (Object)null && ((Component)items[i]).gameObject.activeInHierarchy && items[i].interactable)
				{
					list.Add(items[i]);
				}
			}
			for (int j = 0; j < list.Count; j++)
			{
				Navigation val = default(Navigation);
				((Navigation)(ref val)).mode = (Mode)4;
				((Navigation)(ref val)).selectOnUp = ((j > 0) ? list[j - 1] : null);
				((Navigation)(ref val)).selectOnDown = ((j < list.Count - 1) ? list[j + 1] : null);
				Navigation navigation = val;
				list[j].navigation = navigation;
			}
		}

		internal static void SetNavigationNone(Selectable selectable)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)selectable == (Object)null))
			{
				Navigation navigation = selectable.navigation;
				((Navigation)(ref navigation)).mode = (Mode)0;
				selectable.navigation = navigation;
			}
		}

		internal static void SetExplicit(Selectable selectable, Selectable up, Selectable down, Selectable left, Selectable right)
		{
			//IL_000d: 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)
			if (!((Object)(object)selectable == (Object)null))
			{
				Navigation navigation = default(Navigation);
				((Navigation)(ref navigation)).mode = (Mode)4;
				((Navigation)(ref navigation)).selectOnUp = up;
				((Navigation)(ref navigation)).selectOnDown = down;
				((Navigation)(ref navigation)).selectOnLeft = left;
				((Navigation)(ref navigation)).selectOnRight = right;
				selectable.navigation = navigation;
			}
		}

		internal static Vector2 Center(Selectable selectable)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)selectable == (Object)null)
			{
				return Vector2.zero;
			}
			Transform transform = ((Component)selectable).transform;
			RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			if ((Object)(object)val == (Object)null)
			{
				return Vector2.op_Implicit(((Component)selectable).transform.position);
			}
			val.GetWorldCorners(CornerBuffer);
			return Vector2.op_Implicit((CornerBuffer[0] + CornerBuffer[2]) * 0.5f);
		}

		internal static Selectable Closest(IList<Selectable> options, Selectable from, bool matchVertical)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)from == (Object)null || options == null || options.Count == 0)
			{
				return null;
			}
			Vector2 val = Center(from);
			Selectable result = null;
			float num = float.MaxValue;
			for (int i = 0; i < options.Count; i++)
			{
				Selectable val2 = options[i];
				if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)from))
				{
					Vector2 val3 = Center(val2);
					float num2 = (matchVertical ? Mathf.Abs(val3.y - val.y) : Mathf.Abs(val3.x - val.x));
					if (num2 < num)
					{
						num = num2;
						result = val2;
					}
				}
			}
			return result;
		}

		internal static void ConfigureFromFooter(Settings settings)
		{
			if (!((Object)(object)settings == (Object)null))
			{
				string text = FooterKey(settings.m_backButton);
				string text2 = FooterKey(settings.m_okButton);
				RenameButton = ((text2 == "JoyButtonY" || text == "JoyButtonY") ? "JoyButtonX" : "JoyButtonY");
				if (!_footerLogged)
				{
					_footerLogged = true;
					ModdedWolfsConfigsPlugin.Log.LogInfo((object)("Gamepad footer keys: back='" + (text ?? "-") + "', ok='" + (text2 ?? "-") + "'; rename uses " + RenameButton + "."));
				}
			}
		}

		private static string FooterKey(Button button)
		{
			if ((Object)(object)button == (Object)null)
			{
				return null;
			}
			UIGamePad componentInChildren = ((Component)button).GetComponentInChildren<UIGamePad>(true);
			if (!((Object)(object)componentInChildren != (Object)null) || string.IsNullOrEmpty(componentInChildren.m_zinputKey))
			{
				return null;
			}
			return componentInChildren.m_zinputKey;
		}
	}
	internal sealed class ScrollToSelection : MonoBehaviour
	{
		private const float Padding = 12f;

		private ScrollRect _scroll;

		internal static void Attach(ScrollRect scroll)
		{
			if (!((Object)(object)scroll == (Object)null))
			{
				(((Component)scroll).GetComponent<ScrollToSelection>() ?? ((Component)scroll).gameObject.AddComponent<ScrollToSelection>())._scroll = scroll;
			}
		}

		private void LateUpdate()
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_scroll == (Object)null || (Object)(object)_scroll.content == (Object)null || (Object)(object)EventSystem.current == (Object)null || !GamepadSupport.IsActive)
			{
				return;
			}
			GameObject currentSelectedGameObject = EventSystem.current.currentSelectedGameObject;
			if ((Object)(object)currentSelectedGameObject == (Object)null || !currentSelectedGameObject.activeInHierarchy || !currentSelectedGameObject.transform.IsChildOf((Transform)(object)_scroll.content))
			{
				return;
			}
			RectTransform val = (RectTransform)(((Object)(object)_scroll.viewport != (Object)null) ? ((object)_scroll.viewport) : ((object)(RectTransform)((Component)_scroll).transform));
			Transform transform = currentSelectedGameObject.transform;
			RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			if ((Object)(object)val2 == (Object)null)
			{
				return;
			}
			Bounds val3 = RectTransformUtility.CalculateRelativeRectTransformBounds((Transform)(object)val, (Transform)(object)val2);
			Rect rect = val.rect;
			float num;
			if (((Bounds)(ref val3)).max.y + 12f > ((Rect)(ref rect)).yMax)
			{
				num = ((Bounds)(ref val3)).max.y + 12f - ((Rect)(ref rect)).yMax;
			}
			else
			{
				if (!(((Bounds)(ref val3)).min.y - 12f < ((Rect)(ref rect)).yMin))
				{
					return;
				}
				num = ((Bounds)(ref val3)).min.y - 12f - ((Rect)(ref rect)).yMin;
			}
			RectTransform content = _scroll.content;
			Rect rect2 = content.rect;
			float num2 = Mathf.Max(0f, ((Rect)(ref rect2)).height - ((Rect)(ref rect)).height);
			Vector2 anchoredPosition = content.anchoredPosition;
			anchoredPosition.y = Mathf.Clamp(anchoredPosition.y - num, 0f, num2);
			content.anchoredPosition = anchoredPosition;
			_scroll.velocity = Vector2.zero;
		}
	}
	internal sealed class GamepadFocusKeeper : MonoBehaviour
	{
		private Transform _panelRoot;

		private Func<Selectable> _fallback;

		internal static void Attach(GameObject host, Transform panelRoot, Func<Selectable> fallback)
		{
			if (!((Object)(object)host == (Object)null))
			{
				GamepadFocusKeeper obj = host.GetComponent<GamepadFocusKeeper>() ?? host.AddComponent<GamepadFocusKeeper>();
				obj._panelRoot = panelRoot;
				obj._fallback = fallback;
			}
		}

		internal void FocusFallback()
		{
			GamepadSupport.Select(_fallback?.Invoke());
		}

		private void Update()
		{
			if ((Object)(object)EventSystem.current == (Object)null || !GamepadSupport.IsActive || KeybindCapture.IsListening || KeybindCapture.CommittedThisFrame || ModPicker.IsAnyOpen || PresetEditDialog.IsOpen)
			{
				return;
			}
			GameObject currentSelectedGameObject = EventSystem.current.currentSelectedGameObject;
			if (!((Object)(object)currentSelectedGameObject != (Object)null) || !currentSelectedGameObject.activeInHierarchy || !((Object)(object)_panelRoot != (Object)null) || !currentSelectedGameObject.transform.IsChildOf(_panelRoot))
			{
				FocusFallback();
			}
			else if (GamepadSupport.GetButtonDown(GamepadSupport.RenameButton))
			{
				RightClickRelay component = currentSelectedGameObject.GetComponent<RightClickRelay>();
				if ((Object)(object)component != (Object)null)
				{
					component.Invoke();
				}
			}
		}
	}
	internal sealed class ControllerGlyph : MonoBehaviour
	{
		private TMP_Text _text;

		private string _key;

		private string _shown;

		internal static ControllerGlyph Create(Transform parent, string key, TMP_Text fontSource)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			if ((Object)(object)parent == (Object)null)
			{
				return null;
			}
			GameObject val = new GameObject("ControllerGlyph_" + key, new Type[2]
			{
				typeof(RectTransform),
				typeof(LayoutElement)
			});
			val.transform.SetParent(parent, false);
			LayoutElement component = val.GetComponent<LayoutElement>();
			component.minWidth = 30f;
			component.preferredWidth = 30f;
			component.flexibleWidth = 0f;
			component.minHeight = 30f;
			TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val2).richText = true;
			((Graphic)val2).raycastTarget = false;
			((TMP_Text)val2).alignment = (TextAlignmentOptions)514;
			((TMP_Text)val2).fontSize = 22f;
			((TMP_Text)val2).enableAutoSizing = false;
			((TMP_Text)val2).overflowMode = (TextOverflowModes)0;
			((TMP_Text)val2).textWrappingMode = (TextWrappingModes)0;
			if ((Object)(object)fontSource != (Object)null)
			{
				((TMP_Text)val2).font = fontSource.font;
				((TMP_Text)val2).fontSharedMaterial = fontSource.fontSharedMaterial;
				if ((Object)(object)fontSource.spriteAsset != (Object)null)
				{
					((TMP_Text)val2).spriteAsset = fontSource.spriteAsset;
				}
			}
			ControllerGlyph controllerGlyph = val.AddComponent<ControllerGlyph>();
			controllerGlyph._text = (TMP_Text)(object)val2;
			controllerGlyph._key = key;
			val.SetActive(false);
			return controllerGlyph;
		}

		internal static ControllerGlyph CreateCorner(Transform parent, string key, TMP_Text fontSource)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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_0078: Unknown result type (might be due to invalid IL or missing references)
			ControllerGlyph controllerGlyph = Create(parent, key, fontSource);
			if ((Object)(object)controllerGlyph == (Object)null)
			{
				return null;
			}
			RectTransform component = ((Component)controllerGlyph).GetComponent<RectTransform>();
			component.anchorMin = new Vector2(1f, 1f);
			component.anchorMax = new Vector2(1f, 1f);
			component.pivot = new Vector2(1f, 1f);
			component.anchoredPosition = new Vector2(-1f, -1f);
			component.sizeDelta = new Vector2(22f, 22f);
			((Component)controllerGlyph).GetComponent<LayoutElement>().ignoreLayout = true;
			controllerGlyph._text.fontSize = 18f;
			((Component)controllerGlyph).transform.SetAsLastSibling();
			return controllerGlyph;
		}

		internal void UseKey(string key)
		{
			if (!string.Equals(_key, key, StringComparison.Ordinal))
			{
				_key = key;
				_shown = null;
			}
		}

		internal void SetVisible(bool visible)
		{
			string text = (visible ? Lookup(_key) : null);
			bool flag = !string.IsNullOrEmpty(text);
			if (flag && text != _shown)
			{
				_shown = text;
				_text.text = text;
			}
			if (((Component)this).gameObject.activeSelf != flag)
			{
				((Component)this).gameObject.SetActive(flag);
			}
		}

		private static string Lookup(string key)
		{
			try
			{
				ZInput instance = ZInput.instance;
				if (instance == null)
				{
					return null;
				}
				string boundKeyString = instance.GetBoundKeyString(key, true);
				return (string.IsNullOrEmpty(boundKeyString) || boundKeyString.IndexOf('<') < 0) ? null : boundKeyString;
			}
			catch
			{
				return null;
			}
		}
	}
	internal sealed class SliderValueLink : MonoBehaviour, ISubmitHandler, IEventSystemHandler
	{
		private GuiInputField _value;

		internal static void Attach(Slider slider, GuiInputField value)
		{
			if (!((Object)(object)slider == (Object)null) && !((Object)(object)value == (Object)null))
			{
				SliderValueLink sliderValueLink = ((Component)slider).GetComponent<SliderValueLink>();
				if ((Object)(object)sliderValueLink == (Object)null)
				{
					sliderValueLink = ((Component)slider).gameObject.AddComponent<SliderValueLink>();
				}
				sliderValueLink._value = value;
				SliderValueAnchor sliderValueAnchor = ((Component)value).GetComponent<SliderValueAnchor>();
				if ((Object)(object)sliderValueAnchor == (Object)null)
				{
					sliderValueAnchor = ((Component)value).gameObject.AddComponent<SliderValueAnchor>();
				}
				sliderValueAnchor.Slider = slider;
			}
		}

		internal static Slider SliderFor(GuiInputField field)
		{
			if (!((Object)(object)field != (Object)null))
			{
				return null;
			}
			return ((Component)field).GetComponent<SliderValueAnchor>()?.Slider;
		}

		public void OnSubmit(BaseEventData eventData)
		{
			if (!((Object)(object)_value == (Object)null) && ((Behaviour)_value).isActiveAndEnabled && ((Selectable)_value).interactable && !((TMP_InputField)_value).readOnly && !KeybindCapture.IsListening && !KeybindCapture.CommittedThisFrame && !ModPicker.IsAnyOpen && !PresetEditDialog.IsOpen)
			{
				GamepadSupport.Select((Selectable)(object)_value);
				_value.ActivateInputField();
			}
		}
	}
	internal sealed class SelectedRenameGlyph : MonoBehaviour
	{
		private ControllerGlyph _glyph;

		internal static void Attach(GameObject target, TMP_Text fontSource)
		{
			if (!((Object)(object)target == (Object)null))
			{
				SelectedRenameGlyph selectedRenameGlyph = target.GetComponent<SelectedRenameGlyph>() ?? target.AddComponent<SelectedRenameGlyph>();
				if ((Object)(object)selectedRenameGlyph._glyph == (Object)null)
				{
					selectedRenameGlyph._glyph = ControllerGlyph.CreateCorner(target.transform, GamepadSupport.RenameButton, fontSource);
				}
			}
		}

		private void LateUpdate()
		{
			if (!((Object)(object)_glyph == (Object)null))
			{
				GameObject val = (((Object)(object)EventSystem.current != (Object)null) ? EventSystem.current.currentSelectedGameObject : null);
				_glyph.UseKey(GamepadSupport.RenameButton);
				_glyph.SetVisible(GamepadSupport.IsActive && (Object)(object)val == (Object)(object)((Component)this).gameObject);
			}
		}
	}
	internal sealed class SliderValueAnchor : MonoBehaviour
	{
		internal Slider Slider;
	}
	internal sealed class SliderStep : MonoBehaviour, IMoveHandler, IEventSystemHandler
	{
		private Slider _slider;

		internal static void Attach(Slider slider)
		{
			if (!((Object)(object)slider == (Object)null))
			{
				SliderStep sliderStep = ((Component)slider).GetComponent<SliderStep>();
				if ((Object)(object)sliderStep == (Object)null)
				{
					sliderStep = ((Component)slider).gameObject.AddComponent<SliderStep>();
				}
				sliderStep._slider = slider;
				PointNavigationAtSelf(slider);
			}
		}

		public void OnMove(AxisEventData eventData)
		{
			//IL_002a: 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_004e: Invalid comparison between Unknown and I4
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Invalid comparison between Unknown and I4
			if (!((Object)(object)_slider == (Object)null) && ((UIBehaviour)_slider).IsActive() && ((Selectable)_slider).IsInteractable() && ((int)eventData.moveDir == 0 || (int)eventData.moveDir == 2))
			{
				PointNavigationAtSelf(_slider);
				Step(((int)eventData.moveDir == 2) ? 1 : (-1));
			}
		}

		private void Step(int direction)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between Unknown and I4
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			if ((int)_slider.direction == 1 || (int)_slider.direction == 3)
			{
				direction = -direction;
			}
			float minValue = _slider.minValue;
			float maxValue = _slider.maxValue;
			float num = NiceStep(minValue, maxValue, _slider.wholeNumbers);
			if (!(num <= 0f))
			{
				float num2 = _slider.value / num;
				float num3 = ((direction > 0) ? (Mathf.Floor(num2 + 0.0001f) + 1f) : (Mathf.Ceil(num2 - 0.0001f) - 1f)) * num;
				num3 = (_slider.wholeNumbers ? Mathf.Round(num3) : RoundToStep(num3, num));
				num3 = Mathf.Clamp(num3, minValue, maxValue);
				if (!Mathf.Approximately(num3, _slider.value))
				{
					_slider.value = num3;
				}
			}
		}

		private static void PointNavigationAtSelf(Slider slider)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Invalid comparison between Unknown and I4
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			Navigation navigation = ((Selectable)slider).navigation;
			if ((int)((Navigation)(ref navigation)).mode != 4 || !((Object)(object)((Navigation)(ref navigation)).selectOnLeft == (Object)(object)s