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));
}
}
}
}