Decompiled source of ModSettings v0.2.0

plugins/ModSettings.Core.dll

Decompiled 12 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("ModSettings.Core")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+6baae216dc75e3d6f6ceb0a73f81536dbb0fb0e6")]
[assembly: AssemblyProduct("ModSettings.Core")]
[assembly: AssemblyTitle("ModSettings.Core")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ModSettings.Core
{
	public readonly record struct NumberRange(double Min, double Max);
	public sealed record CfgSetting(string Section, string Key, string RawValue, int Line, string Description, string? TypeName, string? DefaultValue, IReadOnlyList<string> AcceptableValues, NumberRange? Range, bool IsFlags);
	public sealed class CfgDocument
	{
		private sealed class Pending
		{
			private readonly List<string> _description = new List<string>();

			private string? _type;

			private string? _default;

			private IReadOnlyList<string> _values = Array.Empty<string>();

			private NumberRange? _range;

			private bool _flags;

			public void Read(string line)
			{
				if (line.StartsWith("##"))
				{
					List<string> description = _description;
					string text = line;
					description.Add(text.Substring(2, text.Length - 2).Trim());
					return;
				}
				if (line.StartsWith("# Setting type:"))
				{
					string text = line;
					int length = "# Setting type:".Length;
					_type = text.Substring(length, text.Length - length).Trim();
					return;
				}
				if (line.StartsWith("# Default value:"))
				{
					string text = line;
					int length = "# Default value:".Length;
					_default = text.Substring(length, text.Length - length).Trim();
					return;
				}
				if (line.StartsWith("# Acceptable values:"))
				{
					string text = line;
					int length = "# Acceptable values:".Length;
					_values = (from v in text.Substring(length, text.Length - length).Split(',')
						select v.Trim() into v
						where v.Length > 0
						select v).ToArray();
					return;
				}
				if (line.StartsWith("# Multiple values can be set at the same time"))
				{
					_flags = true;
					return;
				}
				Match match = RangeLine.Match(line);
				if (match == null || !match.Success)
				{
					return;
				}
				double? num = ParseNumber(match.Groups[1].Value);
				if (num.HasValue)
				{
					double valueOrDefault = num.GetValueOrDefault();
					num = ParseNumber(match.Groups[2].Value);
					if (num.HasValue)
					{
						double valueOrDefault2 = num.GetValueOrDefault();
						_range = new NumberRange(valueOrDefault, valueOrDefault2);
					}
				}
			}

			public CfgSetting ToSetting(string section, string key, string value, int line)
			{
				return new CfgSetting(section, key, value, line, string.Join("\n", _description).Trim(), _type, _default, _values, _range, _flags);
			}
		}

		private static readonly Regex CreatedBy = new Regex("^## Settings file was created by plugin (.+) v(\\S+)$");

		private static readonly Regex RangeLine = new Regex("^# Acceptable value range: From (.+) to (.+)$");

		private const string GuidPrefix = "## Plugin GUID:";

		private const string TypePrefix = "# Setting type:";

		private const string DefaultPrefix = "# Default value:";

		private const string ValuesPrefix = "# Acceptable values:";

		private const string FlagsPrefix = "# Multiple values can be set at the same time";

		private readonly string[] _lines;

		public string? PluginName { get; private init; }

		public string? PluginVersion { get; private init; }

		public string? PluginGuid { get; private init; }

		public IReadOnlyList<CfgSetting> Settings { get; }

		private CfgDocument(string[] lines, IReadOnlyList<CfgSetting> settings)
		{
			_lines = lines;
			Settings = settings;
		}

		public string WithValue(CfgSetting setting, string rawValue)
		{
			if (rawValue.Contains('\n') || rawValue.Contains('\r'))
			{
				throw new ArgumentException("A value must fit on one line.", "rawValue");
			}
			string text = ((setting.Line < _lines.Length) ? _lines[setting.Line] : "");
			int num = text.IndexOf('=');
			if (num < 0 || text.Substring(0, num).Trim() != setting.Key)
			{
				throw new InvalidOperationException($"Line {setting.Line + 1} does not hold {setting.Key}.");
			}
			string[] array = (string[])_lines.Clone();
			string text2 = (text.EndsWith('\r') ? "\r" : "");
			array[setting.Line] = text.Substring(0, num).TrimEnd() + " = " + rawValue + text2;
			return string.Join('\n', array);
		}

		public static CfgDocument Parse(string text)
		{
			string[] array = text.Split('\n');
			List<CfgSetting> list = new List<CfgSetting>();
			string pluginName = null;
			string pluginVersion = null;
			string pluginGuid = null;
			string section = "";
			bool flag = true;
			Pending pending = new Pending();
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (text2.Length == 0)
				{
					continue;
				}
				if (text2.StartsWith('#'))
				{
					if (flag)
					{
						Match match = CreatedBy.Match(text2);
						if (match != null && match.Success)
						{
							pluginName = match.Groups[1].Value;
							pluginVersion = match.Groups[2].Value;
							continue;
						}
					}
					if (flag && text2.StartsWith("## Plugin GUID:"))
					{
						string text3 = text2;
						int length = "## Plugin GUID:".Length;
						pluginGuid = text3.Substring(length, text3.Length - length).Trim();
					}
					else
					{
						pending.Read(text2);
					}
				}
				else if (text2.StartsWith('[') && text2.EndsWith(']'))
				{
					string text3 = text2;
					section = text3.Substring(1, text3.Length - 1 - 1);
					flag = false;
					pending = new Pending();
				}
				else
				{
					string[] array2 = text2.Split('=', 2);
					if (array2.Length == 2)
					{
						list.Add(pending.ToSetting(section, array2[0].Trim(), array2[1].Trim(), i));
						pending = new Pending();
					}
				}
			}
			return new CfgDocument(array, list)
			{
				PluginName = pluginName,
				PluginVersion = pluginVersion,
				PluginGuid = pluginGuid
			};
		}

		internal static double? ParseNumber(string text)
		{
			text = text.Trim();
			if (double.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				return result;
			}
			if (double.TryParse(text, NumberStyles.Float, CultureInfo.CurrentCulture, out result))
			{
				return result;
			}
			return null;
		}
	}
	public enum ControlKind
	{
		Toggle,
		Cycle,
		Slider,
		Text,
		Key
	}
	public static class Controls
	{
		public static ControlKind For(CfgSetting setting)
		{
			if (setting.TypeName == "Boolean")
			{
				return ControlKind.Toggle;
			}
			if (KeyNames.IsKeyType(setting.TypeName))
			{
				return ControlKind.Key;
			}
			if (setting.AcceptableValues.Count > 0 && !setting.IsFlags)
			{
				return ControlKind.Cycle;
			}
			if (setting.Range.HasValue && ValueRules.IsNumeric(setting.TypeName))
			{
				return ControlKind.Slider;
			}
			return ControlKind.Text;
		}
	}
	public sealed record KeyBinding(string Id, string Label, IReadOnlySet<string> Keys, bool FromGame);
	public static class KeyClashes
	{
		public static string IdOf(ModEntry mod, SettingView view)
		{
			return mod.Source.RelativePath + "\n" + view.Setting.Section + "\n" + view.Setting.Key;
		}

		public static IEnumerable<KeyBinding> FromMods(IEnumerable<ModEntry> mods)
		{
			foreach (ModEntry mod in mods)
			{
				foreach (SettingView item in mod.Sections.SelectMany((SectionView s) => s.Settings))
				{
					if (item.Control == ControlKind.Key)
					{
						IReadOnlyList<string> readOnlyList = KeyNames.Parse(item.Setting.TypeName, item.Setting.RawValue);
						if (readOnlyList != null)
						{
							yield return new KeyBinding(IdOf(mod, item), mod.Title + ": " + item.Label, new HashSet<string>(readOnlyList, StringComparer.OrdinalIgnoreCase), FromGame: false);
						}
					}
				}
			}
		}

		public static IReadOnlyDictionary<string, IReadOnlyList<string>> Find(IEnumerable<KeyBinding> bindings)
		{
			List<KeyBinding> source = bindings.ToList();
			Dictionary<string, IReadOnlyList<string>> dictionary = new Dictionary<string, IReadOnlyList<string>>();
			foreach (KeyBinding binding in source.Where((KeyBinding b) => !b.FromGame))
			{
				List<string> list = (from other in source
					where other.Id != binding.Id && other.Keys.SetEquals(binding.Keys)
					select other.Label).ToList();
				if (list.Count > 0)
				{
					dictionary[binding.Id] = list;
				}
			}
			return dictionary;
		}
	}
	public static class GameBindings
	{
		public static IReadOnlyList<KeyBinding> FromJson(IEnumerable<string> assetJsons, string? overridesJson)
		{
			Dictionary<string, string> dictionary = Overrides(overridesJson);
			List<KeyBinding> list = new List<KeyBinding>();
			foreach (string assetJson in assetJsons)
			{
				try
				{
					using JsonDocument jsonDocument = JsonDocument.Parse(assetJson);
					if (!jsonDocument.RootElement.TryGetProperty("maps", out var value))
					{
						continue;
					}
					foreach (JsonElement item in value.EnumerateArray())
					{
						string value2 = Text(item, "name");
						if (!item.TryGetProperty("bindings", out var value3))
						{
							continue;
						}
						foreach (JsonElement item2 in value3.EnumerateArray())
						{
							if (!Flag(item2, "isComposite"))
							{
								string text = Text(item2, "id");
								string value4;
								string text2 = KeyNames.FromControlPath(dictionary.TryGetValue(text, out value4) ? value4 : Text(item2, "path"));
								if (text2 != null)
								{
									string value5 = ((Flag(item2, "isPartOfComposite") && Text(item2, "name").Length > 0) ? (" (" + Text(item2, "name") + ")") : "");
									list.Add(new KeyBinding("game\n" + text, $"Game: {value2}/{Text(item2, "action")}{value5}", new HashSet<string>(new string[1] { text2 }, StringComparer.OrdinalIgnoreCase), FromGame: true));
								}
							}
						}
					}
				}
				catch (JsonException)
				{
				}
			}
			return list;
		}

		private static Dictionary<string, string> Overrides(string? json)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			if (string.IsNullOrWhiteSpace(json))
			{
				return dictionary;
			}
			try
			{
				using JsonDocument jsonDocument = JsonDocument.Parse(json);
				if (!jsonDocument.RootElement.TryGetProperty("bindings", out var value))
				{
					return dictionary;
				}
				foreach (JsonElement item in value.EnumerateArray())
				{
					string text = Text(item, "id");
					if (text.Length > 0)
					{
						dictionary[text] = Text(item, "path");
					}
				}
			}
			catch (JsonException)
			{
			}
			return dictionary;
		}

		private static string Text(JsonElement element, string name)
		{
			if (!element.TryGetProperty(name, out var value) || value.ValueKind != JsonValueKind.String)
			{
				return "";
			}
			return value.GetString() ?? "";
		}

		private static bool Flag(JsonElement element, string name)
		{
			if (element.TryGetProperty(name, out var value))
			{
				return value.ValueKind == JsonValueKind.True;
			}
			return false;
		}
	}
	public static class KeyNames
	{
		public const string Unbound = "None";

		private static readonly string[] KeyTypes = new string[3] { "Key", "KeyCode", "KeyboardShortcut" };

		private static readonly string[] Modifiers = new string[9] { "LeftShift", "RightShift", "LeftCtrl", "RightCtrl", "LeftAlt", "RightAlt", "AltGr", "LeftMeta", "RightMeta" };

		private static readonly (string KeyCode, string Key)[] Renames = BuildRenames();

		private static readonly Dictionary<string, string> KeyCodeToKey = Renames.ToDictionary<(string, string), string, string>(((string KeyCode, string Key) r) => r.KeyCode, ((string KeyCode, string Key) r) => r.Key, StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, string> KeyToKeyCode = Renames.GroupBy<(string, string), string>(((string KeyCode, string Key) r) => r.Key, StringComparer.OrdinalIgnoreCase).ToDictionary<IGrouping<string, (string, string)>, string, string>((IGrouping<string, (string KeyCode, string Key)> g) => g.Key, (IGrouping<string, (string KeyCode, string Key)> g) => g.First().KeyCode, StringComparer.OrdinalIgnoreCase);

		public static bool IsKeyType(string? typeName)
		{
			if (typeName != null)
			{
				return KeyTypes.Contains<string>(typeName);
			}
			return false;
		}

		public static bool IsModifier(string key)
		{
			return Modifiers.Contains<string>(key, StringComparer.OrdinalIgnoreCase);
		}

		public static IReadOnlyList<string>? Parse(string? typeName, string raw)
		{
			if (!IsKeyType(typeName))
			{
				return null;
			}
			List<string> list = ((typeName == "KeyboardShortcut") ? ((IEnumerable<string>)raw.Split(new char[5] { ' ', '+', ',', ';', '|' }, StringSplitOptions.RemoveEmptyEntries)) : ((IEnumerable<string>)new string[1] { raw.Trim() })).Where((string p) => p.Length > 0 && !string.Equals(p, "None", StringComparison.OrdinalIgnoreCase)).Select(ToKey).Distinct<string>(StringComparer.OrdinalIgnoreCase)
				.OrderBy<string, string>((string k) => k, StringComparer.OrdinalIgnoreCase)
				.ToList();
			if (list.Count != 0)
			{
				return list;
			}
			return null;
		}

		public static string? FromControlPath(string path)
		{
			if (!path.StartsWith("<Keyboard>/", StringComparison.OrdinalIgnoreCase))
			{
				return null;
			}
			string text = path;
			int length = "<Keyboard>/".Length;
			string text2 = text.Substring(length, text.Length - length);
			if (text2.Length == 0 || text2.StartsWith('#') || text2.Contains('/') || text2 == "anyKey")
			{
				return null;
			}
			if (text2.Length == 1 && char.IsDigit(text2[0]))
			{
				return "Digit" + text2;
			}
			switch (text2)
			{
			case "ctrl":
				return "LeftCtrl";
			case "shift":
				return "LeftShift";
			case "alt":
				return "LeftAlt";
			default:
			{
				string text3 = char.ToUpperInvariant(text2[0]).ToString();
				string text4 = text2;
				return text3 + text4.Substring(1, text4.Length - 1);
			}
			}
		}

		public static ValueCheck Capture(CfgSetting setting, string key, IReadOnlyList<string> heldModifiers)
		{
			string typeName = setting.TypeName;
			string text = ((typeName == "KeyCode") ? ToKeyCode(key) : ((!(typeName == "KeyboardShortcut")) ? key : string.Join(" + ", new string[1] { ToKeyCode(key) }.Concat(heldModifiers.Where((string m) => !string.Equals(m, key, StringComparison.OrdinalIgnoreCase)).Select(ToKeyCode)))));
			string raw = text;
			if (setting.AcceptableValues.Count > 0)
			{
				string text2 = setting.AcceptableValues.FirstOrDefault((string v) => string.Equals(v, raw, StringComparison.OrdinalIgnoreCase));
				if (text2 == null)
				{
					return ValueCheck.Invalid(key + " cannot be used for this setting.");
				}
				raw = text2;
			}
			return ValueCheck.Valid(raw);
		}

		private static string ToKey(string name)
		{
			if (!KeyCodeToKey.TryGetValue(name, out string value))
			{
				return name;
			}
			return value;
		}

		private static string ToKeyCode(string key)
		{
			if (!KeyToKeyCode.TryGetValue(key, out string value))
			{
				return key;
			}
			return value;
		}

		private static (string, string)[] BuildRenames()
		{
			List<(string, string)> list = new List<(string, string)>
			{
				("Return", "Enter"),
				("LeftControl", "LeftCtrl"),
				("RightControl", "RightCtrl"),
				("LeftWindows", "LeftMeta"),
				("RightWindows", "RightMeta"),
				("LeftCommand", "LeftMeta"),
				("RightCommand", "RightMeta"),
				("LeftApple", "LeftMeta"),
				("RightApple", "RightMeta"),
				("Print", "PrintScreen"),
				("Menu", "ContextMenu"),
				("KeypadDivide", "NumpadDivide"),
				("KeypadMultiply", "NumpadMultiply"),
				("KeypadMinus", "NumpadMinus"),
				("KeypadPlus", "NumpadPlus"),
				("KeypadPeriod", "NumpadPeriod"),
				("KeypadEquals", "NumpadEquals"),
				("KeypadEnter", "NumpadEnter")
			};
			for (int i = 0; i <= 9; i++)
			{
				list.Add(("Alpha" + i, "Digit" + i));
				list.Add(("Keypad" + i, "Numpad" + i));
			}
			return list.ToArray();
		}
	}
	public sealed record SettingTags(bool Hidden = false, bool ReadOnly = false, int? Order = null, string? DisplayName = null)
	{
		public static SettingTags None { get; } = new SettingTags();

		[CompilerGenerated]
		private SettingTags(SettingTags original)
		{
			Hidden = original.Hidden;
			ReadOnly = original.ReadOnly;
			Order = original.Order;
			DisplayName = original.DisplayName;
		}
	}
	public enum SourceKind
	{
		Loaded,
		NotLoaded,
		Loader
	}
	public sealed record ConfigSource(string RelativePath, string? Text, string? ReadError, SourceKind Kind, string? LoadedName = null, string? LoadedVersion = null, IReadOnlySet<string>? BoundKeys = null, IReadOnlyDictionary<string, SettingTags>? Tags = null)
	{
		public static string KeyOf(string section, string key)
		{
			return section + "\n" + key;
		}
	}
	public sealed record SettingView(CfgSetting Setting, string Label, ControlKind Control, bool ReadOnly, bool AppliesLive);
	public sealed record SectionView(string Name, IReadOnlyList<SettingView> Settings);
	public sealed record ModEntry(string Title, string Version, SourceKind Kind, ConfigSource Source, string? Error, IReadOnlyList<SectionView> Sections)
	{
		public string Status => Kind switch
		{
			SourceKind.Loaded => "loaded", 
			SourceKind.Loader => "mod loader", 
			_ => "not loaded", 
		};
	}
	public static class ModList
	{
		public static IReadOnlyList<ModEntry> Build(IEnumerable<ConfigSource> sources)
		{
			return (from m in sources.Select(Entry)
				orderby m.Kind switch
				{
					SourceKind.Loaded => 0, 
					SourceKind.NotLoaded => 1, 
					_ => 2, 
				}
				select m).ThenBy<ModEntry, string>((ModEntry m) => m.Title, StringComparer.OrdinalIgnoreCase).ToList();
		}

		private static ModEntry Entry(ConfigSource source)
		{
			string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(source.RelativePath);
			if (source.Text == null)
			{
				return new ModEntry(source.LoadedName ?? fileNameWithoutExtension, source.LoadedVersion ?? "", source.Kind, source, source.ReadError ?? "Could not read the file.", Array.Empty<SectionView>());
			}
			CfgDocument cfgDocument = CfgDocument.Parse(source.Text);
			List<SectionView> sections = (from s in cfgDocument.Settings.Select((CfgSetting setting, int index) => (Setting: setting, Index: index, Tags: TagsOf(source, setting)))
				where !s.Tags.Hidden
				group s by s.Setting.Section into @group
				select new SectionView(@group.Key, (from s in @group
					orderby s.Tags.Order.GetValueOrDefault() descending, s.Index
					select View(source, s.Setting, s.Tags)).ToList())).ToList();
			return new ModEntry(source.LoadedName ?? cfgDocument.PluginName ?? fileNameWithoutExtension, source.LoadedVersion ?? cfgDocument.PluginVersion ?? "", source.Kind, source, null, sections);
		}

		private static SettingTags TagsOf(ConfigSource source, CfgSetting setting)
		{
			if (source.Tags == null || !source.Tags.TryGetValue(ConfigSource.KeyOf(setting.Section, setting.Key), out SettingTags value))
			{
				return SettingTags.None;
			}
			return value;
		}

		private static SettingView View(ConfigSource source, CfgSetting setting, SettingTags tags)
		{
			bool appliesLive = source.Kind == SourceKind.Loaded && (source.BoundKeys?.Contains(ConfigSource.KeyOf(setting.Section, setting.Key)) ?? false);
			return new SettingView(setting, tags.DisplayName ?? setting.Key, Controls.For(setting), tags.ReadOnly, appliesLive);
		}
	}
	public static class TomlString
	{
		private static readonly Regex WindowsPath = new Regex("^\"?\\w:\\\\(?!\\\\)(?!.+\\\\\\\\)");

		public static string Escape(string text)
		{
			if (string.IsNullOrEmpty(text))
			{
				return string.Empty;
			}
			StringBuilder stringBuilder = new StringBuilder(text.Length + 2);
			for (int i = 0; i < text.Length; i++)
			{
				char c = text[i];
				StringBuilder stringBuilder2 = stringBuilder;
				stringBuilder2.Append(c switch
				{
					'\0' => "\\0", 
					'\a' => "\\a", 
					'\b' => "\\b", 
					'\t' => "\\t", 
					'\n' => "\\n", 
					'\v' => "\\v", 
					'\f' => "\\f", 
					'\r' => "\\r", 
					'\'' => "\\'", 
					'"' => "\\\"", 
					_ => c.ToString(), 
				});
			}
			return stringBuilder.ToString();
		}

		public static string Unescape(string text)
		{
			if (string.IsNullOrEmpty(text))
			{
				return text;
			}
			StringBuilder stringBuilder = new StringBuilder(text.Length);
			int num = 0;
			while (num < text.Length)
			{
				int num2 = text.IndexOf('\\', num);
				if (num2 < 0 || num2 == text.Length - 1)
				{
					num2 = text.Length;
				}
				stringBuilder.Append(text, num, num2 - num);
				if (num2 >= text.Length)
				{
					break;
				}
				char c = text[num2 + 1];
				switch (c)
				{
				case '0':
					stringBuilder.Append('\0');
					break;
				case 'a':
					stringBuilder.Append('\a');
					break;
				case 'b':
					stringBuilder.Append('\b');
					break;
				case 't':
					stringBuilder.Append('\t');
					break;
				case 'n':
					stringBuilder.Append('\n');
					break;
				case 'v':
					stringBuilder.Append('\v');
					break;
				case 'f':
					stringBuilder.Append('\f');
					break;
				case 'r':
					stringBuilder.Append('\r');
					break;
				case '\'':
					stringBuilder.Append('\'');
					break;
				case '"':
					stringBuilder.Append('"');
					break;
				case '\\':
					stringBuilder.Append('\\');
					break;
				default:
					stringBuilder.Append('\\').Append(c);
					break;
				}
				num = num2 + 2;
			}
			return stringBuilder.ToString();
		}

		public static string Read(string raw)
		{
			if (!WindowsPath.IsMatch(raw))
			{
				return Unescape(raw);
			}
			return raw;
		}
	}
	public readonly record struct ValueCheck(string? Raw, string? Error)
	{
		public bool Ok => Error == null;

		public static ValueCheck Valid(string raw)
		{
			return new ValueCheck(raw, null);
		}

		public static ValueCheck Invalid(string error)
		{
			return new ValueCheck(null, error);
		}
	}
	public static class ValueRules
	{
		private static readonly CultureInfo Invariant = CultureInfo.InvariantCulture;

		private static readonly Dictionary<string, (decimal Min, decimal Max)> Integers = new Dictionary<string, (decimal, decimal)>
		{
			["Byte"] = (0m, 255m),
			["SByte"] = (-128m, 127m),
			["Int16"] = (-32768m, 32767m),
			["UInt16"] = (0m, 65535m),
			["Int32"] = (-2147483648m, 2147483647m),
			["UInt32"] = (0m, 4294967295m),
			["Int64"] = (-9223372036854775808m, 9223372036854775807m),
			["UInt64"] = (0m, 18446744073709551615m)
		};

		private static readonly HashSet<string> Fractions = new HashSet<string> { "Single", "Double", "Decimal" };

		public static bool IsInteger(string? typeName)
		{
			if (typeName != null)
			{
				return Integers.ContainsKey(typeName);
			}
			return false;
		}

		public static bool IsNumeric(string? typeName)
		{
			if (!IsInteger(typeName))
			{
				if (typeName != null)
				{
					return Fractions.Contains(typeName);
				}
				return false;
			}
			return true;
		}

		public static string Display(CfgSetting setting)
		{
			return Readable(setting, setting.RawValue);
		}

		public static ValueCheck Check(CfgSetting setting, string input)
		{
			bool flag = setting.TypeName == "String";
			if (flag && setting.AcceptableValues.Count == 0)
			{
				return ValueCheck.Valid(TomlString.Escape(input));
			}
			string text = input.Trim();
			if (text.Contains('\n') || text.Contains('\r'))
			{
				return ValueCheck.Invalid("Must fit on one line.");
			}
			if (setting.TypeName == "Boolean")
			{
				if (!bool.TryParse(text, out var result))
				{
					return ValueCheck.Invalid("Must be true or false.");
				}
				return ValueCheck.Valid(result ? "true" : "false");
			}
			if (setting.AcceptableValues.Count > 0)
			{
				if (setting.IsFlags)
				{
					return CheckFlags(setting, text);
				}
				string text2 = Match(setting, text);
				if (text2 == null)
				{
					return ValueCheck.Invalid("Must be one of: " + Allowed(setting) + ".");
				}
				return ValueCheck.Valid(flag ? TomlString.Escape(text2) : text2);
			}
			if (setting.TypeName != null && Integers.TryGetValue(setting.TypeName, out (decimal, decimal) value))
			{
				return CheckInteger(setting, text, value);
			}
			if (setting.TypeName != null && Fractions.Contains(setting.TypeName))
			{
				return CheckFraction(setting, text);
			}
			return ValueCheck.Valid(text);
		}

		public static string Cycle(CfgSetting setting, int step)
		{
			IReadOnlyList<string> acceptableValues = setting.AcceptableValues;
			if (acceptableValues.Count == 0)
			{
				return Display(setting);
			}
			string b = Display(setting).Trim();
			int num = -1;
			for (int i = 0; i < acceptableValues.Count; i++)
			{
				if (string.Equals(acceptableValues[i], b, StringComparison.OrdinalIgnoreCase))
				{
					num = i;
				}
			}
			if (num < 0)
			{
				return acceptableValues[0];
			}
			return acceptableValues[((num + step) % acceptableValues.Count + acceptableValues.Count) % acceptableValues.Count];
		}

		public static double? ParseNumber(CfgSetting setting)
		{
			if (!double.TryParse(setting.RawValue, NumberStyles.Float, Invariant, out var result))
			{
				return null;
			}
			return result;
		}

		public static string SliderText(CfgSetting setting, double position)
		{
			NumberRange? range = setting.Range;
			if (range.HasValue)
			{
				NumberRange valueOrDefault = range.GetValueOrDefault();
				double num = Math.Clamp(position, valueOrDefault.Min, valueOrDefault.Max);
				if (IsInteger(setting.TypeName))
				{
					return Math.Round(num).ToString(Invariant);
				}
				double num2 = valueOrDefault.Max - valueOrDefault.Min;
				int digits = ((num2 <= 0.0) ? 2 : Math.Clamp(2 - (int)Math.Floor(Math.Log10(num2)), 0, 6));
				return Math.Round(num, digits).ToString(Invariant);
			}
			return FormatNumber(position);
		}

		public static string FormatNumber(double value)
		{
			return value.ToString("0.######", Invariant);
		}

		public static string Details(CfgSetting setting)
		{
			List<string> list = new List<string>();
			if (!string.IsNullOrWhiteSpace(setting.Description))
			{
				list.Add(setting.Description.Trim());
			}
			List<string> list2 = new List<string>();
			if (setting.DefaultValue != null)
			{
				string text = Readable(setting, setting.DefaultValue);
				list2.Add("Default: " + ((text.Length == 0) ? "(empty)" : text));
			}
			NumberRange? range = setting.Range;
			if (range.HasValue)
			{
				NumberRange valueOrDefault = range.GetValueOrDefault();
				list2.Add("Range: " + FormatNumber(valueOrDefault.Min) + " to " + FormatNumber(valueOrDefault.Max));
			}
			if (setting.IsFlags)
			{
				list2.Add("Several allowed, separated by commas: " + Allowed(setting));
			}
			if (list2.Count > 0)
			{
				list.Add(string.Join(". ", list2) + ".");
			}
			return string.Join("\n", list);
		}

		private static string Readable(CfgSetting setting, string raw)
		{
			if (!(setting.TypeName == "String"))
			{
				return raw;
			}
			return TomlString.Read(raw);
		}

		private static string? Match(CfgSetting setting, string text)
		{
			return setting.AcceptableValues.FirstOrDefault((string v) => string.Equals(v, text, StringComparison.OrdinalIgnoreCase));
		}

		private static string Allowed(CfgSetting setting)
		{
			return string.Join(", ", setting.AcceptableValues);
		}

		private static ValueCheck CheckFlags(CfgSetting setting, string text)
		{
			List<string> list = new List<string>();
			foreach (string item in from p in text.Split(',')
				select p.Trim() into p
				where p.Length > 0
				select p)
			{
				string text2 = Match(setting, item);
				if (text2 == null)
				{
					return ValueCheck.Invalid($"'{item}' is not one of: {Allowed(setting)}.");
				}
				if (!list.Contains(text2))
				{
					list.Add(text2);
				}
			}
			if (list.Count != 0)
			{
				return ValueCheck.Valid(string.Join(", ", list));
			}
			return ValueCheck.Invalid("Pick at least one of: " + Allowed(setting) + ".");
		}

		private static ValueCheck CheckInteger(CfgSetting setting, string text, (decimal Min, decimal Max) bounds)
		{
			if (!decimal.TryParse(text, NumberStyles.AllowLeadingSign, Invariant, out var result))
			{
				return ValueCheck.Invalid("Must be a whole number.");
			}
			if (result < bounds.Min || result > bounds.Max)
			{
				return ValueCheck.Invalid($"Must be a whole number from {bounds.Min.ToString(Invariant)} to {bounds.Max.ToString(Invariant)}.");
			}
			return InRange(setting, (double)result, result.ToString(Invariant));
		}

		private static ValueCheck CheckFraction(CfgSetting setting, string text)
		{
			string s = (text.Contains('.') ? text : text.Replace(',', '.'));
			if (setting.TypeName == "Decimal")
			{
				if (!decimal.TryParse(s, NumberStyles.Float, Invariant, out var result))
				{
					return ValueCheck.Invalid("Must be a number.");
				}
				return InRange(setting, (double)result, result.ToString(Invariant));
			}
			if (!double.TryParse(s, NumberStyles.Float, Invariant, out var result2))
			{
				return ValueCheck.Invalid("Must be a number.");
			}
			if (setting.TypeName == "Single")
			{
				float num = (float)result2;
				if (!float.IsFinite(num))
				{
					return ValueCheck.Invalid("Must be a number.");
				}
				return InRange(setting, num, num.ToString(Invariant));
			}
			if (!double.IsFinite(result2))
			{
				return ValueCheck.Invalid("Must be a number.");
			}
			return InRange(setting, result2, result2.ToString("R", Invariant));
		}

		private static ValueCheck InRange(CfgSetting setting, double value, string raw)
		{
			NumberRange? range = setting.Range;
			if (range.HasValue)
			{
				NumberRange valueOrDefault = range.GetValueOrDefault();
				if (value < valueOrDefault.Min || value > valueOrDefault.Max)
				{
					return ValueCheck.Invalid($"Must be from {FormatNumber(valueOrDefault.Min)} to {FormatNumber(valueOrDefault.Max)}.");
				}
			}
			return ValueCheck.Valid(raw);
		}
	}
}

plugins/ModSettings.Plugin.dll

Decompiled 12 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using I2.Loc;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using ModSettings.Core;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("ModSettings.Plugin")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.2.0.0")]
[assembly: AssemblyInformationalVersion("0.2.0+6baae216dc75e3d6f6ceb0a73f81536dbb0fb0e6")]
[assembly: AssemblyProduct("ModSettings.Plugin")]
[assembly: AssemblyTitle("ModSettings.Plugin")]
[assembly: AssemblyVersion("0.2.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ModSettings.Plugin
{
	internal sealed class ConfigStore
	{
		private sealed class Live
		{
			public ConfigFile File { get; }

			public BepInPlugin Owner { get; }

			public Live(ConfigFile file, BepInPlugin owner)
			{
				File = file;
				Owner = owner;
			}
		}

		private readonly ManualLogSource _log;

		private Dictionary<string, Live> _live = new Dictionary<string, Live>(StringComparer.OrdinalIgnoreCase);

		public IReadOnlyList<ModEntry> Mods { get; private set; } = Array.Empty<ModEntry>();

		public ConfigStore(ManualLogSource log)
		{
			_log = log;
		}

		public void Refresh()
		{
			_live = LiveConfigFiles();
			List<ConfigSource> list = (from path in Directory.EnumerateFiles(Paths.ConfigPath, "*.cfg", SearchOption.AllDirectories)
				where path.EndsWith(".cfg", StringComparison.OrdinalIgnoreCase)
				select path).Select(Source).ToList();
			Mods = ModList.Build((IEnumerable<ConfigSource>)list);
		}

		public string Apply(ModEntry mod, SettingView view, string input)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: 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_00b5: Expected O, but got Unknown
			CfgSetting setting = view.Setting;
			ValueCheck val = ValueRules.Check(setting, input);
			if (!((ValueCheck)(ref val)).Ok)
			{
				return ((ValueCheck)(ref val)).Error;
			}
			string fullPath = Path.GetFullPath(Path.Combine(Paths.ConfigPath, mod.Source.RelativePath));
			try
			{
				_live.TryGetValue(fullPath, out var value);
				ConfigEntryBase val2 = ((value == null) ? null : Entry(value.File, setting));
				if (val2 != null)
				{
					return ApplyToEntry(value.File, val2, ((ValueCheck)(ref val)).Raw);
				}
				WriteFile(fullPath, setting, ((ValueCheck)(ref val)).Raw);
				if (value != null)
				{
					value.File.Reload();
				}
				return null;
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val3 = new BepInExErrorLogInterpolatedStringHandler(22, 4, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Could not save ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(setting.Section);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(".");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(setting.Key);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" in ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(mod.Source.RelativePath);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(": ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<Exception>(ex);
				}
				log.LogError(val3);
				return "Could not save: " + ex.Message;
			}
			finally
			{
				Refresh();
			}
		}

		private ConfigSource Source(string path)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Expected O, but got Unknown
			string fullPath = Path.GetFullPath(path);
			string relativePath = Path.GetRelativePath(Paths.ConfigPath, fullPath);
			bool flag = string.Equals(fullPath, Path.GetFullPath(Paths.BepInExConfigPath), StringComparison.OrdinalIgnoreCase);
			string text;
			try
			{
				text = ReadShared(fullPath);
			}
			catch (Exception ex)
			{
				return new ConfigSource(relativePath, (string)null, ex.Message, (SourceKind)((!flag) ? 1 : 2), (string)null, (string)null, (IReadOnlySet<string>)null, (IReadOnlyDictionary<string, SettingTags>)null);
			}
			if (_live.TryGetValue(fullPath, out var value))
			{
				ReloadIfChangedOnDisk(value.File, text, relativePath);
				HashSet<string> hashSet = new HashSet<string>();
				Dictionary<string, SettingTags> dictionary = new Dictionary<string, SettingTags>();
				foreach (ConfigEntryBase value2 in value.File.Values)
				{
					string text2 = ConfigSource.KeyOf(value2.Definition.Section, value2.Definition.Key);
					hashSet.Add(text2);
					dictionary[text2] = Tags.Of(value2);
				}
				int num = (flag ? 2 : 0);
				BepInPlugin owner = value.Owner;
				string obj = ((owner != null) ? owner.Name : null);
				BepInPlugin owner2 = value.Owner;
				return new ConfigSource(relativePath, text, (string)null, (SourceKind)num, obj, (owner2 == null) ? null : ((object)owner2.Version)?.ToString(), (IReadOnlySet<string>)hashSet, (IReadOnlyDictionary<string, SettingTags>)dictionary);
			}
			return new ConfigSource(relativePath, text, (string)null, (SourceKind)((!flag) ? 1 : 2), (string)null, (string)null, (IReadOnlySet<string>)null, (IReadOnlyDictionary<string, SettingTags>)null);
		}

		private void ReloadIfChangedOnDisk(ConfigFile file, string text, string relative)
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Expected O, but got Unknown
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			bool flag = default(bool);
			try
			{
				foreach (CfgSetting setting in CfgDocument.Parse(text).Settings)
				{
					ConfigEntryBase val = Entry(file, setting);
					if (val != null && !(val.GetSerializedValue() == setting.RawValue))
					{
						file.Reload();
						ManualLogSource log = _log;
						BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(43, 1, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(relative);
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" was changed outside the game; reloaded it.");
						}
						log.LogInfo(val2);
						break;
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = _log;
				BepInExWarningLogInterpolatedStringHandler val3 = new BepInExWarningLogInterpolatedStringHandler(45, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Could not compare ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(relative);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" with its loaded settings: ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(ex.Message);
				}
				log2.LogWarning(val3);
			}
		}

		private static ConfigEntryBase Entry(ConfigFile file, CfgSetting setting)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			try
			{
				ConfigDefinition val = new ConfigDefinition(setting.Section, setting.Key);
				return file.ContainsKey(val) ? file[val] : null;
			}
			catch (ArgumentException)
			{
				return null;
			}
		}

		private static string ApplyToEntry(ConfigFile file, ConfigEntryBase entry, string raw)
		{
			object obj;
			try
			{
				obj = TomlTypeConverter.ConvertToValue(raw, entry.SettingType);
			}
			catch (Exception ex)
			{
				return "Not a valid value: " + ex.Message;
			}
			entry.BoxedValue = obj;
			if (!file.SaveOnConfigSet)
			{
				file.Save();
			}
			if (!object.Equals(entry.BoxedValue, obj))
			{
				return "The mod changed that value to " + entry.GetSerializedValue() + ".";
			}
			return null;
		}

		private static void WriteFile(string path, CfgSetting setting, string raw)
		{
			CfgDocument val = CfgDocument.Parse(ReadShared(path));
			CfgSetting val2 = ((IEnumerable<CfgSetting>)val.Settings).FirstOrDefault((Func<CfgSetting, bool>)((CfgSetting s) => s.Section == setting.Section && s.Key == setting.Key)) ?? throw new InvalidOperationException(setting.Key + " is no longer in the file.");
			string text = path + ".modsettings.tmp";
			File.WriteAllText(text, val.WithValue(val2, raw), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
			File.Move(text, path, overwrite: true);
		}

		private static string ReadShared(string path)
		{
			using FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
			using StreamReader streamReader = new StreamReader(stream);
			return streamReader.ReadToEnd();
		}

		private static Dictionary<string, Live> LiveConfigFiles()
		{
			Dictionary<string, Live> live = new Dictionary<string, Live>(StringComparer.OrdinalIgnoreCase);
			foreach (PluginInfo value in ((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins.Values)
			{
				object instance = value.Instance;
				BasePlugin val = (BasePlugin)((instance is BasePlugin) ? instance : null);
				if (val != null)
				{
					Add(val.Config, value.Metadata);
				}
			}
			Add(ConfigFile.CoreConfig, null);
			return live;
			void Add(ConfigFile file, BepInPlugin owner)
			{
				if (file != null && file.ConfigFilePath != null)
				{
					live.TryAdd(Path.GetFullPath(file.ConfigFilePath), new Live(file, owner));
				}
			}
		}
	}
	internal sealed class FrameWatcher : MonoBehaviour
	{
		public FrameWatcher(IntPtr pointer)
			: base(pointer)
		{
		}

		private void Update()
		{
			Plugin.Instance?.OnFrame();
		}
	}
	internal static class GameKeys
	{
		public static IReadOnlyList<KeyBinding> Read(Action<string, Exception> report)
		{
			List<string> list = new List<string>();
			try
			{
				foreach (InputActionAsset item in Assets())
				{
					list.Add(item.ToJson());
				}
			}
			catch (Exception arg)
			{
				report("reading the game's controls", arg);
			}
			string text = null;
			try
			{
				text = KeyRebinder.CurrentOverridesJson();
			}
			catch (Exception arg2)
			{
				report("reading the game's rebinds", arg2);
			}
			return GameBindings.FromJson((IEnumerable<string>)list, text);
		}

		private static List<InputActionAsset> Assets()
		{
			List<InputActionAsset> assets = new List<InputActionAsset>();
			Add(KeyRebinder.mainAsset);
			Add(KeyRebinder.uiAsset);
			List<InputActionAsset> runtimeAssets = KeyRebinder.RuntimeAssets;
			if (runtimeAssets != null)
			{
				for (int i = 0; i < runtimeAssets.Count; i++)
				{
					Add(runtimeAssets[i]);
				}
			}
			if (assets.Count == 0)
			{
				foreach (InputActionAsset item in Resources.FindObjectsOfTypeAll<InputActionAsset>())
				{
					Add(item);
				}
			}
			return assets;
			void Add(InputActionAsset asset)
			{
				if ((Object)(object)asset != (Object)null && assets.All((InputActionAsset a) => ((Il2CppObjectBase)a).Pointer != ((Il2CppObjectBase)asset).Pointer))
				{
					assets.Add(asset);
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class Hooks
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(MainMenuUI), "Start")]
		private static void AfterMainMenuStart(MainMenuUI __instance)
		{
			AddButton((Component)(object)__instance, "main menu");
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(EscapeMenuUI), "Start")]
		private static void AfterEscapeMenuStart(EscapeMenuUI __instance)
		{
			PauseMenu.Remember(__instance);
			AddButton((Component)(object)__instance, "pause menu");
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(EscapeMenuUI), "Show")]
		private static void AfterEscapeMenuShow(EscapeMenuUI __instance)
		{
			AddButton((Component)(object)__instance, "pause menu");
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(UIManager), "CloseTopWindow")]
		private static bool BeforeCloseTopWindow()
		{
			return !ClosePanel();
		}

		private static void AddButton(Component menu, string where)
		{
			try
			{
				Plugin instance = Plugin.Instance;
				MenuButtons.Add(menu, where, ((BasePlugin)instance).Log, instance.HotkeyName, instance.Panel.Open);
			}
			catch (Exception e)
			{
				Plugin.Instance.ReportOnce("Mods button on the " + where, e);
			}
		}

		private static bool ClosePanel()
		{
			try
			{
				return Plugin.Instance.Panel.HandleEscapeFromGame();
			}
			catch (Exception e)
			{
				Plugin.Instance.ReportOnce("closing the mod settings", e);
				return false;
			}
		}
	}
	internal static class MenuButtons
	{
		private const string CloneName = "ModSettings Mods Button";

		public static void Add(Component menu, string where, ManualLogSource log, string hotkeyName, Action onClick)
		{
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Expected O, but got Unknown
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Expected O, but got Unknown
			if ((Object)(object)menu == (Object)null)
			{
				return;
			}
			Button[] source = ((IEnumerable<Button>)menu.GetComponentsInChildren<Button>(true)).ToArray();
			if (source.Any((Button b) => ((Object)b).name == "ModSettings Mods Button"))
			{
				return;
			}
			List<Button> list = (from b in source
				where (Object)(object)((Component)b).transform.parent != (Object)null && ((Component)b).gameObject.activeSelf
				group b by ((Il2CppObjectBase)((Component)b).transform.parent).Pointer into g
				orderby g.Count() descending
				select g).FirstOrDefault()?.OrderBy((Button b) => ((Component)b).transform.GetSiblingIndex()).ToList();
			if (list == null || list.Count == 0)
			{
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(58, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("No buttons found on the ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(where);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("; press ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(hotkeyName);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" to open the mod settings.");
				}
				log.LogWarning(val);
				return;
			}
			Button val2 = list[list.Count - 1];
			Button obj;
			if (list.Count < 2)
			{
				obj = val2;
			}
			else
			{
				obj = list[list.Count - 2];
			}
			Button val3 = obj;
			Transform parent = ((Component)val2).transform.parent;
			float heightBefore = ColumnHeight(parent);
			GameObject val4 = Object.Instantiate<GameObject>(((Component)val3).gameObject, parent);
			((Object)val4).name = "ModSettings Mods Button";
			val4.transform.SetSiblingIndex(((Component)val2).transform.GetSiblingIndex());
			foreach (Localize componentsInChild in val4.GetComponentsInChildren<Localize>(true))
			{
				((Behaviour)componentsInChild).enabled = false;
			}
			TMP_Text componentInChildren = val4.GetComponentInChildren<TMP_Text>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.text = "Mods";
				Ui.UseFont(componentInChildren);
			}
			Button component = val4.GetComponent<Button>();
			component.onClick = new ButtonClickedEvent();
			Ui.OnClick(component, onClick);
			bool flag2 = (Object)(object)((Component)parent).GetComponent<LayoutGroup>() != (Object)null;
			log.LogInfo((object)($"Added a Mods button to the {where}, copied from '{((Object)val3).name}' under '{PathOf(parent)}'" + (flag2 ? "." : "; that column has no layout group, so the button may overlap another.")));
			KeepHeight(parent, heightBefore, where, log);
		}

		private static void KeepHeight(Transform parent, float heightBefore, string where, ManualLogSource log)
		{
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Expected O, but got Unknown
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			VerticalLayoutGroup component = ((Component)parent).GetComponent<VerticalLayoutGroup>();
			RectTransform val = ((Il2CppObjectBase)parent).TryCast<RectTransform>();
			if ((Object)(object)component == (Object)null || (Object)(object)val == (Object)null || heightBefore <= 0f)
			{
				return;
			}
			LayoutRebuilder.ForceRebuildLayoutImmediate(val);
			float num = ColumnHeight(parent) - heightBefore;
			if (num <= 0.5f)
			{
				return;
			}
			List<RectTransform> list = ActiveChildren(parent);
			int num2 = Math.Max(1, list.Count - 1);
			float spacing = ((HorizontalOrVerticalLayoutGroup)component).spacing;
			float num3 = (((HorizontalOrVerticalLayoutGroup)component).spacing = Math.Max(0f, spacing - num / (float)num2));
			float num5 = num - (spacing - num3) * (float)num2;
			float num6 = ((num5 > 0.5f) ? (num5 / (float)list.Count) : 0f);
			if (num6 > 0f)
			{
				foreach (RectTransform item in list)
				{
					Rect rect = item.rect;
					float num7 = ((Rect)(ref rect)).height - num6;
					if (((HorizontalOrVerticalLayoutGroup)component).childControlHeight)
					{
						LayoutElement obj = ((Component)item).GetComponent<LayoutElement>() ?? ((Component)item).gameObject.AddComponent<LayoutElement>();
						obj.minHeight = num7;
						obj.preferredHeight = num7;
					}
					else
					{
						item.sizeDelta = new Vector2(item.sizeDelta.x, item.sizeDelta.y - num6);
					}
				}
			}
			LayoutRebuilder.ForceRebuildLayoutImmediate(val);
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(74, 6, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Kept the ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(where);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" column ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<float>(heightBefore, "0");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" tall: spacing ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<float>(spacing, "0.#");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" -> ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<float>(num3, "0.#");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", ");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("buttons ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<float>(num6, "0.#");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" shorter (it had grown by ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<float>(num, "0.#");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(").");
			}
			log.LogInfo(val2);
		}

		private static float ColumnHeight(Transform parent)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = ((Il2CppObjectBase)parent).TryCast<RectTransform>();
			if ((Object)(object)val != (Object)null)
			{
				LayoutRebuilder.ForceRebuildLayoutImmediate(val);
			}
			float num = float.MinValue;
			float num2 = float.MaxValue;
			Il2CppStructArray<Vector3> val2 = new Il2CppStructArray<Vector3>(4L);
			foreach (RectTransform item in ActiveChildren(parent))
			{
				item.GetWorldCorners(val2);
				for (int i = 0; i < 4; i++)
				{
					float y = parent.InverseTransformPoint(((Il2CppArrayBase<Vector3>)(object)val2)[i]).y;
					num = Math.Max(num, y);
					num2 = Math.Min(num2, y);
				}
			}
			if (!(num > num2))
			{
				return 0f;
			}
			return num - num2;
		}

		private static List<RectTransform> ActiveChildren(Transform parent)
		{
			List<RectTransform> list = new List<RectTransform>();
			for (int i = 0; i < parent.childCount; i++)
			{
				RectTransform val = ((Il2CppObjectBase)parent.GetChild(i)).TryCast<RectTransform>();
				if ((Object)(object)val != (Object)null && ((Component)val).gameObject.activeSelf)
				{
					list.Add(val);
				}
			}
			return list;
		}

		private static string PathOf(Transform transform)
		{
			List<string> list = new List<string>();
			Transform val = transform;
			while ((Object)(object)val != (Object)null)
			{
				list.Add(((Object)val).name);
				val = val.parent;
			}
			list.Reverse();
			return string.Join("/", list);
		}
	}
	internal static class PauseMenu
	{
		private static EscapeMenuUI _menu;

		public static void Remember(EscapeMenuUI menu)
		{
			_menu = menu;
		}

		public static bool Open()
		{
			EscapeMenuUI menu = _menu;
			if ((Object)(object)menu == (Object)null || ((UIWindow)menu).IsOpen)
			{
				return false;
			}
			UIManager instance = UIManager.Instance;
			if ((Object)(object)instance != (Object)null && instance.IsAnyWindowOpen())
			{
				return false;
			}
			((UIWindow)menu).TryOpen();
			return true;
		}

		public static void Close()
		{
			EscapeMenuUI menu = _menu;
			if ((Object)(object)menu != (Object)null && ((UIWindow)menu).IsOpen)
			{
				((UIWindow)menu).TryClose();
			}
		}
	}
	[BepInPlugin("com.github.kirby1997.modsettings", "ModSettings", "0.2.0")]
	public sealed class Plugin : BasePlugin
	{
		public const string Id = "com.github.kirby1997.modsettings";

		public const string Name = "ModSettings";

		public const string Version = "0.2.0";

		private readonly HashSet<string> _reported = new HashSet<string>();

		private ConfigEntry<Key> _hotkey;

		private List<(Key Key, KeyControl Control)> _keyControls;

		private IntPtr _keyboardPointer;

		private bool _pausedForPanel;

		internal static Plugin Instance { get; private set; }

		internal SettingsPanel Panel { get; private set; }

		internal string HotkeyName => ((object)_hotkey.Value/*cast due to .constrained prefix*/).ToString();

		public override void Load()
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			Instance = this;
			_hotkey = ((BasePlugin)this).Config.Bind<Key>("General", "Hotkey", (Key)103, "Key that opens and closes the mod settings anywhere in the game. None turns it off.");
			Panel = new SettingsPanel(((BasePlugin)this).Log, new ConfigStore(((BasePlugin)this).Log), () => GameKeys.Read(ReportOnce));
			((BasePlugin)this).AddComponent<FrameWatcher>();
			new Harmony("com.github.kirby1997.modsettings").PatchAll(typeof(Hooks));
			ManualLogSource log = ((BasePlugin)this).Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(8, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("ModSettings");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("0.2.0");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" loaded");
			}
			log.LogInfo(val);
		}

		internal void OnFrame()
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Keyboard current = Keyboard.current;
				bool escapePressed = current != null && ((ButtonControl)current.escapeKey).wasPressedThisFrame;
				if (!Panel.IsOpen)
				{
					_pausedForPanel = false;
				}
				if (current != null && Panel.IsCapturing)
				{
					Capture(current);
				}
				else if (current != null && (int)_hotkey.Value != 0 && ((ButtonControl)current[_hotkey.Value]).wasPressedThisFrame)
				{
					ToggleFromHotkey();
				}
				Panel.Tick(escapePressed);
			}
			catch (Exception e)
			{
				ReportOnce("frame update", e);
			}
		}

		private void ToggleFromHotkey()
		{
			if (Panel.IsOpen)
			{
				Panel.Close();
				if (_pausedForPanel)
				{
					PauseMenu.Close();
				}
				_pausedForPanel = false;
			}
			else
			{
				_pausedForPanel = PauseMenu.Open();
				Panel.Open();
			}
		}

		private unsafe void Capture(Keyboard keyboard)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			foreach (var item in KeyControls(keyboard))
			{
				var (val, _) = item;
				if (!((ButtonControl)item.Control).wasPressedThisFrame)
				{
					continue;
				}
				string text = ((object)(*(Key*)(&val))/*cast due to .constrained prefix*/).ToString();
				if (!Panel.CapturingShortcut || !KeyNames.IsModifier(text))
				{
					List<string> heldModifiers = (from k in KeyControls(keyboard)
						where KeyNames.IsModifier(((object)(*(Key*)(&k.Key))/*cast due to .constrained prefix*/).ToString()) && ((ButtonControl)k.Control).isPressed
						select ((object)(*(Key*)(&k.Key))/*cast due to .constrained prefix*/).ToString()).ToList();
					Panel.FinishCapture(text, heldModifiers);
					break;
				}
			}
		}

		private List<(Key Key, KeyControl Control)> KeyControls(Keyboard keyboard)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Invalid comparison between Unknown and I4
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			if (_keyControls != null && _keyboardPointer == ((Il2CppObjectBase)keyboard).Pointer)
			{
				return _keyControls;
			}
			_keyboardPointer = ((Il2CppObjectBase)keyboard).Pointer;
			_keyControls = new List<(Key, KeyControl)>();
			foreach (Key item in Enum.GetValues<Key>().Distinct())
			{
				if ((int)item == 0 || (int)item == 60)
				{
					continue;
				}
				try
				{
					KeyControl val = keyboard[item];
					if (val != null)
					{
						_keyControls.Add((item, val));
					}
				}
				catch (ArgumentException)
				{
				}
			}
			return _keyControls;
		}

		internal void ReportOnce(string what, Exception e)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			if (_reported.Add(what))
			{
				ManualLogSource log = ((BasePlugin)this).Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(9, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(what);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" failed: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(e);
				}
				log.LogError(val);
			}
		}
	}
	internal sealed class SettingsPanel
	{
		private const float SliderDelay = 0.4f;

		private const string Note = "Changes save straight away. Some mods only read their settings when the game starts.";

		private readonly ManualLogSource _log;

		private readonly ConfigStore _store;

		private readonly Func<IReadOnlyList<KeyBinding>> _gameKeys;

		private GameObject _root;

		private RectTransform _modList;

		private RectTransform _settings;

		private ScrollRect _settingsScroll;

		private TextMeshProUGUI _status;

		private Image _statusBar;

		private string _selectedPath;

		private CursorLockMode _cursorLock;

		private bool _cursorVisible;

		private int _escapeFrame = -1;

		private int _escapeHandledFrame = -1;

		private IReadOnlyList<KeyBinding> _gameBindings = Array.Empty<KeyBinding>();

		private IReadOnlyDictionary<string, IReadOnlyList<string>> _clashes = new Dictionary<string, IReadOnlyList<string>>();

		private (ModEntry Mod, SettingView View, TextMeshProUGUI Label)? _capture;

		private (ModEntry Mod, SettingView View, string Text)? _pendingSlider;

		private float _pendingSince;

		public bool IsOpen
		{
			get
			{
				if ((Object)(object)_root != (Object)null)
				{
					return _root.activeSelf;
				}
				return false;
			}
		}

		public bool IsCapturing
		{
			get
			{
				if (IsOpen)
				{
					return _capture.HasValue;
				}
				return false;
			}
		}

		public bool CapturingShortcut
		{
			get
			{
				if (IsCapturing)
				{
					return _capture.Value.View.Setting.TypeName == "KeyboardShortcut";
				}
				return false;
			}
		}

		public SettingsPanel(ManualLogSource log, ConfigStore store, Func<IReadOnlyList<KeyBinding>> gameKeys)
		{
			_log = log;
			_store = store;
			_gameKeys = gameKeys;
		}

		public void Toggle()
		{
			if (IsOpen)
			{
				Close();
			}
			else
			{
				Open();
			}
		}

		public void Open()
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)_root == (Object)null)
				{
					Build();
				}
				_store.Refresh();
				_gameBindings = _gameKeys();
				_capture = null;
				_cursorLock = Cursor.lockState;
				_cursorVisible = Cursor.visible;
				_root.SetActive(true);
				ShowStatus("Changes save straight away. Some mods only read their settings when the game starts.", error: false);
				ShowMods();
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(33, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Could not open the mod settings: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogError(val);
			}
		}

		public void Close()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if (IsOpen)
			{
				FlushSlider();
				_capture = null;
				_root.SetActive(false);
				Cursor.lockState = _cursorLock;
				Cursor.visible = _cursorVisible;
			}
		}

		public void Tick(bool escapePressed)
		{
			if (!IsOpen)
			{
				return;
			}
			Cursor.lockState = (CursorLockMode)0;
			Cursor.visible = true;
			if (_pendingSlider.HasValue && Time.unscaledTime - _pendingSince >= 0.4f)
			{
				FlushSlider();
			}
			int frameCount = Time.frameCount;
			if (escapePressed && _escapeHandledFrame != frameCount)
			{
				if (IsCapturing)
				{
					_escapeHandledFrame = frameCount;
					CancelCapture();
				}
				else
				{
					_escapeFrame = frameCount;
				}
			}
			else if (_escapeFrame == frameCount - 1 && _escapeHandledFrame != _escapeFrame)
			{
				Close();
			}
		}

		public bool HandleEscapeFromGame()
		{
			if (!IsOpen)
			{
				return false;
			}
			int frameCount = Time.frameCount;
			if (_escapeHandledFrame == frameCount)
			{
				return true;
			}
			_escapeHandledFrame = frameCount;
			if (IsCapturing)
			{
				CancelCapture();
			}
			else
			{
				Close();
			}
			return true;
		}

		public void FinishCapture(string key, IReadOnlyList<string> heldModifiers)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			(ModEntry, SettingView, TextMeshProUGUI)? capture = _capture;
			if (capture.HasValue)
			{
				(ModEntry, SettingView, TextMeshProUGUI) valueOrDefault = capture.GetValueOrDefault();
				_capture = null;
				ValueCheck val = KeyNames.Capture(valueOrDefault.Item2.Setting, key, heldModifiers);
				if (!((ValueCheck)(ref val)).Ok)
				{
					((TMP_Text)valueOrDefault.Item3).text = KeyText(valueOrDefault.Item2);
					ShowStatus(valueOrDefault.Item2.Label + " not saved: " + ((ValueCheck)(ref val)).Error, error: true);
				}
				else
				{
					Apply(valueOrDefault.Item1, valueOrDefault.Item2, ((ValueCheck)(ref val)).Raw, rebuild: true);
				}
			}
		}

		private void StartCapture(ModEntry mod, SettingView view, TextMeshProUGUI label)
		{
			CancelCapture();
			_capture = (mod, view, label);
			((TMP_Text)label).text = "Press a key...";
			string value = ((view.Setting.TypeName == "KeyboardShortcut") ? " Hold Ctrl, Shift or Alt with it for a combination." : "");
			ShowStatus($"Press the key to use for {view.Label}.{value} Esc cancels.", error: false);
		}

		private void CancelCapture()
		{
			(ModEntry, SettingView, TextMeshProUGUI)? capture = _capture;
			if (capture.HasValue)
			{
				(ModEntry, SettingView, TextMeshProUGUI) valueOrDefault = capture.GetValueOrDefault();
				_capture = null;
				((TMP_Text)valueOrDefault.Item3).text = KeyText(valueOrDefault.Item2);
				ShowStatus("Changes save straight away. Some mods only read their settings when the game starts.", error: false);
			}
		}

		private static string KeyText(SettingView view)
		{
			if (KeyNames.Parse(view.Setting.TypeName, view.Setting.RawValue) != null)
			{
				return ValueRules.Display(view.Setting);
			}
			return "(none)";
		}

		private void Build()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_005b: 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_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			_root = new GameObject("ModSettings Settings")
			{
				layer = 5
			};
			Object.DontDestroyOnLoad((Object)(object)_root);
			Canvas obj = _root.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = 32000;
			CanvasScaler obj2 = _root.AddComponent<CanvasScaler>();
			obj2.uiScaleMode = (ScaleMode)1;
			obj2.referenceResolution = new Vector2(1920f, 1080f);
			obj2.matchWidthOrHeight = 0.5f;
			_root.AddComponent<GraphicRaycaster>();
			RectTransform component = _root.GetComponent<RectTransform>();
			RectTransform obj3 = Ui.Rect("Blocker", (Transform)(object)component);
			Ui.Stretch(obj3);
			Ui.NewImage((Component)(object)obj3, new Color(0f, 0f, 0f, 0.65f));
			RectTransform val = Ui.Rect("Window", (Transform)(object)component);
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(0.5f, 0.5f);
			val.anchorMax = val2;
			val.anchorMin = val2;
			val.sizeDelta = new Vector2(1500f, 900f);
			Ui.NewImage((Component)(object)val, Ui.PanelColor);
			Ui.Place(((TMP_Text)Ui.NewText((Transform)(object)val, "Mod settings", 44f, (TextAlignmentOptions)4097)).rectTransform, 0f, 1f, 0.6f, 1f, 32f, -84f, 0f, 20f);
			Ui.Place(((Component)Ui.NewButton((Transform)(object)val, "Close", 30f, Ui.ButtonColor, Close)).GetComponent<RectTransform>(), 1f, 1f, 1f, 1f, -196f, -80f, 28f, 24f);
			Ui.Place(((Component)Ui.NewScroll((Transform)(object)val, 6f, out _modList)).GetComponent<RectTransform>(), 0f, 0f, 0f, 1f, 24f, 104f, -444f, 100f);
			_settingsScroll = Ui.NewScroll((Transform)(object)val, 4f, out _settings);
			Ui.Place(((Component)_settingsScroll).GetComponent<RectTransform>(), 0f, 0f, 1f, 1f, 468f, 104f, 24f, 100f);
			RectTransform val3 = Ui.Rect("Status", (Transform)(object)val);
			Ui.Place(val3, 0f, 0f, 1f, 0f, 24f, 24f, 24f, -84f);
			_statusBar = Ui.NewImage((Component)(object)val3, Ui.FieldColor);
			_status = Ui.NewText((Transform)(object)val3, "", 24f, (TextAlignmentOptions)4097);
			Ui.Stretch(((TMP_Text)_status).rectTransform, 12f);
			_root.SetActive(false);
		}

		private void ShowMods()
		{
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			IReadOnlyList<ModEntry> mods = _store.Mods;
			_clashes = KeyClashes.Find(KeyClashes.FromMods((IEnumerable<ModEntry>)mods).Concat(_gameBindings));
			ModEntry val = ((IEnumerable<ModEntry>)mods).FirstOrDefault((Func<ModEntry, bool>)((ModEntry m) => m.Source.RelativePath == _selectedPath)) ?? mods.FirstOrDefault();
			_selectedPath = ((val != null) ? val.Source.RelativePath : null);
			Ui.Clear((Transform)(object)_modList);
			foreach (ModEntry mod in mods)
			{
				string value = ((mod.Version.Length > 0) ? ("v" + mod.Version + " · ") : "");
				bool flag = mod == val;
				string value2 = (_clashes.Keys.Any((string id) => id.StartsWith(mod.Source.RelativePath + "\n", StringComparison.Ordinal)) ? " · key clash" : "");
				Ui.Height((Component)(object)Ui.NewButton((Transform)(object)_modList, $"{mod.Title}\n<size=70%>{value}{mod.Status}{value2}</size>", 28f, flag ? Ui.SelectedColor : Ui.ButtonColor, delegate
				{
					Select(mod);
				}), 76f);
			}
			ShowSettings(val);
		}

		private void Select(ModEntry mod)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			try
			{
				FlushSlider();
				_selectedPath = mod.Source.RelativePath;
				ShowMods();
				_settingsScroll.verticalNormalizedPosition = 1f;
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(17, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Could not show ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(mod.Title);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogError(val);
			}
		}

		private void ShowSettings(ModEntry mod)
		{
			Ui.Clear((Transform)(object)_settings);
			if (mod == (ModEntry)null)
			{
				AddLine("No config files found in BepInEx\\config.", 28f);
				return;
			}
			AddLine(mod.Source.RelativePath, 22f);
			if (mod.Error != null)
			{
				AddLine("Could not read this file: " + mod.Error, 28f);
				return;
			}
			if (mod.Sections.Count == 0)
			{
				AddLine("No settings.", 28f);
			}
			foreach (SectionView section in mod.Sections)
			{
				((TMP_Text)AddLine((section.Name.Length > 0) ? section.Name : "(no section)", 34f)).fontStyle = (FontStyles)1;
				foreach (SettingView setting in section.Settings)
				{
					AddSetting(mod, setting);
				}
			}
		}

		private TextMeshProUGUI AddLine(string text, float size)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			RectTransform obj = Ui.Rect("Line", (Transform)(object)_settings);
			VerticalLayoutGroup obj2 = ((Component)obj).gameObject.AddComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true;
			((LayoutGroup)obj2).padding = new RectOffset
			{
				top = 6
			};
			return Ui.NewText((Transform)(object)obj, text, size, (TextAlignmentOptions)4097);
		}

		private void AddWarning(string text)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected O, but got Unknown
			RectTransform obj = Ui.Rect("Warning", (Transform)(object)_settings);
			Ui.NewImage((Component)(object)obj, Ui.ErrorColor);
			VerticalLayoutGroup obj2 = ((Component)obj).gameObject.AddComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true;
			((LayoutGroup)obj2).padding = new RectOffset
			{
				left = 10,
				right = 10,
				top = 4,
				bottom = 4
			};
			Ui.NewText((Transform)(object)obj, text, 22f, (TextAlignmentOptions)4097);
		}

		private void AddSetting(ModEntry mod, SettingView view)
		{
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Expected O, but got Unknown
			bool flag = !view.AppliesLive;
			RectTransform val = Ui.Rect(view.Label, (Transform)(object)_settings);
			Ui.Height((Component)(object)val, flag ? 76f : 60f);
			Ui.Place(((TMP_Text)Ui.NewText((Transform)(object)val, view.Label + (flag ? "\n<size=70%>applies next launch</size>" : ""), 28f, (TextAlignmentOptions)4097, rich: true)).rectTransform, 0f, 0f, 0.42f, 1f);
			RectTransform val2 = Ui.Rect("Control", (Transform)(object)val);
			Ui.Place(val2, 0.44f, 0f, 1f, 1f, 0f, 4f, 0f, 4f);
			try
			{
				AddControl(mod, view, val2);
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				bool flag2 = default(bool);
				BepInExErrorLogInterpolatedStringHandler val3 = new BepInExErrorLogInterpolatedStringHandler(17, 2, ref flag2);
				if (flag2)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Could not draw ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(view.Setting.Key);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(": ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<Exception>(ex);
				}
				log.LogError(val3);
				Ui.Stretch(((TMP_Text)Ui.NewText((Transform)(object)val2, ValueRules.Display(view.Setting), 28f, (TextAlignmentOptions)4097)).rectTransform);
			}
			if (_clashes.TryGetValue(KeyClashes.IdOf(mod, view), out var value))
			{
				AddWarning("Also bound to: " + string.Join(", ", value));
			}
			string text = ValueRules.Details(view.Setting);
			if (text.Length > 0)
			{
				AddLine(text, 22f);
			}
		}

		private void AddControl(ModEntry mod, SettingView view, RectTransform area)
		{
			//IL_0081: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Expected I4, but got Unknown
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0335: Unknown result type (might be due to invalid IL or missing references)
			//IL_033a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			CfgSetting setting = view.Setting;
			string shown = ValueRules.Display(setting);
			if (view.ReadOnly)
			{
				Ui.Stretch(((TMP_Text)Ui.NewText((Transform)(object)area, shown + "  (read-only)", 28f, (TextAlignmentOptions)4097)).rectTransform);
				return;
			}
			ControlKind control = view.Control;
			switch ((int)control)
			{
			case 4:
			{
				TextMeshProUGUI keyLabel = null;
				Button val = Ui.NewButton((Transform)(object)area, KeyText(view), 28f, Ui.ButtonColor, delegate
				{
					StartCapture(mod, view, keyLabel);
				});
				keyLabel = ((Component)val).GetComponentInChildren<TextMeshProUGUI>();
				Ui.Place(((Component)val).GetComponent<RectTransform>(), 0f, 0f, 0.7f, 1f);
				Ui.Place(((Component)Ui.NewButton((Transform)(object)area, "Clear", 26f, Ui.OffColor, delegate
				{
					Apply(mod, view, "None", rebuild: true);
				})).GetComponent<RectTransform>(), 0.72f, 0f, 1f, 1f);
				return;
			}
			case 0:
			{
				bool on = string.Equals(shown, "true", StringComparison.OrdinalIgnoreCase);
				Ui.Place(((Component)Ui.NewButton((Transform)(object)area, on ? "On" : "Off", 28f, on ? Ui.ButtonColor : Ui.OffColor, delegate
				{
					Apply(mod, view, on ? "false" : "true", rebuild: true);
				})).GetComponent<RectTransform>(), 0f, 0f, 0.3f, 1f);
				return;
			}
			case 1:
				Ui.Place(((Component)Ui.NewButton((Transform)(object)area, "<", 30f, Ui.ButtonColor, delegate
				{
					Apply(mod, view, ValueRules.Cycle(setting, -1), rebuild: true);
				})).GetComponent<RectTransform>(), 0f, 0f, 0.12f, 1f);
				Ui.Place(((TMP_Text)Ui.NewText((Transform)(object)area, shown, 28f, (TextAlignmentOptions)514)).rectTransform, 0.13f, 0f, 0.87f, 1f);
				Ui.Place(((Component)Ui.NewButton((Transform)(object)area, ">", 30f, Ui.ButtonColor, delegate
				{
					Apply(mod, view, ValueRules.Cycle(setting, 1), rebuild: true);
				})).GetComponent<RectTransform>(), 0.88f, 0f, 1f, 1f);
				return;
			case 2:
			{
				NumberRange value = setting.Range.Value;
				double num = ValueRules.ParseNumber(setting) ?? ((NumberRange)(ref value)).Min;
				TextMeshProUGUI valueText = Ui.NewText((Transform)(object)area, shown, 28f, (TextAlignmentOptions)4100);
				Ui.Place(((TMP_Text)valueText).rectTransform, 0.76f, 0f, 1f, 1f);
				Ui.Place(((Component)Ui.NewSlider((Transform)(object)area, (float)((NumberRange)(ref value)).Min, (float)((NumberRange)(ref value)).Max, ValueRules.IsInteger(setting.TypeName), (float)num, delegate(float position)
				{
					string text = ValueRules.SliderText(setting, (double)position);
					((TMP_Text)valueText).text = text;
					_pendingSlider = (mod, view, text);
					_pendingSince = Time.unscaledTime;
				})).GetComponent<RectTransform>(), 0f, 0f, 0.74f, 1f);
				return;
			}
			}
			Ui.Stretch(((Component)Ui.NewInput((Transform)(object)area, shown, 26f, delegate(string text)
			{
				if (text != shown)
				{
					Apply(mod, view, text, rebuild: true);
				}
			})).GetComponent<RectTransform>());
		}

		private void FlushSlider()
		{
			(ModEntry, SettingView, string)? pendingSlider = _pendingSlider;
			if (pendingSlider.HasValue)
			{
				(ModEntry, SettingView, string) valueOrDefault = pendingSlider.GetValueOrDefault();
				_pendingSlider = null;
				Apply(valueOrDefault.Item1, valueOrDefault.Item2, valueOrDefault.Item3, rebuild: false);
			}
		}

		private void Apply(ModEntry mod, SettingView view, string text, bool rebuild)
		{
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Expected O, but got Unknown
			try
			{
				string text2 = _store.Apply(mod, view, text);
				if (text2 == null)
				{
					ShowStatus($"Saved {view.Label} = {text}.", error: false);
				}
				else
				{
					ShowStatus(view.Label + " not saved: " + text2, error: true);
				}
				if (rebuild || text2 != null)
				{
					float verticalNormalizedPosition = _settingsScroll.verticalNormalizedPosition;
					ShowMods();
					Canvas.ForceUpdateCanvases();
					_settingsScroll.verticalNormalizedPosition = verticalNormalizedPosition;
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(18, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Could not apply ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(view.Setting.Key);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogError(val);
			}
		}

		private void ShowStatus(string text, bool error)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			((TMP_Text)_status).text = text;
			((Graphic)_statusBar).color = (error ? Ui.ErrorColor : Ui.FieldColor);
		}
	}
	internal static class Tags
	{
		public static SettingTags Of(ConfigEntryBase entry)
		{
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Expected O, but got Unknown
			ConfigDescription description = entry.Description;
			object[] array = ((description != null) ? description.Tags : null);
			if (array == null)
			{
				return SettingTags.None;
			}
			object[] array2 = array;
			foreach (object obj in array2)
			{
				if (obj != null && !(obj.GetType().Name != "ConfigurationManagerAttributes"))
				{
					object obj2 = Member(obj, "Browsable");
					bool num = obj2 is bool && !(bool)obj2;
					obj2 = Member(obj, "ReadOnly");
					return new SettingTags(num, obj2 is bool && (bool)obj2, Member(obj, "Order") as int?, Member(obj, "DispName") as string);
				}
			}
			return SettingTags.None;
		}

		private static object Member(object target, string name)
		{
			Type type = target.GetType();
			object obj = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(target);
			if (obj == null)
			{
				PropertyInfo? property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if ((object)property == null)
				{
					return null;
				}
				obj = property.GetValue(target);
			}
			return obj;
		}
	}
	internal static class Ui
	{
		public static readonly Color PanelColor = new Color(0.04f, 0.17f, 0.32f, 1f);

		public static readonly Color ButtonColor = new Color(0.02f, 0.55f, 0.72f, 1f);

		public static readonly Color SelectedColor = new Color(0.96f, 0.78f, 0.08f, 1f);

		public static readonly Color FieldColor = new Color(0.01f, 0.09f, 0.18f, 1f);

		public static readonly Color OffColor = new Color(0.2f, 0.27f, 0.35f, 1f);

		public static readonly Color ErrorColor = new Color(0.62f, 0.12f, 0.12f, 1f);

		private const int UiLayer = 5;

		private static TMP_FontAsset _font;

		private static Material _fontMaterial;

		public static void UseFont(TMP_Text template)
		{
			if (!((Object)(object)((template != null) ? template.font : null) == (Object)null))
			{
				_font = template.font;
				_fontMaterial = template.fontSharedMaterial;
			}
		}

		public static RectTransform Rect(string name, Transform parent)
		{
			//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)
			RectTransform obj = new GameObject(name)
			{
				layer = 5
			}.AddComponent<RectTransform>();
			((Transform)obj).SetParent(parent, false);
			return obj;
		}

		public static void Place(RectTransform rect, float xMin, float yMin, float xMax, float yMax, float left = 0f, float bottom = 0f, float right = 0f, float top = 0f)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			rect.anchorMin = new Vector2(xMin, yMin);
			rect.anchorMax = new Vector2(xMax, yMax);
			rect.offsetMin = new Vector2(left, bottom);
			rect.offsetMax = new Vector2(0f - right, 0f - top);
		}

		public static void Stretch(RectTransform rect, float inset = 0f)
		{
			Place(rect, 0f, 0f, 1f, 1f, inset, inset, inset, inset);
		}

		public static Image NewImage(Component owner, Color color)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			Image obj = owner.gameObject.AddComponent<Image>();
			((Graphic)obj).color = color;
			return obj;
		}

		public static TextMeshProUGUI NewText(Transform parent, string text, float size, TextAlignmentOptions alignment = (TextAlignmentOptions)4097, bool rich = false)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			TextMeshProUGUI val = ((Component)Rect("Text", parent)).gameObject.AddComponent<TextMeshProUGUI>();
			if ((Object)(object)_font == (Object)null)
			{
				_font = FallbackFont();
			}
			if ((Object)(object)_font != (Object)null)
			{
				((TMP_Text)val).font = _font;
			}
			if ((Object)(object)_fontMaterial != (Object)null)
			{
				((TMP_Text)val).fontSharedMaterial = _fontMaterial;
			}
			((Graphic)val).color = Color.white;
			((TMP_Text)val).fontSize = size;
			((TMP_Text)val).alignment = alignment;
			((TMP_Text)val).richText = rich;
			((TMP_Text)val).enableWordWrapping = true;
			((Graphic)val).raycastTarget = false;
			((TMP_Text)val).text = text;
			return val;
		}

		public static Button NewButton(Transform parent, string label, float size, Color color, Action onClick)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			RectTransform obj = Rect("Button", parent);
			Image targetGraphic = NewImage((Component)(object)obj, color);
			Button val = ((Component)obj).gameObject.AddComponent<Button>();
			((Selectable)val).targetGraphic = (Graphic)(object)targetGraphic;
			OnClick(val, onClick);
			Stretch(((TMP_Text)NewText((Transform)(object)obj, label, size, (TextAlignmentOptions)514, rich: true)).rectTransform, 6f);
			return val;
		}

		public static void OnClick(Button button, Action onClick)
		{
			((UnityEvent)button.onClick).AddListener(DelegateSupport.ConvertDelegate<UnityAction>((Delegate)onClick));
		}

		public static Slider NewSlider(Transform parent, float min, float max, bool whole, float value, Action<float> changed)
		{
			//IL_0045: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = Rect("Slider", parent);
			RectTransform obj = Rect("Background", (Transform)(object)val);
			Place(obj, 0f, 0.35f, 1f, 0.65f);
			NewImage((Component)(object)obj, FieldColor);
			RectTransform val2 = Rect("Fill Area", (Transform)(object)val);
			Place(val2, 0f, 0.35f, 1f, 0.65f, 12f, 0f, 12f);
			RectTransform val3 = Rect("Fill", (Transform)(object)val2);
			val3.sizeDelta = Vector2.zero;
			NewImage((Component)(object)val3, ButtonColor);
			RectTransform val4 = Rect("Handle Slide Area", (Transform)(object)val);
			Place(val4, 0f, 0f, 1f, 1f, 12f, 0f, 12f);
			RectTransform val5 = Rect("Handle", (Transform)(object)val4);
			val5.sizeDelta = new Vector2(24f, 0f);
			Image targetGraphic = NewImage((Component)(object)val5, SelectedColor);
			Slider obj2 = ((Component)val).gameObject.AddComponent<Slider>();
			obj2.fillRect = val3;
			obj2.handleRect = val5;
			((Selectable)obj2).targetGraphic = (Graphic)(object)targetGraphic;
			obj2.direction = (Direction)0;
			obj2.minValue = min;
			obj2.maxValue = max;
			obj2.wholeNumbers = whole;
			obj2.SetValueWithoutNotify(value);
			((UnityEvent<float>)(object)obj2.onValueChanged).AddListener(DelegateSupport.ConvertDelegate<UnityAction<float>>((Delegate)changed));
			return obj2;
		}

		public static TMP_InputField NewInput(Transform parent, string value, float size, Action<string> endEdit)
		{
			//IL_0019: 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)
			RectTransform val = Rect("Input", parent);
			((Component)val).gameObject.SetActive(false);
			Image targetGraphic = NewImage((Component)(object)val, FieldColor);
			RectTransform val2 = Rect("Text Area", (Transform)(object)val);
			Place(val2, 0f, 0f, 1f, 1f, 10f, 4f, 10f, 4f);
			((Component)val2).gameObject.AddComponent<RectMask2D>();
			TextMeshProUGUI val3 = NewText((Transform)(object)val2, "", size, (TextAlignmentOptions)4097);
			Stretch(((TMP_Text)val3).rectTransform);
			((TMP_Text)val3).enableWordWrapping = false;
			TMP_InputField obj = ((Component)val).gameObject.AddComponent<TMP_InputField>();
			obj.textViewport = val2;
			obj.textComponent = (TMP_Text)(object)val3;
			((Selectable)obj).targetGraphic = (Graphic)(object)targetGraphic;
			obj.lineType = (LineType)0;
			obj.richText = false;
			obj.customCaretColor = true;
			obj.caretColor = Color.white;
			obj.SetTextWithoutNotify(value);
			((UnityEvent<string>)(object)obj.onEndEdit).AddListener(DelegateSupport.ConvertDelegate<UnityAction<string>>((Delegate)endEdit));
			((Component)val).gameObject.SetActive(true);
			return obj;
		}

		public static ScrollRect NewScroll(Transform parent, float spacing, out RectTransform content)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: 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_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Expected O, but got Unknown
			RectTransform val = Rect("Scroll", parent);
			RectTransform val2 = Rect("Viewport", (Transform)(object)val);
			Stretch(val2);
			((Component)val2).gameObject.AddComponent<RectMask2D>();
			NewImage((Component)(object)val2, new Color(0f, 0f, 0f, 0f));
			content = Rect("Content", (Transform)(object)val2);
			content.anchorMin = new Vector2(0f, 1f);
			content.anchorMax = new Vector2(1f, 1f);
			content.pivot = new Vector2(0.5f, 1f);
			content.sizeDelta = Vector2.zero;
			VerticalLayoutGroup obj = ((Component)content).gameObject.AddComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj).spacing = spacing;
			((LayoutGroup)obj).padding = new RectOffset
			{
				left = 4,
				right = 16,
				top = 4,
				bottom = 4
			};
			((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false;
			((Component)content).gameObject.AddComponent<ContentSizeFitter>().verticalFit = (FitMode)2;
			ScrollRect obj2 = ((Component)val).gameObject.AddComponent<ScrollRect>();
			obj2.viewport = val2;
			obj2.content = content;
			obj2.horizontal = false;
			obj2.vertical = true;
			obj2.movementType = (MovementType)2;
			obj2.scrollSensitivity = 40f;
			return obj2;
		}

		public static void Height(Component row, float height)
		{
			LayoutElement obj = row.gameObject.AddComponent<LayoutElement>();
			obj.minHeight = height;
			obj.preferredHeight = height;
		}

		public static void Clear(Transform parent)
		{
			for (int num = parent.childCount - 1; num >= 0; num--)
			{
				GameObject gameObject = ((Component)parent.GetChild(num)).gameObject;
				gameObject.SetActive(false);
				Object.Destroy((Object)(object)gameObject);
			}
		}

		private static TMP_FontAsset FallbackFont()
		{
			Il2CppArrayBase<TMP_FontAsset> val = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();
			if (val.Length <= 0)
			{
				return null;
			}
			return val[0];
		}
	}
}