Decompiled source of Configgy v1.0.4

plugins/Configgy.dll

Decompiled 8 months ago
using System;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using Configgable.Assets;
using Configgy.Assets;
using Configgy.Configuration.AutoGeneration;
using Configgy.Properties;
using Configgy.UI;
using Configgy.UI.Template;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("Hydraxous")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyCopyright("Copyright © 2024 Hydraxous. All rights reserved.")]
[assembly: AssemblyDescription("Configuration plugin")]
[assembly: AssemblyFileVersion("1.0.4.0")]
[assembly: AssemblyInformationalVersion("1.0.4+6b315237c165210b0f4af72982add3c265577ff4")]
[assembly: AssemblyProduct("Configgy")]
[assembly: AssemblyTitle("Configgy")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/Hydraxous/Configgy")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.4.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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 Configgy
{
	public class BehaviourRelay : MonoBehaviour
	{
		public Action<GameObject> OnAwake;

		public Action<GameObject> OnStart;

		public Action<GameObject> OnUpdate;

		public Action<GameObject> OnLateUpdate;

		public Action<GameObject> OnFixedUpdate;

		public Action<GameObject> OnOnEnable;

		public Action<GameObject> OnOnDisable;

		public Action<GameObject> OnOnDestroy;

		private void Awake()
		{
			OnAwake?.Invoke(((Component)this).gameObject);
		}

		private void Start()
		{
			OnStart?.Invoke(((Component)this).gameObject);
		}

		private void Update()
		{
			OnUpdate?.Invoke(((Component)this).gameObject);
		}

		private void LateUpdate()
		{
			OnLateUpdate?.Invoke(((Component)this).gameObject);
		}

		private void FixedUpdate()
		{
			OnFixedUpdate?.Invoke(((Component)this).gameObject);
		}

		private void OnEnable()
		{
			OnOnEnable?.Invoke(((Component)this).gameObject);
		}

		private void OnDisable()
		{
			OnOnDisable?.Invoke(((Component)this).gameObject);
		}

		private void OnDestroy()
		{
			OnOnDestroy?.Invoke(((Component)this).gameObject);
		}
	}
	public class ConfigBuilder
	{
		internal Assembly owner;

		internal List<IConfigElement> _configElements;

		internal static HashSet<Type> environmentBuiltTypes = new HashSet<Type>();

		private bool builtGlobal = false;

		private List<SerializedConfiggable> _data;

		private bool saveNextFrame;

		public string GUID { get; }

		public string DisplayName { get; }

		internal bool initialized { get; private set; }

		private List<SerializedConfiggable> data
		{
			get
			{
				if (_data == null)
				{
					LoadData();
				}
				return _data;
			}
		}

		public event Action<IConfigElement[]> OnConfigElementsChanged;

		public ConfigBuilder(string guid = null, string menuDisplayName = null)
		{
			owner = Assembly.GetCallingAssembly();
			GUID = (string.IsNullOrEmpty(guid) ? owner.GetName().Name : guid);
			DisplayName = (string.IsNullOrEmpty(menuDisplayName) ? GUID : menuDisplayName);
		}

		public void BuildTypes(params Type[] types)
		{
			foreach (Type type in types)
			{
				BuildType(type);
			}
		}

		public void BuildType(Type type)
		{
			if ((object)owner == null)
			{
				owner = Assembly.GetCallingAssembly();
			}
			if (owner != type.Assembly)
			{
				throw new Exception("Configgy.ConfigBuilder:" + GUID + ": You can only build types originating from the assembly that owns the ConfigBuilder.");
			}
			if (environmentBuiltTypes.Contains(type))
			{
				if (builtGlobal)
				{
					throw new Exception("Configgy.ConfigBuilder:" + GUID + ": Type has already been built into an existing config. If this is a mistake and you called BuildAll, you must call BuildType before BuildAll.");
				}
				throw new Exception("Configgy.ConfigBuilder:" + GUID + ": Type has already been built into an existing config.");
			}
			if (_configElements == null)
			{
				_configElements = new List<IConfigElement>();
			}
			ProcessType(type);
			BuildInternal();
		}

		public void BuildAll()
		{
			if (!builtGlobal)
			{
				if ((object)owner == null)
				{
					owner = Assembly.GetCallingAssembly();
				}
				if (_configElements == null)
				{
					_configElements = new List<IConfigElement>();
				}
				Type[] types = owner.GetTypes();
				foreach (Type type in types)
				{
					ProcessType(type);
				}
				builtGlobal = true;
				BuildInternal();
			}
		}

		[Obsolete("Build is now obsolete. Use ConfigBuilder.BuildAll to build using your whole assembly.")]
		public void Build()
		{
			if (!initialized)
			{
				BuildAll();
			}
		}

		internal void ProcessType(Type type)
		{
			if (!environmentBuiltTypes.Contains(type))
			{
				MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo method in methods)
				{
					ProcessMethod(method);
				}
				FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo field in fields)
				{
					ProcessField(field);
				}
				environmentBuiltTypes.Add(type);
			}
		}

		internal void BuildInternal()
		{
			if (!initialized)
			{
				if (_configElements == null)
				{
					_configElements = new List<IConfigElement>();
				}
				CreateSaverObject();
				OnConfigElementsChanged += delegate
				{
					ConfigurationManager.SubMenuElementsChanged();
				};
				this.OnConfigElementsChanged?.Invoke(_configElements.ToArray());
				initialized = true;
				ConfigurationManager.RegisterConfiguraitonMenu(this);
			}
		}

		public void Rebuild()
		{
			this.OnConfigElementsChanged?.Invoke(_configElements.ToArray());
		}

		internal IConfigElement[] GetConfigElements()
		{
			return _configElements.ToArray();
		}

		private void ProcessMethod(MethodInfo method)
		{
			ConfiggableAttribute customAttribute = method.GetCustomAttribute<ConfiggableAttribute>();
			if (customAttribute == null)
			{
				return;
			}
			if (method.ReturnType != typeof(void))
			{
				Debug.LogError((object)("Configgy.ConfigBuilder:" + GUID + ": attempted to register method " + method.DeclaringType.Name + "." + method.Name + ". But it's return type is not void. Skipping!"));
				return;
			}
			if (method.GetParameters().Length != 0)
			{
				Debug.LogError((object)("Configgy.ConfigBuilder:" + GUID + ": attempted to register method " + method.DeclaringType.Name + "." + method.Name + ". But it has more than 0 parameters. Skipping!"));
				return;
			}
			if (!method.IsStatic)
			{
				Debug.LogError((object)("Configgy.ConfigBuilder:" + GUID + ": attempted to register method " + method.DeclaringType.Name + "." + method.Name + ". But it is not static. Skipping!"));
				return;
			}
			customAttribute.SetOwner(this);
			customAttribute.SetSerializationAddress(GUID + "." + method.DeclaringType.Namespace + "." + method.DeclaringType.Name + "." + method.Name);
			if (string.IsNullOrEmpty(customAttribute.DisplayName))
			{
				customAttribute.SetDisplayNameFromCamelCase(method.Name);
			}
			RegisterMethodAsButton(customAttribute, method);
		}

		private void ProcessField(FieldInfo field)
		{
			ConfiggableAttribute customAttribute = field.GetCustomAttribute<ConfiggableAttribute>();
			if (customAttribute == null)
			{
				return;
			}
			if (!field.IsStatic)
			{
				Debug.LogError((object)("Configgy.ConfigBuilder:" + GUID + ": attempted to register field " + field.DeclaringType.Name + "." + field.Name + ". But it is not static. Skipping!"));
				return;
			}
			customAttribute.SetOwner(this);
			customAttribute.SetSerializationAddress(GUID + "." + field.DeclaringType.Namespace + "." + field.DeclaringType.Name + "." + field.Name);
			if (string.IsNullOrEmpty(customAttribute.DisplayName))
			{
				customAttribute.SetDisplayNameFromCamelCase(field.Name);
			}
			if (typeof(IConfigElement).IsAssignableFrom(field.FieldType))
			{
				IConfigElement configElement = (IConfigElement)field.GetValue(null);
				RegisterElementCore(customAttribute, configElement);
			}
			else
			{
				RegisterPrimitive(customAttribute, field);
			}
		}

		private void RegisterMethodAsButton(ConfiggableAttribute descriptor, MethodInfo method)
		{
			ConfigButton configButton = new ConfigButton(delegate
			{
				method.Invoke(null, null);
			});
			configButton.BindConfig(this);
			configButton.BindDescriptor(descriptor);
			RegisterElementCore(descriptor, configButton);
		}

		private void RegisterElementCore(ConfiggableAttribute descriptor, IConfigElement configElement)
		{
			configElement.BindDescriptor(descriptor);
			configElement.BindConfig(this);
			_configElements.Add(configElement);
		}

		public void RegisterElement(ConfiggableAttribute descriptor, IConfigElement configElement)
		{
			BuildInternal();
			RegisterElementCore(descriptor, configElement);
		}

		public void RegisterBepInExConfigEntry(ConfigEntryBase entry)
		{
			BuildInternal();
			ConfiggableAttribute configgableAttribute = new ConfiggableAttribute(entry.Definition.Section, entry.Definition.Key, 0, entry.Description.Description);
			configgableAttribute.SetOwner(this);
			if (!(typeof(ConfigBuilder).GetMethod("MakeBepInExElement", BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod(entry.SettingType).Invoke(null, new object[1] { entry }) is ConfigValueElement element))
			{
				Debug.LogWarning((object)("Configgy.ConfigBuilder:" + GUID + ": failed to auto generate BepInEx ConfigEntry " + entry.Definition.Section + "." + entry.Definition.Key + ". It's type (" + entry.SettingType.Name + ") is not supported."));
			}
			else
			{
				RegisterElementCore(configgableAttribute, BepinElement.WrapUntyped(entry, element));
			}
		}

		private static ConfigValueElement MakeBepInExElement<T>(ConfigEntry<T> entry)
		{
			ConfigDescription description = ((ConfigEntryBase)entry).Description;
			AcceptableValueBase val = ((description != null) ? description.AcceptableValues : null);
			if (val.IsAcceptableValueList())
			{
				MethodInfo method = typeof(ConfigBuilder).GetMethod("MakeBepInExDropdown", BindingFlags.Static | BindingFlags.NonPublic);
				MethodInfo methodInfo = method.MakeGenericMethod(typeof(T));
				return (ConfigDropdown<T>)methodInfo.Invoke(null, new object[1] { entry });
			}
			if (val is AcceptableValueRange<int> val2)
			{
				return new IntegerSlider((int)((ConfigEntryBase)entry).DefaultValue, val2.MinValue, val2.MaxValue);
			}
			if (val is AcceptableValueRange<float> val3)
			{
				return new FloatSlider((float)((ConfigEntryBase)entry).DefaultValue, val3.MinValue, val3.MaxValue);
			}
			T @default = entry.GetDefault<T>();
			return ConfigValueElement.Create(@default);
		}

		private static ConfigDropdown<T> MakeBepInExDropdown<T>(ConfigEntry<T> entry) where T : IEquatable<T>
		{
			AcceptableValueList<T> val = (AcceptableValueList<T>)(object)((ConfigEntryBase)entry).Description.AcceptableValues;
			T[] acceptableValues = val.AcceptableValues;
			Func<T, string> selector = ((ConfigEntryBase)(object)entry).GetTag<Func<T, string>>() ?? ((Func<T, string>)((T v) => v.ToString()));
			string[] names = acceptableValues.Select(selector).ToArray();
			T @default = entry.GetDefault<T>();
			return new ConfigDropdown<T>(acceptableValues, @default, names);
		}

		private void RegisterPrimitive(ConfiggableAttribute descriptor, FieldInfo field)
		{
			ConfigValueElement configValueElement = MakeElementForField(field);
			if (configValueElement != null)
			{
				configValueElement.BindField(field);
				RegisterElementCore(descriptor, configValueElement);
			}
		}

		private ConfigValueElement MakeElementForField(FieldInfo field)
		{
			object value = field.GetValue(null);
			RangeAttribute customAttribute = ((MemberInfo)field).GetCustomAttribute<RangeAttribute>();
			if (customAttribute != null)
			{
				if (value is float num)
				{
					float min = customAttribute.min;
					float max = customAttribute.max;
					float defaultValue = Mathf.Clamp(num, min, max);
					return new FloatSlider(defaultValue, min, max);
				}
				if (value is int num2)
				{
					int num3 = (int)customAttribute.min;
					int num4 = (int)customAttribute.max;
					int defaultValue2 = Mathf.Clamp(num2, num3, num4);
					return new IntegerSlider(defaultValue2, num3, num4);
				}
			}
			ConfigValueElement configValueElement = typeof(ConfigValueElement).GetMethod("Create").MakeGenericMethod(value.GetType()).Invoke(null, new object[1] { value }) as ConfigValueElement;
			if (configValueElement == null)
			{
				Debug.LogError((object)("Configgy.ConfigBuilder:" + GUID + ": attempted to register field " + field.DeclaringType.Name + "." + field.Name + ". But it's type (" + field.FieldType.Name + ") is not supported. Skipping!"));
			}
			return configValueElement;
		}

		internal void LoadData()
		{
			string text = Path.Combine(Paths.DataFolder, owner.GetName().Name);
			if (!Directory.Exists(text))
			{
				string text2 = Path.Combine(Paths.LegacyDataFolder, owner.GetName().Name);
				if (Directory.Exists(text2))
				{
					Debug.LogWarning((object)("Found legacy configgy data for " + GUID + ". Moving to new location."));
					Directory.Move(text2, text);
					Debug.LogWarning((object)"Move Complete.");
				}
				else
				{
					Directory.CreateDirectory(text);
					Debug.LogWarning((object)("Created configgy directory for " + GUID + "."));
				}
			}
			string text3 = Path.Combine(text, GUID + ".json");
			List<SerializedConfiggable> list = new List<SerializedConfiggable>();
			if (!File.Exists(text3))
			{
				string contents = JsonConvert.SerializeObject((object)list);
				File.WriteAllText(text3, contents);
			}
			else
			{
				try
				{
					string text4 = File.ReadAllText(text3);
					list = JsonConvert.DeserializeObject<List<SerializedConfiggable>>(text4);
					Debug.Log((object)$"Loaded Config {GUID} with {list.Count} values");
				}
				catch (Exception ex)
				{
					Debug.LogError((object)"Error Loading Configgy Data!");
					Debug.LogException(ex);
					int i;
					for (i = 0; File.Exists(text3 + ".backup" + ((i > 0) ? $" ({i})" : "")); i++)
					{
					}
					Debug.Log((object)"Created configgy file backup.");
					File.Copy(text3, text3 + ".backup" + ((i > 0) ? $" ({i})" : ""));
					File.Delete(text3);
					list = new List<SerializedConfiggable>();
				}
			}
			list = list.Where((SerializedConfiggable x) => x.IsValid()).ToList();
			_data = list;
		}

		public void SaveData()
		{
			if (_data != null)
			{
				string text = Path.Combine(Paths.DataFolder, owner.GetName().Name);
				if (!Directory.Exists(text))
				{
					Directory.CreateDirectory(text);
				}
				string path = Path.Combine(text, GUID + ".json");
				string contents = JsonConvert.SerializeObject((object)_data, (Formatting)1);
				File.WriteAllText(path, contents);
			}
		}

		internal void SaveDeferred()
		{
			saveNextFrame = true;
		}

		private IEnumerator SaveChecker()
		{
			while (true)
			{
				yield return (object)new WaitForEndOfFrame();
				if (saveNextFrame)
				{
					SaveData();
					saveNextFrame = false;
				}
			}
		}

		internal void CreateSaverObject()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			GameObject val = new GameObject("Configgy_Saver (" + GUID + ")");
			BehaviourRelay behaviourRelay = val.AddComponent<BehaviourRelay>();
			((Object)val).hideFlags = (HideFlags)61;
			((MonoBehaviour)behaviourRelay).StartCoroutine(SaveChecker());
			Object.DontDestroyOnLoad((Object)(object)val);
		}

		internal T GetValueAtAddress<T>(string address)
		{
			foreach (SerializedConfiggable datum in data)
			{
				if (datum.key == address)
				{
					return datum.GetValue<T>();
				}
			}
			return default(T);
		}

		internal bool TryGetValueAtAddress<T>(string address, out T value)
		{
			value = default(T);
			foreach (SerializedConfiggable datum in data)
			{
				if (datum.key == address)
				{
					try
					{
						value = datum.GetValue<T>();
						return true;
					}
					catch (Exception ex)
					{
						Debug.LogError((object)"Failed to deserialize value");
						Debug.LogException(ex);
					}
					break;
				}
			}
			return false;
		}

		internal void SetValueAtAddress(string address, object value)
		{
			foreach (SerializedConfiggable datum in data)
			{
				if (datum.key == address)
				{
					datum.SetValue(value);
					return;
				}
			}
			data.Add(new SerializedConfiggable(address, value));
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field)]
	public class ConfiggableAttribute : Attribute
	{
		public string Path { get; }

		public string DisplayName { get; private set; }

		public string Description { get; private set; }

		public int OrderInList { get; }

		public string SerializationAddress { get; private set; }

		public ConfigBuilder Owner { get; private set; }

		public ConfiggableAttribute(string path = "", string displayName = null, int orderInList = 0, string description = null)
		{
			Path = path;
			DisplayName = displayName;
			Description = description;
			OrderInList = orderInList;
		}

		public void SetSerializationAddress(string address)
		{
			SerializationAddress = address;
		}

		public void SetDisplayName(string name)
		{
			DisplayName = name;
		}

		public void SetDescription(string description)
		{
			Description = description;
		}

		public void SetOwner(ConfigBuilder owner)
		{
			if (Owner == null)
			{
				Owner = owner;
			}
		}

		public void SetDisplayNameFromCamelCase(string camelCaseName)
		{
			string input = camelCaseName;
			input = Regex.Replace(input, "^_", "").Trim();
			input = Regex.Replace(input, "([a-z])([A-Z])", "$1 $2").Trim();
			input = Regex.Replace(input, "([A-Z])([A-Z][a-z])", "$1 $2").Trim();
			input = string.Concat(input.Select((char x) => char.IsUpper(x) ? (" " + x) : x.ToString())).TrimStart(new char[1] { ' ' });
			if (input.Length > 0 && char.IsLower(input[0]))
			{
				char c = input[0];
				input = input.Remove(0, 1);
				input = char.ToUpper(c) + input;
			}
			DisplayName = input;
		}
	}
	public static class ConfigurationManager
	{
		private static List<ConfigBuilder> menus = new List<ConfigBuilder>();

		internal static event Action<ConfigBuilder[]> OnMenusChanged;

		internal static void RegisterConfiguraitonMenu(ConfigBuilder menu)
		{
			if (menus.Select((ConfigBuilder x) => x.GUID).Contains(menu.GUID))
			{
				throw new DuplicateNameException("ConfigBuilder GUID (" + menu.GUID + ") already exists! Using two ConfiggableMenus with the same GUID is not allowed.");
			}
			menus.Add(menu);
			ConfigurationManager.OnMenusChanged?.Invoke(GetMenus());
		}

		internal static ConfigBuilder[] GetMenus()
		{
			return menus.ToArray();
		}

		internal static void SubMenuElementsChanged()
		{
			ConfigurationManager.OnMenusChanged?.Invoke(GetMenus());
		}
	}
	public static class ConfigValidators
	{
		public static bool Clamp(float value, float min, float max)
		{
			return value > min && value < max;
		}

		public static bool Min(float value, float min)
		{
			return value > min;
		}

		public static bool Max(float value, float max)
		{
			return value < max;
		}

		public static bool Clamp(int value, int min, int max)
		{
			return value > min && value < max;
		}

		public static bool Min(int value, int min)
		{
			return value > min;
		}

		public static bool Max(int value, int max)
		{
			return value < max;
		}
	}
	public interface IConfigElement
	{
		internal void BindDescriptor(ConfiggableAttribute configgable);

		internal ConfiggableAttribute GetDescriptor();

		void BuildElement(RectTransform rect);

		void OnMenuOpen();

		void OnMenuClose();

		internal void BindConfig(ConfigBuilder configBuilder);
	}
	internal static class ConstInfo
	{
		public const string GUID = "Hydraxous.ULTRAKILL.Configgy";

		public const string NAME = "Configgy";

		public const string VERSION = "1.0.4";

		public const string GITHUB_URL = "https://github.com/Hydraxous/Configgy/";

		public const string THUNDERSTORE_URL = "https://thunderstore.io/c/ultrakill/p/Hydraxous/Configgy/";

		public const string GITHUB_VERSION_URL = "https://api.github.com/repos/Hydraxous/Configgy/tags";
	}
	public class ConfiggyPersistent<T> : ConfigValueElement<T>
	{
		public ConfiggyPersistent(T defaultValue)
			: base(defaultValue)
		{
		}

		protected override void BuildElementCore(RectTransform rect)
		{
		}

		protected override void RefreshElementValueCore()
		{
		}
	}
	internal static class Paths
	{
		public static string ExecutionPath => Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

		public static string GameFolder => Path.GetDirectoryName(Application.dataPath);

		public static string BepInExFolder => Path.Combine(GameFolder, "BepInEx");

		public static string BepInExConfigFolder => Path.Combine(BepInExFolder, "config");

		public static string DataFolder => Path.Combine(BepInExConfigFolder, "Configgy");

		public static string LegacyDataFolder => Path.Combine(ExecutionPath, "Configs");

		public static void CheckFolders()
		{
			if (!Directory.Exists(DataFolder))
			{
				Directory.CreateDirectory(DataFolder);
			}
		}
	}
	[Serializable]
	public class SerializedConfiggable
	{
		[JsonProperty]
		private string value;

		[JsonIgnore]
		private object obj;

		[JsonIgnore]
		private Type type;

		[JsonProperty]
		public string key { get; }

		public SerializedConfiggable(string key, object value)
		{
			this.key = key;
			SetValue(value);
		}

		[JsonConstructor]
		protected SerializedConfiggable(string key, string jsonValue)
		{
			this.key = key;
			value = jsonValue;
		}

		public string GetSerialized()
		{
			return value;
		}

		public T GetValue<T>()
		{
			return JsonConvert.DeserializeObject<T>(value);
		}

		public void SetValue(object value)
		{
			obj = value;
			type = value.GetType();
			this.value = JsonConvert.SerializeObject(value, type, (Formatting)1, (JsonSerializerSettings)null);
		}

		public bool IsValid()
		{
			if (string.IsNullOrEmpty(value))
			{
				return false;
			}
			if (string.IsNullOrEmpty(key))
			{
				return false;
			}
			return true;
		}
	}
	public static class Extensions
	{
		public static Transform[] GetChildren(this Transform tf)
		{
			int childCount = tf.childCount;
			Transform[] array = (Transform[])(object)new Transform[childCount];
			for (int i = 0; i < childCount; i++)
			{
				array[i] = tf.GetChild(i);
			}
			return array;
		}

		public static T GetDefault<T>(this ConfigEntry<T> entry)
		{
			return (T)((ConfigEntryBase)entry).DefaultValue;
		}

		public static T GetTag<T>(this ConfigEntryBase entry) where T : class
		{
			object result;
			if (entry == null)
			{
				result = null;
			}
			else
			{
				ConfigDescription description = entry.Description;
				if (description == null)
				{
					result = null;
				}
				else
				{
					object[] tags = description.Tags;
					if (tags == null)
					{
						result = null;
					}
					else
					{
						IEnumerable<T> enumerable = tags.OfType<T>();
						result = ((enumerable != null) ? enumerable.FirstOrDefault() : null);
					}
				}
			}
			return (T)result;
		}

		public static bool IsAcceptableValueList(this AcceptableValueBase domain)
		{
			if (domain == null)
			{
				return false;
			}
			if (!((object)domain).GetType().IsGenericType)
			{
				return false;
			}
			if (((object)domain).GetType().GetGenericTypeDefinition() != typeof(AcceptableValueList<>))
			{
				return false;
			}
			return true;
		}
	}
	internal static class LegacyConfigPorter
	{
		public static void PortLegacyConfig(string guid)
		{
		}
	}
	public static class Pauser
	{
		private static GameState configState = new GameState("configgyPause");

		private static List<GameObject> pauserObjects = new List<GameObject>();

		private const string pauseKey = "ConfiggyPauser";

		private static BehaviourRelay watcher;

		public static bool Paused => GameStateManager.Instance.IsStateActive("ConfiggyPauser");

		public static void Pause(GameObject origin)
		{
			pauserObjects = pauserObjects.Where((GameObject x) => (Object)(object)x != (Object)null && x.activeInHierarchy).Distinct().ToList();
			if (!pauserObjects.Contains(origin))
			{
				pauserObjects.Add(origin);
			}
			CheckWatcher();
			SetPaused(paused: true);
		}

		public static void Pause(params GameObject[] origins)
		{
			pauserObjects = pauserObjects.Where((GameObject x) => (Object)(object)x != (Object)null && x.activeInHierarchy).Distinct().ToList();
			for (int i = 0; i < origins.Length; i++)
			{
				if (!pauserObjects.Contains(origins[i]))
				{
					pauserObjects.Add(origins[i]);
				}
			}
			CheckWatcher();
			SetPaused(paused: true);
		}

		private static void CheckWatcher()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)watcher == (Object)null)
			{
				watcher = new GameObject("ConfiggyPauserWatcher").AddComponent<BehaviourRelay>();
				((Object)watcher).hideFlags = (HideFlags)61;
				Object.DontDestroyOnLoad((Object)(object)((Component)watcher).gameObject);
				((MonoBehaviour)watcher).StartCoroutine(PauseWatcher());
			}
		}

		private static void SetPaused(bool paused)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			if (paused != Paused)
			{
				configState = new GameState("ConfiggyPauser");
				configState.cursorLock = (LockMode)2;
				configState.playerInputLock = (LockMode)1;
				configState.cameraInputLock = (LockMode)1;
				configState.priority = 20;
				Time.timeScale = (paused ? 0f : 1f);
				MonoSingleton<OptionsManager>.Instance.paused = paused;
				((Behaviour)MonoSingleton<NewMovement>.Instance).enabled = !paused;
				((Behaviour)MonoSingleton<CameraController>.Instance).enabled = !paused;
				MonoSingleton<GunControl>.Instance.activated = !paused;
				if (paused)
				{
					GameStateManager.Instance.RegisterState(configState);
				}
				else
				{
					GameStateManager.Instance.PopState("ConfiggyPauser");
				}
			}
		}

		private static IEnumerator PauseWatcher()
		{
			while (true)
			{
				if (Paused && !RemainPaused())
				{
					SetPaused(paused: false);
				}
				yield return null;
			}
		}

		private static bool RemainPaused()
		{
			for (int i = 0; i < pauserObjects.Count; i++)
			{
				if (!((Object)(object)pauserObjects[i] == (Object)null) && pauserObjects[i].activeInHierarchy)
				{
					return true;
				}
			}
			return false;
		}

		public static void Unpause(GameObject origin = null)
		{
			if ((Object)(object)origin != (Object)null && pauserObjects.Contains(origin))
			{
				pauserObjects.Remove(origin);
			}
			pauserObjects = pauserObjects.Where((GameObject x) => (Object)(object)x != (Object)null && x.activeInHierarchy).ToList();
			if (pauserObjects.Count <= 0)
			{
				SetPaused(paused: false);
			}
		}
	}
	[BepInPlugin("Hydraxous.ULTRAKILL.Configgy", "Configgy", "1.0.4")]
	[BepInProcess("ULTRAKILL.exe")]
	public class Plugin : BaseUnityPlugin
	{
		private Harmony harmony;

		private ConfigBuilder configgyConfig;

		public static bool UsingLatest = true;

		[Configgable("", null, 0, null)]
		private static ConfiggyPersistent<bool> savedBoolean = new ConfiggyPersistent<bool>(defaultValue: true);

		public static string LatestVersion { get; private set; } = "1.0.4";


		private void Awake()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			PluginAssets.Initialize();
			harmony = new Harmony("Hydraxous.ULTRAKILL.Configgy.harmony");
			harmony.PatchAll();
			Paths.CheckFolders();
			configgyConfig = new ConfigBuilder("Hydraxous.ULTRAKILL.Configgy", "Configgy");
			configgyConfig.BuildAll();
			VersionCheck.CheckVersion("https://api.github.com/repos/Hydraxous/Configgy/tags", "1.0.4", delegate(bool r, string latest)
			{
				UsingLatest = r;
				if (!UsingLatest)
				{
					LatestVersion = latest;
					Debug.LogWarning((object)("New version of Configgy available. Current:(1.0.4) Latest: (" + LatestVersion + ")"));
				}
			});
			SceneManager.sceneLoaded += SceneManager_sceneLoaded;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin Configgy is loaded!");
		}

		private void Update()
		{
			if (Input.GetKeyDown((KeyCode)107))
			{
				savedBoolean.SetValue(!savedBoolean.GetValue());
				Debug.Log((object)savedBoolean.Value);
			}
		}

		private void SceneManager_sceneLoaded(Scene _, LoadSceneMode __)
		{
			if (!(SceneHelper.CurrentScene != "Main Menu"))
			{
				BepinAutoGenerator.Generate();
			}
		}
	}
	public class ConfigButton : IConfigElement
	{
		public Action OnPress;

		private string label;

		private Button instancedButton;

		private Text buttonText;

		private ConfiggableAttribute descriptor;

		public Button GetButton()
		{
			return instancedButton;
		}

		public Text GetButtonLabel()
		{
			return buttonText;
		}

		public ConfigButton(Action onPress, string label = null)
		{
			OnPress = onPress;
			this.label = label;
		}

		public void BindDescriptor(ConfiggableAttribute descriptor)
		{
			this.descriptor = descriptor;
		}

		public ConfiggableAttribute GetDescriptor()
		{
			return descriptor;
		}

		public string GetLabel()
		{
			if (!string.IsNullOrEmpty(label))
			{
				return label;
			}
			if (descriptor != null)
			{
				return descriptor.DisplayName;
			}
			return OnPress.Method.Name;
		}

		private void OnButtonPressed()
		{
			OnPress?.Invoke();
		}

		public void SetLabel(string label)
		{
			this.label = label;
			if ((Object)(object)buttonText != (Object)null)
			{
				buttonText.text = GetLabel();
			}
		}

		public void BuildElement(RectTransform rect)
		{
			DynUI.Frame(rect, delegate(Frame panel)
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				panel.RectTransform.sizeDelta = new Vector2(panel.RectTransform.sizeDelta.x, 55f);
				DynUI.Button(panel.RectTransform, delegate(Button b)
				{
					//IL_003e: Unknown result type (might be due to invalid IL or missing references)
					//IL_0048: Expected O, but got Unknown
					instancedButton = b;
					(buttonText = ((Component)b).GetComponentInChildren<Text>()).text = GetLabel();
					RectTransform component = ((Component)b).GetComponent<RectTransform>();
					DynUI.Layout.FillParent(component);
					((UnityEvent)b.onClick).AddListener(new UnityAction(OnButtonPressed));
				});
			});
		}

		public void OnMenuOpen()
		{
		}

		public void OnMenuClose()
		{
		}

		public void BindConfig(ConfigBuilder configBuilder)
		{
		}
	}
	public class ConfigCustomElement : IConfigElement
	{
		private Action<ConfiggableAttribute, RectTransform> onBuild;

		private ConfiggableAttribute configgable;

		protected ConfigBuilder config;

		public Action OnMenuClosed;

		public Action OnMenuOpened;

		public ConfigCustomElement(Action<ConfiggableAttribute, RectTransform> onBuild)
		{
			this.onBuild = onBuild;
		}

		public void BindDescriptor(ConfiggableAttribute configgable)
		{
			this.configgable = configgable;
		}

		public void BuildElement(RectTransform rect)
		{
			onBuild?.Invoke(configgable, rect);
		}

		public ConfiggableAttribute GetDescriptor()
		{
			return configgable;
		}

		public void OnMenuOpen()
		{
			OnMenuOpened?.Invoke();
		}

		public void OnMenuClose()
		{
			OnMenuClosed?.Invoke();
		}

		public void BindConfig(ConfigBuilder configBuilder)
		{
			config = configBuilder;
		}
	}
	public class ConfigDropdown<T> : ConfigValueElement<T>
	{
		protected int defaultIndex;

		protected int? currentIndex;

		protected Dropdown instancedDropdown;

		public string[] Names { get; private set; }

		public T[] Values { get; private set; }

		public ConfigDropdown(T[] values, string[] names = null, int defaultIndex = 0)
			: base(values[defaultIndex])
		{
			Values = values;
			Names = CreateNames(values, names);
			this.defaultIndex = defaultIndex;
			OnValueChanged = (Action<T>)Delegate.Combine(OnValueChanged, (Action<T>)delegate
			{
				RefreshElementValue();
			});
			RefreshElementValue();
		}

		public ConfigDropdown(T[] values, T defaultValue, string[] names = null)
			: this(values, names, Mathf.Max(0, Array.FindIndex(values, (T v) => defaultValue.Equals(v))))
		{
		}

		public static ConfigDropdown<T> ForEnum(T defaultValue)
		{
			T[] values = Enum.GetValues(typeof(T)).Cast<T>().ToArray();
			string[] names = Enum.GetNames(typeof(T));
			return new ConfigDropdown<T>(values, defaultValue, names);
		}

		private string[] CreateNames(T[] values, string[] providedNames)
		{
			if (providedNames == null)
			{
				return values.Select((T x) => x.ToString()).ToArray();
			}
			string[] array = new string[values.Length];
			for (int i = 0; i < values.Length; i++)
			{
				array[i] = ((i < providedNames.Length) ? providedNames[i] : values[i].ToString());
			}
			return array;
		}

		public void SetOptions(T[] values, string[] names = null, int newIndex = 0, int defaultIndex = 0)
		{
			int num = values.Length;
			if (defaultIndex >= num || defaultIndex < 0)
			{
				throw new IndexOutOfRangeException("Default index is out of bounds with provided values.");
			}
			if (newIndex >= num || newIndex < 0)
			{
				throw new IndexOutOfRangeException("Default index is out of bounds with provided values.");
			}
			Values = values;
			Names = CreateNames(values, names);
			this.defaultIndex = defaultIndex;
			SetIndex(newIndex);
		}

		protected override void LoadValueCore()
		{
			firstLoadDone = true;
			if (config.TryGetValueAtAddress<int>(descriptor.SerializationAddress, out var indexCore))
			{
				try
				{
					SetIndexCore(indexCore);
					return;
				}
				catch (Exception ex)
				{
					Debug.LogException(ex);
				}
			}
			ResetValue();
			SaveValue();
		}

		protected override void SaveValueCore()
		{
			object obj = currentIndex;
			config.SetValueAtAddress(descriptor.SerializationAddress, obj);
			config.SaveDeferred();
			base.IsDirty = false;
		}

		protected override void ResetValueCore()
		{
			SetIndexCore(defaultIndex);
		}

		protected override T GetValueCore()
		{
			return Values[GetCurrentIndex()];
		}

		public string GetSelectedIndexName()
		{
			return Names[GetCurrentIndex()];
		}

		public int GetCurrentIndex()
		{
			return GetCurrentIndexCore();
		}

		protected virtual int GetCurrentIndexCore()
		{
			if (!currentIndex.HasValue)
			{
				LoadValue();
			}
			return currentIndex.Value;
		}

		protected void SetDropdown(Dropdown dropdown)
		{
			((UnityEvent<int>)(object)dropdown.onValueChanged).AddListener((UnityAction<int>)delegate(int v)
			{
				SetValueFromDropdown(dropdown, v);
			});
			instancedDropdown = dropdown;
			RefreshElementValue();
		}

		protected void SetValueFromDropdown(Dropdown source, int newValue)
		{
			if (!((Object)(object)source != (Object)(object)instancedDropdown))
			{
				SetIndex(newValue);
			}
		}

		protected void RefreshValue()
		{
			SetValue(Values[GetCurrentIndex()]);
		}

		protected override void SetValueCore(T value)
		{
			if (!Values.Contains(value))
			{
				throw new KeyNotFoundException("Unable to set Dropdown's value directly. It is not contained within the values. Use SetValuesAndNames and SetIndex.");
			}
			base.SetValueCore(value);
		}

		public void SetIndex(int index)
		{
			if (index >= Values.Length || index < 0)
			{
				throw new IndexOutOfRangeException("Index is out of range of Dropdown's values.");
			}
			SetIndexCore(index);
		}

		protected virtual void SetIndexCore(int index)
		{
			currentIndex = index;
			RefreshValue();
		}

		protected override void BuildElementCore(RectTransform rect)
		{
			DynUI.ConfigUI.CreateElementSlot(rect, this, delegate(RectTransform r)
			{
				DynUI.Dropdown(r, SetDropdown);
			});
		}

		protected override void RefreshElementValueCore()
		{
			if (!((Object)(object)instancedDropdown == (Object)null))
			{
				instancedDropdown.ClearOptions();
				instancedDropdown.options = ((IEnumerable<string>)Names).Select((Func<string, OptionData>)((string x) => new OptionData(x))).ToList();
				instancedDropdown.SetValueWithoutNotify(GetCurrentIndex());
				instancedDropdown.RefreshShownValue();
			}
		}
	}
	public class ConfigInputField<T> : ConfigValueElement<T>
	{
		protected Func<T, bool> inputValidator;

		protected Func<string, (bool, T)> valueConverter;

		public Func<T, string> toStringOverride;

		protected InputField instancedField;

		public ConfigInputField(T defaultValue, Func<T, bool> inputValidator = null, Func<string, (bool, T)> typeConverter = null)
			: base(defaultValue)
		{
			valueConverter = typeConverter ?? new Func<string, (bool, T)>(ValidateInputSyntax);
			this.inputValidator = inputValidator ?? ((Func<T, bool>)((T v) => true));
			toStringOverride = null;
			OnValueChanged = (Action<T>)Delegate.Combine(OnValueChanged, (Action<T>)delegate
			{
				RefreshElementValue();
			});
			RefreshElementValue();
		}

		private (bool, T) ValidateInputSyntax(string inputValue)
		{
			(bool, T) result = default((bool, T));
			result.Item1 = false;
			result.Item2 = default(T);
			try
			{
				TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
				object obj = converter.ConvertFromString(inputValue);
				result.Item2 = (T)obj;
				result.Item1 = result.Item2 != null;
			}
			catch (Exception ex)
			{
				Debug.LogException(ex);
			}
			return result;
		}

		private void SetValueFromString(InputField source, string input)
		{
			if ((Object)(object)source != (Object)(object)instancedField)
			{
				return;
			}
			(bool, T) tuple;
			try
			{
				tuple = valueConverter(input);
				if (!tuple.Item1)
				{
					Debug.LogError((object)"Syntax for field invalid! Conversion failed!");
					RefreshElementValue();
					return;
				}
			}
			catch (Exception ex)
			{
				Debug.LogException(ex);
				RefreshElementValue();
				return;
			}
			if (!inputValidator(tuple.Item2))
			{
				Debug.LogError((object)"Value validation failure. Rejected.");
				RefreshElementValue();
			}
			else
			{
				SetValue(tuple.Item2);
			}
		}

		protected void SetInputField(InputField inputField)
		{
			((UnityEvent<string>)(object)inputField.onEndEdit).AddListener((UnityAction<string>)delegate(string s)
			{
				SetValueFromString(inputField, s);
			});
			instancedField = inputField;
			RefreshElementValue();
		}

		protected override void RefreshElementValueCore()
		{
			if (!((Object)(object)instancedField == (Object)null))
			{
				T arg = GetValue();
				string text = null;
				text = ((toStringOverride == null) ? arg.ToString() : toStringOverride(arg));
				instancedField.SetTextWithoutNotify(text);
			}
		}

		protected override void BuildElementCore(RectTransform rect)
		{
			DynUI.ConfigUI.CreateElementSlot(rect, this, delegate(RectTransform r)
			{
				DynUI.InputField(r, SetInputField);
			});
		}
	}
	public class ConfigKeybind : ConfigValueElement<KeyCode>
	{
		private Text keybindText;

		private Button keybindButton;

		private ConfigurationPage page;

		public bool IsBeingRebound { get; private set; }

		public event Action OnRebindStart;

		public event Action OnRebindEnd;

		public ConfigKeybind(KeyCode keyCode)
			: base(keyCode)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			OnValueChanged = (Action<KeyCode>)Delegate.Combine(OnValueChanged, (Action<KeyCode>)delegate
			{
				RefreshElementValue();
			});
			RefreshElementValue();
		}

		protected override void BuildElementCore(RectTransform rect)
		{
			IsBeingRebound = false;
			page = ((Component)rect).GetComponentInParent<ConfigurationPage>();
			DynUI.ConfigUI.CreateElementSlot(rect, this, delegate(RectTransform r)
			{
				DynUI.Button(r, delegate(Button b)
				{
					SetKeybindButton(b);
				});
			});
		}

		private void SetKeybindButton(Button button)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			keybindButton = button;
			keybindText = ((Component)button).GetComponentInChildren<Text>();
			((UnityEvent)keybindButton.onClick).AddListener(new UnityAction(StartRebinding));
		}

		private void StartRebinding()
		{
			if ((Object)(object)page == (Object)null)
			{
				page = ((Component)keybindButton).GetComponentInParent<ConfigurationPage>();
			}
			if ((Object)(object)page == (Object)null)
			{
				Debug.LogError((object)"Page could not be found?");
				return;
			}
			keybindText.text = "<color=orange>???</color>";
			((Selectable)keybindButton).interactable = false;
			IsBeingRebound = true;
			page.preventClosing = true;
			((MonoBehaviour)page).StartCoroutine(RebindProcess());
			this.OnRebindStart?.Invoke();
		}

		public bool IsPressed()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Invalid comparison between Unknown and I4
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (IsBeingRebound)
			{
				return false;
			}
			if ((int)base.Value == 0)
			{
				return false;
			}
			return Input.GetKey(base.Value);
		}

		public bool WasPeformed()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Invalid comparison between Unknown and I4
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (IsBeingRebound)
			{
				return false;
			}
			if ((int)base.Value == 0)
			{
				return false;
			}
			return Input.GetKeyDown(base.Value);
		}

		public bool WasReleased()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Invalid comparison between Unknown and I4
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (IsBeingRebound)
			{
				return false;
			}
			if ((int)base.Value == 0)
			{
				return false;
			}
			return Input.GetKeyUp(base.Value);
		}

		protected override void RefreshElementValueCore()
		{
			//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)
			if (!((Object)(object)keybindText == (Object)null))
			{
				Text obj = keybindText;
				KeyCode val = GetValue();
				obj.text = ((object)(KeyCode)(ref val)).ToString();
			}
		}

		private void FinishRebind(KeyCode keycode)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			((Selectable)keybindButton).interactable = true;
			page.preventClosing = false;
			IsBeingRebound = false;
			SetValue(keycode);
			this.OnRebindEnd?.Invoke();
		}

		private IEnumerator RebindProcess()
		{
			float timer = 10f;
			IsBeingRebound = true;
			KeyCode currentKeyCode = base.Value;
			int counter = 0;
			yield return (object)new WaitForSecondsRealtime(0.18f);
			while (IsBeingRebound && timer > 0f)
			{
				yield return null;
				timer -= Time.deltaTime;
				Event current = Event.current;
				if ((int)current.type != 4 && (int)current.type != 5)
				{
					continue;
				}
				KeyCode keyCode = current.keyCode;
				KeyCode val = keyCode;
				KeyCode val2 = val;
				if ((int)val2 != 0)
				{
					if ((int)val2 == 27)
					{
						FinishRebind((KeyCode)0);
					}
					else
					{
						FinishRebind(current.keyCode);
					}
					yield break;
				}
				counter++;
			}
			FinishRebind(currentKeyCode);
		}
	}
	public class ConfigLabel : IConfigElement
	{
		private ConfiggableAttribute descriptor;

		private Text label;

		private string labelText;

		private float height;

		public ConfigLabel(string label, float height = 55f)
		{
			labelText = label;
			this.height = 55f;
		}

		public void SetHeight(float height)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			this.height = height;
			if (Object.op_Implicit((Object)(object)label))
			{
				((Component)label).GetComponent<RectTransform>().sizeDelta = new Vector2(0f, height);
			}
		}

		public Text GetLabel()
		{
			return label;
		}

		public string GetCurrentText()
		{
			return labelText;
		}

		public void SetText(string label)
		{
			labelText = label;
			if (Object.op_Implicit((Object)(object)this.label))
			{
				this.label.text = label;
			}
		}

		void IConfigElement.BindConfig(ConfigBuilder configBuilder)
		{
		}

		void IConfigElement.BindDescriptor(ConfiggableAttribute configgable)
		{
			descriptor = configgable;
		}

		void IConfigElement.BuildElement(RectTransform rect)
		{
			DynUI.Label(rect, delegate(Text t)
			{
				//IL_0039: Unknown result type (might be due to invalid IL or missing references)
				label = t;
				label.text = labelText;
				RectTransform component = ((Component)label).GetComponent<RectTransform>();
				DynUI.Layout.CenterAnchor(component);
				component.sizeDelta = new Vector2(0f, height);
			});
		}

		ConfiggableAttribute IConfigElement.GetDescriptor()
		{
			return descriptor;
		}

		void IConfigElement.OnMenuClose()
		{
		}

		void IConfigElement.OnMenuOpen()
		{
		}
	}
	public abstract class ConfigSlider<T> : ConfigValueElement<T>
	{
		protected Slider instancedSlider;

		protected Text outputText;

		public T Min { get; }

		public T Max { get; }

		public ConfigSlider(T defaultValue, T min, T max)
			: base(defaultValue)
		{
			Min = min;
			Max = max;
		}

		protected virtual void SetValueFromSlider(Slider origin, float sliderValue)
		{
			if (!((Object)(object)origin != (Object)(object)instancedSlider))
			{
				SetValueFromSlider(sliderValue);
			}
		}

		protected abstract void ConfigureSliderRange(Slider slider);

		protected abstract void SetValueFromSlider(float value);

		protected void SetSlider(Slider slider)
		{
			((UnityEvent<float>)(object)slider.onValueChanged).AddListener((UnityAction<float>)delegate(float v)
			{
				SetValueFromSlider(slider, v);
			});
			ConfigureSliderRange(slider);
			instancedSlider = slider;
			RefreshElementValue();
		}

		protected override void RefreshElementValueCore()
		{
			if (!((Object)(object)instancedSlider == (Object)null) && (Object)(object)outputText != (Object)null)
			{
				outputText.text = ToString();
			}
		}

		protected override void BuildElementCore(RectTransform rect)
		{
			DynUI.ConfigUI.CreateElementSlot(rect, this, delegate(RectTransform r)
			{
				DynUI.Label(r, delegate(Text t)
				{
					outputText = t;
				});
				DynUI.Slider(r, SetSlider);
			});
		}
	}
	public class ConfigToggle : ConfigValueElement<bool>
	{
		protected Toggle instancedToggle;

		public ConfigToggle(bool defaultValue)
			: base(defaultValue)
		{
			OnValueChanged = (Action<bool>)Delegate.Combine(OnValueChanged, (Action<bool>)delegate
			{
				RefreshElementValue();
			});
		}

		protected override void RefreshElementValueCore()
		{
			if (!((Object)(object)instancedToggle == (Object)null))
			{
				instancedToggle.SetIsOnWithoutNotify(GetValue());
			}
		}

		protected void SetToggle(Toggle toggle)
		{
			((UnityEvent<bool>)(object)toggle.onValueChanged).AddListener((UnityAction<bool>)delegate(bool v)
			{
				SetValueFromToggle(toggle, v);
			});
			instancedToggle = toggle;
			RefreshElementValue();
		}

		protected override void LoadValueCore()
		{
			base.LoadValueCore();
			RefreshElementValue();
		}

		protected void SetValueFromToggle(Toggle source, bool newValue)
		{
			if (!((Object)(object)source != (Object)(object)instancedToggle))
			{
				SetValue(newValue);
			}
		}

		protected override void BuildElementCore(RectTransform rect)
		{
			DynUI.ConfigUI.CreateElementSlot(rect, this, delegate(RectTransform r)
			{
				DynUI.Toggle(r, SetToggle);
			});
		}
	}
	public abstract class ConfigValueElement : IConfigElement
	{
		protected ConfiggableAttribute descriptor;

		protected ConfigBuilder config;

		protected bool firstLoadDone = false;

		private bool initialized => descriptor != null;

		public bool IsDirty { get; protected set; }

		public abstract Type ConfigValueType { get; }

		protected abstract void BuildElementCore(RectTransform rect);

		internal abstract void BindField(FieldInfo field);

		protected abstract void LoadValueCore();

		protected abstract void SaveValueCore();

		protected abstract void ResetValueCore();

		protected abstract void RefreshElementValueCore();

		public void LoadValue()
		{
			if (initialized)
			{
				LoadValueCore();
				firstLoadDone = true;
			}
		}

		public void SaveValue()
		{
			SaveValueCore();
		}

		public void ResetValue()
		{
			ResetValueCore();
		}

		public void RefreshElementValue()
		{
			RefreshElementValueCore();
		}

		public void BuildElement(RectTransform rect)
		{
			if (initialized)
			{
				BuildElementCore(rect);
			}
		}

		public void OnMenuOpen()
		{
			RefreshElementValue();
		}

		public void OnMenuClose()
		{
			if (IsDirty)
			{
				SaveValue();
			}
		}

		void IConfigElement.BindDescriptor(ConfiggableAttribute configgable)
		{
			descriptor = configgable;
		}

		ConfiggableAttribute IConfigElement.GetDescriptor()
		{
			return descriptor;
		}

		void IConfigElement.BindConfig(ConfigBuilder config)
		{
			this.config = config;
		}

		public static ConfigValueElement<T> Create<T>(T defaultValue)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			if (1 == 0)
			{
			}
			ConfigValueElement configValueElement;
			if (defaultValue is bool)
			{
				object obj = defaultValue;
				bool defaultValue2 = (bool)((obj is bool) ? obj : null);
				configValueElement = new ConfigToggle(defaultValue2);
			}
			else if (defaultValue is Vector2)
			{
				object obj2 = defaultValue;
				Vector2 defaultValue3 = (Vector2)((obj2 is Vector2) ? obj2 : null);
				configValueElement = new ConfigVector2(defaultValue3);
			}
			else if (defaultValue is Vector3)
			{
				object obj3 = defaultValue;
				Vector3 defaultValue4 = (Vector3)((obj3 is Vector3) ? obj3 : null);
				configValueElement = new ConfigVector3(defaultValue4);
			}
			else if (defaultValue is Quaternion)
			{
				object obj4 = defaultValue;
				Quaternion defaultValue5 = (Quaternion)((obj4 is Quaternion) ? obj4 : null);
				configValueElement = new ConfigQuaternion(defaultValue5);
			}
			else if (defaultValue is Color)
			{
				object obj5 = defaultValue;
				Color defaultValue6 = (Color)((obj5 is Color) ? obj5 : null);
				configValueElement = new ConfigColor(defaultValue6);
			}
			else if (!(defaultValue is KeyCode))
			{
				configValueElement = ((defaultValue is Enum) ? ((ConfigValueElement<T>)ConfigDropdown<T>.ForEnum(defaultValue)) : ((ConfigValueElement<T>)((!(defaultValue is sbyte) && !(defaultValue is short) && !(defaultValue is int) && !(defaultValue is long) && !(defaultValue is byte) && !(defaultValue is ushort) && !(defaultValue is uint) && !(defaultValue is ulong) && !(defaultValue is float) && !(defaultValue is double) && !(defaultValue is char) && !(defaultValue is string)) ? null : new ConfigInputField<T>(defaultValue))));
			}
			else
			{
				object obj6 = defaultValue;
				KeyCode keyCode = (KeyCode)((obj6 is KeyCode) ? obj6 : null);
				configValueElement = new ConfigKeybind(keyCode);
			}
			if (1 == 0)
			{
			}
			ConfigValueElement configValueElement2 = configValueElement;
			if (configValueElement2 == null)
			{
				return null;
			}
			return (ConfigValueElement<T>)configValueElement2;
		}
	}
	public abstract class ConfigValueElement<T> : ConfigValueElement
	{
		protected readonly T defaultValue;

		protected internal T? value;

		public Action<T> OnValueChanged;

		public sealed override Type ConfigValueType => typeof(T);

		public virtual T DefaultValue => defaultValue;

		public T Value => GetValue();

		public ConfigValueElement(T defaultValue)
		{
			this.defaultValue = defaultValue;
		}

		protected override void LoadValueCore()
		{
			firstLoadDone = true;
			if (descriptor == null || config == null)
			{
				return;
			}
			if (config.TryGetValueAtAddress<T>(descriptor.SerializationAddress, out var val))
			{
				try
				{
					SetValue(val);
					return;
				}
				catch (Exception ex)
				{
					Debug.LogException(ex);
				}
			}
			ResetValue();
		}

		protected override void SaveValueCore()
		{
			object obj = GetValue();
			config.SetValueAtAddress(descriptor.SerializationAddress, obj);
			config.SaveDeferred();
			base.IsDirty = false;
		}

		public T GetValue()
		{
			return GetValueCore();
		}

		protected virtual T GetValueCore()
		{
			if (value == null || !firstLoadDone)
			{
				LoadValue();
			}
			return value;
		}

		public void SetValue(T value)
		{
			SetValueCore(value);
			base.IsDirty = true;
		}

		protected virtual void SetValueCore(T value)
		{
			this.value = value;
			OnValueChanged?.Invoke(value);
		}

		protected override void ResetValueCore()
		{
			SetValue(DefaultValue);
		}

		public override string ToString()
		{
			return GetValue().ToString();
		}

		internal sealed override void BindField(FieldInfo field)
		{
			OnValueChanged = (Action<T>)Delegate.Combine(OnValueChanged, (Action<T>)delegate(T v)
			{
				field.SetValue(null, v);
			});
		}
	}
	public class FloatSlider : ConfigSlider<float>
	{
		public FloatSlider(float defaultValue, float min, float max)
			: base(defaultValue, min, max)
		{
		}

		protected override void BuildElementCore(RectTransform rect)
		{
			base.BuildElementCore(rect);
			instancedSlider.wholeNumbers = false;
			OnValueChanged = (Action<float>)Delegate.Combine(OnValueChanged, (Action<float>)delegate
			{
				RefreshElementValue();
			});
			RefreshElementValue();
		}

		protected override void ConfigureSliderRange(Slider slider)
		{
			slider.minValue = base.Min;
			slider.maxValue = base.Max;
		}

		protected override void LoadValueCore()
		{
			base.LoadValueCore();
			RefreshElementValue();
		}

		protected override void SetValueFromSlider(float value)
		{
			SetValue(value);
		}

		protected override void RefreshElementValueCore()
		{
			base.RefreshElementValueCore();
			if (!((Object)(object)instancedSlider == (Object)null))
			{
				instancedSlider.SetValueWithoutNotify(GetValue());
			}
		}
	}
	public class IntegerSlider : ConfigSlider<int>
	{
		public IntegerSlider(int defaultValue, int min, int max)
			: base(defaultValue, min, max)
		{
		}

		protected override void BuildElementCore(RectTransform rect)
		{
			base.BuildElementCore(rect);
			instancedSlider.wholeNumbers = true;
			OnValueChanged = (Action<int>)Delegate.Combine(OnValueChanged, (Action<int>)delegate
			{
				RefreshElementValue();
			});
			RefreshElementValue();
		}

		protected override void ConfigureSliderRange(Slider slider)
		{
			slider.minValue = base.Min;
			slider.maxValue = base.Max;
		}

		protected override void LoadValueCore()
		{
			base.LoadValueCore();
			RefreshElementValue();
		}

		protected override void SetValueFromSlider(float value)
		{
			SetValue((int)value);
		}

		protected override void RefreshElementValueCore()
		{
			base.RefreshElementValueCore();
			if (!((Object)(object)instancedSlider == (Object)null))
			{
				instancedSlider.SetValueWithoutNotify((float)GetValue());
			}
		}
	}
	public class ConfigColor : ConfigValueElement<Color>
	{
		private SerializedColor serializedColor;

		private Slider[] sliders;

		private InputField hexInput;

		private Image colorDisplay;

		public ConfigColor(Color defaultValue)
			: base(defaultValue)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			OnValueChanged = (Action<Color>)Delegate.Combine(OnValueChanged, (Action<Color>)delegate
			{
				RefreshElementValue();
			});
			OnValueChanged = (Action<Color>)Delegate.Combine(OnValueChanged, new Action<Color>(UpdateColorDisplayColor));
			serializedColor = new SerializedColor(defaultValue);
			sliders = (Slider[])(object)new Slider[4];
		}

		protected override void BuildElementCore(RectTransform rect)
		{
			DynUI.ConfigUI.CreateElementSlot(rect, this, delegate(RectTransform r)
			{
				DynUI.InputField(r, SetInputField);
				int j;
				for (j = 0; j < sliders.Length; j++)
				{
					DynUI.Slider(r, delegate(Slider s)
					{
						SetSlider(s, j);
					});
				}
				DynUI.ImageButton(r, delegate(Button b, Image i)
				{
					Object.Destroy((Object)(object)b);
					SetColorDisplay(i);
				});
			});
		}

		private void SetColorDisplay(Image image)
		{
			image.sprite = null;
			colorDisplay = image;
		}

		private void UpdateColorDisplayColor(Color color)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)colorDisplay == (Object)null))
			{
				((Graphic)colorDisplay).color = color;
			}
		}

		protected override void LoadValueCore()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			firstLoadDone = true;
			if (config.TryGetValueAtAddress<SerializedColor>(descriptor.SerializationAddress, out var serializedColor))
			{
				try
				{
					SetValue(serializedColor.ToColor());
					return;
				}
				catch (Exception ex)
				{
					Debug.LogException(ex);
				}
			}
			ResetValue();
		}

		private string ToHex(Color color)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return ColorUtility.ToHtmlStringRGBA(color) ?? "";
		}

		private bool TryParseHex(string hex, out Color color)
		{
			return ColorUtility.TryParseHtmlString(hex, ref color);
		}

		protected override void SaveValueCore()
		{
			object obj = serializedColor;
			config.SetValueAtAddress(descriptor.SerializationAddress, obj);
			config.SaveDeferred();
			base.IsDirty = false;
		}

		private void SetInputField(InputField input)
		{
			if ((Object)(object)input == (Object)null)
			{
				return;
			}
			hexInput = input;
			((UnityEvent<string>)(object)input.onEndEdit).AddListener((UnityAction<string>)delegate(string s)
			{
				//IL_006c: 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)
				//IL_004a: Unknown result type (might be due to invalid IL or missing references)
				if (!s.StartsWith("#"))
				{
					s = "#" + s;
				}
				if (TryParseHex(s, out var color))
				{
					serializedColor = new SerializedColor(color);
					SetValue(color);
				}
				else
				{
					input.SetTextWithoutNotify(ToHex(serializedColor.ToColor()));
				}
			});
		}

		private void SetSlider(Slider slider, int index)
		{
			sliders[index] = slider;
			((UnityEvent<float>)(object)slider.onValueChanged).AddListener((UnityAction<float>)delegate(float v)
			{
				SetValueFromSlider(index, v);
			});
			slider.minValue = 0f;
			slider.maxValue = 1f;
			slider.wholeNumbers = false;
		}

		private void SetValueFromSlider(int index, float value)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			serializedColor[index] = value;
			SetValue(serializedColor.ToColor());
		}

		protected override void SetValueCore(Color value)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			base.value = value;
			serializedColor = new SerializedColor(value);
			OnValueChanged?.Invoke(value);
		}

		protected override void RefreshElementValueCore()
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			if (sliders == null)
			{
				return;
			}
			for (int i = 0; i < sliders.Length; i++)
			{
				if ((Object)(object)sliders[i] == (Object)null)
				{
					return;
				}
				sliders[i].SetValueWithoutNotify(serializedColor[i]);
			}
			hexInput.SetTextWithoutNotify(ToHex(serializedColor.ToColor()));
			UpdateColorDisplayColor(serializedColor.ToColor());
		}
	}
	[Serializable]
	public struct SerializedColor
	{
		public float r;

		public float g;

		public float b;

		public float a;

		public float this[int index]
		{
			get
			{
				return index switch
				{
					0 => r, 
					1 => g, 
					2 => b, 
					3 => a, 
					_ => throw new IndexOutOfRangeException("Index is out of range of SerializedColor's values."), 
				};
			}
			set
			{
				switch (index)
				{
				case 0:
					r = value;
					break;
				case 1:
					g = value;
					break;
				case 2:
					b = value;
					break;
				case 3:
					a = value;
					break;
				default:
					throw new IndexOutOfRangeException("Index is out of range of SerializedColor's values.");
				}
			}
		}

		public SerializedColor(Color color)
		{
			//IL_0002: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			r = color.r;
			g = color.g;
			b = color.b;
			a = color.a;
		}

		public Color ToColor()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			return new Color(r, g, b, a);
		}
	}
	public class ConfigQuaternion : ConfigInputField<Quaternion>
	{
		private float[] serializedQuaternion;

		public ConfigQuaternion(Quaternion defaultValue, Func<Quaternion, bool> inputValidator = null)
			: base(defaultValue, inputValidator, (Func<string, (bool, Quaternion)>)null)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			serializedQuaternion = new float[4] { defaultValue.x, defaultValue.y, defaultValue.z, defaultValue.w };
			valueConverter = delegate(string v)
			{
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_0038: Unknown result type (might be due to invalid IL or missing references)
				//IL_0067: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a9: 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)
				if (v == "0")
				{
					return (true, Quaternion.identity);
				}
				if (v.ToLower() == "identity")
				{
					return (true, Quaternion.identity);
				}
				string[] array = v.Split(new char[1] { ',' });
				if (array.Length != 3)
				{
					return (false, Quaternion.identity);
				}
				float[] array2 = array.Select((string x) => float.Parse(x)).ToArray();
				return (true, Quaternion.Euler(new Vector3(array2[0], array2[1], array2[2])));
			};
			toStringOverride = (Quaternion v) => $"{((Quaternion)(ref v)).eulerAngles.x},{((Quaternion)(ref v)).eulerAngles.y},{((Quaternion)(ref v)).eulerAngles.z}";
		}

		protected override void LoadValueCore()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			firstLoadDone = true;
			if (config.TryGetValueAtAddress<float[]>(descriptor.SerializationAddress, out var array))
			{
				try
				{
					SetValue(new Quaternion(array[0], array[1], array[2], array[3]));
					return;
				}
				catch (Exception ex)
				{
					Debug.LogException(ex);
				}
			}
			ResetValue();
		}

		protected override void SetValueCore(Quaternion value)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			base.value = value;
			if (serializedQuaternion == null)
			{
				serializedQuaternion = new float[2];
			}
			serializedQuaternion[0] = value.x;
			serializedQuaternion[1] = value.y;
			serializedQuaternion[2] = value.z;
			serializedQuaternion[3] = value.w;
			OnValueChanged?.Invoke(value);
		}

		protected override void SaveValueCore()
		{
			if (serializedQuaternion == null)
			{
				serializedQuaternion = new float[2];
			}
			object obj = serializedQuaternion;
			config.SetValueAtAddress(descriptor.SerializationAddress, obj);
			config.SaveDeferred();
			base.IsDirty = false;
		}
	}
	public class ConfigVector2 : ConfigInputField<Vector2>
	{
		private float[] serializedVector2;

		public ConfigVector2(Vector2 defaultValue, Func<Vector2, bool> inputValidator = null)
			: base(defaultValue, inputValidator, (Func<string, (bool, Vector2)>)null)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			serializedVector2 = new float[2] { defaultValue.x, defaultValue.y };
			valueConverter = delegate(string v)
			{
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: Unknown result type (might be due to invalid IL or missing references)
				//IL_007f: Unknown result type (might be due to invalid IL or missing references)
				if (v == "0")
				{
					return (true, Vector2.zero);
				}
				string[] array = v.Split(new char[1] { ',' });
				if (array.Length != 2)
				{
					return (false, Vector2.zero);
				}
				float[] array2 = array.Select((string x) => float.Parse(x)).ToArray();
				return (true, new Vector2(array2[0], array2[1]));
			};
			toStringOverride = (Vector2 v) => $"{v.x},{v.y}";
		}

		protected override void LoadValueCore()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			firstLoadDone = true;
			if (config.TryGetValueAtAddress<float[]>(descriptor.SerializationAddress, out var array))
			{
				try
				{
					SetValue(new Vector2(array[0], array[1]));
					return;
				}
				catch (Exception ex)
				{
					Debug.LogException(ex);
				}
			}
			ResetValue();
		}

		protected override void SetValueCore(Vector2 value)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			base.value = value;
			if (serializedVector2 == null)
			{
				serializedVector2 = new float[2];
			}
			serializedVector2[0] = value.x;
			serializedVector2[1] = value.y;
			OnValueChanged?.Invoke(value);
		}

		protected override void SaveValueCore()
		{
			if (serializedVector2 == null)
			{
				serializedVector2 = new float[2];
			}
			object obj = serializedVector2;
			config.SetValueAtAddress(descriptor.SerializationAddress, obj);
			config.SaveDeferred();
			base.IsDirty = false;
		}
	}
	public class ConfigVector3 : ConfigInputField<Vector3>
	{
		private float[] serializedVector3;

		public ConfigVector3(Vector3 defaultValue, Func<Vector3, bool> inputValidator = null)
			: base(defaultValue, inputValidator, (Func<string, (bool, Vector3)>)null)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			serializedVector3 = new float[3] { defaultValue.x, defaultValue.y, defaultValue.z };
			valueConverter = delegate(string v)
			{
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: Unknown result type (might be due to invalid IL or missing references)
				//IL_0082: Unknown result type (might be due to invalid IL or missing references)
				if (v == "0")
				{
					return (true, Vector3.zero);
				}
				string[] array = v.Split(new char[1] { ',' });
				if (array.Length != 3)
				{
					return (false, Vector3.zero);
				}
				float[] array2 = array.Select((string x) => float.Parse(x)).ToArray();
				return (true, new Vector3(array2[0], array2[1], array2[2]));
			};
			toStringOverride = (Vector3 v) => $"{v.x},{v.y},{v.z}";
		}

		protected override void LoadValueCore()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			firstLoadDone = true;
			if (config.TryGetValueAtAddress<float[]>(descriptor.SerializationAddress, out var array))
			{
				try
				{
					SetValue(new Vector3(array[0], array[1], array[1]));
					return;
				}
				catch (Exception ex)
				{
					Debug.LogException(ex);
				}
			}
			ResetValue();
		}

		protected override void SetValueCore(Vector3 value)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: 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)
			base.value = value;
			if (serializedVector3 == null)
			{
				serializedVector3 = new float[3];
			}
			serializedVector3[0] = value.x;
			serializedVector3[1] = value.y;
			serializedVector3[2] = value.z;
			OnValueChanged?.Invoke(value);
		}

		protected override void SaveValueCore()
		{
			if (serializedVector3 == null)
			{
				serializedVector3 = new float[3];
			}
			object obj = serializedVector3;
			config.SetValueAtAddress(descriptor.SerializationAddress, obj);
			config.SaveDeferred();
			base.IsDirty = false;
		}
	}
	public static class ExampleConfig
	{
	}
	public static class ModalDialogue
	{
		public static void ShowSimple(string title, string message, Action<bool> onComplete, string confirm = "Yes", string deny = "No")
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ModalDialogueManager.Instance == (Object)null)
			{
				Debug.LogError((object)"No ModalDialogueManager found in scene.");
				return;
			}
			ModalDialogueEvent modalDialogueEvent = new ModalDialogueEvent();
			modalDialogueEvent.Title = title;
			modalDialogueEvent.Message = message;
			modalDialogueEvent.Options = new DialogueBoxOption[2]
			{
				new DialogueBoxOption
				{
					Name = confirm,
					Color = Color.white,
					OnClick = delegate
					{
						onComplete?.Invoke(obj: true);
					}
				},
				new DialogueBoxOption
				{
					Name = deny,
					Color = Color.white,
					OnClick = delegate
					{
						onComplete?.Invoke(obj: false);
					}
				}
			};
			ModalDialogueManager.Instance.RaiseDialogue(modalDialogueEvent);
		}

		public static void ShowDialogue(ModalDialogueEvent modalDialogueEvent)
		{
			if ((Object)(object)ModalDialogueManager.Instance == (Object)null)
			{
				Debug.LogError((object)"No ModalDialogueManager found in scene.");
			}
			else
			{
				ModalDialogueManager.Instance.RaiseDialogue(modalDialogueEvent);
			}
		}

		public static void ShowComplex(string title, string message, params DialogueBoxOption[] options)
		{
			if ((Object)(object)ModalDialogueManager.Instance == (Object)null)
			{
				Debug.LogError((object)"No ModalDialogueManager found in scene.");
				return;
			}
			ModalDialogueManager.Instance.RaiseDialogue(new ModalDialogueEvent
			{
				Title = title,
				Message = message,
				Options = options
			});
		}
	}
	public class ModalDialogueManager : MonoBehaviour
	{
		[SerializeField]
		private GameObject blocker;

		[SerializeField]
		private GameObject dialogueBox;

		[SerializeField]
		private Text titleText;

		[SerializeField]
		private Text messageText;

		[SerializeField]
		private RectTransform buttonContainer;

		private Queue<ModalDialogueEvent> dialogueEvent = new Queue<ModalDialogueEvent>();

		private List<GameObject> spawnedButtons = new List<GameObject>();

		private bool runningCoroutine = false;

		private bool inDialogue = false;

		internal static ModalDialogueManager Instance { get; private set; }

		private void Awake()
		{
			Instance = this;
			blocker.SetActive(false);
			dialogueBox.SetActive(false);
			((MonoBehaviour)this).StartCoroutine(SlowUpdate());
		}

		private IEnumerator SlowUpdate()
		{
			while (true)
			{
				((Component)this).transform.SetAsLastSibling();
				yield return (object)new WaitForSecondsRealtime(2f);
			}
		}

		internal void RaiseDialogue(ModalDialogueEvent modalDialogueEvent)
		{
			if (modalDialogueEvent == null)
			{
				throw new ArgumentNullException("modalDialogueEvent is null!");
			}
			dialogueEvent.Enqueue(modalDialogueEvent);
			if (!runningCoroutine)
			{
				runningCoroutine = true;
				((MonoBehaviour)this).StartCoroutine(DialogueCoroutine());
			}
		}

		private void ShowDialogue(ModalDialogueEvent modalDialogueEvent)
		{
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Expected O, but got Unknown
			inDialogue = true;
			dialogueBox.SetActive(true);
			if (string.IsNullOrEmpty(modalDialogueEvent.Title))
			{
				titleText.text = "";
			}
			else
			{
				titleText.text = "-- " + modalDialogueEvent.Title + " --";
			}
			messageText.text = modalDialogueEvent.Message;
			for (int i = 0; i < modalDialogueEvent.Options.Length; i++)
			{
				DialogueBoxOption option = modalDialogueEvent.Options[i];
				GameObject val = Object.Instantiate<GameObject>(PluginAssets.ButtonPrefab, (Transform)(object)buttonContainer);
				Button component = val.GetComponent<Button>();
				Text componentInChildren = val.GetComponentInChildren<Text>();
				Image val2 = (from x in val.GetComponentsInChildren<Image>()
					where ((Object)x).name == "Border"
					select x).FirstOrDefault();
				spawnedButtons.Add(val);
				((Graphic)componentInChildren).color = option.Color;
				componentInChildren.text = option.Name;
				((Graphic)val2).color = option.Color;
				((UnityEvent)component.onClick).AddListener((UnityAction)delegate
				{
					EndDialogue();
					option.OnClick?.Invoke();
				});
			}
		}

		private void EndDialogue()
		{
			inDialogue = false;
			dialogueBox.SetActive(false);
			for (int i = 0; i < spawnedButtons.Count; i++)
			{
				if (!((Object)(object)spawnedButtons[i] == (Object)null))
				{
					GameObject val = spawnedButtons[i];
					spawnedButtons[i] = null;
					Object.Destroy((Object)(object)val);
				}
			}
			spawnedButtons.Clear();
		}

		private IEnumerator DialogueCoroutine()
		{
			blocker.SetActive(true);
			Pauser.Pause(blocker);
			while (dialogueEvent.Count > 0)
			{
				ModalDialogueEvent dialogue = dialogueEvent.Dequeue();
				ShowDialogue(dialogue);
				while (inDialogue)
				{
					yield return null;
				}
			}
			blocker.SetActive(false);
			runningCoroutine = false;
			Pauser.Unpause();
		}
	}
	public struct DialogueBoxOption
	{
		public string Name;

		public Action OnClick;

		public Color Color;
	}
	public class ModalDialogueEvent
	{
		public string Title;

		public string Message;

		public DialogueBoxOption[] Options;
	}
	public static class VersionCheck
	{
		private static MonoBehaviour _behaviour;

		private static MonoBehaviour behaviour
		{
			get
			{
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)_behaviour == (Object)null)
				{
					_behaviour = (MonoBehaviour)(object)new GameObject("VersionChecker").AddComponent<BehaviourRelay>();
				}
				return _behaviour;
			}
		}

		public static void CheckVersion(string githubURL, string runningVersionName, Action<bool, string> onCheckComplete = null)
		{
			behaviour.StartCoroutine(CheckLatestVersion(githubURL, runningVersionName, onCheckComplete));
		}

		private static IEnumerator CheckLatestVersion(string githubURL, string runningVersionName, Action<bool, string> onCheckComplete = null)
		{
			bool usingLatest = true;
			string latestVersionName = "UNKNOWN";
			UnityWebRequest webRequest = UnityWebRequest.Get(githubURL);
			try
			{
				yield return webRequest.SendWebRequest();
				if (!webRequest.isNetworkError)
				{
					string page = webRequest.downloadHandler.text;
					try
					{
						latestVersionName = JArray.Parse(page)[0].Value<string>((object)"name");
						usingLatest = latestVersionName == runningVersionName;
					}
					catch (Exception ex)
					{
						Exception e = ex;
						usingLatest = true;
						latestVersionName = runningVersionName;
						Debug.LogError((object)$"Error getting version info for {runningVersionName}. {e}");
					}
				}
			}
			finally
			{
				((IDisposable)webRequest)?.Dispose();
			}
			onCheckComplete(usingLatest, latestVersionName);
		}
	}
}
namespace Configgy.UI
{
	public class ConfigurationMenu : MonoBehaviour
	{
		[SerializeField]
		private RectTransform contentbody;

		private ConfigurationPage rootPage;

		private Dictionary<string, ConfigurationPage> pageManifest = new Dictionary<string, ConfigurationPage>();

		private bool menuBuilt = false;

		[Configgable("", "Open Config Menu", 0, null)]
		private static ConfigKeybind cfgKey = new ConfigKeybind((KeyCode)92);

		[Configgable("", "Notify When Update Available", 0, null)]
		private static ConfigToggle notifyOnUpdateAvailable = new ConfigToggle(defaultValue: true);

		private GameObject[] menus;

		private ConfigurationPage lastOpenPage;

		private bool menuOpen = false;

		internal static bool openedOnce;

		private static event Action onGlobalOpen;

		private static event Action<string> onGlobalOpenAtPath;

		private static event Action onGlobalClose;

		private void Awake()
		{
			if (!menuBuilt)
			{
				BuildMenus(ConfigurationManager.GetMenus());
			}
			onGlobalOpen += OpenMenu;
			onGlobalClose += CloseMenu;
			onGlobalOpenAtPath += OpenMenuAtPath;
			ConfigurationManager.OnMenusChanged += BuildMenus;
		}

		private void Update()
		{
			if (menuOpen)
			{
				CheckMenuOpen();
			}
			else if (cfgKey.WasPeformed())
			{
				OpenMenu();
			}
		}

		private void CheckMenuOpen()
		{
			if (menus == null)
			{
				return;
			}
			for (int i = 0; i < menus.Length; i++)
			{
				if (!((Object)(object)menus[i] == (Object)null) && menus[i].activeInHierarchy)
				{
					return;
				}
			}
			Unpause();
		}

		internal void Rebuild()
		{
			BuildMenus(ConfigurationManager.GetMenus());
		}

		private void DestroyPages()
		{
			ConfigurationPage[] array = pageManifest.Values.ToArray();
			foreach (ConfigurationPage configurationPage in array)
			{
				Object.Destroy((Object)(object)((Component)configurationPage).gameObject);
			}
			pageManifest.Clear();
			menuBuilt = false;
		}

		private void BuildMenus(ConfigBuilder[] menus)
		{
			DestroyPages();
			Debug.Log((object)$"Building Configgy Menus {menus.Length}");
			NewPage(delegate(ConfigurationPage mainPage)
			{
				rootPage = mainPage;
				mainPage.SetHeader("Configuration");
				mainPage.Close();
				pageManifest.Add("", rootPage);
			});
			foreach (ConfigBuilder item in menus.OrderBy((ConfigBuilder x) => x.DisplayName))
			{
				IConfigElement[] configElements = item.GetConfigElements();
				if (configElements == null)
				{
					Debug.LogError((object)("ConfigBuilder: " + item.GUID + " has null elements. It cannot be built."));
				}
				else
				{
					BuildMenu(configElements);
				}
			}
		}

		private void BuildMenu(IConfigElement[] configElements)
		{
			foreach (IConfigElement item in configElements.OrderBy((IConfigElement x) => x.GetDescriptor().Path))
			{
				BuildElement(item);
			}
			foreach (KeyValuePair<string, ConfigurationPage> item2 in pageManifest)
			{
				item2.Value.RebuildPage();
			}
			menuBuilt = true;
		}

		private void BuildMenuTreeFromPath(string fullPath)
		{
			string[] path = fullPath.Split(new char[1] { '/' });
			string currentPathAddress = "";
			ConfigurationPage previousPage = null;
			int i;
			for (i = 0; i < path.Length; i++)
			{
				currentPathAddress += path[i];
				if (!pageManifest.ContainsKey(currentPathAddress))
				{
					if ((Object)(object)previousPage == (Object)null)
					{
						previousPage = rootPage;
					}
					NewPage(delegate(ConfigurationPage page)
					{
						ConfigurationPage closablePage = previousPage;
						ConfigButton configElement = new ConfigButton(delegate
						{
							closablePage.Close();
							page.Open();
						}, path[i]);
						closablePage.AddElement(configElement);
						page.SetHeader(path[i]);
						page.SetParent(closablePage);
						((Object)((Component)page).gameObject).name = currentPathAddress;
						page.SetFooter(currentPathAddress);
						page.Close();
						previousPage = page;
						pageManifest.Add(currentPathAddress, page);
					});
				}
				else
				{
					previousPage = pageManifest[currentPathAddress];
				}
				currentPathAddress += "/";
			}
		}

		private void BuildElement(IConfigElement element)
		{
			ConfiggableAttribute descriptor = element.GetDescriptor();
			string text = "";
			if (descriptor != null && descriptor.Owner != null)
			{
				text = descriptor.Owner.DisplayName ?? "";
				if (!string.IsNullOrEmpty(descriptor.Path))
				{
					text = text + "/" + descriptor.Path;
				}
			}
			else
			{
				text = "/Other";
			}
			BuildMenuTreeFromPath(text);
			pageManifest[text].AddElement(element);
		}

		private void NewPage(Action<ConfigurationPage> onInstance)
		{
			GameObject val = Object.Instantiate<GameObject>(PluginAssets.ConfigurationPage, (Transform)(object)contentbody);
			ConfigurationPage page = val.GetComponent<ConfigurationPage>();
			BehaviourRelay behaviourRelay = val.AddComponent<BehaviourRelay>();
			behaviourRelay.OnOnEnable = (Action<GameObject>)Delegate.Combine(behaviourRelay.OnOnEnable, (Action<GameObject>)delegate
			{
				lastOpenPage = page;
			});
			onInstance?.Invoke(page);
		}

		public void OpenMenu()
		{
			if (menuOpen)
			{
				return;
			}
			menus = (from x in ((Component)this).transform.GetChildren()
				select ((Component)x).gameObject).ToArray();
			Pauser.Pause(menus);
			if ((Object)(object)lastOpenPage != (Object)null)
			{
				lastOpenPage.Open();
			}
			else
			{
				rootPage.Open();
			}
			menuOpen = true;
			if (!openedOnce)
			{
				openedOnce = true;
				if (!Plugin.UsingLatest && notifyOnUpdateAvailable.Value)
				{
					ShowUpdatePrompt();
				}
			}
		}

		public void OpenMenuAtPath(string path)
		{
			if (string.IsNullOrEmpty(path))
			{
				OpenMenu();
				return;
			}
			menus = (from x in ((Component)this).transform.GetChildren()
				select ((Component)x).gameObject).ToArray();
			Pauser.Pause(menus);
			string text = path;
			while (!pageManifest.ContainsKey(text) && !string.IsNullOrEmpty(text) && text != "/")
			{
				text = Path.GetDirectoryName(text);
			}
			if (string.IsNullOrEmpty(text) || !pageManifest.ContainsKey(text))
			{
				OpenMenu();
				return;
			}
			pageManifest[text].Open();
			menuOpen = true;
			if (!openedOnce)
			{
				openedOnce = true;
				if (!Plugin.UsingLatest && notifyOnUpdateAvailable.Value)
				{
					ShowUpdatePrompt();
				}
			}
		}

		private void ShowUpdatePrompt()
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			ModalDialogueEvent modalDialogueEvent = new ModalDialogueEvent();
			modalDialogueEvent.Title = "Outdated";
			modalDialogueEvent.Message = "You are using an outdated version of Configgy: (<color=red>1.0.4</color>). Please update to the latest version from Github or Thunderstore: (<color=green>" + Plugin.LatestVersion + "</color>)";
			modalDialogueEvent.Options = new DialogueBoxOption[3]
			{
				new DialogueBoxOption
				{
					Name = "Open Browser",
					Color = Color.white,
					OnClick = delegate
					{
						Application.OpenURL("https://github.com/Hydraxous/Configgy//releases/latest");
					}
				},
				new DialogueBoxOption
				{
					Name = "Later",
					Color = Color.white,
					OnClick = delegate
					{
					}
				},
				new DialogueBoxOption
				{
					Name = "Don't Ask Again.",
					Color = Color.red,
					OnClick = delegate
					{
						notifyOnUpdateAvailable.SetValue(value: false);
					}
				}
			};
			ModalDialogue.ShowDialogue(modalDialogueEvent);
		}

		public void CloseMenu()
		{
			if (menuOpen)
			{
				menus = (from x in ((Component)this).transform.GetChildren()
					select ((Component)x).gameObject).ToArray();
				for (int i = 0; i < menus.Length; i++)
				{
					menus[i].SetActive(false);
				}
			}
		}

		public static void Open()
		{
			ConfigurationMenu.onGlobalOpen?.Invoke();
		}

		public static void OpenAtPath(string path)
		{
			ConfigurationMenu.onGlobalOpenAtPath?.Invoke(path);
		}

		public static void Close()
		{
			ConfigurationMenu.onGlobalClose?.Invoke();
		}

		private void Unpause()
		{
			Pauser.Unpause();
			menuOpen = false;
		}

		private void OnDestroy()
		{
			ConfigurationManager.OnMenusChanged -= BuildMenus;
			onGlobalOpen -= OpenMenu;
			onGlobalClose -= CloseMenu;
			onGlobalOpenAtPath -= OpenMenuAtPath;
		}
	}
	public class ConfigurationPage : MonoBehaviour
	{
		[SerializeField]
		private Text header;

		[SerializeField]
		private Text footer;

		[SerializeField]
		private Button backButton;

		[SerializeField]
		private Button closeButton;

		[SerializeField]
		private RectTransform contentBody;

		private List<IConfigElement> elements = new List<IConfigElement>();

		public bool preventClosing = false;

		private string footerText;

		public ConfigurationPage Parent { get; private set; }

		private void Start()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			((UnityEvent)backButton.onClick).AddListener(new UnityAction(Back));
			((UnityEvent)closeButton.onClick).AddListener(new UnityAction(Close));
		}

		private void Update()
		{
			if (Input.GetKeyDown((KeyCode)27))
			{
				EscapePressed();
			}
			if (Input.GetKeyDown((KeyCode)8))
			{
				BackspacePressed();
			}
		}

		private void EscapePressed()
		{
			if (!preventClosing)
			{
				Close();
			}
		}

		private void BackspacePressed()
		{
			if (preventClosing)
			{
				return;
			}
			InputField[] componentsInChildren = ((Component)contentBody).GetComponentsInChildren<InputField>(true);
			foreach (InputField val in componentsInChildren)
			{
				if (val.isFocused)
				{
					return;
				}
			}
			Back();
		}

		public void SetParent(ConfigurationPage page)
		{
			Parent = page;
		}

		public void SetHeader(string headerText)
		{
			header.text = "-- " + headerText + " --";
		}

		public void SetFooter(string footerText)
		{
			this.footerText = footerText;
			footer.text = footerText.TrimEnd('/', '\n', '\r');
		}

		public void AddElement(IConfigElement configElement)
		{
			elements.Add(configElement);
		}

		public void ClearElements()
		{
			elements.Clear();
			DestroyAllElements();
		}

		private void DestroyAllElements()
		{
			Transform[] children = ((Transform)(object)contentBody).GetChildren();
			for (int i = 0; i < children.Length; i++)
			{
				Transform val = children[i];
				children[i] = null;
				Object.Destroy((Object)(object)((Component)val).gameObject);
			}
		}

		public void Open()
		{
			((Component)this).gameObject.SetActive(true);
		}

		public void Back()
		{
			if ((Object)(object)Parent != (Object)null)
			{
				Parent.Open();
			}
			((Component)this).gameObject.SetActive(false);
		}

		public void Close()
		{
			((Component)this).gameObject.SetActive(false);
		}

		public void RebuildPage()
		{
			DestroyAllElements();
			foreach (IConfigElement item in elements.OrderBy((IConfigElement x) => x.GetDescriptor()?.OrderInList))
			{
				if (item == null)
				{
					Debug.LogError((object)$"Configgy: Null element in page {footer}");
					continue;
				}
				try
				{
					item.BuildElement(contentBody);
				}
				catch (Exception ex)
				{
					Debug.LogException(ex);
				}
			}
		}

		private void OnEnable()
		{
			((Component)backButton).gameObject.SetActive((Object)(object)Parent != (Object)null);
			foreach (IConfigElement item in elements.OrderBy((IConfigElement x) => x.GetDescriptor()?.OrderInList))
			{
				item.OnMenuOpen();
			}
		}

		private void OnDisable()
		{
			foreach (IConfigElement item in elements.OrderBy((IConfigElement x) => x.GetDescriptor()?.OrderInList))
			{
				item.OnMenuClose();
			}
		}
	}
	public static class DynUI
	{
		public static class ConfigUI
		{
			public static void CreateElementSlot<T>(RectTransform rect, ConfigValueElement<T> valueElement, Action<RectTransform> onInstance, Action<RectTransform> onButtonSlots = null)
			{
				ConfiggableAttribute configgable = ((IConfigElement)valueElement).GetDescriptor();
				Frame(rect, delegate(Frame f)
				{
					//IL_000d: Unknown result type (might be due to invalid IL or missing references)
					//IL_001c: Unknown result type (might be due to invalid IL or missing references)
					f.RectTransform.sizeDelta = new Vector2(f.RectTransform.sizeDelta.x, 55f);
					Div(f.Content, delegate(RectTransform operatorsDiv)
					{
						operatorsDiv.SetAnchors(0f, 0f, 0.2f, 1f);
						Layout.Fill(operatorsDiv);
						DynUI.Component<HorizontalLayoutGroup>((Transform)(object)operatorsDiv, (Action<HorizontalLayoutGroup>)delegate(HorizontalLayoutGroup hlg)
						{
							((HorizontalOrVerticalLayoutGroup)hlg).childForceExpandHeight = true;
							((HorizontalOrVerticalLayoutGroup)hlg).childForceExpandWidth = true;
							((HorizontalOrVerticalLayoutGroup)hlg).childControlHeight = false;
							((HorizontalOrVerticalLayoutGroup)hlg).childControlWidth = false;
							((LayoutGroup)hlg).childAlignment = (TextAnchor)3;
						});
						ImageButton(operatorsDiv, delegate(Button button, Image icon)
						{
							//IL_0013: Unknown result type (might be due to invalid IL or missing references)
							//IL_003c: Unknown result type (might be due to invalid IL or missing references)
							//IL_0046: Expected O, but got Unknown
							RectTransform component2 = ((Component)button).GetComponent<RectTransform>();
							component2.sizeDelta = new Vector2(40f, 40f);
							icon.sprite = PluginAssets.Icon_Reset;
							((UnityEvent)button.onClick).AddListener(new UnityAction(valueElement.ResetValue));
						});
						if (!string.IsNullOrEmpty(configgable.Description))
						{
							GameObject newDescriptionBox = null;
							Description(rect, delegate(RectTransform r, Text desc)
							{
								newDescriptionBox = ((Component)r).gameObject;
								desc.text = configgable.Description;
								((Component)r).gameObject.SetActive(false);
							});
							UnityAction val = default(UnityAction);
							ImageButton(operatorsDiv, delegate(Button button, Image icon)
							{
								//IL_0013: 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_0047: Unknown result type (might be due to invalid IL or missing references)
								//IL_0049: Expected O, but got Unknown
								//IL_004e: Expected O, but got Unknown
								RectTransform component = ((Component)button).GetComponent<RectTransform>();
								component.sizeDelta = new Vector2(40f, 40f);
								icon.sprite = PluginAssets.Icon_Info;
								ButtonClickedEvent onClick = button.onClick;
								UnityAction obj = val;
								if (obj == null)
								{
									UnityAction val2 = delegate
									{
										newDescriptionBox.SetActive(!newDescriptionBox.activeInHierarchy);
									};
									UnityAction val3 = val2;
									val = val2;
									obj = val3;
								}
								((UnityEvent)onClick).AddListener(obj);
							});
						}
						onButtonSlots?.Invoke(operatorsDiv);
					});
					Div(f.Content, delegate(RectTransform elementsDiv)
					{
						elementsDiv.SetAnchors(0.2f, 0f, 1f, 1f);
						Layout.Fill(elementsDiv);
						DynUI.Component<HorizontalLayoutGroup>((Transform)(object)elementsDiv, (Action<HorizontalLayoutGroup>)delegate(HorizontalLayoutGroup hlg)
						{
							((HorizontalOrVerticalLayoutGroup)hlg).childForceExpandHeight = true;
							((HorizontalOrVerticalLayoutGroup)hlg).childForceExpandWidth = true;
							((HorizontalOrVerticalLayoutGroup)hlg).childControlHeight = true;
							((HorizontalOrVerticalLayoutGroup)hlg).childControlWidth = true;
							((LayoutGroup)hlg).childAlignment = (TextAnchor)5;
						});
						Label(elementsDiv, delegate(Text t)
						{
							t.text = configgable.DisplayName;
							t.fontSize = 4;
							t.resizeTextMaxSize = 25;
						});
						onInstance?.Invoke(elementsDiv);
					});
				});
			}
		}

		public static class Layout
		{
			public static void HalfTop(RectTransform rt)
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				rt.anchorMin = new Vector2(0f, 0.5f);
				rt.anchorMax = new Vector2(1f, 1f);
			}

			public static void HalfBottom(RectTransform rt)
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				rt.anchorMin = new Vector2(0f, 0f);
				rt.anchorMax = new Vector2(1f, 0.5f);
			}

			public static void HalfLeft(RectTransform rt)
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				rt.anchorMin = new Vector2(0f, 0f);
				rt.anchorMax = new Vector2(0.5f, 1f);
			}

			public static void HalfRight(RectTransform rt)
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				rt.anchorMin = new Vector2(0f, 0f);
				rt.anchorMax = new Vector2(0.5f, 1f);
			}

			public static void FillParent(RectTransform rt)
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				rt.anchorMin = new Vector2(0f, 0f);
				rt.anchorMax = new Vector2(1f, 1f);
				Fill(rt);
			}

			public static void Fill(RectTransform rt)
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				//IL_0038: Unknown result type (might be due to invalid IL or missing references)
				rt.offsetMax = new Vector2(0f, 0f);
				rt.offsetMin = new Vector2(0f, 0f);
				rt.sizeDelta = new Vector2(0f, 0f);
			}

			public static void Padding(RectTransform rt, float padding)
			{
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				rt.anchoredPosition = new Vector2(0f - padding * 2f, 0f - padding * 2f);
			}

			public static void CenterAnchor(RectTransform rt)
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				rt.anchorMin = new Vector2(0.5f, 0.5f);
				rt.anchorMax = new Vector2(0.5f, 0.5f);
			}
		}

		public static void Frame(RectTransform rect, Action<Frame> onInstance)
		{
			Instantiate<Frame>(rect, PluginAssets.FramePrefab, onInstance);
		}

		public static void Button(RectTransform rect, Action<Button> onInstance)
		{
			Instantiate<Button>(rect, PluginAssets.ButtonPrefab, onInstance);
		}

		public static void ImageButton(RectTransform rect, Action<Button, Image> onInstance)
		{
			Action<Button> onInstance2 = delegate(Button b)
			{
				Image arg = (from x in ((Component)b).GetComponentsInChildren<Image>()
					where ((Object)x).name == "Icon"
					select x).FirstOrDefault();
				onInstance?.Invoke(b, arg);
			};
			Instantiate<Button>(rect, PluginAssets.ImageButtonPrefab, onInstance2);
		}

		public static void ScrollRect(RectTransform rect, Action<ScrollRect> onInstance)
		{
			Instantiate<ScrollRect>(rect, PluginAssets.ScrollRectPrefab, onInstance);
		}

		public static void Label(RectTransform rect, Action<Text> onInstance)
		{
			Instantiate<Text>(rect, PluginAssets.TextPrefab, onInstance);
		}

		public static void InputField(RectTransform rect, Action<InputField> onInstance)
		{
			Instantiate<InputField>(rect, PluginAssets.InputFieldPrefab, onInstance);
		}

		public static void Slider(RectTransform rect, Action<Slider> onInstance)
		{
			Instantiate<Slider>(rect, PluginAssets.SliderPrefab, onInstance);
		}

		public static void Toggle(RectTransform rect, Action<Toggle> onInstance)
		{
			Instantiate<Toggle>(rect, PluginAssets.TogglePrefab, onInstance);
		}

		public static void Dropdown(