Decompiled source of BetterModMenu v1.5.0

BetterModMenu.dll

Decompiled 8 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BetterModMenu;
using MelonLoader;
using MelonLoader.Preferences;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(ModMenuMod), "BetterModMenu", "1.5.0", "lyj_0322", null)]
[assembly: MelonGame("ReLUGames", "MIMESIS")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace BetterModMenu;

internal static class BuildInfo
{
	internal const string Version = "1.5.0";

	internal const string Name = "BetterModMenu";

	internal const string Author = "lyj_0322";
}
internal static class ConfigModel
{
	private const BindingFlags AnyStatic = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

	private const BindingFlags AnyInst = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

	internal static readonly List<ModCategory> Categories = new List<ModCategory>();

	private static readonly Dictionary<Type, Dictionary<string, MemberInfo>> MemberCache = new Dictionary<Type, Dictionary<string, MemberInfo>>(64);

	internal static int EntryCount { get; private set; }

	internal static void Refresh()
	{
		Categories.Clear();
		EntryCount = 0;
		IEnumerable enumerable = FindMemberList("Categories", "MelonPreferences_Category");
		if (enumerable == null)
		{
			IEnumerable enumerable2 = FindMemberList("Entries", "MelonPreferences_Entry");
			if (enumerable2 != null)
			{
				BuildFromFlatEntries(enumerable2);
				return;
			}
			Instance log = ModMenuMod.Log;
			if (log != null)
			{
				log.Warning("未能定位 MelonPreferences 的配置集合,菜单将为空。");
			}
			return;
		}
		foreach (object item in enumerable)
		{
			if (item == null || ToBool(GetInst(item, "IsHidden")))
			{
				continue;
			}
			string text = ToStr(GetInst(item, "Identifier")) ?? "?";
			string text2 = ToStr(GetInst(item, "DisplayName"));
			ModCategory modCategory = new ModCategory
			{
				Raw = item,
				Identifier = text,
				DisplayName = Localization.CategoryName(text, string.IsNullOrEmpty(text2) ? Prettify(text) : text2)
			};
			if (GetInst(item, "Entries") is IEnumerable enumerable3)
			{
				foreach (object item2 in enumerable3)
				{
					ModEntry modEntry = BuildEntry(item2, modCategory);
					if (modEntry != null)
					{
						modCategory.Entries.Add(modEntry);
					}
				}
			}
			if (modCategory.Entries.Count != 0)
			{
				modCategory.Entries.Sort((ModEntry a, ModEntry b) => string.Compare(a.Name, b.Name, StringComparison.CurrentCultureIgnoreCase));
				Categories.Add(modCategory);
				EntryCount += modCategory.Entries.Count;
			}
		}
		Categories.Sort((ModCategory a, ModCategory b) => string.Compare(a.DisplayName, b.DisplayName, StringComparison.CurrentCultureIgnoreCase));
	}

	private static void BuildFromFlatEntries(IEnumerable flat)
	{
		Dictionary<string, ModCategory> dictionary = new Dictionary<string, ModCategory>(StringComparer.OrdinalIgnoreCase);
		foreach (object item in flat)
		{
			if (item != null)
			{
				object inst = GetInst(item, "Category");
				string text = ((inst != null) ? ToStr(GetInst(inst, "Identifier")) : "General");
				if (text == null)
				{
					text = "General";
				}
				if (!dictionary.TryGetValue(text, out var value))
				{
					value = (dictionary[text] = new ModCategory
					{
						Raw = inst,
						Identifier = text,
						DisplayName = Localization.CategoryName(text, (inst != null) ? (ToStr(GetInst(inst, "DisplayName")) ?? Prettify(text)) : Prettify(text))
					});
					Categories.Add(value);
				}
				ModEntry modEntry = BuildEntry(item, value);
				if (modEntry != null)
				{
					value.Entries.Add(modEntry);
				}
			}
		}
		Categories.Sort((ModCategory a, ModCategory b) => string.Compare(a.DisplayName, b.DisplayName, StringComparison.CurrentCultureIgnoreCase));
		EntryCount = Categories.Sum((ModCategory c) => c.Entries.Count);
		ChangeSet.Prune(from e in Categories.SelectMany((ModCategory c) => c.Entries)
			select e.Raw);
	}

	private static ModEntry BuildEntry(object raw, ModCategory cat)
	{
		if (raw == null)
		{
			return null;
		}
		if (ToBool(GetInst(raw, "IsHidden")))
		{
			return null;
		}
		string text = ToStr(GetInst(raw, "Identifier")) ?? "?";
		string text2 = ToStr(GetInst(raw, "DisplayName"));
		Type type = raw.GetType();
		Type type2 = typeof(object);
		if (type.IsGenericType)
		{
			Type[] genericArguments = type.GetGenericArguments();
			if (genericArguments.Length == 1)
			{
				type2 = genericArguments[0];
			}
		}
		if (type2 == typeof(object))
		{
			object obj = GetInst(raw, "BoxedValue") ?? GetInst(raw, "Value");
			if (obj != null)
			{
				type2 = obj.GetType();
			}
		}
		ModEntry modEntry = new ModEntry
		{
			Raw = raw,
			Category = cat,
			Identifier = text,
			Name = Localization.EntryName(cat.Identifier, text, string.IsNullOrEmpty(text2) ? Prettify(text) : text2),
			Comment = Localization.Comment(cat.Identifier, text, ToStr(GetInst(raw, "Comment"))),
			ValueType = type2
		};
		modEntry.BaselineValue = GetValue(modEntry);
		object inst = GetInst(raw, "DefaultValue");
		modEntry.DefaultValue = inst ?? modEntry.BaselineValue;
		if (modEntry.BaselineValue == null)
		{
			return null;
		}
		ChangeSet.Register(modEntry);
		return modEntry;
	}

	internal static object GetValue(ModEntry e)
	{
		object inst = GetInst(e.Raw, "BoxedValue");
		if (inst != null)
		{
			return inst;
		}
		return GetInst(e.Raw, "Value");
	}

	internal static bool SetValue(ModEntry e, object value)
	{
		try
		{
			value = Validate(e, value);
			if (SetInst(e.Raw, "BoxedValue", value))
			{
				return true;
			}
			if (SetInst(e.Raw, "Value", value))
			{
				return true;
			}
		}
		catch (Exception ex)
		{
			Instance log = ModMenuMod.Log;
			if (log != null)
			{
				log.Warning("写入配置失败 " + e.Category.Identifier + "/" + e.Identifier + ": " + ex.Message);
			}
		}
		return false;
	}

	private static object Validate(ModEntry e, object value)
	{
		try
		{
			object inst = GetInst(e.Raw, "Validator");
			if (inst == null)
			{
				return value;
			}
			MethodInfo method = inst.GetType().GetMethod("EnsureValid", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (method == null)
			{
				return value;
			}
			return method.Invoke(inst, new object[1] { value }) ?? value;
		}
		catch
		{
			return value;
		}
	}

	internal static bool Save()
	{
		try
		{
			MethodInfo method = typeof(MelonPreferences).GetMethod("Save", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
			if (method != null)
			{
				method.Invoke(null, null);
				return true;
			}
		}
		catch (Exception ex)
		{
			Instance log = ModMenuMod.Log;
			if (log != null)
			{
				log.Warning("保存配置失败: " + ex.Message);
			}
		}
		try
		{
			foreach (ModCategory category in Categories)
			{
				MethodInfo methodInfo = category.Raw?.GetType().GetMethod("Save", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
				if (methodInfo != null)
				{
					methodInfo.Invoke(category.Raw, null);
				}
			}
			return true;
		}
		catch
		{
		}
		return false;
	}

	private static IEnumerable FindMemberList(string preferredName, string itemTypeHint)
	{
		if (GetStatic(typeof(MelonPreferences), preferredName) is IEnumerable result)
		{
			return result;
		}
		Type typeFromHandle = typeof(MelonPreferences);
		List<KeyValuePair<string, object>> list = new List<KeyValuePair<string, object>>();
		FieldInfo[] fields = typeFromHandle.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		foreach (FieldInfo fieldInfo in fields)
		{
			if (typeof(IEnumerable).IsAssignableFrom(fieldInfo.FieldType))
			{
				try
				{
					list.Add(new KeyValuePair<string, object>(fieldInfo.Name, fieldInfo.GetValue(null)));
				}
				catch
				{
				}
			}
		}
		PropertyInfo[] properties = typeFromHandle.GetProperties(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		foreach (PropertyInfo propertyInfo in properties)
		{
			if (typeof(IEnumerable).IsAssignableFrom(propertyInfo.PropertyType) && propertyInfo.CanRead)
			{
				try
				{
					list.Add(new KeyValuePair<string, object>(propertyInfo.Name, propertyInfo.GetValue(null, null)));
				}
				catch
				{
				}
			}
		}
		foreach (KeyValuePair<string, object> item in list)
		{
			if (item.Value is IEnumerable enumerable && FirstItemTypeName(enumerable).IndexOf(itemTypeHint, StringComparison.Ordinal) >= 0)
			{
				return enumerable;
			}
		}
		string text = string.Join(", ", list.ConvertAll((KeyValuePair<string, object> k) => k.Key).ToArray());
		Instance log = ModMenuMod.Log;
		if (log != null)
		{
			log.Warning("MelonPreferences 上未找到 " + preferredName + ",候选集合成员: " + text);
		}
		return null;
	}

	private static string FirstItemTypeName(IEnumerable en)
	{
		try
		{
			foreach (object item in en)
			{
				if (item != null)
				{
					return item.GetType().Name;
				}
			}
		}
		catch
		{
		}
		return string.Empty;
	}

	private static object GetStatic(Type t, string name)
	{
		PropertyInfo property = t.GetProperty(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		if (property != null)
		{
			try
			{
				return property.GetValue(null, null);
			}
			catch
			{
			}
		}
		FieldInfo field = t.GetField(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		if (field != null)
		{
			try
			{
				return field.GetValue(null);
			}
			catch
			{
			}
		}
		return null;
	}

	internal static object GetInst(object o, string name)
	{
		if (o == null)
		{
			return null;
		}
		MemberInfo memberInfo = Resolve(o.GetType(), name);
		if (memberInfo == null)
		{
			return null;
		}
		try
		{
			FieldInfo fieldInfo = memberInfo as FieldInfo;
			if (fieldInfo != null)
			{
				return fieldInfo.GetValue(o);
			}
			return ((PropertyInfo)memberInfo).GetValue(o, null);
		}
		catch
		{
			return null;
		}
	}

	private static bool SetInst(object o, string name, object value)
	{
		if (o == null)
		{
			return false;
		}
		MemberInfo memberInfo = Resolve(o.GetType(), name);
		if (memberInfo == null)
		{
			return false;
		}
		try
		{
			FieldInfo fieldInfo = memberInfo as FieldInfo;
			if (fieldInfo != null)
			{
				fieldInfo.SetValue(o, Coerce(value, fieldInfo.FieldType));
				return true;
			}
			PropertyInfo propertyInfo = (PropertyInfo)memberInfo;
			if (!propertyInfo.CanWrite)
			{
				return false;
			}
			propertyInfo.SetValue(o, Coerce(value, propertyInfo.PropertyType), null);
			return true;
		}
		catch
		{
			return false;
		}
	}

	private static MemberInfo Resolve(Type t, string name)
	{
		if (MemberCache.TryGetValue(t, out var value))
		{
			if (!value.TryGetValue(name, out var value2))
			{
				return null;
			}
			return value2;
		}
		value = new Dictionary<string, MemberInfo>(16, StringComparer.Ordinal);
		PropertyInfo[] properties = t.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		foreach (PropertyInfo propertyInfo in properties)
		{
			if (propertyInfo.CanRead && !value.ContainsKey(propertyInfo.Name))
			{
				value[propertyInfo.Name] = propertyInfo;
			}
		}
		FieldInfo[] fields = t.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		foreach (FieldInfo fieldInfo in fields)
		{
			if (!value.ContainsKey(fieldInfo.Name))
			{
				value[fieldInfo.Name] = fieldInfo;
			}
		}
		MemberCache[t] = value;
		if (!value.TryGetValue(name, out var value3))
		{
			return null;
		}
		return value3;
	}

	internal static object Coerce(object value, Type target)
	{
		if (value == null)
		{
			return null;
		}
		if (target.IsInstanceOfType(value))
		{
			return value;
		}
		if (target.IsEnum)
		{
			if (value is string value2)
			{
				return Enum.Parse(target, value2, ignoreCase: true);
			}
			return Enum.ToObject(target, Convert.ToInt64(value, CultureInfo.InvariantCulture));
		}
		return Convert.ChangeType(value, target, CultureInfo.InvariantCulture);
	}

	private static bool ToBool(object o)
	{
		bool flag = default(bool);
		int num;
		if (o is bool)
		{
			flag = (bool)o;
			num = 1;
		}
		else
		{
			num = 0;
		}
		return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
	}

	private static string ToStr(object o)
	{
		return o as string;
	}

	internal static string Prettify(string raw)
	{
		if (string.IsNullOrEmpty(raw))
		{
			return string.Empty;
		}
		return Regex.Replace(Regex.Replace(Regex.Replace(raw.Replace('_', ' '), "([a-z0-9])([A-Z])", "$1 $2"), "([A-Z])([A-Z][a-z])", "$1 $2"), "\\s+", " ").Trim();
	}
}
internal sealed class ModCategory
{
	internal object Raw;

	internal string Identifier;

	internal string DisplayName;

	internal readonly List<ModEntry> Entries = new List<ModEntry>();

	internal int PendingCached;

	internal int PendingVersion = -1;

	internal float NameWidth = -1f;

	internal string NameShort;

	internal int SubVersion = -1;

	internal string SubText;

	internal int PendingCount
	{
		get
		{
			if (PendingVersion != ChangeSet.Version)
			{
				int num = 0;
				for (int i = 0; i < Entries.Count; i++)
				{
					if (ChangeSet.IsDirty(Entries[i]))
					{
						num++;
					}
				}
				PendingCached = num;
				PendingVersion = ChangeSet.Version;
			}
			return PendingCached;
		}
	}

	internal bool Matches(string term)
	{
		if (string.IsNullOrEmpty(term))
		{
			return true;
		}
		if (DisplayName.IndexOf(term, StringComparison.OrdinalIgnoreCase) >= 0)
		{
			return true;
		}
		if (Identifier.IndexOf(term, StringComparison.OrdinalIgnoreCase) >= 0)
		{
			return true;
		}
		return Entries.Any((ModEntry e) => e.Name.IndexOf(term, StringComparison.OrdinalIgnoreCase) >= 0 || e.Identifier.IndexOf(term, StringComparison.OrdinalIgnoreCase) >= 0);
	}
}
internal sealed class ModEntry
{
	internal object Raw;

	internal ModCategory Category;

	internal string Identifier;

	internal string Name;

	internal string Comment;

	internal Type ValueType;

	internal object BaselineValue;

	internal object DefaultValue;

	internal float NameWidth = -1f;

	internal string NameShort;

	internal float DescWidth = -1f;

	internal string DescShort;

	internal string NumText;

	internal double NumTextValue = double.NaN;

	internal string NumFmt;

	internal string TypeLabel
	{
		get
		{
			Type valueType = ValueType;
			if (valueType == typeof(bool))
			{
				return "开关";
			}
			if (valueType == typeof(int) || valueType == typeof(long) || valueType == typeof(short) || valueType == typeof(byte))
			{
				return "整数";
			}
			if (valueType == typeof(float) || valueType == typeof(double))
			{
				return "数值";
			}
			if (valueType == typeof(string))
			{
				return "文本";
			}
			if (valueType.IsEnum)
			{
				return "选项";
			}
			return valueType.Name;
		}
	}
}
internal static class ChangeSet
{
	private static readonly Dictionary<object, object> Pending = new Dictionary<object, object>();

	private static readonly Dictionary<object, object> Baseline = new Dictionary<object, object>();

	internal static int Version { get; private set; }

	internal static int Count => Pending.Count;

	internal static void Register(ModEntry e)
	{
		if (e != null && e.Raw != null)
		{
			Baseline[e.Raw] = e.BaselineValue;
		}
	}

	internal static void Prune(IEnumerable<object> alive)
	{
		if (alive == null)
		{
			return;
		}
		HashSet<object> hashSet = new HashSet<object>(alive);
		bool flag = false;
		object[] array = Pending.Keys.ToArray();
		foreach (object obj in array)
		{
			if (!hashSet.Contains(obj))
			{
				Pending.Remove(obj);
				flag = true;
			}
		}
		array = Baseline.Keys.ToArray();
		foreach (object obj2 in array)
		{
			if (!hashSet.Contains(obj2))
			{
				Baseline.Remove(obj2);
			}
		}
		if (flag)
		{
			Version++;
		}
	}

	internal static object Current(ModEntry e)
	{
		if (e != null && Pending.TryGetValue(e.Raw, out var value))
		{
			return value;
		}
		return ConfigModel.GetValue(e);
	}

	internal static void Set(ModEntry e, object value)
	{
		if (e == null || e.Raw == null)
		{
			return;
		}
		object value2;
		if (SameValue(e.BaselineValue, value))
		{
			if (Pending.Remove(e.Raw))
			{
				Version++;
			}
		}
		else if (!Pending.TryGetValue(e.Raw, out value2) || !SameValue(value2, value))
		{
			Pending[e.Raw] = value;
			Version++;
		}
	}

	internal static void ResetEntry(ModEntry e)
	{
		if (e != null && e.Raw != null)
		{
			Set(e, e.DefaultValue);
		}
	}

	internal static void ResetCategory(ModCategory c)
	{
		if (c == null)
		{
			return;
		}
		foreach (ModEntry entry in c.Entries)
		{
			ResetEntry(entry);
		}
	}

	internal static bool IsDirty(ModEntry e)
	{
		if (e != null && e.Raw != null)
		{
			return Pending.ContainsKey(e.Raw);
		}
		return false;
	}

	internal static void Revert()
	{
		if (Pending.Count != 0)
		{
			Pending.Clear();
			Version++;
		}
	}

	internal static bool Apply(out int applied, out int failed)
	{
		applied = 0;
		failed = 0;
		KeyValuePair<object, object>[] array = Pending.ToArray();
		for (int i = 0; i < array.Length; i++)
		{
			KeyValuePair<object, object> kv = array[i];
			ModEntry modEntry = ConfigModel.Categories.SelectMany((ModCategory c) => c.Entries).FirstOrDefault((ModEntry e) => e.Raw == kv.Key);
			if (modEntry == null)
			{
				failed++;
			}
			else if (ConfigModel.SetValue(modEntry, kv.Value))
			{
				modEntry.BaselineValue = kv.Value;
				Baseline[kv.Key] = kv.Value;
				applied++;
			}
			else
			{
				failed++;
			}
		}
		Pending.Clear();
		Version++;
		if (applied > 0)
		{
			ConfigModel.Save();
		}
		return failed == 0;
	}

	internal static bool SameValue(object a, object b)
	{
		if (a == null && b == null)
		{
			return true;
		}
		if (a == null || b == null)
		{
			return false;
		}
		if (a.GetType() == b.GetType() && a.Equals(b))
		{
			return true;
		}
		if (IsNumeric(a) && IsNumeric(b))
		{
			return Math.Abs(Convert.ToDouble(a, CultureInfo.InvariantCulture) - Convert.ToDouble(b, CultureInfo.InvariantCulture)) < 1E-09;
		}
		if (a.GetType().IsEnum && b.GetType().IsEnum)
		{
			return Convert.ToInt64(a, CultureInfo.InvariantCulture) == Convert.ToInt64(b, CultureInfo.InvariantCulture);
		}
		return string.Equals(a.ToString(), b.ToString(), StringComparison.Ordinal);
	}

	internal static bool IsNumeric(object o)
	{
		if (!(o is byte) && !(o is sbyte) && !(o is short) && !(o is ushort) && !(o is int) && !(o is uint) && !(o is long) && !(o is ulong) && !(o is float) && !(o is double))
		{
			return o is decimal;
		}
		return true;
	}
}
internal static class Localization
{
	private static readonly Dictionary<string, string> CategoryNames = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
	{
		{ "BetterModMenu", "模组菜单" },
		{ "BiggerLobby", "大厅扩容" },
		{ "Better Joiner", "房间加入优化" },
		{ "BetterJoiner", "房间加入优化" },
		{ "TooManyPlayers", "人数上限" },
		{ "BetterJump", "跳跃手感" },
		{ "MimicAPI", "Mimic 前置库" },
		{ "EnemyDropLoot", "敌人掉落" },
		{ "Enemy Drop Loot", "敌人掉落" }
	};

	private static readonly Dictionary<string, string> Names = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
	{
		{ "BetterModMenu/MenuKey", "菜单热键" },
		{ "BiggerLobby/Enabled", "启用" },
		{ "BiggerLobby/Verbose", "详细日志" },
		{ "BiggerLobby/MaxPlayers", "最大玩家数" },
		{ "BiggerLobby/DebugPlaceholders", "调试占位玩家" },
		{ "BiggerLobby/DebugResultKey", "调试结算热键" },
		{ "BiggerLobby/ShowSlotLabel", "显示槽位序号" },
		{ "BiggerLobby/ShowSteamId", "显示 SteamID" },
		{ "BiggerLobby/MenuColumns", "菜单列数" },
		{ "BiggerLobby/MenuScale", "菜单行缩放" },
		{ "BiggerLobby/ResultColumns", "结算列数" },
		{ "BiggerLobby/ResultScale", "结算缩放" },
		{ "BiggerLobby/ResultTopOffset", "结算顶部偏移" },
		{ "BiggerLobby/SpectatorColumns", "旁观列表列数" },
		{ "BiggerLobby/SpectatorScale", "旁观列表缩放" },
		{ "BiggerLobby/SpectatorOffsetX", "旁观列表水平偏移" },
		{ "BiggerLobby/SpectatorOffsetY", "旁观列表垂直偏移" },
		{ "BiggerLobby/SpectatorFillByColumn", "旁观列表按列填充" },
		{ "BiggerLobby/ShowFullSpectatorName", "显示完整旁观者名称" },
		{ "TooManyPlayers/Enabled", "启用" },
		{ "TooManyPlayers/MaxPlayers", "最大玩家数" },
		{ "BetterJump/Enabled", "启用" },
		{ "BetterJump/JumpVelocity", "起跳速度" },
		{ "BetterJump/ForceUngroundTime", "强制离地时间" },
		{ "BetterJump/AirGravityScale", "空中重力倍率" },
		{ "BetterJump/DebugLogs", "调试日志" },
		{ "BetterJump/LandSettleSeconds", "落地稳定时间" },
		{ "BetterJump/ApexBlendSpeed", "顶点过渡速度" },
		{ "BetterJump/MaxAirGravitySeconds", "减重力最长时间" },
		{ "Better Joiner/Enabled", "启用" },
		{ "BetterJoiner/Enabled", "启用" },
		{ "EnemyDropLoot/Enabled", "启用" },
		{ "EnemyDropLoot/DropChance", "掉落几率" },
		{ "EnemyDropLoot/MaxDropsPerKill", "每次击杀判定次数" },
		{ "EnemyDropLoot/RemoveFakeItemDrops", "过滤假物品掉落" },
		{ "EnemyDropLoot/AllowedItemIds", "仅允许的物品 ID" },
		{ "EnemyDropLoot/BlockedItemIds", "排除的物品 ID" }
	};

	private static readonly Dictionary<string, string> Comments = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
	{
		{ "BetterModMenu/MenuKey", "打开或关闭模组菜单的按键,填 KeyCode 名称,如 F9、F8、Insert。" },
		{ "BiggerLobby/Enabled", "启用大厅扩容;关闭后不应用任何补丁。" },
		{ "BiggerLobby/Verbose", "向 MelonLoader 控制台输出额外诊断信息。" },
		{ "BiggerLobby/MaxPlayers", "房间人数上限(2–32)。界面最多显示 16 人,超出部分只保留数据。" },
		{ "BiggerLobby/DebugPlaceholders", "用假玩家填满所有界面槽位,方便单人检查对齐与缩放。" },
		{ "BiggerLobby/DebugResultKey", "打开 16 人结算界面的调试热键,仅在开启占位玩家时有效。" },
		{ "BiggerLobby/ShowSlotLabel", "在每行右上角显示槽位序号,可选显示 SteamID。" },
		{ "BiggerLobby/ShowSteamId", "在槽位序号下方显示该玩家的 SteamID。" },
		{ "BiggerLobby/MenuColumns", "游戏内菜单玩家列表的列数(1–4),默认 2 列 × 8 行。" },
		{ "BiggerLobby/MenuScale", "菜单玩家列表的行缩放,0 表示自适应列表区域。" },
		{ "BiggerLobby/ResultColumns", "结算界面列数(1–8),默认 8 列 × 2 行容纳 16 人。" },
		{ "BiggerLobby/ResultScale", "结算界面列的缩放,0 表示自适应区域。" },
		{ "BiggerLobby/ResultTopOffset", "结算网格顶部微调(像素),正数下移、负数上移。" },
		{ "BiggerLobby/SpectatorColumns", "旁观玩家列表的列数(1–8),默认 2 列 × 8 行。" },
		{ "BiggerLobby/SpectatorScale", "旁观列表缩放,0 表示自适应。" },
		{ "BiggerLobby/SpectatorOffsetX", "旁观列表整体的水平偏移(像素)。" },
		{ "BiggerLobby/SpectatorOffsetY", "旁观列表整体的垂直偏移(像素,正数下移)。" },
		{ "BiggerLobby/SpectatorFillByColumn", "开启时先填满左列(1–8)再填右列;关闭则逐行填充。" },
		{ "BiggerLobby/ShowFullSpectatorName", "在旁观视角中央完整显示被旁观者名称,长名字不再截断。" },
		{ "TooManyPlayers/Enabled", "启用更大的人数上限;关闭时保持原版 4 人。" },
		{ "TooManyPlayers/MaxPlayers", "单局最大玩家数,默认 8,范围 4–250。" },
		{ "BetterJump/Enabled", "启用跳跃手感调整;关闭时不修改任何跳跃行为。" },
		{ "BetterJump/JumpVelocity", "起跳初速度(单位/秒),数值越大跳得越高。" },
		{ "BetterJump/ForceUngroundTime", "起跳后强制离地的时间(秒),避免立刻又被判定为落地。" },
		{ "BetterJump/AirGravityScale", "上升段的重力倍率,越小越飘;接近顶点会平滑恢复常规重力。" },
		{ "BetterJump/DebugLogs", "输出跳跃相关的调试日志。" },
		{ "BetterJump/LandSettleSeconds", "再次触发强化跳跃前需要的持续着地时间(秒)。" },
		{ "BetterJump/ApexBlendSpeed", "接近顶点时恢复常规重力的速度阈值。" },
		{ "BetterJump/MaxAirGravitySeconds", "减重力效果的最长持续时间(秒)。" },
		{ "Better Joiner/Enabled", "启用改进后的房间加入界面。" },
		{ "BetterJoiner/Enabled", "启用改进后的房间加入界面。" },
		{ "EnemyDropLoot/Enabled", "敌人掉落的总开关,关掉后不产生任何额外掉落。默认开启。" },
		{ "EnemyDropLoot/DropChance", "每次判定掉落成功的概率(0–1):0 表示完全不掉,1 表示每次都掉。默认 0.1。" },
		{ "EnemyDropLoot/MaxDropsPerKill", "每击杀一个敌人最多判定几次掉落。默认 1。" },
		{ "EnemyDropLoot/RemoveFakeItemDrops", "敌人死亡时不再掉出假物品,真实物品、原版奖励和额外掉落都保留。主机设置,默认关闭。" },
		{ "EnemyDropLoot/AllowedItemIds", "只让这些物品 ID 掉出,英文逗号分隔,留空表示当前地图的全部物品都允许;被排除的 ID 优先。最多 128 个,主机设置。" },
		{ "EnemyDropLoot/BlockedItemIds", "这些物品 ID 不会出现在额外掉落里,英文逗号分隔,留空表示不排除任何物品。最多 128 个,主机设置。" }
	};

	private static readonly Dictionary<string, string> CommentsById = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
	{
		{ "Enabled", "启用或关闭该功能;关闭时不应用任何补丁。" },
		{ "Verbose", "向 MelonLoader 控制台输出额外诊断信息。" },
		{ "DebugPlaceholders", "用假玩家填满所有界面槽位,方便单人检查对齐与缩放。" },
		{ "DebugResultKey", "打开 16 人结算界面的调试热键,仅在开启占位玩家时有效。" },
		{ "ShowSlotLabel", "在每行右上角显示槽位序号,可选显示 SteamID。" },
		{ "ShowSteamId", "在槽位序号下方显示该玩家的 SteamID。" },
		{ "MenuColumns", "游戏内菜单玩家列表的列数(1–4),默认 2 列 × 8 行。" },
		{ "MenuScale", "菜单玩家列表的行缩放,0 表示自适应列表区域。" },
		{ "ResultColumns", "结算界面列数(1–8),默认 8 列 × 2 行容纳 16 人。" },
		{ "ResultScale", "结算界面列的缩放,0 表示自适应区域。" },
		{ "ResultTopOffset", "结算网格顶部微调(像素),正数下移、负数上移。" },
		{ "SpectatorColumns", "旁观玩家列表的列数(1–8),默认 2 列 × 8 行。" },
		{ "SpectatorScale", "旁观列表缩放,0 表示自适应。" },
		{ "SpectatorOffsetX", "旁观列表整体的水平偏移(像素)。" },
		{ "SpectatorOffsetY", "旁观列表整体的垂直偏移(像素,正数下移)。" },
		{ "SpectatorFillByColumn", "开启时先填满左列(1–8)再填右列;关闭则逐行填充。" },
		{ "ShowFullSpectatorName", "在旁观视角中央完整显示被旁观者名称,长名字不再截断。" },
		{ "MenuKey", "打开或关闭模组菜单的按键,填 KeyCode 名称,如 F9、F8、Insert。" },
		{ "MaxPlayers", "房间人数上限,超过原版 4 人时生效。" },
		{ "JumpVelocity", "起跳初速度(单位/秒),数值越大跳得越高。" },
		{ "ForceUngroundTime", "起跳后强制离地的时间(秒),避免立刻又被判定为落地。" },
		{ "AirGravityScale", "上升段的重力倍率,越小越飘;接近顶点会平滑恢复常规重力。" },
		{ "DebugLogs", "输出调试日志。" },
		{ "LandSettleSeconds", "再次触发强化跳跃前需要的持续着地时间(秒)。" },
		{ "ApexBlendSpeed", "接近顶点时恢复常规重力的速度阈值。" },
		{ "MaxAirGravitySeconds", "减重力效果的最长持续时间(秒)。" },
		{ "DropChance", "每次判定掉落成功的概率(0–1):0 表示完全不掉,1 表示每次都掉。" },
		{ "MaxDropsPerKill", "每击杀一个敌人最多判定几次掉落。" },
		{ "RemoveFakeItemDrops", "敌人死亡时不再掉出假物品,真实物品和额外掉落保留。主机设置。" },
		{ "AllowedItemIds", "只让这些物品 ID 掉出,英文逗号分隔,留空表示全部允许。主机设置。" },
		{ "BlockedItemIds", "这些物品 ID 不会出现在额外掉落里,英文逗号分隔,留空表示不排除。主机设置。" }
	};

	private static readonly Dictionary<string, string> ByIdentifier = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
	{
		{ "Enabled", "启用" },
		{ "Verbose", "详细日志" },
		{ "DebugPlaceholders", "调试占位玩家" },
		{ "DebugResultKey", "调试结算热键" },
		{ "ShowSlotLabel", "显示槽位序号" },
		{ "ShowSteamId", "显示 SteamID" },
		{ "MenuColumns", "菜单列数" },
		{ "MenuScale", "菜单行缩放" },
		{ "ResultColumns", "结算列数" },
		{ "ResultScale", "结算缩放" },
		{ "ResultTopOffset", "结算顶部偏移" },
		{ "SpectatorColumns", "旁观列表列数" },
		{ "SpectatorScale", "旁观列表缩放" },
		{ "SpectatorOffsetX", "旁观列表水平偏移" },
		{ "SpectatorOffsetY", "旁观列表垂直偏移" },
		{ "SpectatorFillByColumn", "旁观列表按列填充" },
		{ "ShowFullSpectatorName", "显示完整旁观者名称" },
		{ "MenuKey", "菜单热键" },
		{ "MaxPlayers", "最大玩家数" },
		{ "JumpVelocity", "起跳速度" },
		{ "ForceUngroundTime", "强制离地时间" },
		{ "AirGravityScale", "空中重力倍率" },
		{ "DebugLogs", "调试日志" },
		{ "LandSettleSeconds", "落地稳定时间" },
		{ "ApexBlendSpeed", "顶点过渡速度" },
		{ "MaxAirGravitySeconds", "减重力最长时间" },
		{ "DropChance", "掉落几率" },
		{ "MaxDropsPerKill", "每次击杀判定次数" },
		{ "RemoveFakeItemDrops", "过滤假物品掉落" },
		{ "AllowedItemIds", "仅允许的物品 ID" },
		{ "BlockedItemIds", "排除的物品 ID" }
	};

	private static readonly Dictionary<string, string> Words = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
	{
		{ "Enabled", "启用" },
		{ "Enable", "启用" },
		{ "Disabled", "禁用" },
		{ "Max", "最大" },
		{ "Min", "最小" },
		{ "Players", "玩家数" },
		{ "Player", "玩家" },
		{ "Count", "数量" },
		{ "Speed", "速度" },
		{ "Scale", "缩放" },
		{ "Size", "大小" },
		{ "Time", "时间" },
		{ "Seconds", "秒" },
		{ "Debug", "调试" },
		{ "Show", "显示" },
		{ "Hide", "隐藏" },
		{ "Offset", "偏移" },
		{ "Color", "颜色" },
		{ "Volume", "音量" },
		{ "Key", "按键" },
		{ "Mode", "模式" },
		{ "Sound", "音效" },
		{ "Music", "音乐" },
		{ "Distance", "距离" },
		{ "Height", "高度" },
		{ "Width", "宽度" },
		{ "Alpha", "透明度" },
		{ "Opacity", "不透明度" },
		{ "Delay", "延迟" },
		{ "Duration", "持续时间" },
		{ "Cooldown", "冷却" },
		{ "Damage", "伤害" },
		{ "Health", "生命" },
		{ "Item", "物品" },
		{ "Slot", "槽位" },
		{ "List", "列表" },
		{ "Button", "按钮" },
		{ "Menu", "菜单" },
		{ "Language", "语言" },
		{ "Value", "数值" },
		{ "Amount", "数量" },
		{ "Rate", "频率" },
		{ "Visible", "可见" },
		{ "Range", "范围" },
		{ "Limit", "上限" },
		{ "Type", "类型" }
	};

	internal static string CategoryName(string identifier, string fallback)
	{
		if (identifier != null && CategoryNames.TryGetValue(identifier, out var value))
		{
			return value;
		}
		return fallback;
	}

	internal static string EntryName(string category, string identifier, string fallback)
	{
		if (category != null && identifier != null && Names.TryGetValue(category + "/" + identifier, out var value))
		{
			return value;
		}
		if (identifier != null && ByIdentifier.TryGetValue(identifier, out value))
		{
			return value;
		}
		return TranslateWords(fallback);
	}

	internal static string Comment(string category, string identifier, string fallback)
	{
		if (category != null && identifier != null && Comments.TryGetValue(category + "/" + identifier, out var value))
		{
			return value;
		}
		if (identifier != null && CommentsById.TryGetValue(identifier, out value))
		{
			return value;
		}
		if (!HasCjk(fallback))
		{
			return string.Empty;
		}
		return fallback;
	}

	internal static bool HasCjk(string s)
	{
		if (string.IsNullOrEmpty(s))
		{
			return false;
		}
		foreach (char c in s)
		{
			if (c >= '一' && c <= '鿿')
			{
				return true;
			}
		}
		return false;
	}

	private static string TranslateWords(string text)
	{
		if (string.IsNullOrEmpty(text))
		{
			return text;
		}
		string[] array = text.Split(new char[1] { ' ' });
		StringBuilder stringBuilder = new StringBuilder();
		string[] array2 = array;
		foreach (string key in array2)
		{
			if (!Words.TryGetValue(key, out var value))
			{
				return text;
			}
			stringBuilder.Append(value);
		}
		return stringBuilder.ToString();
	}
}
internal static class MainMenuInjector
{
	private const string CloneName = "ModMenuButton";

	private static readonly string[] StartWords = new string[6] { "开始", "開始", "start", "play", "进入", "enter" };

	private static readonly string[] SettingsWords = new string[6] { "设置", "設置", "setting", "option", "选项", "選項" };

	private static bool _scanning;

	private static bool _hooked;

	internal static void Install()
	{
		if (!_hooked)
		{
			_hooked = true;
			try
			{
				SceneManager.sceneLoaded += OnSceneLoaded;
			}
			catch (Exception ex)
			{
				Instance log = ModMenuMod.Log;
				if (log != null)
				{
					log.Warning("监听场景加载失败: " + ex.Message);
				}
			}
		}
		TryStartScan();
	}

	private static void OnSceneLoaded(Scene scene, LoadSceneMode mode)
	{
		TryStartScan();
	}

	private static void TryStartScan()
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		if (!_scanning && IsMainMenu(SceneManager.GetActiveScene()))
		{
			MelonCoroutines.Start(ScanRoutine());
		}
	}

	private static IEnumerator ScanRoutine()
	{
		_scanning = true;
		for (int attempt = 0; attempt < 8; attempt++)
		{
			yield return (object)new WaitForSecondsRealtime(0.5f);
			if (!IsMainMenu(SceneManager.GetActiveScene()))
			{
				break;
			}
			bool flag = false;
			string text = null;
			try
			{
				flag = TryInjectByScan();
			}
			catch (Exception ex)
			{
				text = ex.Message;
			}
			if (text != null)
			{
				Instance log = ModMenuMod.Log;
				if (log != null)
				{
					log.Warning("扫描注入异常: " + text);
				}
			}
			if (flag)
			{
				Instance log2 = ModMenuMod.Log;
				if (log2 != null)
				{
					log2.Msg("主菜单「模组」入口就绪");
				}
				break;
			}
		}
		_scanning = false;
	}

	private static bool IsMainMenu(Scene scene)
	{
		string text = (((Scene)(ref scene)).name ?? string.Empty).ToLowerInvariant();
		if (!text.Contains("mainmenu"))
		{
			return text.Contains("title");
		}
		return true;
	}

	private static bool TryInjectByScan()
	{
		Button[] array = Object.FindObjectsByType<Button>((FindObjectsSortMode)0);
		if (array == null || array.Length == 0)
		{
			return false;
		}
		Transform val = null;
		List<Button> list = null;
		int num = 0;
		Dictionary<Transform, List<Button>> dictionary = new Dictionary<Transform, List<Button>>(8);
		foreach (Button val2 in array)
		{
			if ((Object)(object)val2 == (Object)null || !((Component)val2).gameObject.activeInHierarchy)
			{
				continue;
			}
			Transform parent = ((Component)val2).transform.parent;
			if (!((Object)(object)parent == (Object)null))
			{
				if (!dictionary.TryGetValue(parent, out var value))
				{
					value = (dictionary[parent] = new List<Button>(8));
				}
				value.Add(val2);
			}
		}
		foreach (KeyValuePair<Transform, List<Button>> item in dictionary)
		{
			if (item.Value.Count > num && (item.Value.Any((Button b) => ((Object)b).name.IndexOf("MenuTextButton", StringComparison.OrdinalIgnoreCase) >= 0) || item.Value.Any((Button b) => Matches(b, StartWords) || Matches(b, SettingsWords))))
			{
				num = item.Value.Count;
				val = item.Key;
				list = item.Value;
			}
		}
		if ((Object)(object)val == (Object)null || list == null)
		{
			return false;
		}
		if ((Object)(object)val.Find("ModMenuButton") != (Object)null)
		{
			return true;
		}
		list.Sort((Button a, Button b) => ((Component)a).transform.GetSiblingIndex().CompareTo(((Component)b).transform.GetSiblingIndex()));
		Button val3 = ((IEnumerable<Button>)list).FirstOrDefault((Func<Button, bool>)((Button b) => Matches(b, StartWords)));
		Button val4 = ((IEnumerable<Button>)list).FirstOrDefault((Func<Button, bool>)((Button b) => Matches(b, SettingsWords))) ?? list[list.Count - 1];
		if ((Object)(object)val4 == (Object)null)
		{
			return false;
		}
		Button val5 = val3 ?? list[0];
		Insert(val4, val5);
		Instance log = ModMenuMod.Log;
		if (log != null)
		{
			log.Msg("已在主菜单注入「模组」按钮(按钮组: " + ((Object)val).name + ",模板: " + ((Object)val4).name + ",锚点: " + (((Object)(object)val5 != (Object)null) ? ((Object)val5).name : "无") + ")");
		}
		return true;
	}

	private static void Insert(Button template, Button anchor)
	{
		//IL_0131: Unknown result type (might be due to invalid IL or missing references)
		//IL_013b: Expected O, but got Unknown
		//IL_0149: Unknown result type (might be due to invalid IL or missing references)
		//IL_0153: Expected O, but got Unknown
		//IL_0157: Unknown result type (might be due to invalid IL or missing references)
		//IL_0165: Unknown result type (might be due to invalid IL or missing references)
		//IL_01db: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_0209: Unknown result type (might be due to invalid IL or missing references)
		//IL_020e: Unknown result type (might be due to invalid IL or missing references)
		Transform parent = ((Component)template).transform.parent;
		if ((Object)(object)parent == (Object)null)
		{
			return;
		}
		Transform val = parent.Find("ModMenuButton");
		if ((Object)(object)val != (Object)null)
		{
			Object.DestroyImmediate((Object)(object)((Component)val).gameObject);
		}
		GameObject val2 = Object.Instantiate<GameObject>(((Component)template).gameObject, parent);
		((Object)val2).name = "ModMenuButton";
		val2.SetActive(false);
		MonoBehaviour[] componentsInChildren = val2.GetComponentsInChildren<MonoBehaviour>(true);
		foreach (MonoBehaviour val3 in componentsInChildren)
		{
			if (!((Object)(object)val3 == (Object)null))
			{
				string text = ((object)val3).GetType().Namespace ?? string.Empty;
				if (!text.StartsWith("UnityEngine") && !text.StartsWith("TMPro"))
				{
					Object.DestroyImmediate((Object)(object)val3);
				}
			}
		}
		MonoBehaviour val4 = ((IEnumerable<MonoBehaviour>)val2.GetComponentsInChildren<MonoBehaviour>(true)).FirstOrDefault((Func<MonoBehaviour, bool>)((MonoBehaviour c) => (Object)(object)c != (Object)null && ((object)c).GetType().Name.IndexOf("TextMeshPro", StringComparison.Ordinal) >= 0));
		if ((Object)(object)val4 != (Object)null)
		{
			PropertyInfo property = ((object)val4).GetType().GetProperty("text", BindingFlags.Instance | BindingFlags.Public);
			if (property != null)
			{
				property.SetValue(val4, "模组", null);
			}
		}
		Button component = val2.GetComponent<Button>();
		if ((Object)(object)component != (Object)null)
		{
			component.onClick = new ButtonClickedEvent();
			((UnityEvent)component.onClick).AddListener(new UnityAction(ModMenuMod.OpenMenu));
			Navigation navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)0;
			((Selectable)component).navigation = navigation;
		}
		Transform val5 = (((Object)(object)anchor != (Object)null) ? ((Component)anchor).transform : ((Component)template).transform);
		val2.transform.SetSiblingIndex(val5.GetSiblingIndex());
		if ((Object)(object)((Component)parent).GetComponent<LayoutGroup>() != (Object)null)
		{
			LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform)(object)((parent is RectTransform) ? parent : null));
		}
		else
		{
			RectTransform component2 = ((Component)val5).GetComponent<RectTransform>();
			RectTransform component3 = val2.GetComponent<RectTransform>();
			if ((Object)(object)component2 != (Object)null && (Object)(object)component3 != (Object)null)
			{
				component3.sizeDelta = component2.sizeDelta;
				Vector2 anchoredPosition = component2.anchoredPosition;
				Rect rect = component2.rect;
				component3.anchoredPosition = anchoredPosition + new Vector2(0f, ((Rect)(ref rect)).height + 12f);
			}
		}
		val2.SetActive(true);
	}

	private static bool Matches(Button b, string[] words)
	{
		string label = GetLabel((Component)(object)b);
		if (string.IsNullOrEmpty(label))
		{
			return false;
		}
		string text = label.ToLowerInvariant();
		for (int i = 0; i < words.Length; i++)
		{
			if (text.Contains(words[i]))
			{
				return true;
			}
		}
		return false;
	}

	private static string GetLabel(Component c)
	{
		MonoBehaviour[] componentsInChildren = c.GetComponentsInChildren<MonoBehaviour>(true);
		foreach (MonoBehaviour val in componentsInChildren)
		{
			if (!((Object)(object)val == (Object)null) && ((object)val).GetType().Name.IndexOf("TextMeshPro", StringComparison.Ordinal) >= 0)
			{
				string text = ((object)val).GetType().GetProperty("text", BindingFlags.Instance | BindingFlags.Public)?.GetValue(val, null) as string;
				if (!string.IsNullOrEmpty(text))
				{
					return text.Trim();
				}
			}
		}
		return null;
	}
}
internal static class MenuUI
{
	internal const float W = 1120f;

	internal const float H = 700f;

	private const float HeaderH = 62f;

	private const float FooterH = 58f;

	private const float SidebarW = 252f;

	private const float RowH = 60f;

	private const float SectionH = 28f;

	internal static bool Visible;

	private static Rect _window = new Rect(0f, 0f, 1120f, 700f);

	private static bool _initialized;

	private static Vector2 _sideScroll;

	private static Vector2 _contentScroll;

	private static string _search = string.Empty;

	private static ModCategory _selected;

	private static bool _confirmClose;

	private static string _status = string.Empty;

	private static float _statusUntil;

	private static readonly Dictionary<string, string> _buffers = new Dictionary<string, string>();

	private static int _lastToggleFrame = -1;

	private static bool _prevCursorVisible;

	private static CursorLockMode _prevLockState;

	private static int _openFrame = -10;

	private static bool _warmupPending;

	private static string _cachedSearch;

	private static List<ModEntry> _searchHits;

	private static string _headerSub;

	private static bool InputBlocked => Time.frameCount <= _openFrame + 1;

	internal static void Toggle()
	{
		if (Time.frameCount != _lastToggleFrame)
		{
			_lastToggleFrame = Time.frameCount;
			if (Visible)
			{
				Close();
			}
			else
			{
				Open();
			}
		}
	}

	internal static void Open()
	{
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		string prevId = ((_selected != null) ? _selected.Identifier : null);
		ConfigModel.Refresh();
		_selected = ConfigModel.Categories.FirstOrDefault((ModCategory c) => c.Identifier == prevId) ?? ConfigModel.Categories.FirstOrDefault();
		_contentScroll = Vector2.zero;
		_sideScroll = Vector2.zero;
		_search = string.Empty;
		_confirmClose = false;
		_status = string.Empty;
		_buffers.Clear();
		_searchHits = null;
		_headerSub = null;
		_warmupPending = true;
		Visible = true;
		_openFrame = Time.frameCount;
		_prevCursorVisible = Cursor.visible;
		_prevLockState = Cursor.lockState;
		Cursor.visible = true;
		Cursor.lockState = (CursorLockMode)0;
		Instance log = ModMenuMod.Log;
		if (log != null)
		{
			log.Msg("菜单已打开:共 " + ConfigModel.Categories.Count + " 个分类 / " + ConfigModel.EntryCount + " 项配置");
		}
	}

	internal static void Close()
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		Visible = false;
		_confirmClose = false;
		_buffers.Clear();
		Cursor.visible = _prevCursorVisible;
		Cursor.lockState = _prevLockState;
	}

	internal static void Draw()
	{
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_0109: Unknown result type (might be due to invalid IL or missing references)
		//IL_010e: Unknown result type (might be due to invalid IL or missing references)
		//IL_011a: Unknown result type (might be due to invalid IL or missing references)
		//IL_011f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0135: Unknown result type (might be due to invalid IL or missing references)
		//IL_013a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0149: Unknown result type (might be due to invalid IL or missing references)
		//IL_0155: Unknown result type (might be due to invalid IL or missing references)
		//IL_0169: Expected O, but got Unknown
		//IL_0164: Unknown result type (might be due to invalid IL or missing references)
		//IL_0169: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		if (!Visible)
		{
			return;
		}
		Theme.Ensure();
		if (Event.current != null)
		{
			if (_warmupPending)
			{
				_warmupPending = false;
				WarmupFonts();
			}
			HandleKeys();
			float num = Mathf.Clamp(Mathf.Min((float)Screen.width / 1440f, (float)Screen.height / 900f), 0.75f, 2f);
			float num2 = (float)Screen.width / num;
			float num3 = (float)Screen.height / num;
			if (!_initialized)
			{
				_window = new Rect((num2 - 1120f) * 0.5f, (num3 - 700f) * 0.5f, 1120f, 700f);
				_initialized = true;
			}
			((Rect)(ref _window)).x = Mathf.Clamp(((Rect)(ref _window)).x, 0f, Mathf.Max(0f, num2 - 1120f));
			((Rect)(ref _window)).y = Mathf.Clamp(((Rect)(ref _window)).y, 0f, Mathf.Max(0f, num3 - 700f));
			Matrix4x4 matrix = GUI.matrix;
			GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(num, num, 1f));
			Theme.Rect(new Rect(0f, 0f, num2, num3), Theme.Dim);
			_window = GUI.Window(5066061, _window, new WindowFunction(DrawWindow), GUIContent.none, Theme.Window);
			GUI.matrix = matrix;
		}
	}

	private static void HandleKeys()
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Invalid comparison between Unknown and I4
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Invalid comparison between Unknown and I4
		Event current = Event.current;
		if (current != null && (int)current.type == 4 && GUIUtility.keyboardControl == 0 && (int)current.keyCode == 27)
		{
			if (ChangeSet.Count > 0 && !_confirmClose)
			{
				_confirmClose = true;
			}
			else
			{
				Close();
			}
			current.Use();
		}
	}

	private static void DrawWindow(int id)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: 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)
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		Theme.Rect(new Rect(0f, 0f, 1120f, 700f), Theme.WindowBg);
		Theme.RectOutline(new Rect(0f, 0f, 1120f, 700f), Theme.Line);
		DrawHeader();
		DrawSidebar();
		DrawContent();
		DrawFooter();
		if ((int)Event.current.type == 0)
		{
			Rect val = new Rect(0f, 0f, 1120f, 62f);
			if (((Rect)(ref val)).Contains(Event.current.mousePosition))
			{
				GUI.DragWindow(new Rect(0f, 0f, 800f, 62f));
			}
		}
	}

	private static void DrawHeader()
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_015b: Unknown result type (might be due to invalid IL or missing references)
		//IL_013d: Unknown result type (might be due to invalid IL or missing references)
		//IL_019f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_0186: Unknown result type (might be due to invalid IL or missing references)
		Theme.Rect(new Rect(0f, 0f, 1120f, 62f), Theme.HeaderBg);
		Theme.Rect(new Rect(0f, 61f, 1120f, 1f), Theme.Line);
		Theme.Rect(new Rect(0f, 12f, 3f, 38f), Theme.Accent);
		Theme.LabelShadow(new Rect(22f, 11f, 520f, 26f), "模组菜单", Theme.Title);
		GUI.Label(new Rect(23f, 36f, 560f, 18f), _headerSub ?? (_headerSub = "MIMESIS · 运行时配置 · 共 " + ConfigModel.EntryCount + " 项"), Theme.Subtitle);
		Rect val = default(Rect);
		((Rect)(ref val))..ctor(824f, 17f, 218f, 28f);
		Theme.Rect(val, Theme.PanelBg);
		if (string.IsNullOrEmpty(_search))
		{
			GUI.Label(new Rect(((Rect)(ref val)).x + 10f, ((Rect)(ref val)).y + 5f, ((Rect)(ref val)).width - 16f, 20f), "搜索配置项…", Theme.Subtitle);
		}
		GUI.SetNextControlName("mm_search");
		string text = GUI.TextField(val, _search, 64, Theme.Field);
		if (text != _search)
		{
			_search = text;
			_contentScroll = Vector2.zero;
		}
		if (CloseButton(new Rect(1068f, 17f, 28f, 28f)))
		{
			if (ChangeSet.Count > 0 && !_confirmClose)
			{
				_confirmClose = true;
			}
			else
			{
				Close();
			}
		}
	}

	private static void DrawSidebar()
	{
		//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)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0105: Unknown result type (might be due to invalid IL or missing references)
		//IL_0107: Unknown result type (might be due to invalid IL or missing references)
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0110: Unknown result type (might be due to invalid IL or missing references)
		//IL_0115: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_015c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0177: Unknown result type (might be due to invalid IL or missing references)
		//IL_0179: Unknown result type (might be due to invalid IL or missing references)
		//IL_0189: Unknown result type (might be due to invalid IL or missing references)
		//IL_018b: Unknown result type (might be due to invalid IL or missing references)
		//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_01af: Unknown result type (might be due to invalid IL or missing references)
		//IL_020b: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0316: Unknown result type (might be due to invalid IL or missing references)
		//IL_031b: Unknown result type (might be due to invalid IL or missing references)
		float num = 62f;
		float num2 = 642f;
		Theme.Rect(new Rect(0f, num, 252f, num2 - num), Theme.SidebarBg);
		Theme.Rect(new Rect(251f, num, 1f, num2 - num), Theme.Line);
		GUI.Label(new Rect(18f, num + 12f, 200f, 18f), "分类", Theme.SectionLabel);
		float num3 = num + 36f;
		float num4 = num2 - num3 - 12f;
		Rect val = default(Rect);
		((Rect)(ref val))..ctor(6f, num3, 240f, num4);
		if (ConfigModel.Categories.Count == 0)
		{
			GUI.Label(new Rect(18f, num3 + 6f, 210f, 40f), "未发现任何 MelonPreferences 分类。", Theme.Subtitle);
			return;
		}
		float num5 = (float)ConfigModel.Categories.Count * 52f + 8f;
		Rect val2 = default(Rect);
		((Rect)(ref val2))..ctor(0f, 0f, ((Rect)(ref val)).width - 17f, num5);
		_sideScroll = GUI.BeginScrollView(val, _sideScroll, val2, false, false);
		float num6 = 4f;
		Rect val3 = default(Rect);
		foreach (ModCategory category in ConfigModel.Categories)
		{
			((Rect)(ref val3))..ctor(0f, num6, ((Rect)(ref val2)).width, 46f);
			bool flag = ((Rect)(ref val3)).Contains(Event.current.mousePosition);
			bool flag2 = category == _selected;
			if (flag2)
			{
				Theme.Rect(val3, Theme.RowBg);
			}
			else if (flag)
			{
				Theme.Rect(val3, Theme.RowHover);
			}
			if (flag2)
			{
				Theme.Rect(new Rect(0f, num6, 3f, 46f), Theme.Accent);
			}
			if (category.NameWidth != ((Rect)(ref val2)).width)
			{
				category.NameWidth = ((Rect)(ref val2)).width;
				category.NameShort = Ellipsis(category.DisplayName, 17);
			}
			GUI.Label(new Rect(14f, num6 + 7f, ((Rect)(ref val2)).width - 60f, 20f), category.NameShort ?? category.DisplayName, flag2 ? Theme.SideNameOn : Theme.SideNameOff);
			int pendingCount = category.PendingCount;
			if (category.SubVersion != ChangeSet.Version)
			{
				category.SubVersion = ChangeSet.Version;
				category.SubText = ((pendingCount > 0) ? (category.Entries.Count + " 项 · " + pendingCount + " 项待保存") : (category.Entries.Count + " 项"));
			}
			GUI.Label(new Rect(14f, num6 + 26f, ((Rect)(ref val2)).width - 24f, 16f), category.SubText ?? string.Empty, (pendingCount > 0) ? Theme.SideSubDirty : Theme.SideSubFaint);
			if (GUI.Button(val3, GUIContent.none, GUIStyle.none))
			{
				_selected = category;
				_contentScroll = Vector2.zero;
				_search = string.Empty;
			}
			num6 += 52f;
		}
		GUI.EndScrollView();
	}

	private static void DrawContent()
	{
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		float num = 272f;
		float num2 = 78f;
		float num3 = 1120f - num - 22f;
		float num4 = 642f - num2 - 14f;
		bool num5 = !string.IsNullOrEmpty(_search);
		string text = (num5 ? "搜索结果" : ((_selected != null) ? _selected.DisplayName : "未选择分类"));
		GUI.Label(new Rect(num, num2, num3 - 240f, 26f), text, Theme.Title);
		if (!num5 && _selected != null && LinkButton(new Rect(num + num3 - 118f, num2 + 2f, 118f, 24f), "恢复本类默认"))
		{
			ChangeSet.ResetCategory(_selected);
			SetStatus("已将 " + _selected.DisplayName + " 重置为默认值(待保存)");
		}
		float num6 = num2 + 38f;
		float num7 = num4 - 38f;
		Rect view = default(Rect);
		((Rect)(ref view))..ctor(num, num6, num3, num7);
		if (num5)
		{
			DrawSearchResults(view);
		}
		else
		{
			DrawCategoryEntries(view);
		}
	}

	private static void DrawCategoryEntries(Rect view)
	{
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		if (_selected == null || _selected.Entries.Count == 0)
		{
			GUI.Label(new Rect(((Rect)(ref view)).x, ((Rect)(ref view)).y + 8f, ((Rect)(ref view)).width, 24f), "该分类没有可显示的配置项。", Theme.Subtitle);
			return;
		}
		float num = (float)_selected.Entries.Count * 60f + 10f;
		Rect val = default(Rect);
		((Rect)(ref val))..ctor(0f, 0f, ((Rect)(ref view)).width - 19f, num);
		_contentScroll = GUI.BeginScrollView(view, _contentScroll, val, false, false);
		List<ModEntry> entries = _selected.Entries;
		float y = _contentScroll.y;
		float num2 = y + ((Rect)(ref view)).height;
		int num3 = Mathf.Max(0, Mathf.FloorToInt((y - 2f) / 60f) - 1);
		int num4 = Mathf.Min(entries.Count - 1, Mathf.CeilToInt((num2 - 2f) / 60f) + 1);
		for (int i = num3; i <= num4; i++)
		{
			DrawRow(((Rect)(ref val)).width, 2f + (float)i * 60f, entries[i]);
		}
		GUI.EndScrollView();
	}

	private static void DrawSearchResults(Rect view)
	{
		//IL_0112: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_022c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0266: Unknown result type (might be due to invalid IL or missing references)
		//IL_026b: Unknown result type (might be due to invalid IL or missing references)
		if (_searchHits == null || !string.Equals(_cachedSearch, _search, StringComparison.Ordinal))
		{
			_cachedSearch = _search;
			List<ModEntry> list = new List<ModEntry>();
			foreach (ModCategory category in ConfigModel.Categories)
			{
				foreach (ModEntry entry in category.Entries)
				{
					if (entry.Name.IndexOf(_search, StringComparison.OrdinalIgnoreCase) >= 0 || entry.Identifier.IndexOf(_search, StringComparison.OrdinalIgnoreCase) >= 0 || category.DisplayName.IndexOf(_search, StringComparison.OrdinalIgnoreCase) >= 0)
					{
						list.Add(entry);
					}
				}
			}
			_searchHits = list;
		}
		List<ModEntry> searchHits = _searchHits;
		if (searchHits.Count == 0)
		{
			GUI.Label(new Rect(((Rect)(ref view)).x, ((Rect)(ref view)).y + 8f, ((Rect)(ref view)).width, 24f), "没有匹配「" + _search + "」的配置项。", Theme.Subtitle);
			return;
		}
		float num = 10f;
		string text = null;
		foreach (ModEntry item in searchHits)
		{
			if (text != item.Category.Identifier)
			{
				num += 28f;
				text = item.Category.Identifier;
			}
			num += 60f;
		}
		Rect val = default(Rect);
		((Rect)(ref val))..ctor(0f, 0f, ((Rect)(ref view)).width - 19f, num);
		_contentScroll = GUI.BeginScrollView(view, _contentScroll, val, false, false);
		float num2 = 2f;
		text = null;
		foreach (ModEntry item2 in searchHits)
		{
			if (text != item2.Category.Identifier)
			{
				text = item2.Category.Identifier;
				GUI.Label(new Rect(6f, num2 + 6f, ((Rect)(ref val)).width - 20f, 18f), item2.Category.DisplayName, Theme.SectionLabel);
				Theme.Rect(new Rect(6f, num2 + 24f, ((Rect)(ref val)).width - 20f, 1f), Theme.Line);
				num2 += 28f;
			}
			DrawRow(((Rect)(ref val)).width, num2, item2);
			num2 += 60f;
		}
		GUI.EndScrollView();
	}

	private static void DrawRow(float width, float y, ModEntry entry)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_015c: Unknown result type (might be due to invalid IL or missing references)
		//IL_019d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_0129: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
		Rect r = default(Rect);
		((Rect)(ref r))..ctor(0f, y, width, 54f);
		bool flag = ((Rect)(ref r)).Contains(Event.current.mousePosition);
		bool num = ChangeSet.IsDirty(entry);
		Theme.Rect(r, flag ? Theme.RowHover : Theme.RowBg);
		if (num)
		{
			Theme.Rect(new Rect(0f, ((Rect)(ref r)).y, 2f, ((Rect)(ref r)).height), Theme.Warn);
		}
		float num2 = Mathf.Round(width * 0.47f);
		float num3 = num2 - 26f;
		if (entry.NameWidth != num3)
		{
			entry.NameWidth = num3;
			entry.NameShort = Ellipsis(entry.Name, FitChars(num3, 15f));
			entry.DescWidth = num3;
			entry.DescShort = Ellipsis(entry.Comment, FitChars(num3, 13f));
		}
		GUI.Label(new Rect(14f, ((Rect)(ref r)).y + 7f, num3, 20f), entry.NameShort ?? entry.Name, Theme.NameStyle);
		if (!string.IsNullOrEmpty(entry.DescShort))
		{
			GUI.Label(new Rect(14f, ((Rect)(ref r)).y + 29f, num3, 17f), entry.DescShort, Theme.DescStyle);
		}
		GUI.Label(new Rect(num2 - 82f, ((Rect)(ref r)).y + 8f, 76f, 16f), entry.TypeLabel, Theme.BadgeStyle);
		float num4 = 22f;
		Rect r2 = new Rect(num2 + 10f, ((Rect)(ref r)).y + 15f, width - num2 - num4 - 44f, 28f);
		if (Clickable(new Rect(width - 32f, ((Rect)(ref r)).y + 17f, num4, num4)))
		{
			ChangeSet.ResetEntry(entry);
			SetStatus("已重置:" + entry.Name);
		}
		GUI.Label(new Rect(width - 32f, ((Rect)(ref r)).y + 17f, num4, num4), "↺", Theme.Subtitle);
		DrawControl(r2, entry);
	}

	private static int FitChars(float widthPx, float fontSize)
	{
		return Mathf.Clamp(Mathf.FloorToInt(widthPx / (fontSize * 0.95f)), 6, 120);
	}

	private static string NumText(ModEntry e, double v, string fmt)
	{
		if (e.NumText == null || e.NumTextValue != v || e.NumFmt != fmt)
		{
			e.NumTextValue = v;
			e.NumFmt = fmt;
			e.NumText = v.ToString(fmt, CultureInfo.InvariantCulture);
		}
		return e.NumText;
	}

	private static void DrawControl(Rect r, ModEntry entry)
	{
		//IL_0094: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0285: Unknown result type (might be due to invalid IL or missing references)
		//IL_017e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_0379: Unknown result type (might be due to invalid IL or missing references)
		//IL_037e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0371: Unknown result type (might be due to invalid IL or missing references)
		//IL_0383: Unknown result type (might be due to invalid IL or missing references)
		//IL_0395: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_03db: Unknown result type (might be due to invalid IL or missing references)
		//IL_03fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_0444: Unknown result type (might be due to invalid IL or missing references)
		//IL_0449: Unknown result type (might be due to invalid IL or missing references)
		//IL_046e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0473: Unknown result type (might be due to invalid IL or missing references)
		//IL_04a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_059f: Unknown result type (might be due to invalid IL or missing references)
		//IL_05a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_05b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_07b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_05c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_05cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_05dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_05e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0508: Unknown result type (might be due to invalid IL or missing references)
		//IL_04f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_04f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_05fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_05ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0604: Unknown result type (might be due to invalid IL or missing references)
		//IL_060f: Unknown result type (might be due to invalid IL or missing references)
		//IL_061a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0625: Unknown result type (might be due to invalid IL or missing references)
		//IL_0673: Unknown result type (might be due to invalid IL or missing references)
		//IL_06fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_072c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0780: Unknown result type (might be due to invalid IL or missing references)
		//IL_075f: Unknown result type (might be due to invalid IL or missing references)
		Type valueType = entry.ValueType;
		object obj = ChangeSet.Current(entry);
		if (valueType == typeof(bool))
		{
			bool flag = default(bool);
			int num;
			if (obj is bool)
			{
				flag = (bool)obj;
				num = 1;
			}
			else
			{
				num = 0;
			}
			bool flag2 = (byte)((uint)num & (flag ? 1u : 0u)) != 0;
			if (Toggle(new Rect(((Rect)(ref r)).x, ((Rect)(ref r)).y + 2f, 100f, 24f), flag2))
			{
				ChangeSet.Set(entry, !flag2);
			}
		}
		else if (valueType == typeof(string))
		{
			string text = (obj as string) ?? string.Empty;
			string text2 = TextField(r, text, entry, 0);
			if ((object)text2 != text && text2 != text)
			{
				ChangeSet.Set(entry, text2);
			}
		}
		else if (valueType.IsEnum)
		{
			string[] names = Enum.GetNames(valueType);
			if (names.Length != 0)
			{
				string value = Convert.ToString(obj, CultureInfo.InvariantCulture);
				int num2 = Array.IndexOf(names, value);
				if (num2 < 0)
				{
					num2 = 0;
				}
				int num3 = Cycler(r, names, num2);
				if (num3 != num2)
				{
					ChangeSet.Set(entry, Enum.Parse(valueType, names[num3]));
				}
			}
		}
		else if (ChangeSet.IsNumeric(obj) && IsIntegral(valueType))
		{
			double num4 = Convert.ToDouble(obj, CultureInfo.InvariantCulture);
			NumericRange(num4, out var min, out var max);
			min = Math.Round(min);
			max = Math.Round(max);
			double result = num4;
			if (Slider(new Rect(((Rect)(ref r)).x, ((Rect)(ref r)).y + 2f, ((Rect)(ref r)).width - 92f, 24f), num4, min, max, integer: true, ref result))
			{
				ChangeSet.Set(entry, ConfigModel.Coerce(Math.Round(result), valueType));
			}
			if (double.TryParse(NumberField(new Rect(((Rect)(ref r)).x + ((Rect)(ref r)).width - 84f, ((Rect)(ref r)).y, 84f, 26f), NumText(entry, num4, "0"), entry, 1), NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) && Math.Abs(result2 - num4) > 1E-06)
			{
				double a = Clamp(result2, min, max);
				ChangeSet.Set(entry, ConfigModel.Coerce(Math.Round(a), valueType));
			}
		}
		else if (ChangeSet.IsNumeric(obj))
		{
			double num5 = Convert.ToDouble(obj, CultureInfo.InvariantCulture);
			NumericRange(num5, out var min2, out var max2);
			double result3 = num5;
			if (Slider(new Rect(((Rect)(ref r)).x, ((Rect)(ref r)).y + 2f, ((Rect)(ref r)).width - 92f, 24f), num5, min2, max2, integer: false, ref result3))
			{
				ChangeSet.Set(entry, ConfigModel.Coerce((float)result3, valueType));
			}
			if (double.TryParse(NumberField(new Rect(((Rect)(ref r)).x + ((Rect)(ref r)).width - 84f, ((Rect)(ref r)).y, 84f, 26f), NumText(entry, num5, "0.###"), entry, 1), NumberStyles.Float, CultureInfo.InvariantCulture, out var result4) && Math.Abs(result4 - num5) > 1E-06)
			{
				double num6 = Clamp(result4, min2, max2);
				ChangeSet.Set(entry, ConfigModel.Coerce((float)num6, valueType));
			}
		}
		else if (valueType == typeof(Color) || valueType == typeof(Color32))
		{
			Color val = (Color)((valueType == typeof(Color32)) ? Color32.op_Implicit((Color32)obj) : ((Color)obj));
			string text3 = "#" + Mathf.RoundToInt(val.r * 255f).ToString("X2") + Mathf.RoundToInt(val.g * 255f).ToString("X2") + Mathf.RoundToInt(val.b * 255f).ToString("X2") + Mathf.RoundToInt(val.a * 255f).ToString("X2");
			Theme.Rect(new Rect(((Rect)(ref r)).x, ((Rect)(ref r)).y + 3f, 26f, 22f), val);
			Theme.RectOutline(new Rect(((Rect)(ref r)).x, ((Rect)(ref r)).y + 3f, 26f, 22f), Theme.Line);
			string text4 = TextField(new Rect(((Rect)(ref r)).x + 34f, ((Rect)(ref r)).y, 120f, 26f), text3, entry, 2);
			Color val2 = default(Color);
			if (text4 != text3 && ColorUtility.TryParseHtmlString(text4.StartsWith("#") ? text4 : ("#" + text4), ref val2))
			{
				if (valueType == typeof(Color32))
				{
					ChangeSet.Set(entry, Color32.op_Implicit(val2));
				}
				else
				{
					ChangeSet.Set(entry, val2);
				}
			}
		}
		else if (valueType == typeof(Vector2) || valueType == typeof(Vector3) || valueType == typeof(Vector4) || valueType == typeof(Quaternion))
		{
			int num7 = ((valueType == typeof(Vector2)) ? 2 : ((valueType == typeof(Vector3)) ? 3 : 4));
			float[] array = new float[num7];
			if (obj is Vector2 val3)
			{
				array[0] = val3.x;
				array[1] = val3.y;
			}
			else if (obj is Vector3 val4)
			{
				array[0] = val4.x;
				array[1] = val4.y;
				array[2] = val4.z;
			}
			else if (obj is Vector4 val5)
			{
				array[0] = val5.x;
				array[1] = val5.y;
				array[2] = val5.z;
				array[3] = val5.w;
			}
			float num8 = (((Rect)(ref r)).width - (float)(num7 - 1) * 6f) / (float)num7;
			bool flag3 = false;
			for (int i = 0; i < num7; i++)
			{
				if (float.TryParse(NumberField(new Rect(((Rect)(ref r)).x + (float)i * (num8 + 6f), ((Rect)(ref r)).y, num8, 26f), array[i].ToString("0.###", CultureInfo.InvariantCulture), entry, 10 + i), NumberStyles.Float, CultureInfo.InvariantCulture, out var result5) && Math.Abs(result5 - array[i]) > 1E-05f)
				{
					array[i] = result5;
					flag3 = true;
				}
			}
			if (flag3)
			{
				if (valueType == typeof(Vector2))
				{
					ChangeSet.Set(entry, (object)new Vector2(array[0], array[1]));
				}
				else if (valueType == typeof(Vector3))
				{
					ChangeSet.Set(entry, (object)new Vector3(array[0], array[1], array[2]));
				}
				else if (valueType == typeof(Vector4))
				{
					ChangeSet.Set(entry, (object)new Vector4(array[0], array[1], array[2], array[3]));
				}
				else
				{
					ChangeSet.Set(entry, (object)new Quaternion(array[0], array[1], array[2], array[3]));
				}
			}
		}
		else
		{
			GUI.Label(new Rect(((Rect)(ref r)).x, ((Rect)(ref r)).y + 4f, ((Rect)(ref r)).width, 20f), "暂不支持此类型(" + valueType.Name + ")", Theme.Subtitle);
		}
	}

	private static void DrawFooter()
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0197: Unknown result type (might be due to invalid IL or missing references)
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0136: Unknown result type (might be due to invalid IL or missing references)
		//IL_0239: Unknown result type (might be due to invalid IL or missing references)
		//IL_0169: Unknown result type (might be due to invalid IL or missing references)
		//IL_027f: Unknown result type (might be due to invalid IL or missing references)
		float num = 642f;
		Theme.Rect(new Rect(0f, num, 1120f, 58f), Theme.HeaderBg);
		Theme.Rect(new Rect(0f, num, 1120f, 1f), Theme.Line);
		int count = ChangeSet.Count;
		string text = ((count <= 0) ? ((Time.unscaledTime < _statusUntil && !string.IsNullOrEmpty(_status)) ? _status : "所有修改已保存") : (string.IsNullOrEmpty(_status) ? ("有 " + count + " 项修改未保存") : _status));
		GUIStyle val = ((count > 0) ? Theme.SideSubDirty : Theme.DescStyle);
		GUI.Label(new Rect(22f, num + 20f, 520f, 20f), (count > 0) ? ("● " + text) : ("○ " + text), val);
		if (_confirmClose)
		{
			GUI.Label(new Rect(650f, num + 20f, 180f, 20f), "未保存的修改将丢失", Theme.Subtitle);
			if (PrimaryButton(new Rect(852f, num + 13f, 118f, 32f), "放弃并关闭", enabled: false, danger: true))
			{
				ChangeSet.Revert();
				Close();
			}
			if (GhostButton(new Rect(978f, num + 13f, 64f, 32f), "返回"))
			{
				_confirmClose = false;
			}
			return;
		}
		if (PrimaryButton(new Rect(716f, num + 13f, 96f, 32f), "保存", ChangeSet.Count > 0, danger: false))
		{
			ChangeSet.Apply(out var applied, out var failed);
			SetStatus((failed == 0) ? ("已保存 " + applied + " 项到 MelonPreferences") : ("已保存 " + applied + " 项," + failed + " 项失败"));
			_statusUntil = Time.unscaledTime + 6f;
		}
		if (GhostButton(new Rect(820f, num + 13f, 96f, 32f), "还原"))
		{
			ChangeSet.Revert();
			SetStatus("已放弃本次修改");
			_statusUntil = Time.unscaledTime + 4f;
		}
		if (GhostButton(new Rect(924f, num + 13f, 96f, 32f), "关闭"))
		{
			if (ChangeSet.Count > 0)
			{
				_confirmClose = true;
			}
			else
			{
				Close();
			}
		}
	}

	private static bool Toggle(Rect r, bool value)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		bool result = Clickable(r);
		Rect r2 = default(Rect);
		((Rect)(ref r2))..ctor(((Rect)(ref r)).x, ((Rect)(ref r)).y + 2f, 48f, 24f);
		Theme.Rect(r2, value ? Theme.AccentDark : Theme.TrackBg);
		Theme.RectOutline(r2, value ? Theme.Accent : Theme.Line);
		float num = 18f;
		Theme.Rect(new Rect(value ? (((Rect)(ref r2)).xMax - num - 3f) : (((Rect)(ref r2)).x + 3f), ((Rect)(ref r2)).y + 3f, num, num), value ? Theme.Accent : Theme.TextFaint);
		GUI.Label(new Rect(((Rect)(ref r2)).xMax + 8f, ((Rect)(ref r)).y + 2f, 40f, 24f), value ? "开" : "关", value ? Theme.AccentText : Theme.SideSubFaint);
		return result;
	}

	private static bool Slider(Rect r, double value, double min, double max, bool integer, ref double result)
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Expected I4, but got Unknown
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_013e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0143: Unknown result type (might be due to invalid IL or missing references)
		//IL_0189: Unknown result type (might be due to invalid IL or missing references)
		//IL_018e: Unknown result type (might be due to invalid IL or missing references)
		int controlID = GUIUtility.GetControlID((FocusType)2);
		Event current = Event.current;
		bool flag = false;
		EventType typeForControl = current.GetTypeForControl(controlID);
		switch ((int)typeForControl)
		{
		case 0:
			if (!InputBlocked && ((Rect)(ref r)).Contains(current.mousePosition))
			{
				GUIUtility.hotControl = controlID;
				result = FromX(r, current.mousePosition.x, min, max, integer);
				flag = true;
				current.Use();
			}
			break;
		case 3:
			if (GUIUtility.hotControl == controlID)
			{
				result = FromX(r, current.mousePosition.x, min, max, integer);
				flag = true;
				current.Use();
			}
			break;
		case 1:
			if (GUIUtility.hotControl == controlID)
			{
				GUIUtility.hotControl = 0;
				current.Use();
			}
			break;
		}
		float num = Mathf.Clamp01((float)(((flag ? result : value) - min) / Math.Max(1E-09, max - min)));
		Theme.Rect(new Rect(((Rect)(ref r)).x, ((Rect)(ref r)).y + ((Rect)(ref r)).height * 0.5f - 2f, ((Rect)(ref r)).width, 4f), Theme.TrackBg);
		Theme.Rect(new Rect(((Rect)(ref r)).x, ((Rect)(ref r)).y + ((Rect)(ref r)).height * 0.5f - 2f, ((Rect)(ref r)).width * num, 4f), Theme.Accent);
		Theme.Rect(new Rect(((Rect)(ref r)).x + ((Rect)(ref r)).width * num - 5f, ((Rect)(ref r)).y + ((Rect)(ref r)).height * 0.5f - 5f, 10f, 10f), Theme.Text);
		return flag;
	}

	private static double FromX(Rect r, float mouseX, double min, double max, bool integer)
	{
		float num = Mathf.Clamp01((mouseX - ((Rect)(ref r)).x) / Math.Max(1f, ((Rect)(ref r)).width));
		double num2 = min + (double)num * (max - min);
		if (integer)
		{
			num2 = Math.Round(num2);
		}
		return num2;
	}

	private static int Cycler(Rect r, string[] options, int index)
	{
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: 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_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0109: Unknown result type (might be due to invalid IL or missing references)
		//IL_010a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0119: Unknown result type (might be due to invalid IL or missing references)
		float num = 24f;
		float num2 = Mathf.Min(((Rect)(ref r)).width, 340f);
		Rect val = default(Rect);
		((Rect)(ref val))..ctor(((Rect)(ref r)).x, ((Rect)(ref r)).y, num, 26f);
		Rect val2 = default(Rect);
		((Rect)(ref val2))..ctor(((Rect)(ref r)).x + num + 4f, ((Rect)(ref r)).y, num2 - num * 2f - 8f, 26f);
		Rect val3 = new Rect(((Rect)(ref val2)).xMax + 4f, ((Rect)(ref r)).y, num, 26f);
		if (Clickable(val))
		{
			index = (index - 1 + options.Length) % options.Length;
		}
		if (Clickable(val3))
		{
			index = (index + 1) % options.Length;
		}
		Theme.Rect(val, Theme.PanelBg);
		Theme.RectOutline(val, Theme.Line);
		GUI.Label(val, "◀", Theme.ArrowBtn);
		Theme.Rect(val3, Theme.PanelBg);
		Theme.RectOutline(val3, Theme.Line);
		GUI.Label(val3, "▶", Theme.ArrowBtn);
		Theme.Rect(val2, Theme.PanelBg);
		Theme.RectOutline(val2, Theme.Line);
		GUI.Label(val2, Ellipsis((options.Length != 0) ? options[index] : "-", 30), Theme.BodyCenter);
		return index;
	}

	private static string TextField(Rect r, string value, ModEntry entry, int slot)
	{
		//IL_0008: 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_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		string text = KeyFor(entry, slot);
		Theme.Rect(r, Theme.PanelBg);
		Theme.RectOutline(r, (GUI.GetNameOfFocusedControl() == text) ? Theme.Accent : Theme.Line);
		bool flag = GUI.GetNameOfFocusedControl() == text;
		if (!flag)
		{
			_buffers.Remove(text);
		}
		if (!_buffers.TryGetValue(text, out var value2))
		{
			value2 = value ?? string.Empty;
		}
		GUI.SetNextControlName(text);
		string text2 = GUI.TextField(r, flag ? value2 : (value ?? string.Empty), 200, Theme.Field);
		if (flag)
		{
			_buffers[text] = text2;
			return text2;
		}
		return text2;
	}

	private static string NumberField(Rect r, string display, ModEntry entry, int slot)
	{
		//IL_0008: 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_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a9: Invalid comparison between Unknown and I4
		//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Invalid comparison between Unknown and I4
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: Invalid comparison between Unknown and I4
		string text = KeyFor(entry, slot);
		Theme.Rect(r, Theme.PanelBg);
		Theme.RectOutline(r, (GUI.GetNameOfFocusedControl() == text) ? Theme.Accent : Theme.Line);
		bool flag = GUI.GetNameOfFocusedControl() == text;
		if (!flag)
		{
			_buffers.Remove(text);
		}
		if (!_buffers.TryGetValue(text, out var value))
		{
			value = display;
		}
		GUIStyle val = (flag ? Theme.Field : Theme.FieldRight);
		GUI.SetNextControlName(text);
		string text2 = GUI.TextField(r, flag ? value : display, 32, val);
		if (flag)
		{
			_buffers[text] = text2;
		}
		if (flag && (int)Event.current.type == 4 && ((int)Event.current.keyCode == 13 || (int)Event.current.keyCode == 271))
		{
			_buffers.Remove(text);
			GUI.FocusControl((string)null);
			Event.current.Use();
		}
		return text2;
	}

	private static string KeyFor(ModEntry entry, int slot)
	{
		return "mm_" + entry.Category.Identifier + "_" + entry.Identifier + "_" + slot;
	}

	private static bool Clickable(Rect r)
	{
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		if (InputBlocked)
		{
			return false;
		}
		return GUI.Button(r, GUIContent.none, GUIStyle.none);
	}

	private static bool PrimaryButton(Rect r, string text, bool enabled, bool danger)
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: 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)
		bool flag = ((Rect)(ref r)).Contains(Event.current.mousePosition);
		Color c = ((!enabled) ? Theme.PanelBg : (danger ? Theme.Danger : (flag ? Theme.Accent : Theme.AccentDark)));
		Theme.Rect(r, c);
		Theme.RectOutline(r, (!enabled) ? Theme.Line : (danger ? Theme.Danger : Theme.Accent));
		GUIStyle val = (enabled ? (danger ? Theme.BtnDanger : Theme.BtnPrimary) : (danger ? Theme.BtnDangerDim : Theme.BtnPrimaryDim));
		bool flag2 = GUI.Button(r, text, val);
		return enabled && flag2;
	}

	private static bool GhostButton(Rect r, string text)
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: 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_0016: Unknown result type (might be due to invalid IL or missing references)
		//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_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		bool flag = ((Rect)(ref r)).Contains(Event.current.mousePosition);
		Theme.Rect(r, flag ? Theme.RowHover : Theme.PanelBg);
		Theme.RectOutline(r, flag ? Theme.TextDim : Theme.Line);
		return GUI.Button(r, text, flag ? Theme.BtnGhostHover : Theme.BtnGhost);
	}

	private static bool LinkButton(Rect r, string text)
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		bool flag = ((Rect)(ref r)).Contains(Event.current.mousePosition);
		return GUI.Button(r, text, flag ? Theme.BtnLinkHover : Theme.BtnLink);
	}

	private static bool CloseButton(Rect r)
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: 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_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		bool flag = ((Rect)(ref r)).Contains(Event.current.mousePosition);
		Theme.Rect(r, flag ? Theme.Danger : Theme.PanelBg);
		return GUI.Button(r, "✕", flag ? Theme.BtnCloseHover : Theme.BtnClose);
	}

	private static void WarmupFonts()
	{
		StringBuilder stringBuilder = new StringBuilder(4096);
		stringBuilder.Append("模组菜单分类运行时配置共项搜索配置项…所有修改已保存有项修改未保存●○").Append("保存还原关闭放弃并关闭返回未保存的修改将丢失已保存项到失败已放弃本次修改已重置").Append("大厅扩容房间加入优化人数上限跳跃手感前置库该分类没有可显示的配置项没有匹配的配置项")
			.Append("开关整数数值文本选项开关键重置本类默认恢复本类默认搜索结果为暂不支持此类型")
			.Append("↺◀▶✕●○()、,。:;·「」—…%#0123456789.-+ ")
			.Append("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
		List<ModCategory> categories = ConfigModel.Categories;
		for (int i = 0; i < categories.Count; i++)
		{
			stringBuilder.Append(categories[i].DisplayName);
			List<ModEntry> entries = categories[i].Entries;
			for (int j = 0; j < entries.Count; j++)
			{
				stringBuilder.Append(entries[j].Name).Append(entries[j].Comment).Append(entries[j].TypeLabel);
			}
		}
		Theme.Warmup(stringBuilder.ToString());
	}

	private static void SetStatus(string s)
	{
		_status = s;
		_statusUntil = Time.unscaledTime + 4f;
	}

	private static string Ellipsis(string s, int max)
	{
		if (string.IsNullOrEmpty(s))
		{
			return string.Empty;
		}
		if (s.Length > max)
		{
			return s.Substring(0, max - 1) + "…";
		}
		return s;
	}

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

	internal static void NumericRange(double v, out double min, out double max)
	{
		double num = Math.Abs(v);
		bool flag = v < 0.0;
		double num2;
		double num3;
		if (num < 1E-09)
		{
			num2 = 0.0;
			num3 = 100.0;
		}
		else if (num < 1.0)
		{
			num2 = (flag ? (-1) : 0);
			num3 = ((!flag) ? 1 : 0);
		}
		else if (num <= 100.0)
		{
			num2 = 0.0;
			num3 = Math.Ceiling(num * 3.0);
		}
		else
		{
			num2 = 0.0;
			num3 = Math.Ceiling(num * 2.0);
		}
		min = (flag ? (0.0 - num3) : num2);
		max = (flag ? 0.0 : num3);
	}

	private static double Clamp(double v, double min, double max)
	{
		if (!(v < min))
		{
			if (!(v > max))
			{
				return v;
			}
			return max;
		}
		return min;
	}
}
public class ModMenuMod : MelonMod
{
	internal static Instance Log;

	internal static bool NativeUIEnabled = true;

	private const string PrefCategory = "BetterModMenu";

	private MelonPreferences_Entry<string> _hotkeyEntry;

	private MelonPreferences_Entry<bool> _nativeEntry;

	private KeyCode _hotkey = (KeyCode)290;

	private string _hotkeyName = "F9";

	private bool _selfTest;

	private int _selfTestStage;

	private float _selfTestAt;

	private bool _inventoryLogged;

	private float _inventoryAt;

	internal static bool AnyVisible
	{
		get
		{
			if (!MenuUI.Visible)
			{
				return NativeMenu.Visible;
			}
			return true;
		}
	}

	internal static void ToggleMenu()
	{
		if (ForceClassic())
		{
			if (NativeMenu.Visible)
			{
				NativeMenu.TryToggle();
			}
			MenuUI.Toggle();
		}
		else if (!NativeMenu.TryToggle())
		{
			MenuUI.Toggle();
		}
	}

	internal static void OpenMenu()
	{
		if (ForceClassic())
		{
			if (NativeMenu.Visible)
			{
				NativeMenu.TryToggle();
			}
			MenuUI.Open();
		}
		else if (!NativeMenu.TryOpen())
		{
			MenuUI.Open();
		}
	}

	private static bool ForceClassic()
	{
		try
		{
			return Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303);
		}
		catch
		{
			return false;
		}
	}

	public override void OnInitializeMelon()
	{
		Log = ((MelonBase)this).LoggerInstance;
		try
		{
			MelonPreferences_Category val = MelonPreferences.CreateCategory("BetterModMenu", "Mod 菜单");
			_hotkeyEntry = val.CreateEntry<string>("MenuKey", "F9", "热键", "打开/关闭菜单的按键名(KeyCode),例如 F9 / Insert / F8", false, false, (ValueValidator)null, (string)null);
			_nativeEntry = val.CreateEntry<bool>("NativeUI", true, "原生界面", "用游戏自带的设置面板来渲染菜单(样式和游戏设置一致)。关掉它,或者打开菜单时按住 Shift,就回到旧版窗口", false, false, (ValueValidator)null, (string)null);
		}
		catch (Exception ex)
		{
			Log.Warning("注册自身配置失败(不影响菜单): " + ex.Message);
		}
		ParseHotkey();
		Log.Msg("Mimesis Mod Menu v1.5.0 已加载,热键 " + ((object)Unsafe.As<KeyCode, KeyCode>(ref _hotkey)/*cast due to .constrained prefix*/).ToString() + "(打开时枚举配置)");
		_inventoryAt = Time.realtimeSinceStartup + 6f;
		MainMenuInjector.Install();
		string[] commandLineArgs = Environment.GetCommandLineArgs();
		for (int i = 0; i < commandLineArgs.Length; i++)
		{
			if (string.Equals(commandLineArgs[i], "--mm-selftest", StringComparison.OrdinalIgnoreCase))
			{
				_selfTest = true;
				_selfTestAt = Time.realtimeSinceStartup + 22f;
				Log.Msg("自检模式已启用(--mm-selftest)");
			}
		}
	}

	private void ParseHotkey()
	{
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		string text = ((_hotkeyEntry != null) ? _hotkeyEntry.Value : "F9");
		if (!string.IsNullOrEmpty(text) && Enum.TryParse<KeyCode>(text, ignoreCase: true, out KeyCode result))
		{
			_hotkey = result;
			_hotkeyName = text;
		}
	}

	public override void OnUpdate()
	{
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		if (_nativeEntry != null)
		{
			NativeUIEnabled = _nativeEntry.Value;
		}
		try
		{
			NativeMenu.Tick();
		}
		catch (Exception ex)
		{
			Instance log = Log;
			if (log != null)
			{
				log.Warning("原生界面 Tick 异常: " + ex.Message);
			}
		}
		if (_hotkeyEntry != null && !string.Equals(_hotkeyEntry.Value, _hotkeyName, StringComparison.Ordinal))
		{
			ParseHotkey();
		}
		if (!AnyVisible)
		{
			try
			{
				if (Input.GetKeyDown(_hotkey))
				{
					ToggleMenu();
				}
			}
			catch (Exception)
			{
			}
		}
		if (MenuUI.Visible)
		{
			Cursor.visible = true;
			if ((int)Cursor.lockState != 0)
			{
				Cursor.lockState = (CursorLockMode)0;
			}
		}
		if (!_inventoryLogged && Time.realtimeSinceStartup >= _inventoryAt)
		{
			_inventoryLogged = true;
			try
			{
				ConfigModel.Refresh();
				Log.Msg("配置清单:" + ConfigModel.Categories.Count + " 个分类 / " + ConfigModel.EntryCount + " 项");
				if (ConfigModel.Categories.Count == 0)
				{
					Log.Warning("未枚举到任何配置分类,菜单打开后会为空。");
				}
			}
			catch (Exception ex3)
			{
				Log.Warning("枚举配置失败: " + ex3.Message);
			}
		}
		if (_selfTest)
		{
			RunSelfTest();
		}
	}

	public override void OnGUI()
	{
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Invalid comparison between Unknown and I4
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		Event current = Event.current;
		if (current != null && (int)current.type == 4 && !AnyVisible && GUIUtility.keyboardControl == 0 && current.keyCode == _hotkey)
		{
			ToggleMenu();
			current.Use();
		}
		try
		{
			MenuUI.Draw();
		}
		catch (Exception ex)
		{
			Instance log = Log;
			if (log != null)
			{
				log.Error("绘制菜单异常: " + ex);
			}
			MenuUI.Visible = false;
		}
	}

	private void RunSelfTest()
	{
		if (_selfTestStage == 0 && Time.realtimeSinceStartup >= _selfTestAt)
		{
			Capture("modmenu_mainmenu.png");
			_selfTestStage = 1;
			_selfTestAt = Time.realtimeSinceStartup + 2f;
		}
		else if (_selfTestStage == 1 && Time.realtimeSinceStartup >= _selfTestAt)
		{
			OpenMenu();
			_selfTestStage = 2;
			_selfTestAt = Time.realtimeSinceStartup + 3f;
			Log.Msg("自检:菜单已打开,3 秒后截图");
		}
		else if (_selfTestStage == 2 && Time.realtimeSinceStartup >= _selfTestAt)
		{
			Capture("modmenu_open.png");
			_selfTestStage = 3;
			_selfTestAt = Time.realtimeSinceStartup + 0.5f;
		}
		else if (_selfTestStage == 3 && Time.realtimeSinceStartup >= _selfTestAt)
		{
			if (!NativeMenu.SelectIndex(1))
			{
				Log.Msg("自检:只有一个模组,跳过切换");
			}
			_selfTestStage = 4;
			_selfTestAt = Time.realtimeSinceStartup + 2f;
		}
		else if (_selfTestStage == 4 && Time.realtimeSinceStartup >= _selfTestAt)
		{
			Capture("modmenu_tab2.png");
			_selfTestStage = 5;
			_selfTestAt = Time.realtimeSinceStartup + 1f;
		}
		else if (_selfTestStage == 5 && Time.realtimeSinceStartup >= _selfTestAt)
		{
			Log.Msg("自检结束,退出游戏");
			Application.Quit();
			_selfTestStage = 6;
		}
	}

	private void Capture(string fileName)
	{
		try
		{
			string text = Path.Combine(Application.dataPath, "..", "UserData");
			Directory.CreateDirectory(text);
			string text2 = Path.Combine(text, fileName);
			ScreenCapture.CaptureScreenshot(text2);
			Log.Msg("自检:截图已写入 " + text2);
		}
		catch (Exception ex)
		{
			Log.Warning("自检截图失败: " + ex.Message);
		}
	}
}
internal static class NativeMenu
{
	[Serializable]
	[CompilerGenerated]
	private sealed class <>c
	{
		public static readonly <>c <>9 = new <>c();

		public static UnityAction <>9__27_0;

		public static Action <>9__39_1;

		public static Func<TMP_Text, bool> <>9__46_0;

		public static Func<TMP_Text, float> <>9__46_1;

		internal void <Setup>b__27_0()
		{
			Close();
		}

		internal void <SliderRow>b__39_1()
		{
		}

		internal bool <Text>b__46_0(TMP_Text t)
		{
			return (Object)(object)t != (Object)null;
		}

		internal float <Text>b__46_1(TMP_Text t)
		{
			return PosX(t.transform);
		}
	}

	internal static bool Visible;

	private static UIPrefab_Setting _panel;

	private static UIPrefabScript _prev;

	private static UIPrefab_DisplaySetting _display;

	private static Transform _content;

	private static Transform _tplSlider;

	private static Transform _tplToggle;

	private static float _tplSliderH = 72f;

	private static float _tplToggleH = 72f;

	private static bool _failed;

	private static int _setupFrame = -1;

	private static bool _prevCursor;

	private static CursorLockMode _prevLock;

	private static readonly List<GameObject> _rows = new List<GameObject>();

	private static readonly List<Button> _tabs = new List<Button>();

	private static readonly List<ModCategory> _cats = new List<ModCategory>();

	private static int _selected;

	internal static bool Available
	{
		get
		{
			if (ModMenuMod.NativeUIEnabled)
			{
				return !_failed;
			}
			return false;
		}
	}

	internal static void Tick()
	{
		if (_setupFrame < 0 || Time.frameCount < _setupFrame + 2)
		{
			return;
		}
		if ((Object)(object)_panel == (Object)null)
		{
			_setupFrame = -1;
		}
		else
		{
			if (!((Component)_panel).gameObject.activeSelf)
			{
				return;
			}
			_setupFrame = -1;
			try
			{
				Setup();
				Refresh();
				Instance log = ModMenuMod.Log;
				if (log != null)
				{
					log.Msg("[原生] 界面已就绪," + ConfigModel.EntryCount + " 项配置");
				}
			}
			catch (Exception ex)
			{
				Instance log2 = ModMenuMod.Log;
				if (log2 != null)
				{
					log2.Warning("[原生] 初始化失败,改用经典窗口:" + ex);
				}
				_failed = true;
				SafeDestroy();
				Visible = false;
				MenuUI.Open();
			}
		}
	}

	internal static bool TryToggle()
	{
		if (Visible)
		{
			try
			{
				Close();
				return true;
			}
			catch (Exception ex)
			{
				Fail(ex);
				return true;
			}
		}
		if (!Available)
		{
			return false;
		}
		try
		{
			return Open();
		}
		catch (Exception ex2)
		{
			Fail(ex2);
			return false;
		}
	}

	internal static bool TryOpen()
	{
		if (!Available)
		{
			return false;
		}
		if (Visible)
		{
			return true;
		}
		try
		{
			return Open();
		}
		catch (Exception ex)
		{
			Fail(ex);
			return false;
		}
	}

	private static void Fail(Exception ex)
	{
		Instanc