Decompiled source of Automatics v1.9.0

plugins/Automatics.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using Automatics.AutomaticDoor;
using Automatics.AutomaticFarming;
using Automatics.AutomaticMapping;
using Automatics.AutomaticProcessing;
using Automatics.AutomaticStorage;
using Automatics.AutomaticSupply;
using Automatics.ConsoleCommands;
using Automatics.Valheim;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using JetBrains.Annotations;
using LitJson;
using ModUtils;
using NDesk.Options;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.UI;
using Valheim.SettingsGui;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("Automatics.SmokeTest")]
[assembly: AssemblyTitle("Automatics")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Automatics")]
[assembly: AssemblyCopyright("Copyright (c) 2022-2026 EideeHi")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("1821CB9A-56A9-4013-B268-86F0704773CF")]
[assembly: AssemblyFileVersion("1.9.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = "")]
[assembly: AssemblyVersion("1.9.0.0")]
namespace ModUtils
{
	public class Configuration
	{
		private sealed class LocalizedConfigEntry
		{
			public ConfigEntryBase Entry { get; set; }

			public L10N Localization { get; set; }

			public string Section { get; set; }

			public string Key { get; set; }

			public ConfigurationManagerAttributes Attributes { get; set; }

			public bool CategoryManaged { get; set; }

			public bool DispNameManaged { get; set; }

			public bool DescriptionManaged { get; set; }
		}

		private const int DefaultOrder = 4096;

		private static readonly object LocalizedEntriesLock;

		private static readonly Dictionary<ConfigEntryBase, LocalizedConfigEntry> LocalizedEntries;

		private static readonly string[] DescriptionFieldNames;

		private readonly ConfigFile _config;

		private readonly L10N _localization;

		private Logger _logger;

		private string Section { get; set; } = "general";

		private int Order { get; set; } = 4096;

		static Configuration()
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Expected O, but got Unknown
			//IL_00ac: 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)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Expected O, but got Unknown
			LocalizedEntriesLock = new object();
			DescriptionFieldNames = new string[4] { "<Description>k__BackingField", "Description", "description", "_description" };
			LocalizedEntries = new Dictionary<ConfigEntryBase, LocalizedConfigEntry>();
			if (!TomlTypeConverter.CanConvert(typeof(StringList)))
			{
				TomlTypeConverter.AddConverter(typeof(StringList), new TypeConverter
				{
					ConvertToObject = (string str, Type type) => (!string.IsNullOrEmpty(str)) ? new StringList(Csv.ParseLine(str, trimUnquotedFields: true)) : new StringList(),
					ConvertToString = delegate(object obj, Type type)
					{
						StringList source = (StringList)obj;
						return string.Join(", ", source.Select(Csv.Escape));
					}
				});
			}
			if (!TomlTypeConverter.CanConvert(typeof(KeyboardShortcut)))
			{
				TomlTypeConverter.AddConverter(typeof(KeyboardShortcut), new TypeConverter
				{
					ConvertToObject = (string str, Type type) => KeyboardShortcut.Deserialize(str),
					ConvertToString = delegate(object obj, Type type)
					{
						//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)
						KeyboardShortcut val = (KeyboardShortcut)obj;
						return ((KeyboardShortcut)(ref val)).Serialize();
					}
				});
			}
		}

		public Configuration(ConfigFile config, L10N localization)
		{
			_config = config;
			_localization = localization;
		}

		internal static void RefreshAllLocalizedMetadata()
		{
			LocalizedConfigEntry[] array;
			lock (LocalizedEntriesLock)
			{
				array = LocalizedEntries.Values.ToArray();
			}
			LocalizedConfigEntry[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				RefreshLocalizedMetadata(array2[i]);
			}
		}

		private static void RegisterLocalizedEntry(ConfigEntryBase entry, L10N localization, string section, string key, ConfigurationManagerAttributes attributes, bool categoryManaged, bool dispNameManaged, bool descriptionManaged)
		{
			LocalizedConfigEntry localizedConfigEntry = new LocalizedConfigEntry
			{
				Entry = entry,
				Localization = localization,
				Section = section,
				Key = key,
				Attributes = attributes,
				CategoryManaged = categoryManaged,
				DispNameManaged = dispNameManaged,
				DescriptionManaged = descriptionManaged
			};
			lock (LocalizedEntriesLock)
			{
				LocalizedEntries[entry] = localizedConfigEntry;
			}
			RefreshLocalizedMetadata(localizedConfigEntry);
		}

		private static void RefreshLocalizedMetadata(LocalizedConfigEntry entry)
		{
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Expected O, but got Unknown
			if (entry?.Entry == null || entry.Localization == null)
			{
				return;
			}
			try
			{
				ConfigurationManagerAttributes attributes = entry.Attributes;
				if (attributes != null)
				{
					if (entry.CategoryManaged)
					{
						attributes.Category = entry.Localization.Translate("@config_" + entry.Section + "_section");
					}
					if (entry.DispNameManaged)
					{
						attributes.DispName = entry.Localization.Translate("@config_" + entry.Section + "_" + entry.Key + "_name");
					}
					string text = (attributes.Description = (entry.DescriptionManaged ? entry.Localization.Translate("@config_" + entry.Section + "_" + entry.Key + "_description") : attributes.Description));
					ConfigDescription description = entry.Entry.Description;
					AcceptableValueBase val = ((description != null) ? description.AcceptableValues : null);
					object[] array = ReplaceConfigurationManagerAttributes((description != null) ? description.Tags : null, attributes);
					ConfigDescription description2 = new ConfigDescription(text, val, array);
					if (!TrySetEntryDescription(entry.Entry, description2))
					{
						Debug.LogError((object)("[ModUtils] Failed to replace ConfigDescription for [" + entry.Section + ":" + entry.Key + "]."));
					}
				}
			}
			catch (Exception arg)
			{
				Debug.LogError((object)$"[ModUtils] Failed to refresh localized config metadata for [{entry.Section}:{entry.Key}]: {arg}");
			}
		}

		private static object[] ReplaceConfigurationManagerAttributes(object[] tags, ConfigurationManagerAttributes attributes)
		{
			if (tags == null || tags.Length == 0)
			{
				return new object[1] { attributes };
			}
			bool flag = false;
			List<object> list = new List<object>(tags.Length);
			foreach (object obj in tags)
			{
				if (obj is ConfigurationManagerAttributes)
				{
					if (!flag)
					{
						list.Add(attributes);
						flag = true;
					}
				}
				else
				{
					list.Add(obj);
				}
			}
			if (!flag)
			{
				list.Add(attributes);
			}
			return list.ToArray();
		}

		private static bool TrySetEntryDescription(ConfigEntryBase entry, ConfigDescription description)
		{
			MethodInfo methodInfo = AccessTools.PropertySetter(((object)entry).GetType(), "Description") ?? AccessTools.PropertySetter(typeof(ConfigEntryBase), "Description");
			if (methodInfo != null)
			{
				methodInfo.Invoke(entry, new object[1] { description });
				return true;
			}
			string[] descriptionFieldNames = DescriptionFieldNames;
			foreach (string text in descriptionFieldNames)
			{
				FieldInfo fieldInfo = AccessTools.Field(((object)entry).GetType(), text) ?? AccessTools.Field(typeof(ConfigEntryBase), text);
				if (!(fieldInfo == null) && typeof(ConfigDescription).IsAssignableFrom(fieldInfo.FieldType))
				{
					fieldInfo.SetValue(entry, description);
					return true;
				}
			}
			return false;
		}

		private void LogSection(string section)
		{
			_logger?.Debug("[CONFIG] === " + GetSection(section) + " / [" + section + "]");
		}

		private void LogConfigEntry<T>(ConfigEntry<T> entry, ConfigurationManagerAttributes attributes)
		{
			_logger?.Debug("[CONFIG] ==== " + attributes.DispName + " / [" + ((ConfigEntryBase)entry).Definition.Key + "]");
			_logger?.Debug("[CONFIG] " + ((ConfigEntryBase)entry).Description.Description);
			_logger?.Debug("[CONFIG] ");
			Type type = typeof(T);
			object defaultValue = ((ConfigEntryBase)entry).DefaultValue;
			if (attributes.ObjToStr != null)
			{
				_logger?.Debug("[CONFIG] - Default value: " + attributes.ObjToStr(defaultValue));
			}
			else if (TomlTypeConverter.CanConvert(type))
			{
				_logger?.Debug("[CONFIG] - Default value: " + TomlTypeConverter.ConvertToString(defaultValue, type));
			}
			else
			{
				_logger?.Debug($"[CONFIG] - Default value: {defaultValue}");
			}
			AcceptableValueBase acceptableValues = ((ConfigEntryBase)entry).Description.AcceptableValues;
			if (acceptableValues != null)
			{
				string[] array = acceptableValues.ToDescriptionString().Split('\n');
				foreach (string text in array)
				{
					_logger?.Debug("[CONFIG] - " + text);
				}
			}
			else if (type.IsEnum)
			{
				List<string> list = (from x in Enum.GetValues(type).OfType<T>()
					select Enum.GetName(type, x)).ToList();
				_logger?.Debug("[CONFIG] - Acceptable values: " + string.Join(", ", list));
				if (type.GetCustomAttributes(typeof(FlagsAttribute), inherit: false).Any())
				{
					IEnumerable<string> values = list.Where((string x) => !string.Equals(x, "none", StringComparison.OrdinalIgnoreCase) && !string.Equals(x, "all", StringComparison.OrdinalIgnoreCase)).Take(2);
					_logger?.Debug("[CONFIG] - Multiple values can be set at the same time by separating them with , (e.g. " + string.Join(", ", values) + ")");
				}
			}
			_logger?.Debug("[CONFIG] ");
		}

		public void SetDebugLogger(Logger logger)
		{
			_logger = logger;
		}

		public void ChangeSection(string section, int initialOrder = 4096)
		{
			Section = section;
			Order = initialOrder;
			if (_logger != null)
			{
				LogSection(Section);
			}
		}

		private ConfigEntry<T> Bind<T>(string section, int order, string key, T defaultValue, AcceptableValueBase acceptableValue = null, Action<ConfigurationManagerAttributes> initializer = null)
		{
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Expected O, but got Unknown
			L10N.EnsurePatched();
			string section2 = GetSection(section);
			string name = GetName(section, key);
			ConfigurationManagerAttributes configurationManagerAttributes = new ConfigurationManagerAttributes
			{
				Category = section2,
				Order = order,
				DispName = name,
				CustomDrawer = ConfigurationCustomDrawer.Get(typeof(T), acceptableValue)
			};
			initializer?.Invoke(configurationManagerAttributes);
			bool categoryManaged = string.Equals(configurationManagerAttributes.Category, section2, StringComparison.Ordinal);
			bool dispNameManaged = string.Equals(configurationManagerAttributes.DispName, name, StringComparison.Ordinal);
			bool flag = string.IsNullOrEmpty(configurationManagerAttributes.Description);
			string text = (configurationManagerAttributes.Description = (flag ? GetDescription(section, key) : configurationManagerAttributes.Description));
			ConfigEntry<T> val = _config.Bind<T>(section, key, defaultValue, new ConfigDescription(text, acceptableValue, new object[1] { configurationManagerAttributes }));
			RegisterLocalizedEntry((ConfigEntryBase)(object)val, _localization, section, key, configurationManagerAttributes, categoryManaged, dispNameManaged, flag);
			if (_logger != null)
			{
				LogConfigEntry<T>(val, configurationManagerAttributes);
			}
			return val;
		}

		public ConfigEntry<T> Bind<T>(string section, string key, T defaultValue, AcceptableValueBase acceptableValue = null, Action<ConfigurationManagerAttributes> initializer = null)
		{
			return Bind(section, Order--, key, defaultValue, acceptableValue, initializer);
		}

		public ConfigEntry<T> Bind<T>(string section, string key, T defaultValue, (T, T) acceptableValue, Action<ConfigurationManagerAttributes> initializer = null) where T : IComparable
		{
			var (val, val2) = acceptableValue;
			return Bind(section, key, defaultValue, (AcceptableValueBase)(object)new AcceptableValueRange<T>(val, val2), initializer);
		}

		public ConfigEntry<T> Bind<T>(string key, T defaultValue, AcceptableValueBase acceptableValue = null, Action<ConfigurationManagerAttributes> initializer = null)
		{
			return Bind(Section, key, defaultValue, acceptableValue, initializer);
		}

		public ConfigEntry<T> Bind<T>(string key, T defaultValue, (T, T) acceptableValue, Action<ConfigurationManagerAttributes> initializer = null) where T : IComparable
		{
			return Bind(Section, key, defaultValue, acceptableValue, initializer);
		}

		private string GetSection(string section)
		{
			return _localization.Translate("@config_" + section + "_section");
		}

		private string GetName(string section, string key)
		{
			return _localization.Translate("@config_" + section + "_" + key + "_name");
		}

		private string GetDescription(string section, string key)
		{
			return _localization.Translate("@config_" + section + "_" + key + "_description");
		}
	}
	public class StringList : ICollection<string>, IEnumerable<string>, IEnumerable
	{
		private readonly HashSet<string> _values;

		public int Count => _values.Count;

		public bool IsReadOnly => false;

		public StringList()
		{
			_values = new HashSet<string>();
		}

		public StringList(IEnumerable<string> collection)
		{
			_values = new HashSet<string>(collection);
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}

		public IEnumerator<string> GetEnumerator()
		{
			return _values.GetEnumerator();
		}

		public void Add(string item)
		{
			_values.Add(item);
		}

		public void Clear()
		{
			_values.Clear();
		}

		public bool Contains(string item)
		{
			return _values.Contains(item);
		}

		public void CopyTo(string[] array, int arrayIndex)
		{
			_values.CopyTo(array, arrayIndex);
		}

		public bool Remove(string item)
		{
			return _values.Remove(item);
		}

		public bool TryAdd(string item)
		{
			return _values.Add(item);
		}
	}
	public class LocalizedDescriptionAttribute : DescriptionAttribute
	{
		private readonly string _prefix;

		private readonly string _key;

		public override string Description => L10N.Translate(_prefix, _key);

		public LocalizedDescriptionAttribute(string prefix, string key)
			: base(key)
		{
			_prefix = prefix;
			_key = key;
		}

		public LocalizedDescriptionAttribute(string key)
			: this("", key)
		{
		}
	}
	public class AcceptableValueEnum<T> : AcceptableValueBase where T : Enum
	{
		private readonly bool _isFlags;

		private readonly IList<T> _values;

		public AcceptableValueEnum(params T[] values)
			: base(typeof(T))
		{
			_isFlags = ((AcceptableValueBase)this).ValueType.GetCustomAttributes(typeof(FlagsAttribute), inherit: false).Any();
			_values = MakeValues(((AcceptableValueBase)this).ValueType, (IReadOnlyCollection<T>)(object)values, _isFlags);
		}

		private static IList<T> MakeValues(Type type, IReadOnlyCollection<T> values, bool isFlags)
		{
			object collection;
			if (values.Count != 0)
			{
				collection = values;
			}
			else
			{
				collection = Enum.GetValues(type).OfType<T>();
			}
			List<T> list = new List<T>((IEnumerable<T>)collection);
			if (!isFlags)
			{
				return list;
			}
			HashSet<long> hashSet = new HashSet<long>();
			foreach (long item in list.Select((T @enum) => Convert.ToInt64(@enum)))
			{
				long[] array = hashSet.ToArray();
				foreach (long num2 in array)
				{
					hashSet.Add(num2 | item);
				}
				hashSet.Add(item);
			}
			return hashSet.Select((long x) => Enum.ToObject(type, x)).Cast<T>().ToList();
		}

		public override object Clamp(object value)
		{
			if (!((AcceptableValueBase)this).IsValid(value))
			{
				return _values[0];
			}
			return value;
		}

		public override bool IsValid(object value)
		{
			if (value is T item)
			{
				return _values.Contains(item);
			}
			if (!(value is IConvertible))
			{
				return false;
			}
			long @long = Convert.ToInt64(value);
			return _values.Any((T x) => Convert.ToInt64(x) == @long);
		}

		public override string ToDescriptionString()
		{
			StringBuilder stringBuilder = new StringBuilder();
			Type type = typeof(T);
			List<string> list = (from x in _values
				where Enum.IsDefined(type, x)
				select Enum.GetName(type, x)).ToList();
			stringBuilder.Append("# Acceptable values: ").Append(string.Join(", ", list));
			if (!_isFlags)
			{
				return stringBuilder.ToString();
			}
			List<string> list2 = list.Where((string x) => !string.Equals(x, "none", StringComparison.OrdinalIgnoreCase) && !string.Equals(x, "all", StringComparison.OrdinalIgnoreCase)).Take(2).ToList();
			if (list2.Count == 2)
			{
				stringBuilder.Append('\n').Append("# Multiple values can be set at the same time by separating them with , (e.g. ").Append(string.Join(", ", list2))
					.Append(")");
			}
			return stringBuilder.ToString();
		}
	}
	public static class ConfigurationCustomDrawer
	{
		public delegate bool IsMatchConfig(Type type, AcceptableValueBase acceptableValue);

		public delegate Action<ConfigEntryBase> CustomDrawerSupplier();

		private sealed class MultiSelectSource<T>
		{
			internal Func<IEnumerable<T>> AllElementSupplier { get; }

			internal Func<T, string> LabelGenerator { get; }

			internal MultiSelectSource(Func<IEnumerable<T>> allElementSupplier, Func<T, string> labelGenerator)
			{
				AllElementSupplier = allElementSupplier;
				LabelGenerator = labelGenerator;
			}
		}

		private const string L10NPrefix = "mod_utils";

		private const string EnabledKey = "@config_button_enabled";

		private const string DisabledKey = "@config_button_disabled";

		private const string AddKey = "@config_button_add";

		private const string RemoveKey = "@config_button_remove";

		private static readonly Dictionary<IsMatchConfig, CustomDrawerSupplier> CustomDrawers;

		private static bool _defaultTranslationsInitialized;

		private static readonly Dictionary<string, Dictionary<string, string>> BuiltinDrawerTranslations;

		private static readonly Dictionary<string, Dictionary<string, string>> CustomDrawerTranslations;

		private static readonly Dictionary<string, string> OwnedDefaults;

		private static readonly ConditionalWeakTable<Action<ConfigEntryBase>, object> MultiSelectSources;

		static ConfigurationCustomDrawer()
		{
			BuiltinDrawerTranslations = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase)
			{
				{
					"English",
					new Dictionary<string, string>
					{
						{ "@config_button_enabled", "Enabled" },
						{ "@config_button_disabled", "Disabled" },
						{ "@config_button_add", "Add" },
						{ "@config_button_remove", "Remove" }
					}
				},
				{
					"Japanese",
					new Dictionary<string, string>
					{
						{ "@config_button_enabled", "有効" },
						{ "@config_button_disabled", "無効" },
						{ "@config_button_add", "追加" },
						{ "@config_button_remove", "削除" }
					}
				}
			};
			CustomDrawerTranslations = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase);
			OwnedDefaults = new Dictionary<string, string>();
			MultiSelectSources = new ConditionalWeakTable<Action<ConfigEntryBase>, object>();
			CustomDrawers = new Dictionary<IsMatchConfig, CustomDrawerSupplier>
			{
				{
					IsBool,
					() => Bool
				},
				{
					IsFloatWithRange,
					() => FloatSlider
				},
				{ IsStringList, StringList },
				{
					IsFlagsEnum,
					() => Flags
				}
			};
		}

		public static void RegisterDefaultDrawerTranslation(string language, string key, string value)
		{
			if (!CustomDrawerTranslations.TryGetValue(language, out var value2))
			{
				value2 = new Dictionary<string, string>();
				CustomDrawerTranslations[language] = value2;
			}
			value2[key] = value;
			if (_defaultTranslationsInitialized)
			{
				RefreshDefaultTranslations();
			}
		}

		internal static void EnsureDefaultTranslations()
		{
			if (!_defaultTranslationsInitialized)
			{
				_defaultTranslationsInitialized = TryAddDefaultTranslations();
			}
		}

		internal static void RefreshDefaultTranslations()
		{
			_defaultTranslationsInitialized = false;
			_defaultTranslationsInitialized = TryAddDefaultTranslations();
			if (!_defaultTranslationsInitialized)
			{
				Debug.LogWarning((object)"[ModUtils] Failed to refresh custom drawer fallback translations for the current language.");
			}
		}

		private static Dictionary<string, string> ResolveDrawerTranslations(string language)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>(BuiltinDrawerTranslations["English"]);
			if (CustomDrawerTranslations.TryGetValue("English", out var value))
			{
				foreach (KeyValuePair<string, string> item in value)
				{
					dictionary[item.Key] = item.Value;
				}
			}
			if (!string.Equals(language, "English", StringComparison.OrdinalIgnoreCase))
			{
				if (BuiltinDrawerTranslations.TryGetValue(language, out var value2))
				{
					foreach (KeyValuePair<string, string> item2 in value2)
					{
						dictionary[item2.Key] = item2.Value;
					}
				}
				if (CustomDrawerTranslations.TryGetValue(language, out var value3))
				{
					foreach (KeyValuePair<string, string> item3 in value3)
					{
						dictionary[item3.Key] = item3.Value;
					}
				}
			}
			return dictionary;
		}

		private static bool TryAddDefaultTranslations()
		{
			Localization instance;
			try
			{
				instance = Localization.instance;
			}
			catch (Exception)
			{
				return false;
			}
			if (instance == null)
			{
				return false;
			}
			Dictionary<string, string> field = Reflections.GetField<Dictionary<string, string>>(instance, "m_translations");
			if (field == null)
			{
				return false;
			}
			string text;
			try
			{
				text = instance.GetSelectedLanguage();
			}
			catch (Exception)
			{
				return false;
			}
			if (string.IsNullOrEmpty(text))
			{
				text = "English";
			}
			foreach (KeyValuePair<string, string> item in ResolveDrawerTranslations(text))
			{
				string translationKey = L10N.GetTranslationKey("mod_utils", item.Key);
				if (field.TryGetValue(translationKey, out var value))
				{
					if (OwnedDefaults.TryGetValue(translationKey, out var value2) && value == value2)
					{
						field[translationKey] = item.Value;
					}
				}
				else
				{
					field[translationKey] = item.Value;
				}
				OwnedDefaults[translationKey] = item.Value;
			}
			return true;
		}

		private static bool IsBool(Type type, AcceptableValueBase acceptableValue)
		{
			return type == typeof(bool);
		}

		private static bool IsFloatWithRange(Type type, AcceptableValueBase acceptableValue)
		{
			if (type == typeof(float))
			{
				return acceptableValue is AcceptableValueRange<float>;
			}
			return false;
		}

		private static bool IsStringList(Type type, AcceptableValueBase acceptableValue)
		{
			return type == typeof(StringList);
		}

		private static bool HasFlagsAttribute(Type type)
		{
			if (type.IsEnum)
			{
				return type.GetCustomAttributes(typeof(FlagsAttribute), inherit: false).Any();
			}
			return false;
		}

		private static bool IsFlagsEnum(Type type, AcceptableValueBase acceptableValue)
		{
			return HasFlagsAttribute(type);
		}

		public static void Bool(ConfigEntryBase entry)
		{
			EnsureDefaultTranslations();
			bool flag = (bool)entry.BoxedValue;
			string text = L10N.Translate("mod_utils", flag ? "@config_button_enabled" : "@config_button_disabled");
			bool flag2 = GUILayout.Toggle(flag, text, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
			if (flag2 != flag)
			{
				entry.BoxedValue = flag2;
			}
		}

		public static void FloatSlider(ConfigEntryBase entry)
		{
			AcceptableValueRange<float> val = (AcceptableValueRange<float>)(object)entry.Description.AcceptableValues;
			float num = (float)entry.BoxedValue;
			float minValue = val.MinValue;
			float maxValue = val.MaxValue;
			float num2 = GUILayout.HorizontalSlider(num, minValue, maxValue, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
			num2 = Mathf.Floor(num2 * 100f) / 100f;
			if (Math.Abs(num2 - num) > Mathf.Abs(maxValue - minValue) / 1000f)
			{
				entry.BoxedValue = num2;
			}
			string text = num.ToString("0.00", CultureInfo.InvariantCulture);
			string text2 = GUILayout.TextField(text, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) });
			if (text2 == text)
			{
				return;
			}
			try
			{
				num2 = (float)Convert.ToDouble(text2, CultureInfo.InvariantCulture);
				object boxedValue = Convert.ChangeType(((AcceptableValueBase)val).Clamp((object)num2), entry.SettingType, CultureInfo.InvariantCulture);
				entry.BoxedValue = boxedValue;
			}
			catch (FormatException)
			{
			}
		}

		private static Action<ConfigEntryBase> StringList()
		{
			string inputText = "";
			return delegate(ConfigEntryBase entry)
			{
				//IL_011b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0125: Expected O, but got Unknown
				//IL_0120: Unknown result type (might be due to invalid IL or missing references)
				//IL_013a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0144: Expected O, but got Unknown
				//IL_013f: Unknown result type (might be due to invalid IL or missing references)
				EnsureDefaultTranslations();
				int num = Mathf.Min(Screen.width, 650);
				int num2 = num - Mathf.RoundToInt((float)num / 2.5f) - 115;
				string text = L10N.Translate("mod_utils", "@config_button_add");
				string text2 = L10N.Translate("mod_utils", "@config_button_remove");
				StringList stringList = new StringList((StringList)entry.BoxedValue);
				GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MaxWidth((float)num2) });
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				inputText = GUILayout.TextField(inputText, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
				if (GUILayout.Button(text, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }) && !string.IsNullOrEmpty(inputText))
				{
					if (stringList.TryAdd(inputText))
					{
						entry.BoxedValue = stringList;
					}
					inputText = "";
				}
				GUILayout.EndHorizontal();
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				double num3 = 0.0;
				foreach (string item in stringList.ToList())
				{
					int num4 = Mathf.FloorToInt(GUI.skin.label.CalcSize(new GUIContent(item)).x) + Mathf.FloorToInt(GUI.skin.button.CalcSize(new GUIContent(text2)).x);
					num3 += (double)num4;
					if (num3 > (double)num2)
					{
						GUILayout.EndHorizontal();
						num3 = num4;
						GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					}
					GUILayout.Label(item, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) });
					if (GUILayout.Button(text2, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) }) && stringList.Remove(item))
					{
						entry.BoxedValue = stringList;
					}
				}
				GUILayout.EndHorizontal();
				GUILayout.EndVertical();
				GUILayout.FlexibleSpace();
			};
		}

		public static void Flags(ConfigEntryBase entry)
		{
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Expected O, but got Unknown
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			int num = Mathf.Min(Screen.width, 650);
			int num2 = num - Mathf.RoundToInt((float)num / 2.5f) - 115;
			Type settingType = entry.SettingType;
			long num3 = Convert.ToInt64(entry.BoxedValue);
			AcceptableValueBase acceptableValues = entry.Description.AcceptableValues;
			GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MaxWidth((float)num2) });
			int num4 = 0;
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			foreach (object value2 in Enum.GetValues(settingType))
			{
				if (acceptableValues != null && !acceptableValues.IsValid(value2))
				{
					continue;
				}
				long num5 = Convert.ToInt64(value2);
				if (num5 != 0L)
				{
					string enumLabel = GetEnumLabel(settingType, value2);
					int num6 = Mathf.FloorToInt(GUI.skin.toggle.CalcSize(new GUIContent(enumLabel + "_")).x);
					num4 += num6;
					if (num4 > num2)
					{
						GUILayout.EndHorizontal();
						num4 = num6;
						GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					}
					GUI.changed = false;
					bool flag = GUILayout.Toggle((num3 & num5) == num5, enumLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) });
					if (GUI.changed)
					{
						long value = (flag ? (num3 | num5) : (num3 & ~num5));
						entry.BoxedValue = Enum.ToObject(settingType, value);
					}
				}
			}
			GUILayout.EndHorizontal();
			GUI.changed = false;
			GUILayout.EndVertical();
			GUILayout.FlexibleSpace();
		}

		public static Action<ConfigEntryBase> MultiSelect<T>(Func<IEnumerable<T>> allElementSupplier, Func<T, string> labelGenerator) where T : IComparable<T>
		{
			Action<ConfigEntryBase> action = delegate(ConfigEntryBase entry)
			{
				//IL_013b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0145: Expected O, but got Unknown
				//IL_0140: Unknown result type (might be due to invalid IL or missing references)
				int num = Mathf.Min(Screen.width, 650);
				int num2 = num - Mathf.RoundToInt((float)num / 2.5f) - 115;
				GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MaxWidth((float)num2) });
				Type settingType = entry.SettingType;
				ConstructorInfo constructor = settingType.GetConstructor(new Type[1] { typeof(IEnumerable<T>) });
				if ((object)constructor == null)
				{
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					GUILayout.Label($"{settingType} does not define a constructor that takes IEnumerable<{typeof(T)}> as an argument.", Array.Empty<GUILayoutOption>());
					GUILayout.EndHorizontal();
					GUI.changed = false;
					GUILayout.EndVertical();
					GUILayout.FlexibleSpace();
				}
				else
				{
					ICollection<T> collection = (ICollection<T>)constructor.Invoke(new object[1] { entry.BoxedValue });
					AcceptableValueBase acceptableValues = entry.Description.AcceptableValues;
					int num3 = 0;
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					foreach (T item in allElementSupplier())
					{
						if (acceptableValues == null || acceptableValues.IsValid((object)item))
						{
							string text = labelGenerator(item) ?? item.ToString();
							int num4 = Mathf.FloorToInt(GUI.skin.toggle.CalcSize(new GUIContent(text + "_")).x);
							num3 += num4;
							if (num3 > num2)
							{
								GUILayout.EndHorizontal();
								num3 = num4;
								GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
							}
							GUI.changed = false;
							bool flag = GUILayout.Toggle(collection.Contains(item), text, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(false) });
							if (GUI.changed)
							{
								if (flag)
								{
									collection.Add(item);
								}
								else
								{
									collection.Remove(item);
								}
								entry.BoxedValue = collection;
							}
						}
					}
					GUILayout.EndHorizontal();
					GUI.changed = false;
					GUILayout.EndVertical();
					GUILayout.FlexibleSpace();
				}
			};
			MultiSelectSources.Add(action, new MultiSelectSource<T>(allElementSupplier, labelGenerator));
			return action;
		}

		internal static bool TryGetMultiSelectSource<T>(Action<ConfigEntryBase> drawer, out Func<IEnumerable<T>> allElementSupplier, out Func<T, string> labelGenerator)
		{
			if (drawer != null && MultiSelectSources.TryGetValue(drawer, out var value) && value is MultiSelectSource<T> multiSelectSource)
			{
				allElementSupplier = multiSelectSource.AllElementSupplier;
				labelGenerator = multiSelectSource.LabelGenerator;
				return true;
			}
			allElementSupplier = null;
			labelGenerator = null;
			return false;
		}

		internal static bool IsMultiSelect(Action<ConfigEntryBase> drawer)
		{
			object value;
			if (drawer != null)
			{
				return MultiSelectSources.TryGetValue(drawer, out value);
			}
			return false;
		}

		public static void Register(IsMatchConfig matcher, CustomDrawerSupplier supplier)
		{
			CustomDrawers[matcher] = supplier;
		}

		public static Action<ConfigEntryBase> Get(Type type, AcceptableValueBase acceptableValue)
		{
			return (from x in CustomDrawers
				where x.Key(type, acceptableValue)
				select x.Value()).FirstOrDefault();
		}

		private static string GetEnumLabel(Type type, object @object)
		{
			return (type.GetMember(Enum.GetName(type, @object) ?? "").FirstOrDefault()?.GetCustomAttributes(typeof(DescriptionAttribute), inherit: false).OfType<DescriptionAttribute>().FirstOrDefault())?.Description ?? @object.ToString();
		}
	}
	public static class ConfigurationGui
	{
		internal const string L10NPrefix = "mod_utils";

		internal const string ModsTabKey = "@config_gui_mods_tab";

		internal const string BackKey = "@config_gui_back";

		internal const string ResetKey = "@config_gui_reset";

		internal const string StagedApplyHintKey = "@config_gui_staged_apply_hint";

		internal const string ResetAllKey = "@config_gui_reset_all";

		internal const string ApplyKey = "@config_gui_apply";

		internal const string DiscardHeaderKey = "@config_gui_discard_header";

		internal const string DiscardQuestionKey = "@config_gui_discard_question";

		internal const string SearchPlaceholderKey = "@config_gui_search";

		internal const string ShowAdvancedKey = "@config_gui_show_advanced";

		internal const string ReadOnlyKey = "@config_gui_read_only";

		internal const string PressKeyKey = "@config_gui_press_key";

		internal const string ClearKey = "@config_gui_clear";

		private const string ShowOnSettingsScreenSection = "mod_utils";

		private const string ShowOnSettingsScreenKey = "show_on_settings_screen";

		private const string ShowOnSettingsScreenCategoryKey = "@config_mod_utils_section";

		private const string ShowOnSettingsScreenNameKey = "@config_mod_utils_show_on_settings_screen_name";

		private const string ShowOnSettingsScreenDescriptionKey = "@config_mod_utils_show_on_settings_screen_description";

		internal const string PageName = "ModUtils.ModsTab.v1";

		internal const string TabButtonName = "ModUtils.ModsTab.v1.Button";

		internal const string ListName = "List";

		internal const string PanelsName = "Panels";

		internal const string ButtonTemplateName = "ButtonTemplate";

		private const string HarmonyIdPrefix = "net.eideehi.modutils.configurationgui.";

		private const float ListPadding = 16f;

		private const float ListSpacing = 8f;

		private const float ModButtonMinWidth = 320f;

		private static readonly List<ConfigurationGuiPlugin> Plugins = new List<ConfigurationGuiPlugin>();

		private static readonly List<KeyValuePair<ConfigurationCustomDrawer.IsMatchConfig, Func<ConfigurationGuiCustomEditor>>> CustomEditors = new List<KeyValuePair<ConfigurationCustomDrawer.IsMatchConfig, Func<ConfigurationGuiCustomEditor>>>();

		private static readonly Dictionary<string, Dictionary<string, string>> DefaultTranslations = new Dictionary<string, Dictionary<string, string>>
		{
			{
				"English",
				new Dictionary<string, string>
				{
					{ "@config_gui_mods_tab", "Mods" },
					{ "@config_gui_back", "Back" },
					{ "@config_gui_reset", "Reset" },
					{ "@config_gui_staged_apply_hint", "Changes are saved when you press Apply." },
					{ "@config_gui_reset_all", "Reset all" },
					{ "@config_gui_apply", "Apply" },
					{ "@config_gui_discard_header", "Unsaved changes" },
					{ "@config_gui_discard_question", "Discard the changes that are not applied and go back?" },
					{ "@config_gui_search", "Search" },
					{ "@config_gui_show_advanced", "Show advanced settings" },
					{ "@config_gui_read_only", "Read-only" },
					{ "@config_gui_press_key", "Press a key..." },
					{ "@config_gui_clear", "Clear" },
					{ "@config_mod_utils_section", "Settings screen" },
					{ "@config_mod_utils_show_on_settings_screen_name", "Show on the Settings screen" },
					{ "@config_mod_utils_show_on_settings_screen_description", "Shows this mod on the Mods tab of the game's Settings screen. When no mod is shown there, the tab is not added. A change applies the next time the Settings screen opens. After turning this off, turn it back on in ConfigurationManager or in this mod's config file." }
				}
			},
			{
				"Japanese",
				new Dictionary<string, string>
				{
					{ "@config_gui_mods_tab", "Mod" },
					{ "@config_gui_back", "戻る" },
					{ "@config_gui_reset", "リセット" },
					{ "@config_gui_staged_apply_hint", "変更は「確定」を押すと保存されます。" },
					{ "@config_gui_reset_all", "すべて初期値に戻す" },
					{ "@config_gui_apply", "確定" },
					{ "@config_gui_discard_header", "未確定の変更" },
					{ "@config_gui_discard_question", "確定していない変更を破棄して戻りますか?" },
					{ "@config_gui_search", "検索" },
					{ "@config_gui_show_advanced", "上級者向けの設定を表示" },
					{ "@config_gui_read_only", "読み取り専用" },
					{ "@config_gui_press_key", "キーを押してください..." },
					{ "@config_gui_clear", "クリア" },
					{ "@config_mod_utils_section", "設定画面" },
					{ "@config_mod_utils_show_on_settings_screen_name", "設定画面に表示" },
					{ "@config_mod_utils_show_on_settings_screen_description", "ゲームの設定画面の「Mod」タブにこの Mod を表示します。表示する Mod がひとつもないときは、タブは追加されません。変更は次に設定画面を開いたときに反映されます。オフにしたあとで戻すときは、ConfigurationManager かこの Mod の設定ファイルで変更してください。" }
				}
			}
		};

		private static bool _patchAttempted;

		private static bool _translationsRegistered;

		public static void Register(BaseUnityPlugin plugin)
		{
			if ((Object)(object)plugin == (Object)null)
			{
				throw new ArgumentNullException("plugin");
			}
			BepInPlugin metadata = plugin.Info.Metadata;
			if (!Plugins.Any((ConfigurationGuiPlugin x) => string.Equals(x.Guid, metadata.GUID, StringComparison.Ordinal)))
			{
				RegisterTranslations();
				ConfigurationCustomDrawer.EnsureDefaultTranslations();
				ConfigEntry<bool> showOnSettingsScreen = new Configuration(plugin.Config, new L10N("mod_utils")).Bind("mod_utils", "show_on_settings_screen", defaultValue: true);
				Plugins.Add(new ConfigurationGuiPlugin(metadata.GUID, metadata.Name, metadata.Version, plugin.Config, showOnSettingsScreen));
				ApplyPatch(metadata.GUID);
			}
		}

		public static void RegisterEditor(ConfigurationCustomDrawer.IsMatchConfig matcher, Func<ConfigurationGuiCustomEditor> factory)
		{
			if (matcher == null)
			{
				throw new ArgumentNullException("matcher");
			}
			if (factory == null)
			{
				throw new ArgumentNullException("factory");
			}
			CustomEditors.Add(new KeyValuePair<ConfigurationCustomDrawer.IsMatchConfig, Func<ConfigurationGuiCustomEditor>>(matcher, factory));
		}

		internal static bool TryCreateCustomEditor(ConfigEntryBase entry, string pluginName, out ConfigurationGuiCustomEditor editor)
		{
			editor = null;
			try
			{
				Type settingType = entry.SettingType;
				ConfigDescription description = entry.Description;
				AcceptableValueBase acceptableValue = ((description != null) ? description.AcceptableValues : null);
				for (int num = CustomEditors.Count - 1; num >= 0; num--)
				{
					if (CustomEditors[num].Key(settingType, acceptableValue))
					{
						editor = CustomEditors[num].Value();
						break;
					}
				}
				return true;
			}
			catch (Exception ex)
			{
				ConfigDefinition definition = entry.Definition;
				Debug.LogError((object)$"[ModUtils] Failed to create the registered editor for [{definition.Section}:{definition.Key}] of {pluginName}: {ex}");
				return false;
			}
		}

		internal static string Translate(string key)
		{
			return L10N.Translate("mod_utils", key);
		}

		internal static Transform FindChild(Transform parent, string name)
		{
			if ((Object)(object)parent == (Object)null)
			{
				return null;
			}
			for (int i = 0; i < parent.childCount; i++)
			{
				Transform child = parent.GetChild(i);
				if (string.Equals(((Object)child).name, name, StringComparison.Ordinal))
				{
					return child;
				}
			}
			return null;
		}

		private static void RegisterTranslations()
		{
			if (_translationsRegistered)
			{
				return;
			}
			_translationsRegistered = true;
			foreach (KeyValuePair<string, Dictionary<string, string>> defaultTranslation in DefaultTranslations)
			{
				foreach (KeyValuePair<string, string> item in defaultTranslation.Value)
				{
					ConfigurationCustomDrawer.RegisterDefaultDrawerTranslation(defaultTranslation.Key, item.Key, item.Value);
				}
			}
		}

		private static void ApplyPatch(string guid)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			if (_patchAttempted)
			{
				return;
			}
			_patchAttempted = true;
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(Settings), "Awake", (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					Debug.LogWarning((object)"[ModUtils] Settings.Awake was not found. The Mods settings tab is unavailable.");
				}
				else
				{
					new Harmony("net.eideehi.modutils.configurationgui." + guid).Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ConfigurationGui), "OnSettingsAwake", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
			catch (Exception arg)
			{
				Debug.LogError((object)$"[ModUtils] Failed to patch Settings.Awake. The Mods settings tab is unavailable. {arg}");
			}
		}

		private static void OnSettingsAwake(Settings __instance)
		{
			try
			{
				AddModsTab(__instance);
			}
			catch (Exception arg)
			{
				Debug.LogError((object)$"[ModUtils] Failed to add the Mods tab to the settings screen: {arg}");
			}
		}

		private static void AddModsTab(Settings settings)
		{
			if (!Plugins.Any((ConfigurationGuiPlugin x) => x.ShowOnSettingsScreen.Value))
			{
				return;
			}
			TabHandler componentInChildren = ((Component)settings).GetComponentInChildren<TabHandler>();
			if (!((Object)(object)componentInChildren == (Object)null) && componentInChildren.m_tabs != null && componentInChildren.m_tabs.Count != 0)
			{
				ConfigurationCustomDrawer.RefreshDefaultTranslations();
				RectTransform val = FindPage(componentInChildren) ?? CreatePage(settings, componentInChildren);
				if (!((Object)(object)val == (Object)null))
				{
					AddPluginButtons(val);
				}
			}
		}

		private static RectTransform FindPage(TabHandler tabHandler)
		{
			foreach (Tab tab in tabHandler.m_tabs)
			{
				if ((Object)(object)tab?.m_page != (Object)null && string.Equals(((Object)tab.m_page).name, "ModUtils.ModsTab.v1", StringComparison.Ordinal))
				{
					return tab.m_page;
				}
			}
			return null;
		}

		private static RectTransform CreatePage(Settings settings, TabHandler tabHandler)
		{
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Expected O, but got Unknown
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Expected O, but got Unknown
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Expected O, but got Unknown
			//IL_013d: Expected O, but got Unknown
			List<Tab> tabs = tabHandler.m_tabs;
			Button val = null;
			int num = tabs.Count - 1;
			while (num >= 0 && (Object)(object)val == (Object)null)
			{
				if ((Object)(object)tabs[num]?.m_button != (Object)null)
				{
					val = tabs[num].m_button;
				}
				num--;
			}
			RectTransform val2 = tabs[0]?.m_page;
			Button val3 = ConfigurationGuiTemplates.FindButton(settings);
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || (Object)(object)((Transform)val2).parent == (Object)null || (Object)(object)val3 == (Object)null)
			{
				Debug.LogWarning((object)"[ModUtils] The settings screen has no usable tab button, page or button to copy. The Mods tab is not added.");
				return null;
			}
			GameObject val4 = null;
			GameObject val5 = null;
			try
			{
				val4 = CreateTabButton(settings, val);
				val5 = CreatePageObject(val2, tabs);
				CreatePageChildren(settings, (RectTransform)val5.transform, val3);
				val5.AddComponent<ConfigurationGuiTab>();
			}
			catch
			{
				if ((Object)(object)val4 != (Object)null)
				{
					Object.Destroy((Object)(object)val4);
				}
				if ((Object)(object)val5 != (Object)null)
				{
					Object.Destroy((Object)(object)val5);
				}
				throw;
			}
			RectTransform val6 = (RectTransform)val5.transform;
			tabs.Add(new Tab
			{
				m_button = val4.GetComponent<Button>(),
				m_page = val6,
				m_default = false,
				m_onClick = new UnityEvent()
			});
			return val6;
		}

		private static GameObject CreateTabButton(Settings settings, Button source)
		{
			Transform transform = ((Component)source).transform;
			GameObject val = Object.Instantiate<GameObject>(((Component)source).gameObject, transform.parent, false);
			((Object)val).name = "ModUtils.ModsTab.v1.Button";
			val.transform.SetSiblingIndex(transform.GetSiblingIndex() + 1);
			RemoveTabKeyHints(settings, transform, val.transform);
			ConfigurationGuiTemplates.Sanitize(val);
			string text = "$" + L10N.GetTranslationKey("mod_utils", "@config_gui_mods_tab");
			TMP_Text[] componentsInChildren = val.GetComponentsInChildren<TMP_Text>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].text = text;
			}
			Localization val2 = L10N.TryGetLocalization();
			if (val2 != null)
			{
				val2.Localize(val.transform);
			}
			return val;
		}

		private static void RemoveTabKeyHints(Settings settings, Transform source, Transform clone)
		{
			if (!(AccessTools.Field(typeof(Settings), "m_tabKeyHints")?.GetValue(settings) is GameObject[] array))
			{
				return;
			}
			GameObject[] array2 = array;
			foreach (GameObject val in array2)
			{
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val.transform == (Object)(object)source) && val.transform.IsChildOf(source))
				{
					Transform val2 = FindCopy(source, clone, val.transform);
					if (!((Object)(object)val2 == (Object)null))
					{
						((Component)val2).gameObject.SetActive(false);
						Object.Destroy((Object)(object)((Component)val2).gameObject);
					}
				}
			}
		}

		private static Transform FindCopy(Transform sourceRoot, Transform cloneRoot, Transform sourceTarget)
		{
			List<int> list = new List<int>();
			Transform val = sourceTarget;
			while ((Object)(object)val != (Object)(object)sourceRoot)
			{
				list.Add(val.GetSiblingIndex());
				val = val.parent;
			}
			Transform val2 = cloneRoot;
			for (int num = list.Count - 1; num >= 0; num--)
			{
				if (list[num] >= val2.childCount)
				{
					return null;
				}
				val2 = val2.GetChild(list[num]);
			}
			return val2;
		}

		private static GameObject CreatePageObject(RectTransform firstPage, List<Tab> tabs)
		{
			//IL_0025: 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_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: 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_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Expected O, but got Unknown
			GameObject val = new GameObject("ModUtils.ModsTab.v1", new Type[1] { typeof(RectTransform) });
			val.SetActive(false);
			val.layer = ((Component)firstPage).gameObject.layer;
			RectTransform val2 = (RectTransform)val.transform;
			((Transform)val2).SetParent(((Transform)firstPage).parent, false);
			val2.anchorMin = firstPage.anchorMin;
			val2.anchorMax = firstPage.anchorMax;
			val2.pivot = firstPage.pivot;
			val2.sizeDelta = firstPage.sizeDelta;
			val2.anchoredPosition = firstPage.anchoredPosition;
			((Transform)val2).localScale = ((Transform)firstPage).localScale;
			((Transform)val2).localRotation = ((Transform)firstPage).localRotation;
			int num = tabs.Where((Tab x) => (Object)(object)x?.m_page != (Object)null && (Object)(object)((Transform)x.m_page).parent == (Object)(object)((Transform)firstPage).parent).Max((Tab x) => ((Transform)x.m_page).GetSiblingIndex());
			((Transform)val2).SetSiblingIndex(num + 1);
			return val;
		}

		private static void CreatePageChildren(Settings settings, RectTransform page, Button buttonStyle)
		{
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Expected O, but got Unknown
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Expected O, but got Unknown
			RectTransform obj = ConfigurationGuiTemplates.CreateRect("List", (Transform)(object)page);
			ConfigurationGuiTemplates.Stretch(obj, 16f, 16f, 16f, 16f);
			VerticalLayoutGroup obj2 = ((Component)obj).gameObject.AddComponent<VerticalLayoutGroup>();
			((LayoutGroup)obj2).childAlignment = (TextAnchor)1;
			((HorizontalOrVerticalLayoutGroup)obj2).spacing = 8f;
			((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = false;
			((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = false;
			RectTransform obj3 = ConfigurationGuiTemplates.CreateRect("Panels", (Transform)(object)page);
			ConfigurationGuiTemplates.Stretch(obj3, 0f, 0f, 0f, 0f);
			((Component)obj3).gameObject.SetActive(false);
			Button val = ConfigurationGuiTemplates.Clone<Button>(buttonStyle, (Transform)(object)page, "ButtonTemplate");
			((Component)val).gameObject.SetActive(false);
			TMP_Text val2 = ((Component)val).GetComponentInChildren<TMP_Text>(true);
			if ((Object)(object)val2 == (Object)null)
			{
				val2 = (TMP_Text)(object)ConfigurationGuiTemplates.CreateText(((Component)val).transform, "Label", ConfigurationGuiTemplates.FindLabel(settings));
				ConfigurationGuiTemplates.Stretch((RectTransform)val2.transform, 0f, 0f, 0f, 0f);
				val2.alignment = (TextAlignmentOptions)514;
			}
			val2.text = "";
			RectTransform val3 = (RectTransform)((Component)buttonStyle).transform;
			GameObject gameObject = ((Component)val).gameObject;
			Rect rect = val3.rect;
			ConfigurationGuiTemplates.AddLayout(gameObject, -1f, -1f, Mathf.Max(((Rect)(ref rect)).width, 320f), ConfigurationGuiTemplates.VanillaControlHeight((Component)(object)buttonStyle));
		}

		private static void AddPluginButtons(RectTransform page)
		{
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Expected O, but got Unknown
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Expected O, but got Unknown
			Transform val = FindChild((Transform)(object)page, "List");
			Transform val2 = FindChild((Transform)(object)page, "ButtonTemplate");
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
			{
				Debug.LogWarning((object)"[ModUtils] The Mods tab has no mod list or button template. Mods cannot be listed.");
				return;
			}
			foreach (ConfigurationGuiPlugin plugin in Plugins)
			{
				if (plugin.ShowOnSettingsScreen.Value && !((Object)(object)FindChild(val, plugin.Guid) != (Object)null))
				{
					GameObject obj = Object.Instantiate<GameObject>(((Component)val2).gameObject, val, false);
					((Object)obj).name = plugin.Guid;
					Button component = obj.GetComponent<Button>();
					TMP_Text componentInChildren = obj.GetComponentInChildren<TMP_Text>(true);
					if ((Object)(object)componentInChildren != (Object)null)
					{
						componentInChildren.text = plugin.Name;
					}
					ConfigurationGuiPlugin owner = plugin;
					component.onClick = new ButtonClickedEvent();
					((UnityEvent)component.onClick).AddListener((UnityAction)delegate
					{
						ConfigurationGuiPanel.Open(owner, page);
					});
					obj.SetActive(true);
				}
			}
			SortByLabel(val);
		}

		private static void SortByLabel(Transform list)
		{
			List<Transform> list2 = new List<Transform>();
			for (int i = 0; i < list.childCount; i++)
			{
				list2.Add(list.GetChild(i));
			}
			List<Transform> list3 = list2.OrderBy<Transform, string>(GetLabel, StringComparer.OrdinalIgnoreCase).ThenBy<Transform, string>((Transform x) => ((Object)x).name, StringComparer.Ordinal).ToList();
			for (int num = 0; num < list3.Count; num++)
			{
				list3[num].SetSiblingIndex(num);
			}
		}

		private static string GetLabel(Transform button)
		{
			TMP_Text componentInChildren = ((Component)button).GetComponentInChildren<TMP_Text>(true);
			if (!((Object)(object)componentInChildren != (Object)null))
			{
				return ((Object)button).name;
			}
			return componentInChildren.text ?? "";
		}
	}
	internal sealed class ConfigurationGuiPlugin
	{
		internal string Guid { get; }

		internal string Name { get; }

		internal Version Version { get; }

		internal ConfigFile Config { get; }

		internal ConfigEntry<bool> ShowOnSettingsScreen { get; }

		internal ConfigurationGuiPlugin(string guid, string name, Version version, ConfigFile config, ConfigEntry<bool> showOnSettingsScreen)
		{
			Guid = guid;
			Name = name;
			Version = version;
			Config = config;
			ShowOnSettingsScreen = showOnSettingsScreen;
		}
	}
	public abstract class ConfigurationGuiCustomEditor
	{
		private ConfigurationGuiCustomEditorHost _host;

		private ConfigurationGuiWidgets _widgets;

		protected ConfigEntryBase Entry => _host.HostEntry;

		protected object Value => _host.HostValue;

		protected float LineHeight { get; set; }

		internal float HostLineHeight => LineHeight;

		protected abstract float Build(RectTransform slot, ConfigurationGuiWidgets widgets);

		protected abstract void Refresh();

		protected virtual void SetInteractable(bool interactable)
		{
			_widgets?.SetInteractable(interactable);
		}

		protected virtual bool ConsumesEscape()
		{
			if (_widgets != null)
			{
				return _widgets.ConsumesEscape();
			}
			return false;
		}

		protected void Commit(object value)
		{
			_host.CommitFromEditor(value);
		}

		protected void SetHeight(float height)
		{
			_host.SetSlotHeight(height);
		}

		internal void Attach(ConfigurationGuiCustomEditorHost host)
		{
			_host = host;
		}

		internal float HostBuild(RectTransform slot, ConfigurationGuiWidgets widgets)
		{
			_widgets = widgets;
			return Build(slot, widgets);
		}

		internal void HostRefresh()
		{
			Refresh();
		}

		internal void HostSetInteractable(bool interactable)
		{
			SetInteractable(interactable);
		}

		internal bool HostConsumesEscape()
		{
			return ConsumesEscape();
		}
	}
	internal sealed class ConfigurationGuiCustomEditorHost : ConfigurationGuiEditor
	{
		private readonly ConfigurationGuiCustomEditor _editor;

		private readonly bool _readOnly;

		private ConfigurationGuiEditor _fallback;

		private RectTransform _slot;

		internal override bool IsEditable => _fallback == null;

		internal ConfigEntryBase HostEntry => base.Entry;

		internal object HostValue => base.Value;

		internal ConfigurationGuiCustomEditorHost(ConfigEntryBase entry, ConfigurationGuiCustomEditor editor)
			: base(entry)
		{
			_editor = editor;
			ConfigurationManagerAttributes attributes = ConfigurationGuiPanel.GetAttributes(entry);
			_readOnly = attributes != null && attributes.ReadOnly == true;
			editor?.Attach(this);
		}

		internal override float Build(RectTransform slot, ConfigurationGuiTemplates templates)
		{
			_slot = slot;
			VerticalLayoutGroup obj = ((Component)slot).gameObject.AddComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj).spacing = 4f;
			((LayoutGroup)obj).childAlignment = (TextAnchor)0;
			((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false;
			try
			{
				float result = _editor.HostBuild(slot, new ConfigurationGuiWidgets(templates));
				base.LineHeight = _editor.HostLineHeight;
				return result;
			}
			catch (Exception e)
			{
				LogError("Build", e);
			}
			for (int num = ((Transform)slot).childCount - 1; num >= 0; num--)
			{
				Object.DestroyImmediate((Object)(object)((Component)((Transform)slot).GetChild(num)).gameObject);
			}
			Component[] components = ((Component)slot).GetComponents<Component>();
			for (int num2 = components.Length - 1; num2 >= 0; num2--)
			{
				if (!(components[num2] is RectTransform))
				{
					Object.DestroyImmediate((Object)(object)components[num2]);
				}
			}
			base.LineHeight = 0f;
			_fallback = ConfigurationGuiEditor.CreateReadOnly(base.Entry, base.Pending);
			return _fallback.Build(slot, templates);
		}

		internal override void Refresh()
		{
			if (_fallback != null)
			{
				_fallback.Refresh();
				return;
			}
			try
			{
				_editor.HostRefresh();
			}
			catch (Exception e)
			{
				LogError("Refresh", e);
			}
		}

		internal override void SetInteractable(bool interactable)
		{
			if (_fallback != null)
			{
				_fallback.SetInteractable(interactable);
				return;
			}
			try
			{
				_editor.HostSetInteractable(interactable);
			}
			catch (Exception e)
			{
				LogError("SetInteractable", e);
			}
		}

		internal override bool ConsumesEscape()
		{
			if (_fallback != null)
			{
				return false;
			}
			try
			{
				return _editor.HostConsumesEscape();
			}
			catch (Exception e)
			{
				LogError("ConsumesEscape", e);
				return false;
			}
		}

		internal void CommitFromEditor(object value)
		{
			if (_readOnly)
			{
				Refresh();
			}
			else
			{
				Commit(value);
			}
		}

		internal void SetSlotHeight(float height)
		{
			LayoutElement val = (((Object)(object)_slot != (Object)null) ? ((Component)_slot).GetComponent<LayoutElement>() : null);
			if (!((Object)(object)val == (Object)null))
			{
				val.minHeight = height;
				val.preferredHeight = height;
			}
		}

		private void LogError(string member, Exception e)
		{
			ConfigDefinition definition = base.Entry.Definition;
			Debug.LogError((object)$"[ModUtils] The registered editor for [{definition.Section}:{definition.Key}] of {base.Pending.PluginName} failed in {member}: {e}");
		}
	}
	internal abstract class ConfigurationGuiEditor
	{
		protected ConfigEntryBase Entry { get; }

		protected object Value => Pending.Get(Entry);

		private protected ConfigurationGuiPendingValues Pending { get; private set; }

		internal virtual bool IsEditable => true;

		internal float LineHeight { get; private protected set; }

		protected ConfigurationGuiEditor(ConfigEntryBase entry)
		{
			Entry = entry;
		}

		internal static ConfigurationGuiEditor Create(ConfigEntryBase entry, ConfigurationGuiPendingValues pending, ConfigurationGuiTemplates templates)
		{
			ConfigurationGuiEditor configurationGuiEditor = Select(entry, pending.PluginName, templates);
			configurationGuiEditor.Pending = pending;
			return configurationGuiEditor;
		}

		internal static ConfigurationGuiEditor CreateReadOnly(ConfigEntryBase entry, ConfigurationGuiPendingValues pending)
		{
			return new ConfigurationGuiReadOnlyEditor(entry)
			{
				Pending = pending
			};
		}

		private static ConfigurationGuiEditor Select(ConfigEntryBase entry, string pluginName, ConfigurationGuiTemplates templates)
		{
			if (!ConfigurationGui.TryCreateCustomEditor(entry, pluginName, out var editor))
			{
				return new ConfigurationGuiReadOnlyEditor(entry);
			}
			if (editor != null)
			{
				return new ConfigurationGuiCustomEditorHost(entry, editor);
			}
			Type settingType = entry.SettingType;
			ConfigDescription description = entry.Description;
			AcceptableValueBase val = ((description != null) ? description.AcceptableValues : null);
			if (settingType == typeof(bool) && (Object)(object)templates.Toggle != (Object)null)
			{
				return new ConfigurationGuiToggleEditor(entry);
			}
			if (settingType == typeof(int) && val is AcceptableValueRange<int> val2 && (Object)(object)templates.Slider != (Object)null && (Object)(object)templates.InputField != (Object)null)
			{
				return new ConfigurationGuiSliderEditor(entry, val2.MinValue, val2.MaxValue, wholeNumbers: true);
			}
			if (settingType == typeof(float) && val is AcceptableValueRange<float> val3 && (Object)(object)templates.Slider != (Object)null && (Object)(object)templates.InputField != (Object)null)
			{
				return new ConfigurationGuiSliderEditor(entry, val3.MinValue, val3.MaxValue, wholeNumbers: false);
			}
			if ((settingType == typeof(int) || settingType == typeof(float) || settingType == typeof(string)) && (Object)(object)templates.InputField != (Object)null)
			{
				return new ConfigurationGuiTextEditor(entry, serialized: false);
			}
			if (settingType == typeof(KeyboardShortcut) && (Object)(object)templates.Button != (Object)null)
			{
				return new ConfigurationGuiKeyEditor(entry, shortcut: true);
			}
			if (settingType == typeof(KeyCode) && (Object)(object)templates.Button != (Object)null)
			{
				return new ConfigurationGuiKeyEditor(entry, shortcut: false);
			}
			if (settingType.IsEnum)
			{
				if (!settingType.IsDefined(typeof(FlagsAttribute), inherit: false))
				{
					if ((Object)(object)templates.Dropdown != (Object)null)
					{
						return new ConfigurationGuiDropdownEditor(entry);
					}
				}
				else if ((Object)(object)templates.Toggle != (Object)null)
				{
					return new ConfigurationGuiFlagsEditor(entry);
				}
			}
			if (settingType == typeof(StringList))
			{
				ConfigDescription description2 = entry.Description;
				Action<ConfigEntryBase> drawer = ((description2 == null) ? null : description2.Tags?.OfType<ConfigurationManagerAttributes>().FirstOrDefault()?.CustomDrawer);
				Func<IEnumerable<string>> allElementSupplier;
				Func<string, string> labelGenerator;
				if (!ConfigurationCustomDrawer.IsMultiSelect(drawer))
				{
					if ((Object)(object)templates.InputField != (Object)null)
					{
						return new ConfigurationGuiTextEditor(entry, serialized: true);
					}
				}
				else if (ConfigurationCustomDrawer.TryGetMultiSelectSource(drawer, out allElementSupplier, out labelGenerator) && (Object)(object)templates.Toggle != (Object)null && (Object)(object)templates.Button != (Object)null && settingType.GetConstructor(new Type[1] { typeof(IEnumerable<string>) }) != null)
				{
					return new ConfigurationGuiMultiSelectEditor(entry, allElementSupplier, labelGenerator);
				}
			}
			return new ConfigurationGuiReadOnlyEditor(entry);
		}

		protected static string GetEnumLabel(Type type, object value)
		{
			string name = Enum.GetName(type, value);
			return (((name == null) ? null : type.GetMember(name).FirstOrDefault())?.GetCustomAttributes(typeof(DescriptionAttribute), inherit: false).OfType<DescriptionAttribute>().FirstOrDefault())?.Description ?? value.ToString();
		}

		internal abstract float Build(RectTransform slot, ConfigurationGuiTemplates templates);

		internal abstract void Refresh();

		internal abstract void SetInteractable(bool interactable);

		internal virtual bool ConsumesEscape()
		{
			return false;
		}

		internal void ResetToDefault()
		{
			Commit(Entry.DefaultValue);
		}

		protected void Commit(object value)
		{
			try
			{
				Pending.Stage(Entry, value);
			}
			catch (Exception arg)
			{
				Debug.LogError((object)$"[ModUtils] Failed to stage [{Entry.Definition.Section}:{Entry.Definition.Key}]: {arg}");
			}
			Refresh();
		}
	}
	internal sealed class ConfigurationGuiToggleEditor : ConfigurationGuiEditor
	{
		private Toggle _toggle;

		internal ConfigurationGuiToggleEditor(ConfigEntryBase entry)
			: base(entry)
		{
		}

		internal override float Build(RectTransform slot, ConfigurationGuiTemplates templates)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			_toggle = ConfigurationGuiTemplates.Clone<Toggle>(templates.Toggle, (Transform)(object)slot, "Toggle");
			TMP_Text[] componentsInChildren = ((Component)_toggle).GetComponentsInChildren<TMP_Text>(true);
			foreach (TMP_Text val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)(object)_toggle.graphic)
				{
					val.text = "";
				}
			}
			float num = ConfigurationGuiTemplates.ControlHeight((Component)(object)templates.Toggle);
			ConfigurationGuiTemplates.FillWidth((RectTransform)((Component)_toggle).transform, num);
			Refresh();
			((UnityEvent<bool>)(object)_toggle.onValueChanged).AddListener((UnityAction<bool>)delegate(bool value)
			{
				Commit(value);
			});
			return num;
		}

		internal override void Refresh()
		{
			_toggle.SetIsOnWithoutNotify((bool)base.Value);
		}

		internal override void SetInteractable(bool interactable)
		{
			((Selectable)_toggle).interactable = interactable;
		}
	}
	internal sealed class ConfigurationGuiSliderEditor : ConfigurationGuiEditor
	{
		private const float ValueWidth = 110f;

		private const float ValueSpacing = 8f;

		private readonly float _min;

		private readonly float _max;

		private readonly bool _wholeNumbers;

		private ConfigurationGuiInputField _field;

		private ConfigurationGuiPointerHold _hold;

		private string _shown = "";

		private Slider _slider;

		internal ConfigurationGuiSliderEditor(ConfigEntryBase entry, float min, float max, bool wholeNumbers)
			: base(entry)
		{
			_min = min;
			_max = max;
			_wholeNumbers = wholeNumbers;
		}

		internal override float Build(RectTransform slot, ConfigurationGuiTemplates templates)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Expected O, but got Unknown
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			float num = ConfigurationGuiTemplates.ControlHeight((Component)(object)templates.Slider);
			_slider = ConfigurationGuiTemplates.Clone<Slider>(templates.Slider, (Transform)(object)slot, "Slider");
			TMP_Text[] componentsInChildren = ((Component)_slider).GetComponentsInChildren<TMP_Text>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].text = "";
			}
			RectTransform val = (RectTransform)((Component)_slider).transform;
			ConfigurationGuiTemplates.FillWidth(val, num);
			val.offsetMax = new Vector2(-118f, val.offsetMax.y);
			Navigation navigation = ((Selectable)_slider).navigation;
			((Navigation)(ref navigation)).mode = (Mode)2;
			((Selectable)_slider).navigation = navigation;
			_slider.wholeNumbers = _wholeNumbers;
			_slider.minValue = _min;
			_slider.maxValue = _max;
			_field = ConfigurationGuiInputField.Create(templates, (Transform)(object)slot, "Value", OnEditFinished);
			RectTransform val2 = (RectTransform)((Component)_field.Input).transform;
			val2.anchorMin = new Vector2(1f, 0.5f);
			val2.anchorMax = new Vector2(1f, 0.5f);
			val2.pivot = new Vector2(1f, 0.5f);
			val2.sizeDelta = new Vector2(110f, num);
			val2.anchoredPosition = Vector2.zero;
			_hold = ((Component)_slider).gameObject.AddComponent<ConfigurationGuiPointerHold>();
			_hold.Released = OnReleased;
			Refresh();
			((UnityEvent<float>)(object)_slider.onValueChanged).AddListener((UnityAction<float>)OnValueChanged);
			((UnityEvent<string>)(object)_field.Input.onValueChanged).AddListener((UnityAction<string>)OnTextChanged);
			return num;
		}

		internal override void Refresh()
		{
			object value = base.Value;
			if (_wholeNumbers)
			{
				int num = (int)value;
				_slider.SetValueWithoutNotify((float)num);
				_shown = num.ToString(CultureInfo.InvariantCulture);
			}
			else
			{
				float valueWithoutNotify = (float)value;
				_slider.SetValueWithoutNotify(valueWithoutNotify);
				_shown = valueWithoutNotify.ToString(CultureInfo.InvariantCulture);
			}
			_field.Input.SetTextWithoutNotify(_shown);
		}

		internal override void SetInteractable(bool interactable)
		{
			((Selectable)_slider).interactable = interactable;
			((Selectable)_field.Input).interactable = interactable;
		}

		internal override bool ConsumesEscape()
		{
			return _field.ConsumesEscape();
		}

		private void OnValueChanged(float value)
		{
			_field.Input.SetTextWithoutNotify(_wholeNumbers ? Mathf.RoundToInt(value).ToString(CultureInfo.InvariantCulture) : FloorToHundredths(value).ToString(CultureInfo.InvariantCulture));
			if (!_hold.IsHeld)
			{
				Commit(ToEntryValue(value));
			}
		}

		private void OnReleased()
		{
			if (((Selectable)_slider).interactable)
			{
				Commit(ToEntryValue(_slider.value));
			}
		}

		private void OnTextChanged(string text)
		{
			if (ConfigurationGuiInputField.TryParseNumber(text, _wholeNumbers, out var value))
			{
				_slider.SetValueWithoutNotify(Mathf.Clamp(_wholeNumbers ? ((float)(int)value) : ((float)value), _min, _max));
			}
		}

		private void OnEditFinished(string text)
		{
			object value;
			if (string.Equals(text, _shown, StringComparison.Ordinal))
			{
				Refresh();
			}
			else if (ConfigurationGuiInputField.TryParseNumber(text, _wholeNumbers, out value))
			{
				Commit(value);
			}
			else
			{
				Refresh();
			}
		}

		private object ToEntryValue(float value)
		{
			if (_wholeNumbers)
			{
				return Mathf.RoundToInt(value);
			}
			return FloorToHundredths(value);
		}

		private static float FloorToHundredths(float value)
		{
			return Mathf.Floor(value * 100f + 0.001f) / 100f;
		}
	}
	internal sealed class ConfigurationGuiDropdownEditor : ConfigurationGuiEditor
	{
		private readonly List<object> _values = new List<object>();

		private TMP_Dropdown _dropdown;

		internal ConfigurationGuiDropdownEditor(ConfigEntryBase entry)
			: base(entry)
		{
		}

		internal override float Build(RectTransform slot, ConfigurationGuiTemplates templates)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			_dropdown = ConfigurationGuiTemplates.Clone<TMP_Dropdown>(templates.Dropdown, (Transform)(object)slot, "Dropdown");
			HideVanillaTitle(_dropdown);
			float num = ConfigurationGuiTemplates.ControlHeight((Component)(object)templates.Dropdown);
			ConfigurationGuiTemplates.FillWidth((RectTransform)((Component)_dropdown).transform, num);
			TMP_Text captionText = _dropdown.captionText;
			captionText.enableAutoSizing = false;
			captionText.fontSize = templates.Label.fontSize;
			captionText.textWrappingMode = (TextWrappingModes)0;
			captionText.overflowMode = (TextOverflowModes)3;
			RectTransform rectTransform = captionText.rectTransform;
			rectTransform.anchorMin = new Vector2(rectTransform.anchorMin.x, 0f);
			rectTransform.anchorMax = new Vector2(rectTransform.anchorMax.x, 1f);
			rectTransform.offsetMin = new Vector2(rectTransform.offsetMin.x, 0f);
			rectTransform.offsetMax = new Vector2(rectTransform.offsetMax.x, 0f);
			captionText.margin = new Vector4(captionText.margin.x, 0f, captionText.margin.z, 0f);
			Type type = base.Entry.SettingType;
			ConfigDescription description = base.Entry.Description;
			AcceptableValueBase val = ((description != null) ? description.AcceptableValues : null);
			foreach (object value in Enum.GetValues(type))
			{
				if (val == null || val.IsValid(value))
				{
					_values.Add(value);
				}
			}
			_dropdown.ClearOptions();
			_dropdown.AddOptions(_values.Select((object x) => ConfigurationGuiEditor.GetEnumLabel(type, x)).ToList());
			Refresh();
			((UnityEvent<int>)(object)_dropdown.onValueChanged).AddListener((UnityAction<int>)OnValueChanged);
			return num;
		}

		private static void HideVanillaTitle(TMP_Dropdown dropdown)
		{
			List<Transform> list = new List<Transform>();
			if ((Object)(object)dropdown.captionText != (Object)null)
			{
				list.Add(dropdown.captionText.transform);
			}
			if ((Object)(object)dropdown.itemText != (Object)null)
			{
				list.Add(dropdown.itemText.transform);
			}
			TMP_Text[] componentsInChildren = ((Component)dropdown).GetComponentsInChildren<TMP_Text>(true);
			foreach (TMP_Text text in componentsInChildren)
			{
				Transform transform = text.transform;
				if ((!((Object)(object)dropdown.template != (Object)null) || !transform.IsChildOf((Transform)(object)dropdown.template)) && !list.Any((Transform x) => x.IsChildOf(transform)))
				{
					if (((Component)transform).GetComponentsInChildren<Graphic>(true).Any((Graphic x) => (Object)(object)x != (Object)(object)text && !(x is TMP_SubMeshUI)))
					{
						text.text = "";
					}
					else
					{
						((Component)text).gameObject.SetActive(false);
					}
				}
			}
		}

		internal override void Refresh()
		{
			object value = base.Value;
			int num = _values.IndexOf(value);
			if (num < 0)
			{
				_values.Add(value);
				_dropdown.AddOptions(new List<string> { ConfigurationGuiEditor.GetEnumLabel(base.Entry.SettingType, value) });
				num = _values.Count - 1;
			}
			_dropdown.SetValueWithoutNotify(num);
		}

		internal override void SetInteractable(bool interactable)
		{
			((Selectable)_dropdown).interactable = interactable;
		}

		private void OnValueChanged(int index)
		{
			if (index >= 0 && index < _values.Count)
			{
				Commit(_values[index]);
			}
		}
	}
	internal sealed class ConfigurationGuiReadOnlyEditor : ConfigurationGuiEditor
	{
		private const int MaxLength = 120;

		private ConfigurationGuiSwatch _swatch;

		private TMP_Text _text;

		internal override bool IsEditable => false;

		internal ConfigurationGuiReadOnlyEditor(ConfigEntryBase entry)
			: base(entry)
		{
		}

		internal override float Build(RectTransform slot, ConfigurationGuiTemplates templates)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			_text = (TMP_Text)(object)ConfigurationGuiTemplates.CreateText((Transform)(object)slot, "Value", templates.Label);
			RectTransform val = (RectTransform)_text.transform;
			ConfigurationGuiTemplates.Stretch(val, 0f, 0f, 0f, 0f);
			if (base.Entry.SettingType == typeof(Color))
			{
				_swatch = ConfigurationGuiSwatch.Create(slot, val, 30f);
			}
			Refresh();
			return 30f;
		}

		internal override void Refresh()
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			object value = base.Value;
			string text;
			try
			{
				text = TomlTypeConverter.ConvertToString(value, base.Entry.SettingType);
			}
			catch (Exception)
			{
				text = value?.ToString();
			}
			text = (text ?? "").Replace('\r', ' ').Replace('\n', ' ');
			_text.text = ((text.Length > 120) ? (text.Substring(0, 120) + "...") : text);
			_swatch?.Show((Color)value);
		}

		internal override void SetInteractable(bool interactable)
		{
		}
	}
	internal sealed class ConfigurationGuiSwatch
	{
		private const float Margin = 3f;

		private const float Spacing = 8f;

		private const float FrameWidth = 2f;

		private static readonly Color FrameColor = new Color(0.05f, 0.05f, 0.05f, 0.9f);

		private static readonly Regex ColorCodePattern = new Regex("^#([0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$");

		private readonly Image _fill;

		private ConfigurationGuiSwatch(Image fill)
		{
			_fill = fill;
		}

		internal static bool IsColorCode(object value)
		{
			if (value is string input)
			{
				return ColorCodePattern.IsMatch(input);
			}
			return false;
		}

		internal static bool TryParseColor(string value, out Color color)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			color = default(Color);
			if (string.IsNullOrWhiteSpace(value))
			{
				return false;
			}
			string text = value.Trim();
			if (!text.StartsWith("#", StringComparison.Ordinal))
			{
				text = "#" + text;
			}
			return ColorUtility.TryParseHtmlString(text, ref color);
		}

		internal static ConfigurationGuiSwatch Create(RectTransform slot, RectTransform beside, float height)
		{
			//IL_001f: 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_0049: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			float num = height - 6f;
			RectTransform val = ConfigurationGuiTemplates.CreateRect("Swatch", (Transform)(object)slot);
			val.anchorMin = new Vector2(1f, 0.5f);
			val.anchorMax = new Vector2(1f, 0.5f);
			val.pivot = new Vector2(1f, 0.5f);
			val.sizeDelta = new Vector2(num, num);
			val.anchoredPosition = Vector2.zero;
			Image obj = ((Component)val).gameObject.AddComponent<Image>();
			((Graphic)obj).color = FrameColor;
			((Graphic)obj).raycastTarget = false;
			RectTransform obj2 = ConfigurationGuiTemplates.CreateRect("Fill", (Transform)(object)val);
			ConfigurationGuiTemplates.Stretch(obj2, 2f, 2f, 2f, 2f);
			Image obj3 = ((Component)obj2).gameObject.AddComponent<Image>();
			((Graphic)obj3).color = Color.clear;
			((Graphic)obj3).raycastTarget = false;
			beside.offsetMax = new Vector2(0f - (num + 8f), beside.offsetMax.y);
			return new ConfigurationGuiSwatch(obj3);
		}

		internal void Show(Color color)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			((Graphic)_fill).color = color;
		}

		internal void Show(string text)
		{
			//IL_0017: 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)
			((Graphic)_fill).color = (TryParseColor(text, out var color) ? color : Color.clear);
		}
	}
	internal sealed class ConfigurationGuiPointerHold : MonoBehaviour, IPointerDownHandler, IEventSystemHandler, IPointerUpHandler
	{
		internal Action Released;

		internal bool IsHeld { get; private set; }

		public void OnPointerDown(PointerEventData eventData)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			if ((int)eventData.button == 0)
			{
				IsHeld = true;
			}
		}

		public void OnPointerUp(PointerEventData eventData)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if (IsHeld && (int)eventData.button == 0)
			{
				IsHeld = false;
				Released?.Invoke();
			}
		}

		private void OnDisable()
		{
			IsHeld = false;
		}
	}
	internal sealed class ConfigurationGuiFullDescription
	{
		private const int Padding = 12;

		private const float Spacing = 4f;

		private const float TextScale = 0.9f;

		private readonly RectTransform _root;

		private readonly TMP_Text _text;

		private readonly TMP_Text _topic;

		private ConfigurationGuiFullDescription(RectTransform root, TMP_Text topic, TMP_Text text)
		{
			_root = root;
			_topic = topic;
			_text = text;
		}

		internal static ConfigurationGuiFullDescription Create(Transform panel, ConfigurationGuiTemplates templates)
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Expected O, but got Unknown
			if ((Object)(object)templates.TooltipFrame == (Object)null)
			{
				return null;
			}
			RectTransform val = ConfigurationGuiTemplates.CreateRect("FullDescriptionLayer", panel);
			ConfigurationGuiTemplates.AddLayout(((Component)val).gameObject).ignoreLayout = true;
			ConfigurationGuiTemplates.Stretch(val, 0f, 0f, 0f, 0f);
			RectTransform val2 = ConfigurationGuiTemplates.CreateRect("FullDescription", (Transform)(object)val);
			val2.anchorMin = Vector2.zero;
			val2.anchorMax = Vector2.zero;
			val2.pivot = Vector2.zero;
			VerticalLayoutGroup obj = ((Component)val2).gameObject.AddComponent<VerticalLayoutGroup>();
			((LayoutGroup)obj).padding = new RectOffset(12, 12, 12, 12);
			((HorizontalOrVerticalLayoutGroup)obj).spacing = 4f;
			((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false;
			((Component)val2).gameObject.AddComponent<ContentSizeFitter>().verticalFit = (FitMode)2;
			((Component)val2).gameObject.AddComponent<CanvasGroup>().blocksRaycasts = false;
			Image val3 = ConfigurationGuiTemplates.Clone<Image>(templates.TooltipFrame, (Transform)(object)val2, "Frame");
			for (int num = ((Component)val3).transform.childCount - 1; num >= 0; num--)
			{
				Object.Destroy((Object)(object)((Component)((Component)val3).transform.GetChild(num)).gameObject);
			}
			((Graphic)val3).raycastTarget = false;
			ConfigurationGuiTemplates.AddLayout(((Component)val3).gameObject).ignoreLayout = true;
			ConfigurationGuiTemplates.Stretch(((Graphic)val3).rectTransform, 0f, 0f, 0f, 0f);
			TextMeshProUGUI val4 = ConfigurationGuiTemplates.CreateText((Transform)(object)val2, "Topic", templates.Label);
			((TMP_Text)val4).fontStyle = (FontStyles)1;
			TextMeshProUGUI val5 = ConfigurationGuiTemplates.CreateText((Transform)(object)val2, "Text", templates.Label, 0.9f);
			TextMeshProUGUI[] array = (TextMeshProUGUI[])(object)new TextMeshProUGUI[2] { val4, val5 };
			foreach (TextMeshProUGUI obj2 in array)
			{
				((TMP_Text)obj2).textWrappingMode = (TextWrappingModes)1;
				((TMP_Text)obj2).overflowMode = (TextOverflowModes)0;
				((TMP_Text)obj2).alignment = (TextAlignmentOptions)257;
			}
			((Component)val2).gameObject.SetActive(false);
			return new ConfigurationGuiFullDescription(val2, (TMP_Text)(object)val4, (TMP_Text)(object)val5);
		}

		internal void Show(RectTransform area, string topic, string text)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			_topic.text = topic;
			_text.text = text;
			Vector3[] array = (Vector3[])(object)new Vector3[4];
			area.GetWorldCorners(array);
			((Transform)_root).position = array[0];
			RectTransform root = _root;
			Rect rect = area.rect;
			root.SetSizeWithCurrentAnchors((Axis)0, ((Rect)(ref rect)).width);
			((Component)_root).gameObject.SetActive(true);
		}

		internal void Hide()
		{
			((Component)_root).gameObject.SetActive(false);
		}
	}
	internal sealed class ConfigurationGuiKeyEditor : ConfigurationGuiEditor
	{
		private const float ClearWidth = 110f;

		private const float Spacing = 8f;

		private static ConfigurationGuiKeyEditor _capturing;

		private readonly bool _shortcut;

		private Button _button;

		private ConfigurationGuiKeyCapture _capture;

		private Button _clear;

		private int _endFrame = -1;

		private bool IsCapturing => _capturing == this;

		internal ConfigurationGuiKeyEditor(ConfigEntryBase entry, bool shortcut)
			: base(entry)
		{
			_shortcut = shortcut;
		}

		internal override float Build(RectTransform slot, ConfigurationGuiTemplates templates)
		{
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Expected O, but got Unknown
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Expected O, but got Unknown
			float num = ConfigurationGuiTemplates.ControlHeight((Component)(object)templates.Button);
			HorizontalLayoutGroup obj = ((Component)slot).gameObject.AddComponent<HorizontalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj).spacing = 8f;
			((LayoutGroup)obj).childAlignment = (TextAnchor)3;
			((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = false;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false;
			_button = ConfigurationGuiTemplates.Clone<Button>(templates.Button, (Transform)(object)slot, "Key");
			ConfigurationGuiTemplates.SetFixedButtonLabel(_button, templates.Label, 0f, (TextAlignmentOptions)514);
			ConfigurationGuiTemplates.AddLayout(((Component)_button).gameObject, 0f, -1f, 0f, num, 1f);
			_capture = ((Component)_button).gameObject.AddComponent<ConfigurationGuiKeyCapture>();
			((Behaviour)_capture).enabled = false;
			_capture.Owner = this;
			((UnityEvent)_button.onClick).AddListener(new UnityAction(StartCapture));
			if (_shortcut)
			{
				_clear = ConfigurationGuiTemplates.Clone<Button>(templates.Button, (Transform)(object)slot, "Clear");
				ConfigurationGuiTemplates.SetLabel((Component)(object)_clear, ConfigurationGui.Translate("@config_gui_clear"));
				ConfigurationGuiTemplates.SetFixedButtonLabel(_clear, templates.Label, 110f, (TextAlignmentOptions)514);
				ConfigurationGuiTemplates.AddLayout(((Component)_clear).gameObject, 110f, -1f, 110f, num);
				((UnityEvent)_clear.onClick).AddListener((UnityAction)delegate
				{
					//IL_0007: Unknown result type (might be due to invalid IL or missing references)
					StopCapture();
					Commit(KeyboardShortcut.Empty);
				});
			}
			Refresh();
			return num;
		}

		internal override void Refresh()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			ConfigurationGuiTemplates.SetLabel(label: IsCapturing ? ConfigurationGui.Translate("@config_gui_press_key") : ((!_shortcut) ? base.Value.ToString() : ((object)(KeyboardShortcut)base.Value/*cast due to .constrained prefix*/).ToString()), component: (Component)(object)_button);
		}

		internal override void SetInteractable(bool interactable)
		{
			((Selectable)_button).interactable = interactable;
			if ((Object)(object)_clear != (Object)null)
			{
				((Selectable)_clear).interactable = interactable;
			}
		}

		internal override bool ConsumesEscape()
		{
			if (!IsCapturing)
			{
				return _endFrame == Time.frameCount;
			}
			return true;
		}

		internal void StopCapture()
		{
			if (IsCapturing)
			{
				_capturing = null;
				_endFrame = Time.frameCount;
				if ((Object)(object)_capture != (Object)null)
				{
					((Behaviour)_capture).enabled = false;
				}
				if ((Object)(object)_button != (Object)null)
				{
					Refresh();
				}
			}
		}

		internal void FinishCapture(KeyCode key, KeyCode[] heldKeys)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			StopCapture();
			Commit(_shortcut ? ((object)new KeyboardShortcut(key, heldKeys)) : ((object)key));
		}

		private void StartCapture()
		{
			if (!IsCapturing)
			{
				if (_capturing != null)
				{
					_capturing.StopCapture();
				}
				_capturing = this;
				if ((Object)(object)EventSystem.current != (Object)null)
				{
					EventSystem.current.SetSelectedGameObject((GameObject)null);
				}
				_capture.Begin();
				Refresh();
			}
		}
	}
	internal sealed class ConfigurationGuiKeyCapture : MonoBehaviour
	{
		private static KeyCode[] _keys;

		internal ConfigurationGuiKeyEditor Owner;

		private int _startFrame;

		private static KeyCode[] Keys => _keys ?? (_keys = UnityInput.Current.SupportedKeyCodes.Except((IEnumerable<KeyCode>)(object)new KeyCode[3]
		{
			default(KeyCode),
			(KeyCode)323,
			(KeyCode)27
		}).ToArray());

		internal void Begin()
		{
			_startFrame = Time.frameCount;
			((Behaviour)this).enabled = true;
		}

		private void Update()
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			if (Owner == null || Time.frameCount == _startFrame)
			{
				return;
			}
			if (ZInput.GetKeyDown((KeyCode)27, true))
			{
				Owner.StopCapture();
				return;
			}
			IInputSystem current = UnityInput.Current;
			KeyCode[] keys = Keys;
			foreach (KeyCode val in keys)
			{
				if (current.GetKeyUp(val))
				{
					Owner.FinishCapture(val, ((IEnumerable<KeyCode>)Keys).Where((Func<KeyCode, bool>)current.GetKey).ToArray());
					break;
				}
			}
		}

		private void OnDisable()
		{
			if (Owner != null)
			{
				Owner.StopCapture();
			}
		}
	}
	internal sealed class ConfigurationGuiPanel : MonoBehaviour
	{
		private sealed class Section
		{
			internal string Category { get; }

			internal Button Header { get; }

			internal TMP_Text HeaderLabel { get; }

			internal RectTransform Body { get; }

			internal List<Row> Rows { get; } = new List<Row>();

			internal bool Collapsed { get; set; }

			internal bool CollapsedInSearch { get; set; }

			internal Section(string category, Button header, TMP_Text headerLabel, RectTransform body)
			{
				Category = category;
				Header = header;
				HeaderLabel = headerLabel;
				Body = body;
			}
		}

		private sealed class Row
		{
			internal ConfigEntryBase Entry { get; }

			internal int Index { get; }

			internal string Category { get; }

			internal string Name { get; }

			internal string Description { get; }

			internal int Order { get; }

			internal bool ReadOnly { get; }

			internal bool Advanced { get; }

			internal GameObject Object { get; set; }

			internal ConfigurationGuiEditor Editor { get; set; }

			internal bool Editable { get; set; }

			private Row(ConfigEntryBase entry, int index, string category, string name, string description, int order, bool readOnly, bool advanced)
			{
				Entry = entry;
				Index = index;
				Category = category;
				Name = name;
				Description = description;
				Order = order;
				ReadOnly = readOnly;
				Advanced = advanced;
			}

			internal static Row Create(ConfigEntryBase entry, int index)
			{
				ConfigurationManagerAttributes attributes = GetAttributes(entry);
				if (attributes != null && attributes.Browsable == false)
				{
					return null;
				}
				ConfigDefinition definition = entry.Definition;
				string category = (string.IsNullOrEmpty(attributes?.Category) ? definition.Section : attributes.Category);
				string name = (string.IsNullOrEmpty(attributes?.DispName) ? definition.Key : attributes.DispName);
				object obj;
				if (!string.IsNullOrEmpty(attributes?.Description))
				{
					obj = attributes.Description;
				}
				else
				{
					ConfigDescription description = entry.Description;
					obj = ((description != null) ? description.Description : null);
				}
				string text = (string)obj;
				return new Row(entry, index, category, name, text ?? "", (attributes?.Order).GetValueOrDefault(), attributes != null && attributes.ReadOnly == true, attributes != null && attributes.IsAdvanced == true);
			}

			internal bool Matches(string[] terms)
			{
				ConfigDefinition definition = Entry.Definition;
				return terms.All((string x) => Contains(Name, x) || Contains(Category, x) || Contains(Description, x) || Contains(definition.Section, x) || Contains(definition.Key, x));
			}

			private static bool Contains(string text, string term)
			{
				if (text != null)
				{
					return text.IndexOf(term, StringComparison.OrdinalIgnoreCase) >= 0;
				}
				return false;
			}
		}

		private const float Padding = 8f;

		private const float Spacing = 6f;

		private const float RowMinHeight = 34f;

		private const int RowPadding = 2;

		private const float RowSpacing = 8f;

		private const float SectionRowSpacing = 2f;

		private const float SectionHeaderHeight = 36f;

		private const int WheelStepRows = 3;

		private const float NameMinWidth = 120f;

		private const float EditorMinWidth = 200f;

		private const float ResetWidth = 120f;

		private const float ScrollMinHeight = 120f;

		private const float ScrollbarSpacing = 4f;

		private const float DescriptionLines = 3.6f;

		private const float UnfoldDelay = 1.5f;

		private const float BackMinWidth = 120f;

		private const float BackMaxWidth = 260f;

		private const int RowsPerFrame = 16;

		private static bool _showAdvanced;

		private readonly List<Row> _rows = new List<Row>();

		private readonly List<Section> _sections = new List<Section>();

		private readonly Queue<(Section Section, Row Row)> _unbuiltRows = new Queue<(Section, Row)>();

		private Button _apply;

		private bool _closed;

		private TMP_Text _description;

		private ConfigurationGuiFullDescription _fullDescription;

		private ConfigurationGuiRowHover _hoveredRow;

		private GameObject _list;

		private GameObject _panels;

		private ConfigurationGuiPendingValues _pending;

		private bool _prompting;

		private Button _resetAll;

		private ConfigurationGuiInputField _search;

		private bool _searching;

		private string[] _searchTerms = Array.Empty<string>();

		private ConfigurationGuiTemplates _templates;

		private float _unfoldTime = float.PositiveInfinity;

		internal ConfigurationGuiRowHover HoveredRow => _hoveredRow;

		internal static void Open(ConfigurationGuiPlugin plugin, RectTransform page)
		{
			GameObject val = null;
			try
			{
				Settings instance = Settings.instance;
				Transform val2 = ConfigurationGui.FindChild((Transform)(object)page, "List");
				Transform val3 = ConfigurationGui.FindChild((Transform)(object)page, "Panels");
				if (!((Object)(object)instance == (Object)null) && !((Object)(object)val2 == (Object)null) && !((Object)(object)val3 == (Object)null))
				{
					ConfigurationGuiTemplates configurationGuiTemplates = ConfigurationGuiTemplates.Find(instance);
					if ((Object)(object)configurationGuiTemplates.Label == (Object)null || (Object)(object)configurationGuiTemplates.Button == (Object)null)
					{
						Debug.LogWarning((object)"[ModUtils] The settings screen has no label or button to copy. The mod panel cannot be shown.");
						return;
					}
					RectTransform obj = ConfigurationGuiTemplates.CreateRect(plugin.Guid, val3);
					val = ((Component)obj).gameObject;
					ConfigurationGuiTemplates.Stretch(obj, 0f, 0f, 0f, 0f);
					ConfigurationGuiPanel configurationGuiPanel = val.AddComponent<ConfigurationGuiPanel>();
					configurationGuiPanel._list = ((Component)val2).gameObject;
					configurationGuiPanel._panels = ((Component)val3).gameObject;
					configurationGuiPanel.Build(plugin, configurationGuiTemplates);
					((Component)val2).gameObject.SetActive(false);
					((Component)val3).gameObject.SetActive(true);
					instance.BlockNavigation(true);
				}
			}
			catch (Exception arg)
			{
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)val);
				}
				Debug.LogError((object)$"[ModUtils] Failed to open the configuration panel of {plugin.Name}: {arg}");
			}
		}

		internal bool IsEscapeConsumed()
		{
			if (_search != null && _search.ConsumesEscape())
			{
				return true;
			}
			foreach (Row row in _rows)
			{
				if (row.Editor.ConsumesEscape())
				{
					return true;
				}
			}
			return false;
		}

		internal void ShowDescription(ConfigurationGuiRowHover row)
		{
			string text = (((Object)(object)row != (Object)null) ? row.Description : "");
			if ((Object)(object)_description != (Object)null)
			{
				_description.text = text ?? "";
			}
			_hoveredRow = row;
			_unfoldTime = (string.IsNullOrEmpty(text) ? float.PositiveInfinity : (Time.unscaledTime + 1.5f));
			_fullDescription?.Hide();
		}

		private void UnfoldDescription()
		{
			_unfoldTime = float.PositiveInfinity;
			if (!IsEditingText())
			{
				_description.ForceMeshUpdate(false, false);
				if (_description.isTextTruncated)
				{
					_fullDescription?.Show(_description.rectTransform, _hoveredRow.RowName, _description.text);
				}
			}
		}

		private static bool IsEditingText()
		{
			GameObject val = (((Object)(object)EventSystem.current !=