Decompiled source of Emote Deck v2.0.3
plugins/Emote_Deck/Emote_Deck.dll
Decompiled a week ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; using UnityEngine.Events; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("Project too-many-emotes")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Project too-many-emotes")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("a36e8062-eaaf-433e-bd67-e49ec781b591")] [assembly: AssemblyFileVersion("2.0.3.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("2.0.3.0")] namespace ATLYSSEmoteDeck; [BepInPlugin("com.eleen.atlyss.emotedeck", "Emote Deck", "2.0.3")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInProcess("ATLYSS.exe")] [DefaultExecutionOrder(-9000)] public class EmoteDeckPlugin : BaseUnityPlugin { public const string PluginGuid = "com.eleen.atlyss.emotedeck"; public const string PluginName = "Emote Deck"; public const string PluginVersion = "2.0.3"; public const int MaxPages = 10; public const int MaxSlots = 100; internal static EmoteDeckPlugin Instance; internal static ManualLogSource Log; internal static ConfigEntry<string> CfgMainWindowKey; internal static ConfigEntry<string> CfgGridWindowKey; internal static ConfigEntry<float> CfgMainX; internal static ConfigEntry<float> CfgMainY; internal static ConfigEntry<float> CfgMainW; internal static ConfigEntry<float> CfgMainH; internal static ConfigEntry<float> CfgMainOpacity; internal static ConfigEntry<float> CfgGridX; internal static ConfigEntry<float> CfgGridY; internal static ConfigEntry<float> CfgGridW; internal static ConfigEntry<float> CfgGridH; internal static ConfigEntry<float> CfgGridOpacity; internal static ConfigEntry<int> CfgGridColumns; internal static ConfigEntry<float> CfgGridIconAspect; internal static ConfigEntry<bool> CfgGridAutoColumns; internal static ConfigEntry<bool> CfgGridAutoIconAspect; internal static ConfigEntry<bool> CfgCloseGridAfterEmote; internal static ConfigEntry<string> CfgGridViewMode; internal static ConfigEntry<string> CfgGridMouseMode; internal static ConfigEntry<bool> CfgGridShowHeaderControls; internal static ConfigEntry<int> CfgActiveSlotCount; internal static ConfigEntry<bool> CfgBlockGameInputWhileMainWindowOpen; internal static ConfigEntry<bool> CfgBlockGameInputWhileGridWindowOpen; internal static ConfigEntry<bool> CfgDebugLogging; internal static ConfigEntry<bool> CfgIncludeNativeVanillaWhenWheelBaseExists; internal static ConfigEntry<string> CfgHiddenPackages; internal static ConfigEntry<bool> CfgEnableChatCommands; internal static ConfigEntry<bool> CfgEnableNamedSlotCommands; internal static ConfigEntry<bool> CfgEnableClosestNameMatch; internal static ConfigEntry<bool> CfgClosestMatchIncludeCustomCommands; internal static ConfigEntry<bool> CfgEnableCustomChatPrefix; internal static ConfigEntry<string> CfgChatCommandPrefix; internal static ConfigEntry<bool> CfgEnableCustomSlotCommands; internal static ConfigEntry<string> CfgDeckSlotKeys; internal static ConfigEntry<string> CfgDeckCustomCommands; internal static ConfigEntry<bool> CfgMigratedCompactSlotStorage; internal static readonly ConfigEntry<string>[] CfgSlotCustomCommands = new ConfigEntry<string>[100]; internal static readonly ConfigEntry<string>[] CfgPageCustomCommands = new ConfigEntry<string>[10]; internal static ConfigEntry<bool> CfgEnablePages; internal static ConfigEntry<int> CfgPageCount; internal static ConfigEntry<int> CfgCurrentPage; internal static ConfigEntry<string>[] CfgPageSlotKeys = new ConfigEntry<string>[10]; internal static ConfigEntry<bool> CfgEnableRecent; internal static ConfigEntry<int> CfgRecentLimit; internal static ConfigEntry<string> CfgRecentKeys; internal static ConfigEntry<bool> CfgEnableFavorites; internal static ConfigEntry<string> CfgFavoriteKeys; internal static ConfigEntry<bool> CfgAutoRescanEnabled; internal static ConfigEntry<bool> CfgPickerAutoAdvanceSlot; internal static ConfigEntry<bool> CfgPickerHideAssigned; internal static ConfigEntry<bool> CfgMigratedAutoAdvanceDefaultOff; internal static ConfigEntry<bool> CfgSettingsDeckOpen; internal static ConfigEntry<bool> CfgSettingsSystemsOpen; internal static ConfigEntry<bool> CfgSettingsEmotesOpen; internal static ConfigEntry<bool> CfgSettingsChatOpen; internal static ConfigEntry<bool> CfgSettingsGridOpen; internal static ConfigEntry<bool> CfgSettingsPickerOpen; internal static ConfigEntry<bool> CfgSettingsKeybindsOpen; internal static ConfigEntry<bool> CfgSettingsAdvancedOpen; internal static readonly ConfigEntry<string>[] CfgSlotEmoteKeys = new ConfigEntry<string>[100]; private KeyCode _mainWindowKey = (KeyCode)121; private KeyCode _gridWindowKey = (KeyCode)116; private EmoteDeckWindow _window; private Harmony _harmony; private float _nextAutoRefreshTime; private bool _forceNextAutoRefresh; private bool _configSaveQueued; private float _configSaveAt; private readonly HashSet<KeyCode> _suppressedHotkeyActivations = new HashSet<KeyCode>(); private int _suppressHotkeysUntilFrame; internal readonly List<EmoteEntry> AllEmotes = new List<EmoteEntry>(); internal readonly Dictionary<string, EmoteEntry> EmotesByKey = new Dictionary<string, EmoteEntry>(StringComparer.OrdinalIgnoreCase); internal readonly List<string> PackageIds = new List<string>(); internal readonly HashSet<string> HiddenPackages = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal readonly string[][] PageSlotKeys = new string[10][]; internal readonly string[][] PageCustomCommands = new string[10][]; internal readonly List<string> RecentKeys = new List<string>(); internal readonly List<string> FavoriteKeys = new List<string>(); private int _lastRegistryFingerprint; private static FieldInfo _chatEmoteBufferField; internal bool EmoteWheelBridgeAvailable { get; private set; } internal int LastWheelEmoteCount { get; private set; } internal int LastNativeEmoteCount { get; private set; } internal float LastRegistryRefreshTime { get; private set; } internal int RegistryRevision { get; private set; } internal int FilterRevision { get; private set; } internal int SlotRevision { get; private set; } internal int RecentRevision { get; private set; } internal int FavoriteRevision { get; private set; } internal KeyCode MainWindowKey => _mainWindowKey; internal KeyCode GridWindowKey => _gridWindowKey; private void Awake() { Instance = this; Log = ((BaseUnityPlugin)this).Logger; BindConfig(); ReloadHotkeysFromConfig(); LoadHiddenPackagesFromConfig(); LoadPageSlotsFromConfig(); LoadCustomCommandsFromConfig(); LoadRecentAndFavoritesFromConfig(); RefreshEmoteRegistry(); ScheduleAutoRescan(1f, force: false); TryPatchHarmonyHooks(); _window = new EmoteDeckWindow(this); TrySetupEasySettingsBridge(); Log.LogInfo((object)("[EmoteDeck] Loaded 2.0.3 mainKey=" + ((object)Unsafe.As<KeyCode, KeyCode>(ref _mainWindowKey)/*cast due to .constrained prefix*/).ToString() + " gridKey=" + ((object)Unsafe.As<KeyCode, KeyCode>(ref _gridWindowKey)/*cast due to .constrained prefix*/).ToString() + " emotes=" + AllEmotes.Count)); } private void BindConfig() { CfgMainWindowKey = ((BaseUnityPlugin)this).Config.Bind<string>("Input", "MainWindowKey", "Y", "Open/close the Emote Deck main window. Set to None to disable the global main-window hotkey."); CfgGridWindowKey = ((BaseUnityPlugin)this).Config.Bind<string>("Input", "GridWindowKey", "T", "Open/close the Emote Grid window. Set to None to disable the global grid hotkey."); CfgMainX = ((BaseUnityPlugin)this).Config.Bind<float>("MainWindow", "X", 240f, "Main window X position."); CfgMainY = ((BaseUnityPlugin)this).Config.Bind<float>("MainWindow", "Y", 120f, "Main window Y position."); CfgMainW = ((BaseUnityPlugin)this).Config.Bind<float>("MainWindow", "Width", 620f, "Main window width."); CfgMainH = ((BaseUnityPlugin)this).Config.Bind<float>("MainWindow", "Height", 640f, "Main window height."); CfgMainOpacity = ((BaseUnityPlugin)this).Config.Bind<float>("MainWindow", "ContentOpacity", 0.92f, "Opacity for main window content/background below the header. 0 = transparent, 1 = opaque."); CfgGridX = ((BaseUnityPlugin)this).Config.Bind<float>("GridWindow", "X", 260f, "Grid window X position."); CfgGridY = ((BaseUnityPlugin)this).Config.Bind<float>("GridWindow", "Y", 160f, "Grid window Y position."); CfgGridW = ((BaseUnityPlugin)this).Config.Bind<float>("GridWindow", "Width", 720f, "Grid window width."); CfgGridH = ((BaseUnityPlugin)this).Config.Bind<float>("GridWindow", "Height", 480f, "Grid window height."); CfgGridOpacity = ((BaseUnityPlugin)this).Config.Bind<float>("GridWindow", "Opacity", 0.88f, "Grid window content/background opacity. 0 = transparent, 1 = opaque."); CfgGridColumns = ((BaseUnityPlugin)this).Config.Bind<int>("GridWindow", "Columns", 8, "Column count when AutoColumns is off."); CfgGridIconAspect = ((BaseUnityPlugin)this).Config.Bind<float>("GridWindow", "IconAspectRatio", 1f, "Icon width/height ratio when AutoIconAspectRatio is off. 1.0 = square, 1.3 = wider, 0.8 = taller."); CfgGridAutoColumns = ((BaseUnityPlugin)this).Config.Bind<bool>("GridWindow", "AutoColumns", true, "Choose columns from the current grid width. This prevents clipped columns and horizontal scrolling."); CfgGridAutoIconAspect = ((BaseUnityPlugin)this).Config.Bind<bool>("GridWindow", "AutoIconAspectRatio", true, "Use icon cells that scale with the grid width."); CfgCloseGridAfterEmote = ((BaseUnityPlugin)this).Config.Bind<bool>("GridWindow", "CloseAfterEmote", true, "Close the grid window after clicking an emote."); CfgGridViewMode = ((BaseUnityPlugin)this).Config.Bind<string>("GridWindow", "View", "Standard", "Grid view: Standard, Compact, Mini, or Names."); CfgGridViewMode.Value = NormalizeGridViewModeValue(CfgGridViewMode.Value); CfgGridMouseMode = ((BaseUnityPlugin)this).Config.Bind<string>("GridWindow", "MouseMode", "Auto", "Grid mouse mode: Auto, Always, or Off. Auto unlocks only when Close grid after emote is on."); CfgGridMouseMode.Value = NormalizeGridMouseModeValue(CfgGridMouseMode.Value); CfgGridShowHeaderControls = ((BaseUnityPlugin)this).Config.Bind<bool>("GridWindow", "ShowHeaderControls", true, "Show the second header row in the grid window."); CfgActiveSlotCount = ((BaseUnityPlugin)this).Config.Bind<int>("Behavior", "ActiveSlotCount", 24, "Number of slots shown on each deck page. Range 1-100."); CfgBlockGameInputWhileMainWindowOpen = ((BaseUnityPlugin)this).Config.Bind<bool>("Behavior", "BlockGameInputWhileMainWindowOpen", false, "Block player movement, combat, hotbar, and interact input while the main window is open."); CfgBlockGameInputWhileGridWindowOpen = ((BaseUnityPlugin)this).Config.Bind<bool>("Behavior", "BlockGameInputWhileGridWindowOpen", false, "Block player movement, combat, hotbar, and interact input while the grid window is open."); CfgIncludeNativeVanillaWhenWheelBaseExists = ((BaseUnityPlugin)this).Config.Bind<bool>("Behavior", "IncludeNativeVanillaWhenWheelBaseExists", false, "Show native /emote commands even when Emote Wheel Base is available. Keeping this off usually avoids duplicates."); CfgHiddenPackages = ((BaseUnityPlugin)this).Config.Bind<string>("Filters", "HiddenPackages", "", "Semicolon-separated package IDs hidden in Picker and Grid."); CfgEnableChatCommands = ((BaseUnityPlugin)this).Config.Bind<bool>("ChatCommands", "EnableChatCommands", true, "Allow commands like /ed 1 to play deck slots."); CfgEnableNamedSlotCommands = ((BaseUnityPlugin)this).Config.Bind<bool>("ChatCommands", "EnableNamedSlotCommands", true, "Allow /ed commands that use emote names, like /ed point or /ed fist bump."); CfgEnableClosestNameMatch = ((BaseUnityPlugin)this).Config.Bind<bool>("ChatCommands", "EnableClosestNameMatch", false, "If an /ed name command is close enough, play the nearest matching emote."); CfgClosestMatchIncludeCustomCommands = ((BaseUnityPlugin)this).Config.Bind<bool>("ChatCommands", "ClosestMatchIncludeCustomCommands", false, "Let closest match also check custom slot commands."); CfgEnableCustomChatPrefix = ((BaseUnityPlugin)this).Config.Bind<bool>("ChatCommands", "EnableCustomPrefix", false, "Allow the /ed command prefix to be changed."); CfgChatCommandPrefix = ((BaseUnityPlugin)this).Config.Bind<string>("ChatCommands", "CommandPrefix", "/ed", "Prefix used for Emote Deck chat commands."); CfgChatCommandPrefix.Value = NormalizeChatCommandPrefix(CfgChatCommandPrefix.Value); CfgEnableCustomSlotCommands = ((BaseUnityPlugin)this).Config.Bind<bool>("ChatCommands", "EnableCustomSlotCommands", false, "Allow direct custom commands like /pnt. These can overlap with other slash commands."); CfgEnablePages = ((BaseUnityPlugin)this).Config.Bind<bool>("Pages", "EnablePages", false, "Enable separate Emote Deck pages."); CfgPageCount = ((BaseUnityPlugin)this).Config.Bind<int>("Pages", "PageCount", 4, "Number of deck pages when pages are enabled. Range 1-10."); CfgCurrentPage = ((BaseUnityPlugin)this).Config.Bind<int>("Pages", "CurrentPage", 1, "Current deck page. Range 1-10."); for (int i = 1; i < 10; i++) { CfgPageSlotKeys[i] = ((BaseUnityPlugin)this).Config.Bind<string>("Pages", "Page" + (i + 1).ToString("D2", CultureInfo.InvariantCulture) + "Slots", "", "Packed slot keys for page " + (i + 1) + "."); CfgPageCustomCommands[i] = ((BaseUnityPlugin)this).Config.Bind<string>("CustomCommands", "Page" + (i + 1).ToString("D2", CultureInfo.InvariantCulture) + "Commands", "", "Packed custom chat commands for page " + (i + 1) + "."); } CfgEnableRecent = ((BaseUnityPlugin)this).Config.Bind<bool>("Recent", "EnableRecent", false, "Show a Recent grid mode."); CfgRecentLimit = ((BaseUnityPlugin)this).Config.Bind<int>("Recent", "RecentLimit", 24, "Maximum recent emotes to keep. Range 1-100."); CfgRecentKeys = ((BaseUnityPlugin)this).Config.Bind<string>("Recent", "RecentKeys", "", "Packed recent emote keys."); CfgEnableFavorites = ((BaseUnityPlugin)this).Config.Bind<bool>("Favorites", "EnableFavorites", false, "Show a Favorites grid mode and star buttons."); CfgFavoriteKeys = ((BaseUnityPlugin)this).Config.Bind<string>("Favorites", "FavoriteKeys", "", "Packed favorite emote keys."); CfgAutoRescanEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Behavior", "AutoRescan", true, "Rescan after windows open so newly loaded emotes can appear."); CfgPickerAutoAdvanceSlot = ((BaseUnityPlugin)this).Config.Bind<bool>("Behavior", "PickerAutoAdvanceSlot", false, "After setting an emote in Picker, move to the next slot."); CfgPickerHideAssigned = ((BaseUnityPlugin)this).Config.Bind<bool>("Behavior", "PickerHideAssigned", false, "Hide emotes already assigned on any enabled page."); CfgMigratedAutoAdvanceDefaultOff = ((BaseUnityPlugin)this).Config.Bind<bool>("Migrations", "AutoAdvanceDefaultOff_0110", false, "Internal migration flag. Do not edit."); if (!CfgMigratedAutoAdvanceDefaultOff.Value) { CfgPickerAutoAdvanceSlot.Value = false; CfgMigratedAutoAdvanceDefaultOff.Value = true; } CfgDebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugLogging", false, "Enable debug logs."); CfgSettingsDeckOpen = ((BaseUnityPlugin)this).Config.Bind<bool>("SettingsUI", "DeckOpen", true, "Show the Deck settings section."); CfgSettingsSystemsOpen = ((BaseUnityPlugin)this).Config.Bind<bool>("SettingsUI", "SystemsOpen", true, "Show the Pages/Recent/Favorites settings section."); CfgSettingsEmotesOpen = ((BaseUnityPlugin)this).Config.Bind<bool>("SettingsUI", "EmotesOpen", true, "Show the Emotes and pack filters settings section."); CfgSettingsChatOpen = ((BaseUnityPlugin)this).Config.Bind<bool>("SettingsUI", "ChatOpen", true, "Show the Chat commands settings section."); CfgSettingsGridOpen = ((BaseUnityPlugin)this).Config.Bind<bool>("SettingsUI", "GridOpen", true, "Show the Grid settings section."); CfgSettingsPickerOpen = ((BaseUnityPlugin)this).Config.Bind<bool>("SettingsUI", "PickerOpen", true, "Show the Picker settings section."); CfgSettingsKeybindsOpen = ((BaseUnityPlugin)this).Config.Bind<bool>("SettingsUI", "KeybindsOpen", true, "Show the Keybinds settings section."); CfgSettingsAdvancedOpen = ((BaseUnityPlugin)this).Config.Bind<bool>("SettingsUI", "AdvancedOpen", true, "Show the Advanced settings section."); CfgDeckSlotKeys = ((BaseUnityPlugin)this).Config.Bind<string>("Deck", "Page01Slots", DefaultPageOneSlots(), "Packed slot keys for page 1. Semicolon-separated. Empty trailing slots are omitted."); CfgDeckCustomCommands = ((BaseUnityPlugin)this).Config.Bind<string>("Deck", "Page01Commands", "", "Packed custom slot commands for page 1. Semicolon-separated. Empty trailing slots are omitted."); CfgMigratedCompactSlotStorage = ((BaseUnityPlugin)this).Config.Bind<bool>("Migrations", "CompactSlotStorage_0201", false, "Internal migration flag. Do not edit."); MigrateLegacySlotConfigIfNeeded(); } private static string DefaultPageOneSlots() { return "Base:Point;Base:Clap;Base:Think;Base:Shrug;Base:Dance;Base:Taunt"; } private void MigrateLegacySlotConfigIfNeeded() { string[] array = new string[100]; string[] array2 = new string[100]; UnpackConfigList((CfgDeckSlotKeys != null) ? CfgDeckSlotKeys.Value : DefaultPageOneSlots(), array); UnpackConfigList((CfgDeckCustomCommands != null) ? CfgDeckCustomCommands.Value : string.Empty, array2); bool flag = false; bool flag2 = false; for (int i = 0; i < 100; i++) { string key = "Slot" + (i + 1).ToString("D3", CultureInfo.InvariantCulture); if (TryGetRawConfigValue("Slots", key, out var value)) { array[i] = value ?? string.Empty; flag = true; if (!string.IsNullOrEmpty(array[i])) { flag2 = true; } } if (TryGetRawConfigValue("CustomCommands", key, out var value2)) { array2[i] = (TryNormalizeCustomSlotCommand(value2, out var normalized, out var _) ? normalized : string.Empty); flag = true; if (!string.IsNullOrEmpty(array2[i])) { flag2 = true; } } } if (flag) { BackupLegacyConfigFileIfNeeded(); if (CfgDeckSlotKeys != null) { CfgDeckSlotKeys.Value = PackConfigList(array); } if (CfgDeckCustomCommands != null) { CfgDeckCustomCommands.Value = PackConfigList(array2); } RemoveLegacySlotConfigEntries(); if (CfgMigratedCompactSlotStorage != null) { CfgMigratedCompactSlotStorage.Value = true; } SavePluginConfig(); if (flag2 && Log != null) { Log.LogInfo((object)"[EmoteDeck] Legacy slot config migrated into compact storage."); } } else if (CfgMigratedCompactSlotStorage != null && !CfgMigratedCompactSlotStorage.Value) { CfgMigratedCompactSlotStorage.Value = true; SavePluginConfig(); } } private bool TryGetRawConfigValue(string section, string key, out string value) { value = null; if (TryGetRawConfigValueFromLoadedConfig(section, key, out value)) { return true; } if (TryGetRawConfigValueFromFile(section, key, out value)) { return true; } return false; } private bool TryGetRawConfigValueFromLoadedConfig(string section, string key, out string value) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown value = null; try { ConfigDefinition val = new ConfigDefinition(section, key); PropertyInfo property = typeof(ConfigFile).GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null) { object value2 = property.GetValue(((BaseUnityPlugin)this).Config, null); if (value2 is IDictionary dictionary) { if (dictionary.Contains(val)) { object obj = dictionary[val]; value = ((obj != null) ? obj.ToString() : string.Empty); return true; } foreach (DictionaryEntry item in dictionary) { if (ConfigDefinitionMatches(item.Key, section, key)) { object value3 = item.Value; value = ((value3 != null) ? value3.ToString() : string.Empty); return true; } } } } MethodInfo method = typeof(ConfigFile).GetMethod("TryGetEntry", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method != null) { object[] array = new object[2] { val, null }; object obj2 = method.Invoke(((BaseUnityPlugin)this).Config, array); if (obj2 is bool && (bool)obj2 && array.Length > 1 && array[1] != null) { object obj3 = array[1]; PropertyInfo property2 = obj3.GetType().GetProperty("BoxedValue", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); object obj4 = ((property2 != null) ? property2.GetValue(obj3, null) : obj3); value = ((obj4 != null) ? obj4.ToString() : string.Empty); return true; } } } catch { } return false; } private static bool ConfigDefinitionMatches(object definition, string section, string key) { if (definition == null) { return false; } try { ConfigDefinition val = (ConfigDefinition)((definition is ConfigDefinition) ? definition : null); if (val != (ConfigDefinition)null) { return string.Equals(val.Section, section, StringComparison.OrdinalIgnoreCase) && string.Equals(val.Key, key, StringComparison.OrdinalIgnoreCase); } Type type = definition.GetType(); PropertyInfo property = type.GetProperty("Section", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); PropertyInfo property2 = type.GetProperty("Key", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); string a = ((property != null) ? (property.GetValue(definition, null) as string) : null); string a2 = ((property2 != null) ? (property2.GetValue(definition, null) as string) : null); return string.Equals(a, section, StringComparison.OrdinalIgnoreCase) && string.Equals(a2, key, StringComparison.OrdinalIgnoreCase); } catch { } return false; } private bool TryGetRawConfigValueFromFile(string section, string key, out string value) { value = null; try { string configFilePath = GetConfigFilePath(); if (string.IsNullOrEmpty(configFilePath) || !File.Exists(configFilePath)) { return false; } string a = string.Empty; string[] array = File.ReadAllLines(configFilePath); for (int i = 0; i < array.Length; i++) { string text = array[i] ?? string.Empty; string text2 = text.Trim(); if (text2.Length == 0 || text2.StartsWith("#")) { continue; } if (text2.StartsWith("[") && text2.EndsWith("]") && text2.Length >= 2) { a = text2.Substring(1, text2.Length - 2).Trim(); } else { if (!string.Equals(a, section, StringComparison.OrdinalIgnoreCase)) { continue; } int num = text.IndexOf('='); if (num >= 0) { string a2 = text.Substring(0, num).Trim(); if (string.Equals(a2, key, StringComparison.OrdinalIgnoreCase)) { value = text.Substring(num + 1).Trim(); return true; } } } } } catch { } return false; } private static string GetConfigFilePath() { try { string text = Path.Combine(Paths.ConfigPath, "com.eleen.atlyss.emotedeck.cfg"); if (!string.IsNullOrEmpty(text)) { return text; } } catch { } return null; } private void BackupLegacyConfigFileIfNeeded() { try { string configFilePath = GetConfigFilePath(); if (!string.IsNullOrEmpty(configFilePath) && File.Exists(configFilePath)) { string text = configFilePath + ".legacy-slot-backup"; if (!File.Exists(text)) { File.Copy(configFilePath, text, overwrite: false); } } } catch { } } private void RemoveLegacySlotConfigEntries() { for (int i = 0; i < 100; i++) { string key = "Slot" + (i + 1).ToString("D3", CultureInfo.InvariantCulture); RemoveConfigEntryIfPresent("Slots", key); RemoveConfigEntryIfPresent("CustomCommands", key); } } private void RemoveConfigEntryIfPresent(string section, string key) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Expected O, but got Unknown try { ConfigDefinition val = new ConfigDefinition(section, key); bool flag = false; MethodInfo method = typeof(ConfigFile).GetMethod("Remove", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(ConfigDefinition) }, null); if (method != null) { object obj = method.Invoke(((BaseUnityPlugin)this).Config, new object[1] { val }); flag = !(obj is bool) || (bool)obj; } PropertyInfo property = typeof(ConfigFile).GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null) { object value = property.GetValue(((BaseUnityPlugin)this).Config, null); if (value is IDictionary dictionary) { if (dictionary.Contains(val)) { dictionary.Remove(val); flag = true; } else { ArrayList arrayList = new ArrayList(); foreach (DictionaryEntry item in dictionary) { if (ConfigDefinitionMatches(item.Key, section, key)) { arrayList.Add(item.Key); } } for (int i = 0; i < arrayList.Count; i++) { dictionary.Remove(arrayList[i]); flag = true; } } } } if (flag) { } } catch { } } private static void UnpackConfigList(string raw, string[] target) { if (target != null) { for (int i = 0; i < target.Length; i++) { target[i] = string.Empty; } string[] array = SplitConfigList(raw); int num = Math.Min(target.Length, array.Length); for (int j = 0; j < num; j++) { target[j] = array[j] ?? string.Empty; } } } private static string[] SplitConfigList(string raw) { if (string.IsNullOrEmpty(raw)) { return new string[0]; } return raw.Split(new char[1] { ';' }, StringSplitOptions.None); } private static string PackConfigList(string[] values) { if (values == null || values.Length == 0) { return string.Empty; } int num = -1; for (int num2 = values.Length - 1; num2 >= 0; num2--) { if (!string.IsNullOrEmpty(values[num2])) { num = num2; break; } } if (num < 0) { return string.Empty; } string[] array = new string[num + 1]; for (int i = 0; i <= num; i++) { array[i] = values[i] ?? string.Empty; } return string.Join(";", array); } internal static string NormalizeGridViewModeValue(string value) { if (string.IsNullOrEmpty(value)) { return "Standard"; } if (string.Equals(value, "Standard", StringComparison.OrdinalIgnoreCase)) { return "Standard"; } if (string.Equals(value, "Compact", StringComparison.OrdinalIgnoreCase)) { return "Compact"; } if (string.Equals(value, "Mini", StringComparison.OrdinalIgnoreCase)) { return "Mini"; } if (string.Equals(value, "Names", StringComparison.OrdinalIgnoreCase)) { return "Names"; } if (string.Equals(value, "Names only", StringComparison.OrdinalIgnoreCase)) { return "Names"; } return "Standard"; } internal static string GridViewModeLabel(string value) { value = NormalizeGridViewModeValue(value); if (value == "Names") { return "Names only"; } return value; } internal static string NormalizeGridMouseModeValue(string value) { if (string.IsNullOrEmpty(value)) { return "Auto"; } if (string.Equals(value, "Auto", StringComparison.OrdinalIgnoreCase)) { return "Auto"; } if (string.Equals(value, "Always", StringComparison.OrdinalIgnoreCase)) { return "Always"; } if (string.Equals(value, "Off", StringComparison.OrdinalIgnoreCase)) { return "Off"; } if (string.Equals(value, "Never", StringComparison.OrdinalIgnoreCase)) { return "Off"; } return "Auto"; } internal static string GridMouseModeLabel(string value) { return NormalizeGridMouseModeValue(value); } internal static string NormalizeChatCommandPrefix(string value) { string text = (value ?? string.Empty).Trim(); if (text.Length == 0) { return "/ed"; } if (!text.StartsWith("/")) { text = "/" + text; } int num = text.IndexOf(' '); if (num >= 0) { text = text.Substring(0, num); } text = text.Replace("<", string.Empty).Replace(">", string.Empty).Replace("\\0", string.Empty); if (text.Length < 2) { return "/ed"; } if (text.Length > 24) { text = text.Substring(0, 24); } return text; } internal static string GetActiveChatCommandPrefix() { if (CfgEnableCustomChatPrefix != null && CfgEnableCustomChatPrefix.Value) { return NormalizeChatCommandPrefix((CfgChatCommandPrefix != null) ? CfgChatCommandPrefix.Value : "/ed"); } return "/ed"; } internal static bool TryNormalizeCustomSlotCommand(string value, out string normalized, out string error) { normalized = string.Empty; error = null; string text = (value ?? string.Empty).Trim(); if (text.Length == 0) { return true; } if (!text.StartsWith("/")) { text = "/" + text; } if (text.Length < 2) { error = "Command is too short."; return false; } if (text.Length > 32) { error = "Command is too long."; return false; } if (text.IndexOfAny(new char[4] { ' ', '\t', '\r', '\n' }) >= 0) { error = "Use one command word only."; return false; } if (text.IndexOf('<') >= 0 || text.IndexOf('>') >= 0) { error = "Rich text characters are not allowed."; return false; } string activeChatCommandPrefix = GetActiveChatCommandPrefix(); if (string.Equals(text, "/ed", StringComparison.OrdinalIgnoreCase) || string.Equals(text, activeChatCommandPrefix, StringComparison.OrdinalIgnoreCase)) { error = "That command is already used by the slot command prefix."; return false; } normalized = text; return true; } internal static bool IsBlockedMouseBindKey(KeyCode key) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 return (int)key == 323 || (int)key == 324; } internal static string KeyLabel(string value) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(value)) { return "None"; } if (!Enum.TryParse<KeyCode>(value, ignoreCase: true, out KeyCode result)) { return value; } return KeyLabel(result); } internal unsafe static string KeyLabel(KeyCode key) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Invalid comparison between Unknown and I4 //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Invalid comparison between Unknown and I4 //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Invalid comparison between Unknown and I4 //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Invalid comparison between Unknown and I4 //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Invalid comparison between Unknown and I4 //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Invalid comparison between Unknown and I4 if ((int)key == 0) { return "None"; } if ((int)key == 323) { return "Left Mouse"; } if ((int)key == 324) { return "Right Mouse"; } if ((int)key == 325) { return "Middle Mouse"; } if ((int)key == 326) { return "Mouse 4"; } if ((int)key == 327) { return "Mouse 5"; } if ((int)key == 328) { return "Mouse 6"; } if ((int)key == 329) { return "Mouse 7"; } return ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString(); } internal void SavePluginConfig() { try { _configSaveQueued = false; ((BaseUnityPlugin)this).Config.Save(); } catch (Exception ex) { Log.LogWarning((object)("[EmoteDeck] Config save failed: " + ex.Message)); } } internal void QueueConfigSave(float delaySeconds) { if (delaySeconds < 0.05f) { delaySeconds = 0.05f; } _configSaveQueued = true; _configSaveAt = Time.unscaledTime + delaySeconds; } internal void QueueConfigSave() { QueueConfigSave(0.6f); } internal void ScheduleAutoRescan(float delaySeconds, bool force) { if (CfgAutoRescanEnabled != null && CfgAutoRescanEnabled.Value) { if (delaySeconds < 0.05f) { delaySeconds = 0.05f; } float num = Time.unscaledTime + delaySeconds; if (_nextAutoRefreshTime <= 0f || num < _nextAutoRefreshTime) { _nextAutoRefreshTime = num; } if (force) { _forceNextAutoRefresh = true; } } } private void FlushQueuedConfigSaveIfDue() { if (_configSaveQueued && Time.unscaledTime >= _configSaveAt) { SavePluginConfig(); } } private void OnDestroy() { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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_0014: Unknown result type (might be due to invalid IL or missing references) EmoteDeckInputBlocker.SetWindowState(mainOpen: false, default(Rect), gridOpen: false, default(Rect), blockGameplayInput: false); try { if (_harmony != null) { _harmony.UnpatchSelf(); _harmony = null; } } catch { } if (_window != null) { _window.SaveOpenWindowRects(); } if (_configSaveQueued) { SavePluginConfig(); } } private void TryPatchHarmonyHooks() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown try { if (_harmony == null) { _harmony = new Harmony("com.eleen.atlyss.emotedeck"); } } catch (Exception ex) { Log.LogWarning((object)("[EmoteDeck] Harmony init failed. Guards were skipped: " + ex.Message)); return; } TryPatchScrollRectOnScroll(); TryPatchGuiWindowPointerGuard(); TryPatchUiRaycastGuards(); TryPatchChatCommandGuard(); TryPatchGameplayInputGuards(); } private void TryPatchChatCommandGuard() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown try { if (_harmony == null) { _harmony = new Harmony("com.eleen.atlyss.emotedeck"); } MethodInfo methodInfo = AccessTools.Method(typeof(ChatBehaviour), "Cmd_SendChatMessage", new Type[2] { typeof(string), typeof(ChatChannel) }, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(EmoteDeckChatCommandPatch), "Prefix", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null) { Log.LogWarning((object)"[EmoteDeck] Chat command guard skipped: method lookup failed."); return; } _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)"[EmoteDeck] Chat command guard patched."); } catch (Exception ex) { Log.LogWarning((object)("[EmoteDeck] Chat command guard failed and was skipped: " + ex.Message)); } } private void TryPatchScrollRectOnScroll() { //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Expected O, but got Unknown try { Type type = FindType("UnityEngine.UI.ScrollRect"); Type type2 = FindType("UnityEngine.EventSystems.PointerEventData"); if (type == null || type2 == null) { Log.LogWarning((object)"[EmoteDeck] ScrollRect.OnScroll guard skipped: Unity UI/EventSystems types were not found."); return; } MethodInfo methodInfo = AccessTools.Method(type, "OnScroll", new Type[1] { type2 }, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(EmoteDeckScrollRectOnScrollPatch), "Prefix", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null) { Log.LogWarning((object)"[EmoteDeck] ScrollRect.OnScroll guard skipped: method lookup failed."); return; } _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)"[EmoteDeck] ScrollRect.OnScroll guard patched."); } catch (Exception ex) { Log.LogWarning((object)("[EmoteDeck] ScrollRect.OnScroll guard failed and was skipped: " + ex.Message)); } } private void TryPatchGuiWindowPointerGuard() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Expected O, but got Unknown try { if (_harmony == null) { _harmony = new Harmony("com.eleen.atlyss.emotedeck"); } MethodInfo methodInfo = AccessTools.Method(typeof(EmoteDeckGuiWindowPointerPatch), "Prefix", (Type[])null, (Type[])null); if (methodInfo == null) { Log.LogWarning((object)"[EmoteDeck] GUI.Window pointer guard skipped: prefix lookup failed."); return; } int num = 0; MethodInfo[] methods = typeof(GUI).GetMethods(BindingFlags.Static | BindingFlags.Public); foreach (MethodInfo methodInfo2 in methods) { if (!(methodInfo2 == null) && !(methodInfo2.Name != "Window") && !(methodInfo2.ReturnType != typeof(Rect))) { ParameterInfo[] parameters = methodInfo2.GetParameters(); if (parameters.Length >= 2 && !(parameters[0].ParameterType != typeof(int)) && !(parameters[1].ParameterType != typeof(Rect))) { _harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); num++; } } } Log.LogInfo((object)("[EmoteDeck] GUI.Window pointer guards patched: " + num + ".")); } catch (Exception ex) { Log.LogWarning((object)("[EmoteDeck] GUI.Window pointer guard failed and was skipped: " + ex.Message)); } } private void TryPatchUiRaycastGuards() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Expected O, but got Unknown try { if (_harmony == null) { _harmony = new Harmony("com.eleen.atlyss.emotedeck"); } Type type = FindType("UnityEngine.EventSystems.EventSystem"); Type type2 = FindType("UnityEngine.EventSystems.PointerEventData"); Type type3 = FindType("UnityEngine.EventSystems.RaycastResult"); if (type == null || type2 == null || type3 == null) { Log.LogWarning((object)"[EmoteDeck] EventSystem.RaycastAll guard skipped: EventSystem types were not found."); return; } Type type4 = typeof(List<>).MakeGenericType(type3); MethodInfo methodInfo = AccessTools.Method(type, "RaycastAll", new Type[2] { type2, type4 }, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(EmoteDeckEventSystemRaycastAllPatch), "Postfix", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null) { Log.LogWarning((object)"[EmoteDeck] EventSystem.RaycastAll guard skipped: method lookup failed."); return; } _harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)"[EmoteDeck] EventSystem.RaycastAll pointer guard patched."); } catch (Exception ex) { Log.LogWarning((object)("[EmoteDeck] EventSystem.RaycastAll guard failed and was skipped: " + ex.Message)); } } private void TryPatchGameplayInputGuards() { //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Expected O, but got Unknown try { int patched = 0; MethodInfo prefix = AccessTools.Method(typeof(EmoteDeckGameplayInputPatch), "Prefix", (Type[])null, (Type[])null); MethodInfo methodInfo = AccessTools.Method(typeof(EmoteDeckPlayerLocalParamsPatch), "Postfix", (Type[])null, (Type[])null); TryPatchPrefix(typeof(PlayerMove), "Handle_MovementControl", prefix, ref patched); TryPatchPrefix(typeof(PlayerMove), "Handle_DashControl", prefix, ref patched); TryPatchPrefix(typeof(PlayerMove), "Handle_JumpControl", prefix, ref patched); TryPatchPrefix(typeof(PlayerCasting), "Client_SkillControl", prefix, ref patched); TryPatchPrefix(typeof(ActionBarManager), "OnActionkeyPress", prefix, ref patched); TryPatchPrefix(typeof(PlayerCombat), "Client_Handle_WeaponSheatheControl", prefix, ref patched); TryPatchPrefix(typeof(PlayerCombat), "Client_Handle_QuickSwapWeaponControl", prefix, ref patched); TryPatchPrefix(typeof(PlayerCombat), "Client_Handle_CombatControl", prefix, ref patched); TryPatchPrefix(typeof(PlayerInteract), "Handle_InteractControl", prefix, ref patched); MethodInfo methodInfo2 = FindPlayerLocalParamsMethod(); if (methodInfo2 != null && methodInfo != null) { _harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); patched++; } else { Log.LogWarning((object)"[EmoteDeck] Player._inUI postfix guard skipped: method lookup failed."); } Log.LogInfo((object)("[EmoteDeck] Gameplay input guards patched: " + patched + ".")); } catch (Exception ex) { Log.LogWarning((object)("[EmoteDeck] Gameplay input guard patch failed and was skipped: " + ex.Message)); } } private void TryPatchPrefix(Type type, string methodName, MethodInfo prefix, ref int patched) { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown try { if (!(type == null) && !(prefix == null)) { MethodInfo methodInfo = AccessTools.Method(type, methodName, (Type[])null, (Type[])null); if (methodInfo == null) { Log.LogWarning((object)("[EmoteDeck] Input guard skipped: " + type.Name + "." + methodName + " not found.")); } else { _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(prefix), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); patched++; } } } catch (Exception ex) { Log.LogWarning((object)("[EmoteDeck] Input guard failed: " + type.Name + "." + methodName + ": " + ex.Message)); } } private static MethodInfo FindPlayerLocalParamsMethod() { try { MethodInfo[] methods = typeof(Player).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (!(methodInfo == null)) { string text = methodInfo.Name ?? string.Empty; if (text.IndexOf("Handle_LocalParams", StringComparison.Ordinal) >= 0) { return methodInfo; } } } } catch { } return null; } internal void ReloadHotkeysFromConfig() { //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_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) _mainWindowKey = ParseOptionalKeyCode(CfgMainWindowKey.Value, "MainWindowKey"); _gridWindowKey = ParseOptionalKeyCode(CfgGridWindowKey.Value, "GridWindowKey"); } private void TrySetupEasySettingsBridge() { EmoteDeckEasySettingsBridge.TryInstall(this); ((MonoBehaviour)this).StartCoroutine(EmoteDeckEasySettingsBridge.DelayedInstall(this)); } internal unsafe void SetMainWindowKeyFromEasySettings(KeyCode key) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) if (IsBlockedMouseBindKey(key)) { EmoteDeckEasySettingsBridge.ResetMainKeyButton(this); return; } CfgMainWindowKey.Value = (((int)key == 0) ? "None" : ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString()); ReloadHotkeysFromConfig(); EmoteDeckEasySettingsBridge.SyncButtonsFromConfig(this); SuppressHotkeyActivationUntilReleased(key); QueueConfigSave(0.15f); } internal unsafe void SetGridWindowKeyFromEasySettings(KeyCode key) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) if (IsBlockedMouseBindKey(key)) { EmoteDeckEasySettingsBridge.ResetGridKeyButton(this); return; } CfgGridWindowKey.Value = (((int)key == 0) ? "None" : ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString()); ReloadHotkeysFromConfig(); EmoteDeckEasySettingsBridge.SyncButtonsFromConfig(this); SuppressHotkeyActivationUntilReleased(key); QueueConfigSave(0.15f); } internal unsafe static KeyCode ParseRequiredKeyCode(string value, KeyCode fallback, string name) { //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) if (!string.IsNullOrWhiteSpace(value) && Enum.TryParse<KeyCode>(value, ignoreCase: true, out KeyCode result) && (int)result != 0 && !IsBlockedMouseBindKey(result)) { return result; } if (Log != null) { Log.LogWarning((object)("[EmoteDeck] Invalid or disabled required key " + name + "='" + value + "'. Falling back to " + ((object)(*(KeyCode*)(&fallback))/*cast due to .constrained prefix*/).ToString() + ".")); } return fallback; } internal static KeyCode ParseOptionalKeyCode(string value, string name) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0087: 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_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrWhiteSpace(value) || string.Equals(value, "None", StringComparison.OrdinalIgnoreCase)) { return (KeyCode)0; } if (Enum.TryParse<KeyCode>(value, ignoreCase: true, out KeyCode result) && !IsBlockedMouseBindKey(result)) { return result; } if (Log != null) { Log.LogWarning((object)("[EmoteDeck] Invalid optional key " + name + "='" + value + "'. Disabling it.")); } return (KeyCode)0; } internal void SuppressHotkeyActivationUntilReleased(KeyCode key) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_000b: 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) if ((int)key != 0 && !IsBlockedMouseBindKey(key)) { _suppressedHotkeyActivations.Add(key); int num = Time.frameCount + 2; if (num > _suppressHotkeysUntilFrame) { _suppressHotkeysUntilFrame = num; } } } private void UpdateSuppressedHotkeyActivations() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_006e: 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) if (_suppressedHotkeyActivations.Count == 0 || Time.frameCount <= _suppressHotkeysUntilFrame) { return; } List<KeyCode> list = null; foreach (KeyCode suppressedHotkeyActivation in _suppressedHotkeyActivations) { if (!IsKeyCurrentlyHeld(suppressedHotkeyActivation)) { if (list == null) { list = new List<KeyCode>(); } list.Add(suppressedHotkeyActivation); } } if (list != null) { for (int i = 0; i < list.Count; i++) { _suppressedHotkeyActivations.Remove(list[i]); } } } private bool IsHotkeyActivationSuppressed(KeyCode key) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_0013: Unknown result type (might be due to invalid IL or missing references) if ((int)key == 0) { return false; } return _suppressedHotkeyActivations.Contains(key); } private static bool IsKeyCurrentlyHeld(KeyCode key) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_000f: Unknown result type (might be due to invalid IL or missing references) if ((int)key == 0) { return false; } try { return Input.GetKey(key); } catch { return false; } } private void Update() { //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) if (_window == null) { return; } UpdateSuppressedHotkeyActivations(); EmoteDeckEasySettingsBridge.PollSync(this); if (_window.IsCapturingKeyBind) { return; } if (CfgAutoRescanEnabled.Value && _nextAutoRefreshTime > 0f && Time.unscaledTime >= _nextAutoRefreshTime) { bool flag = _window.IsMainOpen || _window.IsGridOpen; bool flag2 = _forceNextAutoRefresh || AllEmotes.Count == 0; _forceNextAutoRefresh = false; if (flag2 || flag) { if (flag2) { RefreshEmoteRegistry(); } else { RefreshEmoteRegistryIfChanged(); } _nextAutoRefreshTime = (flag ? (Time.unscaledTime + ((AllEmotes.Count == 0) ? 3f : 10f)) : 0f); } else { _nextAutoRefreshTime = 0f; } } if (!IsChatTyping()) { if ((int)_mainWindowKey != 0 && Input.GetKeyDown(_mainWindowKey) && !IsHotkeyActivationSuppressed(_mainWindowKey)) { _window.ToggleMainWindow(); return; } if ((int)_gridWindowKey != 0 && _gridWindowKey != _mainWindowKey && Input.GetKeyDown(_gridWindowKey) && !IsHotkeyActivationSuppressed(_gridWindowKey)) { _window.ToggleGridWindow(); return; } } FlushQueuedConfigSaveIfDue(); } private void LateUpdate() { if (_window != null) { _window.MaintainInputState(); } } private void OnGUI() { if (_window != null) { _window.OnGUI(); } } internal int GetActiveSlotCount() { int num = CfgActiveSlotCount.Value; if (num < 1) { num = 1; } if (num > 100) { num = 100; } return num; } internal int GetPageCount() { int num = CfgPageCount.Value; if (num < 1) { num = 1; } if (num > 10) { num = 10; } return num; } internal int GetCurrentPageIndex() { if (!CfgEnablePages.Value) { return 0; } int pageCount = GetPageCount(); int num = CfgCurrentPage.Value - 1; if (num < 0) { num = 0; } if (num >= pageCount) { num = pageCount - 1; } return num; } internal int GetEffectiveDeckPageCount() { return (!CfgEnablePages.Value) ? 1 : GetPageCount(); } internal int GetTotalDeckSlotCapacity() { return GetActiveSlotCount() * GetEffectiveDeckPageCount(); } internal string GetSlotKeyForPage(int pageIndex, int index) { if (index < 0 || index >= 100) { return string.Empty; } if (!CfgEnablePages.Value || pageIndex <= 0) { pageIndex = 0; } if (pageIndex >= 10) { return string.Empty; } EnsurePageSlotArray(pageIndex); return PageSlotKeys[pageIndex][index] ?? string.Empty; } internal int CountAssignedSlotsInPage(int pageIndex) { int num = 0; int activeSlotCount = GetActiveSlotCount(); for (int i = 0; i < activeSlotCount; i++) { if (TryGetSlotEmoteForPage(pageIndex, i, out var _)) { num++; } } return num; } internal int CountAssignedSlotsAcrossEnabledPages() { int num = 0; int effectiveDeckPageCount = GetEffectiveDeckPageCount(); for (int i = 0; i < effectiveDeckPageCount; i++) { num += CountAssignedSlotsInPage(i); } return num; } internal void SetCurrentPageIndex(int pageIndex) { int pageCount = GetPageCount(); if (pageIndex < 0) { pageIndex = 0; } if (pageIndex >= pageCount) { pageIndex = pageCount - 1; } CfgCurrentPage.Value = pageIndex + 1; QueueConfigSave(); } internal string GetSlotKey(int index) { return GetSlotKeyForPage(GetCurrentPageIndex(), index); } internal void TouchSlotRevision() { SlotRevision++; } internal void SetSlotKey(int index, string key) { if (index >= 0 && index < 100) { int num = GetCurrentPageIndex(); if (!CfgEnablePages.Value || num <= 0) { num = 0; } EnsurePageSlotArray(num); PageSlotKeys[num][index] = key ?? string.Empty; SavePageSlotConfig(num); TouchSlotRevision(); SavePluginConfig(); } } internal bool TryGetSlotEmote(int index, out EmoteEntry entry) { return TryGetSlotEmoteForPage(GetCurrentPageIndex(), index, out entry); } internal bool TryGetSlotEmoteForPage(int pageIndex, int index, out EmoteEntry entry) { entry = null; string slotKeyForPage = GetSlotKeyForPage(pageIndex, index); if (string.IsNullOrEmpty(slotKeyForPage)) { return false; } return EmotesByKey.TryGetValue(slotKeyForPage, out entry) && entry != null; } internal bool IsAssignedOnCurrentDeck(string key) { if (string.IsNullOrEmpty(key)) { return false; } int activeSlotCount = GetActiveSlotCount(); for (int i = 0; i < activeSlotCount; i++) { if (string.Equals(GetSlotKey(i), key, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } internal bool IsAssignedOnAnyEnabledPage(string key) { if (string.IsNullOrEmpty(key)) { return false; } int activeSlotCount = GetActiveSlotCount(); int effectiveDeckPageCount = GetEffectiveDeckPageCount(); for (int i = 0; i < effectiveDeckPageCount; i++) { for (int j = 0; j < activeSlotCount; j++) { if (string.Equals(GetSlotKeyForPage(i, j), key, StringComparison.OrdinalIgnoreCase)) { return true; } } } return false; } private void LoadPageSlotsFromConfig() { for (int i = 0; i < 10; i++) { EnsurePageSlotArray(i); string packedSlotConfigValue = GetPackedSlotConfigValue(i); UnpackConfigList(packedSlotConfigValue, PageSlotKeys[i]); } } private string GetPackedSlotConfigValue(int page) { if (page <= 0) { return (CfgDeckSlotKeys != null) ? (CfgDeckSlotKeys.Value ?? string.Empty) : string.Empty; } return (CfgPageSlotKeys[page] != null) ? (CfgPageSlotKeys[page].Value ?? string.Empty) : string.Empty; } private void EnsurePageSlotArray(int page) { if (page >= 0 && page < 10 && (PageSlotKeys[page] == null || PageSlotKeys[page].Length != 100)) { PageSlotKeys[page] = new string[100]; } } private void SavePageSlotConfig(int page) { if (page < 0 || page >= 10) { return; } EnsurePageSlotArray(page); string value = PackConfigList(PageSlotKeys[page]); if (page <= 0) { if (CfgDeckSlotKeys != null) { CfgDeckSlotKeys.Value = value; } } else if (CfgPageSlotKeys[page] != null) { CfgPageSlotKeys[page].Value = value; } } private void LoadCustomCommandsFromConfig() { for (int i = 0; i < 10; i++) { EnsurePageCustomCommandArray(i); string packedCustomCommandConfigValue = GetPackedCustomCommandConfigValue(i); string[] array = SplitConfigList(packedCustomCommandConfigValue); for (int j = 0; j < 100; j++) { string value = ((j < array.Length) ? array[j] : string.Empty); PageCustomCommands[i][j] = (TryNormalizeCustomSlotCommand(value, out var normalized, out var _) ? normalized : string.Empty); } } } private string GetPackedCustomCommandConfigValue(int page) { if (page <= 0) { return (CfgDeckCustomCommands != null) ? (CfgDeckCustomCommands.Value ?? string.Empty) : string.Empty; } return (CfgPageCustomCommands[page] != null) ? (CfgPageCustomCommands[page].Value ?? string.Empty) : string.Empty; } private void EnsurePageCustomCommandArray(int page) { if (page >= 0 && page < 10 && (PageCustomCommands[page] == null || PageCustomCommands[page].Length != 100)) { PageCustomCommands[page] = new string[100]; } } private void SavePageCustomCommandConfig(int page) { if (page < 0 || page >= 10) { return; } EnsurePageCustomCommandArray(page); string value = PackConfigList(PageCustomCommands[page]); if (page <= 0) { if (CfgDeckCustomCommands != null) { CfgDeckCustomCommands.Value = value; } } else if (CfgPageCustomCommands[page] != null) { CfgPageCustomCommands[page].Value = value; } } internal string GetCustomCommandForPage(int pageIndex, int index) { if (index < 0 || index >= 100) { return string.Empty; } if (!CfgEnablePages.Value || pageIndex <= 0) { pageIndex = 0; } if (pageIndex >= 10) { return string.Empty; } EnsurePageCustomCommandArray(pageIndex); return PageCustomCommands[pageIndex][index] ?? string.Empty; } internal string GetCustomCommand(int index) { return GetCustomCommandForPage(GetCurrentPageIndex(), index); } internal bool SetCustomCommand(int index, string rawCommand, out string normalized, out string error) { normalized = string.Empty; if (index < 0 || index >= 100) { error = "Slot is out of range."; return false; } if (!TryNormalizeCustomSlotCommand(rawCommand, out normalized, out error)) { return false; } if (normalized.Length > 0 && TryFindCustomCommand(normalized, GetCurrentPageIndex(), index, out var pageIndex, out var slotIndex)) { error = "Already used on page " + (pageIndex + 1).ToString(CultureInfo.InvariantCulture) + ", slot " + (slotIndex + 1).ToString(CultureInfo.InvariantCulture) + "."; return false; } int num = GetCurrentPageIndex(); if (!CfgEnablePages.Value || num <= 0) { num = 0; } EnsurePageCustomCommandArray(num); PageCustomCommands[num][index] = normalized; SavePageCustomCommandConfig(num); SavePluginConfig(); return true; } internal bool TryFindCustomCommand(string command, int ignorePage, int ignoreSlot, out int pageIndex, out int slotIndex) { pageIndex = -1; slotIndex = -1; if (!TryNormalizeCustomSlotCommand(command, out var normalized, out var _) || normalized.Length == 0) { return false; } int effectiveDeckPageCount = GetEffectiveDeckPageCount(); int activeSlotCount = GetActiveSlotCount(); for (int i = 0; i < effectiveDeckPageCount; i++) { for (int j = 0; j < activeSlotCount; j++) { if (i != ignorePage || j != ignoreSlot) { string customCommandForPage = GetCustomCommandForPage(i, j); if (string.Equals(customCommandForPage, normalized, StringComparison.OrdinalIgnoreCase)) { pageIndex = i; slotIndex = j; return true; } } } } return false; } internal bool TryFindCustomCommandSlot(string message, out int pageIndex, out int slotIndex) { pageIndex = -1; slotIndex = -1; if (!CfgEnableCustomSlotCommands.Value) { return false; } if (!TryNormalizeCustomSlotCommand(message, out var normalized, out var _) || normalized.Length == 0) { return false; } return TryFindCustomCommand(normalized, -1, -1, out pageIndex, out slotIndex); } internal void MoveToNextPage() { if (CfgEnablePages.Value) { int pageCount = GetPageCount(); int currentPageIndex = GetCurrentPageIndex(); if (currentPageIndex + 1 < pageCount) { SetCurrentPageIndex(currentPageIndex + 1); } } } internal void MoveToPreviousPage() { if (CfgEnablePages.Value) { int currentPageIndex = GetCurrentPageIndex(); if (currentPageIndex > 0) { SetCurrentPageIndex(currentPageIndex - 1); } } } private static List<string> ParseKeyList(string raw) { List<string> list = new List<string>(); string[] array = (raw ?? string.Empty).Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length > 0 && !ContainsString(list, text)) { list.Add(text); } } return list; } private static bool ContainsString(List<string> list, string key) { for (int i = 0; i < list.Count; i++) { if (string.Equals(list[i], key, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } private static void RemoveString(List<string> list, string key) { for (int num = list.Count - 1; num >= 0; num--) { if (string.Equals(list[num], key, StringComparison.OrdinalIgnoreCase)) { list.RemoveAt(num); } } } private void LoadRecentAndFavoritesFromConfig() { RecentKeys.Clear(); FavoriteKeys.Clear(); RecentKeys.AddRange(ParseKeyList(CfgRecentKeys.Value)); FavoriteKeys.AddRange(ParseKeyList(CfgFavoriteKeys.Value)); } private void SaveRecentKeys() { CfgRecentKeys.Value = string.Join(";", RecentKeys.ToArray()); RecentRevision++; QueueConfigSave(); } private void SaveFavoriteKeys() { CfgFavoriteKeys.Value = string.Join(";", FavoriteKeys.ToArray()); FavoriteRevision++; QueueConfigSave(); } internal void NoteRecent(EmoteEntry entry) { if (entry != null && CfgEnableRecent.Value && !string.IsNullOrEmpty(entry.Key)) { RemoveString(RecentKeys, entry.Key); RecentKeys.Insert(0, entry.Key); int num = Mathf.Clamp(CfgRecentLimit.Value, 1, 100); while (RecentKeys.Count > num) { RecentKeys.RemoveAt(RecentKeys.Count - 1); } SaveRecentKeys(); } } internal bool IsFavorite(string key) { if (string.IsNullOrEmpty(key)) { return false; } return ContainsString(FavoriteKeys, key); } internal void ToggleFavorite(EmoteEntry entry) { if (entry != null && !string.IsNullOrEmpty(entry.Key)) { if (IsFavorite(entry.Key)) { RemoveString(FavoriteKeys, entry.Key); } else { FavoriteKeys.Add(entry.Key); } SaveFavoriteKeys(); } } internal void BuildEntryListFromKeys(List<string> keys, List<EmoteEntry> dest) { dest.Clear(); for (int i = 0; i < keys.Count; i++) { if (EmotesByKey.TryGetValue(keys[i], out var value) && value != null) { dest.Add(value); } } } internal List<EmoteEntry> GetVisibleEmotes() { List<EmoteEntry> list = new List<EmoteEntry>(); for (int i = 0; i < AllEmotes.Count; i++) { EmoteEntry emoteEntry = AllEmotes[i]; if (emoteEntry != null && IsPackageVisible(emoteEntry.PackageId)) { list.Add(emoteEntry); } } return list; } internal bool IsPackageVisible(string packageId) { string item = (string.IsNullOrEmpty(packageId) ? "Unknown" : packageId); return !HiddenPackages.Contains(item); } internal void SetPackageVisible(string packageId, bool visible) { string item = (string.IsNullOrEmpty(packageId) ? "Unknown" : packageId); if (visible) { HiddenPackages.Remove(item); } else { HiddenPackages.Add(item); } SaveHiddenPackagesToConfig(); } internal void ShowAllPackages() { HiddenPackages.Clear(); SaveHiddenPackagesToConfig(); } internal void HideAllPackages() { HiddenPackages.Clear(); for (int i = 0; i < PackageIds.Count; i++) { HiddenPackages.Add(PackageIds[i]); } SaveHiddenPackagesToConfig(); } private void LoadHiddenPackagesFromConfig() { HiddenPackages.Clear(); string text = CfgHiddenPackages.Value ?? string.Empty; string[] array = text.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); if (text2.Length > 0) { HiddenPackages.Add(text2); } } } private void SaveHiddenPackagesToConfig() { List<string> list = new List<string>(HiddenPackages); list.Sort(StringComparer.OrdinalIgnoreCase); CfgHiddenPackages.Value = string.Join(";", list.ToArray()); FilterRevision++; SavePluginConfig(); } private bool IsChatTyping() { try { Player mainPlayer = Player._mainPlayer; if ((Object)(object)mainPlayer != (Object)null) { if (mainPlayer._inChat) { return true; } if ((Object)(object)mainPlayer._chatBehaviour != (Object)null && mainPlayer._chatBehaviour._focusedInChat) { return true; } } } catch { } try { ChatBehaviour current = ChatBehaviour._current; if ((Object)(object)current != (Object)null && current._focusedInChat) { return true; } } catch { } return IsUnityTextInputFocused(); } private static bool IsUnityTextInputFocused() { try { Type type = FindType("UnityEngine.EventSystems.EventSystem"); if (type == null) { return false; } PropertyInfo property = type.GetProperty("current", BindingFlags.Static | BindingFlags.Public); object obj = ((property != null) ? property.GetValue(null, null) : null); if (obj == null) { return false; } PropertyInfo property2 = type.GetProperty("currentSelectedGameObject", BindingFlags.Instance | BindingFlags.Public); GameObject val = (GameObject)((property2 != null) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)val == (Object)null) { return false; } Type type2 = FindType("UnityEngine.UI.InputField"); if (type2 != null && (Object)(object)val.GetComponent(type2) != (Object)null) { return true; } Type type3 = FindType("TMPro.TMP_InputField"); if (type3 != null && (Object)(object)val.GetComponent(type3) != (Object)null) { return true; } } catch { } return false; } private void RefreshEmoteRegistryIfChanged() { int lastRegistryFingerprint = _lastRegistryFingerprint; int num = ComputeRegistryFingerprintCheap(); if (num != lastRegistryFingerprint) { RefreshEmoteRegistry(); } } private int ComputeRegistryFingerprintCheap() { int num = 17; try { Type type = FindType("AtlyssEmotes.EmoteManager"); if (type != null) { PropertyInfo property = type.GetProperty("allEmotes", BindingFlags.Static | BindingFlags.Public); object obj = ((property != null) ? property.GetValue(null, null) : null); if (obj is IDictionary dictionary) { num = num * 31 + dictionary.Count; } } } catch { } try { ScriptableEmoteList nativeScriptableEmoteList = GetNativeScriptableEmoteList(); if ((Object)(object)nativeScriptableEmoteList != (Object)null && nativeScriptableEmoteList._emoteCommandList != null) { num = num * 31 + nativeScriptableEmoteList._emoteCommandList.Length; } } catch { } return num; } internal void RefreshEmoteRegistry() { Dictionary<string, EmoteEntry> dictionary = new Dictionary<string, EmoteEntry>(StringComparer.OrdinalIgnoreCase); EmoteWheelBridgeAvailable = FindType("AtlyssEmotes.EmoteManager") != null; int lastWheelEmoteCount = CollectEmoteWheelEntries(dictionary); bool flag = false; foreach (EmoteEntry value in dictionary.Values) { if (value != null && string.Equals(value.PackageId, "Base", StringComparison.OrdinalIgnoreCase)) { flag = true; break; } } int lastNativeEmoteCount = 0; if (!flag || CfgIncludeNativeVanillaWhenWheelBaseExists.Value) { lastNativeEmoteCount = CollectNativeVanillaEntries(dictionary); } AllEmotes.Clear(); foreach (EmoteEntry value2 in dictionary.Values) { if (value2 != null && !string.Equals(value2.Key, "None", StringComparison.OrdinalIgnoreCase)) { AllEmotes.Add(value2); } } AllEmotes.Sort(CompareEmotes); EmotesByKey.Clear(); PackageIds.Clear(); HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); for (int i = 0; i < AllEmotes.Count; i++) { EmoteEntry emoteEntry = AllEmotes[i]; if (!EmotesByKey.ContainsKey(emoteEntry.Key)) { EmotesByKey.Add(emoteEntry.Key, emoteEntry); } string item = (string.IsNullOrEmpty(emoteEntry.PackageId) ? "Unknown" : emoteEntry.PackageId); if (hashSet.Add(item)) { PackageIds.Add(item); } } PackageIds.Sort(StringComparer.OrdinalIgnoreCase); LastWheelEmoteCount = lastWheelEmoteCount; LastNativeEmoteCount = lastNativeEmoteCount; LastRegistryRefreshTime = Time.unscaledTime; RegistryRevision++; _lastRegistryFingerprint = ComputeRegistryFingerprintCheap(); if (CfgDebugLogging.Value) { Log.LogInfo((object)("[EmoteDeck] Registry refreshed. total=" + AllEmotes.Count + " wheel=" + lastWheelEmoteCount + " native=" + lastNativeEmoteCount + " packages=" + PackageIds.Count)); } } private static int CompareEmotes(EmoteEntry a, EmoteEntry b) { int num = string.Compare(a.PackageId, b.PackageId, StringComparison.OrdinalIgnoreCase); if (num != 0) { return num; } return string.Compare(a.DisplayName, b.DisplayName, StringComparison.OrdinalIgnoreCase); } private int CollectEmoteWheelEntries(Dictionary<string, EmoteEntry> merged) { int num = 0; try { Type type = FindType("AtlyssEmotes.EmoteManager"); if (type == null) { return 0; } PropertyInfo property = type.GetProperty("allEmotes", BindingFlags.Static | BindingFlags.Public); object obj = ((property != null) ? property.GetValue(null, null) : null); if (!(obj is IDictionary dictionary)) { return 0; } foreach (DictionaryEntry item in dictionary) { string text = item.Key as string; object value = item.Value; if (!string.IsNullOrEmpty(text) && value != null && !string.Equals(text, "None", StringComparison.OrdinalIgnoreCase)) { Type type2 = value.GetType(); string text2 = ReadFieldString(type2, value, "emoteName"); string text3 = ReadFieldString(type2, value, "emoteID"); string text4 = ReadFieldString(type2, value, "packageName"); bool flag = ReadFieldBool(type2, value, "isVanilla"); Sprite icon = ReadFieldSprite(type2, value, "icon"); if (string.IsNullOrEmpty(text4)) { text4 = ExtractPackageFromKey(text); } if (string.IsNullOrEmpty(text2)) { text2 = ExtractNameFromKey(text); } EmoteEntry emoteEntry = new EmoteEntry(); emoteEntry.Key = text; emoteEntry.DisplayName = text2; emoteEntry.PackageId = text4; emoteEntry.Source = "Emote Wheel"; emoteEntry.AnimationTag = (flag ? text3 : text); emoteEntry.IsVanilla = flag; emoteEntry.Icon = icon; emoteEntry.SortName = text4 + ":" + text2; if (!string.IsNullOrEmpty(emoteEntry.AnimationTag) && !merged.ContainsKey(emoteEntry.Key)) { merged.Add(emoteEntry.Key, emoteEntry); num++; } } } } catch (Exception ex) { Log.LogWarning((object)("[EmoteDeck] Emote Wheel reflection failed: " + ex.GetType().Name + ": " + ex.Message)); } return num; } private int CollectNativeVanillaEntries(Dictionary<string, EmoteEntry> merged) { int num = 0; try { ScriptableEmoteList nativeScriptableEmoteList = GetNativeScriptableEmoteList(); if ((Object)(object)nativeScriptableEmoteList == (Object)null || nativeScriptableEmoteList._emoteCommandList == null) { return 0; } for (int i = 0; i < nativeScriptableEmoteList._emoteCommandList.Length; i++) { EmoteCommand val = nativeScriptableEmoteList._emoteCommandList[i]; if (val != null && !string.IsNullOrEmpty(val._emoteChatCommand) && !string.IsNullOrEmpty(val._emoteAnimationTag)) { string key = "Vanilla:" + val._emoteChatCommand; if (!merged.ContainsKey(key)) { EmoteEntry emoteEntry = new EmoteEntry(); emoteEntry.Key = key; emoteEntry.DisplayName = PrettyCommandName(val._emoteChatCommand); emoteEntry.PackageId = "Vanilla"; emoteEntry.Source = "Game"; emoteEntry.AnimationTag = val._emoteAnimationTag; emoteEntry.IsVanilla = true; emoteEntry.Icon = null; emoteEntry.SortName = "Vanilla:" + emoteEntry.DisplayName; merged.Add(key, emoteEntry); num++; } } } } catch (Exception ex) { Log.LogWarning((object)("[EmoteDeck] Native emote reflection failed: " + ex.GetType().Name + ": " + ex.Message)); } return num; } private static ScriptableEmoteList GetNativeScriptableEmoteList() { ChatBehaviour current = ChatBehaviour._current; if ((Object)(object)current == (Object)null) { return null; } FieldInfo field = typeof(ChatBehaviour).GetField("_scriptableEmoteList", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) { return null; } object? value = field.GetValue(current); return (ScriptableEmoteList)((value is ScriptableEmoteList) ? value : null); } private static Type FindType(string fullName) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { Type type = null; try { type = assemblies[i].GetType(fullName, throwOnError: false); } catch { } if (type != null) { return type; } } return null; } private static string ReadFieldString(Type t, object obj, string fieldName) { try { FieldInfo field = t.GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { return string.Empty; } object value = field.GetValue(obj); return (value as string) ?? string.Empty; } catch { return string.Empty; } } private static bool ReadFieldBool(Type t, object obj, string fieldName) { try { FieldInfo field = t.GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { return false; } object value = field.GetValue(obj); return value is bool && (bool)value; } catch { return false; } } private static Sprite ReadFieldSprite(Type t, object obj, string fieldName) { try { FieldInfo field = t.GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { return null; } object? value = field.GetValue(obj); return (Sprite)((value is Sprite) ? value : null); } catch { return null; } } private static string ExtractPackageFromKey(string key) { int num = key.IndexOf(':'); if (num > 0) { return key.Substring(0, num); } return "Unknown"; } private static string ExtractNameFromKey(string key) { int num = key.IndexOf(':'); if (num >= 0 && num + 1 < key.Length) { return key.Substring(num + 1); } return key; } private static string PrettyCommandName(string cmd) { if (string.IsNullOrEmpty(cmd)) { return "Emote"; } string text = cmd.Trim(); if (text.StartsWith("/")) { text = text.Substring(1); } if (text.Length == 0) { return cmd; } return char.ToUpperInvariant(text[0]) + ((text.Length > 1) ? text.Substring(1) : string.Empty); } internal bool TryHandleChatCommand(string message) { if (string.IsNullOrWhiteSpace(message)) { return false; } string text = message.Trim(); if (TryHandleWindowChatCommand(text)) { return true; } if (TryFindCustomCommandSlot(text, out var pageIndex, out var slotIndex)) { return TryPlaySlotFromChat(pageIndex, slotIndex); } if (CfgEnableChatCommands == null || !CfgEnableChatCommands.Value) { return false; } string activeChatCommandPrefix = GetActiveChatCommandPrefix(); if (!text.Equals(activeChatCommandPrefix, StringComparison.OrdinalIgnoreCase) && !text.StartsWith(activeChatCommandPrefix + " ", StringComparison.OrdinalIgnoreCase)) { return false; } string text2 = ((text.Length > activeChatCommandPrefix.Length) ? text.Substring(activeChatCommandPrefix.Length).Trim() : string.Empty); if (text2.Length == 0 || text2.Equals("help", StringComparison.OrdinalIgnoreCase) || text2 == "?") { ShowLocalChatNotice("Use " + activeChatCommandPrefix + " 1, " + activeChatCommandPrefix + " p2 1, or " + activeChatCommandPrefix + " point."); return true; } if (TryParseDeckCommandArgs(text2, out var pageIndex2, out var slotIndex2, out var error)) { return TryPlaySlotFromChat(pageIndex2, slotIndex2); } if (CfgEnableNamedSlotCommands != null && CfgEnableNamedSlotCommands.Value) { if (TryFindNamedSlotCommand(text2, out pageIndex2, out slotIndex2, out var error2)) { return TryPlaySlotFromChat(pageIndex2, slotIndex2); } ShowLocalChatNotice(error2 ?? error ?? "No matching emote slot."); return true; } ShowLocalChatNotice(error); return true; } private bool TryHandleWindowChatCommand(string trimmed) { if (string.IsNullOrEmpty(trimmed)) { return false; } string activeChatCommandPrefix = GetActiveChatCommandPrefix(); string activeCommand = activeChatCommandPrefix + "set"; string activeCommand2 = activeChatCommandPrefix + "mod"; string activeCommand3 = activeChatCommandPrefix + "grid"; if (IsWindowCommand(trimmed, "/edset", activeCommand)) { if (_window != null) { _window.ToggleSettingsTab(); } return true; } if (IsWindowCommand(trimmed, "/edmod", activeCommand2)) { if (_window != null) { _window.ToggleMainWindow(); } return true; } if (IsWindowCommand(trimmed, "/edgrid", activeCommand3)) { if (_window != null) { _window.ToggleGridWindow(); } return true; } return false; } private static bool IsWindowCommand(string trimmed, string defaultCommand, string activeCommand) { return string.Equals(trimmed, defaultCommand, StringComparison.OrdinalIgnoreCase) || string.Equals(trimmed, activeCommand, StringComparison.OrdinalIgnoreCase); } private bool TryPlaySlotFromChat(int pageIndex, int slotIndex) { int activeSlotCount = GetActiveSlotCount(); if (slotIndex < 0 || slotIndex >= activeSlotCount) { ShowLocalChatNotice("Slot " + (slotIndex + 1).ToString(CultureInfo.InvariantCulture) + " is outside the active slot count."); return true; } int effectiveDeckPageCount = GetEffectiveDeckPageCount(); if (pageIndex < 0 || pageIndex >= effectiveDeckPageCount) { ShowLocalChatNotice("Page " + (pageIndex + 1).ToString(CultureInfo.InvariantCulture) + " is not available."); return true; } string slotKeyForPage = GetSlotKeyForPage(pageIndex, slotIndex); if (string.IsNullOrEmpty(slotKeyForPage)) { ShowLocalChatNotice("Slot " + (slotIndex + 1).ToString(CultureInfo.InvariantCulture) + " is empty."); return true; } if (!EmotesByKey.TryGetValue(slotKeyForPage, out var value) || value == null) { ShowLocalChatNotice("That emote is not loaded. Try Rescan."); return true; } if (TryPlayEmote(value, out var status)) { TryCancelProfessionActionAfterEmote(); } else if (!string.IsNullOrEmpty(status) && status.IndexOf("cooling down", StringComparison.OrdinalIgnoreCase) < 0) { ShowLocalChatNotice(status); } return true; } private bool TryParseDeckCommandArgs(string args, out int pageIndex, out int slotIndex, out string error) { pageIndex = GetCurrentPageIndex(); slotIndex = -1; error = null; string[] array = args.Split(new char[2] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length == 1) { if (!int.TryParse(array[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { error = "Expected a slot number or emote name."; return false; } slotIndex = result - 1; return true; } if (array.Length == 2) { if (!TryParsePageToken(array[0], out var page) || !int.TryParse(array[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2)) { error = "Use /ed 1, /ed p2 1, or /ed point."; return false; } if (!CfgEnablePages.Value && page > 1) { error = "Pages are not enabled."; return false; } int effectiveDeckPageCount = GetEffectiveDeckPageCount(); if (page < 1 || page > effectiveDeckPageCount) { error = "Page " + page.ToString(CultureInfo.InvariantCulture) + " is not available."; return false; } pageIndex = page - 1; slotIndex = result2 - 1; return true; } if (array.Length == 3 && array[0].Equals("page", StringComparison.OrdinalIgnoreCase)) { if (!int.TryParse(array[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result3) || !int.TryParse(array[2], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result4)) { error = "Use /ed page 2 1."; return false; } if (!CfgEnablePages.Value && result3 > 1) { error = "Pages are not enabled."; return false; } int effectiveDeckPageCount2 = GetEffectiveDeckPageCount(); if (result3 < 1 || result3 > effectiveDeckPageCount2) { error = "Page " + result3.ToString(CultureInfo.InvariantCulture) + " is not available."; return false; } pageIndex = result3 - 1; slotIndex = result4 - 1; return true; } error = "Use /ed 1, /ed p2 1, or /ed point."; return false; } private bool TryFindNamedSlotCommand(string args, out int pageIndex, out int slotIndex, out string error) { pageIndex = -1; slotIndex = -1; error = null; int pageIndex2; string query; bool flag = TryExtractPageFromNamedArgs(args, out pageIndex2, out query); if (!flag) { query = args; } query = (query ?? string.Empty).Trim(); string text = NormalizeEmoteCommandName(query); if (text.Length == 0) { error = "Expected an emote name."; return false; } if (!ValidateNamedCommandPage(flag, pageIndex2, out error)) { return false; } int activeSlotCount = GetActiveSlotCount(); int num = (flag ? pageIndex2 : 0); int num2 = (flag ? (pageIndex2 + 1) : GetEffectiveDeckPageCount()); int num3 = -1; int num4 = -1; int num5 = 0; for (int i = num; i < num2; i++) { for (int j = 0; j < activeSlotCount; j++) { string slotKeyForPage = GetSlotKeyForPage(i, j); if (string.IsNullOrEmpty(slotKeyForPage) || !EmotesByKey.TryGetValue(slotKeyForPage, out var value) || value == null) { continue; } string customCommandForPage = GetCustomCommandForPage(i, j); if (!(NormalizeEmoteCommandName(customCommandForPage) != text) || DoesEntryMatchNameCommand(value, text)) { num5++; num3 = i; num4 = j; if (num5 > 1) { error = "More than one slot matches \"" + query + "\". Try " + GetActiveChatCommandPrefix() + " p" + (i + 1).ToString(CultureInfo.InvariantCulture) + " " + query + "."; return false; } } } } if (num5 == 1) { pageIndex = num3; slotIndex = num4; return true; } if (CfgEnableClosestNameMatch != null && CfgEnableClosestNameMatch.Value) { if (TryFindClosestNamedSlotCommand(text, query, flag, pageIndex2, out pageIndex, out slotIndex, out var error2)) { return true; } if (!string.IsNullOrEmpty(error2)) { error = error2; return false; } } error = "No slot matches \"" + query + "\"."; return false; } private bool ValidateNamedCommandPage(bool hasExplicitPage, int explicitPage, out string error) { error = null; if (!hasExplicitPage) { return true; } if (!CfgEnablePages.Value && explicitPage > 0) { error = "Pages are not enabled."; return false; } int effectiveDeckPageCount = GetEffectiveDeckPageCount(); if (explicitPage < 0 || explicitPage >= effectiveDeckPageCount) { error = "Page " + (explicitPage + 1).ToString(CultureInfo.InvariantCulture) + " is not available."; return false; } return true; } private bool TryFindClosestNamedSlotCommand(string normalizedQuery, string rawQuery, bool hasExplicitPage, int explicitPage, out int pageIndex, out int slotIndex, out string error) { pageIndex = -1; slotIndex = -1; error = null; if (string.IsNullOrEmpty(normalizedQuery)) { return false; } int activeSlotCount = GetActiveSlotCount(); int num = (hasExplicitPage ? explicitPage : 0); int num2 = (hasExplicitPage ? (explicitPage + 1) : GetEffectiveDeckPageCount()); bool flag = CfgClosestMatchIncludeCustomCommands != null && CfgClosestMatchIncludeCustomCommands.Value; int num3 = -1; int num4 = -1; int num5 = int.MaxValue; int num6 = 0; for (int i = num; i < num2; i++) { for (int j = 0; j < activeSlotCount; j++) { string slotKeyForPage = GetSlotKeyForPage(i, j); if (!string.IsNullOrEmpty(slotKeyForPage) && EmotesByKey.TryGetValue(slotKeyForPage, out var value) && value != null && TryGetClosestNameScore(value, flag ? GetCustomCommandForPage(i, j) : string.Empty, normalizedQuery, out var score)) { if (score < num5) { num5 = score; num3 = i; num4 = j; num6 = 1; } else if (score == num5 && (num3 != i || num4 != j)) { num6++; } } } } if (num3 >= 0 && num4 >= 0) { pageIndex = num3; slotIndex = num4; if (num6 > 1) { ShowLocalChatNotice("Several close matches. Playing the closest one."); } return true; } return false; } private static bool TryGetClosestNameScore(EmoteEntry entry, string customCommand, string normalizedQuery, out int score) { score = int.MaxValue; if (entry == null || string.IsNullOrEmpty(normalizedQuery)) { return false; } bool matched = false; AddClosestScore(NormalizeEmoteCommandName(entry.DisplayName), normalizedQuery, ref score, ref matched); AddClosestScore(NormalizeEmoteCommandName(ExtractNameFromKey(entry.Key)), normalizedQuery, ref score, ref matched); AddClosestScore(NormalizeEmoteCommandName(entry.AnimationTag), normalizedQuery, ref score, ref matched); if (!string.IsNullOrEmpty(customCommand)) { AddClosestScore(NormalizeEmoteCommandName(customCommand), normalizedQuery, ref score, ref matched); } return matched; } private static void AddClosestScore(string candidate, string query, ref int bestScore, ref bool matched) { if (string.IsNullOrEmpty(candidate) || string.IsNullOrEmpty(query)) { return; } int num; if (candidate.StartsWith(query, StringComparison.Ordinal)) { num = candidate.Length - query.Length; } else if (query.Length >= 3 && candidate.IndexOf(query, StringComparison.Ordinal) >= 0) { num = 100 + candidate.IndexOf(query, StringComparison.Ordinal) + Math.Abs(candidate.Length - query.Length); } else { if (query.Length < 3) { return; } int num2 = LevenshteinDistance(candidate, query); int num3 = Math.Min(3, Math.Max(1, query.Length / 3)); if (num2 > num3) { return; } num = 200 + num2 * 10 + Math.Abs(candidate.Length - query.Length); } if (num < bestScore) { bestScore = num; } matched = true; } private static int LevenshteinDistance(string a, string b) { if (a == null) { a = string.Empty; } if (b == null) { b = string.Empty; } int length = a.Length; int length2 = b.Length; if (length == 0) { return length2; } if (length2 == 0) { return length; } int[] array = new int[length2 + 1]; int[] array2 = new int[length2 + 1]; for (int i = 0; i <= length2; i++) { array[i] = i; } for (int j = 1; j <= length; j++) { array2[0] = j; char c = a[j - 1]; for (int k = 1; k <= length2; k++) { int num = ((c != b[k - 1]) ? 1 : 0); int val = array[k] + 1; int val2 = array2[k - 1] + 1; int val3 = array[k - 1] + num; array2[k] = Math.Min(Math.Min(val, val2), val3); } int[] array3 = array; array = array2; array2 = array3; } return array[length2]; } private static bool DoesEntryMatchNameCommand(EmoteEntry entry, string normalizedQuery) { if (entry == null || string.IsNullOrEmpty(normalizedQuery)) { return false; } if (NormalizeEmoteCommandName(entry.DisplayName) == normalizedQuery) { return true; } if (NormalizeEmoteCommandName(ExtractNameFromKey(entry.Key)) == normalizedQuery) { return true; } if (NormalizeEmoteCommandName(entry.AnimationTag) == normalizedQuery) { return true; } return false; } private static bool TryExtractPageFromNamedArgs(string args, out int pageIndex, out string query) { pageIndex = -1; query = args ?? string.Empty; string text = (args ?? string.Empty).Trim(); if (text.Length == 0) { return false; } string[] array = text.Split(new char[2] { ' ', '\t' }, 3, StringSplitOptions.RemoveEmptyEntries); if (array.Length >= 2 && TryParsePageToken(array[0], out var page)) { pageIndex = page - 1; query = ((array.Length >= 2) ? array[1] : string.Empty); if (array.Length == 3) { query = array[1] + " " + array[2]; } return true; } if (array.Length >= 3 && array[0].Equals("page", StringComparison.OrdinalIgnoreCase) && int.TryParse(array[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { pageIndex = result - 1; query = array[2]; return true; } return false; } private static string NormalizeEmoteCommandName(string value) { string text = (value ?? string.Empty).Trim(); if (text.StartsWith("/")) { text = text.Substring(1); } StringBuilder stringBuilder = new StringBuilder(text.Length); bool flag = false; foreach (char c in text) { if (c == '_' || c == '-' || char.IsWhiteSpace(c)) { if (!flag && stringBuilder.Length > 0) { stringBuilder.Append(' '); flag = true; } } else if (char.IsLetterOrDigit(c)) { stringBuilder.Append(char.ToLowerInvariant(c)); flag = false; } } return stringBuilder.ToString().Trim(); } private static bool TryParsePageToken(string token, out int page) { page = 0; if (string.IsNullOrEmpty(token)) { return false; } string text = token.Trim(); if (text.StartsWith("p", StringComparison.OrdinalIgnoreCase)) { text = text.Substring(1); } return int.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out page); } private static void ShowLocalChatNotice(string text) { try { ChatBehaviour current = ChatBehaviour._current; if ((Object)(object)current != (Object)null) { current.New_ChatMessage("<color=yellow>[Emote Deck]</color> " + (text ?? string.Empty)); } } catch { try { if (Log != null) { Log.LogInfo((object)("[EmoteDeck] " + text)); } } catch { } } } private static void TryCancelProfessionActionAfterEmote() { try { Player mainPlayer = Player._mainPlayer; if ((Object)(object)mainPlayer != (Object)null && (Object)(object)mainPlayer._pProfession != (Object)null && mainPlayer._pProfession._isProfessionAction) { mainPlayer._pProfession.Cancel_ProfessionAction(); } } catch { } } internal bool TryPlayEmote(EmoteEntry entry, out string status) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Invalid comparison between Unknown and I4 status = string.Empty; if (entry == null) { status = "No emote selected."; return false; } if (string.IsNullOrEmpty(entry.AnimationTag)) { status = "That emote has no animation tag."; return false; } try { Player mainPlayer = Player._mainPlayer; if ((Object)(object)mainPlayer == (Object)null || (Object)(object)mainPlayer._pVisual == (Object)null) { status = "Local player not found."; return false; } if ((int)mainPlayer._currentPlayerCondition != 2) { status = "Player is not active."; return false; } ChatBehaviour current = ChatBehaviour._current; if ((Object)(object)current != (Object)null) { float num = ReadChatEmoteBuffer(current); if (num > 0f) { status = "Emotes are cooling down."; return false; } } mainPlayer._pVisual.Cmd_CrossFadeAnim(entry.AnimationTag, 0.1f, 11); mainPlayer._pVisual.Local_CrossFadeAnim(entry.AnimationTag, 0.1f, 11); if ((Object)(object)current != (Object)null) { WriteChatEmoteBuffer(current, 0.85f); } NoteRecent(entry); status = "Played " + entry.DisplayName + "."; if (CfgDebugLogging.Value) { Log.LogInfo((object)("[EmoteDeck] Play " + entry.Key + " tag=" + entry.AnimationTag + " source=" + entry.Source)); } return true; } catch (Exception ex) { status = "Play failed: " + ex.GetType().Name + ": " + ex.Message; Log.LogWarning((object)("[EmoteDeck] " + status)); return false; } } private static float ReadChatEmoteBuffer(ChatBehaviour chat) { try { if (_chatEmoteBufferField == null) { _chatEmoteBufferField = typeof(ChatBehaviour).GetField("_emoteBuffer", BindingFlags.Instance | BindingFlags.NonPublic); } if (_chatEmoteBufferField == null) { return 0f; } if (_chatEmoteBufferField.GetValue(chat) is float result) { return result; } } catch { } return 0f; } private static void WriteChatEmoteBuffer(ChatBehaviour chat, float value) { try { if (_chatEmoteBufferField == null) { _chatEmoteBufferField = typeof(ChatBehaviour).GetField("_emoteBuffer", BindingFlags.Instance | BindingFlags.NonPublic); } if (_chatEmoteBufferField != null) { _chatEmoteBufferField.SetValue(chat, value); } } catch { } } } internal sealed class EmoteEntry { public string Key; public string DisplayName; public string PackageId; public string Source; public string AnimationTag; public bool IsVanilla; public Sprite Icon; public string SortName; } internal enum BindTarget { None, MainWindow, GridWindow } internal enum GridMode { Deck, Recent, Favorites } internal static class EmoteDeckEasySettingsBridge { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static UnityAction <>9__14_0; internal void <TrySubscribe>b__14_0() { TryRegisterIfReady(EmoteDeckPlugin.Instance); } } private const string EasySettingsTypeName = "Nessie.ATLYSS.EasySettings.Settings"; private static bool _subscribed; private static bool _registered; private static bool _registering; private static bool _loggedMissing; private static bool _syncingButtons; private static int _activeEasySettingsBindTarget; private static float _activeEasySettingsBindUntil; private static KeyCode _lastSyncedMainKey; private static KeyCode _lastSyncedGridKey; private static object _mainKeyButton; private static object _gridKeyButton; internal static void TryInstall(EmoteDeckPlugin plugin) { if (!((Object)(object)plugin == (Object)null)) { TrySubscribe(plugin); TryRegisterIfReady(plugin); } } internal static IEnumerator DelayedInstall(EmoteDeckPlugin plugin) { yield return (object)new WaitForSeconds(0.5f); TryInstall(plugin); yield return (object)new WaitForSeconds(1.5f); TryRegisterIfReady(plugin); yield return (object)new WaitForSeconds(4f); TryRegisterIfReady(plugin); } private static void TrySubscribe(EmoteDeckPlugin plugin) { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Expected O, but got Unknown if (_subscribed) { return; } Type type = FindType("Nessie.ATLYSS.EasySettings.Settings"); if (type == null) { LogMissingOnce(plugin); return; } try { PropertyInfo property = type.GetProperty("OnInitialized", BindingFlags.Static | BindingFlags.Public); object obj = ((property != null) ? property.GetValue(null, null) : null); if (obj == null) { return; } MethodInfo method = obj.GetType().GetMethod("AddListener", new Type[1] { typeof(UnityAction) }); if (method == null) { return; } object obj2 = <>c.<>9__14_0; if (obj2 == null) { UnityAction val = delegate { TryRegisterIfReady(EmoteDeckPlugin.Instance); }; <>c.<>9__14_0 = val; obj2 = (object)val; } UnityAction val2 = (UnityAction)obj2; method.Invoke(obj, new object[1] { val2 }); _subscribed = true; } catch (Exception ex) { if (EmoteDeckPlugin.CfgDebugLogging != null && EmoteDeckPlugin.CfgDebugLogging.Value && EmoteDeckPlugin.Log != null) { EmoteDeckPlugin.Log.LogWarning((object)("[EmoteDeck] EasySettings hook failed: " + ex.GetType().Name + ": " + ex.Message)); } } } private static void TryRegisterIfReady(EmoteDeckPlugin plugin) { //IL_016b: 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) if ((Object)(object)plugin == (Object)null || _registered || _registering) { return; } Type type = FindType("Nessie.ATLYSS.EasySettings.Settings"); if (type == null) { LogMissingOnce(plugin); } else { if (!IsEasySettingsReady(type)) { return; } _registering = true; try { MethodInfo method = type.GetMethod("GetOrAddCustomTab", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(string) }, null); if (method == null) { return; } object obj = method.Invoke(null, new object[1] { "Eleen's Lab" }); if (obj == null) { return; } Type type2 = obj.GetType(); MethodInfo method2 = type2.GetMethod("AddHeader", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(string) }, null); MethodInfo method3 = type2.GetMethod("AddKeyButton", BindingFlags.Instance | BindingFlags.Public, null, new Type[2] { typeof(string), typeof(KeyCode) }, null); if (!(method3 == null)) { if (method2 != null) { method2.Invoke(obj, new object[1] { "Emote Deck" }); } _mainKeyButton = method3.Invoke(obj, new object[2] { "Main window", plugin.MainWindowKey }); _gridKeyButton = method3.Invoke(obj, new object[2] { "Emote grid", plugin.GridWindowKey }); HookKeyButton(_mainKeyButton, main: true); HookKeyButton(_gridKeyButton, main: false); _registered = true; SyncButtonsFromConfig(plugin); TryUpdateEasySettingsVisibility(type); if (EmoteDeckPlugin.CfgDebugLogging != null && EmoteDeckPlugin.CfgDebugLogging.Value && EmoteDeckPlugin.Log != null) { EmoteDeckPlugin.Log.LogInfo((object)"[EmoteDeck] EasySettings keys registered."); } } } catch (Exception ex) { if (EmoteDeckPlugin.CfgDebugLogging != null && EmoteDeckPlugin.CfgDebugLogging.Value && EmoteDeckPlugin.Log != null) { EmoteDeckPlugin.Log.LogWarning((object)("[EmoteDeck] EasySettings registration failed: " + ex.GetType().Name + ": " + ex.Message)); } } finally { _registering = false; } } } private static bool IsEasySettingsReady(Type settingsType) { try { if ((Object)(object)SettingsManager._current == (Object)null) { return false; } PropertyInfo property = settingsType.GetProperty("ModTab", BindingFlags.Static | BindingFlags.Public); object obj = ((property != null) ? property.GetValue(null, null) : null); if (obj == null) { return false; } FieldInfo field = obj.GetType().GetField("Content", BindingFlags.Instance | BindingFlags.Public); object obj2 = ((field != null) ? field.GetValue(obj) : null); if (obj2 == null) { return false; } Type type = FindType("Nessie.ATLYSS.EasySettings.TemplateManager"); if (type != null) { FieldInfo field2 = ty