Decompiled source of ModMenu v1.1.1

ModMenu.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BrutalistickModMenu;
using HarmonyLib;
using Il2Cpp;
using MelonLoader;
using MelonLoader.Preferences;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(ModMenuMod), "ModMenu", "1.2.0", "misha", null)]
[assembly: MelonGame("Kubunautilus", "BrutalistickVR")]
[assembly: MelonPriority(100)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("ModMenu")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+7108fab20107837d2436969e6a7e49fcb30a0ece")]
[assembly: AssemblyProduct("ModMenu")]
[assembly: AssemblyTitle("ModMenu")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace System.Runtime.CompilerServices
{
	internal sealed class NullableAttribute : Attribute
	{
		public NullableAttribute(byte b)
		{
		}

		public NullableAttribute(byte[] b)
		{
		}
	}
	internal sealed class NullableContextAttribute : Attribute
	{
		public NullableContextAttribute(byte b)
		{
		}
	}
}
namespace BrutalistickModMenu
{
	public class ModMenuMod : MelonMod
	{
		private class HoldStepInfo
		{
			public GameObject ButtonObj;

			public MelonPreferences_Entry Entry;

			public int Direction;

			public Text ValueLabel;
		}

		public const string Tag = "[ModMenu]";

		private static float _nextEnsure;

		private static readonly Dictionary<int, Action> ButtonActions = new Dictionary<int, Action>();

		private static readonly Dictionary<int, HoldStepInfo> HoldButtons = new Dictionary<int, HoldStepInfo>();

		private static HoldStepInfo _activeHold;

		private static float _holdStartTime;

		private static float _nextHoldTick;

		internal static Harmony SharedHarmony;

		public override void OnInitializeMelon()
		{
			SharedHarmony = ((MelonBase)this).HarmonyInstance;
			ModToggleManager.Init();
			PatchTabs();
			PatchClicksAndHolds();
			List<ModMenuItem> list = ModConfigManager.BuildScriptModList();
			MelonLogger.Msg($"{"[ModMenu]"} Loaded! Active mods/configs found: {list.Count}");
			foreach (ModMenuItem item in list)
			{
				ModToggleManager.EnsureModPatched(item.Melon);
				MelonLogger.Msg($"{"[ModMenu]"}   -> {item.Name} ({item.Version}) | CFG Categories: {item.Categories.Count}");
			}
		}

		public override void OnSceneWasInitialized(int buildIndex, string sceneName)
		{
			MelonCoroutines.Start(ProbeLater(2.5f));
		}

		private static IEnumerator ProbeLater(float delay)
		{
			yield return (object)new WaitForSecondsRealtime(delay);
			ModMenuPanel.Ensure();
		}

		public override void OnUpdate()
		{
			if (Time.unscaledTime >= _nextEnsure)
			{
				_nextEnsure = Time.unscaledTime + 1.5f;
				ModMenuPanel.Ensure();
			}
			UpdateHoldStep();
		}

		private static void UpdateHoldStep()
		{
			if (_activeHold == null)
			{
				return;
			}
			if ((Object)(object)_activeHold.ButtonObj == (Object)null || !_activeHold.ButtonObj.activeInHierarchy)
			{
				StopHold();
			}
			else if (!(Time.unscaledTime < _nextHoldTick))
			{
				_nextHoldTick = Time.unscaledTime + 0.08f;
				float heldSeconds = Time.unscaledTime - _holdStartTime;
				float num = CalculateDynamicStep(_activeHold.Entry, heldSeconds);
				ModConfigManager.StepNumericEntry(_activeHold.Entry, num * (float)_activeHold.Direction, saveImmediately: false);
				if ((Object)(object)_activeHold.ValueLabel != (Object)null)
				{
					_activeHold.ValueLabel.text = ModConfigManager.FormatValue(_activeHold.Entry);
				}
			}
		}

		private static float CalculateDynamicStep(MelonPreferences_Entry entry, float heldSeconds)
		{
			bool flag = entry.GetReflectedType() == typeof(int);
			if (heldSeconds < 1.2f)
			{
				return flag ? 1f : 0.1f;
			}
			if (heldSeconds < 2.2f)
			{
				return 1f;
			}
			if (heldSeconds < 3.2f)
			{
				return 5f;
			}
			if (heldSeconds < 4.2f)
			{
				return 10f;
			}
			if (heldSeconds < 5.5f)
			{
				return 50f;
			}
			if (heldSeconds < 7f)
			{
				return 100f;
			}
			return 500f;
		}

		private static void StopHold()
		{
			if (_activeHold != null)
			{
				MelonPreferences.Save();
				_activeHold = null;
			}
		}

		public static void RegisterButton(Button btn, Action onClick)
		{
			if (!((Object)(object)btn == (Object)null) && onClick != null)
			{
				ButtonActions[((Object)btn).GetInstanceID()] = onClick;
			}
		}

		public static void RegisterHoldStepButton(Button btn, MelonPreferences_Entry entry, int direction, Text valueLabel)
		{
			if (!((Object)(object)btn == (Object)null) && entry != null)
			{
				HoldButtons[((Object)btn).GetInstanceID()] = new HoldStepInfo
				{
					ButtonObj = ((Component)btn).gameObject,
					Entry = entry,
					Direction = direction,
					ValueLabel = valueLabel
				};
			}
		}

		public static void ClearRegisteredButtons()
		{
			StopHold();
			HoldButtons.Clear();
		}

		private void PatchTabs()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			try
			{
				MethodInfo method = typeof(MenuUIManager).GetMethod("ChangeActiveTab", BindingFlags.Instance | BindingFlags.Public);
				if (method != null)
				{
					((MelonBase)this).HarmonyInstance.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(typeof(ModMenuMod).GetMethod("ChangeActiveTabPostfix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[ModMenu] ChangeActiveTab patch error: " + ex.Message);
			}
		}

		private static void ChangeActiveTabPostfix(int tabIndex)
		{
			ModMenuPanel.Hide();
		}

		private void PatchClicksAndHolds()
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Expected O, but got Unknown
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Expected O, but got Unknown
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Expected O, but got Unknown
			try
			{
				MethodInfo method = typeof(Button).GetMethod("OnPointerClick", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(PointerEventData) }, null);
				if (method != null)
				{
					((MelonBase)this).HarmonyInstance.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(typeof(ModMenuMod).GetMethod("OnPointerClickPostfix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				MethodInfo method2 = typeof(Selectable).GetMethod("OnPointerDown", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(PointerEventData) }, null);
				if (method2 != null)
				{
					((MelonBase)this).HarmonyInstance.Patch((MethodBase)method2, (HarmonyMethod)null, new HarmonyMethod(typeof(ModMenuMod).GetMethod("OnPointerDownPostfix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				MethodInfo method3 = typeof(Selectable).GetMethod("OnPointerUp", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(PointerEventData) }, null);
				if (method3 != null)
				{
					((MelonBase)this).HarmonyInstance.Patch((MethodBase)method3, (HarmonyMethod)null, new HarmonyMethod(typeof(ModMenuMod).GetMethod("OnPointerUpPostfix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				MethodInfo method4 = typeof(Selectable).GetMethod("OnPointerExit", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(PointerEventData) }, null);
				if (method4 != null)
				{
					((MelonBase)this).HarmonyInstance.Patch((MethodBase)method4, (HarmonyMethod)null, new HarmonyMethod(typeof(ModMenuMod).GetMethod("OnPointerUpPostfix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[ModMenu] Pointer patch error: " + ex.Message);
			}
		}

		private static void OnPointerClickPostfix(Button __instance)
		{
			if ((Object)(object)__instance == (Object)null || !ButtonActions.TryGetValue(((Object)__instance).GetInstanceID(), out var value))
			{
				return;
			}
			try
			{
				value();
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[ModMenu] Click error: " + ex.Message);
			}
		}

		private static void OnPointerDownPostfix(Selectable __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && HoldButtons.TryGetValue(((Object)__instance).GetInstanceID(), out var value))
			{
				_activeHold = value;
				_holdStartTime = Time.unscaledTime;
				_nextHoldTick = Time.unscaledTime + 0.35f;
				float num = ((value.Entry.GetReflectedType() == typeof(int)) ? 1f : 0.1f);
				ModConfigManager.StepNumericEntry(value.Entry, num * (float)value.Direction);
				if ((Object)(object)value.ValueLabel != (Object)null)
				{
					value.ValueLabel.text = ModConfigManager.FormatValue(value.Entry);
				}
			}
		}

		private static void OnPointerUpPostfix(Selectable __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && _activeHold != null && HoldButtons.TryGetValue(((Object)__instance).GetInstanceID(), out var value) && value == _activeHold)
			{
				StopHold();
			}
		}
	}
	public static class ModToggleManager
	{
		private static MelonPreferences_Category _stateCat;

		private static readonly HashSet<Assembly> DisabledAssemblies = new HashSet<Assembly>();

		private static readonly HashSet<Assembly> PatchedAssemblies = new HashSet<Assembly>();

		public static void Init()
		{
			_stateCat = MelonPreferences.CreateCategory("ModMenu_States", "ModMenu States");
		}

		public static bool IsModEnabled(ModMenuItem item)
		{
			if (item == null)
			{
				return true;
			}
			MelonPreferences_Entry val = FindNativeEnabledEntry(item);
			if (val != null && val.BoxedValue is bool result)
			{
				return result;
			}
			MelonBase melon = item.Melon;
			object obj;
			if (melon == null)
			{
				obj = null;
			}
			else
			{
				MelonAssembly melonAssembly = melon.MelonAssembly;
				obj = ((melonAssembly != null) ? melonAssembly.Assembly : null);
			}
			if ((Assembly?)obj != null)
			{
				return !DisabledAssemblies.Contains(item.Melon.MelonAssembly.Assembly);
			}
			return true;
		}

		public static void ToggleMod(ModMenuItem item)
		{
			if (item == null)
			{
				return;
			}
			bool flag = !IsModEnabled(item);
			MelonPreferences_Entry val = FindNativeEnabledEntry(item);
			if (val != null)
			{
				val.BoxedValue = flag;
			}
			MelonBase melon = item.Melon;
			object obj;
			if (melon == null)
			{
				obj = null;
			}
			else
			{
				MelonAssembly melonAssembly = melon.MelonAssembly;
				obj = ((melonAssembly != null) ? melonAssembly.Assembly : null);
			}
			if ((Assembly?)obj != null)
			{
				EnsureModPatched(item.Melon);
				Assembly assembly = item.Melon.MelonAssembly.Assembly;
				if (flag)
				{
					DisabledAssemblies.Remove(assembly);
				}
				else
				{
					DisabledAssemblies.Add(assembly);
				}
				SaveModState(item.Name, flag);
			}
			MelonPreferences.Save();
			MelonLogger.Msg($"{"[ModMenu]"} Mod '{item.Name}' set to {(flag ? "ENABLED" : "DISABLED")}");
		}

		private static void SaveModState(string modName, bool enabled)
		{
			if (_stateCat != null && !string.IsNullOrEmpty(modName))
			{
				string text = "Enabled_" + modName.Replace(" ", "_");
				MelonPreferences_Entry<bool> val = _stateCat.GetEntry<bool>(text) ?? _stateCat.CreateEntry<bool>(text, true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
				val.Value = enabled;
			}
		}

		public static void EnsureModPatched(MelonBase melon)
		{
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Expected O, but got Unknown
			object obj;
			if (melon == null)
			{
				obj = null;
			}
			else
			{
				MelonAssembly melonAssembly = melon.MelonAssembly;
				obj = ((melonAssembly != null) ? melonAssembly.Assembly : null);
			}
			if ((Assembly?)obj == null || ModMenuMod.SharedHarmony == null)
			{
				return;
			}
			Assembly assembly = melon.MelonAssembly.Assembly;
			if (assembly == typeof(ModMenuMod).Assembly || PatchedAssemblies.Contains(assembly))
			{
				return;
			}
			PatchedAssemblies.Add(assembly);
			MelonInfoAttribute info = melon.Info;
			string text = "Enabled_" + (((info != null) ? info.Name : null) ?? "Mod").Replace(" ", "_");
			MelonPreferences_Entry<bool> val = _stateCat.GetEntry<bool>(text) ?? _stateCat.CreateEntry<bool>(text, true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
			if (!val.Value)
			{
				DisabledAssemblies.Add(assembly);
			}
			MethodInfo method = typeof(ModToggleManager).GetMethod("ExecutionGuardPrefix", BindingFlags.Static | BindingFlags.NonPublic);
			string[] array = new string[9] { "OnUpdate", "OnFixedUpdate", "OnLateUpdate", "OnGUI", "OnSceneWasLoaded", "OnSceneWasInitialized", "Update", "FixedUpdate", "LateUpdate" };
			try
			{
				Type[] types = assembly.GetTypes();
				foreach (Type type in types)
				{
					string[] array2 = array;
					foreach (string name in array2)
					{
						MethodInfo method2 = type.GetMethod(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
						if (method2 != null && method2.ReturnType == typeof(void))
						{
							ModMenuMod.SharedHarmony.Patch((MethodBase)method2, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						}
					}
				}
			}
			catch (Exception ex)
			{
				DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(31, 3);
				defaultInterpolatedStringHandler.AppendFormatted("[ModMenu]");
				defaultInterpolatedStringHandler.AppendLiteral(" Could not hook lifecycle of ");
				MelonInfoAttribute info2 = melon.Info;
				defaultInterpolatedStringHandler.AppendFormatted((info2 != null) ? info2.Name : null);
				defaultInterpolatedStringHandler.AppendLiteral(": ");
				defaultInterpolatedStringHandler.AppendFormatted(ex.Message);
				MelonLogger.Warning(defaultInterpolatedStringHandler.ToStringAndClear());
			}
		}

		private static bool ExecutionGuardPrefix(MethodBase __originalMethod)
		{
			Assembly assembly = __originalMethod?.DeclaringType?.Assembly;
			if (assembly != null && DisabledAssemblies.Contains(assembly))
			{
				return false;
			}
			return true;
		}

		private static MelonPreferences_Entry FindNativeEnabledEntry(ModMenuItem item)
		{
			foreach (MelonPreferences_Category category in item.Categories)
			{
				if (category?.Entries == null)
				{
					continue;
				}
				foreach (MelonPreferences_Entry entry in category.Entries)
				{
					if (entry != null && entry.GetReflectedType() == typeof(bool) && (string.Equals(entry.Identifier, "Enabled", StringComparison.OrdinalIgnoreCase) || string.Equals(entry.Identifier, "Enable", StringComparison.OrdinalIgnoreCase) || string.Equals(entry.Identifier, "ModEnabled", StringComparison.OrdinalIgnoreCase)))
					{
						return entry;
					}
				}
			}
			return null;
		}
	}
	public static class ModMenuPanel
	{
		private static GameObject _panelRoot;

		private static GameObject _tabButtonObj;

		private static Transform _leftListRoot;

		private static Transform _rightConfigRoot;

		private static Font _cachedFont;

		private static List<ModMenuItem> _mods = new List<ModMenuItem>();

		private static int _selectedModIndex = 0;

		private static int _modPage = 0;

		private const int ModsPerPage = 8;

		private static int _configPage = 0;

		private const int EntriesPerPage = 5;

		public static void Ensure()
		{
			if ((Object)(object)_panelRoot != (Object)null)
			{
				return;
			}
			MenuUIManager val = Object.FindObjectOfType<MenuUIManager>();
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			try
			{
				BuildUI(val);
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[ModMenu] Failed to build UI: " + ex.Message);
			}
		}

		public static void Hide()
		{
			ModMenuMod.ClearRegisteredButtons();
			if ((Object)(object)_panelRoot != (Object)null && _panelRoot.activeSelf)
			{
				_panelRoot.SetActive(false);
			}
		}

		public static void TogglePanel(MenuUIManager menuMgr)
		{
			if ((Object)(object)_panelRoot == (Object)null)
			{
				return;
			}
			if (!_panelRoot.activeSelf)
			{
				_mods = ModConfigManager.BuildScriptModList();
				if (_selectedModIndex >= _mods.Count)
				{
					_selectedModIndex = 0;
				}
				_modPage = _selectedModIndex / 8;
				_panelRoot.SetActive(true);
				_panelRoot.transform.SetAsLastSibling();
				RebuildLists();
			}
			else
			{
				Hide();
			}
		}

		private static void BuildUI(MenuUIManager menuMgr)
		{
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Expected O, but got Unknown
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: 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_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_026d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0274: Expected O, but got Unknown
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f5: Expected O, but got Unknown
			//IL_0322: Unknown result type (might be due to invalid IL or missing references)
			//IL_0339: Unknown result type (might be due to invalid IL or missing references)
			//IL_0346: Unknown result type (might be due to invalid IL or missing references)
			//IL_0353: Unknown result type (might be due to invalid IL or missing references)
			_cachedFont = Resources.GetBuiltinResource<Font>("Arial.ttf");
			Text componentInChildren = ((Component)menuMgr).GetComponentInChildren<Text>(true);
			if ((Object)(object)componentInChildren != (Object)null && (Object)(object)componentInChildren.font != (Object)null)
			{
				_cachedFont = componentInChildren.font;
			}
			Button componentInChildren2 = ((Component)menuMgr).GetComponentInChildren<Button>(true);
			Transform val = ((Component)menuMgr).transform;
			if ((Object)(object)componentInChildren2 != (Object)null && (Object)(object)((Component)componentInChildren2).transform.parent != (Object)null)
			{
				val = ((Component)componentInChildren2).transform.parent.parent ?? ((Component)componentInChildren2).transform.parent;
			}
			_tabButtonObj = CreateStyledButton(val, "ModMenu_TabButton", "MODS [CFG]", new Vector2(0.82f, 1.02f), new Vector2(0.98f, 1.09f), new Color(0.18f, 0.45f, 0.22f, 0.95f));
			Button component = _tabButtonObj.GetComponent<Button>();
			ModMenuMod.RegisterButton(component, delegate
			{
				TogglePanel(menuMgr);
			});
			_panelRoot = new GameObject("ModMenu_MainPanel");
			_panelRoot.transform.SetParent(val, false);
			RectTransform val2 = _panelRoot.AddComponent<RectTransform>();
			val2.anchorMin = new Vector2(0.03f, 0.05f);
			val2.anchorMax = new Vector2(0.97f, 0.9f);
			val2.offsetMin = Vector2.zero;
			val2.offsetMax = Vector2.zero;
			Image val3 = _panelRoot.AddComponent<Image>();
			((Graphic)val3).color = new Color(0.08f, 0.08f, 0.1f, 0.96f);
			CreateLabel(_panelRoot.transform, "Header", "ACTIVE MODS & CONFIG EDITOR", new Vector2(0.02f, 0.9f), new Vector2(0.85f, 0.98f), 18, (TextAnchor)3, Color.white);
			GameObject val4 = CreateStyledButton(_panelRoot.transform, "CloseBtn", "X", new Vector2(0.92f, 0.91f), new Vector2(0.98f, 0.98f), new Color(0.6f, 0.15f, 0.15f, 1f));
			ModMenuMod.RegisterButton(val4.GetComponent<Button>(), Hide);
			GameObject val5 = new GameObject("LeftModsList");
			val5.transform.SetParent(_panelRoot.transform, false);
			RectTransform val6 = val5.AddComponent<RectTransform>();
			val6.anchorMin = new Vector2(0.02f, 0.04f);
			val6.anchorMax = new Vector2(0.34f, 0.88f);
			val6.offsetMin = Vector2.zero;
			val6.offsetMax = Vector2.zero;
			_leftListRoot = val5.transform;
			GameObject val7 = new GameObject("RightConfigList");
			val7.transform.SetParent(_panelRoot.transform, false);
			RectTransform val8 = val7.AddComponent<RectTransform>();
			val8.anchorMin = new Vector2(0.36f, 0.04f);
			val8.anchorMax = new Vector2(0.98f, 0.88f);
			val8.offsetMin = Vector2.zero;
			val8.offsetMax = Vector2.zero;
			_rightConfigRoot = val7.transform;
			_panelRoot.SetActive(false);
		}

		private static void RebuildLists()
		{
			//IL_0050: 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_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0282: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0287: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_036f: 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_0386: Unknown result type (might be due to invalid IL or missing references)
			//IL_03aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03be: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0470: Unknown result type (might be due to invalid IL or missing references)
			//IL_0455: Unknown result type (might be due to invalid IL or missing references)
			//IL_0475: Unknown result type (might be due to invalid IL or missing references)
			//IL_049f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0572: Unknown result type (might be due to invalid IL or missing references)
			//IL_0581: Unknown result type (might be due to invalid IL or missing references)
			//IL_059a: Unknown result type (might be due to invalid IL or missing references)
			//IL_064a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0659: Unknown result type (might be due to invalid IL or missing references)
			//IL_0675: Unknown result type (might be due to invalid IL or missing references)
			//IL_075a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0769: Unknown result type (might be due to invalid IL or missing references)
			//IL_0782: Unknown result type (might be due to invalid IL or missing references)
			//IL_0802: Unknown result type (might be due to invalid IL or missing references)
			//IL_0811: Unknown result type (might be due to invalid IL or missing references)
			//IL_0819: Unknown result type (might be due to invalid IL or missing references)
			//IL_083d: Unknown result type (might be due to invalid IL or missing references)
			//IL_084c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0865: Unknown result type (might be due to invalid IL or missing references)
			ModMenuMod.ClearRegisteredButtons();
			ClearChildren(_leftListRoot);
			ClearChildren(_rightConfigRoot);
			if (_mods.Count == 0)
			{
				CreateLabel(_leftListRoot, "Empty", "No active mods found", new Vector2(0f, 0.8f), new Vector2(1f, 0.95f), 14, (TextAnchor)4, Color.gray);
				return;
			}
			int totalModPages = (_mods.Count + 8 - 1) / 8;
			if (_modPage >= totalModPages)
			{
				_modPage = 0;
			}
			int num = _modPage * 8;
			int num2 = Math.Min(8, _mods.Count - num);
			for (int i = 0; i < num2; i++)
			{
				int actualModIdx = num + i;
				ModMenuItem modMenuItem = _mods[actualModIdx];
				bool flag = actualModIdx == _selectedModIndex;
				bool flag2 = ModToggleManager.IsModEnabled(modMenuItem);
				float num3 = 1f - (float)i * 0.106f;
				float num4 = num3 - 0.094f;
				Color bgColor = (flag ? new Color(0.22f, 0.48f, 0.28f, 1f) : new Color(0.18f, 0.18f, 0.22f, 1f));
				if (!flag2)
				{
					bgColor = (flag ? new Color(0.5f, 0.2f, 0.2f, 1f) : new Color(0.25f, 0.14f, 0.14f, 1f));
				}
				string text = (flag2 ? "[ON] " : "[OFF] ");
				string text2 = text + modMenuItem.Name;
				GameObject val = CreateStyledButton(_leftListRoot, $"ModBtn_{actualModIdx}", text2, new Vector2(0f, num4), new Vector2(1f, num3), bgColor);
				ModMenuMod.RegisterButton(val.GetComponent<Button>(), delegate
				{
					_selectedModIndex = actualModIdx;
					_configPage = 0;
					RebuildLists();
				});
			}
			Color bgColor2 = ((totalModPages > 1) ? new Color(0.25f, 0.25f, 0.32f, 1f) : new Color(0.15f, 0.15f, 0.18f, 0.7f));
			GameObject val2 = CreateStyledButton(_leftListRoot, "PrevModPage", "<", new Vector2(0f, 0.01f), new Vector2(0.22f, 0.11f), bgColor2);
			if (totalModPages > 1)
			{
				ModMenuMod.RegisterButton(val2.GetComponent<Button>(), delegate
				{
					_modPage = (_modPage - 1 + totalModPages) % totalModPages;
					RebuildLists();
				});
			}
			CreateLabel(_leftListRoot, "ModPageInfo", $"Page {_modPage + 1}/{totalModPages} ({_mods.Count})", new Vector2(0.23f, 0.01f), new Vector2(0.77f, 0.11f), 13, (TextAnchor)4, Color.white);
			GameObject val3 = CreateStyledButton(_leftListRoot, "NextModPage", ">", new Vector2(0.78f, 0.01f), new Vector2(1f, 0.11f), bgColor2);
			if (totalModPages > 1)
			{
				ModMenuMod.RegisterButton(val3.GetComponent<Button>(), delegate
				{
					_modPage = (_modPage + 1) % totalModPages;
					RebuildLists();
				});
			}
			if (_selectedModIndex < 0 || _selectedModIndex >= _mods.Count)
			{
				_selectedModIndex = 0;
			}
			ModMenuItem selectedMod = _mods[_selectedModIndex];
			bool flag3 = ModToggleManager.IsModEnabled(selectedMod);
			Color bgColor3 = (flag3 ? new Color(0.16f, 0.48f, 0.22f, 1f) : new Color(0.55f, 0.16f, 0.16f, 1f));
			string text3 = (flag3 ? "MOD STATUS: ENABLED" : "MOD STATUS: DISABLED");
			GameObject val4 = CreateStyledButton(_rightConfigRoot, "ToggleModStateBtn", text3, new Vector2(0.02f, 0.89f), new Vector2(0.55f, 0.99f), bgColor3);
			ModMenuMod.RegisterButton(val4.GetComponent<Button>(), delegate
			{
				ModToggleManager.ToggleMod(selectedMod);
				RebuildLists();
			});
			List<MelonPreferences_Entry> allEntries = new List<MelonPreferences_Entry>();
			foreach (MelonPreferences_Category category in selectedMod.Categories)
			{
				if (category?.Entries != null)
				{
					allEntries.AddRange(category.Entries);
				}
			}
			if (allEntries.Count > 0)
			{
				GameObject val5 = CreateStyledButton(_rightConfigRoot, "ResetDefaultsBtn", "RESET DEFAULTS", new Vector2(0.58f, 0.89f), new Vector2(0.98f, 0.99f), new Color(0.45f, 0.3f, 0.12f, 1f));
				ModMenuMod.RegisterButton(val5.GetComponent<Button>(), delegate
				{
					ModConfigManager.ResetAllToDefault(allEntries);
					RebuildLists();
				});
			}
			if (allEntries.Count == 0)
			{
				CreateLabel(_rightConfigRoot, "NoCfg", $"Mod '{selectedMod.Name}' ({selectedMod.Version})\nNo config entries in MelonPreferences.cfg.\nYou can toggle this mod ON/OFF using the button above.", new Vector2(0.05f, 0.35f), new Vector2(0.95f, 0.78f), 14, (TextAnchor)4, new Color(0.75f, 0.75f, 0.75f, 1f));
				return;
			}
			int totalPages = (allEntries.Count + 5 - 1) / 5;
			if (_configPage >= totalPages)
			{
				_configPage = 0;
			}
			int num5 = _configPage * 5;
			int num6 = Math.Min(5, allEntries.Count - num5);
			for (int num7 = 0; num7 < num6; num7++)
			{
				MelonPreferences_Entry entry = allEntries[num5 + num7];
				float num8 = 0.84f - (float)num7 * 0.14f;
				float bottom = num8 - 0.12f;
				BuildEntryRow(_rightConfigRoot, entry, bottom, num8);
			}
			if (totalPages > 1)
			{
				GameObject val6 = CreateStyledButton(_rightConfigRoot, "PrevPage", "< PREV", new Vector2(0.08f, 0.01f), new Vector2(0.34f, 0.11f), new Color(0.25f, 0.25f, 0.3f, 1f));
				ModMenuMod.RegisterButton(val6.GetComponent<Button>(), delegate
				{
					_configPage = (_configPage - 1 + totalPages) % totalPages;
					RebuildLists();
				});
				CreateLabel(_rightConfigRoot, "PageInfo", $"Page {_configPage + 1} / {totalPages}", new Vector2(0.35f, 0.01f), new Vector2(0.65f, 0.11f), 14, (TextAnchor)4, Color.white);
				GameObject val7 = CreateStyledButton(_rightConfigRoot, "NextPage", "NEXT >", new Vector2(0.66f, 0.01f), new Vector2(0.92f, 0.11f), new Color(0.25f, 0.25f, 0.3f, 1f));
				ModMenuMod.RegisterButton(val7.GetComponent<Button>(), delegate
				{
					_configPage = (_configPage + 1) % totalPages;
					RebuildLists();
				});
			}
		}

		private static void BuildEntryRow(Transform parent, MelonPreferences_Entry entry, float bottom, float top)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cf: 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)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: 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_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			string identifier = entry.Identifier;
			CreateLabel(parent, "Lbl_" + entry.Identifier, identifier, new Vector2(0.02f, bottom), new Vector2(0.48f, top), 14, (TextAnchor)3, Color.white);
			Type reflectedType = entry.GetReflectedType();
			if (reflectedType == typeof(bool) || reflectedType.IsEnum)
			{
				string text = ModConfigManager.FormatValue(entry);
				GameObject val = CreateStyledButton(parent, "Toggle_" + entry.Identifier, text, new Vector2(0.5f, bottom), new Vector2(0.88f, top), new Color(0.2f, 0.25f, 0.32f, 1f));
				ModMenuMod.RegisterButton(val.GetComponent<Button>(), delegate
				{
					ModConfigManager.ToggleOrCycleEntry(entry);
					RebuildLists();
				});
			}
			else if (reflectedType == typeof(int) || reflectedType == typeof(float))
			{
				Text valueLabel = CreateLabel(parent, "Val_" + entry.Identifier, ModConfigManager.FormatValue(entry), new Vector2(0.61f, bottom), new Vector2(0.77f, top), 14, (TextAnchor)4, Color.yellow);
				GameObject val2 = CreateStyledButton(parent, "Minus_" + entry.Identifier, "-", new Vector2(0.5f, bottom), new Vector2(0.6f, top), new Color(0.35f, 0.2f, 0.2f, 1f));
				ModMenuMod.RegisterHoldStepButton(val2.GetComponent<Button>(), entry, -1, valueLabel);
				GameObject val3 = CreateStyledButton(parent, "Plus_" + entry.Identifier, "+", new Vector2(0.78f, bottom), new Vector2(0.88f, top), new Color(0.2f, 0.35f, 0.2f, 1f));
				ModMenuMod.RegisterHoldStepButton(val3.GetComponent<Button>(), entry, 1, valueLabel);
			}
			else
			{
				CreateLabel(parent, "Val_" + entry.Identifier, ModConfigManager.FormatValue(entry), new Vector2(0.5f, bottom), new Vector2(0.88f, top), 13, (TextAnchor)5, Color.gray);
			}
			GameObject val4 = CreateStyledButton(parent, "Reset_" + entry.Identifier, "R", new Vector2(0.9f, bottom), new Vector2(0.98f, top), new Color(0.35f, 0.25f, 0.15f, 1f));
			ModMenuMod.RegisterButton(val4.GetComponent<Button>(), delegate
			{
				entry.ResetToDefault();
				MelonPreferences.Save();
				RebuildLists();
			});
		}

		private static GameObject CreateStyledButton(Transform parent, string name, string text, Vector2 anchorMin, Vector2 anchorMax, Color bgColor)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			RectTransform val2 = val.AddComponent<RectTransform>();
			val2.anchorMin = anchorMin;
			val2.anchorMax = anchorMax;
			val2.offsetMin = Vector2.zero;
			val2.offsetMax = Vector2.zero;
			Image val3 = val.AddComponent<Image>();
			((Graphic)val3).color = bgColor;
			Button val4 = val.AddComponent<Button>();
			((Selectable)val4).targetGraphic = (Graphic)(object)val3;
			CreateLabel(val.transform, "Text", text, Vector2.zero, Vector2.one, 13, (TextAnchor)4, Color.white);
			return val;
		}

		private static Text CreateLabel(Transform parent, string name, string content, Vector2 anchorMin, Vector2 anchorMax, int fontSize, TextAnchor align, Color color)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			RectTransform val2 = val.AddComponent<RectTransform>();
			val2.anchorMin = anchorMin;
			val2.anchorMax = anchorMax;
			val2.offsetMin = Vector2.zero;
			val2.offsetMax = Vector2.zero;
			Text val3 = val.AddComponent<Text>();
			val3.font = _cachedFont;
			val3.text = content;
			val3.fontSize = fontSize;
			val3.alignment = align;
			((Graphic)val3).color = color;
			((Graphic)val3).raycastTarget = false;
			return val3;
		}

		private static void ClearChildren(Transform root)
		{
			if (!((Object)(object)root == (Object)null))
			{
				for (int num = root.childCount - 1; num >= 0; num--)
				{
					Object.Destroy((Object)(object)((Component)root.GetChild(num)).gameObject);
				}
			}
		}
	}
	public class ModMenuItem
	{
		public string Name = string.Empty;

		public string Version = string.Empty;

		public string Author = string.Empty;

		public MelonBase Melon;

		public bool IsUnlinkedCategory;

		public List<MelonPreferences_Category> Categories = new List<MelonPreferences_Category>();
	}
	public static class ModConfigManager
	{
		public static List<ModMenuItem> BuildScriptModList()
		{
			List<ModMenuItem> list = new List<ModMenuItem>();
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			foreach (MelonBase registeredMelon in MelonBase.RegisteredMelons)
			{
				if (((registeredMelon != null) ? registeredMelon.Info : null) == null || string.Equals(registeredMelon.Info.Name, "ModMenu", StringComparison.OrdinalIgnoreCase))
				{
					continue;
				}
				ModMenuItem modMenuItem = new ModMenuItem
				{
					Name = (registeredMelon.Info.Name ?? "Unknown Mod"),
					Version = (registeredMelon.Info.Version ?? "1.0.0"),
					Author = (registeredMelon.Info.Author ?? "Unknown"),
					Melon = registeredMelon
				};
				string value = Normalize(modMenuItem.Name);
				MelonAssembly melonAssembly = registeredMelon.MelonAssembly;
				string value2 = Normalize((melonAssembly == null) ? null : melonAssembly.Assembly?.GetName().Name);
				foreach (MelonPreferences_Category category in MelonPreferences.Categories)
				{
					if (category == null || string.Equals(category.Identifier, "ModMenu_States", StringComparison.OrdinalIgnoreCase))
					{
						continue;
					}
					string text = Normalize(category.Identifier);
					string text2 = Normalize(category.DisplayName);
					bool flag = !string.IsNullOrEmpty(value) && (text.Contains(value) || text2.Contains(value));
					bool flag2 = !string.IsNullOrEmpty(value2) && (text.Contains(value2) || text2.Contains(value2));
					if (flag || flag2)
					{
						modMenuItem.Categories.Add(category);
						if (!string.IsNullOrEmpty(category.Identifier))
						{
							hashSet.Add(category.Identifier);
						}
					}
				}
				list.Add(modMenuItem);
			}
			foreach (MelonPreferences_Category category2 in MelonPreferences.Categories)
			{
				if (category2 != null && !string.IsNullOrEmpty(category2.Identifier) && !hashSet.Contains(category2.Identifier) && category2.Entries != null && category2.Entries.Count != 0 && !category2.Identifier.StartsWith("MelonLoader", StringComparison.OrdinalIgnoreCase) && !string.Equals(category2.Identifier, "ModMenu_States", StringComparison.OrdinalIgnoreCase))
				{
					list.Add(new ModMenuItem
					{
						Name = category2.Identifier,
						Version = "CFG",
						Author = "MelonPreferences",
						IsUnlinkedCategory = true,
						Categories = new List<MelonPreferences_Category> { category2 }
					});
				}
			}
			return list;
		}

		public static void ResetAllToDefault(List<MelonPreferences_Entry> entries)
		{
			if (entries == null)
			{
				return;
			}
			foreach (MelonPreferences_Entry entry in entries)
			{
				if (entry != null)
				{
					entry.ResetToDefault();
				}
			}
			MelonPreferences.Save();
		}

		public static void ToggleOrCycleEntry(MelonPreferences_Entry entry)
		{
			if (entry == null)
			{
				return;
			}
			Type reflectedType = entry.GetReflectedType();
			if (reflectedType == typeof(bool) && entry.BoxedValue is bool flag)
			{
				entry.BoxedValue = !flag;
				MelonPreferences.Save();
			}
			else
			{
				if (!reflectedType.IsEnum || entry.BoxedValue == null)
				{
					return;
				}
				Array values = Enum.GetValues(reflectedType);
				if (values.Length > 0)
				{
					int num = Array.IndexOf(values, entry.BoxedValue);
					int index = (num + 1) % values.Length;
					object value = values.GetValue(index);
					if (value != null)
					{
						entry.BoxedValue = value;
						MelonPreferences.Save();
					}
				}
			}
		}

		public static void StepNumericEntry(MelonPreferences_Entry entry, float delta, bool saveImmediately = true)
		{
			if (entry == null)
			{
				return;
			}
			Type reflectedType = entry.GetReflectedType();
			if (reflectedType == typeof(int) && entry.BoxedValue is int num)
			{
				entry.BoxedValue = num + (int)Math.Round(delta);
				if (saveImmediately)
				{
					MelonPreferences.Save();
				}
			}
			else if (reflectedType == typeof(float) && entry.BoxedValue is float num2)
			{
				entry.BoxedValue = (float)Math.Round(num2 + delta, 2);
				if (saveImmediately)
				{
					MelonPreferences.Save();
				}
			}
		}

		public static string FormatValue(MelonPreferences_Entry entry)
		{
			if (((entry != null) ? entry.BoxedValue : null) == null)
			{
				return "null";
			}
			if (entry.BoxedValue is bool flag)
			{
				return flag ? "ON" : "OFF";
			}
			if (entry.BoxedValue is float num)
			{
				return num.ToString("0.##", CultureInfo.InvariantCulture);
			}
			return entry.BoxedValue.ToString() ?? "null";
		}

		private static string Normalize(string s)
		{
			if (string.IsNullOrEmpty(s))
			{
				return string.Empty;
			}
			return s.Replace(" ", "").Replace("_", "").Replace("-", "")
				.ToLowerInvariant();
		}
	}
}