Decompiled source of MonsterHotkeys v2.3.1

com.github.zehsteam.MonsterHotkeys.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
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 ControlValley;
using DunGen;
using DunGen.Graph;
using GameNetcodeStuff;
using HarmonyLib;
using LethalCompanyInputUtils.Api;
using LethalCompanyTestMod;
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 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;
using com.github.zehsteam.TwitchChatAPI;
using com.github.zehsteam.TwitchChatAPI.Objects;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("com.github.zehsteam.MonsterHotkeys")]
[assembly: AssemblyConfiguration("Debug")]
[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.3.1.0")]
[assembly: AssemblyInformationalVersion("2.3.1+51a65cde01ebbcc64cf28c5bff711b944be0c129")]
[assembly: AssemblyProduct("MonsterHotkeys")]
[assembly: AssemblyTitle("com.github.zehsteam.MonsterHotkeys")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.3.1.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
{
	public class ConfigManager
	{
		public ConfigEntry<bool> ExtendedLogging { get; private set; }

		public ConfigEntry<bool> Enemy_OnlyHostSpawnEnemies { get; private set; }

		public ConfigEntry<bool> Enemy_MuteSpawnSFX { get; private set; }

		public ConfigEntry<bool> Enemy_SpawnStunned { get; private set; }

		public ConfigEntry<float> Enemy_StunDuration { get; private set; }

		public SyncedConfigEntry<int> Plushie_SpawnCount { get; private set; }

		public SyncedConfigEntry<float> Plushie_DespawnDuration { get; private set; }

		public ConfigEntry<float> Plushie_SFXVolume { get; private set; }

		public ConfigEntry<bool> Plushie_PlaySFXOnCollision { get; private set; }

		public SyncedConfigEntry<bool> Plushie_AttractDogs { get; private set; }

		public SyncedConfigEntry<float> Plushie_Scale { get; private set; }

		public ConfigEntry<bool> Message_ShowMessages { get; private set; }

		public ConfigEntry<bool> Message_ShowSpawnEnemyMessages { get; private set; }

		public ConfigEntry<bool> Message_ShowLocalSpawnEnemyMessages { get; private set; }

		public ConfigEntry<bool> Message_ShowDetailedTwitchEventSpawnEnemyMessages { get; private set; }

		public ConfigEntry<float> Message_Duration { get; private set; }

		public ConfigEntry<int> Message_FontSize { get; private set; }

		public ConfigEntry<int> Message_BackgroundTransparency { get; private set; }

		public ConfigEntry<bool> CrowdControl_Enabled { get; private set; }

		public ConfigEntry<bool> CrowdControl_RewardSpawnPoints { get; private set; }

		public ConfigEntry<bool> TwitchIntegration_Enabled { get; private set; }

		public ConfigEntry<bool> TwitchIntegration_SpawnAllOfTheSameEnemy { get; private set; }

		public ConfigEntry<bool> TwitchSubEvent_Enabled { get; private set; }

		public ConfigEntry<int> TwitchSubEvent_EnemiesPerSub { get; private set; }

		public ConfigEntry<int> TwitchSubEvent_Tier2EnemyMultiplier { get; private set; }

		public ConfigEntry<int> TwitchSubEvent_Tier3EnemyMultiplier { get; private set; }

		public ConfigEntry<bool> TwitchCheerEvent_Enabled { get; private set; }

		public ConfigEntry<int> TwitchCheerEvent_AmountToSpawnEnemy { get; private set; }

		public ConfigEntry<int> TwitchCheerEvent_AmountToSpawnPlushies { get; private set; }

		public ConfigEntry<bool> TwitchRaidEvent_Enabled { get; private set; }

		public ConfigEntry<int> TwitchRaidEvent_ViewersPerEnemy { get; private set; }

		public ConfigEntry<int> TwitchRaidEvent_MaxSpawnCount { get; private set; }

		public ConfigEntry<bool> SpawnPoints_Enabled { get; private set; }

		public ConfigEntry<int> SpawnPoints_MaxSpawnsPerDay { get; private set; }

		public ConfigEntry<int> SpawnPoints_RewardPointsPerDeath { get; private set; }

		public ConfigEntry<int> SpawnPoints_RewardPointsPerCrewmateDeath { get; private set; }

		public ConfigEntry<bool> EnemyNametag_Enabled { get; private set; }

		public ConfigEntry<bool> EnemyNametag_ShowPlatform { get; private set; }

		public ConfigEntry<float> EnemyNametag_ScaleMultiplier { get; private set; }

		public ConfigEntry<int> EnemyNametag_BackgroundTransparency { get; private set; }

		public ConfigManager()
		{
			BindConfigs();
			MigrateOldConfigSettings();
		}

		private 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.");
			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 void MigrateOldConfigSettings()
		{
			foreach (KeyValuePair<ConfigDefinition, string> orphanedConfigEntry in ConfigHelper.GetOrphanedConfigEntries())
			{
				MigrateOldConfigSetting(orphanedConfigEntry.Key.Section, orphanedConfigEntry.Key.Key, orphanedConfigEntry.Value);
			}
		}

		private void MigrateOldConfigSetting(string section, string key, string value)
		{
			StringComparison comparisonType = StringComparison.OrdinalIgnoreCase;
			if (section.Equals("General Settings", comparisonType) && key.Equals("ExtendedLogging", comparisonType))
			{
				ConfigHelper.SetConfigEntryValue<bool>(ExtendedLogging, value);
				return;
			}
			if (section.Equals("Monster Settings", comparisonType))
			{
				if (key.Equals("OnlyHostSpawnMonsters", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue<bool>(Enemy_OnlyHostSpawnEnemies, value);
					return;
				}
				if (key.Equals("MuteSpawnSFX", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue<bool>(Enemy_MuteSpawnSFX, value);
					return;
				}
				if (key.Equals("SpawnStunned", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue<bool>(Enemy_SpawnStunned, value);
					return;
				}
				if (key.Equals("StunDuration", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue<float>(Enemy_StunDuration, value);
					return;
				}
			}
			if (section.Equals("Plushie Settings", comparisonType))
			{
				if (key.Equals("SpawnCount", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue(Plushie_SpawnCount, value);
					return;
				}
				if (key.Equals("DespawnDuration", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue(Plushie_DespawnDuration, value);
					return;
				}
				if (key.Equals("SFXVolume", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue<float>(Plushie_SFXVolume, value);
					return;
				}
				if (key.Equals("PlaySFXOnCollision", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue<bool>(Plushie_PlaySFXOnCollision, value);
					return;
				}
				if (key.Equals("AttractDogs", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue(Plushie_AttractDogs, value);
					return;
				}
				if (key.Equals("Scale", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue(Plushie_Scale, value);
					return;
				}
			}
			if (section.Equals("Message Settings", comparisonType))
			{
				if (key.Equals("ShowMessages", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue<bool>(Message_ShowMessages, value);
					return;
				}
				if (key.Equals("ShowSpawnEnemyMessages", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue<bool>(Message_ShowSpawnEnemyMessages, value);
					return;
				}
				if (key.Equals("ShowLocalSpawnEnemyMessages", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue<bool>(Message_ShowLocalSpawnEnemyMessages, value);
					return;
				}
				if (key.Equals("ShowDetailedTwitchEventSpawnEnemyMessages", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue<bool>(Message_ShowDetailedTwitchEventSpawnEnemyMessages, value);
					return;
				}
				if (key.Equals("Duration", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue<float>(Message_Duration, value);
					return;
				}
				if (key.Equals("FontSize", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue<int>(Message_FontSize, value);
					return;
				}
				if (key.Equals("BackgroundTransparency", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue<int>(Message_BackgroundTransparency, value);
					return;
				}
			}
			if (section.Equals("Crowd Control Integration Settings", comparisonType) && key.Equals("Enabled", comparisonType))
			{
				ConfigHelper.SetConfigEntryValue<bool>(CrowdControl_Enabled, value);
				return;
			}
			if (section.Equals("Twitch Integration Settings", comparisonType) && key.Equals("Enabled", comparisonType))
			{
				ConfigHelper.SetConfigEntryValue<bool>(TwitchIntegration_Enabled, value);
				return;
			}
			if (section.Equals("Twitch Integration", comparisonType))
			{
				if (key.Equals("SpawnPointsEnabled", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue<bool>(SpawnPoints_Enabled, value);
					return;
				}
				if (key.Equals("SpawnPointsPerDeath", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue<int>(SpawnPoints_RewardPointsPerDeath, value);
					return;
				}
			}
			if (section.Equals("Twitch Subs Event Settings", comparisonType))
			{
				if (key.Equals("Enabled", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue<bool>(TwitchSubEvent_Enabled, value);
					return;
				}
				if (key.Equals("SpawnAllOfTheSameEnemy", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue<bool>(TwitchIntegration_SpawnAllOfTheSameEnemy, value);
					return;
				}
			}
			if (section.Equals("Twitch Bits Event Settings", comparisonType))
			{
				if (key.Equals("Enabled", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue<bool>(TwitchCheerEvent_Enabled, value);
					return;
				}
				if (key.Equals("MinAmountToSpawnMonster", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue<int>(TwitchCheerEvent_AmountToSpawnEnemy, value);
					return;
				}
				if (key.Equals("MinAmountToSpawnPlushies", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue<int>(TwitchCheerEvent_AmountToSpawnPlushies, value);
					return;
				}
			}
			if (section.Equals("Enemy Nametag Settings", comparisonType))
			{
				if (key.Equals("Enabled", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue<bool>(EnemyNametag_Enabled, value);
				}
				else if (key.Equals("ShowPlatform", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue<bool>(EnemyNametag_ShowPlatform, value);
				}
				else if (key.Equals("ScaleMultiplier", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue<float>(EnemyNametag_ScaleMultiplier, value);
				}
				else if (key.Equals("BackgroundTransparency", comparisonType))
				{
					ConfigHelper.SetConfigEntryValue<int>(EnemyNametag_BackgroundTransparency, value);
				}
			}
		}
	}
	internal static class Content
	{
		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()
		{
			LoadAssetsFromAssetBundle();
		}

		private static void LoadAssetsFromAssetBundle()
		{
			AssetBundle val = LoadAssetBundle("monsterhotkeys_assets");
			if (!((Object)(object)val == (Object)null))
			{
				NetworkHandlerPrefab = LoadAssetFromAssetBundle<GameObject>("NetworkHandler", val);
				MessageCanvasPrefab = LoadAssetFromAssetBundle<GameObject>("MonsterHotkeysCanvas", val);
				EnemyDataList = LoadAssetFromAssetBundle<EnemyDataList>("EnemyDataList", val);
				Plugin.Logger.LogInfo((object)"Successfully loaded assets from AssetBundle!");
			}
		}

		private static AssetBundle LoadAssetBundle(string fileName)
		{
			try
			{
				string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)Plugin.Instance).Info.Location);
				string text = Path.Combine(directoryName, fileName);
				return AssetBundle.LoadFromFile(text);
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Failed to load AssetBundle \"{fileName}\". {arg}");
			}
			return null;
		}

		private static T LoadAssetFromAssetBundle<T>(string name, AssetBundle assetBundle) where T : Object
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				Plugin.Logger.LogError((object)("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)
			{
				Plugin.Logger.LogError((object)("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)
			{
				Plugin.Logger.LogError((object)("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;
		}
	}
	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;
			Plugin.Logger.LogInfo((object)"Setup keybind callbacks.");
		}

		private static void OnSpawnKeyPressed(CallbackContext context)
		{
			//IL_0075: 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;
			Plugin.Instance.LogInfoExtended(name + " key pressed.");
			if (!Utils.CanPerformHotkeys())
			{
				return;
			}
			if (DisableHotkeys && (IsMonsterPrefixKeyPressed || IsPlushiePrefixKeyPressed))
			{
				MessageCanvas.Instance.ShowMessage_LocalClient("Hotkeys have been disabled by another mod", Color.red);
				Plugin.Logger.LogInfo((object)"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 = Content.EnemyDataList.GetByEnemyName(text);
			if (byEnemyName == null)
			{
				Plugin.Logger.LogError((object)("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_006c: Unknown result type (might be due to invalid IL or missing references)
			if (!((CallbackContext)(ref context)).performed)
			{
				return;
			}
			Plugin.Instance.LogInfoExtended(((CallbackContext)(ref context)).action.name + " key pressed.");
			if (!Utils.CanPerformHotkeys())
			{
				return;
			}
			if (DisableHotkeys && (IsMonsterPrefixKeyPressed || IsPlushiePrefixKeyPressed))
			{
				MessageCanvas.Instance.ShowMessage_LocalClient("Hotkeys have been disabled by another mod", Color.red);
				Plugin.Logger.LogInfo((object)"Hotkeys have been disabled by another mod.");
				return;
			}
			if (IsMonsterPrefixKeyPressed)
			{
				EnemyHelper.SpawnRandomEnemy();
			}
			if (IsPlushiePrefixKeyPressed)
			{
				PlushieManager.Instance.SpawnRandomPlushies();
			}
		}
	}
	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.3.1")]
	[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 ManualLogSource Logger { get; private set; }

		internal static ConfigManager ConfigManager { get; private set; }

		internal static HotkeyInputClass InputActionsInstance { get; private set; }

		private void Awake()
		{
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = this;
			}
			Logger = Logger.CreateLogSource("com.github.zehsteam.MonsterHotkeys");
			Logger.LogInfo((object)"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);
			}
			Content.Load();
			ConfigManager = new ConfigManager();
			InputActionsInstance = new HotkeyInputClass();
			HotkeyListener.SetupKeybindCallbacks();
			Content.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)
								{
									Logger.LogWarning((object)("Failed to invoke method " + methodInfo.Name + ": " + ex.Message));
								}
							}
						}
						catch (Exception ex2)
						{
							Logger.LogWarning((object)("Error processing method " + methodInfo.Name + " in type " + type.Name + ": " + ex2.Message));
						}
					}
				}
			}
			catch (Exception ex3)
			{
				Logger.LogError((object)("An error occurred in NetcodePatcherAwake: " + ex3.Message));
			}
		}

		public void OnNewLevelLoaded()
		{
			InteriorHelper.SetInteriorType();
			EnemyNametagManager.Instance?.Reset();
		}

		public void SpawnMessageCanvas()
		{
			if (!((Object)(object)MessageCanvas.Instance != (Object)null))
			{
				Object.Instantiate<GameObject>(Content.MessageCanvasPrefab);
			}
		}

		public void LogInfoExtended(object data)
		{
			LogExtended((LogLevel)16, data);
		}

		public void LogWarningExtended(object data)
		{
			LogExtended((LogLevel)4, data);
		}

		public void LogExtended(LogLevel level, object data)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			if (ConfigManager == null || ConfigManager.ExtendedLogging == null)
			{
				Logger.Log(level, data);
			}
			else if (ConfigManager.ExtendedLogging.Value)
			{
				Logger.Log(level, data);
			}
		}
	}
	internal static class Utils
	{
		public static string GetEnumName<T>(T e) where T : Enum
		{
			return Enum.GetName(typeof(T), e) ?? string.Empty;
		}

		public static string GetPluginDirectoryPath()
		{
			return Path.GetDirectoryName(((BaseUnityPlugin)Plugin.Instance).Info.Location);
		}

		public static string GetConfigDirectoryPath()
		{
			return Paths.ConfigPath;
		}

		public static string GetGlobalConfigDirectoryPath()
		{
			return Path.Combine(Application.persistentDataPath, "MonsterHotkeys");
		}

		public static ConfigFile CreateConfigFile(string directoryPath, string name = null, bool saveOnInit = false)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			BepInPlugin metadata = MetadataHelper.GetMetadata((object)Plugin.Instance);
			if (name == null)
			{
				name = metadata.GUID;
			}
			name += ".cfg";
			return new ConfigFile(Path.Combine(directoryPath, name), saveOnInit, metadata);
		}

		public static ConfigFile CreateLocalConfigFile(string name = null, bool saveOnInit = false)
		{
			if (name == null)
			{
				name = "com.github.zehsteam.MonsterHotkeys-" + name;
			}
			return CreateConfigFile(Paths.ConfigPath, name, saveOnInit);
		}

		public static ConfigFile CreateGlobalConfigFile(string name = null, bool saveOnInit = false)
		{
			if (name == null)
			{
				name = "global";
			}
			return CreateConfigFile(GetGlobalConfigDirectoryPath(), 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;
				Plugin.Instance.LogInfoExtended($"Call stack depth {i}: {declaringType}.{name}");
			}
		}

		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);
			}
			Plugin.Logger.LogError((object)("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 class MyPluginInfo
	{
		public const string PLUGIN_GUID = "com.github.zehsteam.MonsterHotkeys";

		public const string PLUGIN_NAME = "MonsterHotkeys";

		public const string PLUGIN_VERSION = "2.3.1";
	}
}
namespace com.github.zehsteam.MonsterHotkeys.Twitch
{
	internal static class TwitchIntegrationManager
	{
		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 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)
			{
				Plugin.Logger.LogError((object)$"Failed to initialize TwitchIntegrationManager. {arg}");
			}
		}

		private static void LoadData()
		{
			Plugin.Logger.LogInfo((object)"Loading saved TwitchIntegrationManager data...");
			try
			{
				if (SaveHelper.TryLoadValue<string>("CheerQueue", SaveLocation.Global, out var value))
				{
					Plugin.Instance.LogInfoExtended("Loaded CheerQueue JSON data:\n\n" + value);
					CheerQueue = JsonConvert.DeserializeObject<List<TwitchCheerEvent>>(value);
				}
				if (SaveHelper.TryLoadValue<string>("SubQueue", SaveLocation.Global, out value))
				{
					Plugin.Instance.LogInfoExtended("Loaded SubQueue JSON data:\n\n" + value);
					SubQueue = JsonConvert.DeserializeObject<List<TwitchSubEvent>>(value);
				}
				if (SaveHelper.TryLoadValue<string>("RaidQueue", SaveLocation.Global, out value))
				{
					Plugin.Instance.LogInfoExtended("Loaded RaidQueue JSON data:\n\n" + value);
					RaidQueue = JsonConvert.DeserializeObject<List<TwitchRaidEvent>>(value);
				}
				if (SaveHelper.TryLoadValue<string>("AccumulatedBits", SaveLocation.Global, out value))
				{
					Plugin.Instance.LogInfoExtended("Loaded AccumulatedBits JSON data:\n\n" + value);
					AccumulatedBits = JsonConvert.DeserializeObject<Dictionary<string, int>>(value);
				}
				if (SaveHelper.TryLoadValue<string>("SpawnPoints", SaveLocation.Global, out value))
				{
					Plugin.Instance.LogInfoExtended("Loaded SpawnPoints JSON data:\n\n" + value);
					SpawnPoints = JsonConvert.DeserializeObject<Dictionary<string, int>>(value);
				}
				Plugin.Logger.LogInfo((object)"Finished loading saved TwitchIntegrationManager data.");
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Failed to load TwitchIntegrationManager save data. {arg}");
			}
		}

		public static void SaveData()
		{
			try
			{
				SaveHelper.SaveValue("CheerQueue", JsonConvert.SerializeObject((object)CheerQueue), SaveLocation.Global);
				SaveHelper.SaveValue("SubQueue", JsonConvert.SerializeObject((object)SubQueue), SaveLocation.Global);
				SaveHelper.SaveValue("RaidQueue", JsonConvert.SerializeObject((object)RaidQueue), SaveLocation.Global);
				SaveHelper.SaveValue("AccumulatedBits", JsonConvert.SerializeObject((object)AccumulatedBits), SaveLocation.Global);
				SaveHelper.SaveValue("SpawnPoints", JsonConvert.SerializeObject((object)SpawnPoints), SaveLocation.Global);
				Plugin.Logger.LogInfo((object)"Saved TwitchIntegrationManager data.");
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Failed to save TwitchIntegrationManager data. {arg}");
			}
		}

		public static void PlayQueue(float initialDelay = 0f)
		{
			if (!Plugin.ConfigManager.TwitchIntegration_Enabled.Value)
			{
				return;
			}
			if ((Object)(object)ViewerSpawnEventHandler.Instance == (Object)null)
			{
				Plugin.Logger.LogWarning((object)"Failed to play Twitch event queue. ViewerSpawnEventHandler instance is null.");
				return;
			}
			if (_isPlayingQueue)
			{
				Plugin.Logger.LogWarning((object)"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));
		}

		private static IEnumerator PlayQueueCoroutine(float initialDelay = 0f)
		{
			_isPlayingQueue = true;
			Plugin.Instance.LogInfoExtended("Started Twitch event queue.");
			yield return (object)new WaitForSeconds(initialDelay);
			if (!CanExecuteEvents())
			{
				Plugin.Instance.LogInfoExtended("Finished Twitch event queue. No events could be executed.");
				_isPlayingQueue = false;
				yield break;
			}
			if (SubQueue.Count > 0 || CheerQueue.Count > 0 || RaidQueue.Count > 0)
			{
				MessageCanvas.Instance?.ShowMessage_LocalClient("Playing Twitch events from the queue");
			}
			float delay = 0.5f;
			while (SubQueue.Count > 0 && CanExecuteEvents())
			{
				TwitchSubEvent twitchSubEvent = SubQueue[0];
				SubQueue.RemoveAt(0);
				HandleSub(twitchSubEvent);
				yield return (object)new WaitForSeconds(delay);
			}
			while (CheerQueue.Count > 0 && CanExecuteEvents())
			{
				TwitchCheerEvent twitchCheerEvent = CheerQueue[0];
				CheerQueue.RemoveAt(0);
				HandleCheer(twitchCheerEvent);
				yield return (object)new WaitForSeconds(delay);
			}
			while (RaidQueue.Count > 0 && CanExecuteEvents())
			{
				TwitchRaidEvent twitchRaidEvent = RaidQueue[0];
				RaidQueue.RemoveAt(0);
				HandleRaid(twitchRaidEvent);
				yield return (object)new WaitForSeconds(delay);
			}
			Plugin.Instance.LogInfoExtended("Finished Twitch event queue.");
			SaveData();
			_isPlayingQueue = false;
		}

		private static void HandleMessage(TwitchMessage twitchMessage)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.ConfigManager.TwitchIntegration_Enabled.Value)
			{
				TwitchCommandManager.ExecuteCommand(twitchMessage);
			}
		}

		private static void HandleCheer(TwitchCheerEvent cheerEvent)
		{
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: 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_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.ConfigManager.TwitchIntegration_Enabled.Value || !Plugin.ConfigManager.TwitchCheerEvent_Enabled.Value)
			{
				return;
			}
			if (cheerEvent == null)
			{
				Plugin.Logger.LogError((object)"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 == Plugin.ConfigManager.TwitchCheerEvent_AmountToSpawnPlushies.Value)
			{
				Plugin.Instance.LogInfoExtended("HandleCheer:\n" + JsonConvert.SerializeObject((object)viewerData));
				PlushieManager.Instance?.SpawnPlushiesFromViewer(viewerData, $"by cheering {cheerEvent.CheerAmount} bits");
				return;
			}
			int accumulatedBits = GetAccumulatedBits(viewerData);
			int num = cheerEvent.CheerAmount + accumulatedBits;
			int value = Plugin.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);
			Plugin.Instance.LogInfoExtended("HandleCheer:\n" + JsonConvert.SerializeObject((object)viewerSpawnEvent));
			ViewerSpawnEventHandler.Instance?.ExecuteViewerSpawnEventServerRpc(viewerSpawnEvent);
		}

		private static void HandleSub(TwitchSubEvent subEvent)
		{
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Invalid comparison between Unknown and I4
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Invalid comparison between Unknown and I4
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Invalid comparison between Unknown and I4
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Invalid comparison between Unknown and I4
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Invalid comparison between Unknown and I4
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0282: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.ConfigManager.TwitchIntegration_Enabled.Value || !Plugin.ConfigManager.TwitchSubEvent_Enabled.Value)
			{
				return;
			}
			if (subEvent == null)
			{
				Plugin.Logger.LogError((object)"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 = Plugin.ConfigManager.TwitchSubEvent_EnemiesPerSub.Value;
			if ((int)subEvent.SubType == 3)
			{
				num *= subEvent.GiftCount;
			}
			if (subEvent.Tier == 2)
			{
				num *= Plugin.ConfigManager.TwitchSubEvent_Tier2EnemyMultiplier.Value;
			}
			else if (subEvent.Tier == 3)
			{
				num *= Plugin.ConfigManager.TwitchSubEvent_Tier3EnemyMultiplier.Value;
			}
			string spawnReason = string.Empty;
			if ((int)subEvent.SubType == 0)
			{
				spawnReason = ((!subEvent.IsPrime) ? $"by subbing at tier {subEvent.Tier}" : "by subbing with prime");
			}
			else if ((int)subEvent.SubType == 1)
			{
				spawnReason = ((!subEvent.IsPrime) ? $"by resubbing at tier {subEvent.Tier} for {subEvent.Months} months" : "by resubbing with prime");
			}
			else if ((int)subEvent.SubType == 2)
			{
				spawnReason = $"by gifting a tier {subEvent.Tier} sub to {subEvent.RecipientUser}";
			}
			else if ((int)subEvent.SubType == 3)
			{
				spawnReason = $"by gifting {subEvent.GiftCount} tier {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);
			Plugin.Instance.LogInfoExtended("HandleSub:\n" + JsonConvert.SerializeObject((object)viewerSpawnEvent));
			ViewerSpawnEventHandler.Instance?.ExecuteViewerSpawnEventServerRpc(viewerSpawnEvent);
		}

		private static void HandleRaid(TwitchRaidEvent raidEvent)
		{
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: 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_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: 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)
			if (Plugin.ConfigManager.TwitchIntegration_Enabled.Value && Plugin.ConfigManager.TwitchRaidEvent_Enabled.Value)
			{
				if (raidEvent == null)
				{
					Plugin.Logger.LogError((object)"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 = Plugin.ConfigManager.TwitchRaidEvent_ViewersPerEnemy.Value;
				int value2 = Plugin.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);
				Plugin.Instance.LogInfoExtended("HandleRaid:\n" + JsonConvert.SerializeObject((object)viewerSpawnEvent));
				ViewerSpawnEventHandler.Instance?.ExecuteViewerSpawnEventServerRpc(viewerSpawnEvent);
			}
		}

		public static int GetAccumulatedBits(ViewerData viewer)
		{
			if (viewer == null)
			{
				return 0;
			}
			return GetAccumulatedBits(viewer.DisplayName);
		}

		public static int GetAccumulatedBits(string displayName)
		{
			return AccumulatedBits.GetValueOrDefault(displayName.ToLower(), 0);
		}

		public static void SetAccumulatedBits(ViewerData viewer, int value)
		{
			if (viewer != null)
			{
				if (value <= 0)
				{
					AccumulatedBits.Remove(viewer.DisplayName.ToLower());
				}
				else
				{
					AccumulatedBits[viewer.DisplayName.ToLower()] = value;
				}
				SaveData();
			}
		}

		public static void RewardSpawnPointsFromDeath(EnemyNametagType nametagType, string displayName, string color)
		{
			if (!Plugin.ConfigManager.TwitchIntegration_Enabled.Value || !Plugin.ConfigManager.SpawnPoints_Enabled.Value)
			{
				return;
			}
			switch (nametagType)
			{
			case EnemyNametagType.Default:
				return;
			case EnemyNametagType.CrowdControl:
				if (!Plugin.ConfigManager.CrowdControl_RewardSpawnPoints.Value)
				{
					return;
				}
				break;
			}
			int value = Plugin.ConfigManager.SpawnPoints_RewardPointsPerDeath.Value;
			if (value > 0)
			{
				AddSpawnPoints(displayName, value);
				int spawnPoints = GetSpawnPoints(displayName);
				string text = ((value == 1) ? "" : "s");
				MessageCanvas.Instance?.ShowMessage_LocalClient(string.Format("<color={0}>{1}</color> just earned {2} spawn point{3} ({4} total) {5}", color, displayName, 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 (!Plugin.ConfigManager.TwitchIntegration_Enabled.Value || !Plugin.ConfigManager.SpawnPoints_Enabled.Value || NetworkUtils.IsLocalClientId(senderClientId))
			{
				return;
			}
			switch (nametagType)
			{
			case EnemyNametagType.Default:
				return;
			case EnemyNametagType.CrowdControl:
				if (!Plugin.ConfigManager.CrowdControl_RewardSpawnPoints.Value)
				{
					return;
				}
				break;
			}
			int value = Plugin.ConfigManager.SpawnPoints_RewardPointsPerCrewmateDeath.Value;
			if (value > 0)
			{
				PlayerControllerB playerScriptByClientId = PlayerUtils.GetPlayerScriptByClientId(senderClientId);
				if (!((Object)(object)playerScriptByClientId == (Object)null))
				{
					AddSpawnPoints(displayName, value);
					int spawnPoints = GetSpawnPoints(displayName);
					string text = ((value == 1) ? "" : "s");
					MessageCanvas.Instance?.ShowMessage_LocalClient(string.Format("<color={0}>{1}</color> just earned {2} spawn point{3} by killing {4} ({5} total) {6}", color, displayName, 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.DisplayName);
		}

		public static int GetSpawnPoints(string displayName)
		{
			return SpawnPoints.GetValueOrDefault(displayName.ToLower(), 0);
		}

		public static void SetSpawnPoints(ViewerData viewer, int value)
		{
			if (viewer != null)
			{
				SetSpawnPoints(viewer.DisplayName, value);
			}
		}

		public static void SetSpawnPoints(string displayName, int value)
		{
			if (value <= 0)
			{
				SpawnPoints.Remove(displayName.ToLower());
			}
			else
			{
				SpawnPoints[displayName.ToLower()] = value;
			}
			SaveData();
		}

		public static void AddSpawnPoints(ViewerData viewer, int amount = 1)
		{
			if (viewer != null)
			{
				AddSpawnPoints(viewer.DisplayName.ToLower());
			}
		}

		public static void AddSpawnPoints(string displayName, int amount = 1)
		{
			int valueOrDefault = SpawnPoints.GetValueOrDefault(displayName.ToLower(), 0);
			int num = valueOrDefault + amount;
			if (num <= 0)
			{
				SpawnPoints.Remove(displayName.ToLower());
			}
			else
			{
				SpawnPoints[displayName.ToLower()] = num;
			}
			SaveData();
		}

		public static void OnLocalDisconnect()
		{
			SpawnPointsUsedThisDay = 0;
		}

		public static void OnDayEnded()
		{
			SpawnPointsUsedThisDay = 0;
		}

		public static bool CanExecuteEvents()
		{
			return EnemyHelper.CanSpawnEnemy();
		}

		public static string GetDisplayNameWithColor(TwitchUser user)
		{
			string text = ((TwitchUser)(ref user)).Color;
			if (string.IsNullOrEmpty(text))
			{
				text = "#FFFFFF";
			}
			return "<color=" + text + ">" + ((TwitchUser)(ref user)).DisplayName + "</color>";
		}

		public static string GetDisplayNameWithColor(ViewerData viewer)
		{
			if (viewer == null)
			{
				return string.Empty;
			}
			string text = viewer.Color;
			if (string.IsNullOrEmpty(text))
			{
				text = "#FFFFFF";
			}
			return "<color=" + text + ">" + viewer.DisplayName + "</color>";
		}
	}
}
namespace com.github.zehsteam.MonsterHotkeys.Twitch.Commands
{
	internal abstract class TwitchCommand
	{
		private readonly Dictionary<string, float> _timesSinceLastUserExecution = new Dictionary<string, float>();

		private float _timeSinceLastExecution;

		public virtual bool IsCommand(TwitchMessage twitchMessage)
		{
			return false;
		}

		public void PreExecute(TwitchMessage twitchMessage)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: 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_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			TwitchUser user = ((TwitchMessage)(ref twitchMessage)).User;
			if (!IsOnCooldown(((TwitchUser)(ref user)).DisplayName) && Execute(twitchMessage))
			{
				user = ((TwitchMessage)(ref twitchMessage)).User;
				UpdateCooldowns(((TwitchUser)(ref user)).DisplayName);
			}
		}

		protected virtual bool Execute(TwitchMessage twitchMessage)
		{
			return true;
		}

		protected virtual float GetUserCooldown()
		{
			return 0f;
		}

		protected virtual float GetGlobalCooldown()
		{
			return 0f;
		}

		private void UpdateCooldowns(string displayName)
		{
			_timesSinceLastUserExecution[displayName.ToLower()] = Time.realtimeSinceStartup;
			_timeSinceLastExecution = Time.realtimeSinceStartup;
		}

		protected bool IsOnCooldown(string displayName)
		{
			if (IsOnUserCooldown(displayName))
			{
				return true;
			}
			if (IsOnGlobalCooldown())
			{
				return true;
			}
			return false;
		}

		protected bool IsOnUserCooldown(string displayName)
		{
			float userCooldown = GetUserCooldown();
			if (userCooldown <= 0f)
			{
				return false;
			}
			float valueOrDefault = _timesSinceLastUserExecution.GetValueOrDefault(displayName.ToLower(), 0f);
			return Time.realtimeSinceStartup - valueOrDefault <= userCooldown;
		}

		protected bool IsOnGlobalCooldown()
		{
			float globalCooldown = GetGlobalCooldown();
			if (globalCooldown <= 0f)
			{
				return false;
			}
			return Time.realtimeSinceStartup - _timeSinceLastExecution <= globalCooldown;
		}

		protected static bool IsModeratorOrHigher(TwitchUser twitchUser)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			return ((TwitchUser)(ref twitchUser)).IsModerator || ((TwitchUser)(ref twitchUser)).IsBroadcaster || IsDeveloper(twitchUser);
		}

		protected static bool IsDeveloper(TwitchUser twitchUser)
		{
			return ((TwitchUser)(ref twitchUser)).DisplayName.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 TwitchGiveSpawnCommand());
			TwitchCommands.Add(new TwitchViewSpawnCommand());
			TwitchCommands.Add(new TwitchViewAllSpawnCommand());
			TwitchCommands.Add(new TwitchViewBitsCommand());
			TwitchCommands.Add(new TwitchViewAllBitsCommand());
			TwitchCommands.Add(new TwitchDevSpawnCommand());
			TwitchCommands.Add(new TwitchDevPlushiesCommand());
		}

		public static void ExecuteCommand(TwitchMessage twitchMessage)
		{
			//IL_001c: 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)
			if (((TwitchMessage)(ref twitchMessage)).Message.StartsWith("!") && TryGetTwitchCommand(twitchMessage, out var twitchCommand))
			{
				twitchCommand.PreExecute(twitchMessage);
			}
		}

		private static TwitchCommand GetTwitchCommand(TwitchMessage twitchMessage)
		{
			//IL_0019: 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_0002: 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 float GetUserCooldown()
		{
			return base.GetUserCooldown();
		}

		protected override float GetGlobalCooldown()
		{
			return base.GetGlobalCooldown();
		}

		protected override bool Execute(TwitchMessage twitchMessage)
		{
			//IL_0017: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			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);
			Plugin.Instance.LogInfoExtended("TwitchDevPlushiesCommand:\n" + JsonConvert.SerializeObject((object)viewerData));
			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 float GetUserCooldown()
		{
			return base.GetUserCooldown();
		}

		protected override float GetGlobalCooldown()
		{
			return base.GetGlobalCooldown();
		}

		protected override bool Execute(TwitchMessage twitchMessage)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: 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_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: 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 result = 1;
			string[] array = ((TwitchMessage)(ref twitchMessage)).Message.Split(' ');
			if (array.Length >= 2 && !int.TryParse(array[1], out result))
			{
				return false;
			}
			if (result <= 0)
			{
				return false;
			}
			result = Mathf.Min(result, 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, result, spawnReason);
			Plugin.Instance.LogInfoExtended("TwitchDevSpawnCommand:\n" + JsonConvert.SerializeObject((object)viewerSpawnEvent));
			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 float GetUserCooldown()
		{
			return base.GetUserCooldown();
		}

		protected override float GetGlobalCooldown()
		{
			return base.GetGlobalCooldown();
		}

		protected override bool Execute(TwitchMessage twitchMessage)
		{
			//IL_0024: 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_0129: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.ConfigManager.SpawnPoints_Enabled.Value)
			{
				return false;
			}
			if (!TwitchCommand.IsModeratorOrHigher(((TwitchMessage)(ref twitchMessage)).User))
			{
				return false;
			}
			string[] array = ((TwitchMessage)(ref twitchMessage)).Message.Split(' ');
			if (array.Length < 2)
			{
				return false;
			}
			string text = array[1].Replace("@", "");
			if (text.Length > 25)
			{
				return false;
			}
			int result = 1;
			if (text.Length < 4)
			{
				TwitchUser user = ((TwitchMessage)(ref twitchMessage)).User;
				text = ((TwitchUser)(ref user)).DisplayName;
				if (!int.TryParse(array[1], out result))
				{
					return false;
				}
			}
			else if (array.Length >= 3)
			{
				int.TryParse(array[2], out result);
			}
			TwitchIntegrationManager.AddSpawnPoints(text, result);
			int spawnPoints = TwitchIntegrationManager.GetSpawnPoints(text);
			string text2 = ((result == 1) ? "" : "s");
			MessageCanvas.Instance?.ShowMessage_LocalClient(string.Format("{0} gave {1} {2} spawn point{3} ({4} total) {5}", TwitchIntegrationManager.GetDisplayNameWithColor(((TwitchMessage)(ref twitchMessage)).User), text, result, text2, spawnPoints, "<color=#00FF00>Use !spawn to spawn your free enemy</color>"));
			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 float GetUserCooldown()
		{
			return base.GetUserCooldown();
		}

		protected override float GetGlobalCooldown()
		{
			return base.GetGlobalCooldown();
		}

		protected override bool Execute(TwitchMessage twitchMessage)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.ConfigManager.SpawnPoints_Enabled.Value)
			{
				return false;
			}
			if (!TwitchIntegrationManager.CanExecuteEvents())
			{
				return false;
			}
			TwitchUser user = ((TwitchMessage)(ref twitchMessage)).User;
			int spawnPoints = TwitchIntegrationManager.GetSpawnPoints(((TwitchUser)(ref user)).DisplayName);
			if (spawnPoints <= 0)
			{
				return false;
			}
			int value = Plugin.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 result = 1;
			string[] array = ((TwitchMessage)(ref twitchMessage)).Message.Split(' ');
			if (array.Length >= 2)
			{
				int.TryParse(array[1], out result);
			}
			if (result <= 0)
			{
				return false;
			}
			if (result > spawnPoints)
			{
				result = spawnPoints;
			}
			if (result > num)
			{
				result = num;
			}
			int num2 = spawnPoints - result;
			user = ((TwitchMessage)(ref twitchMessage)).User;
			TwitchIntegrationManager.SetSpawnPoints(((TwitchUser)(ref user)).DisplayName, num2);
			TwitchIntegrationManager.SpawnPointsUsedThisDay += result;
			string arg = ((result == 1) ? "" : "s");
			string spawnReason = $"by redeeming {result} spawn point{arg} ({num2} 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, result, spawnReason);
			Plugin.Instance.LogInfoExtended("TwitchSpawnCommand:\n" + JsonConvert.SerializeObject((object)viewerSpawnEvent));
			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 float GetUserCooldown()
		{
			return base.GetUserCooldown();
		}

		protected override float GetGlobalCooldown()
		{
			return base.GetGlobalCooldown();
		}

		protected override bool Execute(TwitchMessage twitchMessage)
		{
			//IL_0003: 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 float GetUserCooldown()
		{
			return base.GetUserCooldown();
		}

		protected override float GetGlobalCooldown()
		{
			return base.GetGlobalCooldown();
		}

		protected override bool Execute(TwitchMessage twitchMessage)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.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 float GetUserCooldown()
		{
			return base.GetUserCooldown();
		}

		protected override float GetGlobalCooldown()
		{
			return base.GetGlobalCooldown();
		}

		protected override bool Execute(TwitchMessage twitchMessage)
		{
			//IL_0003: 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_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			TwitchUser user = ((TwitchMessage)(ref twitchMessage)).User;
			string text = ((TwitchUser)(ref user)).DisplayName;
			user = ((TwitchMessage)(ref twitchMessage)).User;
			string arg = ((TwitchUser)(ref user)).Color;
			string[] array = ((TwitchMessage)(ref twitchMessage)).Message.Split(' ');
			if (array.Length > 1)
			{
				text = array[1].Replace("@", "");
				arg = "#FFFFFF";
			}
			int accumulatedBits = TwitchIntegrationManager.GetAccumulatedBits(text);
			MessageCanvas.Instance?.ShowMessage_LocalClient($"<color={arg}>{text}</color> 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 float GetUserCooldown()
		{
			return base.GetUserCooldown();
		}

		protected override float GetGlobalCooldown()
		{
			return base.GetGlobalCooldown();
		}

		protected override bool Execute(TwitchMessage twitchMessage)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.ConfigManager.SpawnPoints_Enabled.Value)
			{
				return false;
			}
			TwitchUser user = ((TwitchMessage)(ref twitchMessage)).User;
			string text = ((TwitchUser)(ref user)).DisplayName;
			user = ((TwitchMessage)(ref twitchMessage)).User;
			string text2 = ((TwitchUser)(ref user)).Color;
			string[] array = ((TwitchMessage)(ref twitchMessage)).Message.Split(' ');
			if (array.Length > 1)
			{
				text = array[1].Replace("@", "");
				text2 = "#FFFFFF";
			}
			int spawnPoints = TwitchIntegrationManager.GetSpawnPoints(text);
			string text3 = ((spawnPoints == 1) ? "" : "s");
			MessageCanvas.Instance?.ShowMessage_LocalClient($"<color={text2}>{text}</color> has {spawnPoints} spawn point{text3}");
			return true;
		}
	}
}
namespace com.github.zehsteam.MonsterHotkeys.Patches
{
	[HarmonyPatch(typeof(ButlerEnemyAI))]
	internal static class ButlerEnemyAIPatch
	{
		[HarmonyTargetMethod]
		private static MethodBase TargetMethod()
		{
			Type type = typeof(ButlerEnemyAI).Assembly.GetTypes().FirstOrDefault((Type t) => t.Name.Contains("ButlerBlowUpAndPop") && t.Name.Contains("d__"));
			if (type == null)
			{
				Plugin.Logger.LogError((object)"[ButlerEnemyAIPatch] Failed to locate state machine class for ButlerBlowUpAndPop.");
				return null;
			}
			Plugin.Instance.LogInfoExtended("[ButlerEnemyAIPatch] Found state machine class: " + type.FullName);
			MethodInfo method = type.GetMethod("MoveNext", BindingFlags.Instance | BindingFlags.NonPublic);
			if (method == null)
			{
				Plugin.Logger.LogError((object)("[ButlerEnemyAIPatch] Failed to locate MoveNext method in " + type.FullName));
				return null;
			}
			Plugin.Instance.LogInfoExtended("[ButlerEnemyAIPatch] Found MoveNext method: " + method.Name);
			return method;
		}

		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> ButlerBlowUpAndPopTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Expected O, but got Unknown
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Expected O, but got Unknown
			MethodInfo method = typeof(RoundManager).GetMethod("SpawnEnemyGameObject");
			MethodInfo method2 = typeof(ButlerHelper).GetMethod("SpawnButlerBees");
			if (method == null || method2 == null)
			{
				Plugin.Logger.LogError((object)"[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));
					Plugin.Instance.LogInfoExtended("[ButlerEnemyAIPatch] Replaced " + method.Name + " call with " + method2.Name + ".");
				}
				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(Content.NetworkHandlerPrefab);
		}

		private static void AddNetworkPrefab(GameObject prefab)
		{
			if ((Object)(object)prefab == (Object)null)
			{
				Plugin.Logger.LogError((object)"Failed to register network prefab. GameObject is null.");
				return;
			}
			NetworkManager.Singleton.AddNetworkPrefab(prefab);
			Plugin.Logger.LogInfo((object)("Registered \"" + ((Object)prefab).name + "\" network prefab."));
		}
	}
	[HarmonyPatch(typeof(HUDManager))]
	internal static class HUDManagerPatch
	{
		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void StartPatch()
		{
			Plugin.Instance.SpawnMessageCanvas();
		}
	}
	[HarmonyPatch(typeof(Landmine))]
	internal static class LandminePatch
	{
		[HarmonyPatch("SpawnExplosion")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> SpawnExplosionTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Expected O, but got Unknown
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Expected O, but got Unknown
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Expected O, but got Unknown
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: 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)
			{
				Plugin.Logger.LogError((object)"[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));
						Plugin.Instance.LogInfoExtended("[LandminePatch] Replaced DamagePlayer call with " + method3.Name + ".");
						continue;
					}
					if (methodInfo2 == method2)
					{
						list.Add(new CodeInstruction(OpCodes.Call, (object)methodInfo));
						list.Add(new CodeInstruction(OpCodes.Call, (object)method4));
						Plugin.Instance.LogInfoExtended("[LandminePatch] Replaced KillPlayer call with " + method4.Name + ".");
						continue;
					}
				}
				list.Add(instruction);
			}
			return list.AsEnumerable();
		}
	}
	internal static class PlayerDamagePatcher
	{
		private static readonly MethodInfo _originalDamagePlayer = typeof(PlayerControllerB).GetMethod("DamagePlayer");

		private static readonly MethodInfo _originalKillPlayer = typeof(PlayerControllerB).GetMethod("KillPlayer");

		private static readonly MethodInfo _replacementDamagePlayer = typeof(PlayerHelper).GetMethod("DamagePlayerWithCaller");

		private static readonly MethodInfo _replacementKillPlayer = typeof(PlayerHelper).GetMethod("KillPlayerWithCaller");

		private static bool _patched;

		private static int _transpilersCreated;

		public static void PatchAll(Harmony harmony)
		{
			if (_patched)
			{
				return;
			}
			_patched = true;
			LogInfo("Running patcher...");
			if (_originalDamagePlayer == null || _originalKillPlayer == null || _replacementDamagePlayer == null || _replacementKillPlayer == null)
			{
				LogError("Required methods not found for patcher.");
				return;
			}
			IEnumerable<Assembly> validAssemblies = GetValidAssemblies();
			LogInfo($"Found {validAssemblies.Count()} valid assemblies.");
			foreach (Assembly item in validAssemblies)
			{
				LogInfoExtended("Found assembly: " + item.FullName);
			}
			_transpilersCreated = 0;
			Parallel.ForEach(validAssemblies, delegate(Assembly assembly)
			{
				PatchAssembly(assembly, harmony);
			});
			LogInfo($"Created {_transpilersCreated} transpilers.");
			LogInfo("Patcher finished.");
		}

		private static void PatchAssembly(Assembly assembly, Harmony harmony)
		{
			LogInfoExtended("Patching assembly: " + assembly.FullName);
			IEnumerable<Type> validClasses = GetValidClasses(assembly);
			Parallel.ForEach(validClasses, delegate(Type type)
			{
				PatchClass(type, harmony);
			});
		}

		private static void PatchClass(Type type, Harmony harmony)
		{
			LogInfoExtended("Patching class: " + type.FullName);
			IEnumerable<MethodInfo> validMethods = GetValidMethods(type);
			Parallel.ForEach(validMethods, delegate(MethodInfo method)
			{
				PatchMethod(method, harmony);
			});
		}

		private static void PatchMethod(MethodInfo method, Harmony harmony)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			try
			{
				if (ReflectionHelper.IsCoroutineMethod(method))
				{
					MethodInfo coroutineMoveNextMethod = ReflectionHelper.GetCoroutineMoveNextMethod(method);
					if (coroutineMoveNextMethod == null)
					{
						return;
					}
					harmony.Patch((MethodBase)coroutineMoveNextMethod, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(PlayerDamagePatcher), "Transpiler", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
					LogInfoExtended($"Patched coroutine: {coroutineMoveNextMethod}");
				}
				else
				{
					harmony.Patch((MethodBase)method, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(PlayerDamagePatcher), "Transpiler", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
				}
				LogInfoExtended("Patched method: " + method.Name);
				Interlocked.Increment(ref _transpilersCreated);
			}
			catch (Exception arg)
			{
				LogError($"Failed to patch method: {method}\n\n{arg}");
			}
		}

		public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Expected O, but got Unknown
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Expected O, but got Unknown
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Expected O, but got Unknown
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Expected O, but got Unknown
			if (_originalDamagePlayer == null || _originalKillPlayer == null || _replacementDamagePlayer == null || _replacementKillPlayer == null)
			{
				LogError("Required methods not found 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)
				{
					if (methodInfo == _originalDamagePlayer)
					{
						list.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null));
						list.Add(new CodeInstruction(OpCodes.Call, (object)_replacementDamagePlayer));
						LogInfoExtended("Replaced " + _originalDamagePlayer.Name + " call with " + _replacementDamagePlayer.Name + ".");
						continue;
					}
					if (methodInfo == _originalKillPlayer)
					{
						list.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null));
						list.Add(new CodeInstruction(OpCodes.Call, (object)_replacementKillPlayer));
						LogInfoExtended("Replaced " + _originalKillPlayer.Name + " call with " + _replacementKillPlayer.Name + ".");
						continue;
					}
				}
				list.Add(instruction);
			}
			return list.AsEnumerable();
		}

		private static IEnumerable<Assembly> GetValidAssemblies()
		{
			return AppDomain.CurrentDomain.GetAssemblies().Where(IsValidAssembly);
		}

		private static bool IsValidAssembly(Assembly assembly)
		{
			if (assembly == null || assembly.IsDynamic)
			{
				return false;
			}
			if (assembly == Assembly.GetExecutingAssembly())
			{
				return false;
			}
			if (assembly.FullName.StartsWithAny(new string[4] { "System.", "giosuel.Imperium", "MMHOOK_", "UnityExplorer." }, StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			if (assembly.Location.StartsWith(Paths.PluginPath, StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			if (assembly.FullName.StartsWith("Assembly-CSharp"))
			{
				return true;
			}
			return false;
		}

		private static IEnumerable<Type> GetValidClasses(Assembly assembly)
		{
			if (assembly == null)
			{
				return Array.Empty<Type>();
			}
			try
			{
				return assembly.GetTypes().Where(IsValidClass);
			}
			catch (ReflectionTypeLoadException ex)
			{
				LogWarningExtended("Error loading types from assembly " + assembly.FullName + ": " + ex.Message);
				return Array.Empty<Type>();
			}
		}

		private static bool IsValidClass(Type type)
		{
			if (type == null)
			{
				return false;
			}
			if (!type.IsClass || type.IsAbstract)
			{
				return false;
			}
			if (type == typeof(PlayerControllerB))
			{
				return false;
			}
			if (type.FullName.StartsWithAny(new string[2] { "DunGen.", "DigitalRuby.ThunderAndLightning." }, StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			if (type.Name.Contains("TurretBehaviour"))
			{
				return true;
			}
			if (typeof(EnemyAI).IsAssignableFrom(type) || typeof(ShotgunItem).IsAssignableFrom(type))
			{
				return true;
			}
			return false;
		}

		private static IEnumerable<MethodInfo> GetValidMethods(Type type)
		{
			return type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Where(IsValidMethod);
		}

		private static bool IsValidMethod(MethodInfo method)
		{
			if (method == null)
			{
				return false;
			}
			if (method.IsGenericMethod || method.DeclaringType.IsGenericType)
			{
				return false;
			}
			return ILHelper.MethodCallsMethods(method, new MethodInfo[2] { _originalDamagePlayer, _originalKillPlayer });
		}

		private static void LogInfo(object data)
		{
			Log((LogLevel)16, data);
		}

		private static void LogError(object data)
		{
			Log((LogLevel)2, data);
		}

		private static void Log(LogLevel logLevel, object data)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Plugin.Logger.Log(logLevel, (object)$"[PlayerDamagePatcher] {data}");
		}

		private static void LogInfoExtended(object data)
		{
			LogExtended((LogLevel)16, data);
		}

		private static void LogWarningExtended(object data)
		{
			LogExtended((LogLevel)4, data);
		}

		private static void LogExtended(LogLevel logLevel, object data)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Plugin.Instance.LogExtended(logLevel, $"[PlayerDamagePatcher] {data}");
		}
	}
	[HarmonyPatch(typeof(RadMechAI))]
	internal static class RadMechAIPatch
	{
		[HarmonyPatch("SetExplosion")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> SetExplosionTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			return ReplaceLandmineSpawnExplosionTranspiler(instructions);
		}

		[HarmonyPatch("DoFootstepCycle")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> DoFootstepCycleTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			return ReplaceLandmineSpawnExplosionTranspiler(instructions);
		}

		private static IEnumerable<CodeInstruction> ReplaceLandmineSpawnExplosionTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Expected O, but got Unknown
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Expected O, but got Unknown
			MethodInfo method = typeof(Landmine).GetMethod("SpawnExplosion");
			MethodInfo method2 = typeof(LandmineHelper).GetMethod("SpawnExplosionWithCaller");
			if (method == null || method2 == null)
			{
				Plugin.Logger.LogError((object)"[RadMechAIPatch] 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));
					Plugin.Instance.LogInfoExtended("[RadMechAIPatch] Replaced " + method.Name + " call with " + method2.Name + ".");
				}
				else
				{
					list.Add(instruction);
				}
			}
			return list.AsEnumerable();
		}
	}
	[HarmonyPatch(typeof(RoundManager))]
	internal static class RoundManagerPatch
	{
		private static bool _shipArrived;

		private static float _timeSinceShipArrived;

		[HarmonyPatch("LoadNewLevel")]
		[HarmonyPostfix]
		private static void LoadNewLevelPatch()
		{
			Plugin.Instance.OnNewLevelLoaded();
		}

		[HarmonyPatch("GenerateNewLevelClientRpc")]
		[HarmonyPrefix]
		private static void GenerateNewLevelClientRpcPatch()
		{
			if (!NetworkUtils.IsServer)
			{
				Plugin.Instance.OnNewLevelLoaded();
			}
		}

		[HarmonyPatch("F