Decompiled source of ConfigManager v1.0.0

BepInEx/plugins/DiceModders.ConfigMenu.dll

Decompiled a day 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.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using DiceModders.UiKit;
using DiceModders.UiKit.Custom;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("DiceModders.ConfigMenu")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+d6dc3b7e5b1a87d3d33ea76d5fee5b85a8473a8e")]
[assembly: AssemblyProduct("ConfigMenu")]
[assembly: AssemblyTitle("DiceModders.ConfigMenu")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 ConfigMenu
{
	internal sealed class PluginConfig
	{
		public string Guid { get; }

		public string Name { get; }

		public string Version { get; }

		public ConfigFile File { get; }

		public string ConfigPath { get; }

		public List<ConfigSection> Sections { get; } = new List<ConfigSection>();

		public int EntryCount { get; private set; }

		public PluginConfig(string guid, string name, string version, ConfigFile file)
		{
			Guid = guid;
			Name = name;
			Version = version;
			File = file;
			ConfigPath = DisplayPath(file.ConfigFilePath);
		}

		public void BuildSections()
		{
			Sections.Clear();
			EntryCount = 0;
			IEnumerable<ConfigEntryBase> source;
			try
			{
				source = File.Values;
			}
			catch (Exception)
			{
				source = Array.Empty<ConfigEntryBase>();
			}
			foreach (IGrouping<string, ConfigEntryBase> item in (from entry in source
				group entry by entry.Definition.Section ?? string.Empty).OrderBy<IGrouping<string, ConfigEntryBase>, string>((IGrouping<string, ConfigEntryBase> group) => group.Key, StringComparer.OrdinalIgnoreCase))
			{
				ConfigSection configSection = new ConfigSection(string.IsNullOrWhiteSpace(item.Key) ? "General" : item.Key);
				configSection.Entries.AddRange(item.OrderBy<ConfigEntryBase, string>((ConfigEntryBase entry) => entry.Definition.Key, StringComparer.OrdinalIgnoreCase));
				if (configSection.Entries.Count != 0)
				{
					Sections.Add(configSection);
					EntryCount += configSection.Entries.Count;
				}
			}
		}

		private static string DisplayPath(string? fullPath)
		{
			if (string.IsNullOrWhiteSpace(fullPath))
			{
				return string.Empty;
			}
			try
			{
				string fullPath2 = Path.GetFullPath(Paths.ConfigPath);
				string fullPath3 = Path.GetFullPath(fullPath);
				if (fullPath3.StartsWith(fullPath2, StringComparison.OrdinalIgnoreCase))
				{
					string text = fullPath3.Substring(fullPath2.Length).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
					return "BepInEx/config/" + text.Replace('\\', '/');
				}
			}
			catch (Exception)
			{
			}
			return fullPath.Replace('\\', '/');
		}
	}
	internal sealed class ConfigSection
	{
		public string Name { get; }

		public List<ConfigEntryBase> Entries { get; } = new List<ConfigEntryBase>();

		public ConfigSection(string name)
		{
			Name = name;
		}
	}
	internal static class ConfigCatalog
	{
		public static List<PluginConfig> Scan(ManualLogSource? log)
		{
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Expected O, but got Unknown
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Expected O, but got Unknown
			List<PluginConfig> list = new List<PluginConfig>();
			bool flag = default(bool);
			try
			{
				IL2CPPChainloader instance = IL2CPPChainloader.Instance;
				if (instance == null)
				{
					if (log != null)
					{
						log.LogWarning((object)"ConfigMenu: the BepInEx chainloader is not available yet.");
					}
					return list;
				}
				foreach (KeyValuePair<string, PluginInfo> plugin in ((BaseChainloader<BasePlugin>)(object)instance).Plugins)
				{
					try
					{
						PluginInfo value = plugin.Value;
						object obj = ((value != null) ? value.Instance : null);
						BasePlugin val = (BasePlugin)((obj is BasePlugin) ? obj : null);
						if (val == null)
						{
							continue;
						}
						ConfigFile config = val.Config;
						if (config != null && config.Count != 0)
						{
							BepInPlugin metadata = value.Metadata;
							string text = (string.IsNullOrWhiteSpace((metadata != null) ? metadata.GUID : null) ? plugin.Key : value.Metadata.GUID);
							BepInPlugin metadata2 = value.Metadata;
							string name = (string.IsNullOrWhiteSpace((metadata2 != null) ? metadata2.Name : null) ? text : value.Metadata.Name);
							BepInPlugin metadata3 = value.Metadata;
							string version = ((metadata3 == null) ? null : ((object)metadata3.Version)?.ToString()) ?? string.Empty;
							PluginConfig pluginConfig = new PluginConfig(text, name, version, config);
							pluginConfig.BuildSections();
							if (pluginConfig.EntryCount != 0)
							{
								list.Add(pluginConfig);
							}
						}
					}
					catch (Exception ex)
					{
						ManualLogSource val2 = log;
						if (val2 != null)
						{
							BepInExWarningLogInterpolatedStringHandler val3 = new BepInExWarningLogInterpolatedStringHandler(52, 2, ref flag);
							if (flag)
							{
								((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("ConfigMenu: could not read the configuration of '");
								((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(plugin.Key);
								((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("': ");
								((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(ex.Message);
							}
							val2.LogWarning(val3);
						}
					}
				}
			}
			catch (Exception ex2)
			{
				ManualLogSource val2 = log;
				if (val2 != null)
				{
					BepInExErrorLogInterpolatedStringHandler val4 = new BepInExErrorLogInterpolatedStringHandler(39, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("ConfigMenu: configuration scan failed: ");
						((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<Exception>(ex2);
					}
					val2.LogError(val4);
				}
			}
			return list.OrderBy<PluginConfig, string>((PluginConfig plugin) => plugin.Name, StringComparer.OrdinalIgnoreCase).ThenBy<PluginConfig, string>((PluginConfig plugin) => plugin.Guid, StringComparer.OrdinalIgnoreCase).ToList();
		}
	}
	internal enum ConfigValueKind
	{
		Bool,
		Choice,
		Range,
		Number,
		ReadOnly
	}
	internal sealed class ConfigEntryAdapter
	{
		private static readonly CultureInfo Invariant = CultureInfo.InvariantCulture;

		private static readonly HashSet<Type> NumericTypes = new HashSet<Type>
		{
			typeof(byte),
			typeof(sbyte),
			typeof(short),
			typeof(ushort),
			typeof(int),
			typeof(uint),
			typeof(long),
			typeof(ulong),
			typeof(float),
			typeof(double),
			typeof(decimal)
		};

		private static readonly HashSet<Type> SliderTypes = new HashSet<Type>
		{
			typeof(byte),
			typeof(sbyte),
			typeof(short),
			typeof(ushort),
			typeof(int),
			typeof(float),
			typeof(double)
		};

		private readonly object[] _choices = Array.Empty<object>();

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

		public ConfigEntryBase Entry { get; }

		public ConfigValueKind Kind { get; }

		public string Label => Entry.Definition.Key;

		public string Section
		{
			get
			{
				if (!string.IsNullOrWhiteSpace(Entry.Definition.Section))
				{
					return Entry.Definition.Section;
				}
				return "General";
			}
		}

		public string Description
		{
			get
			{
				ConfigDescription description = Entry.Description;
				return ((description != null) ? description.Description : null) ?? string.Empty;
			}
		}

		public bool WholeNumbers { get; private set; }

		public float RangeMin { get; private set; }

		public float RangeMax { get; private set; }

		public double Step { get; private set; } = 1.0;

		public string NumberFormat { get; private set; } = "0.###";

		public object? CurrentValue
		{
			get
			{
				try
				{
					return Entry.BoxedValue;
				}
				catch (Exception)
				{
					return null;
				}
			}
		}

		public bool BoolValue
		{
			get
			{
				object currentValue = CurrentValue;
				bool flag = default(bool);
				int num;
				if (currentValue is bool)
				{
					flag = (bool)currentValue;
					num = 1;
				}
				else
				{
					num = 0;
				}
				return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
			}
		}

		public double NumberValue
		{
			get
			{
				double num = ToDouble(CurrentValue, 0.0);
				if (Kind == ConfigValueKind.Range)
				{
					return Math.Clamp(num, RangeMin, RangeMax);
				}
				return num;
			}
		}

		public IReadOnlyList<string> ChoiceLabels => _choiceLabels;

		public IReadOnlyList<object> Choices => _choices;

		public int ChoiceIndex
		{
			get
			{
				object currentValue = CurrentValue;
				for (int i = 0; i < _choices.Length; i++)
				{
					if (object.Equals(_choices[i], currentValue))
					{
						return i;
					}
				}
				return 0;
			}
		}

		public string DisplayValue
		{
			get
			{
				try
				{
					string serializedValue = Entry.GetSerializedValue();
					if (!string.IsNullOrEmpty(serializedValue))
					{
						return serializedValue;
					}
				}
				catch (Exception)
				{
				}
				return FormatChoice(CurrentValue);
			}
		}

		public string Hint
		{
			get
			{
				List<string> list = new List<string>();
				if (!string.IsNullOrWhiteSpace(Description))
				{
					list.Add(Description.Trim());
				}
				if (Kind == ConfigValueKind.Range)
				{
					list.Add("Range: " + FormatNumber(RangeMin) + ".." + FormatNumber(RangeMax));
				}
				else if (Kind == ConfigValueKind.Number)
				{
					list.Add("Step: " + FormatNumber(Step));
				}
				else if (Kind == ConfigValueKind.ReadOnly)
				{
					list.Add("Read-only here; edit the .cfg file with a text editor.");
				}
				return string.Join("  ", list);
			}
		}

		public ConfigEntryAdapter(ConfigEntryBase entry)
		{
			Entry = entry;
			Kind = ConfigValueKind.ReadOnly;
			Type settingType = entry.SettingType;
			ConfigDescription description = entry.Description;
			AcceptableValueBase acceptable = ((description != null) ? description.AcceptableValues : null);
			double min;
			double max;
			if (TryGetAcceptableList(acceptable, out object[] values))
			{
				_choices = values;
				_choiceLabels = values.Select(FormatChoice).ToArray();
				Kind = ConfigValueKind.Choice;
			}
			else if (settingType == typeof(bool))
			{
				Kind = ConfigValueKind.Bool;
			}
			else if (settingType.IsEnum)
			{
				if (settingType.GetCustomAttributes(typeof(FlagsAttribute), inherit: false).Length == 0)
				{
					_choices = Enum.GetValues(settingType).Cast<object>().ToArray();
					_choiceLabels = _choices.Select(FormatChoice).ToArray();
					Kind = ConfigValueKind.Choice;
				}
			}
			else if (NumericTypes.Contains(settingType) && TryGetRange(acceptable, out min, out max))
			{
				float num = (float)min;
				float num2 = (float)max;
				if (SliderTypes.Contains(settingType) && float.IsFinite(num) && float.IsFinite(num2) && num2 > num && num2 - num <= 1000000f)
				{
					RangeMin = num;
					RangeMax = num2;
					WholeNumbers = IsIntegral(settingType);
					NumberFormat = (WholeNumbers ? "0" : "0.###");
					Kind = ConfigValueKind.Range;
				}
				else
				{
					Kind = ConfigValueKind.Number;
				}
			}
			else if (NumericTypes.Contains(settingType))
			{
				Kind = ConfigValueKind.Number;
				NumberFormat = (IsIntegral(settingType) ? "0" : "0.###");
			}
			if (Kind == ConfigValueKind.Number)
			{
				Step = ComputeStep(settingType, entry.DefaultValue);
			}
		}

		public bool TrySetBool(bool value, out string error)
		{
			return TrySet(value, out error);
		}

		public bool TrySetChoice(int index, out string error)
		{
			if (index < 0 || index >= _choices.Length)
			{
				error = "The selected value is no longer available.";
				return false;
			}
			return TrySet(_choices[index], out error);
		}

		public bool TrySetNumber(double value, out string error)
		{
			return TrySet(value, out error);
		}

		public bool TryStep(int direction, out string error)
		{
			double value = NumberValue + (double)Math.Sign(direction) * Step;
			Type settingType = Entry.SettingType;
			if (IsIntegral(settingType))
			{
				value = Math.Round(value, MidpointRounding.AwayFromZero);
				value = ClampIntegral(settingType, value);
			}
			return TrySetNumber(value, out error);
		}

		public bool TryReset(out string error)
		{
			try
			{
				object defaultValue = Entry.DefaultValue;
				if (defaultValue == null)
				{
					error = "This setting has no default value.";
					return false;
				}
				return TrySet(defaultValue, out error);
			}
			catch (Exception ex)
			{
				error = ex.Message;
				return false;
			}
		}

		private bool TrySet(object? value, out string error)
		{
			try
			{
				if (value == null)
				{
					error = "The setting value is null.";
					return false;
				}
				object boxedValue = Coerce(value, Entry.SettingType);
				Entry.BoxedValue = boxedValue;
				if (!Entry.ConfigFile.SaveOnConfigSet)
				{
					Entry.ConfigFile.Save();
				}
				error = string.Empty;
				return true;
			}
			catch (Exception ex)
			{
				error = ex.Message;
				return false;
			}
		}

		private static object Coerce(object value, Type targetType)
		{
			if (targetType.IsInstanceOfType(value))
			{
				return value;
			}
			if (targetType.IsEnum)
			{
				if (value is string value2)
				{
					return Enum.Parse(targetType, value2, ignoreCase: true);
				}
				return Enum.ToObject(targetType, value);
			}
			if (targetType == typeof(bool))
			{
				return Convert.ToBoolean(value, Invariant);
			}
			return Convert.ChangeType(value, targetType, Invariant) ?? throw new InvalidCastException($"Cannot convert '{value}' to {targetType.Name}.");
		}

		private static bool TryGetAcceptableList(AcceptableValueBase? acceptable, out object[] values)
		{
			values = Array.Empty<object>();
			if (acceptable == null)
			{
				return false;
			}
			Type type = ((object)acceptable).GetType();
			if (!type.IsGenericType || type.GetGenericTypeDefinition() != typeof(AcceptableValueList<>))
			{
				return false;
			}
			if (!(type.GetProperty("AcceptableValues")?.GetValue(acceptable) is Array { Length: not 0 } array))
			{
				return false;
			}
			values = array.Cast<object>().ToArray();
			return true;
		}

		private static bool TryGetRange(AcceptableValueBase? acceptable, out double min, out double max)
		{
			min = 0.0;
			max = 0.0;
			if (acceptable == null)
			{
				return false;
			}
			Type type = ((object)acceptable).GetType();
			if (!type.IsGenericType || type.GetGenericTypeDefinition() != typeof(AcceptableValueRange<>))
			{
				return false;
			}
			try
			{
				PropertyInfo property = type.GetProperty("MinValue");
				PropertyInfo property2 = type.GetProperty("MaxValue");
				if (property == null || property2 == null)
				{
					return false;
				}
				min = Convert.ToDouble(property.GetValue(acceptable), Invariant);
				max = Convert.ToDouble(property2.GetValue(acceptable), Invariant);
				return double.IsFinite(min) && double.IsFinite(max) && max > min;
			}
			catch (Exception)
			{
				return false;
			}
		}

		private static double ComputeStep(Type type, object? defaultValue)
		{
			if (IsIntegral(type))
			{
				return 1.0;
			}
			double num = Math.Abs(ToDouble(defaultValue, 0.0));
			if (!double.IsFinite(num) || num <= 0.0)
			{
				num = 1.0;
			}
			double num2 = Math.Floor(Math.Log10(num));
			return Math.Clamp(Math.Pow(10.0, num2 - 1.0), 0.0001, 1000000.0);
		}

		private static bool IsIntegral(Type type)
		{
			if (!(type == typeof(byte)) && !(type == typeof(sbyte)) && !(type == typeof(short)) && !(type == typeof(ushort)) && !(type == typeof(int)) && !(type == typeof(uint)) && !(type == typeof(long)))
			{
				return type == typeof(ulong);
			}
			return true;
		}

		private static double ClampIntegral(Type type, double value)
		{
			if (type == typeof(byte))
			{
				return Math.Clamp(value, 0.0, 255.0);
			}
			if (type == typeof(sbyte))
			{
				return Math.Clamp(value, -128.0, 127.0);
			}
			if (type == typeof(short))
			{
				return Math.Clamp(value, -32768.0, 32767.0);
			}
			if (type == typeof(ushort))
			{
				return Math.Clamp(value, 0.0, 65535.0);
			}
			if (type == typeof(int))
			{
				return Math.Clamp(value, -2147483648.0, 2147483647.0);
			}
			if (type == typeof(uint))
			{
				return Math.Clamp(value, 0.0, 4294967295.0);
			}
			if (type == typeof(long))
			{
				return Math.Clamp(value, -9.223372036854776E+18, 9.223372036854776E+18);
			}
			if (type == typeof(ulong))
			{
				return Math.Clamp(value, 0.0, 1.8446744073709552E+19);
			}
			return value;
		}

		private static double ToDouble(object? value, double fallback)
		{
			if (value == null)
			{
				return fallback;
			}
			try
			{
				return (value is IConvertible convertible) ? convertible.ToDouble(Invariant) : fallback;
			}
			catch (Exception)
			{
				return fallback;
			}
		}

		private static string FormatChoice(object? value)
		{
			if (value != null)
			{
				if (!(value is string result))
				{
					if (!(value is bool))
					{
						if (!(value is Enum obj))
						{
							if (value is IFormattable formattable)
							{
								return formattable.ToString(null, Invariant) ?? string.Empty;
							}
							return value.ToString() ?? string.Empty;
						}
						return obj.ToString();
					}
					return ((bool)value) ? "True" : "False";
				}
				return result;
			}
			return string.Empty;
		}

		private static string FormatNumber(double value)
		{
			return value.ToString("0.######", Invariant);
		}
	}
	internal sealed class ConfigWindow : IDisposable
	{
		private sealed class RowBinding
		{
			private readonly ConfigEntryAdapter _adapter;

			private readonly UiToggle? _toggle;

			private readonly UiDropdown? _dropdown;

			private readonly UiSlider? _slider;

			private readonly UiText? _valueText;

			public RowBinding(ConfigEntryAdapter adapter, UiToggle? toggle, UiDropdown? dropdown, UiSlider? slider, UiText? valueText)
			{
				_adapter = adapter;
				_toggle = toggle;
				_dropdown = dropdown;
				_slider = slider;
				_valueText = valueText;
			}

			public void Refresh()
			{
				try
				{
					switch (_adapter.Kind)
					{
					case ConfigValueKind.Bool:
					{
						UiToggle? toggle = _toggle;
						if (toggle != null)
						{
							toggle.Set(_adapter.BoolValue);
						}
						break;
					}
					case ConfigValueKind.Choice:
					{
						UiDropdown? dropdown = _dropdown;
						if (dropdown != null)
						{
							dropdown.Set(_adapter.ChoiceIndex);
						}
						break;
					}
					case ConfigValueKind.Range:
					{
						UiSlider? slider = _slider;
						if (slider != null)
						{
							slider.Set((float)_adapter.NumberValue);
						}
						break;
					}
					default:
						if (_valueText != null)
						{
							_valueText.Value = _adapter.DisplayValue;
						}
						break;
					}
				}
				catch (Exception)
				{
				}
			}
		}

		private static readonly Color HeaderColor = new Color(0.95f, 0.83f, 0.55f, 1f);

		private static readonly Color DimColor = new Color(0.72f, 0.68f, 0.6f, 1f);

		private static readonly Color ErrorColor = new Color(1f, 0.42f, 0.38f, 1f);

		private readonly UiScope _scope;

		private readonly ManualLogSource _log;

		private readonly Dictionary<string, UiButton> _pluginButtons = new Dictionary<string, UiButton>();

		private readonly Dictionary<ConfigEntryBase, RowBinding> _rowBindings = new Dictionary<ConfigEntryBase, RowBinding>();

		private UiWindow? _window;

		private List<PluginConfig> _plugins = new List<PluginConfig>();

		private string? _selectedGuid;

		private ConfigFile? _subscribedFile;

		private EventHandler<SettingChangedEventArgs>? _settingChanged;

		private UiContainer? _pluginList;

		private UiScroll? _pluginScroll;

		private UiScroll? _entryScroll;

		private UiText? _pluginTitle;

		private UiText? _pluginMeta;

		private UiText? _status;

		private bool _disposed;

		private PluginConfig? SelectedPlugin
		{
			get
			{
				if (string.IsNullOrEmpty(_selectedGuid))
				{
					return null;
				}
				return _plugins.FirstOrDefault((PluginConfig plugin) => plugin.Guid == _selectedGuid);
			}
		}

		public ConfigWindow(UiScope scope, ManualLogSource log)
		{
			_scope = scope;
			_log = log;
		}

		public void Toggle()
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			if (_disposed)
			{
				return;
			}
			try
			{
				if (_window != null && ((UiElement)_window).IsAlive && _window.IsVisible)
				{
					_window.Close();
				}
				else
				{
					Open();
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(41, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ConfigMenu: could not toggle the window: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogError(val);
			}
		}

		public void Open()
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			if (_disposed || _scope.IsDisposed)
			{
				return;
			}
			try
			{
				if (_window != null && ((UiElement)_window).IsAlive)
				{
					if (!_window.IsVisible)
					{
						_window.Show();
					}
					_window.BringToFront();
				}
				else
				{
					RefreshCatalog();
					BuildWindow();
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(39, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ConfigMenu: could not open the window: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogError(val);
			}
		}

		public void Dispose()
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			if (_disposed)
			{
				return;
			}
			_disposed = true;
			Unsubscribe();
			UiWindow window = _window;
			_window = null;
			if (window != null)
			{
				try
				{
					((UiElement)window).Dispose();
				}
				catch (Exception ex)
				{
					ManualLogSource log = _log;
					bool flag = default(bool);
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(35, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ConfigMenu: window cleanup failed: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
					}
					log.LogWarning(val);
				}
			}
			ResetViewFields();
		}

		private void BuildWindow()
		{
			EnsureSelection();
			_pluginButtons.Clear();
			_rowBindings.Clear();
			UiWindow val = _scope.Custom.Window((Action<UiWindow>)delegate(UiWindow w)
			{
				w.Title("Mod Configuration").Size(920f, 620f).Center()
					.Draggable(true)
					.Closable(true)
					.Fullscreenable(true)
					.FullscreenButton(true)
					.Ornament((OrnamentStyle)3)
					.OnClose((Action)HandleClosed);
				UiContainer obj = w.Body.Row((Action<UiContainer>)delegate(UiContainer bodyRow)
				{
					UiContainer obj2 = bodyRow.Column((Action<UiContainer>)delegate(UiContainer leftColumn)
					{
						//IL_001b: Unknown result type (might be due to invalid IL or missing references)
						UiText obj4 = leftColumn.Text("Mods");
						if (obj4 != null)
						{
							obj4.Size(18f).Color(HeaderColor);
						}
						UiScroll obj5 = leftColumn.Scroll((Action<UiContainer>)delegate(UiContainer list)
						{
							_pluginList = list;
							BuildPluginList(list);
						});
						_pluginScroll = ((obj5 != null) ? UiLayout.FillHeight<UiScroll>(obj5) : null);
					});
					if (obj2 != null)
					{
						UiLayout.FillHeight<UiContainer>(UiLayout.FixedW<UiContainer>(obj2, 232f));
					}
					UiContainer obj3 = bodyRow.Column((Action<UiContainer>)delegate(UiContainer rightColumn)
					{
						//IL_001d: Unknown result type (might be due to invalid IL or missing references)
						//IL_0049: Unknown result type (might be due to invalid IL or missing references)
						//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
						UiText obj4 = rightColumn.Text(string.Empty);
						_pluginTitle = ((obj4 != null) ? obj4.Size(18f).Color(HeaderColor) : null);
						UiText obj5 = rightColumn.Text(string.Empty);
						_pluginMeta = ((obj5 != null) ? obj5.Size(12f).Color(DimColor) : null);
						UiContainer obj6 = rightColumn.Row((Action<UiContainer>)delegate(UiContainer tools)
						{
							UiButton obj9 = tools.Button("Refresh", (Action)RefreshClicked);
							if (obj9 != null)
							{
								UiLayout.FixedW<UiButton>(obj9, 90f);
							}
							UiButton obj10 = tools.Button("Reload", (Action)ReloadClicked);
							if (obj10 != null)
							{
								UiLayout.FixedW<UiButton>(obj10, 90f);
							}
							UiButton obj11 = tools.Button("Save all", (Action)SaveAllClicked);
							if (obj11 != null)
							{
								UiLayout.FixedW<UiButton>(obj11, 90f);
							}
						});
						if (obj6 != null)
						{
							UiContainer obj7 = UiLayout.Height<UiContainer>(obj6, 34f);
							if (obj7 != null)
							{
								obj7.Spacing(8f, 0f);
							}
						}
						UiText obj8 = rightColumn.Text("Ready.");
						_status = ((obj8 != null) ? obj8.Size(13f).Color(DimColor) : null);
						_entryScroll = rightColumn.Scroll((Action<UiContainer>)delegate(UiContainer list)
						{
							BuildEntries(list);
						});
						UiScroll? entryScroll = _entryScroll;
						if (entryScroll != null)
						{
							UiLayout.FillHeight<UiScroll>(entryScroll);
						}
					});
					if (obj3 != null)
					{
						UiLayout.FillHeight<UiContainer>(UiLayout.WeightW<UiContainer>(obj3, 1f));
					}
				});
				if (obj != null)
				{
					UiLayout.FillHeight<UiContainer>(obj);
				}
			});
			if (val == null)
			{
				_window = null;
				_log.LogError((object)"ConfigMenu: the window could not be created.");
				return;
			}
			_window = val;
			UpdateHeader();
			Subscribe();
			Status("Ready.");
		}

		private void HandleClosed()
		{
			Unsubscribe();
			_window = null;
			ResetViewFields();
		}

		private void ResetViewFields()
		{
			_pluginList = null;
			_pluginScroll = null;
			_entryScroll = null;
			_pluginTitle = null;
			_pluginMeta = null;
			_status = null;
			_pluginButtons.Clear();
			_rowBindings.Clear();
		}

		private void EnsureSelection()
		{
			if (_plugins.Count == 0)
			{
				_selectedGuid = null;
			}
			else if (string.IsNullOrEmpty(_selectedGuid) || _plugins.All((PluginConfig plugin) => plugin.Guid != _selectedGuid))
			{
				_selectedGuid = _plugins[0].Guid;
			}
		}

		private void RefreshCatalog()
		{
			string previous = _selectedGuid;
			_plugins = ConfigCatalog.Scan(_log);
			if (!string.IsNullOrEmpty(previous) && _plugins.Any((PluginConfig plugin) => plugin.Guid == previous))
			{
				_selectedGuid = previous;
			}
			else
			{
				_selectedGuid = _plugins.FirstOrDefault()?.Guid;
			}
			if (_window != null && ((UiElement)_window).IsAlive)
			{
				if (_pluginList != null)
				{
					BuildPluginList(_pluginList);
				}
				UiScroll? entryScroll = _entryScroll;
				if (((entryScroll != null) ? entryScroll.Content : null) != null)
				{
					BuildEntries(_entryScroll.Content);
				}
				UpdateHeader();
				Subscribe();
			}
		}

		private void BuildPluginList(UiContainer list)
		{
			list.Clear();
			_pluginButtons.Clear();
			if (_plugins.Count == 0)
			{
				list.Paragraph("No mods with configuration files were found.");
				return;
			}
			foreach (PluginConfig plugin in _plugins)
			{
				PluginConfig model = plugin;
				UiButton val = list.Button($"{model.Name} ({model.EntryCount})", (Action)delegate
				{
					SelectPlugin(model.Guid);
				});
				if (val != null)
				{
					UiLayout.Height<UiButton>(val, 32f);
				}
				if (val != null)
				{
					val.Selected(model.Guid == _selectedGuid);
				}
				if (val != null)
				{
					_pluginButtons[model.Guid] = val;
				}
			}
		}

		private void SelectPlugin(string guid)
		{
			if (_selectedGuid == guid)
			{
				return;
			}
			Unsubscribe();
			_selectedGuid = guid;
			foreach (KeyValuePair<string, UiButton> pluginButton in _pluginButtons)
			{
				pluginButton.Value.Selected(pluginButton.Key == guid);
			}
			Subscribe();
			UiScroll? entryScroll = _entryScroll;
			if (((entryScroll != null) ? entryScroll.Content : null) != null)
			{
				BuildEntries(_entryScroll.Content);
			}
			UpdateHeader();
			Status("Selected " + (SelectedPlugin?.Name ?? guid) + ".");
		}

		private void UpdateHeader()
		{
			PluginConfig selectedPlugin = SelectedPlugin;
			if (_pluginTitle != null)
			{
				_pluginTitle.Value = ((selectedPlugin == null) ? "No mods found" : (selectedPlugin.Name + " " + selectedPlugin.Version).Trim());
			}
			if (_pluginMeta != null)
			{
				_pluginMeta.Value = ((selectedPlugin == null) ? string.Empty : $"{selectedPlugin.Guid}  |  {selectedPlugin.ConfigPath}  |  {selectedPlugin.EntryCount} settings");
			}
		}

		private void BuildEntries(UiContainer list)
		{
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Expected O, but got Unknown
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Expected O, but got Unknown
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			list.Clear();
			_rowBindings.Clear();
			PluginConfig selectedPlugin = SelectedPlugin;
			if (selectedPlugin == null)
			{
				list.Paragraph("Select a mod to see its settings.");
				return;
			}
			if (selectedPlugin.Sections.Count == 0)
			{
				list.Paragraph("This mod does not expose any editable settings.");
				return;
			}
			bool flag = Plugin.ShowReadOnly?.Value ?? true;
			bool flag2 = false;
			bool flag3 = default(bool);
			foreach (ConfigSection section in selectedPlugin.Sections)
			{
				List<ConfigEntryAdapter> list2 = new List<ConfigEntryAdapter>();
				foreach (ConfigEntryBase entry in section.Entries)
				{
					try
					{
						ConfigEntryAdapter configEntryAdapter = new ConfigEntryAdapter(entry);
						if (flag || configEntryAdapter.Kind != ConfigValueKind.ReadOnly)
						{
							list2.Add(configEntryAdapter);
						}
					}
					catch (Exception ex)
					{
						ManualLogSource log = _log;
						BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(36, 2, ref flag3);
						if (flag3)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ConfigMenu: could not inspect row ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<ConfigDefinition>(entry.Definition);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
						}
						log.LogWarning(val);
					}
				}
				if (list2.Count == 0)
				{
					continue;
				}
				flag2 = true;
				UiText obj = list.Text(section.Name);
				if (obj != null)
				{
					obj.Size(16f).Color(HeaderColor);
				}
				list.Separator(1f);
				list.Spacer(2f);
				foreach (ConfigEntryAdapter item in list2)
				{
					try
					{
						BuildEntryRow(list, item);
					}
					catch (Exception ex2)
					{
						ManualLogSource log2 = _log;
						BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(34, 2, ref flag3);
						if (flag3)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ConfigMenu: could not build row ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<ConfigDefinition>(item.Entry.Definition);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex2.Message);
						}
						log2.LogWarning(val);
						UiText obj2 = list.Paragraph(item.Label + ": could not be displayed (" + ex2.Message + ")");
						if (obj2 != null)
						{
							obj2.Size(12f).Color(ErrorColor);
						}
					}
				}
				list.Spacer(10f);
			}
			if (!flag2)
			{
				list.Paragraph(flag ? "This mod does not expose any settings ConfigMenu can display." : "This mod has no editable settings. Enable ShowReadOnly in ConfigMenu's own settings to see them.");
			}
		}

		private void BuildEntryRow(UiContainer list, ConfigEntryAdapter adapter)
		{
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			UiToggle toggle = null;
			UiDropdown dropdown = null;
			UiSlider slider = null;
			UiText valueText = null;
			UiContainer val = list.Row((Action<UiContainer>)delegate(UiContainer controlRow)
			{
				//IL_032d: Unknown result type (might be due to invalid IL or missing references)
				//IL_035b: Unknown result type (might be due to invalid IL or missing references)
				switch (adapter.Kind)
				{
				case ConfigValueKind.Bool:
				{
					toggle = controlRow.Toggle(adapter.Label, adapter.BoolValue, (Action<bool>)delegate(bool value)
					{
						OnBool(adapter, value);
					});
					UiToggle obj13 = toggle;
					if (obj13 != null)
					{
						UiLayout.WeightW<UiToggle>(obj13, 1f);
					}
					break;
				}
				case ConfigValueKind.Choice:
				{
					UiText obj11 = controlRow.Text(adapter.Label);
					if (obj11 != null)
					{
						UiLayout.WeightW<UiText>(obj11, 1f);
					}
					dropdown = controlRow.Dropdown((IEnumerable<string>)adapter.ChoiceLabels, adapter.ChoiceIndex, (Action<int>)delegate(int index)
					{
						OnChoice(adapter, index);
					});
					UiDropdown obj12 = dropdown;
					if (obj12 != null)
					{
						UiLayout.FixedW<UiDropdown>(obj12, 280f);
					}
					break;
				}
				case ConfigValueKind.Range:
				{
					UiText obj7 = controlRow.Text(adapter.Label);
					if (obj7 != null)
					{
						UiLayout.WeightW<UiText>(obj7, 1f);
					}
					slider = controlRow.Slider(adapter.RangeMin, adapter.RangeMax, (float)adapter.NumberValue, (Action<float>)delegate(float value)
					{
						OnNumber(adapter, value);
					});
					UiSlider obj8 = slider;
					if (obj8 != null)
					{
						obj8.Format(adapter.NumberFormat);
					}
					UiSlider obj9 = slider;
					if (obj9 != null)
					{
						obj9.WholeNumbers(adapter.WholeNumbers);
					}
					UiSlider obj10 = slider;
					if (obj10 != null)
					{
						UiLayout.WeightW<UiSlider>(obj10, 1.4f);
					}
					break;
				}
				case ConfigValueKind.Number:
				{
					UiText obj14 = controlRow.Text(adapter.Label);
					if (obj14 != null)
					{
						UiLayout.WeightW<UiText>(obj14, 1f);
					}
					UiButton obj15 = controlRow.Button("-", (Action)delegate
					{
						OnStep(adapter, -1);
					});
					if (obj15 != null)
					{
						UiLayout.FixedW<UiButton>(obj15, 30f);
					}
					valueText = controlRow.Text(adapter.DisplayValue);
					UiText obj16 = valueText;
					if (obj16 != null)
					{
						UiLayout.FixedW<UiText>(obj16, 120f);
					}
					UiText obj17 = valueText;
					if (obj17 != null)
					{
						obj17.Align((TextAlignmentOptions)4100);
					}
					UiButton obj18 = controlRow.Button("+", (Action)delegate
					{
						OnStep(adapter, 1);
					});
					if (obj18 != null)
					{
						UiLayout.FixedW<UiButton>(obj18, 30f);
					}
					break;
				}
				default:
				{
					UiText obj2 = controlRow.Text(adapter.Label);
					if (obj2 != null)
					{
						UiLayout.WeightW<UiText>(obj2, 1f);
					}
					valueText = controlRow.Text(adapter.DisplayValue);
					UiText obj3 = valueText;
					if (obj3 != null)
					{
						UiLayout.WeightW<UiText>(obj3, 1f);
					}
					UiText obj4 = valueText;
					if (obj4 != null)
					{
						obj4.Align((TextAlignmentOptions)4100);
					}
					UiText obj5 = valueText;
					if (obj5 != null)
					{
						obj5.Color(DimColor);
					}
					UiText obj6 = controlRow.Text("read-only");
					if (obj6 != null)
					{
						UiLayout.FixedW<UiText>(obj6, 72f);
					}
					if (obj6 != null)
					{
						obj6.Color(DimColor);
					}
					break;
				}
				}
				UiButton obj19 = controlRow.Button("Reset", (Action)delegate
				{
					OnReset(adapter);
				});
				if (obj19 != null)
				{
					UiLayout.FixedW<UiButton>(obj19, 58f);
				}
			});
			if (val != null)
			{
				UiLayout.Height<UiContainer>(val, 34f);
				val.Spacing(8f, 0f);
			}
			_rowBindings[adapter.Entry] = new RowBinding(adapter, toggle, dropdown, slider, valueText);
			string hint = adapter.Hint;
			if (!string.IsNullOrWhiteSpace(hint))
			{
				UiText obj = list.Paragraph(hint);
				if (obj != null)
				{
					obj.Size(12f).Color(DimColor);
				}
			}
		}

		private void OnBool(ConfigEntryAdapter adapter, bool value)
		{
			if (adapter.TrySetBool(value, out string error))
			{
				RefreshEntry(adapter.Entry);
				Status($"Saved {adapter.Section}/{adapter.Label}.");
			}
			else
			{
				StatusError("Could not save " + adapter.Label + ": " + error);
			}
		}

		private void OnChoice(ConfigEntryAdapter adapter, int index)
		{
			if (adapter.TrySetChoice(index, out string error))
			{
				RefreshEntry(adapter.Entry);
				Status($"Saved {adapter.Section}/{adapter.Label}.");
			}
			else
			{
				StatusError("Could not save " + adapter.Label + ": " + error);
			}
		}

		private void OnNumber(ConfigEntryAdapter adapter, float value)
		{
			if (adapter.TrySetNumber(value, out string error))
			{
				RefreshEntry(adapter.Entry);
				Status($"Saved {adapter.Section}/{adapter.Label}.");
			}
			else
			{
				StatusError("Could not save " + adapter.Label + ": " + error);
			}
		}

		private void OnStep(ConfigEntryAdapter adapter, int direction)
		{
			if (adapter.TryStep(direction, out string error))
			{
				RefreshEntry(adapter.Entry);
				Status($"Saved {adapter.Section}/{adapter.Label}.");
			}
			else
			{
				StatusError("Could not save " + adapter.Label + ": " + error);
			}
		}

		private void OnReset(ConfigEntryAdapter adapter)
		{
			if (adapter.TryReset(out string error))
			{
				RefreshEntry(adapter.Entry);
				Status($"Reset {adapter.Section}/{adapter.Label} to default.");
			}
			else
			{
				StatusError("Could not reset " + adapter.Label + ": " + error);
			}
		}

		private void RefreshEntry(ConfigEntryBase entry)
		{
			if (_rowBindings.TryGetValue(entry, out RowBinding value))
			{
				value.Refresh();
			}
		}

		private void Subscribe()
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			Unsubscribe();
			PluginConfig selectedPlugin = SelectedPlugin;
			if (selectedPlugin == null)
			{
				return;
			}
			_settingChanged = delegate(object? _, SettingChangedEventArgs args)
			{
				//IL_0079: Unknown result type (might be due to invalid IL or missing references)
				//IL_007f: Expected O, but got Unknown
				try
				{
					if (args.ChangedSetting.Definition.Section == "UI" && args.ChangedSetting.Definition.Key == "ShowReadOnly")
					{
						UiScroll? entryScroll = _entryScroll;
						if (((entryScroll != null) ? entryScroll.Content : null) != null)
						{
							BuildEntries(_entryScroll.Content);
						}
					}
					else
					{
						RefreshEntry(args.ChangedSetting);
					}
				}
				catch (Exception ex2)
				{
					ManualLogSource log2 = _log;
					bool flag2 = default(bool);
					BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(45, 1, ref flag2);
					if (flag2)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("ConfigMenu: could not refresh a setting row: ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex2.Message);
					}
					log2.LogWarning(val2);
				}
			};
			try
			{
				selectedPlugin.File.SettingChanged += _settingChanged;
				_subscribedFile = selectedPlugin.File;
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(46, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ConfigMenu: could not subscribe to ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(selectedPlugin.Guid);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" settings: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				log.LogWarning(val);
				_settingChanged = null;
			}
		}

		private void Unsubscribe()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			if (_subscribedFile != null && _settingChanged != null)
			{
				try
				{
					_subscribedFile.SettingChanged -= _settingChanged;
				}
				catch (Exception ex)
				{
					ManualLogSource log = _log;
					bool flag = default(bool);
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(49, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ConfigMenu: could not unsubscribe from settings: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
					}
					log.LogWarning(val);
				}
			}
			_subscribedFile = null;
			_settingChanged = null;
		}

		private void RefreshClicked()
		{
			RefreshCatalog();
			Status($"Refreshed: {_plugins.Count} mod(s) with settings.");
		}

		private void ReloadClicked()
		{
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Expected O, but got Unknown
			PluginConfig selectedPlugin = SelectedPlugin;
			if (selectedPlugin == null)
			{
				return;
			}
			try
			{
				Unsubscribe();
				selectedPlugin.File.Reload();
				selectedPlugin.BuildSections();
				Subscribe();
				UiScroll? entryScroll = _entryScroll;
				if (((entryScroll != null) ? entryScroll.Content : null) != null)
				{
					BuildEntries(_entryScroll.Content);
				}
				UpdateHeader();
				Status("Reloaded " + selectedPlugin.ConfigPath + " from disk.");
			}
			catch (Exception ex)
			{
				StatusError("Could not reload " + selectedPlugin.Name + ": " + ex.Message);
				ManualLogSource log = _log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(31, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ConfigMenu: reload of ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(selectedPlugin.Guid);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" failed: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogWarning(val);
			}
		}

		private void SaveAllClicked()
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			int num = 0;
			int num2 = 0;
			bool flag = default(bool);
			foreach (PluginConfig plugin in _plugins)
			{
				try
				{
					plugin.File.Save();
					num++;
				}
				catch (Exception ex)
				{
					num2++;
					ManualLogSource log = _log;
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(29, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ConfigMenu: could not save ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(plugin.Guid);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
					}
					log.LogWarning(val);
				}
			}
			if (num2 > 0)
			{
				StatusError($"Saved {num} file(s); {num2} failed.");
			}
			else
			{
				Status($"Saved {num} config file(s).");
			}
		}

		private void Status(string message)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (_status != null)
			{
				_status.Value = message;
				_status.Color(HeaderColor);
			}
		}

		private void StatusError(string message)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (_status != null)
			{
				_status.Value = message;
				_status.Color(ErrorColor);
			}
			ManualLogSource log = _log;
			bool flag = default(bool);
			BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(12, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ConfigMenu: ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(message);
			}
			log.LogWarning(val);
		}
	}
	[BepInPlugin("DiceModders.ConfigMenu", "ConfigMenu", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BasePlugin
	{
		internal static ManualLogSource Log;

		internal static ConfigEntry<int>? TopBarOrder;

		internal static ConfigEntry<bool>? ShowReadOnly;

		internal static ConfigEntry<bool>? OpenOnStart;

		private UiScope? _ui;

		private ConfigWindow? _window;

		public override void Load()
		{
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Expected O, but got Unknown
			Log = ((BasePlugin)this).Log;
			TopBarOrder = ((BasePlugin)this).Config.Bind<int>("UI", "TopBarOrder", 100, "Order of the ConfigMenu button among mod buttons in the game's top-right bar. Lower values come first. Takes effect after a restart.");
			ShowReadOnly = ((BasePlugin)this).Config.Bind<bool>("UI", "ShowReadOnly", true, "Show settings that ConfigMenu cannot edit in this version (strings and advanced types) as read-only rows. Takes effect immediately.");
			OpenOnStart = ((BasePlugin)this).Config.Bind<bool>("UI", "OpenOnStart", false, "Open the configuration window automatically after the game's UI is ready. Intended for testing and screenshots.");
			_ui = UiKit.CreateScope("DiceModders.ConfigMenu");
			if (_ui == null)
			{
				Log.LogError((object)"ConfigMenu: UiKit is not available; the configuration window will not open.");
				return;
			}
			_window = new ConfigWindow(_ui, Log);
			_ui.WhenReady((Action<UiScope>)delegate(UiScope ui)
			{
				//IL_0090: Unknown result type (might be due to invalid IL or missing references)
				//IL_0096: Expected O, but got Unknown
				try
				{
					string text = (((Object)(object)ui.Custom.Theme.Icon("settings") != (Object)null) ? "settings" : "hammer");
					ui.Native.TopBar.AddIconButton(text, "Mod configuration", (Action)delegate
					{
						_window?.Toggle();
					}, TopBarOrder?.Value ?? 100);
					ConfigEntry<bool>? openOnStart = OpenOnStart;
					if (openOnStart != null && openOnStart.Value)
					{
						_window?.Open();
					}
				}
				catch (Exception ex)
				{
					ManualLogSource log2 = Log;
					bool flag2 = default(bool);
					BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(51, 1, ref flag2);
					if (flag2)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("ConfigMenu: could not register the top-bar button: ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
					}
					log2.LogError(val2);
				}
			});
			ManualLogSource log = Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(18, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Plugin ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("DiceModders.ConfigMenu");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" is loaded!");
			}
			log.LogInfo(val);
		}

		public override bool Unload()
		{
			_window?.Dispose();
			_window = null;
			UiScope? ui = _ui;
			if (ui != null)
			{
				ui.Dispose();
			}
			_ui = null;
			return true;
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "DiceModders.ConfigMenu";

		public const string PLUGIN_NAME = "ConfigMenu";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}