Decompiled source of MonsterHotkeys v2.7.0
com.github.zehsteam.MonsterHotkeys.dll
Decompiled 3 weeks 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.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using BepinControl; using ControlValley; using GameNetcodeStuff; using HarmonyLib; using LethalCompanyInputUtils.Api; using LethalConfig; using LethalConfig.ConfigItems; using LethalConfig.ConfigItems.Options; using Microsoft.CodeAnalysis; using Mono.Cecil; using Mono.Cecil.Cil; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using TMPro; using TwitchChatAPI; using TwitchChatAPI.Objects; using Unity.Netcode; using UnityEngine; using UnityEngine.AI; using UnityEngine.InputSystem; using UnityEngine.UI; using com.github.zehsteam.MonsterHotkeys.Data; using com.github.zehsteam.MonsterHotkeys.Dependencies; using com.github.zehsteam.MonsterHotkeys.Dependencies.CrowdControl; using com.github.zehsteam.MonsterHotkeys.Dependencies.CrowdControl.Patches; using com.github.zehsteam.MonsterHotkeys.Enums; using com.github.zehsteam.MonsterHotkeys.Extensions; using com.github.zehsteam.MonsterHotkeys.Helpers; using com.github.zehsteam.MonsterHotkeys.MonoBehaviours; using com.github.zehsteam.MonsterHotkeys.NetcodePatcher; using com.github.zehsteam.MonsterHotkeys.Patches; using com.github.zehsteam.MonsterHotkeys.Twitch; using com.github.zehsteam.MonsterHotkeys.Twitch.Commands; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Zehs")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © 2025 Zehs")] [assembly: AssemblyDescription("Spawn Monsters and Monster Plushies using Hotkeys or from Twitch Subs, Cheers, and Raids. Supports Modded Monsters. Highly Configurable. (Twitch and CrowdControl Integration)")] [assembly: AssemblyFileVersion("2.7.0.0")] [assembly: AssemblyInformationalVersion("2.7.0+2bc0cda330e0e05d74569bf51f81753e37b0a7df")] [assembly: AssemblyProduct("MonsterHotkeys")] [assembly: AssemblyTitle("com.github.zehsteam.MonsterHotkeys")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.7.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] [module: NetcodePatchedAssembly] internal class <Module> { static <Module>() { } } namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace com.github.zehsteam.MonsterHotkeys { internal static class Assets { public static GameObject NetworkHandlerPrefab { get; private set; } public static GameObject MessageCanvasPrefab { get; private set; } public static EnemyDataList EnemyDataList { get; private set; } public static void Load() { string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); string text = "monsterhotkeys_assets"; string text2 = Path.Combine(directoryName, text); if (!File.Exists(text2)) { Logger.LogFatal("Failed to load assets. AssetBundle file could not be found at path \"" + text2 + "\". Make sure the \"" + text + "\" file is in the same folder as the mod's DLL file."); } else { AssetBundle val = AssetBundle.LoadFromFile(text2); if ((Object)(object)val == (Object)null) { Logger.LogFatal("Failed to load assets. AssetBundle is null."); } else { OnAssetBundleLoaded(val); } } } private static void OnAssetBundleLoaded(AssetBundle assetBundle) { NetworkHandlerPrefab = LoadAsset<GameObject>("NetworkHandler", assetBundle); MessageCanvasPrefab = LoadAsset<GameObject>("MonsterHotkeysCanvas", assetBundle); EnemyDataList = LoadAsset<EnemyDataList>("EnemyDataList", assetBundle); } private static T LoadAsset<T>(string name, AssetBundle assetBundle) where T : Object { if (string.IsNullOrWhiteSpace(name)) { Logger.LogError("Failed to load asset of type \"" + typeof(T).Name + "\" from AssetBundle. Name is null or whitespace."); return default(T); } if ((Object)(object)assetBundle == (Object)null) { Logger.LogError("Failed to load asset of type \"" + typeof(T).Name + "\" with name \"" + name + "\" from AssetBundle. AssetBundle is null."); return default(T); } T val = assetBundle.LoadAsset<T>(name); if ((Object)(object)val == (Object)null) { Logger.LogError("Failed to load asset of type \"" + typeof(T).Name + "\" with name \"" + name + "\" from AssetBundle. No asset found with that type and name."); return default(T); } return val; } private static bool TryLoadAsset<T>(string name, AssetBundle assetBundle, out T asset) where T : Object { asset = LoadAsset<T>(name, assetBundle); return (Object)(object)asset != (Object)null; } } internal static class ConfigManager { public static ConfigFile ConfigFile { get; private set; } public static ConfigEntry<bool> ExtendedLogging { get; private set; } public static ConfigEntry<bool> Enemy_OnlyHostSpawnEnemies { get; private set; } public static ConfigEntry<bool> Enemy_MuteSpawnSFX { get; private set; } public static ConfigEntry<bool> Enemy_SpawnStunned { get; private set; } public static ConfigEntry<float> Enemy_StunDuration { get; private set; } public static SyncedConfigEntry<int> Plushie_SpawnCount { get; private set; } public static SyncedConfigEntry<float> Plushie_DespawnDuration { get; private set; } public static ConfigEntry<float> Plushie_SFXVolume { get; private set; } public static ConfigEntry<bool> Plushie_PlaySFXOnCollision { get; private set; } public static SyncedConfigEntry<bool> Plushie_AttractDogs { get; private set; } public static SyncedConfigEntry<float> Plushie_Scale { get; private set; } public static ConfigEntry<bool> Message_ShowMessages { get; private set; } public static ConfigEntry<bool> Message_ShowSpawnEnemyMessages { get; private set; } public static ConfigEntry<bool> Message_ShowLocalSpawnEnemyMessages { get; private set; } public static ConfigEntry<bool> Message_ShowDetailedTwitchEventSpawnEnemyMessages { get; private set; } public static ConfigEntry<float> Message_Duration { get; private set; } public static ConfigEntry<int> Message_FontSize { get; private set; } public static ConfigEntry<int> Message_BackgroundTransparency { get; private set; } public static ConfigEntry<bool> CrowdControl_Enabled { get; private set; } public static ConfigEntry<bool> CrowdControl_RewardSpawnPoints { get; private set; } public static ConfigEntry<bool> TwitchIntegration_Enabled { get; private set; } public static ConfigEntry<bool> TwitchIntegration_SpawnAllOfTheSameEnemy { get; private set; } public static ConfigEntry<bool> TwitchSubEvent_Enabled { get; private set; } public static ConfigEntry<int> TwitchSubEvent_EnemiesPerSub { get; private set; } public static ConfigEntry<int> TwitchSubEvent_Tier2EnemyMultiplier { get; private set; } public static ConfigEntry<int> TwitchSubEvent_Tier3EnemyMultiplier { get; private set; } public static ConfigEntry<bool> TwitchCheerEvent_Enabled { get; private set; } public static ConfigEntry<int> TwitchCheerEvent_AmountToSpawnEnemy { get; private set; } public static ConfigEntry<int> TwitchCheerEvent_AmountToSpawnPlushies { get; private set; } public static ConfigEntry<bool> TwitchRaidEvent_Enabled { get; private set; } public static ConfigEntry<int> TwitchRaidEvent_ViewersPerEnemy { get; private set; } public static ConfigEntry<int> TwitchRaidEvent_MaxSpawnCount { get; private set; } public static ConfigEntry<bool> SpawnPoints_Enabled { get; private set; } public static ConfigEntry<int> SpawnPoints_MaxSpawnsPerDay { get; private set; } public static ConfigEntry<int> SpawnPoints_RewardPointsPerDeath { get; private set; } public static ConfigEntry<int> SpawnPoints_RewardPointsPerCrewmateDeath { get; private set; } public static ConfigEntry<bool> TwitchCommandGiveSpawnRandom_ExcludeBroadcaster { get; private set; } public static ConfigEntry<bool> TwitchCommandGiveSpawnRandom_ExcludeExecutingUser { get; private set; } public static ConfigEntry<string> TwitchCommandGiveSpawnRandom_ExcludeUsersList { get; private set; } public static ConfigEntry<bool> EnemyNametag_Enabled { get; private set; } public static ConfigEntry<bool> EnemyNametag_ShowPlatform { get; private set; } public static ConfigEntry<float> EnemyNametag_ScaleMultiplier { get; private set; } public static ConfigEntry<int> EnemyNametag_BackgroundTransparency { get; private set; } public static void Initialize(ConfigFile configFile) { ConfigFile = configFile; BindConfigs(); MigrateOldConfigEntries(); } private static void BindConfigs() { ConfigHelper.SkipAutoGen(); ExtendedLogging = ConfigHelper.Bind("- General -", "ExtendedLogging", defaultValue: false, "Enable extended logging."); Enemy_OnlyHostSpawnEnemies = ConfigHelper.Bind("- Enemy -", "OnlyHostSpawnEnemies", defaultValue: false, "If enabled, only the host can spawn enemies."); Enemy_MuteSpawnSFX = ConfigHelper.Bind("- Enemy -", "MuteSpawnSFX", defaultValue: false, "If enabled, the enemy spawn sfx will not play."); Enemy_SpawnStunned = ConfigHelper.Bind("- Enemy -", "SpawnStunned", defaultValue: false, "If enabled, spawned enemies will be stunned for StunDuration seconds."); Enemy_StunDuration = ConfigHelper.Bind("- Enemy -", "StunDuration", 6f, "The duration enemies will be stunned for in seconds."); Enemy_MuteSpawnSFX.SettingChanged += AudioPlayerManager.OnSettingsChanged; Plushie_SpawnCount = ConfigHelper.BindSynced("- Plushie -", "SpawnCount", 30, "The amount of plushies to spawn.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100)); Plushie_DespawnDuration = ConfigHelper.BindSynced("- Plushie -", "DespawnDuration", 15f, "The duration in seconds until a plushie gets despawned."); Plushie_SFXVolume = ConfigHelper.Bind("- Plushie -", "SFXVolume", 25f, "The volume of the plushie's squeak sound effect.", requiresRestart: false, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f)); Plushie_PlaySFXOnCollision = ConfigHelper.Bind("- Plushie -", "PlaySFXOnCollision", defaultValue: true, "If enabled, the plushies will play a sound effect when colliding with the environment."); Plushie_AttractDogs = ConfigHelper.BindSynced("- Plushie -", "AttractDogs", defaultValue: true, "If enabled, the plushies will attract dogs when making noise."); Plushie_Scale = ConfigHelper.BindSynced("- Plushie -", "Scale", 4f, "The size of the plushies."); Message_ShowMessages = ConfigHelper.Bind("- Message -", "ShowMessages", defaultValue: true, "If enabled, will show messages in the bottom right."); Message_ShowSpawnEnemyMessages = ConfigHelper.Bind("- Message -", "ShowSpawnEnemyMessages", defaultValue: true, "If enabled, will show a message when someone else spawns an enemy."); Message_ShowLocalSpawnEnemyMessages = ConfigHelper.Bind("- Message -", "ShowLocalSpawnEnemyMessages", defaultValue: true, "If enabled, will show a message when you spawn an enemy."); Message_ShowDetailedTwitchEventSpawnEnemyMessages = ConfigHelper.Bind("- Message -", "ShowDetailedTwitchEventSpawnEnemyMessages", defaultValue: true, "If enabled, will show a detailed Twitch event spawn enemy messages."); Message_Duration = ConfigHelper.Bind("- Message -", "Duration", 8f, "The duration of a message in seconds."); Message_FontSize = ConfigHelper.Bind("- Message -", "FontSize", 25, "The font size of the messages."); Message_BackgroundTransparency = ConfigHelper.Bind("- Message -", "BackgroundTransparency", 192, "The transparency of the message background.", requiresRestart: false, (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 255)); Message_FontSize.SettingChanged += MessageItem.OnSettingsChanged; Message_BackgroundTransparency.SettingChanged += MessageItem.OnSettingsChanged; CrowdControl_Enabled = ConfigHelper.Bind("- Crowd Control Integration -", "Enabled", defaultValue: true, "If enabled, Crowd Control will be able to spawn enemies anywhere and spawned enemies will have a nametag with the name of the viewer that spawned that enemy."); CrowdControl_RewardSpawnPoints = ConfigHelper.Bind("- Crowd Control Integration -", "RewardSpawnPoints", defaultValue: true, "If you die to an enemy spawned by a viewer, they will gain a spawn point to spawn a free enemy by writing !spawn in your Twitch chat. (Requries Spawn Points to be enabled, Twitch Integration to be enabled, and the TwitchChatAPI mod)"); TwitchIntegration_Enabled = ConfigHelper.Bind("- Twitch Integration -", "Enabled", defaultValue: true, "If enabled, Twitch integration will be enabled to spawn enemies from Subs, Cheers, and Raids. (Requires the TwitchChatAPI mod)"); TwitchIntegration_SpawnAllOfTheSameEnemy = ConfigHelper.Bind("- Twitch Integration -", "SpawnAllOfTheSameEnemy", defaultValue: false, "If enabled, when spawning multiple enemies from a single event, all enemies spawned will be of the same type."); TwitchSubEvent_Enabled = ConfigHelper.Bind("- Twitch Sub Event -", "Enabled", defaultValue: true, "If enabled, Twitch subs will be able to spawn enemies. (Requires Twitch Integration to be enabled and the TwitchChatAPI mod)"); TwitchSubEvent_EnemiesPerSub = ConfigHelper.Bind("- Twitch Sub Event -", "EnemiesPerSub", 1, "The amount of enemies that will spawn per sub."); TwitchSubEvent_Tier2EnemyMultiplier = ConfigHelper.Bind("- Twitch Sub Event -", "Tier2EnemyMultiplier", 3, "The amount to multiply the enemy spawn count for tier 2 subs."); TwitchSubEvent_Tier3EnemyMultiplier = ConfigHelper.Bind("- Twitch Sub Event -", "Tier3EnemyMultiplier", 6, "The amount to multiply the enemy spawn count for tier 3 subs."); TwitchCheerEvent_Enabled = ConfigHelper.Bind("- Twitch Cheer Event -", "Enabled", defaultValue: true, "If enabled, Twitch cheers will be able to spawn enemies. (Requires Twitch Integration to be enabled and the TwitchChatAPI mod)"); TwitchCheerEvent_AmountToSpawnEnemy = ConfigHelper.Bind("- Twitch Cheer Event -", "AmountToSpawnEnemy", 350, "The amount of bits to spawn an enemy."); TwitchCheerEvent_AmountToSpawnPlushies = ConfigHelper.Bind("- Twitch Cheer Event -", "AmountToSpawnPlushies", 100, "The amount of bits to spawn plushies that create noise and block your view."); TwitchRaidEvent_Enabled = ConfigHelper.Bind("- Twitch Raid Event -", "Enabled", defaultValue: true, "If enabled, Twitch raids will be able to spawn enemies. (Requires Twitch Integration to be enabled and the TwitchChatAPI mod)"); TwitchRaidEvent_ViewersPerEnemy = ConfigHelper.Bind("- Twitch Raid Event -", "ViewersPerEnemy", 5, "The amount of viewers for each enemy spawn."); TwitchRaidEvent_MaxSpawnCount = ConfigHelper.Bind("- Twitch Raid Event -", "MaxSpawnCount", 20, "The max amount of enemies that can spawn."); SpawnPoints_Enabled = ConfigHelper.Bind("- Spawn Points -", "Enabled", defaultValue: true, "If you die to an enemy spawned by a viewer, they will gain a spawn point to spawn a free enemy by writing !spawn in your Twitch chat. (Requires Twitch Integration to be enabled and the TwitchChatAPI mod)"); SpawnPoints_MaxSpawnsPerDay = ConfigHelper.Bind("- Spawn Points -", "MaxSpawnsPerDay", 100, "The max amount of spawn points that can be redeemed per in-game day."); SpawnPoints_RewardPointsPerDeath = ConfigHelper.Bind("- Spawn Points -", "RewardPointsPerDeath", 1, "The amount of spawn points a viewer will receive from your death."); SpawnPoints_RewardPointsPerCrewmateDeath = ConfigHelper.Bind("- Spawn Points -", "RewardPointsPerCrewmateDeath", 0, "The amount of spawn points a viewer will receive from a crewmate's death."); ConfigHelper.AddButton("- Spawn Points -", "Reset all spawn points", "Reset", "Reset all viewers spawn points.", TwitchIntegrationManager.ResetAllSpawnPoints); TwitchCommandGiveSpawnRandom_ExcludeBroadcaster = ConfigHelper.Bind("- Twitch Command !givespawnrandom -", "ExcludeBroadcaster", defaultValue: true, "If enabled, the !givespawnrandom command will exclude the broadcaster from winning."); TwitchCommandGiveSpawnRandom_ExcludeExecutingUser = ConfigHelper.Bind("- Twitch Command !givespawnrandom -", "ExcludeExecutingUser", defaultValue: true, "If enabled, the !givespawnrandom command will exclude the user that wrote the command from winning."); TwitchCommandGiveSpawnRandom_ExcludeUsersList = ConfigHelper.Bind("- Twitch Command !givespawnrandom -", "ExcludeUsersList", "", "The list of Twitch users to exclude from winning the !givespawnrandom command."); EnemyNametag_Enabled = ConfigHelper.Bind("- Enemy Nametag -", "Enabled", defaultValue: true, "If enabled, enemies will spawn with a nametag of the viewer that spawned that enemy."); EnemyNametag_ShowPlatform = ConfigHelper.Bind("- Enemy Nametag -", "ShowPlatform", defaultValue: true, "If enabled, nametags will show which platform the enemy was spawned from."); EnemyNametag_ScaleMultiplier = ConfigHelper.Bind("- Enemy Nametag -", "ScaleMultiplier", 1f, "The scale multiplier for enemy nametags.", requiresRestart: false, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 5f)); EnemyNametag_BackgroundTransparency = ConfigHelper.Bind("- Enemy Nametag -", "BackgroundTransparency", 192, "The transparency of the nametag background.", requiresRestart: false, (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 255)); EnemyNametag_ScaleMultiplier.SettingChanged += EnemyNametag.OnSettingsChanged; EnemyNametag_ShowPlatform.SettingChanged += EnemyNametag.OnSettingsChanged; EnemyNametag_BackgroundTransparency.SettingChanged += EnemyNametag.OnSettingsChanged; } private static void MigrateOldConfigEntries() { ConfigSectionMigration[] migrations = new ConfigSectionMigration[12] { new ConfigSectionMigration("General", "- General -"), new ConfigSectionMigration("Enemy", "- Enemy -"), new ConfigSectionMigration("Plushie", "- Plushie -"), new ConfigSectionMigration("Message", "- Message -"), new ConfigSectionMigration("Crowd Control Integration", "- Crowd Control Integration -"), new ConfigSectionMigration("Twitch Integration", "- Twitch Integration -"), new ConfigSectionMigration("Twitch Sub Event", "- Twitch Sub Event -"), new ConfigSectionMigration("Twitch Cheer Event", "- Twitch Cheer Event -"), new ConfigSectionMigration("Twitch Raid Event", "- Twitch Raid Event -"), new ConfigSectionMigration("Spawn Points", "- Spawn Points -"), new ConfigSectionMigration("Twitch Command !givespawnrandom", "- Twitch Command !givespawnrandom -"), new ConfigSectionMigration("Enemy Nametag", "- Enemy Nametag -") }; ConfigFile.MigrateConfigEntries(migrations); } } internal class HotkeyInputClass : LcInputActions { [InputAction(/*Could not decode attribute arguments.*/)] public InputAction MonsterPrefixKey { get; set; } [InputAction(/*Could not decode attribute arguments.*/)] public InputAction PlushiePrefixKey { get; set; } [InputAction(/*Could not decode attribute arguments.*/)] public InputAction SpawnRandomKey { get; set; } [InputAction(/*Could not decode attribute arguments.*/)] public InputAction SpawnBaboonHawkKey { get; set; } [InputAction(/*Could not decode attribute arguments.*/)] public InputAction SpawnBarberKey { get; set; } [InputAction(/*Could not decode attribute arguments.*/)] public InputAction SpawnBlobKey { get; set; } [InputAction(/*Could not decode attribute arguments.*/)] public InputAction SpawnBrackenKey { get; set; } [InputAction(/*Could not decode attribute arguments.*/)] public InputAction SpawnBunkerSpiderKey { get; set; } [InputAction(/*Could not decode attribute arguments.*/)] public InputAction SpawnButlerKey { get; set; } [InputAction(/*Could not decode attribute arguments.*/)] public InputAction SpawnCoilHeadKey { get; set; } [InputAction(/*Could not decode attribute arguments.*/)] public InputAction SpawnEarthLeviathanKey { get; set; } [InputAction(/*Could not decode attribute arguments.*/)] public InputAction SpawnEyelessDogKey { get; set; } [InputAction(/*Could not decode attribute arguments.*/)] public InputAction SpawnForestGiantKey { get; set; } [InputAction(/*Could not decode attribute arguments.*/)] public InputAction SpawnGhostGirlKey { get; set; } [InputAction(/*Could not decode attribute arguments.*/)] public InputAction SpawnHoardingBugKey { get; set; } [InputAction(/*Could not decode attribute arguments.*/)] public InputAction SpawnJesterKey { get; set; } [InputAction(/*Could not decode attribute arguments.*/)] public InputAction SpawnKidnapperFoxKey { get; set; } [InputAction(/*Could not decode attribute arguments.*/)] public InputAction SpawnManeaterKey { get; set; } [InputAction(/*Could not decode attribute arguments.*/)] public InputAction SpawnManticoilKey { get; set; } [InputAction(/*Could not decode attribute arguments.*/)] public InputAction SpawnMaskedKey { get; set; } [InputAction(/*Could not decode attribute arguments.*/)] public InputAction SpawnNutcrackerKey { get; set; } [InputAction(/*Could not decode attribute arguments.*/)] public InputAction SpawnOldBirdKey { get; set; } [InputAction(/*Could not decode attribute arguments.*/)] public InputAction SpawnSnareFleaKey { get; set; } [InputAction(/*Could not decode attribute arguments.*/)] public InputAction SpawnSporeLizardKey { get; set; } [InputAction(/*Could not decode attribute arguments.*/)] public InputAction SpawnThumperKey { get; set; } [InputAction(/*Could not decode attribute arguments.*/)] public InputAction SpawnTulipSnakeKey { get; set; } } public static class HotkeyListener { public static bool DisableHotkeys; public static bool IsMonsterPrefixKeyPressed => Plugin.InputActionsInstance.MonsterPrefixKey.IsPressed(); public static bool IsPlushiePrefixKeyPressed => Plugin.InputActionsInstance.PlushiePrefixKey.IsPressed(); internal static void SetupKeybindCallbacks() { Plugin.InputActionsInstance.SpawnRandomKey.performed += OnSpawnRandomKeyPressed; Plugin.InputActionsInstance.SpawnBaboonHawkKey.performed += OnSpawnKeyPressed; Plugin.InputActionsInstance.SpawnBarberKey.performed += OnSpawnKeyPressed; Plugin.InputActionsInstance.SpawnBlobKey.performed += OnSpawnKeyPressed; Plugin.InputActionsInstance.SpawnBrackenKey.performed += OnSpawnKeyPressed; Plugin.InputActionsInstance.SpawnBunkerSpiderKey.performed += OnSpawnKeyPressed; Plugin.InputActionsInstance.SpawnButlerKey.performed += OnSpawnKeyPressed; Plugin.InputActionsInstance.SpawnCoilHeadKey.performed += OnSpawnKeyPressed; Plugin.InputActionsInstance.SpawnEarthLeviathanKey.performed += OnSpawnKeyPressed; Plugin.InputActionsInstance.SpawnEyelessDogKey.performed += OnSpawnKeyPressed; Plugin.InputActionsInstance.SpawnForestGiantKey.performed += OnSpawnKeyPressed; Plugin.InputActionsInstance.SpawnGhostGirlKey.performed += OnSpawnKeyPressed; Plugin.InputActionsInstance.SpawnHoardingBugKey.performed += OnSpawnKeyPressed; Plugin.InputActionsInstance.SpawnJesterKey.performed += OnSpawnKeyPressed; Plugin.InputActionsInstance.SpawnKidnapperFoxKey.performed += OnSpawnKeyPressed; Plugin.InputActionsInstance.SpawnManeaterKey.performed += OnSpawnKeyPressed; Plugin.InputActionsInstance.SpawnManticoilKey.performed += OnSpawnKeyPressed; Plugin.InputActionsInstance.SpawnMaskedKey.performed += OnSpawnKeyPressed; Plugin.InputActionsInstance.SpawnNutcrackerKey.performed += OnSpawnKeyPressed; Plugin.InputActionsInstance.SpawnOldBirdKey.performed += OnSpawnKeyPressed; Plugin.InputActionsInstance.SpawnSnareFleaKey.performed += OnSpawnKeyPressed; Plugin.InputActionsInstance.SpawnSporeLizardKey.performed += OnSpawnKeyPressed; Plugin.InputActionsInstance.SpawnThumperKey.performed += OnSpawnKeyPressed; Plugin.InputActionsInstance.SpawnTulipSnakeKey.performed += OnSpawnKeyPressed; Logger.LogInfo("Setup keybind callbacks."); } private static void OnSpawnKeyPressed(CallbackContext context) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) if (!((CallbackContext)(ref context)).performed) { return; } string name = ((CallbackContext)(ref context)).action.name; Logger.LogInfo(name + " key pressed.", extended: true); if (!Utils.CanPerformHotkeys()) { return; } if (DisableHotkeys && (IsMonsterPrefixKeyPressed || IsPlushiePrefixKeyPressed)) { MessageCanvas.Instance.ShowMessage_LocalClient("Hotkeys have been disabled by another mod", Color.red); Logger.LogInfo("Hotkeys have been disabled by another mod."); return; } string text = name.Replace("Spawn", "").Replace("Key", ""); switch (text) { case "BaboonHawk": text = "Baboon hawk"; break; case "BunkerSpider": text = "Bunker Spider"; break; case "Bracken": text = "Flowerman"; break; case "CoilHead": text = "Spring"; break; case "EarthLeviathan": text = "Earth Leviathan"; break; case "EyelessDog": text = "MouthDog"; break; case "GhostGirl": text = "Girl"; break; case "HoardingBug": text = "Hoarding bug"; break; case "OldBird": text = "RadMech"; break; case "SnareFlea": text = "Centipede"; break; case "SporeLizard": text = "Puffer"; break; case "Thumper": text = "Crawler"; break; case "TulipSnake": text = "Tulip Snake"; break; case "KidnapperFox": text = "Bush Wolf"; break; case "Barber": text = "Clay Surgeon"; break; } EnemyData byEnemyName = Assets.EnemyDataList.GetByEnemyName(text); if (byEnemyName == null) { Logger.LogError("Failed to find EnemyData from key name \"" + name + "\"."); return; } if (Plugin.InputActionsInstance.MonsterPrefixKey.IsPressed()) { EnemyHelper.SpawnEnemy(byEnemyName); } if (Plugin.InputActionsInstance.PlushiePrefixKey.IsPressed()) { PlushieManager.Instance.SpawnPlushies(byEnemyName.EnemyName); } } private static void OnSpawnRandomKeyPressed(CallbackContext context) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) if (!((CallbackContext)(ref context)).performed) { return; } Logger.LogInfo(((CallbackContext)(ref context)).action.name + " key pressed.", extended: true); if (!Utils.CanPerformHotkeys()) { return; } if (DisableHotkeys && (IsMonsterPrefixKeyPressed || IsPlushiePrefixKeyPressed)) { MessageCanvas.Instance.ShowMessage_LocalClient("Hotkeys have been disabled by another mod", Color.red); Logger.LogInfo("Hotkeys have been disabled by another mod."); return; } if (IsMonsterPrefixKeyPressed) { EnemyHelper.SpawnRandomEnemy(); } if (IsPlushiePrefixKeyPressed) { PlushieManager.Instance.SpawnRandomPlushies(); } } } internal static class Logger { public static ManualLogSource ManualLogSource { get; private set; } public static void Initialize(ManualLogSource manualLogSource) { ManualLogSource = manualLogSource; } public static void LogDebug(object data) { Log((LogLevel)32, data); } public static void LogInfo(object data, bool extended = false) { Log((LogLevel)16, data, extended); } public static void LogWarning(object data, bool extended = false) { Log((LogLevel)4, data, extended); } public static void LogError(object data, bool extended = false, bool showMessage = false) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) Log((LogLevel)2, data, extended); if (showMessage) { MessageCanvas.Instance?.ShowMessage(data.ToString(), Color.red); } } public static void LogFatal(object data, bool extended = false) { Log((LogLevel)1, data, extended); } public static void Log(LogLevel logLevel, object data, bool extended = false) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (!extended || IsExtendedLoggingEnabled()) { ManualLogSource manualLogSource = ManualLogSource; if (manualLogSource != null) { manualLogSource.Log(logLevel, data); } } } public static bool IsExtendedLoggingEnabled() { if (ConfigManager.ExtendedLogging == null) { return false; } return ConfigManager.ExtendedLogging.Value; } } internal static class NetworkUtils { public static bool IsConnected { get { if ((Object)(object)NetworkManager.Singleton == (Object)null) { return false; } return NetworkManager.Singleton.IsConnectedClient; } } public static bool IsServer { get { if ((Object)(object)NetworkManager.Singleton == (Object)null) { return false; } return NetworkManager.Singleton.IsServer; } } public static bool IsHost { get { if ((Object)(object)NetworkManager.Singleton == (Object)null) { return false; } return NetworkManager.Singleton.IsHost; } } public static ulong GetLocalClientId() { return NetworkManager.Singleton.LocalClientId; } public static bool IsLocalClientId(ulong clientId) { return clientId == GetLocalClientId(); } public static bool IsNetworkPrefab(GameObject prefab) { foreach (NetworkPrefab prefab2 in NetworkManager.Singleton.NetworkConfig.Prefabs.Prefabs) { if ((Object)(object)prefab2.Prefab == (Object)(object)prefab) { return true; } } return false; } } internal static class PlayerUtils { public static PlayerControllerB GetLocalPlayerScript() { if ((Object)(object)GameNetworkManager.Instance == (Object)null) { return null; } return GameNetworkManager.Instance.localPlayerController; } public static bool IsLocalPlayer(PlayerControllerB playerScript) { return (Object)(object)playerScript == (Object)(object)GetLocalPlayerScript(); } public static PlayerControllerB GetPlayerScriptByClientId(ulong clientId) { PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (!((Object)(object)val == (Object)null) && val.actualClientId == clientId) { return val; } } return null; } public static List<PlayerControllerB> GetPlayerScripts() { List<PlayerControllerB> list = new List<PlayerControllerB>(); PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (!((Object)(object)val == (Object)null) && (val.isInHangarShipRoom || val.isInsideFactory || val.isInElevator)) { list.Add(val); } } return list; } public static PlayerControllerB GetRandomPlayerScript(bool onlyAlivePlayers = true, bool excludeLocalPlayer = false) { List<PlayerControllerB> list = new List<PlayerControllerB>(); foreach (PlayerControllerB playerScript in GetPlayerScripts()) { if ((!onlyAlivePlayers || !playerScript.isPlayerDead) && (!excludeLocalPlayer || !IsLocalPlayer(playerScript))) { list.Add(playerScript); } } if (list.Count == 0) { return null; } return list[Random.Range(0, list.Count)]; } } [BepInPlugin("com.github.zehsteam.MonsterHotkeys", "MonsterHotkeys", "2.7.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] internal class Plugin : BaseUnityPlugin { private readonly Harmony _harmony = new Harmony("com.github.zehsteam.MonsterHotkeys"); internal static Plugin Instance { get; private set; } internal static HotkeyInputClass InputActionsInstance { get; private set; } internal static JsonSave GlobalSave { get; private set; } internal static JsonSave LocalSave { get; private set; } private void Awake() { Instance = this; Logger.Initialize(Logger.CreateLogSource("com.github.zehsteam.MonsterHotkeys")); Logger.LogInfo("MonsterHotkeys has awoken!"); _harmony.PatchAll(typeof(GameNetworkManagerPatch)); _harmony.PatchAll(typeof(StartOfRoundPatch)); _harmony.PatchAll(typeof(RoundManagerPatch)); _harmony.PatchAll(typeof(HUDManagerPatch)); _harmony.PatchAll(typeof(EnemyAIPatch)); _harmony.PatchAll(typeof(RadMechAIPatch)); _harmony.PatchAll(typeof(ButlerEnemyAIPatch)); _harmony.PatchAll(typeof(LandminePatch)); if (CrowdControlProxy.Enabled) { CrowdControlProxy.PatchAll(_harmony); } GlobalSave = new JsonSave(Utils.GetPluginPersistentDataPath(), "GlobalSave"); LocalSave = new JsonSave(Paths.ConfigPath, "MonsterHotkeys_Save.json"); ((Object)this).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)this); Assets.Load(); ConfigManager.Initialize(((BaseUnityPlugin)this).Config); InputActionsInstance = new HotkeyInputClass(); HotkeyListener.SetupKeybindCallbacks(); Assets.EnemyDataList.Initialize(); TwitchIntegrationManager.Initialize(); NetcodePatcherAwake(); } private void Start() { PlayerDamagePatcher.PatchAll(_harmony); } private void NetcodePatcherAwake() { try { Assembly executingAssembly = Assembly.GetExecutingAssembly(); Type[] types = executingAssembly.GetTypes(); Type[] array = types; foreach (Type type in array) { MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic); MethodInfo[] array2 = methods; foreach (MethodInfo methodInfo in array2) { try { object[] customAttributes = methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false); if (customAttributes.Length != 0) { try { methodInfo.Invoke(null, null); } catch (TargetInvocationException ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to invoke method " + methodInfo.Name + ": " + ex.Message)); } } } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Error processing method " + methodInfo.Name + " in type " + type.Name + ": " + ex2.Message)); } } } } catch (Exception ex3) { ((BaseUnityPlugin)this).Logger.LogError((object)("An error occurred in NetcodePatcherAwake: " + ex3.Message)); } } public void OnNewLevelLoaded() { EnemyNametagManager.Instance?.Reset(); } } internal static class Utils { public static string GetPluginPersistentDataPath() { return Path.Combine(Application.persistentDataPath, "MonsterHotkeys"); } public static ConfigFile CreateConfigFile(BaseUnityPlugin plugin, string path, string name = null, bool saveOnInit = false) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown BepInPlugin metadata = MetadataHelper.GetMetadata((object)plugin); if (name == null) { name = metadata.GUID; } name += ".cfg"; return new ConfigFile(Path.Combine(path, name), saveOnInit, metadata); } public static ConfigFile CreateLocalConfigFile(BaseUnityPlugin plugin, string name = null, bool saveOnInit = false) { return CreateConfigFile(plugin, Paths.ConfigPath, name, saveOnInit); } public static ConfigFile CreateGlobalConfigFile(BaseUnityPlugin plugin, string name = null, bool saveOnInit = false) { string pluginPersistentDataPath = GetPluginPersistentDataPath(); if (name == null) { name = "global"; } return CreateConfigFile(plugin, pluginPersistentDataPath, name, saveOnInit); } public static void LogStackTrace() { StackTrace stackTrace = new StackTrace(); for (int i = 1; i < stackTrace.FrameCount; i++) { StackFrame frame = stackTrace.GetFrame(i); MethodBase method = frame.GetMethod(); Type declaringType = method.DeclaringType; string name = method.Name; Logger.LogInfo($"Call stack depth {i}: {declaringType}.{name}", extended: true); } } public static bool RandomPercent(float percent) { if (percent <= 0f) { return false; } if (percent >= 100f) { return true; } return Random.value * 100f <= percent; } public static string GetFormattedString(string text) { if (string.IsNullOrWhiteSpace(text)) { return string.Empty; } return string.Join(" ", from word in text.Split(' ', StringSplitOptions.RemoveEmptyEntries) select $"{char.ToUpper(word[0])}{word.Substring(1).ToLower()}"); } public static bool CanPerformHotkeys() { PlayerControllerB localPlayerScript = PlayerUtils.GetLocalPlayerScript(); if ((Object)(object)localPlayerScript == (Object)null) { return false; } if (localPlayerScript.isPlayerDead) { return false; } if (localPlayerScript.isTypingChat) { return false; } if (localPlayerScript.quickMenuManager.isMenuOpen) { return false; } return true; } public static Coroutine StartCoroutine(IEnumerator routine) { if ((Object)(object)Plugin.Instance != (Object)null) { return ((MonoBehaviour)Plugin.Instance).StartCoroutine(routine); } if ((Object)(object)GameNetworkManager.Instance != (Object)null) { return ((MonoBehaviour)GameNetworkManager.Instance).StartCoroutine(routine); } Logger.LogError("Failed to start coroutine. " + routine); return null; } public static bool TryParseValue<T>(string value, out T result) { try { if (typeof(T) == typeof(int) && int.TryParse(value, out var result2)) { result = (T)(object)result2; return true; } if (typeof(T) == typeof(float) && float.TryParse(value, out var result3)) { result = (T)(object)result3; return true; } if (typeof(T) == typeof(double) && double.TryParse(value, out var result4)) { result = (T)(object)result4; return true; } if (typeof(T) == typeof(bool) && bool.TryParse(value, out var result5)) { result = (T)(object)result5; return true; } if (typeof(T) == typeof(string)) { result = (T)(object)value; return true; } } catch { } result = default(T); return false; } public static string GetFormattedKeyValuePairMessage<T>(Dictionary<string, T> keyValuePair, int columns, string format, string separator = " ") { if (keyValuePair == null || keyValuePair.Count == 0) { return string.Empty; } int num = Mathf.CeilToInt((float)keyValuePair.Count / (float)columns); List<List<KeyValuePair<string, T>>> list = new List<List<KeyValuePair<string, T>>>(); for (int i = 0; i < columns; i++) { list.Add(keyValuePair.Skip(i * num).Take(num).ToList()); } List<int> list2 = list.Select((List<KeyValuePair<string, T>> column) => column.Any() ? column.Max((KeyValuePair<string, T> item) => item.Key.Length) : 0).ToList(); List<int> list3 = list.Select((List<KeyValuePair<string, T>> column) => column.Any() ? column.Max((KeyValuePair<string, T> item) => item.Value.ToString().Length) : 0).ToList(); StringBuilder stringBuilder = new StringBuilder(); for (int j = 0; j < num; j++) { for (int k = 0; k < columns; k++) { if (k < list.Count && j < list[k].Count) { KeyValuePair<string, T> keyValuePair2 = list[k][j]; string newValue = keyValuePair2.Key.PadRight(list2[k]); string newValue2 = keyValuePair2.Value.ToString().PadRight(list3[k]); string value = format.Replace("{key}", newValue).Replace("{value}", newValue2); stringBuilder.Append(value); if (k < columns - 1) { stringBuilder.Append(" | "); } } } stringBuilder.AppendLine(); } return stringBuilder.ToString().TrimEnd(); } public static bool IsChildOfComponent<T>(Transform transform, out T component) where T : Component { component = default(T); if ((Object)(object)transform == (Object)null || (Object)(object)transform.parent == (Object)null) { return false; } if (((Component)transform.parent).TryGetComponent<T>(ref component)) { return true; } return IsChildOfComponent<T>(transform.parent, out component); } public static string GetTextWithColor(string text, string hexColor, string backgroundHexColor = "#000000") { if (string.IsNullOrWhiteSpace(hexColor)) { hexColor = "#FFFFFF"; } string readableColor = ColorHelper.GetReadableColor(hexColor, backgroundHexColor); return "<color=" + readableColor + ">" + text + "</color>"; } public static IEnumerable<T> StringToCollection<T>(string value) { if (string.IsNullOrEmpty(value)) { return Enumerable.Empty<T>(); } T result; return from x in value.Split(',', StringSplitOptions.RemoveEmptyEntries) where !string.IsNullOrWhiteSpace(x) select x.Trim() into x select (!TryConvertStringToType<T>(x, out result)) ? default(T) : result into x where x != null select x; } public static string CollectionToString<T>(IEnumerable<T> value) { if (value == null || !value.Any()) { return string.Empty; } return string.Join(", ", from x in value where x != null && !string.IsNullOrWhiteSpace(x.ToString()) select x.ToString().Trim()); } public static bool TryConvertStringToType<T>(string value, out T result) { if (string.IsNullOrWhiteSpace(value)) { result = default(T); return false; } try { Type typeFromHandle = typeof(T); if (typeFromHandle.IsEnum && Enum.TryParse(typeFromHandle, value.Trim(), ignoreCase: true, out object result2)) { result = (T)result2; return true; } if (typeFromHandle == typeof(Guid) && Guid.TryParse(value.Trim(), out var result3)) { result = (T)(object)result3; return true; } Type conversionType = Nullable.GetUnderlyingType(typeFromHandle) ?? typeFromHandle; result = (T)Convert.ChangeType(value.Trim(), conversionType); return true; } catch { result = default(T); return false; } } } public static class MyPluginInfo { public const string PLUGIN_GUID = "com.github.zehsteam.MonsterHotkeys"; public const string PLUGIN_NAME = "MonsterHotkeys"; public const string PLUGIN_VERSION = "2.7.0"; } } namespace com.github.zehsteam.MonsterHotkeys.Twitch { internal static class TwitchIntegrationManager { [CompilerGenerated] private sealed class <PlayQueueCoroutine>d__32 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public float initialDelay; private float <delay>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <PlayQueueCoroutine>d__32(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Expected O, but got Unknown //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Expected O, but got Unknown //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; _isPlayingQueue = true; Logger.LogInfo("Started Twitch event queue.", extended: true); <>2__current = (object)new WaitForSeconds(initialDelay); <>1__state = 1; return true; case 1: <>1__state = -1; if (!CanExecuteEvents()) { Logger.LogInfo("Finished Twitch event queue. No events could be executed.", extended: true); _isPlayingQueue = false; return false; } if (SubQueue.Count > 0 || CheerQueue.Count > 0 || RaidQueue.Count > 0) { MessageCanvas.Instance?.ShowMessage_LocalClient("Playing Twitch events from the queue"); } <delay>5__2 = 0.5f; goto IL_0107; case 2: <>1__state = -1; goto IL_0107; case 3: <>1__state = -1; goto IL_015e; case 4: { <>1__state = -1; break; } IL_0107: if (SubQueue.Count > 0 && CanExecuteEvents()) { TwitchSubEvent subEvent = SubQueue[0]; SubQueue.RemoveAt(0); HandleSub(subEvent); <>2__current = (object)new WaitForSeconds(<delay>5__2); <>1__state = 2; return true; } goto IL_015e; IL_015e: if (CheerQueue.Count > 0 && CanExecuteEvents()) { TwitchCheerEvent cheerEvent = CheerQueue[0]; CheerQueue.RemoveAt(0); HandleCheer(cheerEvent); <>2__current = (object)new WaitForSeconds(<delay>5__2); <>1__state = 3; return true; } break; } if (RaidQueue.Count > 0 && CanExecuteEvents()) { TwitchRaidEvent raidEvent = RaidQueue[0]; RaidQueue.RemoveAt(0); HandleRaid(raidEvent); <>2__current = (object)new WaitForSeconds(<delay>5__2); <>1__state = 4; return true; } Logger.LogInfo("Finished Twitch event queue.", extended: true); SaveData(); _isPlayingQueue = false; return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public static int SpawnPointsUsedThisDay; public const string UseSpawnPointText = "<color=#00FF00>Use !spawn to spawn your free enemy</color>"; private static Coroutine _playQueueCoroutine; private static bool _isPlayingQueue; public static List<TwitchCheerEvent> CheerQueue { get; private set; } = new List<TwitchCheerEvent>(); public static List<TwitchSubEvent> SubQueue { get; private set; } = new List<TwitchSubEvent>(); public static List<TwitchRaidEvent> RaidQueue { get; private set; } = new List<TwitchRaidEvent>(); public static Dictionary<string, int> AccumulatedBits { get; private set; } = new Dictionary<string, int>(); public static Dictionary<string, int> SpawnPoints { get; private set; } = new Dictionary<string, int>(); public static string[] TwitchBotUsernames { get; private set; } = new string[24] { "streamelements", "nightbot", "sery_bot", "wizebot", "kofistreambot", "botrixoficial", "tangiabot", "moobot", "fyow", "creatisbot", "frostytoolsdotcom", "own3d", "streamlabs", "pokemoncommunitygame", "fossabot", "lurxx", "blerp", "streamstickers", "wzbot", "botbandera", "soundalerts", "overlayexpert", "trackerggbot", "lumiastream" }; public static void Initialize() { try { API.OnMessage += HandleMessage; API.OnCheer += HandleCheer; API.OnSub += HandleSub; API.OnRaid += HandleRaid; LoadData(); Application.quitting += delegate { API.OnMessage -= HandleMessage; API.OnCheer -= HandleCheer; API.OnSub -= HandleSub; API.OnRaid -= HandleRaid; SaveData(); }; } catch (Exception arg) { Logger.LogError($"Failed to initialize TwitchIntegrationManager. {arg}"); } } private static void LoadData() { Logger.LogInfo("Loading saved TwitchIntegrationManager data..."); try { if (Plugin.GlobalSave.TryLoad<string>("CheerQueue", out var value)) { Logger.LogInfo("Loaded CheerQueue JSON data:\n\n" + value, extended: true); CheerQueue = JsonConvert.DeserializeObject<List<TwitchCheerEvent>>(value); } if (Plugin.GlobalSave.TryLoad<string>("SubQueue", out value)) { Logger.LogInfo("Loaded SubQueue JSON data:\n\n" + value, extended: true); SubQueue = JsonConvert.DeserializeObject<List<TwitchSubEvent>>(value); } if (Plugin.GlobalSave.TryLoad<string>("RaidQueue", out value)) { Logger.LogInfo("Loaded RaidQueue JSON data:\n\n" + value, extended: true); RaidQueue = JsonConvert.DeserializeObject<List<TwitchRaidEvent>>(value); } if (Plugin.GlobalSave.TryLoad<string>("AccumulatedBits", out value)) { Logger.LogInfo("Loaded AccumulatedBits JSON data:\n\n" + value, extended: true); AccumulatedBits = JsonConvert.DeserializeObject<Dictionary<string, int>>(value); } if (Plugin.GlobalSave.TryLoad<string>("SpawnPoints", out value)) { Logger.LogInfo("Loaded SpawnPoints JSON data:\n\n" + value, extended: true); SpawnPoints = JsonConvert.DeserializeObject<Dictionary<string, int>>(value); } Logger.LogInfo("Finished loading saved TwitchIntegrationManager data."); } catch (Exception arg) { Logger.LogError($"Failed to load TwitchIntegrationManager save data. {arg}"); } } public static void SaveData() { try { Plugin.GlobalSave.Save("CheerQueue", JsonConvert.SerializeObject((object)CheerQueue)); Plugin.GlobalSave.Save("SubQueue", JsonConvert.SerializeObject((object)SubQueue)); Plugin.GlobalSave.Save("RaidQueue", JsonConvert.SerializeObject((object)RaidQueue)); Plugin.GlobalSave.Save("AccumulatedBits", JsonConvert.SerializeObject((object)AccumulatedBits)); Plugin.GlobalSave.Save("SpawnPoints", JsonConvert.SerializeObject((object)SpawnPoints)); Logger.LogInfo("Saved TwitchIntegrationManager data."); } catch (Exception arg) { Logger.LogError($"Failed to save TwitchIntegrationManager data. {arg}"); } } public static void PlayQueue(float initialDelay = 0f) { if (!ConfigManager.TwitchIntegration_Enabled.Value) { return; } if ((Object)(object)ViewerSpawnEventHandler.Instance == (Object)null) { Logger.LogWarning("Failed to play Twitch event queue. ViewerSpawnEventHandler instance is null."); return; } if (_isPlayingQueue) { Logger.LogWarning("Failed to play Twitch event queue. Twitch event queue is already playing."); return; } if (_playQueueCoroutine != null) { ((MonoBehaviour)ViewerSpawnEventHandler.Instance).StopCoroutine(_playQueueCoroutine); } _playQueueCoroutine = ((MonoBehaviour)ViewerSpawnEventHandler.Instance).StartCoroutine(PlayQueueCoroutine(initialDelay)); } [IteratorStateMachine(typeof(<PlayQueueCoroutine>d__32))] private static IEnumerator PlayQueueCoroutine(float initialDelay = 0f) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <PlayQueueCoroutine>d__32(0) { initialDelay = initialDelay }; } private static void HandleMessage(TwitchMessage twitchMessage) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) if (ConfigManager.TwitchIntegration_Enabled.Value) { TwitchCommandManager.ExecuteCommand(twitchMessage); } } private static void HandleCheer(TwitchCheerEvent cheerEvent) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) if (!ConfigManager.TwitchIntegration_Enabled.Value || !ConfigManager.TwitchCheerEvent_Enabled.Value) { return; } if (cheerEvent == null) { Logger.LogError("Failed to handle cheer. TwitchCheerEvent is null."); return; } if (!CanExecuteEvents()) { CheerQueue.Add(cheerEvent); SaveData(); MessageCanvas.Instance?.ShowMessage_LocalClient("Added Twitch cheer event from " + GetDisplayNameWithColor(((TwitchEvent)cheerEvent).User) + " to queue"); return; } TwitchUser user = ((TwitchEvent)cheerEvent).User; string userId = ((TwitchUser)(ref user)).UserId; user = ((TwitchEvent)cheerEvent).User; string displayName = ((TwitchUser)(ref user)).DisplayName; user = ((TwitchEvent)cheerEvent).User; ViewerData viewerData = new ViewerData(userId, displayName, ((TwitchUser)(ref user)).Color); if (cheerEvent.CheerAmount == ConfigManager.TwitchCheerEvent_AmountToSpawnPlushies.Value) { Logger.LogInfo("HandleCheer:\n" + JsonConvert.SerializeObject((object)viewerData), extended: true); PlushieManager.Instance?.SpawnPlushiesFromViewer(viewerData, $"by cheering {cheerEvent.CheerAmount} bits"); return; } int accumulatedBits = GetAccumulatedBits(viewerData); int num = cheerEvent.CheerAmount + accumulatedBits; int value = ConfigManager.TwitchCheerEvent_AmountToSpawnEnemy.Value; if (num < value) { SetAccumulatedBits(viewerData, num); return; } int spawnCount = Mathf.FloorToInt((float)(num / value)); int num2 = num % value; int num3 = num - num2; SetAccumulatedBits(viewerData, num2); string spawnReason = $"by cheering {num3} bits"; ViewerSpawnEvent viewerSpawnEvent = new ViewerSpawnEvent(viewerData, spawnCount, spawnReason); Logger.LogInfo("HandleCheer:\n" + JsonConvert.SerializeObject((object)viewerSpawnEvent), extended: true); ViewerSpawnEventHandler.Instance?.ExecuteViewerSpawnEventServerRpc(viewerSpawnEvent); } private static void HandleSub(TwitchSubEvent subEvent) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Invalid comparison between Unknown and I4 //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Invalid comparison between Unknown and I4 //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Invalid comparison between Unknown and I4 //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Invalid comparison between Unknown and I4 //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Invalid comparison between Unknown and I4 //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Expected I4, but got Unknown //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Invalid comparison between Unknown and I4 //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Expected I4, but got Unknown //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Expected I4, but got Unknown //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Expected I4, but got Unknown //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) if (!ConfigManager.TwitchIntegration_Enabled.Value || !ConfigManager.TwitchSubEvent_Enabled.Value) { return; } if (subEvent == null) { Logger.LogError("Failed to handle sub. TwitchSubEvent is null."); return; } if (!CanExecuteEvents()) { SubQueue.Add(subEvent); SaveData(); MessageCanvas.Instance?.ShowMessage_LocalClient("Added Twitch sub event from " + GetDisplayNameWithColor(((TwitchEvent)subEvent).User) + " to queue"); return; } int num = ConfigManager.TwitchSubEvent_EnemiesPerSub.Value; if ((int)subEvent.Type == 3) { num *= subEvent.GiftCount; } if ((int)subEvent.Tier == 2) { num *= ConfigManager.TwitchSubEvent_Tier2EnemyMultiplier.Value; } else if ((int)subEvent.Tier == 3) { num *= ConfigManager.TwitchSubEvent_Tier3EnemyMultiplier.Value; } string spawnReason = string.Empty; if ((int)subEvent.Type == 0) { spawnReason = (((int)subEvent.Tier != 0) ? $"by subbing at tier {(int)subEvent.Tier}" : "by subbing with prime"); } else if ((int)subEvent.Type == 1) { spawnReason = (((int)subEvent.Tier != 0) ? $"by resubbing at tier {(int)subEvent.Tier} for {subEvent.CumulativeMonths} months" : $"by resubbing with prime for {subEvent.CumulativeMonths} months"); } else if ((int)subEvent.Type == 2) { spawnReason = $"by gifting a tier {(int)subEvent.Tier} sub to {subEvent.RecipientUser}"; } else if ((int)subEvent.Type == 3) { spawnReason = $"by gifting {subEvent.GiftCount} tier {(int)subEvent.Tier} subs"; } TwitchUser user = ((TwitchEvent)subEvent).User; string userId = ((TwitchUser)(ref user)).UserId; user = ((TwitchEvent)subEvent).User; string displayName = ((TwitchUser)(ref user)).DisplayName; user = ((TwitchEvent)subEvent).User; ViewerData viewer = new ViewerData(userId, displayName, ((TwitchUser)(ref user)).Color); ViewerSpawnEvent viewerSpawnEvent = new ViewerSpawnEvent(viewer, num, spawnReason); Logger.LogInfo("HandleSub:\n" + JsonConvert.SerializeObject((object)viewerSpawnEvent), extended: true); ViewerSpawnEventHandler.Instance?.ExecuteViewerSpawnEventServerRpc(viewerSpawnEvent); } private static void HandleRaid(TwitchRaidEvent raidEvent) { //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) if (ConfigManager.TwitchIntegration_Enabled.Value && ConfigManager.TwitchRaidEvent_Enabled.Value) { if (raidEvent == null) { Logger.LogError("Failed to handle raid. TwitchRaidEvent is null."); return; } if (!CanExecuteEvents()) { RaidQueue.Add(raidEvent); SaveData(); MessageCanvas.Instance?.ShowMessage_LocalClient("Added Twitch raid event from " + GetDisplayNameWithColor(((TwitchEvent)raidEvent).User) + " to queue"); return; } int value = ConfigManager.TwitchRaidEvent_ViewersPerEnemy.Value; int value2 = ConfigManager.TwitchRaidEvent_MaxSpawnCount.Value; int spawnCount = Mathf.Clamp(raidEvent.ViewerCount / value, 1, value2); string spawnReason = $"by raiding with {raidEvent.ViewerCount} viewers"; TwitchUser user = ((TwitchEvent)raidEvent).User; string userId = ((TwitchUser)(ref user)).UserId; user = ((TwitchEvent)raidEvent).User; string displayName = ((TwitchUser)(ref user)).DisplayName; user = ((TwitchEvent)raidEvent).User; ViewerData viewer = new ViewerData(userId, displayName, ((TwitchUser)(ref user)).Color); ViewerSpawnEvent viewerSpawnEvent = new ViewerSpawnEvent(viewer, spawnCount, spawnReason); Logger.LogInfo("HandleRaid:\n" + JsonConvert.SerializeObject((object)viewerSpawnEvent), extended: true); ViewerSpawnEventHandler.Instance?.ExecuteViewerSpawnEventServerRpc(viewerSpawnEvent); } } public static int GetAccumulatedBits(ViewerData viewer) { if (viewer == null) { return 0; } return GetAccumulatedBits(viewer.Username); } public static int GetAccumulatedBits(string username) { return AccumulatedBits.GetValueOrDefault(username.ToLower(), 0); } public static void SetAccumulatedBits(ViewerData viewer, int value) { if (viewer != null) { if (value <= 0) { AccumulatedBits.Remove(viewer.Username); } else { AccumulatedBits[viewer.Username] = value; } SaveData(); } } public static void RewardSpawnPointsFromDeath(EnemyNametagType nametagType, string displayName, string color) { if (!ConfigManager.TwitchIntegration_Enabled.Value || !ConfigManager.SpawnPoints_Enabled.Value) { return; } switch (nametagType) { case EnemyNametagType.Default: return; case EnemyNametagType.CrowdControl: if (!ConfigManager.CrowdControl_RewardSpawnPoints.Value) { return; } break; } int value = ConfigManager.SpawnPoints_RewardPointsPerDeath.Value; if (value > 0) { AddSpawnPoints(displayName, value); int spawnPoints = GetSpawnPoints(displayName); TwitchUser val = default(TwitchUser); if (API.TryGetUserByUsername(displayName, ref val)) { color = ((TwitchUser)(ref val)).Color; } string text = ((value == 1) ? "" : "s"); MessageCanvas.Instance?.ShowMessage_LocalClient(string.Format("{0} just earned {1} spawn point{2} ({3} total) {4}", Utils.GetTextWithColor(displayName, color), value, text, spawnPoints, "<color=#00FF00>Use !spawn to spawn your free enemy</color>")); } } public static void RewardSpawnPointsFromCrewmateDeath(ulong senderClientId, EnemyNametagType nametagType, string displayName, string color) { if (!ConfigManager.TwitchIntegration_Enabled.Value || !ConfigManager.SpawnPoints_Enabled.Value || NetworkUtils.IsLocalClientId(senderClientId)) { return; } switch (nametagType) { case EnemyNametagType.Default: return; case EnemyNametagType.CrowdControl: if (!ConfigManager.CrowdControl_RewardSpawnPoints.Value) { return; } break; } int value = ConfigManager.SpawnPoints_RewardPointsPerCrewmateDeath.Value; if (value <= 0) { return; } PlayerControllerB playerScriptByClientId = PlayerUtils.GetPlayerScriptByClientId(senderClientId); if (!((Object)(object)playerScriptByClientId == (Object)null)) { AddSpawnPoints(displayName, value); int spawnPoints = GetSpawnPoints(displayName); TwitchUser val = default(TwitchUser); if (API.TryGetUserByUsername(displayName, ref val)) { color = ((TwitchUser)(ref val)).Color; } string text = ((value == 1) ? "" : "s"); MessageCanvas.Instance?.ShowMessage_LocalClient(string.Format("{0} just earned {1} spawn point{2} by killing {3} ({4} total) {5}", Utils.GetTextWithColor(displayName, color), value, text, playerScriptByClientId.playerUsername, spawnPoints, "<color=#00FF00>Use !spawn to spawn your free enemy</color>")); } } public static int GetSpawnPoints(ViewerData viewer) { if (viewer == null) { return 0; } return GetSpawnPoints(viewer.Username); } public static int GetSpawnPoints(string username) { return SpawnPoints.GetValueOrDefault(username.ToLower(), 0); } public static void SetSpawnPoints(ViewerData viewer, int value) { if (viewer != null) { SetSpawnPoints(viewer.Username, value); } } public static void SetSpawnPoints(string username, int value) { if (value <= 0) { SpawnPoints.Remove(username.ToLower()); } else { SpawnPoints[username.ToLower()] = value; } SaveData(); } public static void AddSpawnPoints(ViewerData viewer, int amount = 1) { if (viewer != null) { AddSpawnPoints(viewer.Username); } } public static void AddSpawnPoints(string username, int amount = 1) { int valueOrDefault = SpawnPoints.GetValueOrDefault(username.ToLower(), 0); int num = valueOrDefault + amount; if (num <= 0) { SpawnPoints.Remove(username.ToLower()); } else { SpawnPoints[username.ToLower()] = num; } SaveData(); } public static void ResetAllSpawnPoints() { SpawnPoints.Clear(); SaveData(); Logger.LogInfo("Reset all spawn points."); } public static void OnLocalDisconnect() { SpawnPointsUsedThisDay = 0; } public static void OnDayEnded() { SpawnPointsUsedThisDay = 0; } public static bool IsBotUser(TwitchUser twitchUser) { return TwitchBotUsernames.Contains(((TwitchUser)(ref twitchUser)).Username); } public static bool CanExecuteEvents() { return EnemyHelper.CanSpawnEnemies(); } public static string GetDisplayNameWithColor(TwitchUser twitchUser, string backgroundHexColor = "#000000") { //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) if (((TwitchUser)(ref twitchUser)).Equals(default(TwitchUser))) { return Utils.GetTextWithColor("Unknown", "#FFFFFF", backgroundHexColor); } return Utils.GetTextWithColor(((TwitchUser)(ref twitchUser)).DisplayName, ((TwitchUser)(ref twitchUser)).Color, backgroundHexColor); } public static string GetDisplayNameWithColor(ViewerData viewerData, string backgroundHexColor = "#000000") { if (viewerData == null) { return Utils.GetTextWithColor("Unknown", "#FFFFFF", backgroundHexColor); } return Utils.GetTextWithColor(viewerData.DisplayName, viewerData.Color, backgroundHexColor); } } } namespace com.github.zehsteam.MonsterHotkeys.Twitch.Commands { internal abstract class TwitchCommand { private readonly Dictionary<string, float> _timesSinceLastUserExecution = new Dictionary<string, float>(); private float _timeSinceLastExecution = float.NegativeInfinity; public virtual bool IsCommand(TwitchMessage twitchMessage) { return false; } public bool PreExecute(TwitchMessage twitchMessage) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) TwitchUser user = ((TwitchMessage)(ref twitchMessage)).User; string text = ((TwitchUser)(ref user)).Username.ToLower(); if (IsOnCooldown(text)) { Logger.LogInfo("Command on cooldown for user: " + text, extended: true); return false; } if (Execute(twitchMessage)) { UpdateCooldowns(text); return true; } return false; } protected virtual bool Execute(TwitchMessage twitchMessage) { return true; } protected virtual TimeSpan GetUserCooldown() { return TimeSpan.Zero; } protected virtual TimeSpan GetGlobalCooldown() { return TimeSpan.Zero; } private void UpdateCooldowns(string username) { float realtimeSinceStartup = Time.realtimeSinceStartup; _timesSinceLastUserExecution[username] = realtimeSinceStartup; _timeSinceLastExecution = realtimeSinceStartup; } protected bool IsOnCooldown(string username) { if (!IsOnUserCooldown(username)) { return IsOnGlobalCooldown(); } return true; } protected bool IsOnUserCooldown(string username) { float num = (float)GetUserCooldown().TotalSeconds; if (num <= 0f) { return false; } float valueOrDefault = _timesSinceLastUserExecution.GetValueOrDefault(username, float.NegativeInfinity); bool flag = Time.realtimeSinceStartup - valueOrDefault < num; if (flag) { Logger.LogInfo($"User {username} is on cooldown for {num - (Time.realtimeSinceStartup - valueOrDefault)} more seconds.", extended: true); } return flag; } protected bool IsOnGlobalCooldown() { float num = (float)GetGlobalCooldown().TotalSeconds; if (num <= 0f) { return false; } bool flag = Time.realtimeSinceStartup - _timeSinceLastExecution < num; if (flag) { Logger.LogInfo($"Global cooldown active for {num - (Time.realtimeSinceStartup - _timeSinceLastExecution)} more seconds.", extended: true); } return flag; } protected static bool IsModeratorOrHigher(TwitchUser twitchUser) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) if (!((TwitchUser)(ref twitchUser)).IsModerator && !((TwitchUser)(ref twitchUser)).IsBroadcaster) { return IsDeveloper(twitchUser); } return true; } protected static bool IsDeveloper(TwitchUser twitchUser) { return ((TwitchUser)(ref twitchUser)).Username.Equals("CritHaxXoG", StringComparison.OrdinalIgnoreCase); } } internal static class TwitchCommandManager { public static List<TwitchCommand> TwitchCommands { get; private set; } static TwitchCommandManager() { TwitchCommands = new List<TwitchCommand>(); TwitchCommands.Add(new TwitchSpawnCommand()); TwitchCommands.Add(new TwitchGiveSpawnRandomCommand()); TwitchCommands.Add(new TwitchGiveSpawnCommand()); TwitchCommands.Add(new TwitchLustySpawnCommand()); TwitchCommands.Add(new TwitchViewSpawnCommand()); TwitchCommands.Add(new TwitchViewAllSpawnCommand()); TwitchCommands.Add(new TwitchViewBitsCommand()); TwitchCommands.Add(new TwitchViewAllBitsCommand()); TwitchCommands.Add(new TwitchInfoCommand()); TwitchCommands.Add(new TwitchDevSpawnCommand()); TwitchCommands.Add(new TwitchDevPlushiesCommand()); } public static bool ExecuteCommand(TwitchMessage twitchMessage) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (!((TwitchMessage)(ref twitchMessage)).Message.StartsWith("!")) { return false; } if (TryGetTwitchCommand(twitchMessage, out var twitchCommand)) { return twitchCommand.PreExecute(twitchMessage); } return false; } private static TwitchCommand GetTwitchCommand(TwitchMessage twitchMessage) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) foreach (TwitchCommand twitchCommand in TwitchCommands) { if (twitchCommand.IsCommand(twitchMessage)) { return twitchCommand; } } return null; } private static bool TryGetTwitchCommand(TwitchMessage twitchMessage, out TwitchCommand twitchCommand) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) twitchCommand = GetTwitchCommand(twitchMessage); return twitchCommand != null; } } internal class TwitchDevPlushiesCommand : TwitchCommand { public override bool IsCommand(TwitchMessage twitchMessage) { if (((TwitchMessage)(ref twitchMessage)).Message.Equals("!devplushies", StringComparison.OrdinalIgnoreCase)) { return true; } return false; } protected override bool Execute(TwitchMessage twitchMessage) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) if (!TwitchIntegrationManager.CanExecuteEvents()) { return false; } if (!TwitchCommand.IsDeveloper(((TwitchMessage)(ref twitchMessage)).User)) { return false; } TwitchUser user = ((TwitchMessage)(ref twitchMessage)).User; string userId = ((TwitchUser)(ref user)).UserId; user = ((TwitchMessage)(ref twitchMessage)).User; string displayName = ((TwitchUser)(ref user)).DisplayName; user = ((TwitchMessage)(ref twitchMessage)).User; ViewerData viewerData = new ViewerData(userId, displayName, ((TwitchUser)(ref user)).Color); Logger.LogInfo("TwitchDevPlushiesCommand:\n" + JsonConvert.SerializeObject((object)viewerData), extended: true); PlushieManager.Instance?.SpawnPlushiesFromViewer(viewerData, "by being the mod developer"); return true; } } internal class TwitchDevSpawnCommand : TwitchCommand { public override bool IsCommand(TwitchMessage twitchMessage) { if (((TwitchMessage)(ref twitchMessage)).Message.StartsWith("!devspawn", StringComparison.OrdinalIgnoreCase)) { return true; } return false; } protected override bool Execute(TwitchMessage twitchMessage) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) if (!TwitchIntegrationManager.CanExecuteEvents()) { return false; } if (!TwitchCommand.IsDeveloper(((TwitchMessage)(ref twitchMessage)).User)) { return false; } int num = 1; string targetEnemyName = string.Empty; string[] array = ((TwitchMessage)(ref twitchMessage)).Message.Split(' '); if (array.Length >= 2) { if (array[1].Length < 4 && int.TryParse(array[1], out var result)) { num = result; } else { targetEnemyName = array[1]; if (array.Length >= 3 && int.TryParse(array[2], out result)) { num = result; } } } if (num <= 0) { return false; } num = Mathf.Min(num, 25); string spawnReason = "by being the mod developer"; TwitchUser user = ((TwitchMessage)(ref twitchMessage)).User; string userId = ((TwitchUser)(ref user)).UserId; user = ((TwitchMessage)(ref twitchMessage)).User; string displayName = ((TwitchUser)(ref user)).DisplayName; user = ((TwitchMessage)(ref twitchMessage)).User; ViewerData viewer = new ViewerData(userId, displayName, ((TwitchUser)(ref user)).Color); ViewerSpawnEvent viewerSpawnEvent = new ViewerSpawnEvent(viewer, num, spawnReason, targetEnemyName); Logger.LogInfo("TwitchDevSpawnCommand:\n" + JsonConvert.SerializeObject((object)viewerSpawnEvent), extended: true); ViewerSpawnEventHandler.Instance?.ExecuteViewerSpawnEventServerRpc(viewerSpawnEvent); return true; } } internal class TwitchGiveSpawnCommand : TwitchCommand { public override bool IsCommand(TwitchMessage twitchMessage) { if (((TwitchMessage)(ref twitchMessage)).Message.StartsWith("!givespawn", StringComparison.OrdinalIgnoreCase)) { return true; } return false; } protected override bool Execute(TwitchMessage twitchMessage) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) if (!ConfigManager.SpawnPoints_Enabled.Value) { return false; } if (!TwitchCommand.IsModeratorOrHigher(((TwitchMessage)(ref twitchMessage)).User)) { return false; } string[] array = ((TwitchMessage)(ref twitchMessage)).Message.Split(' '); int num = 1; TwitchUser user = ((TwitchMessage)(ref twitchMessage)).User; string text = ((TwitchUser)(ref user)).DisplayName; user = ((TwitchMessage)(ref twitchMessage)).User; string hexColor = ((TwitchUser)(ref user)).Color; if (array.Length >= 2) { if (array[1].Length < 4 && int.TryParse(array[1], out var result)) { num = result; } else { text = array[1].Replace("@", ""); hexColor = "#FFFFFF"; if (text.Length < 4 || text.Length > 25) { return false; } if (array.Length >= 3 && int.TryParse(array[2], out result)) { num = result; } } } TwitchUser val = default(TwitchUser); if (API.TryGetUserByUsername(text, ref val)) { text = ((TwitchUser)(ref val)).DisplayName; hexColor = ((TwitchUser)(ref val)).Color; } TwitchIntegrationManager.AddSpawnPoints(text, num); int spawnPoints = TwitchIntegrationManager.GetSpawnPoints(text); string text2 = ((num == 1) ? "" : "s"); MessageCanvas.Instance?.ShowMessage_LocalClient(string.Format("{0} gave {1} {2} spawn point{3} ({4} total) {5}", TwitchIntegrationManager.GetDisplayNameWithColor(((TwitchMessage)(ref twitchMessage)).User), Utils.GetTextWithColor(text, hexColor), num, text2, spawnPoints, "<color=#00FF00>Use !spawn to spawn your free enemy</color>")); return true; } } internal class TwitchGiveSpawnRandomCommand : TwitchCommand { public override bool IsCommand(TwitchMessage twitchMessage) { if (((TwitchMessage)(ref twitchMessage)).Message.StartsWith("!givespawnrandom", StringComparison.OrdinalIgnoreCase)) { return true; } return false; } protected override bool Execute(TwitchMessage twitchMessage) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) if (!ConfigManager.SpawnPoints_Enabled.Value) { return false; } if (!TwitchCommand.IsModeratorOrHigher(((TwitchMessage)(ref twitchMessage)).User)) { return false; } string[] array = ((TwitchMessage)(ref twitchMessage)).Message.Split(' '); int num = 1; int num2 = 5; if (array.Length >= 2 && int.TryParse(array[1], out var result)) { num = result; } if (array.Length >= 3 && int.TryParse(array[2], out result)) { num2 = result; } TwitchUser[] array2 = (from user in API.GetUsersSeenWithin(TimeSpan.FromMinutes(num2)) where IsAllowedUserForGiveaway(user, ((TwitchMessage)(ref twitchMessage)).User) select user).ToArray(); if (array2.Length == 0) { MessageCanvas.Instance?.ShowMessage_LocalClient("Could not find any valid Twitch users."); return false; } int num3 = Random.Range(0, array2.Length); string displayName = ((TwitchUser)(ref array2[num3])).DisplayName; string color = ((TwitchUser)(ref array2[num3])).Color; TwitchIntegrationManager.AddSpawnPoints(displayName, num); int spawnPoints = TwitchIntegrationManager.GetSpawnPoints(displayName); string text = ((num == 1) ? "" : "s"); MessageCanvas.Instance?.ShowMessage_LocalClient(string.Format("{0} gave {1} {2} spawn point{3} ({4} total) {5}", TwitchIntegrationManager.GetDisplayNameWithColor(((TwitchMessage)(ref twitchMessage)).User), Utils.GetTextWithColor(displayName, color), num, text, spawnPoints, "<color=#00FF00>Use !spawn to spawn your free enemy</color>")); return true; } private static bool IsAllowedUserForGiveaway(TwitchUser twitchUser, TwitchUser executingTwitchUser) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) if (ConfigManager.TwitchCommandGiveSpawnRandom_ExcludeExecutingUser.Value && twitchUser == executingTwitchUser) { return false; } if (ConfigManager.TwitchCommandGiveSpawnRandom_ExcludeBroadcaster.Value && ((TwitchUser)(ref twitchUser)).IsBroadcaster) { return false; } if (TwitchIntegrationManager.IsBotUser(twitchUser)) { return false; } string[] source = Utils.StringToCollection<string>(ConfigManager.TwitchCommandGiveSpawnRandom_ExcludeUsersList.Value).ToArray(); if (source.Any((string username) => username.Equals(((TwitchUser)(ref twitchUser)).Username, StringComparison.OrdinalIgnoreCase))) { return false; } return true; } } internal class TwitchInfoCommand : TwitchCommand { public override bool IsCommand(TwitchMessage twitchMessage) { if (((TwitchMessage)(ref twitchMessage)).Message.StartsWith("!info", StringComparison.OrdinalIgnoreCase)) { return true; } if (((TwitchMessage)(ref twitchMessage)).Message.StartsWith("!mhinfo", StringComparison.OrdinalIgnoreCase)) { return true; } return false; } protected override bool Execute(TwitchMessage twitchMessage) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) if (!TwitchCommand.IsModeratorOrHigher(((TwitchMessage)(ref twitchMessage)).User)) { return false; } bool value = ConfigManager.TwitchSubEvent_Enabled.Value; bool value2 = ConfigManager.TwitchCheerEvent_Enabled.Value; bool value3 = ConfigManager.TwitchRaidEvent_Enabled.Value; if (!value && !value2 && !value3) { MessageCanvas.Instance?.ShowMessage_LocalClient("MonsterHotkeys subs/cheers/raids are not enabled."); return false; } MessageCanvas.Instance?.ShowMessage_LocalClient("--- MonsterHotkeys Info ---"); if (value) { MessageCanvas.Instance?.ShowMessage_LocalClient("1 sub = Random Enemy"); } if (value2) { int value4 = ConfigManager.TwitchCheerEvent_AmountToSpawnEnemy.Value; MessageCanvas.Instance?.ShowMessage_LocalClient($"{value4} bits = Random Enemy"); } if (value3) { int value5 = ConfigManager.TwitchRaidEvent_ViewersPerEnemy.Value; int value6 = ConfigManager.TwitchRaidEvent_MaxSpawnCount.Value; MessageCanvas.Instance?.ShowMessage_LocalClient($"Raids: Every {value5} viewers = Random Enemy ({value6} max)"); } if (value2) { int value7 = ConfigManager.TwitchCheerEvent_AmountToSpawnPlushies.Value; MessageCanvas.Instance?.ShowMessage_LocalClient($"{value7} bits = Random Plushies"); } return true; } } internal class TwitchLustySpawnCommand : TwitchCommand { public override bool IsCommand(TwitchMessage twitchMessage) { if (((TwitchMessage)(ref twitchMessage)).Message.StartsWith("!lustyspawn", StringComparison.OrdinalIgnoreCase)) { return true; } return false; } protected override TimeSpan GetUserCooldown() { return TimeSpan.FromMinutes(5.0); } protected override TimeSpan GetGlobalCooldown() { return TimeSpan.FromMinutes(1.0); } protected override bool Execute(TwitchMessage twitchMessage) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) if (!TwitchIntegrationManager.CanExecuteEvents()) { return false; } TwitchUser user = ((TwitchMessage)(ref twitchMessage)).User; if (!((TwitchUser)(ref user)).Username.Equals("LustStings", StringComparison.OrdinalIgnoreCase) && !TwitchCommand.IsDeveloper(((TwitchMessage)(ref twitchMessage)).User)) { return false; } int num = 69; string targetEnemyName = "Blob"; string[] array = ((TwitchMessage)(ref twitchMessage)).Message.Split(' '); if (array.Length >= 2) { if (array[1].Length < 4 && int.TryParse(array[1], out var result)) { num = result; } else { targetEnemyName = array[1]; if (array.Length >= 3 && int.TryParse(array[2], out result)) { num = result; } } } if (num <= 0) { return false; } num = Mathf.Min(num, 100); user = ((TwitchMessage)(ref twitchMessage)).User; string userId = ((TwitchUser)(ref user)).UserId; user = ((TwitchMessage)(ref twitchMessage)).User; string displayName = ((TwitchUser)(ref user)).DisplayName; user = ((TwitchMessage)(ref twitchMessage)).User; ViewerData viewer = new ViewerData(userId, displayName, ((TwitchUser)(ref user)).Color); ViewerSpawnEvent viewerSpawnEvent = new ViewerSpawnEvent(viewer, num, string.Empty, targetEnemyName); Logger.LogInfo("TwitchLustySpawnCommand:\n" + JsonConvert.SerializeObject((object)viewerSpawnEvent), extended: true); ViewerSpawnEventHandler.Instance?.ExecuteViewerSpawnEventServerRpc(viewerSpawnEvent); return true; } } internal class TwitchSpawnCommand : TwitchCommand { public override bool IsCommand(TwitchMessage twitchMessage) { if (((TwitchMessage)(ref twitchMessage)).Message.StartsWith("!spawn", StringComparison.OrdinalIgnoreCase)) { return true; } return false; } protected override bool Execute(TwitchMessage twitchMessage) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0119: 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_0166: Unknown result type (might be due to invalid IL or missing references) if (!ConfigManager.SpawnPoints_Enabled.Value) { return false; } if (!TwitchIntegrationManager.CanExecuteEvents()) { return false; } TwitchUser user = ((TwitchMessage)(ref twitchMessage)).User; int spawnPoints = TwitchIntegrationManager.GetSpawnPoints(((TwitchUser)(ref user)).Username); if (spawnPoints <= 0) { return false; } int value = ConfigManager.SpawnPoints_MaxSpawnsPerDay.Value; int num = value - TwitchIntegrationManager.SpawnPointsUsedThisDay; if (num <= 0) { MessageCanvas.Instance?.ShowMessage_LocalClient("The max amount of spawn points have been redeemed for this day"); return false; } int num2 = 1; string[] array = ((TwitchMessage)(ref twitchMessage)).Message.Split(' '); if (array.Length >= 2 && int.TryParse(array[1], out var result)) { num2 = result; } if (num2 <= 0) { return false; } if (num2 > spawnPoints) { num2 = spawnPoints; } if (num2 > num) { num2 = num; } int num3 = spawnPoints - num2; user = ((TwitchMessage)(ref twitchMessage)).User; TwitchIntegrationManager.SetSpawnPoints(((TwitchUser)(ref user)).Username, num3); TwitchIntegrationManager.SpawnPointsUsedThisDay += num2; string arg = ((num2 == 1) ? "" : "s"); string spawnReason = $"by redeeming {num2} spawn point{arg} ({num3} remaining)"; user = ((TwitchMessage)(ref twitchMessage)).User; string userId = ((TwitchUser)(ref user)).UserId; user = ((TwitchMessage)(ref twitchMessage)).User; string displayName = ((TwitchUser)(ref user)).DisplayName; user = ((TwitchMessage)(ref twitchMessage)).User; ViewerData viewer = new ViewerData(userId, displayName, ((TwitchUser)(ref user)).Color); ViewerSpawnEvent viewerSpawnEvent = new ViewerSpawnEvent(viewer, num2, spawnReason); Logger.LogInfo("TwitchSpawnCommand:\n" + JsonConvert.SerializeObject((object)viewerSpawnEvent), extended: true); ViewerSpawnEventHandler.Instance?.ExecuteViewerSpawnEventServerRpc(viewerSpawnEvent); return true; } } internal class TwitchViewAllBitsCommand : TwitchCommand { public override bool IsCommand(TwitchMessage twitchMessage) { if (((TwitchMessage)(ref twitchMessage)).Message.Equals("!viewallbits", StringComparison.OrdinalIgnoreCase)) { return true; } return false; } protected override bool Execute(TwitchMessage twitchMessage) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) if (!TwitchCommand.IsModeratorOrHigher(((TwitchMessage)(ref twitchMessage)).User)) { return false; } if (TwitchIntegrationManager.AccumulatedBits.Count == 0) { MessageCanvas.Instance?.ShowMessage_LocalClient("Nobody has accumulated any bits"); return false; } int columns = 1; if (TwitchIntegrationManager.AccumulatedBits.Count >= 20) { columns = 3; } else if (TwitchIntegrationManager.AccumulatedBits.Count >= 10) { columns = 2; } Dictionary<string, int> keyValuePair = TwitchIntegrationManager.AccumulatedBits.OrderByDescending((KeyValuePair<string, int> x) => x.Value).ToDictionary((KeyValuePair<string, int> a) => a.Key, (KeyValuePair<string, int> b) => b.Value); MessageCanvas.Instance?.ShowMessage_LocalClient(Utils.GetFormattedKeyValuePairMessage(keyValuePair, columns, "{key} {value} bits")); return true; } } internal class TwitchViewAllSpawnCommand : TwitchCommand { public override bool IsCommand(TwitchMessage twitchMessage) { if (((TwitchMessage)(ref twitchMessage)).Message.Equals("!viewallspawn", StringComparison.OrdinalIgnoreCase)) { return true; } return false; } protected override bool Execute(TwitchMessage twitchMessage) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (!ConfigManager.SpawnPoints_Enabled.Value) { return false; } if (!TwitchCommand.IsModeratorOrHigher(((TwitchMessage)(ref twitchMessage)).User)) { return false; } if (TwitchIntegrationManager.SpawnPoints.Count == 0) { MessageCanvas.Instance?.ShowMessage_LocalClient("Nobody has spawn points"); return false; } int columns = 1; if (TwitchIntegrationManager.SpawnPoints.Count >= 20) { columns = 3; } else if (TwitchIntegrationManager.SpawnPoints.Count >= 10) { columns = 2; } Dictionary<string, int> keyValuePair = TwitchIntegrationManager.SpawnPoints.OrderByDescending((KeyValuePair<string, int> x) => x.Value).ToDictionary((KeyValuePair<string, int> a) => a.Key, (KeyValuePair<string, int> b) => b.Value); MessageCanvas.Instance?.ShowMessage_LocalClient(Utils.GetFormattedKeyValuePairMessage(keyValuePair, columns, "{key} {value} sp")); return true; } } internal class TwitchViewBitsCommand : TwitchCommand { public override bool IsCommand(TwitchMessage twitchMessage) { if (((TwitchMessage)(ref twitchMessage)).Message.StartsWith("!viewbits", StringComparison.OrdinalIgnoreCase)) { return true; } return false; } protected override bool Execute(TwitchMessage twitchMessage) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) TwitchUser user = ((TwitchMessage)(ref twitchMessage)).User; string text = ((TwitchUser)(ref user)).DisplayName; user = ((TwitchMessage)(ref twitchMessage)).User; string hexColor = ((TwitchUser)(ref user)).Color; string[] array = ((TwitchMessage)(ref twitchMessage)).Message.Split(' '); if (array.Length > 1) { text = array[1].Replace("@", ""); hexColor = "#FFFFFF"; TwitchUser val = default(TwitchUser); if (API.TryGetUserByUsername(text, ref val)) { text = ((TwitchUser)(ref val)).DisplayName; hexColor = ((TwitchUser)(ref val)).Color; } } int accumulatedBits = TwitchIntegrationManager.GetAccumulatedBits(text); MessageCanvas.Instance?.ShowMessage_LocalClient($"{Utils.GetTextWithColor(text, hexColor)} has {accumulatedBits} accumulated bits"); return true; } } internal class TwitchViewSpawnCommand : TwitchCommand { public override bool IsCommand(TwitchMessage twitchMessage) { if (((TwitchMessage)(ref twitchMessage)).Message.StartsWith("!viewspawn", StringComparison.OrdinalIgnoreCase)) { return true; } return false; } protected override bool Execute(TwitchMessage twitchMessage) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) if (!ConfigManager.SpawnPoints_Enabled.Value) { return false; } TwitchUser user = ((TwitchMessage)(ref twitchMessage)).User; string text = ((TwitchUser)(ref user)).DisplayName; user = ((TwitchMessage)(ref twitchMessage)).User; string hexColor = ((TwitchUser)(ref user)).Color; string[] array = ((TwitchMessage)(ref twitchMessage)).Message.Split(' '); if (array.Length > 1) { text = array[1].Replace("@", ""); hexColor = "#FFFFFF"; TwitchUser val = default(TwitchUser); if (API.TryGetUserByUsername(text, ref val)) { text = ((TwitchUser)(ref val)).DisplayName; hexColor = ((TwitchUser)(ref val)).Color; } } int spawnPoints = TwitchIntegrationManager.GetSpawnPoints(text); string arg = ((spawnPoints == 1) ? "" : "s"); MessageCanvas.Instance?.ShowMessage_LocalClient($"{Utils.GetTextWithColor(text, hexColor)} has {spawnPoints} spawn point{arg}"); return true; } } } namespace com.github.zehsteam.MonsterHotkeys.Patches { [HarmonyPatch(typeof(ButlerEnemyAI))] internal static class ButlerEnemyAIPatch { [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> ButlerBlowUpAndPopTranspiler(IEnumerable<CodeInstruction> instructions) { //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Expected O, but got Unknown //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Expected O, but got Unknown MethodInfo method = typeof(RoundManager).GetMethod("SpawnEnemyGameObject"); MethodInfo method2 = typeof(ButlerHelper).GetMethod("SpawnButlerBees"); if (method == null || method2 == null) { Logger.LogError("[ButlerEnemyAIPatch] Failed to find required methods for transpiler."); return instructions; } List<CodeInstruction> list = new List<CodeInstruction>(); foreach (CodeInstruction instruction in instructions) { if ((instruction.opcode == OpCodes.Call || instruction.opcode == OpCodes.Callvirt) && instruction.operand is MethodInfo methodInfo && methodInfo == method) { list.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Add(new CodeInstruction(OpCodes.Call, (object)method2)); Logger.LogInfo("[ButlerEnemyAIPatch] Replaced " + method.Name + " call with " + method2.Name + ".", extended: true); } else { list.Add(instruction); } } return list.AsEnumerable(); } } [HarmonyPatch(typeof(EnemyAI))] internal static class EnemyAIPatch { [HarmonyPatch("KillEnemy")] [HarmonyPrefix] private static void KillEnemyPatchPrefix(ref EnemyAI __instance) { if (__instance.enemyType.canDie) { EnemyNametagManager.Instance?.DisableNametag_LocalClient(__instance); } } [HarmonyPatch("OnDestroy")] [HarmonyPostfix] private static void OnDestroyPatch(ref EnemyAI __instance) { EnemyNametagManager.Instance?.DespawnNametag_LocalClient(__instance); } } [HarmonyPatch(typeof(GameNetworkManager))] internal static class GameNetworkManagerPatch { [HarmonyPatch("Start")] [HarmonyPostfix] private static void StartPatch() { AddNetworkPrefabs(); } private static void AddNetworkPrefabs() { AddNetworkPrefab(Assets.NetworkHandlerPrefab); } private static void AddNetworkPrefab(GameObject prefab) { if ((Object)(object)prefab == (Object)null) { Logger.LogError("Failed to register network prefab. GameObject is null."); return; } NetworkManager.Singleton.AddNetworkPrefab(prefab); Logger.LogInfo("Registered \"" + ((Object)prefab).name + "\" network prefab."); } } [HarmonyPatch(typeof(HUDManager))] internal static class HUDManagerPatch { [HarmonyPatch("Start")] [HarmonyPostfix] private static void StartPatch() { MessageCanvas.Spawn(); } } [HarmonyPatch(typeof(Landmine))] internal static class LandminePatch { [HarmonyPatch("SpawnExplosion")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> SpawnExplosionTranspiler(IEnumerable<CodeInstruction> instructions) { //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Expected O, but got Unknown //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Expected O, but got Unknown //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Expected O, but got Unknown //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Expected O, but got Unknown MethodInfo method = typeof(PlayerControllerB).GetMethod("DamagePlayer"); MethodInfo method2 = typeof(PlayerControllerB).GetMethod("KillPlayer"); MethodInfo method3 = typeof(PlayerHelper).GetMethod("DamagePlayerWithCaller"); MethodInfo method4 = typeof(PlayerHelper).GetMethod("KillPlayerWithCaller"); MethodInfo methodInfo = typeof(LandmineHelper).GetProperty("SpawnExplosionCaller")?.GetGetMethod(); if (method == null || method2 == null || method3 == null || method4 == null || methodInfo == null) { Logger.LogError("[LandminePatch] Failed to find required methods for transpiler."); return instructions; } List<CodeInstruction> list = new List<CodeInstruction>(); foreach (CodeInstruction instruction in instructions) { if ((instruction.opcode == OpCodes.Call || instruction.opcode == OpCodes.Callvirt) && instruction.operand is MethodInfo methodInfo2) { if (methodInfo2 == method) { list.Add(new CodeInstruction(OpCodes.Call, (object)methodInfo)); list.Add(new CodeInstruction(OpCodes.Call, (object)method3)); Logger.LogInfo("[LandminePatch] Replaced DamagePlayer call with " + method3.Name + ".", extended: true); continue; } if (methodInfo2 == method2) { list.Add(new CodeInstruction(OpCodes.Call, (object)metho