Decompiled source of ModConfigMenu v1.0.3

ModConfigMenu.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HBS.Pooling;
using HarmonyLib;
using InControl;
using Necro;
using Necro.UI;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: AssemblyDescription("Universal configuration menu for BepInEx mods in Necropolis. Provides in-game UI for managing mod settings.")]
[assembly: AssemblyConfiguration("")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyTitle("Necropolis Mod Config Menu by KoMiKoZa")]
[assembly: AssemblyCopyright("Copyright © KoMiKoZa 2025")]
[assembly: AssemblyCompany("KoMiKoZa")]
[assembly: AssemblyProduct("Necropolis Mod Config Menu")]
[assembly: ComVisible(false)]
[assembly: AssemblyFileVersion("1.0.2.0")]
[assembly: AssemblyTrademark("")]
[assembly: Guid("481f31b5-cfc6-414e-80b1-e8cd99d13528")]
[assembly: AssemblyVersion("1.0.2.0")]
namespace ModConfigMenu;

[BepInPlugin("komikoza.necropolis.modconfigmenu", "Necropolis Mod Config Menu", "1.0.2")]
public class Plugin : BaseUnityPlugin
{
	private const string GUID = "komikoza.necropolis.modconfigmenu";

	private const string NAME = "Necropolis Mod Config Menu";

	private const string VERSION = "1.0.2";

	private const float SECTION_SPACER_HEIGHT = 30f;

	private const float MODAL_FONT_SCALE = 1.25f;

	private const float MENU_CHECK_INTERVAL = 1f;

	private const float MENU_CLOSE_DELAY = 0.1f;

	private const float ENSURE_EVENT_SYSTEM_DELAY = 0.2f;

	private const int INPUT_DRAIN_FRAMES = 10;

	private const int BUTTON_RELEASE_WAIT_FRAMES = 5;

	private const int EXTRA_INPUT_DRAIN_FRAMES = 10;

	private const int INCONTROL_MAX_WAIT_FRAMES = 30;

	public static Plugin Instance;

	public static ManualLogSource Log;

	private static bool mainMenuButtonAdded = false;

	private int frameCounter = 0;

	private static bool justClosedModlist = false;

	private static GameObject cachedMenuParent;

	private static GameObject mainMenuButtonLayout;

	private static GameObject modalDialogController;

	private static readonly KeyCode[] allKeyCodes = (KeyCode[])Enum.GetValues(typeof(KeyCode));

	public static ConfigEntry<bool> enableLogging;

	private static ConfigEntry<bool> showUnsupportedTypes;

	private static ConfigEntry<bool> allowForbiddenKeys;

	private static Color highlightColor = new Color(1f, 1f, 0f, 1f);

	private static MenuContainer modListMenu;

	private static MenuContainer currentConfigMenu;

	private static float savedModListScrollPosition = 1f;

	private static bool rebindCancelled = false;

	private void Awake()
	{
		//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Expected O, but got Unknown
		Instance = this;
		Log = ((BaseUnityPlugin)this).Logger;
		enableLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableLogging", false, "Enable debug logging to console");
		showUnsupportedTypes = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowUnsupportedTypes", false, "Show unsupported config types (greyed out)");
		allowForbiddenKeys = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced", "AllowForbiddenKeyRebind", false, "WARNING: Allows rebinding menu navigation keys. May break mod menu. Use at own risk.");
		allowForbiddenKeys.SettingChanged += OnForbiddenKeysChanged;
		Log.LogInfo((object)"================================================");
		Log.LogInfo((object)string.Format("{0} v{1} loaded!", "Necropolis Mod Config Menu", "1.0.2"));
		Log.LogInfo((object)"================================================");
		try
		{
			Harmony val = new Harmony("komikoza.necropolis.modconfigmenu");
			val.PatchAll();
		}
		catch (Exception ex)
		{
			LogError("Failed to apply Harmony patches: " + ex.Message);
		}
	}

	private void OnForbiddenKeysChanged(object sender, EventArgs args)
	{
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Expected O, but got Unknown
		if (allowForbiddenKeys.Value && !((Object)(object)Instance == (Object)null) && !((Object)(object)Instance != (Object)(object)this))
		{
			ModalDialogController.CreateModal("<color=" + ColorToHex(highlightColor) + ">WARNING: You have disabled the forbidden key protection.\n\nYou can now rebind menu navigation and default game action keys.\n\nThat may break everything.\n\nUse at your own risk!</color>", "Hard Lock Disabled", (ModalType)0, (OnModalClosed)null, (ModalButton[])(object)new ModalButton[1]
			{
				new ModalButton("I understand", (InputControlType)11)
			});
			((MonoBehaviour)this).StartCoroutine(FormatModalText());
		}
	}

	private void Update()
	{
		frameCounter++;
		if (frameCounter < 60)
		{
			return;
		}
		frameCounter = 0;
		GameObject val = GameObject.Find("Start Screen/Main Menu Group/MainButtonLayout");
		if ((Object)(object)val != (Object)null && val.activeInHierarchy)
		{
			if ((Object)(object)val.transform.Find("ModManager") == (Object)null)
			{
				if (!mainMenuButtonAdded)
				{
					TryAddModButton();
					mainMenuButtonAdded = true;
				}
			}
			else
			{
				mainMenuButtonAdded = true;
			}
		}
		else
		{
			mainMenuButtonAdded = false;
		}
	}

	private void OnDestroy()
	{
		if (allowForbiddenKeys != null)
		{
			allowForbiddenKeys.SettingChanged -= OnForbiddenKeysChanged;
		}
		if ((Object)(object)modListMenu != (Object)null)
		{
			try
			{
				Object.Destroy((Object)(object)((Component)modListMenu).gameObject);
			}
			catch (Exception ex)
			{
				LogError("Failed to destroy modListMenu: " + ex.Message);
			}
			modListMenu = null;
		}
		if ((Object)(object)currentConfigMenu != (Object)null)
		{
			try
			{
				Object.Destroy((Object)(object)((Component)currentConfigMenu).gameObject);
			}
			catch (Exception ex)
			{
				LogError("Failed to destroy currentConfigMenu: " + ex.Message);
			}
			currentConfigMenu = null;
		}
		cachedMenuParent = null;
		mainMenuButtonLayout = null;
		modalDialogController = null;
		mainMenuButtonAdded = false;
		justClosedModlist = false;
		LogInfo("Mod Config Menu cleanup complete");
	}

	private void TryAddModButton()
	{
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Expected O, but got Unknown
		//IL_0210: Unknown result type (might be due to invalid IL or missing references)
		//IL_021a: Expected O, but got Unknown
		try
		{
			GameObject val = GameObject.Find("Start Screen/Main Menu Group/MainButtonLayout");
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Menu_MainMenu instance = Menu_MainMenu.Instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.buttonTemplate == (Object)null)
			{
				return;
			}
			Transform val2 = val.transform.Find("Options");
			if ((Object)(object)val2 == (Object)null)
			{
				return;
			}
			Button val3 = (Button)Object.Instantiate((Object)(object)instance.buttonTemplate, val.transform);
			if ((Object)(object)val3 == (Object)null)
			{
				LogError("Failed to instantiate mod button");
				return;
			}
			((Object)val3).name = "ModManager";
			Transform val4 = val.transform.Find("Restart");
			if ((Object)(object)val4 != (Object)null)
			{
				int siblingIndex = val4.GetSiblingIndex();
				((Component)val3).transform.SetSiblingIndex(siblingIndex + 1);
			}
			else
			{
				int siblingIndex2 = val2.GetSiblingIndex();
				((Component)val3).transform.SetSiblingIndex(siblingIndex2);
			}
			Component component = ((Component)val3).GetComponent("MenuEvent");
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			Component component2 = ((Component)val3).GetComponent("PrefabLink");
			if ((Object)(object)component2 != (Object)null)
			{
				Object.Destroy((Object)(object)component2);
			}
			RectTransform component3 = ((Component)val3).GetComponent<RectTransform>();
			RectTransform component4 = ((Component)val2).GetComponent<RectTransform>();
			CopyRectTransformProperties(component4, component3);
			Text componentInChildren = ((Component)val3).GetComponentInChildren<Text>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.text = "Mods";
				Component component5 = ((Component)componentInChildren).gameObject.GetComponent("LocalizedText");
				if ((Object)(object)component5 != (Object)null)
				{
					Object.Destroy((Object)(object)component5);
				}
				Component component6 = ((Component)componentInChildren).gameObject.GetComponent("TextUpdater");
				if ((Object)(object)component6 != (Object)null)
				{
					Object.Destroy((Object)(object)component6);
				}
			}
			((UnityEventBase)val3.onClick).RemoveAllListeners();
			((UnityEvent)val3.onClick).AddListener(new UnityAction(ShowModList));
			LogInfo("Mod Config Menu button added to main menu");
		}
		catch (Exception ex)
		{
			LogError("Failed to add mod button: " + ex.Message);
		}
	}

	public static void ShowModList()
	{
		//IL_0215: Unknown result type (might be due to invalid IL or missing references)
		//IL_021f: Expected O, but got Unknown
		try
		{
			LogInfo("=== OPENING MOD CONFIG MENU ===");
			Menu_MainMenu instance = Menu_MainMenu.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				LogError("Menu_MainMenu not found!");
				return;
			}
			GameObject val = mainMenuButtonLayout;
			if ((Object)(object)val == (Object)null)
			{
				val = (mainMenuButtonLayout = GameObject.Find("Start Screen/Main Menu Group/MainButtonLayout"));
			}
			if ((Object)(object)val != (Object)null && val.activeInHierarchy)
			{
				val.SetActive(false);
				LogInfo("MainButtonLayout hidden");
			}
			if ((Object)(object)modListMenu == (Object)null)
			{
				if ((Object)(object)cachedMenuParent == (Object)null)
				{
					cachedMenuParent = GameObject.Find("Bootstrapper/Main Canvas/Screen Controller/Menu Container");
				}
				if ((Object)(object)cachedMenuParent == (Object)null)
				{
					LogError("Menu Container parent not found!");
					return;
				}
				modListMenu = PoolManager.Spawn<MenuContainer>(instance.menuTemplate, cachedMenuParent.transform);
				if ((Object)(object)modListMenu == (Object)null)
				{
					LogError("Failed to spawn modListMenu from template!");
					return;
				}
				((Object)modListMenu).name = "MenuContainer (MOD_MANAGER)";
				modListMenu.header = "Mods";
				((Component)modListMenu).gameObject.SetActive(false);
				Animator component = ((Component)modListMenu).GetComponent<Animator>();
				if ((Object)(object)component != (Object)null)
				{
					((Behaviour)component).enabled = false;
				}
				MenuContainer componentInChildren = cachedMenuParent.GetComponentInChildren<MenuContainer>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					RectTransform component2 = ((Component)modListMenu).GetComponent<RectTransform>();
					RectTransform component3 = ((Component)componentInChildren).GetComponent<RectTransform>();
					CopyRectTransformProperties(component3, component2);
				}
				PopulateModList(modListMenu);
				Canvas.ForceUpdateCanvases();
				Transform parent = ((Component)modListMenu).transform.parent;
				if ((Object)(object)parent != (Object)null)
				{
					VerticalLayoutGroup component4 = ((Component)parent).GetComponent<VerticalLayoutGroup>();
					if ((Object)(object)component4 != (Object)null)
					{
						LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform)((Component)component4).transform);
					}
				}
				LayoutRebuilder.ForceRebuildLayoutImmediate(((Component)modListMenu).GetComponent<RectTransform>());
				ScrollRect componentInChildren2 = ((Component)modListMenu).GetComponentInChildren<ScrollRect>();
				if ((Object)(object)componentInChildren2 != (Object)null)
				{
					componentInChildren2.verticalNormalizedPosition = 1f;
				}
			}
			if ((Object)(object)modListMenu == (Object)null)
			{
				LogError("modListMenu is null after creation attempt!");
				return;
			}
			if ((Object)(object)val != (Object)null && (Object)(object)GameObject.Find("Start Screen") != (Object)null)
			{
				((AnimatedScreenController)instance).CloseAll();
				justClosedModlist = true;
				instance.OpenScreen(modListMenu, (Action)RestoreMainMenu);
			}
			else
			{
				instance.OpenScreen(modListMenu, (Action)null);
			}
			Animator component5 = ((Component)modListMenu).GetComponent<Animator>();
			if ((Object)(object)component5 != (Object)null)
			{
				((Behaviour)component5).enabled = true;
			}
			if ((Object)(object)Instance != (Object)null)
			{
				((MonoBehaviour)Instance).StartCoroutine(RestoreModListScrollPosition());
			}
			LogInfo("Mod Config Menu opened");
		}
		catch (Exception ex)
		{
			LogError("Error in ShowModList: " + ex.Message);
		}
	}

	private static IEnumerator RestoreModListScrollPosition()
	{
		yield return null;
		yield return null;
		if ((Object)(object)modListMenu != (Object)null)
		{
			ScrollRect componentInChildren = ((Component)modListMenu).GetComponentInChildren<ScrollRect>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.verticalNormalizedPosition = savedModListScrollPosition;
				LogInfo("Restored modlist scroll position: " + savedModListScrollPosition);
			}
		}
	}

	public static void CloseAllModMenus()
	{
		try
		{
			Menu_MainMenu instance = Menu_MainMenu.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				if ((Object)(object)currentConfigMenu != (Object)null && (Object)(object)instance.topMenuContainer == (Object)(object)currentConfigMenu)
				{
					((AnimatedScreenController)instance).CloseCurrent();
					LogInfo("Closed config menu to prevent conflict with game UI");
				}
				if ((Object)(object)modListMenu != (Object)null && (Object)(object)instance.topMenuContainer == (Object)(object)modListMenu)
				{
					((AnimatedScreenController)instance).CloseCurrent();
					LogInfo("Closed mod list to prevent conflict with game UI");
				}
			}
		}
		catch (Exception ex)
		{
			LogError("Error in CloseAllModMenus: " + ex.Message);
		}
	}

	private static string ColorToHex(Color color)
	{
		int num = Mathf.RoundToInt(color.r * 255f);
		int num2 = Mathf.RoundToInt(color.g * 255f);
		int num3 = Mathf.RoundToInt(color.b * 255f);
		int num4 = Mathf.RoundToInt(color.a * 255f);
		return $"#{num:X2}{num2:X2}{num3:X2}{num4:X2}";
	}

	private static void RestoreMainMenu()
	{
		if (!((Object)(object)Menu_MainMenu.Instance != (Object)null) || ((AnimatedScreenController)Menu_MainMenu.Instance).HasActiveStack)
		{
			return;
		}
		GameObject val = GameObject.Find("Start Screen/Main Menu Group/MainButtonLayout");
		if ((Object)(object)val != (Object)null)
		{
			val.SetActive(true);
			LogInfo("MainButtonLayout restored");
			if (justClosedModlist && (Object)(object)Instance != (Object)null)
			{
				((MonoBehaviour)Instance).StartCoroutine(SelectFirstMainMenuButton());
				justClosedModlist = false;
			}
		}
	}

	private static IEnumerator SelectFirstMainMenuButton()
	{
		yield return null;
		EventSystem eventSystem = EventSystem.current;
		GameObject buttonLayout = GameObject.Find("Start Screen/Main Menu Group/MainButtonLayout");
		if (!((Object)(object)eventSystem != (Object)null) || !((Object)(object)buttonLayout != (Object)null) || !buttonLayout.activeInHierarchy)
		{
			yield break;
		}
		Button val = null;
		foreach (Transform item in buttonLayout.transform)
		{
			Transform val2 = item;
			Button component = ((Component)val2).GetComponent<Button>();
			if ((Object)(object)component != (Object)null && ((Behaviour)component).isActiveAndEnabled && ((Selectable)component).interactable)
			{
				val = component;
				break;
			}
		}
		if ((Object)(object)val != (Object)null)
		{
			eventSystem.SetSelectedGameObject(((Component)val).gameObject);
			LogInfo("Selected first main menu button: " + ((Object)val).name);
		}
	}

	private static void PopulateModList(MenuContainer menu)
	{
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b0: Expected O, but got Unknown
		if ((Object)(object)menu == (Object)null)
		{
			LogError("PopulateModList called with null menu!");
			return;
		}
		Menu_MainMenu instance = Menu_MainMenu.Instance;
		if ((Object)(object)instance == (Object)null)
		{
			LogError("Menu_MainMenu.Instance is null!");
			return;
		}
		List<PluginInfo> allPlugins = GetAllPlugins();
		LogInfo("Populating mod list with " + allPlugins.Count + " plugins...");
		foreach (PluginInfo item in allPlugins)
		{
			PluginInfo capturedPlugin = item;
			instance.AddButtonMenuItem(menu, item.Metadata.Name, (UnityAction)delegate
			{
				ShowConfigMenu(capturedPlugin);
			}, (string)null, (object[])null);
		}
		LogInfo("Mod list populated");
		SetupLoopableNavigation(menu);
	}

	private static List<PluginInfo> GetAllPlugins()
	{
		List<PluginInfo> list = new List<PluginInfo>();
		foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos)
		{
			list.Add(pluginInfo.Value);
		}
		return list;
	}

	private static void ShowConfigMenu(PluginInfo pluginInfo)
	{
		//IL_020a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0218: Unknown result type (might be due to invalid IL or missing references)
		//IL_0226: Unknown result type (might be due to invalid IL or missing references)
		//IL_0234: Unknown result type (might be due to invalid IL or missing references)
		//IL_0242: Unknown result type (might be due to invalid IL or missing references)
		//IL_0312: Unknown result type (might be due to invalid IL or missing references)
		//IL_031c: Expected O, but got Unknown
		try
		{
			if (pluginInfo == null)
			{
				LogError("ShowConfigMenu called with null pluginInfo!");
				return;
			}
			LogInfo("=== OPENING CONFIG FOR: " + pluginInfo.Metadata.Name + " ===");
			Menu_MainMenu instance = Menu_MainMenu.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				LogError("Menu_MainMenu.Instance is null!");
				return;
			}
			if ((Object)(object)modListMenu != (Object)null)
			{
				ScrollRect componentInChildren = ((Component)modListMenu).GetComponentInChildren<ScrollRect>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					savedModListScrollPosition = componentInChildren.verticalNormalizedPosition;
					LogInfo("Saved modlist scroll position: " + savedModListScrollPosition);
				}
			}
			RectTransform val = null;
			if ((Object)(object)currentConfigMenu != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)currentConfigMenu).gameObject);
				currentConfigMenu = null;
			}
			if ((Object)(object)cachedMenuParent == (Object)null)
			{
				cachedMenuParent = GameObject.Find("Bootstrapper/Main Canvas/Screen Controller/Menu Container");
			}
			if ((Object)(object)cachedMenuParent == (Object)null)
			{
				LogError("Menu Container parent not found!");
				return;
			}
			currentConfigMenu = PoolManager.Spawn<MenuContainer>(instance.menuTemplate, cachedMenuParent.transform);
			if ((Object)(object)currentConfigMenu == (Object)null)
			{
				LogError("Failed to spawn currentConfigMenu from template!");
				return;
			}
			((Object)currentConfigMenu).name = "MenuContainer (MOD_CONFIG)";
			((Component)currentConfigMenu).gameObject.SetActive(false);
			Animator component = ((Component)currentConfigMenu).GetComponent<Animator>();
			if ((Object)(object)component != (Object)null)
			{
				((Behaviour)component).enabled = false;
			}
			if ((Object)(object)modListMenu != (Object)null)
			{
				val = ((Component)currentConfigMenu).GetComponent<RectTransform>();
				RectTransform component2 = ((Component)modListMenu).GetComponent<RectTransform>();
				if ((Object)(object)val != (Object)null && (Object)(object)component2 != (Object)null)
				{
					val.sizeDelta = component2.sizeDelta;
					val.anchorMin = component2.anchorMin;
					val.anchorMax = component2.anchorMax;
					val.pivot = component2.pivot;
					((Transform)val).localScale = ((Transform)component2).localScale;
				}
			}
			currentConfigMenu.header = pluginInfo.Metadata.Name;
			if ((Object)(object)val == (Object)null)
			{
				val = ((Component)currentConfigMenu).GetComponent<RectTransform>();
			}
			PopulateConfigMenu(currentConfigMenu, pluginInfo);
			if ((Object)(object)pluginInfo.Instance != (Object)null && pluginInfo.Instance.Config != null && pluginInfo.Instance.Config.Count > 0)
			{
				Canvas.ForceUpdateCanvases();
				Transform parent = ((Component)currentConfigMenu).transform.parent;
				if ((Object)(object)parent != (Object)null)
				{
					VerticalLayoutGroup component3 = ((Component)parent).GetComponent<VerticalLayoutGroup>();
					if ((Object)(object)component3 != (Object)null)
					{
						LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform)((Component)component3).transform);
					}
				}
				if ((Object)(object)val != (Object)null)
				{
					LayoutRebuilder.ForceRebuildLayoutImmediate(val);
				}
			}
			ScrollRect componentInChildren2 = ((Component)currentConfigMenu).GetComponentInChildren<ScrollRect>();
			if ((Object)(object)componentInChildren2 != (Object)null)
			{
				componentInChildren2.verticalNormalizedPosition = 1f;
			}
			instance.OpenScreen(currentConfigMenu, (Action)null);
			Animator component4 = ((Component)currentConfigMenu).GetComponent<Animator>();
			if ((Object)(object)component4 != (Object)null)
			{
				((Behaviour)component4).enabled = true;
				LogInfo("Animator re-enabled");
			}
			LogInfo("Config menu opened");
		}
		catch (Exception ex)
		{
			LogError("Error in ShowConfigMenu: " + ex.Message);
		}
	}

	private static void ShowResetConfirmation(PluginInfo pluginInfo)
	{
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_009d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Expected O, but got Unknown
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Expected O, but got Unknown
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Expected O, but got Unknown
		OnModalClosed val = null;
		if (pluginInfo == null)
		{
			return;
		}
		try
		{
			string text = "<color=" + ColorToHex(highlightColor) + ">Reset all settings for " + pluginInfo.Metadata.Name + " to their default values?</color>";
			if (val == null)
			{
				val = (OnModalClosed)delegate(InputControlType buttonType)
				{
					//IL_0001: Unknown result type (might be due to invalid IL or missing references)
					//IL_0004: Invalid comparison between Unknown and I4
					//IL_002e: 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_0090: Expected O, but got Unknown
					if ((int)buttonType == 11)
					{
						int num = ResetConfigToDefaults(pluginInfo);
						ModalDialogController.CreateModal("<color=" + ColorToHex(highlightColor) + ">" + num + " settings have been reset to their default values for " + pluginInfo.Metadata.Name + ".</color>", "Settings Reset", (ModalType)0, (OnModalClosed)null, (ModalButton[])(object)new ModalButton[1]
						{
							new ModalButton("OK", (InputControlType)11)
						});
						if ((Object)(object)Instance != (Object)null)
						{
							((MonoBehaviour)Instance).StartCoroutine(FormatModalText());
						}
					}
				};
			}
			ModalDialogController.CreateModal(text, "Reset Configuration", (ModalType)0, val, (ModalButton[])(object)new ModalButton[2]
			{
				new ModalButton("Confirm", (InputControlType)11),
				new ModalButton("Cancel", (InputControlType)12)
			});
			if ((Object)(object)Instance != (Object)null)
			{
				((MonoBehaviour)Instance).StartCoroutine(FormatModalText());
			}
		}
		catch (Exception ex)
		{
			LogError("Error showing reset confirmation: " + ex.Message);
		}
	}

	private static int ResetConfigToDefaults(PluginInfo pluginInfo)
	{
		if (pluginInfo == null || (Object)(object)pluginInfo.Instance == (Object)null || pluginInfo.Instance.Config == null)
		{
			LogError("Cannot reset config - invalid plugin info");
			return 0;
		}
		try
		{
			ConfigFile config = pluginInfo.Instance.Config;
			int num = 0;
			foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in config)
			{
				ConfigEntryBase value = item.Value;
				if (value != null && value.DefaultValue != null)
				{
					value.BoxedValue = value.DefaultValue;
					num++;
				}
			}
			LogInfo("Reset " + num + " settings to defaults for " + pluginInfo.Metadata.Name);
			RefreshConfigMenuInPlace(pluginInfo);
			return num;
		}
		catch (Exception ex)
		{
			LogError("Error resetting config: " + ex.Message);
			return 0;
		}
	}

	private static void RefreshConfigMenuInPlace(PluginInfo pluginInfo)
	{
		if ((Object)(object)currentConfigMenu == (Object)null || pluginInfo == null)
		{
			return;
		}
		try
		{
			Menu_MainMenu instance = Menu_MainMenu.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				for (int num = ((Component)currentConfigMenu).transform.childCount - 1; num >= 0; num--)
				{
					Transform child = ((Component)currentConfigMenu).transform.GetChild(num);
					Object.Destroy((Object)(object)((Component)child).gameObject);
				}
				PopulateConfigMenu(currentConfigMenu, pluginInfo);
				LogInfo("Config menu refreshed in place");
			}
		}
		catch (Exception ex)
		{
			LogError("Error refreshing config menu: " + ex.Message);
		}
	}

	private static void ShowKeyRebindModal(ConfigEntryBase configEntry, string keyName, PluginInfo pluginInfo)
	{
		if (configEntry == null || string.IsNullOrEmpty(keyName))
		{
			LogError("ShowKeyRebindModal called with invalid parameters!");
			return;
		}
		try
		{
			rebindCancelled = false;
			SetButtonTextForRebind(currentConfigMenu, keyName, "[Press Any Key]");
			if ((Object)(object)Instance != (Object)null)
			{
				((MonoBehaviour)Instance).StartCoroutine(CaptureKeyWithModals(configEntry, keyName, pluginInfo));
			}
		}
		catch (Exception ex)
		{
			LogError("Error starting rebind: " + ex.Message);
		}
	}

	private static void SetButtonTextForRebind(MenuContainer menu, string keyName, string newText)
	{
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Expected O, but got Unknown
		if ((Object)(object)menu == (Object)null || string.IsNullOrEmpty(keyName))
		{
			return;
		}
		foreach (Transform item in ((Component)menu).transform)
		{
			Transform val = item;
			Button component = ((Component)val).GetComponent<Button>();
			if ((Object)(object)component != (Object)null)
			{
				Text componentInChildren = ((Component)component).GetComponentInChildren<Text>();
				if ((Object)(object)componentInChildren != (Object)null && componentInChildren.text.Contains(keyName + ":"))
				{
					componentInChildren.text = keyName + ": " + newText;
					break;
				}
			}
		}
	}

	private static string GetFriendlyKeyName(KeyCode key)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0003: Invalid comparison between Unknown and I4
		//IL_0018: 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_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e2: Expected I4, but got Unknown
		//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
		if ((int)key == 0)
		{
			return "[Not Set]";
		}
		return "[" + (key - 303) switch
		{
			27 => "Button A / Cross", 
			28 => "Button B / Circle", 
			29 => "Button X / Square", 
			30 => "Button Y / Triangle", 
			31 => "Left Bumper / L1", 
			32 => "Right Bumper / R1", 
			33 => "Back / Select", 
			34 => "Start / Options", 
			35 => "Left Stick Click / L3", 
			36 => "Right Stick Click / R3", 
			37 => "Button 10", 
			38 => "Button 11", 
			39 => "Button 12", 
			40 => "Button 13", 
			41 => "Button 14", 
			42 => "Button 15", 
			43 => "Button 16", 
			44 => "Button 17", 
			45 => "Button 18", 
			46 => "Button 19", 
			1 => "Left Shift", 
			0 => "Right Shift", 
			3 => "Left Ctrl", 
			2 => "Right Ctrl", 
			5 => "Left Alt", 
			4 => "Right Alt", 
			_ => ((object)key).ToString(), 
		} + "]";
	}

	private static bool IsCancelButtonHeld()
	{
		return Input.GetKey((KeyCode)27);
	}

	private static bool IsForbiddenKey(KeyCode key)
	{
		//IL_0025: 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_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Invalid comparison between Unknown and I4
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Invalid comparison between Unknown and I4
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Invalid comparison between Unknown and I4
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Expected I4, but got Unknown
		//IL_0071: 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)
		//IL_008e: Expected I4, but got Unknown
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Invalid comparison between Unknown and I4
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Invalid comparison between Unknown and I4
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e4: Expected I4, but got Unknown
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Invalid comparison between Unknown and I4
		//IL_004e: 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_0067: Expected I4, but got Unknown
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Invalid comparison between Unknown and I4
		//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_0404: Expected I4, but got Unknown
		if (allowForbiddenKeys != null && allowForbiddenKeys.Value)
		{
			return false;
		}
		if ((int)key <= 52)
		{
			if ((int)key <= 13)
			{
				if ((int)key != 9 && (int)key != 13)
				{
					goto IL_040a;
				}
			}
			else if ((int)key != 32)
			{
				switch (key - 49)
				{
				case 0:
				case 1:
				case 2:
				case 3:
					break;
				default:
					goto IL_040a;
				}
			}
		}
		else if ((int)key <= 105)
		{
			switch (key - 97)
			{
			default:
				if ((int)key == 105)
				{
					break;
				}
				goto IL_040a;
			case 0:
			case 3:
			case 4:
				break;
			case 1:
			case 2:
				goto IL_040a;
			}
		}
		else
		{
			switch (key - 113)
			{
			default:
				switch (key - 271)
				{
				default:
					switch (key - 303)
					{
					case 0:
					case 1:
					case 2:
					case 3:
					case 20:
					case 21:
					case 27:
					case 28:
					case 29:
					case 30:
					case 31:
					case 32:
					case 33:
					case 34:
					case 35:
					case 36:
					case 37:
					case 38:
					case 39:
					case 40:
					case 41:
					case 42:
					case 43:
					case 67:
					case 68:
					case 69:
					case 70:
					case 71:
					case 72:
					case 73:
					case 74:
					case 75:
					case 76:
					case 77:
					case 78:
					case 79:
					case 80:
					case 81:
					case 82:
					case 83:
					case 87:
					case 88:
					case 89:
					case 90:
					case 91:
					case 92:
					case 93:
					case 94:
					case 95:
					case 96:
					case 107:
					case 108:
					case 109:
					case 110:
					case 111:
					case 112:
					case 113:
					case 114:
					case 115:
					case 116:
					case 127:
					case 128:
					case 129:
					case 130:
					case 131:
					case 132:
					case 133:
					case 134:
					case 135:
					case 136:
					case 147:
					case 148:
					case 149:
					case 150:
					case 151:
					case 152:
					case 153:
					case 154:
					case 155:
					case 156:
					case 167:
					case 168:
					case 169:
					case 170:
					case 171:
					case 172:
					case 173:
					case 174:
					case 175:
					case 176:
					case 187:
					case 188:
					case 189:
					case 190:
					case 191:
					case 192:
					case 193:
					case 194:
					case 195:
					case 196:
						break;
					default:
						goto IL_040a;
					}
					break;
				case 0:
				case 2:
				case 3:
				case 4:
				case 5:
					break;
				case 1:
					goto IL_040a;
				}
				break;
			case 0:
			case 1:
			case 2:
			case 5:
			case 6:
				break;
			case 3:
			case 4:
				goto IL_040a;
			}
		}
		return true;
		IL_040a:
		return false;
	}

	private static IEnumerator CaptureKeyWithModals(ConfigEntryBase configEntry, string keyName, PluginInfo pluginInfo)
	{
		if (configEntry == null || string.IsNullOrEmpty(keyName))
		{
			yield break;
		}
		LogInfo("Capturing input for: " + keyName);
		KeyCode oldKey = (KeyCode)configEntry.BoxedValue;
		Button rebindButton = null;
		ColorBlock originalColorBlock = default(ColorBlock);
		Animator buttonAnimator = null;
		bool animatorWasEnabled = false;
		if ((Object)(object)currentConfigMenu != (Object)null)
		{
			foreach (Transform item in ((Component)currentConfigMenu).transform)
			{
				Transform val = item;
				Button component = ((Component)val).GetComponent<Button>();
				if ((Object)(object)component != (Object)null)
				{
					Text componentInChildren = ((Component)component).GetComponentInChildren<Text>();
					if ((Object)(object)componentInChildren != (Object)null && componentInChildren.text.Contains(keyName + ":"))
					{
						rebindButton = component;
						break;
					}
				}
			}
		}
		if ((Object)(object)rebindButton != (Object)null)
		{
			originalColorBlock = ((Selectable)rebindButton).colors;
			ColorBlock colors = ((Selectable)rebindButton).colors;
			Color val2 = default(Color);
			((Color)(ref val2))..ctor(1f, 1f, 1f, 1f);
			((ColorBlock)(ref colors)).normalColor = val2;
			((ColorBlock)(ref colors)).highlightedColor = val2;
			((ColorBlock)(ref colors)).pressedColor = val2;
			((ColorBlock)(ref colors)).disabledColor = val2;
			((ColorBlock)(ref colors)).colorMultiplier = 1f;
			((Selectable)rebindButton).colors = colors;
			buttonAnimator = ((Component)rebindButton).GetComponent<Animator>();
			if ((Object)(object)buttonAnimator != (Object)null)
			{
				animatorWasEnabled = ((Behaviour)buttonAnimator).enabled;
				((Behaviour)buttonAnimator).enabled = false;
			}
		}
		bool originalCursorVisible = Cursor.visible;
		CursorLockMode originalLockState = Cursor.lockState;
		Cursor.visible = false;
		Cursor.lockState = (CursorLockMode)1;
		EventSystem eventSystem = EventSystem.current;
		bool eventSystemWasEnabled = false;
		if ((Object)(object)eventSystem != (Object)null)
		{
			eventSystemWasEnabled = ((Behaviour)eventSystem).enabled;
			((Behaviour)eventSystem).enabled = false;
			LogInfo("EventSystem DISABLED for rebind capture");
		}
		else
		{
			LogInfo("Warning: Could not find EventSystem");
		}
		for (int i = 0; i < 10; i++)
		{
			yield return null;
			if (rebindCancelled)
			{
				yield break;
			}
		}
		bool keyPressed = false;
		KeyCode capturedKey = (KeyCode)0;
		while (!keyPressed && !rebindCancelled)
		{
			if (Input.GetKeyDown((KeyCode)27))
			{
				LogInfo("ESC pressed - cancelling rebind");
				rebindCancelled = true;
				break;
			}
			KeyCode[] array = allKeyCodes;
			foreach (KeyCode val3 in array)
			{
				if (Input.GetKeyDown(val3) && (int)val3 != 0 && (int)val3 != 27 && (int)val3 != 336 && (int)val3 != 337 && (int)val3 != 338 && (int)val3 != 339)
				{
					capturedKey = val3;
					keyPressed = true;
					LogInfo("Key captured: " + val3);
					break;
				}
			}
			if (keyPressed || rebindCancelled)
			{
				break;
			}
			yield return null;
		}
		Cursor.visible = originalCursorVisible;
		Cursor.lockState = originalLockState;
		if ((Object)(object)rebindButton != (Object)null)
		{
			((Selectable)rebindButton).colors = originalColorBlock;
			if ((Object)(object)buttonAnimator != (Object)null)
			{
				((Behaviour)buttonAnimator).enabled = animatorWasEnabled;
			}
			if (rebindCancelled)
			{
				((Selectable)rebindButton).OnDeselect((BaseEventData)null);
			}
		}
		if (rebindCancelled)
		{
			LogInfo("Capture cancelled - waiting for button release");
			while (IsCancelButtonHeld())
			{
				yield return null;
			}
			for (int j = 0; j < 5; j++)
			{
				yield return null;
			}
			for (int k = 0; k < 10; k++)
			{
				yield return null;
			}
			InputDevice activeDevice = InputManager.ActiveDevice;
			if (activeDevice != null)
			{
				int maxWait = 30;
				while (maxWait > 0 && (activeDevice.Action2.WasPressed || activeDevice.Action2.IsPressed))
				{
					yield return null;
					maxWait--;
				}
				LogInfo("InControl Action2 cleared");
			}
			LogInfo("Extra input drain delay complete");
			if ((Object)(object)eventSystem != (Object)null)
			{
				((Behaviour)eventSystem).enabled = eventSystemWasEnabled;
				LogInfo("EventSystem restored after cancel");
			}
			UpdateKeyButtonText(currentConfigMenu, keyName, oldKey);
			yield break;
		}
		if ((Object)(object)eventSystem != (Object)null)
		{
			((Behaviour)eventSystem).enabled = eventSystemWasEnabled;
			LogInfo("EventSystem restored");
		}
		LogInfo("Input captured: " + capturedKey);
		if (IsForbiddenKey(capturedKey))
		{
			UpdateKeyButtonText(currentConfigMenu, keyName, oldKey);
			if ((Object)(object)rebindButton != (Object)null && (Object)(object)eventSystem != (Object)null && (Object)(object)eventSystem.currentSelectedGameObject == (Object)(object)((Component)rebindButton).gameObject)
			{
				eventSystem.SetSelectedGameObject((GameObject)null);
			}
			ModalDialogController.CreateModal("<color=" + ColorToHex(highlightColor) + ">" + GetFriendlyKeyName(capturedKey) + " cannot be rebound.\n\nThis key is reserved for menu navigation.\n\nAdvanced users: Set 'AllowForbiddenKeyRebind' to true in Mod Config Menu settings to bypass this restriction.</color>", "Reserved Key", (ModalType)0, (OnModalClosed)null, (ModalButton[])(object)new ModalButton[1]
			{
				new ModalButton("OK", (InputControlType)11)
			});
			if ((Object)(object)Instance != (Object)null)
			{
				((MonoBehaviour)Instance).StartCoroutine(FormatModalText());
			}
			yield break;
		}
		if (capturedKey == oldKey)
		{
			UpdateKeyButtonText(currentConfigMenu, keyName, oldKey);
			if ((Object)(object)rebindButton != (Object)null && (Object)(object)eventSystem != (Object)null && (Object)(object)eventSystem.currentSelectedGameObject == (Object)(object)((Component)rebindButton).gameObject)
			{
				eventSystem.SetSelectedGameObject((GameObject)null);
			}
			ModalDialogController.CreateModal("<color=" + ColorToHex(highlightColor) + ">" + keyName + " is already bound to " + GetFriendlyKeyName(capturedKey) + ".</color>", "Already Bound", (ModalType)0, (OnModalClosed)null, (ModalButton[])(object)new ModalButton[1]
			{
				new ModalButton("OK", (InputControlType)11)
			});
			if ((Object)(object)Instance != (Object)null)
			{
				((MonoBehaviour)Instance).StartCoroutine(FormatModalText());
			}
			yield break;
		}
		string duplicateInfo = CheckForDuplicateKeybind(capturedKey, pluginInfo, configEntry);
		if (!string.IsNullOrEmpty(duplicateInfo))
		{
			UpdateKeyButtonText(currentConfigMenu, keyName, oldKey);
			if ((Object)(object)rebindButton != (Object)null && (Object)(object)eventSystem != (Object)null && (Object)(object)eventSystem.currentSelectedGameObject == (Object)(object)((Component)rebindButton).gameObject)
			{
				eventSystem.SetSelectedGameObject((GameObject)null);
			}
			ModalDialogController.CreateModal("<color=" + ColorToHex(highlightColor) + ">" + GetFriendlyKeyName(capturedKey) + " is already bound to:\n" + duplicateInfo + "\n\nCannot rebind.</color>", "Duplicate Binding", (ModalType)0, (OnModalClosed)null, (ModalButton[])(object)new ModalButton[1]
			{
				new ModalButton("OK", (InputControlType)11)
			});
			if ((Object)(object)Instance != (Object)null)
			{
				((MonoBehaviour)Instance).StartCoroutine(FormatModalText());
			}
			yield break;
		}
		configEntry.BoxedValue = capturedKey;
		LogInfo(keyName + " rebound to: " + capturedKey);
		UpdateKeyButtonText(currentConfigMenu, keyName, capturedKey);
		if ((Object)(object)rebindButton != (Object)null && (Object)(object)eventSystem != (Object)null && (Object)(object)eventSystem.currentSelectedGameObject == (Object)(object)((Component)rebindButton).gameObject)
		{
			eventSystem.SetSelectedGameObject((GameObject)null);
		}
		string keyString = ((object)capturedKey).ToString();
		bool isGamepadButton = keyString.Contains("Joystick") && keyString.Contains("Button");
		string successMessage = keyName + " rebound:\n" + GetFriendlyKeyName(oldKey) + " → " + GetFriendlyKeyName(capturedKey);
		if (isGamepadButton)
		{
			successMessage += "\n\nNote: Button names may differ on non-standard controllers, but functionality works correctly.";
		}
		ModalDialogController.CreateModal("<color=" + ColorToHex(highlightColor) + ">" + successMessage + "</color>", "Success", (ModalType)0, (OnModalClosed)null, (ModalButton[])(object)new ModalButton[1]
		{
			new ModalButton("OK", (InputControlType)11)
		});
		if ((Object)(object)Instance != (Object)null)
		{
			((MonoBehaviour)Instance).StartCoroutine(FormatModalText());
		}
	}

	private static IEnumerator FormatModalText()
	{
		yield return null;
		GameObject modalObj = modalDialogController;
		if ((Object)(object)modalObj == (Object)null)
		{
			modalObj = (modalDialogController = GameObject.Find("Bootstrapper/Main Canvas/Modal Dialog Controller"));
		}
		if (!((Object)(object)modalObj != (Object)null))
		{
			yield break;
		}
		Text[] componentsInChildren = modalObj.GetComponentsInChildren<Text>();
		Text[] array = componentsInChildren;
		foreach (Text val in array)
		{
			if ((Object)(object)val != (Object)null && (val.text.Contains("bound") || val.text.Contains("rebound") || val.text.Contains("Reset") || val.text.Contains("settings")))
			{
				val.supportRichText = true;
				val.alignment = (TextAnchor)4;
				int fontSize = val.fontSize;
				val.fontSize = (int)((float)fontSize * 1.25f);
				LogInfo("Formatted modal text: centered and increased font to " + val.fontSize);
			}
		}
	}

	private static string CheckForDuplicateKeybind(KeyCode keyToCheck, PluginInfo currentPlugin, ConfigEntryBase currentEntry)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0003: Invalid comparison between Unknown and I4
		//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: 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)
		if ((int)keyToCheck == 0)
		{
			return null;
		}
		StringBuilder stringBuilder = new StringBuilder();
		foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos)
		{
			PluginInfo value = pluginInfo.Value;
			if (value == null || (Object)(object)value.Instance == (Object)null || value.Instance.Config == null)
			{
				continue;
			}
			foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in value.Instance.Config)
			{
				ConfigEntryBase value2 = item.Value;
				if (value2 != null && (object)value2.SettingType == typeof(KeyCode) && (value != currentPlugin || value2 != currentEntry))
				{
					KeyCode val = (KeyCode)value2.BoxedValue;
					if (val == keyToCheck)
					{
						stringBuilder.AppendLine("• " + value2.Definition.Key + " (" + value.Metadata.Name + ")");
					}
				}
			}
		}
		return (stringBuilder.Length > 0) ? stringBuilder.ToString().TrimEnd(new char[0]) : null;
	}

	private static void UpdateKeyButtonText(MenuContainer menu, string keyName, KeyCode newKey)
	{
		//IL_0023: 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_0047: Expected O, but got Unknown
		if ((Object)(object)menu == (Object)null || string.IsNullOrEmpty(keyName))
		{
			return;
		}
		string friendlyKeyName = GetFriendlyKeyName(newKey);
		foreach (Transform item in ((Component)menu).transform)
		{
			Transform val = item;
			Button component = ((Component)val).GetComponent<Button>();
			if ((Object)(object)component != (Object)null)
			{
				Text componentInChildren = ((Component)component).GetComponentInChildren<Text>();
				if ((Object)(object)componentInChildren != (Object)null && componentInChildren.text.Contains(keyName + ":"))
				{
					componentInChildren.text = keyName + ": " + friendlyKeyName;
					break;
				}
			}
		}
	}

	private static void CycleEnumValue(ConfigEntryBase configEntry, Array enumValues, MenuContainer menu, PluginInfo pluginInfo)
	{
		//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: Expected O, but got Unknown
		if (configEntry == null || enumValues == null || enumValues.Length == 0 || (Object)(object)menu == (Object)null)
		{
			LogError("CycleEnumValue called with invalid parameters!");
			return;
		}
		int num = Array.IndexOf(enumValues, configEntry.BoxedValue);
		if (num < 0)
		{
			LogError("Current enum value not found in array, resetting to first value");
			num = 0;
		}
		int index = (num + 1) % enumValues.Length;
		configEntry.BoxedValue = enumValues.GetValue(index);
		LogInfo("Cycled " + configEntry.Definition.Key + " to: " + configEntry.BoxedValue);
		string key = configEntry.Definition.Key;
		foreach (Transform item in ((Component)menu).transform)
		{
			Transform val = item;
			Button component = ((Component)val).GetComponent<Button>();
			if ((Object)(object)component != (Object)null)
			{
				Text componentInChildren = ((Component)component).GetComponentInChildren<Text>();
				if ((Object)(object)componentInChildren != (Object)null && componentInChildren.text.Contains(key))
				{
					componentInChildren.text = key + ": " + configEntry.BoxedValue.ToString();
					break;
				}
			}
		}
	}

	private static void PopulateConfigMenu(MenuContainer menu, PluginInfo pluginInfo)
	{
		//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_0261: Unknown result type (might be due to invalid IL or missing references)
		//IL_0330: Unknown result type (might be due to invalid IL or missing references)
		//IL_033c: Expected O, but got Unknown
		//IL_0355: Unknown result type (might be due to invalid IL or missing references)
		//IL_035c: Expected O, but got Unknown
		//IL_041f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0826: Unknown result type (might be due to invalid IL or missing references)
		//IL_082b: Unknown result type (might be due to invalid IL or missing references)
		//IL_085c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0870: Unknown result type (might be due to invalid IL or missing references)
		//IL_087c: Expected O, but got Unknown
		//IL_0a9c: Unknown result type (might be due to invalid IL or missing references)
		//IL_096f: Unknown result type (might be due to invalid IL or missing references)
		//IL_097b: Expected O, but got Unknown
		//IL_0a23: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)menu == (Object)null || pluginInfo == null)
		{
			LogError("PopulateConfigMenu called with null parameters!");
			return;
		}
		LogInfo("Populating config menu for: " + pluginInfo.Metadata.Name);
		if ((Object)(object)pluginInfo.Instance == (Object)null)
		{
			LogError("Plugin instance is null!");
			return;
		}
		Menu_MainMenu instance = Menu_MainMenu.Instance;
		if ((Object)(object)instance == (Object)null)
		{
			LogError("Menu_MainMenu.Instance is null!");
			return;
		}
		ConfigFile config = pluginInfo.Instance.Config;
		if (config == null)
		{
			LogError("Config is null!");
			return;
		}
		Text val2 = instance.AddTextMenuItem(menu, pluginInfo.Metadata.Name, true);
		if ((Object)(object)val2 != (Object)null)
		{
			Selectable[] components = ((Component)val2).gameObject.GetComponents<Selectable>();
			Selectable[] array = components;
			foreach (Selectable val3 in array)
			{
				if ((Object)(object)val3 != (Object)null)
				{
					((Behaviour)val3).enabled = false;
				}
			}
			Button component = ((Component)val2).gameObject.GetComponent<Button>();
			if ((Object)(object)component != (Object)null)
			{
				((Behaviour)component).enabled = false;
			}
		}
		Text val4 = instance.AddTextMenuItem(menu, "Version: " + pluginInfo.Metadata.Version, false);
		if ((Object)(object)val4 != (Object)null)
		{
			((Graphic)val4).color = Color.gray;
			Selectable[] components = ((Component)val4).gameObject.GetComponents<Selectable>();
			Selectable[] array = components;
			foreach (Selectable val3 in array)
			{
				if ((Object)(object)val3 != (Object)null)
				{
					((Behaviour)val3).enabled = false;
				}
			}
			Button component = ((Component)val4).gameObject.GetComponent<Button>();
			if ((Object)(object)component != (Object)null)
			{
				((Behaviour)component).enabled = false;
			}
		}
		Text val5 = instance.AddTextMenuItem(menu, pluginInfo.Metadata.GUID, false);
		if ((Object)(object)val5 != (Object)null)
		{
			((Graphic)val5).color = Color.gray;
			Selectable[] components = ((Component)val5).gameObject.GetComponents<Selectable>();
			Selectable[] array = components;
			foreach (Selectable val3 in array)
			{
				if ((Object)(object)val3 != (Object)null)
				{
					((Behaviour)val3).enabled = false;
				}
			}
			Button component = ((Component)val5).gameObject.GetComponent<Button>();
			if ((Object)(object)component != (Object)null)
			{
				((Behaviour)component).enabled = false;
			}
		}
		LogInfo("Added headers as non-selectable text");
		if (config.Count > 0)
		{
			PluginInfo capturedPluginForReset = pluginInfo;
			Button val6 = instance.AddButtonMenuItem(menu, "↺ Reset to Defaults", (UnityAction)delegate
			{
				ShowResetConfirmation(capturedPluginForReset);
			}, (string)null, (object[])null);
			if ((Object)(object)val6 != (Object)null)
			{
				GameObject val7 = new GameObject("Spacer");
				RectTransform val8 = val7.AddComponent<RectTransform>();
				((Transform)val8).SetParent(((Component)menu).transform);
				int siblingIndex = ((Component)val6).transform.GetSiblingIndex();
				((Transform)val8).SetSiblingIndex(siblingIndex + 1);
				LayoutElement val9 = val7.AddComponent<LayoutElement>();
				val9.minHeight = 30f;
				val9.preferredHeight = 30f;
				LogInfo("Added spacer after Reset button");
			}
		}
		LogInfo("Config has " + config.Count + " entries");
		if (config.Count == 0)
		{
			Text val10 = instance.AddTextMenuItem(menu, "This mod is loaded, but has no configuration options.", false);
			if ((Object)(object)val10 != (Object)null)
			{
				((Graphic)val10).color = Color.gray;
				val10.fontStyle = (FontStyle)2;
			}
		}
		else
		{
			foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in config)
			{
				ConfigDefinition definition = item.Key;
				ConfigEntryBase configEntry = item.Value;
				if (definition == (ConfigDefinition)null || configEntry == null)
				{
					LogError("Null config entry or definition found!");
					continue;
				}
				LogInfo("  Adding: " + definition.Key + " (Type: " + configEntry.SettingType.Name + ")");
				if ((object)configEntry.SettingType == typeof(bool))
				{
					bool flag = (bool)configEntry.BoxedValue;
					instance.AddToggleMenuItem(menu, definition.Key, flag, (UnityAction<bool>)delegate(bool val)
					{
						configEntry.BoxedValue = val;
						LogInfo("Toggle " + definition.Key + " changed to: " + val);
					});
				}
				else if ((object)configEntry.SettingType == typeof(float))
				{
					float num = (float)configEntry.BoxedValue;
					float min2 = 0f;
					float max2 = 100f;
					if (configEntry.Description.AcceptableValues != null && configEntry.Description.AcceptableValues is AcceptableValueRange<float> val11)
					{
						min2 = val11.MinValue;
						max2 = val11.MaxValue;
					}
					num = Mathf.Clamp(num, min2, max2);
					instance.AddSliderMenuItem(menu, definition.Key + ": " + num.ToString("0.##"), min2, max2, num, (UnityAction<float>)delegate(float val)
					{
						val = Mathf.Clamp(val, min2, max2);
						configEntry.BoxedValue = val;
						LogInfo("Slider " + definition.Key + " changed to: " + val);
						UpdateSliderValueText(menu, definition.Key, val);
					});
				}
				else if ((object)configEntry.SettingType == typeof(int))
				{
					int num2 = (int)configEntry.BoxedValue;
					float min = 0f;
					float max = 100f;
					if (configEntry.Description.AcceptableValues != null && configEntry.Description.AcceptableValues is AcceptableValueRange<int> val12)
					{
						min = val12.MinValue;
						max = val12.MaxValue;
					}
					num2 = Mathf.Clamp(num2, (int)min, (int)max);
					instance.AddSliderMenuItem(menu, definition.Key + ": " + num2, min, max, (float)num2, (UnityAction<float>)delegate(float val)
					{
						int num3 = Mathf.Clamp((int)val, (int)min, (int)max);
						configEntry.BoxedValue = num3;
						LogInfo("Slider " + definition.Key + " changed to: " + num3);
						UpdateSliderValueTextInt(menu, definition.Key, num3);
					});
				}
				else if ((object)configEntry.SettingType == typeof(KeyCode))
				{
					KeyCode key = (KeyCode)configEntry.BoxedValue;
					ConfigEntryBase capturedEntry2 = configEntry;
					PluginInfo capturedPlugin2 = pluginInfo;
					instance.AddButtonMenuItem(menu, definition.Key + ": " + GetFriendlyKeyName(key), (UnityAction)delegate
					{
						ShowKeyRebindModal(capturedEntry2, definition.Key, capturedPlugin2);
					}, (string)null, (object[])null);
				}
				else if (configEntry.SettingType.IsEnum)
				{
					Array enumValues = Enum.GetValues(configEntry.SettingType);
					if (enumValues == null || enumValues.Length == 0)
					{
						LogError("Enum type has no values: " + configEntry.SettingType.Name);
						continue;
					}
					string text = configEntry.BoxedValue.ToString();
					ConfigEntryBase capturedEntry = configEntry;
					PluginInfo capturedPlugin = pluginInfo;
					instance.AddButtonMenuItem(menu, definition.Key + ": " + text, (UnityAction)delegate
					{
						CycleEnumValue(capturedEntry, enumValues, menu, capturedPlugin);
					}, (string)null, (object[])null);
				}
				else if ((object)configEntry.SettingType == typeof(string))
				{
					if (showUnsupportedTypes.Value)
					{
						string text2 = (string)configEntry.BoxedValue;
						if (string.IsNullOrEmpty(text2))
						{
							text2 = "(empty)";
						}
						Text val13 = instance.AddTextMenuItem(menu, definition.Key + ": " + text2, false);
						if ((Object)(object)val13 != (Object)null)
						{
							((Graphic)val13).color = Color.gray;
						}
					}
				}
				else if (showUnsupportedTypes.Value)
				{
					string name = configEntry.SettingType.Name;
					Text val14 = instance.AddTextMenuItem(menu, definition.Key + ": (unsupported - " + name + ")", false);
					if ((Object)(object)val14 != (Object)null)
					{
						((Graphic)val14).color = Color.gray;
					}
				}
			}
		}
		if ((Object)(object)Instance != (Object)null)
		{
			((MonoBehaviour)Instance).StartCoroutine(SetupNavigationDelayed(menu));
		}
	}

	private static IEnumerator SetupNavigationDelayed(MenuContainer menu)
	{
		yield return null;
		yield return null;
		SetupLoopableNavigation(menu);
	}

	private static void SetupLoopableNavigation(MenuContainer menu)
	{
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: Expected O, but got Unknown
		//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e1: 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)
		if ((Object)(object)menu == (Object)null)
		{
			LogError("SetupLoopableNavigation: menu is null");
			return;
		}
		List<Selectable> list = new List<Selectable>();
		foreach (Transform item in ((Component)menu).transform)
		{
			Transform val = item;
			if (!(((Object)val).name == "Spacer"))
			{
				Button component = ((Component)val).GetComponent<Button>();
				Toggle component2 = ((Component)val).GetComponent<Toggle>();
				Slider component3 = ((Component)val).GetComponent<Slider>();
				Selectable val2 = null;
				if ((Object)(object)component != (Object)null && ((Behaviour)component).enabled && ((Selectable)component).interactable)
				{
					val2 = (Selectable)(object)component;
				}
				else if ((Object)(object)component2 != (Object)null && ((Behaviour)component2).enabled && ((Selectable)component2).interactable)
				{
					val2 = (Selectable)(object)component2;
				}
				else if ((Object)(object)component3 != (Object)null && ((Behaviour)component3).enabled && ((Selectable)component3).interactable)
				{
					val2 = (Selectable)(object)component3;
				}
				if ((Object)(object)val2 != (Object)null)
				{
					list.Add(val2);
					LogInfo("Added to navigation: " + ((Object)val).name + " (Type: " + ((object)val2).GetType().Name + ")");
				}
			}
		}
		if (list.Count < 2)
		{
			LogInfo("Not enough buttons for loop navigation: " + list.Count);
			return;
		}
		for (int i = 0; i < list.Count; i++)
		{
			Navigation navigation = list[i].navigation;
			((Navigation)(ref navigation)).mode = (Mode)4;
			((Navigation)(ref navigation)).selectOnUp = ((i == 0) ? list[list.Count - 1] : list[i - 1]);
			((Navigation)(ref navigation)).selectOnDown = ((i == list.Count - 1) ? list[0] : list[i + 1]);
			list[i].navigation = navigation;
		}
		LogInfo("Setup loopable navigation for " + list.Count + " buttons in menu: " + ((Object)menu).name);
	}

	private static void UpdateSliderValueText(MenuContainer menu, string sliderName, float value)
	{
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Expected O, but got Unknown
		if ((Object)(object)menu == (Object)null || string.IsNullOrEmpty(sliderName))
		{
			return;
		}
		foreach (Transform item in ((Component)menu).transform)
		{
			Transform val = item;
			Text componentInChildren = ((Component)val).GetComponentInChildren<Text>();
			if ((Object)(object)componentInChildren != (Object)null && componentInChildren.text.StartsWith(sliderName))
			{
				componentInChildren.text = sliderName + ": " + value.ToString("0.##");
				break;
			}
		}
	}

	private static void UpdateSliderValueTextInt(MenuContainer menu, string sliderName, int value)
	{
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Expected O, but got Unknown
		if ((Object)(object)menu == (Object)null || string.IsNullOrEmpty(sliderName))
		{
			return;
		}
		foreach (Transform item in ((Component)menu).transform)
		{
			Transform val = item;
			Text componentInChildren = ((Component)val).GetComponentInChildren<Text>();
			if ((Object)(object)componentInChildren != (Object)null && componentInChildren.text.StartsWith(sliderName))
			{
				componentInChildren.text = sliderName + ": " + value;
				break;
			}
		}
	}

	private static Button FindButtonByKeyName(MenuContainer menu, string keyName)
	{
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Expected O, but got Unknown
		if ((Object)(object)menu == (Object)null || string.IsNullOrEmpty(keyName))
		{
			return null;
		}
		foreach (Transform item in ((Component)menu).transform)
		{
			Transform val = item;
			Button component = ((Component)val).GetComponent<Button>();
			if ((Object)(object)component != (Object)null)
			{
				Text componentInChildren = ((Component)component).GetComponentInChildren<Text>();
				if ((Object)(object)componentInChildren != (Object)null && componentInChildren.text.Contains(keyName + ":"))
				{
					return component;
				}
			}
		}
		return null;
	}

	private static void CopyRectTransformProperties(RectTransform source, RectTransform target)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: 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_0047: 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_0061: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)source == (Object)null) && !((Object)(object)target == (Object)null))
		{
			target.anchoredPosition = source.anchoredPosition;
			target.sizeDelta = source.sizeDelta;
			target.anchorMin = source.anchorMin;
			target.anchorMax = source.anchorMax;
			target.pivot = source.pivot;
			((Transform)target).localScale = ((Transform)source).localScale;
		}
	}

	public static void LogInfo(string message)
	{
		if (enableLogging != null && enableLogging.Value && Log != null)
		{
			Log.LogInfo((object)("[LOGGING] " + message));
		}
	}

	public static void LogError(string message)
	{
		if (Log != null)
		{
			Log.LogError((object)message);
		}
	}
}
[HarmonyPatch(typeof(Menu_MainMenu), "UpdateInput")]
internal class Patch_Menu_MainMenu_UpdateInput
{
	private static bool Prefix()
	{
		try
		{
			EventSystem current = EventSystem.current;
			if ((Object)(object)current == (Object)null || !((Behaviour)current).enabled)
			{
				return false;
			}
			return true;
		}
		catch (Exception ex)
		{
			if (Plugin.Log != null)
			{
				Plugin.Log.LogError((object)("[ModConfigMenu] Error in Patch_Menu_MainMenu_UpdateInput: " + ex.Message));
			}
			return true;
		}
	}
}
[HarmonyPatch(typeof(EventSystemListener), "Update")]
internal class Patch_EventSystemListener_Update
{
	private static bool Prefix()
	{
		try
		{
			EventSystem current = EventSystem.current;
			if ((Object)(object)current == (Object)null || !((Behaviour)current).enabled)
			{
				return false;
			}
			return true;
		}
		catch (Exception ex)
		{
			if (Plugin.Log != null)
			{
				Plugin.Log.LogError((object)("[ModConfigMenu] Error in Patch_EventSystemListener_Update: " + ex.Message));
			}
			return true;
		}
	}
}
[HarmonyPatch(typeof(CharacterSelectorCamera), "UpdateMainMenu")]
internal class Patch_CharacterSelector_MenuStack
{
	private static bool Prefix()
	{
		try
		{
			if ((Object)(object)Menu_MainMenu.Instance != (Object)null && ((AnimatedScreenController)Menu_MainMenu.Instance).HasActiveStack)
			{
				return false;
			}
			return true;
		}
		catch (Exception ex)
		{
			if (Plugin.Log != null && Plugin.enableLogging != null && Plugin.enableLogging.Value)
			{
				Plugin.Log.LogError((object)("[ModConfigMenu] Error in Patch_CharacterSelector_MenuStack: " + ex.Message));
			}
			return true;
		}
	}
}
[HarmonyPatch(typeof(FriendsMenuData), "ShowFriendsMenu")]
internal class Patch_FriendsMenuData_ShowFriendsMenu
{
	private static void Prefix()
	{
		try
		{
			Plugin.CloseAllModMenus();
		}
		catch (Exception ex)
		{
			if (Plugin.Log != null)
			{
				Plugin.Log.LogError((object)("[ModConfigMenu] Error in Patch_FriendsMenuData_ShowFriendsMenu: " + ex.Message));
			}
		}
	}
}
[HarmonyPatch(typeof(FriendsMenuData), "OnInvited")]
internal class Patch_FriendsMenuData_OnInvited
{
	private static void Prefix()
	{
		try
		{
			Plugin.CloseAllModMenus();
		}
		catch (Exception ex)
		{
			if (Plugin.Log != null)
			{
				Plugin.Log.LogError((object)("[ModConfigMenu] Error in Patch_FriendsMenuData_OnInvited: " + ex.Message));
			}
		}
	}
}
[HarmonyPatch(typeof(Menu_MainMenu), "PopulateInGameMenu")]
internal class Patch_PopulateInGameMenu
{
	private static void Postfix(Menu_MainMenu __instance, MenuContainer m)
	{
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Expected O, but got Unknown
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Expected O, but got Unknown
		try
		{
			if ((Object)(object)__instance == (Object)null || (Object)(object)m == (Object)null)
			{
				return;
			}
			Button val = __instance.AddButtonMenuItem(m, "Mods", new UnityAction(Plugin.ShowModList), (string)null, (object[])null);
			if (!((Object)(object)val != (Object)null))
			{
				return;
			}
			((Object)val).name = "ModManager";
			Transform val2 = null;
			foreach (Transform item in ((Component)m).transform)
			{
				Transform val3 = item;
				Text componentInChildren = ((Component)val3).GetComponentInChildren<Text>();
				if ((Object)(object)componentInChildren != (Object)null && componentInChildren.text.Contains("OPTIONS"))
				{
					val2 = val3;
					break;
				}
			}
			if ((Object)(object)val2 != (Object)null)
			{
				int siblingIndex = val2.GetSiblingIndex();
				((Component)val).transform.SetSiblingIndex(siblingIndex);
			}
			else
			{
				((Component)val).transform.SetSiblingIndex(1);
			}
			if (Plugin.enableLogging != null && Plugin.enableLogging.Value && Plugin.Log != null)
			{
				Plugin.Log.LogInfo((object)"[ModConfigMenu] In-game Mod Config Menu button added");
			}
		}
		catch (Exception ex)
		{
			if (Plugin.Log != null && Plugin.enableLogging != null && Plugin.enableLogging.Value)
			{
				Plugin.Log.LogError((object)("[ModConfigMenu] Error in Patch_PopulateInGameMenu: " + ex.Message));
			}
		}
	}
}
[HarmonyPatch(typeof(AnimatedScreenController), "CloseCurrent")]
internal class Patch_AnimatedScreenController_CloseCurrent
{
	private static void Prefix(AnimatedScreenController __instance)
	{
		try
		{
			if (!((Object)(object)__instance != (Object)null) || __instance.Peek() == null)
			{
				return;
			}
			ScreenRecord val = __instance.Peek();
			if (val == null || !((Object)(object)val.animator != (Object)null))
			{
				return;
			}
			string name = ((Object)val.animator).name;
			if (name != null && name.Contains("MOD_"))
			{
				GameObject val2 = GameObject.Find("Bootstrapper/Main Canvas/Modal Dialog Controller");
				if ((Object)(object)val2 != (Object)null && val2.activeInHierarchy)
				{
					val2.SetActive(false);
					Plugin.LogInfo("Closed modal because mod menu is closing");
				}
			}
		}
		catch (Exception ex)
		{
			if (Plugin.Log != null)
			{
				Plugin.Log.LogError((object)("[ModConfigMenu] Error in Patch_AnimatedScreenController_CloseCurrent: " + ex.Message));
			}
		}
	}
}