Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Controller Support Revamped v1.0.2
BepInEx\plugins\ControllerSupport\ControllerSupport.dll
Decompiled 14 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using TMPro; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.InputSystem.DualShock; using UnityEngine.InputSystem.LowLevel; using UnityEngine.InputSystem.Switch; using UnityEngine.InputSystem.Utilities; using UnityEngine.InputSystem.XInput; using UnityEngine.TextCore; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("ControllerSupport")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.2.0")] [assembly: AssemblyInformationalVersion("1.0.2+6bd8635c21563e73b67211474a60513b7751f487")] [assembly: AssemblyProduct("Controller Support")] [assembly: AssemblyTitle("ControllerSupport")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.2.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ControllerSupport { internal static class ColorLedPatches { internal static ControllerLedManager Led; internal static ConfigManager Config; internal static ManualLogSource Logger; internal static void Initialize(ControllerLedManager led, ConfigManager config, ManualLogSource logger) { Led = led; Config = config; Logger = logger; } internal static bool ShouldSyncLed() { if (Config != null && Led != null) { return Config.EnableLedSync; } return false; } } [HarmonyPatch(typeof(PlayerCosmetics), "SetupColorsLogic")] internal static class PlayerCosmeticsSetupColorsLogicLedPatch { [HarmonyPostfix] private static void Postfix(PlayerCosmetics __instance) { if (ColorLedPatches.ShouldSyncLed() && ControllerLedManager.IsLocalPlayerCosmetics(__instance)) { ColorLedPatches.Led.SyncFromPlayer(); } } } [HarmonyPatch(typeof(PlayerCosmetics), "SetupColors")] internal static class PlayerCosmeticsSetupColorsLedPatch { [HarmonyPostfix] private static void Postfix(PlayerCosmetics __instance) { if (ColorLedPatches.ShouldSyncLed() && ControllerLedManager.IsLocalPlayerCosmetics(__instance)) { ColorLedPatches.Led.SyncFromPlayer(); } } } [HarmonyPatch(typeof(DataDirector), "ColorSetBody")] internal static class DataDirectorColorSetBodyLedPatch { [HarmonyPostfix] private static void Postfix() { if (ColorLedPatches.ShouldSyncLed()) { ColorLedPatches.Led.SyncFromPlayer(); } } } [HarmonyPatch(typeof(MenuPageColor), "ConfirmButton")] internal static class MenuPageColorConfirmLedPatch { [HarmonyPostfix] private static void Postfix() { if (ColorLedPatches.ShouldSyncLed()) { ColorLedPatches.Led.SyncFromPlayer(); } } } [HarmonyPatch(typeof(PlayerAvatar), "Awake")] internal static class PlayerAvatarAwakeLedPatch { [HarmonyPostfix] private static void Postfix(PlayerAvatar __instance) { if (ColorLedPatches.ShouldSyncLed() && ControllerLedManager.IsAvatarMarkedLocal(__instance)) { ColorLedPatches.Led.SyncFromPlayer(); } } } [HarmonyPatch(typeof(PlayerCosmetics), "SetupColorsAllLogic")] internal static class PlayerCosmeticsSetupColorsAllLogicLedPatch { [HarmonyPostfix] private static void Postfix(PlayerCosmetics __instance) { if (ColorLedPatches.ShouldSyncLed() && ControllerLedManager.IsLocalPlayerCosmetics(__instance)) { ColorLedPatches.Led.SyncFromPlayer(); } } } public enum ControllerGlyphStyleOverride { Auto, Xbox, PlayStation, Switch, SteamDeck } public class ConfigManager { private ConfigFile _config; private ConfigEntry<float> _mouseSensitivityConfig; private ConfigEntry<float> _scrollSpeedConfig; private ConfigEntry<float> _deadZoneRadiusConfig; private ConfigEntry<float> _diagonalZoneSizeConfig; private ConfigEntry<bool> _enableTabToggleConfig; private ConfigEntry<bool> _enableCtrlToggleConfig; private ConfigEntry<bool> _enableShiftToggleConfig; private ConfigEntry<bool> _releaseTabOnShiftConfig; private ConfigEntry<bool> _releaseCtrlOnShiftConfig; private ConfigEntry<bool> _releaseCtrlOnAConfig; private ConfigEntry<bool> _autoReleaseShiftAfterWASDConfig; private ConfigEntry<float> _shiftReleaseDelayConfig; private ConfigEntry<bool> _enableLedSyncConfig; private ConfigEntry<bool> _enableVibrationConfig; private ConfigEntry<float> _vibrationIntensityConfig; private ConfigEntry<bool> _enableInputVibrationConfig; private ConfigEntry<bool> _enableDamageVibrationConfig; private ConfigEntry<bool> _enableItemBreakVibrationConfig; private ConfigEntry<bool> _enableHoldVibrationConfig; private ConfigEntry<bool> _enableMenuNavigationConfig; private ConfigEntry<float> _menuScrollSpeedConfig; private ConfigEntry<bool> _enableControllerGlyphsConfig; private ConfigEntry<string> _controllerGlyphStyleConfig; private ConfigEntry<bool> _debugOutputConfig; private ConfigEntry<bool> _devModeConfig; public float MouseSensitivity => _mouseSensitivityConfig.Value; public float ScrollSpeed => _scrollSpeedConfig.Value; public float DeadZoneRadius => _deadZoneRadiusConfig.Value; public float DiagonalZoneSize => _diagonalZoneSizeConfig.Value; public bool EnableTabToggle => _enableTabToggleConfig.Value; public bool EnableCtrlToggle => _enableCtrlToggleConfig.Value; public bool EnableShiftToggle => _enableShiftToggleConfig.Value; public bool ReleaseTabOnShift => _releaseTabOnShiftConfig.Value; public bool ReleaseCtrlOnShift => _releaseCtrlOnShiftConfig.Value; public bool ReleaseCtrlOnA => _releaseCtrlOnAConfig.Value; public bool AutoReleaseShiftAfterWASD => _autoReleaseShiftAfterWASDConfig.Value; public float ShiftReleaseDelay => _shiftReleaseDelayConfig.Value; public bool EnableLedSync => _enableLedSyncConfig.Value; public bool EnableVibration => _enableVibrationConfig.Value; public float VibrationIntensity => _vibrationIntensityConfig.Value; public bool EnableInputVibration => _enableInputVibrationConfig.Value; public bool EnableDamageVibration => _enableDamageVibrationConfig.Value; public bool EnableItemBreakVibration => _enableItemBreakVibrationConfig.Value; public bool EnableHoldVibration => _enableHoldVibrationConfig.Value; public bool EnableMenuNavigation => _enableMenuNavigationConfig.Value; public float MenuScrollSpeed => _menuScrollSpeedConfig.Value; public bool EnableControllerGlyphs => _enableControllerGlyphsConfig.Value; public ControllerGlyphStyleOverride ControllerGlyphStyle => ParseGlyphStyle(_controllerGlyphStyleConfig.Value); public bool DebugOutput => _debugOutputConfig.Value; public bool DevMode => _devModeConfig.Value; public float CurrentJoystickX { get; set; } public float CurrentJoystickY { get; set; } public float CurrentJoystickAngle { get; set; } public ConfigManager(ConfigFile config) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Expected O, but got Unknown //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Expected O, but got Unknown //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_0261: Expected O, but got Unknown //IL_031c: Unknown result type (might be due to invalid IL or missing references) //IL_0326: Expected O, but got Unknown //IL_0395: Unknown result type (might be due to invalid IL or missing references) //IL_039f: Expected O, but got Unknown _config = config; string configFilePath = config.ConfigFilePath; _mouseSensitivityConfig = config.Bind<float>("Mouse Controls", "MouseSensitivity", 10f, new ConfigDescription("Sensitivity of the right stick for mouse movement. Higher values make the mouse move faster.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 1000f), Array.Empty<object>())); _scrollSpeedConfig = config.Bind<float>("Mouse Controls", "ScrollSpeed", 0.0021f, new ConfigDescription("Adjust the scroll speed for bumper buttons (RB/LB). Lower values result in slower scrolling, higher values in faster scrolling.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.0001f, 0.01f), Array.Empty<object>())); _deadZoneRadiusConfig = config.Bind<float>("Movement Controls", "DeadZoneRadius", 0.25f, new ConfigDescription("Radius of the center dead zone for the left joystick (0.0 to 1.0). Higher values require more joystick movement before keys are pressed.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); _diagonalZoneSizeConfig = config.Bind<float>("Movement Controls", "DiagonalZoneSize", 0.7071f, new ConfigDescription("Size of the diagonal zones for the left joystick (0.5 to 1.0). Higher values make diagonal movement more likely.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 1f), Array.Empty<object>())); _enableTabToggleConfig = config.Bind<bool>("Toggle Controls", "EnableMapToggle", true, "Enable toggle functionality for the Map key (Back button)."); _enableCtrlToggleConfig = config.Bind<bool>("Toggle Controls", "EnableCrouchToggle", true, "Enable toggle functionality for the Crouch key (B button)."); _enableShiftToggleConfig = config.Bind<bool>("Toggle Controls", "EnableRunToggle", false, "Enable toggle functionality for the Run key (L3 button)."); _releaseTabOnShiftConfig = config.Bind<bool>("Key Interactions", "ReleaseMapOnRun", true, "When enabled, pressing Run will automatically release Map if active."); _releaseCtrlOnShiftConfig = config.Bind<bool>("Key Interactions", "ReleaseCrouchOnRun", true, "When enabled, activating Run will automatically release Crouch."); _releaseCtrlOnAConfig = config.Bind<bool>("Key Interactions", "ReleaseCrouchOnJump", true, "When enabled, pressing Jump will automatically release Crouch."); _autoReleaseShiftAfterWASDConfig = config.Bind<bool>("Key Interactions", "AutoReleaseRunAfterWASD", true, "Automatically release Run after WASD inactivity."); _shiftReleaseDelayConfig = config.Bind<float>("Key Interactions", "RunReleaseDelay", 0.5f, new ConfigDescription("Delay before auto-releasing Run (seconds).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>())); _enableLedSyncConfig = config.Bind<bool>("Controller LED", "EnableLedSync", true, "Sync the controller LED/light bar to your player head color when Unity exposes LED control for the connected device."); _enableVibrationConfig = config.Bind<bool>("Vibration", "EnableVibration", true, "Enable controller vibration/rumble."); _vibrationIntensityConfig = config.Bind<float>("Vibration", "VibrationIntensity", 1f, new ConfigDescription("Overall vibration strength (0.0 to 1.0).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); _enableInputVibrationConfig = config.Bind<bool>("Vibration", "EnableInputVibration", true, "Rumble on controller actions such as shooting, jumping, and interacting."); _enableDamageVibrationConfig = config.Bind<bool>("Vibration", "EnableDamageVibration", true, "Rumble when your player takes damage."); _enableItemBreakVibrationConfig = config.Bind<bool>("Vibration", "EnableItemBreakVibration", true, "Rumble when an item you are holding breaks or takes impact damage."); _enableHoldVibrationConfig = config.Bind<bool>("Vibration", "EnableHoldVibration", true, "Subtle continuous rumble while holding an item with the grab beam."); _enableMenuNavigationConfig = config.Bind<bool>("Menu Navigation", "EnableMenuNavigation", true, "Navigate menus with the controller using focus-based selection (left stick/D-pad to move, A to confirm, B to go back)."); _menuScrollSpeedConfig = config.Bind<float>("Menu Navigation", "MenuScrollSpeed", 0.0021f, new ConfigDescription("Scroll speed for LB/RB when a scrollable menu list is focused.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.0001f, 0.01f), Array.Empty<object>())); _enableControllerGlyphsConfig = config.Bind<bool>("Controller Glyphs", "EnableControllerGlyphs", true, "Replace keyboard/mouse prompt text with controller button glyphs when a gamepad is connected."); _controllerGlyphStyleConfig = config.Bind<string>("Controller Glyphs", "GlyphStyle", "Auto", new ConfigDescription("Which glyph set to use. Auto picks Xbox, PlayStation, Switch, or Steam Deck based on the connected controller.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[5] { "Auto", "Xbox", "PlayStation", "Switch", "SteamDeck" }), Array.Empty<object>())); _debugOutputConfig = config.Bind<bool>("Debug", "EnableDebugOutput", false, "Enable detailed debug logging."); _devModeConfig = config.Bind<bool>("Debug", "DevMode", false, "Enable developer tools with numpad controls."); InjectAboutSection(configFilePath); } private void InjectAboutSection(string configPath) { string[] collection = new string[11] { "[About]", "## Thunderstore Link.", "# Setting type: String", "# Default value: https://thunderstore.io/c/repo/p/AKASGaming/Controller_Support_Revamped/", "Thunderstore = https://thunderstore.io/c/repo/p/AKASGaming/Controller_Support_Revamped/", "", "## Github Link.", "# Setting type: String", "# Default value: https://github.com/AKASGaming/R.E.P.O.ControllerSupport", "Github = https://github.com/AKASGaming/R.E.P.O.ControllerSupport", "" }; try { if (!File.Exists(configPath)) { return; } List<string> list = File.ReadAllLines(configPath).ToList(); if (!list.Any((string l) => l.Trim().Equals("[About]", StringComparison.OrdinalIgnoreCase))) { int i; for (i = 0; i < list.Count && (list[i].StartsWith("##") || string.IsNullOrWhiteSpace(list[i])); i++) { } list.InsertRange(i, collection); File.WriteAllLines(configPath, list); } } catch (Exception) { _ = Debugger.IsAttached; } } public float IncreaseScrollSpeed() { float num = ScrollSpeed + 0.0001f; _scrollSpeedConfig.Value = num; return num; } public float DecreaseScrollSpeed() { float num = Math.Max(0.0001f, ScrollSpeed - 0.0001f); _scrollSpeedConfig.Value = num; return num; } public float UpdateDeadZoneRadius(float magnitude) { _deadZoneRadiusConfig.Value = magnitude; return magnitude; } public float UpdateDiagonalZoneSize(float angle) { _diagonalZoneSizeConfig.Value = angle; return angle; } private static ControllerGlyphStyleOverride ParseGlyphStyle(string value) { return value?.Trim() switch { "Xbox" => ControllerGlyphStyleOverride.Xbox, "PlayStation" => ControllerGlyphStyleOverride.PlayStation, "Switch" => ControllerGlyphStyleOverride.Switch, "SteamDeck" => ControllerGlyphStyleOverride.SteamDeck, _ => ControllerGlyphStyleOverride.Auto, }; } } internal enum ControllerGlyphStyle { Xbox, PlayStation, Switch, SteamDeck } internal enum ControllerGlyphButton { South, West, East, North, LeftShoulder, RightShoulder, LeftTrigger, RightTrigger, LeftStick, RightStick, LeftStickClick, RightStickClick, DpadUp, DpadDown, DpadLeft, DpadRight, Select, Start } internal class ControllerGlyphManager { private readonly struct LoadedGlyph { internal string SpriteName { get; } internal Texture2D Texture { get; } internal LoadedGlyph(string spriteName, Texture2D texture) { SpriteName = spriteName; Texture = texture; } } internal const string SpriteAssetName = "ControllerSupportGlyphs"; private const string SpriteTagFormat = "<size=120%><voffset=0.2em><sprite=\"{0}\" name=\"{1}\"></size>"; private static readonly Dictionary<ControllerGlyphButton, string> SpriteNames = new Dictionary<ControllerGlyphButton, string> { { ControllerGlyphButton.South, "btn_south" }, { ControllerGlyphButton.West, "btn_west" }, { ControllerGlyphButton.East, "btn_east" }, { ControllerGlyphButton.North, "btn_north" }, { ControllerGlyphButton.LeftShoulder, "btn_lb" }, { ControllerGlyphButton.RightShoulder, "btn_rb" }, { ControllerGlyphButton.LeftTrigger, "btn_lt" }, { ControllerGlyphButton.RightTrigger, "btn_rt" }, { ControllerGlyphButton.LeftStick, "btn_left_stick" }, { ControllerGlyphButton.RightStick, "btn_right_stick" }, { ControllerGlyphButton.LeftStickClick, "btn_l3" }, { ControllerGlyphButton.RightStickClick, "btn_r3" }, { ControllerGlyphButton.DpadUp, "btn_dpad_up" }, { ControllerGlyphButton.DpadDown, "btn_dpad_down" }, { ControllerGlyphButton.DpadLeft, "btn_dpad_left" }, { ControllerGlyphButton.DpadRight, "btn_dpad_right" }, { ControllerGlyphButton.Select, "btn_select" }, { ControllerGlyphButton.Start, "btn_start" } }; private readonly ManualLogSource _logger; private readonly ConfigManager _configManager; private readonly string _glyphRoot; private static readonly FieldInfo SpriteGlyphTableField = typeof(TMP_SpriteAsset).GetField("m_SpriteGlyphTable", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo SpriteCharacterTableField = typeof(TMP_SpriteAsset).GetField("m_SpriteCharacterTable", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo SpriteAssetVersionField = typeof(TMP_SpriteAsset).GetField("m_Version", BindingFlags.Instance | BindingFlags.NonPublic); private const string SpriteAssetVersion = "1.1.0"; private static readonly Assembly PluginAssembly = typeof(ControllerGlyphManager).Assembly; private const string EmbeddedResourcePrefix = "ControllerSupport.Glyphs"; private TMP_SpriteAsset _spriteAsset; private ControllerGlyphStyle _activeStyle; private Gamepad _activeGamepad; private bool _initialized; internal static ControllerGlyphManager Instance { get; private set; } internal ControllerGlyphManager(ManualLogSource logger, ConfigManager configManager, string pluginPath) { _logger = logger; _configManager = configManager; _glyphRoot = Path.Combine(Path.GetDirectoryName(pluginPath) ?? string.Empty, "glyphs"); Instance = this; } internal void Initialize() { if (!_initialized) { if (!HasEmbeddedGlyphPack()) { _logger.LogWarning((object)"No embedded controller glyphs found in ControllerSupport.dll. Rebuild the mod or place PNGs in a glyphs folder next to the DLL."); return; } _initialized = true; RefreshActiveGamepad(forceReload: true); } } private static bool HasEmbeddedGlyphPack() { string name = "ControllerSupport.Glyphs.XboxSeries.XboxSeriesX_A.png"; using Stream stream = PluginAssembly.GetManifestResourceStream(name); return stream != null; } internal void Update() { if (_initialized && _configManager.EnableControllerGlyphs) { RefreshActiveGamepad(forceReload: false); } } internal bool ShouldUseGlyphs() { if (_initialized && _configManager.EnableControllerGlyphs && _activeGamepad != null) { return (Object)(object)_spriteAsset != (Object)null; } return false; } internal bool TryGetInputKeyGlyph(InputKey inputKey, KeyType keyType, MovementDirection movementDirection, out string glyphTag) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected I4, but got Unknown glyphTag = null; if (!ShouldUseGlyphs()) { return false; } if ((int)keyType == 1) { if ((int)inputKey != 0) { return false; } switch ((int)movementDirection) { case 0: glyphTag = BuildTag(ControllerGlyphButton.DpadUp); return glyphTag != null; case 1: glyphTag = BuildTag(ControllerGlyphButton.DpadDown); return glyphTag != null; case 2: glyphTag = BuildTag(ControllerGlyphButton.DpadLeft); return glyphTag != null; case 3: glyphTag = BuildTag(ControllerGlyphButton.DpadRight); return glyphTag != null; default: return false; } } ControllerGlyphButton? controllerGlyphButton = MapInputKey(inputKey); if (!controllerGlyphButton.HasValue) { return false; } glyphTag = BuildTag(controllerGlyphButton.Value); return glyphTag != null; } internal bool TryGetMouseGlyph(string originalDisplay, out string glyphTag) { glyphTag = null; if (!ShouldUseGlyphs() || string.IsNullOrEmpty(originalDisplay)) { return false; } string text = originalDisplay.Trim().ToUpperInvariant(); ControllerGlyphButton? controllerGlyphButton = null; if (text.Contains("MOUSE LEFT") || text.Contains("LEFT BUTTON")) { controllerGlyphButton = ControllerGlyphButton.RightTrigger; } else if (text.Contains("MOUSE RIGHT") || text.Contains("RIGHT BUTTON")) { controllerGlyphButton = ControllerGlyphButton.LeftTrigger; } else if (text.Contains("MOUSE SCROLL") || text.Contains("SCROLL")) { controllerGlyphButton = ControllerGlyphButton.RightShoulder; } if (!controllerGlyphButton.HasValue) { return false; } glyphTag = BuildTag(controllerGlyphButton.Value); return glyphTag != null; } private void RefreshActiveGamepad(bool forceReload) { Gamepad val = GamepadHelper.FindActiveGamepad(); if (!forceReload && val == _activeGamepad) { return; } _activeGamepad = val; if (_activeGamepad == null) { _spriteAsset = null; return; } ControllerGlyphStyle controllerGlyphStyle = ResolveStyle(_activeGamepad); if (!forceReload && controllerGlyphStyle == _activeStyle && (Object)(object)_spriteAsset != (Object)null) { return; } if (!TryBuildSpriteAsset(controllerGlyphStyle, out var spriteAsset)) { _spriteAsset = null; return; } if ((Object)(object)_spriteAsset != (Object)null) { Object.Destroy((Object)(object)_spriteAsset); } _activeStyle = controllerGlyphStyle; _spriteAsset = spriteAsset; MaterialReferenceManager.AddSpriteAsset(_spriteAsset); _logger.LogInfo((object)$"Controller glyphs loaded for {_activeStyle} ({((InputControl)_activeGamepad).displayName})."); } private ControllerGlyphStyle ResolveStyle(Gamepad gamepad) { switch (_configManager.ControllerGlyphStyle) { case ControllerGlyphStyleOverride.Xbox: return ControllerGlyphStyle.Xbox; case ControllerGlyphStyleOverride.PlayStation: return ControllerGlyphStyle.PlayStation; case ControllerGlyphStyleOverride.Switch: return ControllerGlyphStyle.Switch; case ControllerGlyphStyleOverride.SteamDeck: return ControllerGlyphStyle.SteamDeck; default: { if (gamepad is DualShockGamepad) { return ControllerGlyphStyle.PlayStation; } if (gamepad is SwitchProControllerHID) { return ControllerGlyphStyle.Switch; } string obj = ((InputControl)gamepad).displayName ?? string.Empty; string text = ((InputControl)gamepad).layout ?? string.Empty; string text2 = (obj + " " + text).ToLowerInvariant(); if (text2.Contains("steam deck") || text2.Contains("steam controller")) { return ControllerGlyphStyle.SteamDeck; } if (text2.Contains("switch") || text2.Contains("nintendo")) { return ControllerGlyphStyle.Switch; } if (text2.Contains("dualsense") || text2.Contains("dualshock") || text2.Contains("playstation") || text2.Contains("wireless controller")) { return ControllerGlyphStyle.PlayStation; } if (!(gamepad is XInputController) && !text2.Contains("xbox")) { text2.Contains("xinput"); } return ControllerGlyphStyle.Xbox; } } } private bool TryBuildSpriteAsset(ControllerGlyphStyle style, out TMP_SpriteAsset spriteAsset) { spriteAsset = null; try { return TryBuildSpriteAssetInternal(style, out spriteAsset); } catch (Exception arg) { if ((Object)(object)spriteAsset != (Object)null) { Object.Destroy((Object)(object)spriteAsset); spriteAsset = null; } _logger.LogError((object)$"Failed to build controller glyph sprite asset for '{style}': {arg}"); return false; } } private bool TryBuildSpriteAssetInternal(ControllerGlyphStyle style, out TMP_SpriteAsset spriteAsset) { spriteAsset = null; List<LoadedGlyph> list = new List<LoadedGlyph>(); foreach (KeyValuePair<ControllerGlyphButton, string> spriteName in SpriteNames) { string glyphFileName = GetGlyphFileName(style, spriteName.Key); if (string.IsNullOrEmpty(glyphFileName)) { continue; } Texture2D texture; if (!TryReadGlyphBytes(style, glyphFileName, out var bytes)) { if (_configManager.DebugOutput) { _logger.LogWarning((object)("Missing controller glyph: " + GetStyleResourceFolder(style) + "/" + glyphFileName)); } } else if (TryLoadGlyphTexture(bytes, out texture)) { list.Add(new LoadedGlyph(spriteName.Value, texture)); } } if (list.Count == 0) { _logger.LogWarning((object)$"No controller glyphs loaded for style '{style}'."); return false; } if (!TryCreateAtlasSpriteAsset(list, out spriteAsset)) { DestroyLoadedGlyphs(list); return false; } DestroyLoadedGlyphs(list); return true; } private bool TryCreateAtlasSpriteAsset(List<LoadedGlyph> loadedGlyphs, out TMP_SpriteAsset spriteAsset) { //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Expected O, but got Unknown //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Expected O, but got Unknown //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Expected O, but got Unknown //IL_02cb: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Expected O, but got Unknown //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Expected O, but got Unknown spriteAsset = ScriptableObject.CreateInstance<TMP_SpriteAsset>(); ((Object)spriteAsset).name = "ControllerSupportGlyphs"; ((TMP_Asset)spriteAsset).hashCode = TMP_TextUtilities.GetSimpleHashCode(((Object)spriteAsset).name); SpriteAssetVersionField?.SetValue(spriteAsset, "1.1.0"); int num = 0; int num2 = 0; foreach (LoadedGlyph loadedGlyph2 in loadedGlyphs) { num = Math.Max(num, ((Texture)loadedGlyph2.Texture).width); num2 = Math.Max(num2, ((Texture)loadedGlyph2.Texture).height); } int num3 = num + 4; int num4 = num2 + 4; int count = loadedGlyphs.Count; int num5 = Mathf.CeilToInt(Mathf.Sqrt((float)count)); int num6 = Mathf.CeilToInt((float)count / (float)num5); int num7 = Math.Max(64, num5 * num3); int num8 = Math.Max(64, num6 * num4); Texture2D val = new Texture2D(num7, num8, (TextureFormat)4, false) { filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1 }; Color32[] array = (Color32[])(object)new Color32[num7 * num8]; for (int i = 0; i < array.Length; i++) { array[i] = new Color32((byte)0, (byte)0, (byte)0, (byte)0); } val.SetPixels32(array); List<TMP_SpriteGlyph> orCreateGlyphTable = GetOrCreateGlyphTable(spriteAsset, clearExisting: true); List<TMP_SpriteCharacter> orCreateCharacterTable = GetOrCreateCharacterTable(spriteAsset, clearExisting: true); uint num9 = 0u; GlyphRect val2 = default(GlyphRect); GlyphMetrics val3 = default(GlyphMetrics); for (int j = 0; j < loadedGlyphs.Count; j++) { LoadedGlyph loadedGlyph = loadedGlyphs[j]; int num10 = j % num5; int num11 = j / num5; int num12 = num10 * num3 + 2; int num13 = num11 * num4 + 2; int width = ((Texture)loadedGlyph.Texture).width; int height = ((Texture)loadedGlyph.Texture).height; val.SetPixels(num12, num13, width, height, loadedGlyph.Texture.GetPixels()); ((GlyphRect)(ref val2))..ctor(num12, num13, width, height); ((GlyphMetrics)(ref val3))..ctor((float)width, (float)height, 0f, (float)height * 0.85f, (float)width + 2f); TMP_SpriteGlyph val4 = new TMP_SpriteGlyph(num9, val3, val2, 1f, 0); TMP_SpriteCharacter item = new TMP_SpriteCharacter(65534 + num9, val4) { name = loadedGlyph.SpriteName, scale = 1f }; orCreateGlyphTable.Add(val4); orCreateCharacterTable.Add(item); num9++; } val.Apply(false, false); spriteAsset.spriteSheet = (Texture)(object)val; TMP_SpriteAsset defaultSpriteAsset = TMP_Settings.defaultSpriteAsset; if ((Object)(object)defaultSpriteAsset != (Object)null && (Object)(object)((TMP_Asset)defaultSpriteAsset).material != (Object)null) { ((TMP_Asset)spriteAsset).material = new Material(((TMP_Asset)defaultSpriteAsset).material); ((TMP_Asset)spriteAsset).material.mainTexture = (Texture)(object)val; } else { Shader val5 = Shader.Find("TextMeshPro/Sprite"); if ((Object)(object)val5 == (Object)null) { Object.Destroy((Object)(object)val); Object.Destroy((Object)(object)spriteAsset); spriteAsset = null; _logger.LogError((object)"TextMeshPro/Sprite shader not found; controller glyphs cannot render."); return false; } ((TMP_Asset)spriteAsset).material = new Material(val5) { mainTexture = (Texture)(object)val }; } spriteAsset.UpdateLookupTables(); return true; } private static bool TryLoadGlyphTexture(byte[] bytes, out Texture2D texture) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown texture = new Texture2D(2, 2, (TextureFormat)4, false); if (!ImageConversion.LoadImage(texture, bytes)) { Object.Destroy((Object)(object)texture); texture = null; return false; } ((Texture)texture).filterMode = (FilterMode)1; ((Texture)texture).wrapMode = (TextureWrapMode)1; return true; } private static void DestroyLoadedGlyphs(List<LoadedGlyph> loadedGlyphs) { foreach (LoadedGlyph loadedGlyph in loadedGlyphs) { if ((Object)(object)loadedGlyph.Texture != (Object)null) { Object.Destroy((Object)(object)loadedGlyph.Texture); } } } private static List<TMP_SpriteGlyph> GetOrCreateGlyphTable(TMP_SpriteAsset spriteAsset, bool clearExisting) { List<TMP_SpriteGlyph> list = SpriteGlyphTableField?.GetValue(spriteAsset) as List<TMP_SpriteGlyph>; if (list == null) { list = new List<TMP_SpriteGlyph>(); SpriteGlyphTableField?.SetValue(spriteAsset, list); } else if (clearExisting) { list.Clear(); } return list; } private static List<TMP_SpriteCharacter> GetOrCreateCharacterTable(TMP_SpriteAsset spriteAsset, bool clearExisting) { List<TMP_SpriteCharacter> list = SpriteCharacterTableField?.GetValue(spriteAsset) as List<TMP_SpriteCharacter>; if (list == null) { list = new List<TMP_SpriteCharacter>(); SpriteCharacterTableField?.SetValue(spriteAsset, list); } else if (clearExisting) { list.Clear(); } return list; } private bool TryReadGlyphBytes(ControllerGlyphStyle style, string fileName, out byte[] bytes) { string name = "ControllerSupport.Glyphs." + GetStyleResourceFolder(style) + "." + fileName; using (Stream stream = PluginAssembly.GetManifestResourceStream(name)) { if (stream != null) { bytes = ReadAllBytes(stream); return bytes.Length != 0; } } if (!string.IsNullOrEmpty(_glyphRoot)) { string path = Path.Combine(_glyphRoot, GetStyleFolder(style), fileName); if (File.Exists(path)) { bytes = File.ReadAllBytes(path); return bytes.Length != 0; } } bytes = null; return false; } private static byte[] ReadAllBytes(Stream stream) { using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); return memoryStream.ToArray(); } private string BuildTag(ControllerGlyphButton button) { if ((Object)(object)_spriteAsset == (Object)null || !SpriteNames.TryGetValue(button, out var value)) { return null; } if (_spriteAsset.GetSpriteIndexFromName(value) < 0) { return null; } return string.Format("<size=120%><voffset=0.2em><sprite=\"{0}\" name=\"{1}\"></size>", "ControllerSupportGlyphs", value); } private static ControllerGlyphButton? MapInputKey(InputKey inputKey) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected I4, but got Unknown switch (inputKey - 1) { case 0: case 8: return ControllerGlyphButton.South; case 1: return ControllerGlyphButton.West; case 11: return ControllerGlyphButton.East; case 13: return ControllerGlyphButton.North; case 14: return ControllerGlyphButton.LeftStickClick; case 7: return ControllerGlyphButton.Select; case 5: case 17: case 21: return ControllerGlyphButton.Start; case 9: case 23: return ControllerGlyphButton.RightTrigger; case 10: case 22: return ControllerGlyphButton.LeftTrigger; case 3: case 4: case 16: return ControllerGlyphButton.RightShoulder; case 18: return ControllerGlyphButton.DpadLeft; case 19: return ControllerGlyphButton.DpadUp; case 20: return ControllerGlyphButton.DpadRight; default: return null; } } private static string GetStyleFolder(ControllerGlyphStyle style) { return style switch { ControllerGlyphStyle.PlayStation => "PS5", ControllerGlyphStyle.Switch => "Switch", ControllerGlyphStyle.SteamDeck => "Steam Deck", _ => "Xbox Series", }; } private static string GetStyleResourceFolder(ControllerGlyphStyle style) { return style switch { ControllerGlyphStyle.PlayStation => "PS5", ControllerGlyphStyle.Switch => "Switch", ControllerGlyphStyle.SteamDeck => "SteamDeck", _ => "XboxSeries", }; } private static string GetGlyphFileName(ControllerGlyphStyle style, ControllerGlyphButton button) { return style switch { ControllerGlyphStyle.PlayStation => GetPlayStationFileName(button), ControllerGlyphStyle.Switch => GetSwitchFileName(button), ControllerGlyphStyle.SteamDeck => GetSteamDeckFileName(button), _ => GetXboxFileName(button), }; } private static string GetXboxFileName(ControllerGlyphButton button) { return button switch { ControllerGlyphButton.South => "XboxSeriesX_A.png", ControllerGlyphButton.West => "XboxSeriesX_X.png", ControllerGlyphButton.East => "XboxSeriesX_B.png", ControllerGlyphButton.North => "XboxSeriesX_Y.png", ControllerGlyphButton.LeftShoulder => "XboxSeriesX_LB.png", ControllerGlyphButton.RightShoulder => "XboxSeriesX_RB.png", ControllerGlyphButton.LeftTrigger => "XboxSeriesX_LT.png", ControllerGlyphButton.RightTrigger => "XboxSeriesX_RT.png", ControllerGlyphButton.LeftStick => "XboxSeriesX_Left_Stick.png", ControllerGlyphButton.RightStick => "XboxSeriesX_Right_Stick.png", ControllerGlyphButton.LeftStickClick => "XboxSeriesX_Left_Stick_Click.png", ControllerGlyphButton.RightStickClick => "XboxSeriesX_Right_Stick_Click.png", ControllerGlyphButton.DpadUp => "XboxSeriesX_Dpad_Up.png", ControllerGlyphButton.DpadDown => "XboxSeriesX_Dpad_Down.png", ControllerGlyphButton.DpadLeft => "XboxSeriesX_Dpad_Left.png", ControllerGlyphButton.DpadRight => "XboxSeriesX_Dpad_Right.png", ControllerGlyphButton.Select => "XboxSeriesX_View.png", ControllerGlyphButton.Start => "XboxSeriesX_Menu.png", _ => null, }; } private static string GetPlayStationFileName(ControllerGlyphButton button) { return button switch { ControllerGlyphButton.South => "PS5_Cross.png", ControllerGlyphButton.West => "PS5_Square.png", ControllerGlyphButton.East => "PS5_Circle.png", ControllerGlyphButton.North => "PS5_Triangle.png", ControllerGlyphButton.LeftShoulder => "PS5_L1.png", ControllerGlyphButton.RightShoulder => "PS5_R1.png", ControllerGlyphButton.LeftTrigger => "PS5_L2.png", ControllerGlyphButton.RightTrigger => "PS5_R2.png", ControllerGlyphButton.LeftStick => "PS5_Left_Stick.png", ControllerGlyphButton.RightStick => "PS5_Right_Stick.png", ControllerGlyphButton.LeftStickClick => "PS5_Left_Stick_Click.png", ControllerGlyphButton.RightStickClick => "PS5_Right_Stick_Click.png", ControllerGlyphButton.DpadUp => "PS5_Dpad_Up.png", ControllerGlyphButton.DpadDown => "PS5_Dpad_Down.png", ControllerGlyphButton.DpadLeft => "PS5_Dpad_Left.png", ControllerGlyphButton.DpadRight => "PS5_Dpad_Right.png", ControllerGlyphButton.Select => "PS5_Share.png", ControllerGlyphButton.Start => "PS5_Options.png", _ => null, }; } private static string GetSwitchFileName(ControllerGlyphButton button) { return button switch { ControllerGlyphButton.South => "Switch_B.png", ControllerGlyphButton.West => "Switch_Y.png", ControllerGlyphButton.East => "Switch_A.png", ControllerGlyphButton.North => "Switch_X.png", ControllerGlyphButton.LeftShoulder => "Switch_LB.png", ControllerGlyphButton.RightShoulder => "Switch_RB.png", ControllerGlyphButton.LeftTrigger => "Switch_LT.png", ControllerGlyphButton.RightTrigger => "Switch_RT.png", ControllerGlyphButton.LeftStick => "Switch_Left_Stick.png", ControllerGlyphButton.RightStick => "Switch_Right_Stick.png", ControllerGlyphButton.LeftStickClick => "Switch_Left_Stick_Click.png", ControllerGlyphButton.RightStickClick => "Switch_Right_Stick_Click.png", ControllerGlyphButton.DpadUp => "Switch_Dpad_Up.png", ControllerGlyphButton.DpadDown => "Switch_Dpad_Down.png", ControllerGlyphButton.DpadLeft => "Switch_Dpad_Left.png", ControllerGlyphButton.DpadRight => "Switch_Dpad_Right.png", ControllerGlyphButton.Select => "Switch_Minus.png", ControllerGlyphButton.Start => "Switch_Plus.png", _ => null, }; } private static string GetSteamDeckFileName(ControllerGlyphButton button) { return button switch { ControllerGlyphButton.South => "SteamDeck_A.png", ControllerGlyphButton.West => "SteamDeck_X.png", ControllerGlyphButton.East => "SteamDeck_B.png", ControllerGlyphButton.North => "SteamDeck_Y.png", ControllerGlyphButton.LeftShoulder => "SteamDeck_L1.png", ControllerGlyphButton.RightShoulder => "SteamDeck_R1.png", ControllerGlyphButton.LeftTrigger => "SteamDeck_L2.png", ControllerGlyphButton.RightTrigger => "SteamDeck_R2.png", ControllerGlyphButton.LeftStick => "SteamDeck_Left_Stick.png", ControllerGlyphButton.RightStick => "SteamDeck_Right_Stick.png", ControllerGlyphButton.LeftStickClick => "SteamDeck_Left_Stick_Click.png", ControllerGlyphButton.RightStickClick => "SteamDeck_Right_Stick_Click.png", ControllerGlyphButton.DpadUp => "SteamDeck_Dpad_Up.png", ControllerGlyphButton.DpadDown => "SteamDeck_Dpad_Down.png", ControllerGlyphButton.DpadLeft => "SteamDeck_Dpad_Left.png", ControllerGlyphButton.DpadRight => "SteamDeck_Dpad_Right.png", ControllerGlyphButton.Select => "SteamDeck_Minus.png", ControllerGlyphButton.Start => "SteamDeck_Plus.png", _ => null, }; } } [HarmonyPatch(typeof(InputManager), "InputDisplayGet")] internal static class InputDisplayGetGlyphPatch { [HarmonyPostfix] private static void Postfix(InputKey _inputKey, KeyType _keyType, MovementDirection _movementDirection, ref string __result) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (ControllerGlyphManager.Instance != null && ControllerGlyphManager.Instance.TryGetInputKeyGlyph(_inputKey, _keyType, _movementDirection, out var glyphTag)) { __result = glyphTag; } } } [HarmonyPatch(typeof(InputManager), "InputDisplayGetString")] internal static class InputDisplayGetStringGlyphPatch { [HarmonyPostfix] private static void Postfix(ref string __result) { if (ControllerGlyphManager.Instance != null && ControllerGlyphManager.Instance.TryGetMouseGlyph(__result, out var glyphTag)) { __result = glyphTag; } } } [HarmonyPatch(typeof(InputManager), "InputDisplayMouseStringGet")] internal static class InputDisplayMouseStringGetGlyphPatch { [HarmonyPostfix] private static void Postfix(ref string __result) { if (ControllerGlyphManager.Instance != null && ControllerGlyphManager.Instance.TryGetMouseGlyph(__result, out var glyphTag)) { __result = glyphTag; } } } public class ControllerLedManager { private readonly ManualLogSource _logger; private readonly ConfigManager _configManager; private readonly VibrationManager _vibrationManager; private InputDevice _device; private bool _supported; private bool _loggedUnsupported; private Color? _lastAppliedColor; private float _nextHeartbeatTime; private const float HeartbeatIntervalSeconds = 2f; public Color? CurrentColor { get; private set; } public ControllerLedManager(ManualLogSource logger, ConfigManager configManager, VibrationManager vibrationManager) { _logger = logger; _configManager = configManager; _vibrationManager = vibrationManager; _vibrationManager.MotorStateChanged = ApplyManagedVibrationOutput; } public void SetGamepad(Gamepad gamepad) { if (_device == gamepad) { return; } _device = (InputDevice)(object)gamepad; _supported = ControllerLedUtility.SupportsLed((InputDevice)(object)gamepad); _lastAppliedColor = null; _loggedUnsupported = false; if (_configManager.EnableLedSync && gamepad != null) { if (_supported) { _logger.LogInfo((object)("Controller LED sync enabled for " + ((InputControl)gamepad).displayName)); } else if (_configManager.DebugOutput) { _logger.LogInfo((object)("Controller LED sync unavailable for " + ((InputControl)gamepad).displayName + " (no Unity LED API)")); } } } public void Update() { //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) if (_device == null) { return; } if (_configManager.EnableLedSync && _supported) { ApplyManagedVibrationOutput(); } else if (!_supported && _configManager.EnableLedSync && _configManager.DebugOutput && !_loggedUnsupported) { _loggedUnsupported = true; _logger.LogInfo((object)("Controller LED sync skipped: " + ((InputControl)_device).displayName + " has no Unity LED API")); } if (!_configManager.EnableLedSync || !_supported) { return; } Color? localPlayerHeadColor = GetLocalPlayerHeadColor(); if (localPlayerHeadColor.HasValue) { bool num = _vibrationManager != null && _vibrationManager.HasActiveMotors; bool flag = Time.realtimeSinceStartup >= _nextHeartbeatTime; if (flag) { _nextHeartbeatTime = Time.realtimeSinceStartup + 2f; } if (num || flag || !_lastAppliedColor.HasValue || !ColorsApproximatelyEqual(_lastAppliedColor.Value, localPlayerHeadColor.Value)) { ApplyLedColor(localPlayerHeadColor.Value); } } } internal void ApplyManagedVibrationOutput() { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) if (_device == null || _vibrationManager == null || !_configManager.EnableVibration || !_configManager.EnableLedSync || !_supported) { return; } float activeLowMotor = _vibrationManager.ActiveLowMotor; float activeHighMotor = _vibrationManager.ActiveHighMotor; if (ControllerLedUtility.SupportsCombinedMotorLed(_device)) { Color color = (Color)(((??)CurrentColor) ?? ((??)_lastAppliedColor) ?? Color.black); ControllerLedUtility.TrySetLedColor(_device, color, activeLowMotor, activeHighMotor); return; } InputDevice device = _device; Gamepad val = (Gamepad)(object)((device is Gamepad) ? device : null); if (val != null) { val.SetMotorSpeeds(activeLowMotor, activeHighMotor); if (CurrentColor.HasValue) { ControllerLedUtility.TrySetLedColor(_device, CurrentColor.Value); } } } private void ApplyLedColor(Color color) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) CurrentColor = color; if (ControllerLedUtility.SupportsCombinedMotorLed(_device)) { float value = ((_vibrationManager != null) ? _vibrationManager.ActiveLowMotor : 0f); float value2 = ((_vibrationManager != null) ? _vibrationManager.ActiveHighMotor : 0f); if (ControllerLedUtility.TrySetLedColor(_device, color, value, value2)) { _lastAppliedColor = color; } } else if (ControllerLedUtility.TrySetLedColor(_device, color)) { _lastAppliedColor = color; if (_configManager.DebugOutput) { _logger.LogInfo((object)$"Controller LED set to ({color.r:F2}, {color.g:F2}, {color.b:F2})"); } } } private void ApplyLedAndMotors(Color color, float lowMotor, float highMotor) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) CurrentColor = color; if (ControllerLedUtility.SupportsCombinedMotorLed(_device)) { if (ControllerLedUtility.TrySetLedColor(_device, color, lowMotor, highMotor)) { _lastAppliedColor = color; } return; } InputDevice device = _device; Gamepad val = (Gamepad)(object)((device is Gamepad) ? device : null); if (val != null && _configManager.EnableVibration) { val.SetMotorSpeeds(lowMotor, highMotor); } if (ControllerLedUtility.TrySetLedColor(_device, color)) { _lastAppliedColor = color; if (_configManager.DebugOutput) { _logger.LogInfo((object)$"Controller LED set to ({color.r:F2}, {color.g:F2}, {color.b:F2})"); } } } public void SyncFromPlayer() { //IL_0067: Unknown result type (might be due to invalid IL or missing references) if (_configManager.EnableLedSync && _device != null && _supported) { Color? localPlayerHeadColor = GetLocalPlayerHeadColor(); if (localPlayerHeadColor.HasValue) { float lowMotor = ((_vibrationManager != null) ? _vibrationManager.ActiveLowMotor : 0f); float highMotor = ((_vibrationManager != null) ? _vibrationManager.ActiveHighMotor : 0f); ApplyLedAndMotors(localPlayerHeadColor.Value, lowMotor, highMotor); } } } private void ApplyColor(Color color) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) float lowMotor = ((_vibrationManager != null) ? _vibrationManager.ActiveLowMotor : 0f); float highMotor = ((_vibrationManager != null) ? _vibrationManager.ActiveHighMotor : 0f); ApplyLedAndMotors(color, lowMotor, highMotor); } internal static PlayerAvatar GetLocalPlayerAvatar() { try { PlayerAvatar val = SemiFunc.PlayerGetLocal(); if ((Object)(object)val != (Object)null) { return val; } } catch { } try { PlayerAvatar val2 = SemiFunc.PlayerAvatarLocal(); if ((Object)(object)val2 != (Object)null) { return val2; } } catch { } if ((Object)(object)PlayerAvatar.instance != (Object)null) { return PlayerAvatar.instance; } try { foreach (PlayerAvatar item in SemiFunc.PlayerGetAll()) { if ((Object)(object)item != (Object)null && Traverse.Create((object)item).Field("isLocal").GetValue<bool>()) { return item; } } } catch { } try { List<PlayerAvatar> playerList = GameDirector.instance.PlayerList; if (playerList != null) { foreach (PlayerAvatar item2 in playerList) { if ((Object)(object)item2 != (Object)null && Traverse.Create((object)item2).Field("isLocal").GetValue<bool>()) { return item2; } } if (playerList.Count == 1 && (Object)(object)playerList[0] != (Object)null) { return playerList[0]; } } } catch { } return null; } internal static bool IsLocalPlayer(PlayerAvatar avatar) { if ((Object)(object)avatar == (Object)null) { return false; } if (IsAvatarMarkedLocal(avatar)) { return true; } PlayerAvatar localPlayerAvatar = GetLocalPlayerAvatar(); if ((Object)(object)localPlayerAvatar != (Object)null) { return localPlayerAvatar == avatar; } return false; } internal static bool IsAvatarMarkedLocal(PlayerAvatar avatar) { if ((Object)(object)avatar == (Object)null) { return false; } try { if (Traverse.Create((object)avatar).Field("isLocal").GetValue<bool>()) { return true; } } catch { } return !GameManager.Multiplayer(); } internal static bool IsLocalPlayerCosmetics(PlayerCosmetics cosmetics) { if ((Object)(object)cosmetics == (Object)null || (Object)(object)cosmetics.playerAvatarVisuals == (Object)null) { return false; } return IsLocalPlayer(cosmetics.playerAvatarVisuals.playerAvatar); } internal static Color? GetLocalPlayerHeadColor() { //IL_001b: 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_0021: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) PlayerAvatar localPlayerAvatar = GetLocalPlayerAvatar(); if ((Object)(object)localPlayerAvatar == (Object)null) { return null; } try { Color val = SemiFunc.PlayerGetColorMain(localPlayerAvatar); if (val.a > 0f || val.r > 0f || val.g > 0f || val.b > 0f) { return val; } } catch { } if ((Object)(object)localPlayerAvatar.playerAvatarVisuals == (Object)null) { return null; } Traverse val2 = Traverse.Create((object)localPlayerAvatar.playerAvatarVisuals); try { Color value = val2.Field("playerColorTop").GetValue<Color>(); if (value.a > 0f || value.r > 0f || value.g > 0f || value.b > 0f) { return value; } } catch { } try { return val2.Field("color").GetValue<Color>(); } catch { } return GetSavedPlayerColor(); } private static Color? GetSavedPlayerColor() { //IL_0066: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)DataDirector.instance == (Object)null || (Object)(object)AssetManager.instance == (Object)null) { return null; } int num = DataDirector.instance.ColorGetBody(); Color[] value = Traverse.Create((object)AssetManager.instance).Field("playerColors").GetValue<Color[]>(); if (value == null || num < 0 || num >= value.Length) { return null; } return value[num]; } catch { return null; } } private static bool ColorsApproximatelyEqual(Color a, Color b) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: 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_002c: Unknown result type (might be due to invalid IL or missing references) if (Mathf.Approximately(a.r, b.r) && Mathf.Approximately(a.g, b.g)) { return Mathf.Approximately(a.b, b.b); } return false; } } internal static class ControllerLedUtility { public static bool SupportsLed(InputDevice device) { if (device == null) { return false; } if (device is IDualShockHaptics) { return true; } return FindSetLightBarColorMethod(device) != null; } public static bool SupportsCombinedMotorLed(InputDevice device) { return FindSetMotorSpeedsAndLightBarColorMethod(device) != null; } public static bool TrySetLedColor(InputDevice device, Color color) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return TrySetLedColor(device, color, null, null); } public static bool TrySetLedColor(InputDevice device, Color color, float? lowMotor, float? highMotor) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) if (device == null) { return false; } color = ClampColor(color); if (lowMotor.HasValue || highMotor.HasValue) { MethodInfo methodInfo = FindSetMotorSpeedsAndLightBarColorMethod(device); if (methodInfo != null) { methodInfo.Invoke(device, new object[3] { lowMotor, highMotor, color }); return true; } } IDualShockHaptics val = (IDualShockHaptics)(object)((device is IDualShockHaptics) ? device : null); if (val != null) { val.SetLightBarColor(color); return true; } MethodInfo methodInfo2 = FindSetLightBarColorMethod(device); if (methodInfo2 != null) { methodInfo2.Invoke(device, new object[1] { color }); return true; } return false; } private static Color ClampColor(Color color) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) return new Color(Mathf.Clamp01(color.r), Mathf.Clamp01(color.g), Mathf.Clamp01(color.b), 1f); } private static MethodInfo FindSetLightBarColorMethod(InputDevice device) { foreach (Type item in GetTypeHierarchy(((object)device).GetType())) { MethodInfo method = item.GetMethod("SetLightBarColor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(Color) }, null); if (method != null) { return method; } } return null; } private static MethodInfo FindSetMotorSpeedsAndLightBarColorMethod(InputDevice device) { foreach (Type item in GetTypeHierarchy(((object)device).GetType())) { MethodInfo method = item.GetMethod("SetMotorSpeedsAndLightBarColor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[3] { typeof(float?), typeof(float?), typeof(Color?) }, null); if (method != null) { return method; } } return null; } private static IEnumerable<Type> GetTypeHierarchy(Type type) { while (type != null) { yield return type; type = type.BaseType; } } } [BepInPlugin("pacmanninja998.nexus.ControllerSupport", "Controller Support", "1.0.2")] public class ControllerSupportPlugin : BaseUnityPlugin { private InputManager _inputManager; private ConfigManager _configManager; private VibrationManager _vibrationManager; private ControllerLedManager _ledManager; private ControllerGlyphManager _glyphManager; private Harmony _harmony; private void Awake() { //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Expected O, but got Unknown ((BaseUnityPlugin)this).Logger.LogInfo((object)"Controller Support plugin loaded!"); _configManager = new ConfigManager(((BaseUnityPlugin)this).Config); _vibrationManager = new VibrationManager(((BaseUnityPlugin)this).Logger, _configManager); _ledManager = new ControllerLedManager(((BaseUnityPlugin)this).Logger, _configManager, _vibrationManager); _inputManager = new InputManager(((BaseUnityPlugin)this).Logger, _configManager, _vibrationManager, _ledManager); _glyphManager = new ControllerGlyphManager(((BaseUnityPlugin)this).Logger, _configManager, ((BaseUnityPlugin)this).Info.Location); if (!_configManager.EnableVibration && !_configManager.EnableLedSync && !_configManager.EnableMenuNavigation && !_configManager.EnableControllerGlyphs) { return; } if (_configManager.EnableVibration) { GameEventPatches.Initialize(_vibrationManager, _configManager, ((BaseUnityPlugin)this).Logger); } ColorLedPatches.Initialize(_ledManager, _configManager, ((BaseUnityPlugin)this).Logger); MenuNavigationPatches.Initialize(_inputManager.MenuNavigation, _configManager, ((BaseUnityPlugin)this).Logger); _harmony = new Harmony("pacmanninja998.nexus.ControllerSupport"); try { _harmony.PatchAll(typeof(ControllerSupportPlugin).Assembly); if (_configManager.EnableVibration) { if (_configManager.EnableDamageVibration) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Damage vibration patches applied."); } if (_configManager.EnableItemBreakVibration) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Item break vibration patches applied."); } if (_configManager.EnableHoldVibration) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Hold vibration patches applied."); } } if (_configManager.EnableLedSync) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Controller LED sync patches applied."); } if (_configManager.EnableMenuNavigation) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Menu navigation patches applied."); } if (_configManager.EnableControllerGlyphs) { _glyphManager.Initialize(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Controller glyph patches applied."); } } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Harmony patching failed: {arg}"); } } private void Update() { _inputManager?.Update(); _glyphManager?.Update(); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } _vibrationManager?.Stop(); if (Keyboard.current != null && _inputManager != null) { _inputManager.ReleaseAllKeys(); } } } internal static class GameEventPatches { internal static VibrationManager Vibration; internal static ConfigManager Config; internal static ManualLogSource Logger; internal static void Initialize(VibrationManager vibration, ConfigManager config, ManualLogSource logger) { Vibration = vibration; Config = config; Logger = logger; } internal static bool ShouldApplyGameVibration() { if (Config != null && Vibration != null) { return Config.EnableVibration; } return false; } internal static bool IsLocalPlayerHealth(PlayerHealth instance) { PlayerAvatar localPlayerAvatar = ControllerLedManager.GetLocalPlayerAvatar(); if ((Object)(object)localPlayerAvatar == (Object)null || (Object)(object)instance == (Object)null) { return false; } return localPlayerAvatar.playerHealth == instance; } internal static bool IsHeldByLocalPlayer(PhysGrabObject physGrabObject) { if ((Object)(object)physGrabObject == (Object)null) { return false; } return Traverse.Create((object)physGrabObject).Field("heldByLocalPlayer").GetValue<bool>(); } internal static bool ShouldSkipDamageFeedback(PlayerHealth instance, int damage) { if (damage <= 0) { return true; } Traverse val = Traverse.Create((object)instance); if (val.Field("godMode").GetValue<bool>()) { return true; } PlayerAvatar value = val.Field("playerAvatar").GetValue<PlayerAvatar>(); if ((Object)(object)value != (Object)null && Traverse.Create((object)value).Field("deadSet").GetValue<bool>()) { return true; } if (val.Field("invincibleTimer").GetValue<float>() > 0f) { return true; } if (GameManager.Multiplayer()) { PhotonView value2 = val.Field("photonView").GetValue<PhotonView>(); if ((Object)(object)value2 != (Object)null && !value2.IsMine) { return true; } } return false; } internal static void ApplyHoldSustain(PhysGrabObject grabbedObject) { float num = 0.5f; if ((Object)(object)grabbedObject != (Object)null) { object value = Traverse.Create((object)grabbedObject).Field("rb").GetValue<object>(); if (value != null) { num = Traverse.Create(value).Property("mass", (object[])null).GetValue<float>(); } } float num2 = Mathf.Clamp01(num / 7f); float lowFrequency = Mathf.Lerp(0.04f, 0.12f, num2); float highFrequency = Mathf.Lerp(0.06f, 0.18f, num2); Vibration.SetHoldSustain(lowFrequency, highFrequency); } } [HarmonyPatch(typeof(PlayerHealth), "Hurt")] internal static class PlayerHealthHurtVibrationPatch { [HarmonyPostfix] private static void Postfix(PlayerHealth __instance, int damage) { if (GameEventPatches.ShouldApplyGameVibration() && GameEventPatches.Config.EnableDamageVibration && GameEventPatches.IsLocalPlayerHealth(__instance) && !GameEventPatches.ShouldSkipDamageFeedback(__instance, damage)) { float num = Mathf.Clamp01((float)damage / 50f); float lowFrequency = Mathf.Lerp(0.25f, 0.85f, num); float highFrequency = Mathf.Lerp(0.4f, 1f, num); float durationSeconds = Mathf.Lerp(0.12f, 0.45f, num); GameEventPatches.Vibration.Pulse(lowFrequency, highFrequency, durationSeconds); } } } [HarmonyPatch(typeof(PhysGrabObjectImpactDetector), "BreakRPC")] internal static class PhysGrabObjectBreakVibrationPatch { [HarmonyPostfix] private static void Postfix(PhysGrabObjectImpactDetector __instance, float valueLost, int breakLevel, bool _loseValue) { if (!GameEventPatches.ShouldApplyGameVibration() || !GameEventPatches.Config.EnableItemBreakVibration || !_loseValue || !GameEventPatches.IsHeldByLocalPlayer(Traverse.Create((object)__instance).Field("physGrabObject").GetValue<PhysGrabObject>())) { return; } float num = Mathf.Clamp01(valueLost / 500f); if (breakLevel > 1) { num = Mathf.Max(num, Mathf.Clamp01(0.35f + (float)breakLevel * 0.12f)); } float lowFrequency = Mathf.Lerp(0.3f, 0.9f, num); float highFrequency = Mathf.Lerp(0.5f, 1f, num); float durationSeconds = Mathf.Lerp(0.15f, 0.5f, num); GameEventPatches.Vibration.Pulse(lowFrequency, highFrequency, durationSeconds); if (GameEventPatches.Config.DebugOutput) { ManualLogSource logger = GameEventPatches.Logger; if (logger != null) { logger.LogInfo((object)$"Item break vibration: valueLost={valueLost:F0}, breakLevel={breakLevel}, severity={num:F2}"); } } } } [HarmonyPatch(typeof(PhysGrabber), "PhysGrabStartEffects")] internal static class PhysGrabberStartVibrationPatch { [HarmonyPostfix] private static void Postfix(PhysGrabber __instance) { if (!GameEventPatches.ShouldApplyGameVibration() || !GameEventPatches.Config.EnableHoldVibration || !__instance.isLocal) { return; } GameEventPatches.ApplyHoldSustain(Traverse.Create((object)__instance).Field("grabbedPhysGrabObject").GetValue<PhysGrabObject>()); GameEventPatches.Vibration.Pulse(0.1f, 0.16f, 0.06f); if (GameEventPatches.Config.DebugOutput) { ManualLogSource logger = GameEventPatches.Logger; if (logger != null) { logger.LogInfo((object)"Hold vibration started."); } } } } [HarmonyPatch(typeof(PhysGrabber), "PhysGrabEndEffects")] internal static class PhysGrabberEndVibrationPatch { [HarmonyPostfix] private static void Postfix(PhysGrabber __instance) { if (!GameEventPatches.ShouldApplyGameVibration() || !GameEventPatches.Config.EnableHoldVibration || !__instance.isLocal) { return; } GameEventPatches.Vibration.ClearHoldSustain(); if (GameEventPatches.Config.DebugOutput) { ManualLogSource logger = GameEventPatches.Logger; if (logger != null) { logger.LogInfo((object)"Hold vibration stopped."); } } } } internal static class GamepadHelper { internal static Gamepad FindActiveGamepad() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) Gamepad current = Gamepad.current; if (current is IDualShockHaptics) { return current; } Enumerator<Gamepad> enumerator = Gamepad.all.GetEnumerator(); try { while (enumerator.MoveNext()) { Gamepad current2 = enumerator.Current; if (current2 is IDualShockHaptics) { return current2; } } } finally { ((IDisposable)enumerator).Dispose(); } if (current != null) { return current; } enumerator = Gamepad.all.GetEnumerator(); try { while (enumerator.MoveNext()) { Gamepad current3 = enumerator.Current; if (current3 != null) { return current3; } } } finally { ((IDisposable)enumerator).Dispose(); } return null; } } public class InputManager { private readonly ManualLogSource _logger; private readonly ConfigManager _configManager; private readonly KeyboardSimulator _keyboardSimulator; private readonly MouseSimulator _mouseSimulator; private readonly JoystickZoneHandler _joystickZoneHandler; private readonly VibrationManager _vibrationManager; private readonly ControllerLedManager _ledManager; private readonly MenuNavigationManager _menuNavigation; private Gamepad _gamepad; private bool _isControllerConnected; private float _previousLeftTrigger; private float _previousRightTrigger; internal MenuNavigationManager MenuNavigation => _menuNavigation; [DllImport("user32.dll")] private static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr lpdwProcessId); [DllImport("user32.dll")] private static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach); [DllImport("user32.dll")] private static extern IntPtr GetForegroundWindow(); [DllImport("kernel32.dll")] private static extern uint GetCurrentThreadId(); [DllImport("user32.dll")] private static extern bool BringWindowToTop(IntPtr hWnd); [DllImport("user32.dll")] private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); public InputManager(ManualLogSource logger, ConfigManager configManager, VibrationManager vibrationManager, ControllerLedManager ledManager) { _logger = logger; _configManager = configManager; _vibrationManager = vibrationManager; _ledManager = ledManager; _keyboardSimulator = new KeyboardSimulator(logger, configManager); _mouseSimulator = new MouseSimulator(logger, configManager); _joystickZoneHandler = new JoystickZoneHandler(logger, configManager, _keyboardSimulator); _menuNavigation = new MenuNavigationManager(logger, configManager); _gamepad = GamepadHelper.FindActiveGamepad(); _isControllerConnected = _gamepad != null; if (_isControllerConnected) { _logger.LogInfo((object)("Controller connected: " + ((InputControl)_gamepad).displayName)); } else { _logger.LogWarning((object)"No controller connected. Waiting for connection..."); } } public void Update() { //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) ProcessDevInputs(); if (_configManager.EnableMenuNavigation) { _menuNavigation.Update(); } bool isControllerConnected = _isControllerConnected; _gamepad = GamepadHelper.FindActiveGamepad(); _isControllerConnected = _gamepad != null; if (_isControllerConnected && !isControllerConnected) { _logger.LogInfo((object)("Controller connected: " + ((InputControl)_gamepad).displayName)); } if (_configManager.EnableMenuNavigation && _menuNavigation.IsActive) { _vibrationManager.ClearRunSustain(); if (_isControllerConnected) { _vibrationManager.SetGamepad(_gamepad); _ledManager.SetGamepad(_gamepad); _menuNavigation.ProcessControllerInput(_gamepad, _keyboardSimulator, _mouseSimulator, _vibrationManager); } _vibrationManager.Update(); _ledManager.Update(); } else if (!_isControllerConnected && isControllerConnected) { _logger.LogWarning((object)"Controller disconnected!"); _vibrationManager.Stop(); ReleaseAllKeys(); } else { if (!_isControllerConnected) { return; } _vibrationManager.SetGamepad(_gamepad); _ledManager.SetGamepad(_gamepad); try { if (_configManager.DebugOutput) { Vector2 val = ((InputControl<Vector2>)(object)_gamepad.leftStick).ReadValue(); Vector2 val2 = ((InputControl<Vector2>)(object)_gamepad.rightStick).ReadValue(); _logger.LogInfo((object)$"Left Stick: X={val.x:F3}, Y={val.y:F3}"); _logger.LogInfo((object)$"Right Stick: X={val2.x:F3}, Y={val2.y:F3}"); _logger.LogInfo((object)$"Triggers: Left={((InputControl<float>)(object)_gamepad.leftTrigger).ReadValue():F3}, Right={((InputControl<float>)(object)_gamepad.rightTrigger).ReadValue():F3}"); } ProcessButtonInputs(_gamepad); ProcessJoystickInputs(_gamepad); ProcessRunVibration(_gamepad); ProcessTriggerInputs(_gamepad); _vibrationManager.Update(); _ledManager.Update(); if (!_configManager.AutoReleaseShiftAfterWASD || !_keyboardSimulator.IsShiftPressed || !(Time.realtimeSinceStartup - _joystickZoneHandler.LastWASDActivityTime > _configManager.ShiftReleaseDelay)) { return; } if (_configManager.EnableShiftToggle) { if (_keyboardSimulator.IsShiftPressed) { _keyboardSimulator.ToggleShift(); if (_configManager.DebugOutput) { _logger.LogInfo((object)"Auto-released Shift after WASD inactivity"); } } } else { _keyboardSimulator.SendKeyEvent((Key)51, isPressed: false); if (_configManager.DebugOutput) { _logger.LogInfo((object)"Auto-released Shift after WASD inactivity"); } } } catch (Exception ex) { _logger.LogError((object)("Error reading controller: " + ex.Message)); _isControllerConnected = false; ReleaseAllKeys(); } } } private void ForceForegroundWindow(IntPtr hWnd) { if (!(hWnd == IntPtr.Zero)) { uint windowThreadProcessId = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero); uint currentThreadId = GetCurrentThreadId(); if (windowThreadProcessId != currentThreadId) { AttachThreadInput(windowThreadProcessId, currentThreadId, fAttach: true); BringWindowToTop(hWnd); ShowWindow(hWnd, 5); AttachThreadInput(windowThreadProcessId, currentThreadId, fAttach: false); } else { BringWindowToTop(hWnd); ShowWindow(hWnd, 5); } } } private bool ActivateREPOProcess() { try { Process[] processesByName = Process.GetProcessesByName("REPO"); if (processesByName.Length == 0) { if (_configManager.DebugOutput) { _logger.LogWarning((object)"No REPO.exe process found."); } return false; } Process process = processesByName.OrderByDescending((Process p) => p.WorkingSet64).FirstOrDefault((Process p) => p.MainWindowHandle != IntPtr.Zero); if (process == null) { process = processesByName.FirstOrDefault((Process p) => p.MainWindowHandle != IntPtr.Zero); } if (process != null) { ForceForegroundWindow(process.MainWindowHandle); if (_configManager.DebugOutput) { _logger.LogInfo((object)$"Activated REPO.exe process (PID: {process.Id})"); } return true; } if (_configManager.DebugOutput) { _logger.LogWarning((object)"Could not find a valid window handle for any REPO.exe process."); } return false; } catch (Exception ex) { _logger.LogError((object)("Error activating REPO.exe process: " + ex.Message)); return false; } } private void ProcessDevInputs() { if (_configManager.DevMode && Keyboard.current != null) { if (((ButtonControl)Keyboard.current[(Key)80]).wasPressedThisFrame) { float num = _configManager.IncreaseScrollSpeed(); _logger.LogInfo((object)$"Increased ScrollSpeed to {num:F6}"); } if (((ButtonControl)Keyboard.current[(Key)81]).wasPressedThisFrame) { float num2 = _configManager.DecreaseScrollSpeed(); _logger.LogInfo((object)$"Decreased ScrollSpeed to {num2:F6}"); } if (((ButtonControl)Keyboard.current[(Key)91]).wasPressedThisFrame) { float magnitude = (float)Math.Sqrt(_configManager.CurrentJoystickX * _configManager.CurrentJoystickX + _configManager.CurrentJoystickY * _configManager.CurrentJoystickY); float num3 = _configManager.UpdateDeadZoneRadius(magnitude); _logger.LogInfo((object)$"Updated DeadZoneRadius to {num3:F4} based on current joystick position"); } if (((ButtonControl)Keyboard.current[(Key)88]).wasPressedThisFrame) { float num4 = _configManager.UpdateDiagonalZoneSize(_configManager.CurrentJoystickAngle); _logger.LogInfo((object)$"Updated DiagonalZoneSize to {num4:F4} based on current joystick angle"); } } } private void RumbleInput(float lowFrequency, float highFrequency, float durationSeconds) { if (_configManager.EnableVibration && _configManager.EnableInputVibration) { _vibrationManager.Pulse(lowFrequency, highFrequency, durationSeconds); } } private void ProcessButtonInputs(Gamepad gamepad) { if (gamepad.buttonSouth.wasPressedThisFrame) { if (_configManager.ReleaseCtrlOnA && _keyboardSimulator.IsCtrlToggled) { _keyboardSimulator.ToggleCtrl(); if (_configManager.DebugOutput) { _logger.LogInfo((object)"Released Ctrl due to A button press"); } } _keyboardSimulator.SendKeyEvent((Key)1, isPressed: true); RumbleInput(0.12f, 0.22f, 0.07f); if (_configManager.DebugOutput) { _logger.LogInfo((object)"A pressed - Space"); } } else if (gamepad.buttonSouth.wasReleasedThisFrame) { _keyboardSimulator.SendKeyEvent((Key)1, isPressed: false); } if (gamepad.buttonWest.wasPressedThisFrame) { _keyboardSimulator.SendKeyEvent((Key)19, isPressed: true); RumbleInput(0.1f, 0.18f, 0.06f); if (_configManager.DebugOutput) { _logger.LogInfo((object)"X pressed - E"); } } else if (gamepad.buttonWest.wasReleasedThisFrame) { _keyboardSimulator.SendKeyEvent((Key)19, isPressed: false); } if (gamepad.buttonEast.wasPressedThisFrame) { if (_configManager.EnableCtrlToggle) { _keyboardSimulator.ToggleCtrl(); RumbleInput(0.08f, 0.14f, 0.05f); if (_configManager.DebugOutput) { _logger.LogInfo((object)("B pressed - Ctrl " + (_keyboardSimulator.IsCtrlToggled ? "ON" : "OFF"))); } } else { _keyboardSimulator.SendKeyEvent((Key)55, isPressed: true); if (_configManager.DebugOutput) { _logger.LogInfo((object)"B pressed - Ctrl"); } } } else if (gamepad.buttonEast.wasReleasedThisFrame && !_configManager.EnableCtrlToggle) { _keyboardSimulator.SendKeyEvent((Key)55, isPressed: false); } if (gamepad.buttonNorth.wasPressedThisFrame) { _keyboardSimulator.SendKeyEvent((Key)31, isPressed: true); if (_configManager.DebugOutput) { _logger.LogInfo((object)"Y pressed - Q"); } } else if (gamepad.buttonNorth.wasReleasedThisFrame) { _keyboardSimulator.SendKeyEvent((Key)31, isPressed: false); } if (gamepad.leftStickButton.wasPressedThisFrame) { if (_configManager.ReleaseCtrlOnShift && _keyboardSimulator.IsCtrlToggled) { _keyboardSimulator.ToggleCtrl(); if (_configManager.DebugOutput) { _logger.LogInfo((object)"Released Ctrl due to Shift activation"); } } if (_configManager.ReleaseTabOnShift && _keyboardSimulator.IsTabToggled) { _keyboardSimulator.ToggleTab(); if (_configManager.DebugOutput) { _logger.LogInfo((object)"Released Tab due to Shift activation"); } } if (_configManager.EnableShiftToggle) { _keyboardSimulator.ToggleShift(); RumbleInput(0.08f, 0.14f, 0.05f); if (_configManager.DebugOutput) { _logger.LogInfo((object)("L3 pressed - Shift " + (_keyboardSimulator.IsShiftPressed ? "ON" : "OFF"))); } } else { _keyboardSimulator.SendKeyEvent((Key)51, isPressed: true); if (_configManager.DebugOutput) { _logger.LogInfo((object)"L3 pressed - Shift ON"); } } } else if (gamepad.leftStickButton.wasReleasedThisFrame && !_configManager.EnableShiftToggle) { _keyboardSimulator.SendKeyEvent((Key)51, isPressed: false); if (_configManager.DebugOutput) { _logger.LogInfo((object)"L3 released - Shift OFF"); } } if (gamepad.rightShoulder.isPressed) { _mouseSimulator.Scroll(_configManager.ScrollSpeed); if (_configManager.DebugOutput) { _logger.LogInfo((object)$"RB held - Scroll Up ({_configManager.ScrollSpeed})"); } } if (gamepad.leftShoulder.isPressed) { _mouseSimulator.Scroll(0f - _configManager.ScrollSpeed); if (_configManager.DebugOutput) { _logger.LogInfo((object)$"LB held - Scroll Down ({0f - _configManager.ScrollSpeed})"); } } if (gamepad.dpad.left.wasPressedThisFrame) { _keyboardSimulator.SendKeyEvent((Key)41, isPressed: true); if (_configManager.DebugOutput) { _logger.LogInfo((object)"D-Pad Left - 1"); } } else if (gamepad.dpad.left.wasReleasedThisFrame) { _keyboardSimulator.SendKeyEvent((Key)41, isPressed: false); } if (gamepad.dpad.up.wasPressedThisFrame) { _keyboardSimulator.SendKeyEvent((Key)42, isPressed: true); if (_configManager.DebugOutput) { _logger.LogInfo((object)"D-Pad Up - 2"); } } else if (gamepad.dpad.up.wasReleasedThisFrame) { _keyboardSimulator.SendKeyEvent((Key)42, isPressed: false); } if (gamepad.dpad.right.wasPressedThisFrame) { _keyboardSimulator.SendKeyEvent((Key)43, isPressed: true); if (_configManager.DebugOutput) { _logger.LogInfo((object)"D-Pad Right - 3"); } } else if (gamepad.dpad.right.wasReleasedThisFrame) { _keyboardSimulator.SendKeyEvent((Key)43, isPressed: false); } if (gamepad.startButton.wasPressedThisFrame) { _keyboardSimulator.SendKeyEvent((Key)60, isPressed: true); if (_configManager.DebugOutput) { _logger.LogInfo((object)"Start pressed - Escape"); } } else if (gamepad.startButton.wasReleasedThisFrame) { _keyboardSimulator.SendKeyEvent((Key)60, isPressed: false); } if (gamepad.selectButton.wasPressedThisFrame) { if (_configManager.EnableTabToggle) { _keyboardSimulator.ToggleTab(); RumbleInput(0.08f, 0.14f, 0.05f); if (_configManager.DebugOutput) { _logger.LogInfo((object)("Back pressed - Tab " + (_keyboardSimulator.IsTabToggled ? "ON" : "OFF"))); } } else { _keyboardSimulator.SendKeyEvent((Key)3, isPressed: true); if (_configManager.DebugOutput) { _logger.LogInfo((object)"Back pressed - Tab"); } } } else if (gamepad.selectButton.wasReleasedThisFrame && !_configManager.EnableTabToggle) { _keyboardSimulator.SendKeyEvent((Key)3, isPressed: false); } } private void ProcessJoystickInputs(Gamepad gamepad) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) Vector2 val = ((InputControl<Vector2>)(object)gamepad.leftStick).ReadValue(); Vector2 val2 = ((InputControl<Vector2>)(object)gamepad.rightStick).ReadValue(); short x = (short)(Mathf.Clamp(val.x, -1f, 1f) * 32767f); short y = (short)(Mathf.Clamp(val.y, -1f, 1f) * 32767f); short x2 = (short)(Mathf.Clamp(val2.x, -1f, 1f) * 32767f); short y2 = (short)(Mathf.Clamp(val2.y, -1f, 1f) * 32767f); _joystickZoneHandler.ProcessLeftJoystick(x, y); _mouseSimulator.MoveMouse(x2, y2); } private void ProcessRunVibration(Gamepad gamepad) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) if (!_configManager.EnableVibration || !_configManager.EnableInputVibration) { _vibrationManager.ClearRunSustain(); return; } if (!_keyboardSimulator.IsShiftPressed) { _vibrationManager.ClearRunSustain(); return; } Vector2 val = ((InputControl<Vector2>)(object)gamepad.leftStick).ReadValue(); float deadZoneRadius = _configManager.DeadZoneRadius; if (((Vector2)(ref val)).sqrMagnitude <= deadZoneRadius * deadZoneRadius) { _vibrationManager.ClearRunSustain(); return; } float num = Mathf.Clamp01(((Vector2)(ref val)).magnitude); _vibrationManager.SetRunSustain(Mathf.Lerp(0.05f, 0.12f, num), Mathf.Lerp(0.08f, 0.16f, num)); } private void ProcessTriggerInputs(Gamepad gamepad) { float num = ((InputControl<float>)(object)gamepad.leftTrigger).ReadValue(); float num2 = ((InputControl<float>)(object)gamepad.rightTrigger).ReadValue(); if (num2 > 0.5f && _previousRightTrigger <= 0.5f) { ActivateREPOProcess(); _mouseSimulator.LeftMouseDown(); RumbleInput(0.18f, 0.35f, 0.08f); if (_configManager.DebugOutput) { _logger.LogInfo((object)"RT pressed - Left Mouse Down"); } } else if (num2 <= 0.5f && _previousRightTrigger > 0.5f) { _mouseSimulator.LeftMouseUp(); } if (num > 0.5f && _previousLeftTrigger <= 0.5f) { _mouseSimulator.RightMouseDown(); RumbleInput(0.1f, 0.16f, 0.06f); if (_configManager.DebugOutput) { _logger.LogInfo((object)"LT pressed - Right Mouse Down"); } } else if (num <= 0.5f && _previousLeftTrigger > 0.5f) { _mouseSimulator.RightMouseUp(); } _previousLeftTrigger = num; _previousRightTrigger = num2; } public void ReleaseAllKeys() { _keyboardSimulator.ReleaseAllKeys(); _mouseSimulator.ReleaseAllButtons(); _previousLeftTrigger = 0f; _previousRightTrigger = 0f; } } public class JoystickZoneHandler { private readonly ManualLogSource _logger; private readonly ConfigManager _configManager; private readonly KeyboardSimulator _keyboardSimulator; private float _lastX; private float _lastY; private bool _lastWPressed; private bool _lastAPressed; private bool _lastSPressed; private bool _lastDPressed; private float _lastWASDActivityTime; public float LastWASDActivityTime => _lastWASDActivityTime; public JoystickZoneHandler(ManualLogSource logger, ConfigManager configManager, KeyboardSimulator keyboardSimulator) { _logger = logger; _configManager = configManager; _keyboardSimulator = keyboardSimulator; _lastWASDActivityTime = Time.realtimeSinceStartup; } public void ProcessLeftJoystick(short x, short y) { float num = (float)x / 32768f; float num2 = (float)y / 32768f; _configManager.CurrentJoystickX = num; _configManager.CurrentJoystickY = num2; bool flag = Math.Abs(num - _lastX) > 0.01f || Math.Abs(num2 - _lastY) > 0.01f; _lastX = num; _lastY = num2; float num3 = (float)Math.Sqrt(num * num + num2 * num2); bool flag2 = false; bool flag3 = false; bool flag4 = false; bool flag5 = false; if (!(num3 < _configManager.DeadZoneRadius)) { float num4 = (float)Math.Atan2(num2, num) * 180f / (float)Math.PI; if (num4 < 0f) { num4 += 360f; } _configManager.CurrentJoystickAngle = num4; if (num4 > 45f && num4 < 135f) { flag2 = true; } else if (num4 > 225f && num4 < 315f) { flag4 = true; } else if (num4 > 135f && num4 < 225f) { flag3 = true; } else if (num4 < 45f || num4 > 315f) { flag5 = true; } if (num4 > 45f && num4 < 75f) { flag2 = true; flag5 = true; } else if (num4 > 105f && num4 < 135f) { flag2 = true; flag3 = true; } else if (num4 > 225f && num4 < 255f) { flag4 = true; flag3 = true; } else if (num4 > 285f && num4 < 315f) { flag4 = true; flag5 = true; } if (flag && _configManager.DebugOutput) { _logger.LogInfo((object)$"Joystick: X={num:F2}, Y={num2:F2}, Angle={num4:F1}, Magnitude={num3:F2}"); } } if (flag2 || flag3 || flag4 || flag5) { _lastWASDActivityTime = Time.realtimeSinceStartup; } if (flag2 != _lastWPressed) { _keyboardSimulator.SendKeyEvent((Key)37, flag2); _lastWPressed = flag2; if (_configManager.DebugOutput) { _logger.LogInfo((object)("W key " + (flag2 ? "pressed" : "released"))); } } if (flag3 != _lastAPressed) { _keyboardSimulator.SendKeyEvent((Key)15, flag3); _lastAPressed = flag3; if (_configManager.DebugOutput) { _logger.LogInfo((object)("A key " + (flag3 ? "pressed" : "released"))); } } if (flag4 != _lastSPressed) { _keyboardSimulator.SendKeyEvent((Key)33, flag4); _lastSPressed = flag4; if (_configManager.DebugOutput) { _logger.LogInfo((object)("S key " + (flag4 ? "pressed" : "released"))); } } if (flag5 != _lastDPressed) { _keyboardSimulator.SendKeyEvent((Key)18, flag5); _lastDPressed = flag5; if (_configManager.DebugOutput) { _logger.LogInfo((object)("D key " + (flag5 ? "pressed" : "released"))); } } } public void ReleaseAllDirectionKeys() { if (Keyboard.current != null) { if (_lastWPressed) { _keyboardSimulator.SendKeyEvent((Key)37, isPressed: false); } if (_lastAPressed) { _keyboardSimulator.SendKeyEvent((Key)15, isPressed: false); } if (_lastSPressed) { _keyboardSimulator.SendKeyEvent((Key)33, isPressed: false); } if (_lastDPressed) { _keyboardSimulator.SendKeyEvent((Key)18, isPressed: false); } _lastWPressed = false; _lastAPressed = false; _lastSPressed = false; _lastDPressed = false; } } } public class KeyboardSimulator { private readonly ManualLogSource _logger; private readonly ConfigManager _configManager; private bool _wPressed; private bool _aPressed; private bool _sPressed; private bool _dPressed; private bool _shiftPressed; private bool _ctrlToggled; private bool _tabToggled; public bool IsWPressed => _wPressed; public bool IsAPressed => _aPressed; public bool IsSPressed => _sPressed; public bool IsDPressed => _dPressed; public bool IsShiftPressed => _shiftPressed; public bool IsCtrlToggled => _ctrlToggled; public bool IsTabToggled => _tabToggled; public KeyboardSimulator(ManualLogSource logger, ConfigManager configManager) { _logger = logger; _configManager = configManager; } public void ToggleCtrl() { _ctrlToggled = !_ctrlToggled; SendKeyEvent((Key)55, _ctrlToggled); } public void ToggleTab() { _tabToggled = !_tabToggled; SendKeyEvent((Key)3, _tabToggled); } public void ToggleShift() { _shiftPressed = !_shiftPressed; SendKeyEvent((Key)51, _shiftPressed); } public void SendKeyEvent(Key key, bool isPressed) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) if (Keyboard.current != null) { UpdateKeyState(key, isPressed); KeyboardState val = default(KeyboardState); if (_wPressed) { ((KeyboardState)(ref val)).Set((Key)37, true); } if (_aPressed) { ((KeyboardState)(ref val)).Set((Key)15, true); } if (_sPressed) { ((KeyboardState)(ref val)).Set((Key)33, true); } if (_dPressed) { ((KeyboardState)(ref val)).Set((Key)18, true); } if (_shiftPressed) { ((KeyboardState)(ref val)).Set((Key)51, true); } if (_ctrlToggled) { ((KeyboardState)(ref val)).Set((Key)55, true); } if (_tabToggled) { ((KeyboardState)(ref val)).Set((Key)3, true); } ((KeyboardState)(ref val)).Set(key, isPressed); InputSystem.QueueStateEvent<KeyboardState>((InputDevice)(object)Keyboard.current, val, -1.0); if (_configManager.DebugOutput) { _logger.LogInfo((object)string.Format("Key {0} {1}", key, isPressed ? "pressed" : "released")); } } } private void UpdateKeyState(Key key, bool isPressed) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Invalid comparison between Unknown and I4 //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Invalid comparison between Unknown and I4 //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Invalid comparison between Unknown and I4 //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Invalid comparison between Unknown and I4 //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 if ((int)key <= 18) { if ((int)key != 3) { if ((int)key != 15) { if ((int)key == 18) { _dPressed = isPressed; } } else { _aPressed = isPressed; } } else { _tabToggled = isPressed; } } else if ((int)key <= 37) { if ((int)key != 33) { if ((int)key == 37) { _wPressed = isPressed; } } else { _sPressed = isPressed; } } else if ((int)key != 51) { if ((int)key == 55) { _ctrlToggled = isPressed; } } else { _shiftPressed = isPressed; } } public void ReleaseAllKeys() { try { if (Keyboard.current != null) { if (_wPressed) { SendKeyEvent((Key)37, isPressed: false); } if (_aPressed) { SendKeyEvent((Key)15, isPressed: false); } if (_sPressed) { SendKeyEvent((Key)33, isPressed: false); } if (_dPressed) { SendKeyEvent((Key)18, isPressed: false); } if (_shiftPressed) { SendKeyEvent((Key)51, isPressed: false); } if (_ctrlToggled) { SendKeyEvent((Key)55, isPressed: false); } if (_tabToggled) { SendKeyEvent((Key)3, isPressed: false); } SendKeyEvent((Key)1, isPressed: false); SendKeyEvent((Key)19, isPressed: false); SendKeyEvent((Key)31, isPressed: false); SendKeyEvent((Key)41, isPressed: false); SendKeyEvent((Key)42, isPressed: false); SendKeyEvent((Key)43, isPressed: false); SendKeyEvent((Key)60, isPressed: false); SendKeyEvent((Key)3, isPressed: false); } } catch (ArgumentNullException ex) { if (_configManager.DebugOutput) { _logger.LogError((object)("Error releasing keys: " + ex.Message)); } } } } internal class MenuNavigationManager { private const int MenuStateOpen = 0; private const float NavInitialDelay = 0.35f; private const float NavRepeatInterval = 0.12f; private const float RowYTolerance = 40f; private readonly ManualLogSource _logger; private readonly ConfigManager _configManager; private MenuSelectableElement _focusedElement; private MenuPage _currentPage; private readonly List<MenuSelectableElement> _elements = new List<MenuSelectableElement>(); private int _lastSourceElementCount = -1; private Vector2 _activeDirection; private float _nextRepeatTime; private bool _wasMenuActive; private int _focusedIndex = -1; private float _previousRightTrigger; public bool IsActive { get; private set; } public MenuSelectableElement FocusedElement => _focusedElement; public MenuNavigationManager(ManualLogSource logger, ConfigManager configManager) { _logger = logger; _configManager = configManager; } internal MenuButton GetFocusedMenuButton() { if (!((Object)(object)_focusedElement == (Object)null)) { return FindMenuButton(_focusedElement); } return null; } public bool TryGetForcedHover(RectTransform rectTransform, out bool hover) { hover = false; if (!IsActive || (Object)(object)_focusedElement == (Object)null || (Object)(object)rectTransform == (Object)null) { return false; } hover = IsFocusedRect(rectTransform); return true; } public bool TryGetSyntheticMousePosition(out Vector2 position) { //IL_0001: 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_003f: Unknown result type (might be due to invalid IL or missing references) position = default(Vector2); if (!IsActive || (Object)(object)_focusedElement == (Object)null) { return false; } RectTransform focusRectTransform = GetFocusRectTransform(_focusedElement); if ((Object)(object)focusRectTransform == (Object)null) { return false; } position = SemiFunc.UIGetRectTransformPositionOnScreen(focusRectTransform, false); return true; } public void Update() { UpdateMenuState(); } public void ProcessControllerInput(Gamepad gamepad, KeyboardSimulator keyboard, MouseSimulator mouse, VibrationManager vibration) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) if (IsActive) { if (!_wasMenuActive) { keyboard.ReleaseAllKeys(); mouse.ReleaseAllButtons(); } RefreshElements(); EnsureFocus(); Vector2 navInput = ReadNavig