Decompiled source of MonsterHotkeys v1.4.0
com.github.zehsteam.MonsterHotkeys.dll
Decompiled 2 months ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Net.Sockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text.RegularExpressions; 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 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.MonoBehaviours; using com.github.zehsteam.MonsterHotkeys.NetcodePatcher; using com.github.zehsteam.MonsterHotkeys.Patches; [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. Highly Configurable.")] [assembly: AssemblyFileVersion("1.4.0.0")] [assembly: AssemblyInformationalVersion("1.4.0+c97ccfba10a5a8bbdaa2e76f624b7a986e78a87f")] [assembly: AssemblyProduct("MonsterHotkeys")] [assembly: AssemblyTitle("com.github.zehsteam.MonsterHotkeys")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.4.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] [module: NetcodePatchedAssembly] internal class <Module> { static <Module>() { } } namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace com.github.zehsteam.MonsterHotkeys { internal static class ConfigHelper { public static void SetModIcon(Sprite sprite) { if (LethalConfigProxy.Enabled) { LethalConfigProxy.SetModIcon(sprite); } } public static void SetModDescription(string description) { if (LethalConfigProxy.Enabled) { LethalConfigProxy.SetModDescription(description); } } public static void SkipAutoGen() { if (LethalConfigProxy.Enabled) { LethalConfigProxy.SkipAutoGen(); } } public static ConfigEntry<T> Bind<T>(string section, string key, T defaultValue, bool requiresRestart, string description, AcceptableValueBase acceptableValues = null, Action<T> settingChanged = null, ConfigFile configFile = null) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown if (configFile == null) { configFile = ((BaseUnityPlugin)Plugin.Instance).Config; } ConfigEntry<T> configEntry = ((acceptableValues == null) ? configFile.Bind<T>(section, key, defaultValue, description) : configFile.Bind<T>(section, key, defaultValue, new ConfigDescription(description, acceptableValues, Array.Empty<object>()))); if (settingChanged != null) { configEntry.SettingChanged += delegate { settingChanged?.Invoke(configEntry.Value); }; } if (LethalConfigProxy.Enabled) { if (acceptableValues == null) { LethalConfigProxy.AddConfig<T>(configEntry, requiresRestart); } else { LethalConfigProxy.AddConfigSlider<T>(configEntry, requiresRestart); } } return configEntry; } public static void AddButton(string section, string name, string description, string buttonText, Action callback) { if (LethalConfigProxy.Enabled) { LethalConfigProxy.AddButton(section, name, description, buttonText, callback); } } } 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 = val.LoadAsset<GameObject>("NetworkHandler"); MessageCanvasPrefab = val.LoadAsset<GameObject>("MonsterHotkeysCanvas"); EnemyDataList = val.LoadAsset<EnemyDataList>("EnemyDataList"); 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; } } public static class EnemyHelper { private static List<TwitchSubEvent> _twitchSubEventQueue = new List<TwitchSubEvent>(); private static List<TwitchBitsEvents> _twitchBitsEventQueue = new List<TwitchBitsEvents>(); public static void Initialize() { TwitchEvents.OnSub = (Action<TwitchSubEvent>)Delegate.Combine(TwitchEvents.OnSub, new Action<TwitchSubEvent>(SpawnEnemyFromSub)); TwitchEvents.OnBits = (Action<TwitchBitsEvents>)Delegate.Combine(TwitchEvents.OnBits, new Action<TwitchBitsEvents>(SpawnEnemyFromBits)); } public static void SpawnEnemy(EnemyData enemyData, string phrase = "") { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) if (CanSpawnEnemy()) { if (enemyData == null) { Plugin.logger.LogError((object)"Failed to spawn enemy. EnemyData is null."); } else if (NetworkUtils.IsServer) { SpawnEnemyOnServer(enemyData, PlayerUtils.GetLocalPlayerScript(), phrase); } else { PluginNetworkBehaviour.Instance.SpawnEnemyServerRpc(enemyData.EnemyName, phrase); } } } public static void SpawnRandomEnemy(string phrase = "") { SpawnEnemy(Content.EnemyDataList.GetRandom(PlayerUtils.GetLocalPlayerScript()), phrase); } public static void SpawnEnemyOnServer(EnemyData enemyData, PlayerControllerB playerScript, string phrase = "") { //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: 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) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) if (!NetworkUtils.IsServer) { Plugin.logger.LogError((object)"Failed to spawn enemy. Only the host can spawn enemies."); return; } if (enemyData == null) { Plugin.logger.LogError((object)"Failed to spawn enemy. EnemyData is null."); return; } EnemyType enemyType = enemyData.EnemyType; if ((Object)(object)enemyType == (Object)null) { Plugin.logger.LogError((object)("Failed to spawn \"" + enemyData.EnemyName + "\" enemy. EnemyType is null.")); return; } if ((Object)(object)enemyType.enemyPrefab == (Object)null) { Plugin.logger.LogError((object)("Failed to spawn \"" + enemyData.EnemyName + "\" enemy. EnemyType.enemyPrefab is null.")); return; } if ((Object)(object)playerScript == (Object)null) { Plugin.logger.LogError((object)("Failed to spawn \"" + enemyData.EnemyName + "\" enemy. PlayerControllerB is null.")); return; } int value = enemyData.ConfigData.SpawnCount.Value; bool value2 = enemyData.ConfigData.SpawnNearPlayer.Value; bool value3 = enemyData.ConfigData.SpawnInFrontOfPlayer.Value; Plugin.Instance.LogInfoExtended($"Trying to spawn \"{enemyData.EnemyName}\" enemy. (SpawnCount: {value})"); List<NetworkObjectReference> list = new List<NetworkObjectReference>(); List<Vector3> list2 = new List<Vector3>(); for (int i = 0; i < value; i++) { Vector3 val = ((value2 && !value3) ? GetSpawnPositionNearPlayer(playerScript, enemyData) : ((!value3) ? GetRandomSpawnPosition(playerScript) : GetSpawnPositionInFrontOfPlayer(playerScript, enemyData))); list2.Add(val); EnemyAI val2 = SpawnEnemyAtPositionOnServer(enemyType, val, Plugin.ConfigManager.Monster_SpawnStunned, Plugin.ConfigManager.Monster_StunDuration); list.Add(NetworkObjectReference.op_Implicit(((Component)val2).GetComponent<NetworkObject>())); Plugin.Instance.LogInfoExtended($"Spawned \"{enemyData.EnemyName}\" enemy at position: (x: {val.x}, y: {val.y}, z: {val.z})"); } AudioPlayerManager.Instance.SpawnOnServer(enemyData.EnemyName, list2.ToArray(), playerScript.isInsideFactory); MessageCanvas.Instance.ShowSpawnEnemyMessageOnServer(enemyData, playerScript, phrase); EnemyNametagManager.Instance.SpawnNametagsOnServer(EnemyNametagType.Default, playerScript.playerUsername, playerScript, list.ToArray()); } public static void SpawnEnemyFromSub(TwitchSubEvent twitchSubEvent) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) if (!CanSpawnEnemy()) { MessageCanvas.Instance?.ShowMessageOnLocalClient("Could not spawn enemies from Twitch sub event from " + twitchSubEvent.Sender); MessageCanvas.Instance?.ShowMessageOnLocalClient("Adding Twitch sub event to the queue for the next round"); _twitchSubEventQueue.Add(twitchSubEvent); } else if (NetworkUtils.IsServer) { SpawnEnemyFromSubOnServer(twitchSubEvent, PlayerUtils.GetLocalPlayerScript()); } else { PluginNetworkBehaviour.Instance.SpawnEnemyFromSubServerRpc(twitchSubEvent); } } public static void SpawnEnemyFromSubOnServer(TwitchSubEvent twitchSubEvent, PlayerControllerB playerScript) { //IL_00fd: Unknown result type (might be due to invalid IL or missing references) if (!NetworkUtils.IsServer) { Plugin.logger.LogError((object)"Failed to spawn enemy from Twitch sub. Only the host can spawn enemies."); return; } if ((Object)(object)playerScript == (Object)null) { Plugin.logger.LogError((object)"Failed to spawn enemy from Twitch sub. PlayerControllerB is null."); return; } int num = twitchSubEvent.Amount; if (twitchSubEvent.Tier == 2) { num = twitchSubEvent.Amount * 2; } if (twitchSubEvent.Tier == 3) { num = twitchSubEvent.Amount * 6; } Plugin.Instance.LogInfoExtended($"Trying to spawn {num} enemies from Twitch sub."); if (TrySpawnEnemiesForTwitchEventOnServer(twitchSubEvent.Sender, num, playerScript, out var enemyDisplayName)) { MessageCanvas.Instance.ShowSpawnEnemyMessageFromSubOnServer(enemyDisplayName, num, twitchSubEvent, playerScript); return; } MessageCanvas.Instance.ShowMessage("[" + playerScript.playerUsername + "] Failed to spawn enemies from " + twitchSubEvent.Sender + " Twitch sub", Color.yellow); } public static void SpawnEnemyFromBits(TwitchBitsEvents twitchBitsEvents) { //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) if (twitchBitsEvents.Amount >= Plugin.ConfigManager.TwitchBitsEvent_MinAmountToSpawnMonster) { if (!CanSpawnEnemy()) { MessageCanvas.Instance?.ShowMessageOnLocalClient("Could not spawn enemies from Twitch bits event from " + twitchBitsEvents.Sender); MessageCanvas.Instance?.ShowMessageOnLocalClient("Adding Twitch bits event to the queue for the next round"); _twitchBitsEventQueue.Add(twitchBitsEvents); } else if (NetworkUtils.IsServer) { SpawnEnemyFromBitsOnServer(twitchBitsEvents, PlayerUtils.GetLocalPlayerScript()); } else { PluginNetworkBehaviour.Instance.SpawnEnemyFromBitsServerRpc(twitchBitsEvents); } } } public static void SpawnEnemyFromBitsOnServer(TwitchBitsEvents twitchBitsEvents, PlayerControllerB playerScript) { //IL_00df: Unknown result type (might be due to invalid IL or missing references) if (!NetworkUtils.IsServer) { Plugin.logger.LogError((object)"Failed to spawn enemy from Twitch bits. Only the host can spawn enemies."); return; } if ((Object)(object)playerScript == (Object)null) { Plugin.logger.LogError((object)"Failed to spawn enemy from Twitch bits. PlayerControllerB is null."); return; } int twitchBitsEvent_MinAmountToSpawnMonster = Plugin.ConfigManager.TwitchBitsEvent_MinAmountToSpawnMonster; int num = (int)Mathf.Floor((float)(twitchBitsEvents.Amount / twitchBitsEvent_MinAmountToSpawnMonster)); Plugin.Instance.LogInfoExtended($"Trying to spawn {num} enemies from Twitch bits."); if (TrySpawnEnemiesForTwitchEventOnServer(twitchBitsEvents.Sender, num, playerScript, out var enemyDisplayName)) { MessageCanvas.Instance.ShowSpawnEnemyMessageFromBitsOnServer(enemyDisplayName, num, twitchBitsEvents, playerScript); return; } MessageCanvas.Instance.ShowMessage("[" + playerScript.playerUsername + "] Failed to spawn enemies from " + twitchBitsEvents.Sender + " Twitch bits.", Color.yellow); } private static bool TrySpawnEnemiesForTwitchEventOnServer(string sender, int amount, PlayerControllerB playerScript, out string enemyDisplayName) { //IL_02fc: Unknown result type (might be due to invalid IL or missing references) //IL_0301: Unknown result type (might be due to invalid IL or missing references) //IL_0319: Unknown result type (might be due to invalid IL or missing references) //IL_031e: 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_017d: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Unknown result type (might be due to invalid IL or missing references) //IL_0340: Unknown result type (might be due to invalid IL or missing references) //IL_032f: Unknown result type (might be due to invalid IL or missing references) //IL_0334: Unknown result type (might be due to invalid IL or missing references) //IL_0344: Unknown result type (might be due to invalid IL or missing references) //IL_034e: Unknown result type (might be due to invalid IL or missing references) //IL_0373: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) enemyDisplayName = string.Empty; if (!NetworkUtils.IsServer) { Plugin.logger.LogError((object)"Failed to spawn enemies for Twitch event. Only the host can spawn enemies."); return false; } if ((Object)(object)playerScript == (Object)null) { Plugin.logger.LogError((object)"Failed to spawn enemies for Twitch event. PlayerControllerB is null."); return false; } if (amount < 1) { Plugin.logger.LogError((object)"Failed to spawn enemies for Twitch event. The spawn amount is less than 1."); return false; } Plugin.Instance.LogInfoExtended("Trying to spawn enemies for Twitch event."); List<NetworkObjectReference> list = new List<NetworkObjectReference>(); List<Vector3> list2 = new List<Vector3>(); if (Plugin.ConfigManager.TwitchSubEvent_SpawnAllOfTheSameEnemy) { EnemyData random = Content.EnemyDataList.GetRandom(playerScript, forTwitchEvent: true); if (random == null) { random = Content.EnemyDataList.GetRandom(playerScript); } if (random == null) { Plugin.logger.LogError((object)"Failed to spawn enemies for Twitch event. EnemyData is null."); return false; } EnemyType enemyType = random.EnemyType; if (!IsValidEnemyType(enemyType)) { Plugin.logger.LogError((object)"Failed to spawn enemies for Twitch event. EnemyType is invalid."); return false; } bool value = random.ConfigData.SpawnNearPlayer.Value; bool value2 = random.ConfigData.SpawnInFrontOfPlayer.Value; for (int i = 0; i < amount; i++) { Vector3 val = ((value && !value2) ? GetSpawnPositionNearPlayer(playerScript, random) : ((!value2) ? GetRandomSpawnPosition(playerScript) : GetSpawnPositionInFrontOfPlayer(playerScript, random))); list2.Add(val); EnemyAI val2 = SpawnEnemyAtPositionOnServer(enemyType, val, Plugin.ConfigManager.Monster_SpawnStunned, Plugin.ConfigManager.Monster_StunDuration); list.Add(NetworkObjectReference.op_Implicit(((Component)val2).GetComponent<NetworkObject>())); } enemyDisplayName = random.EnemyDisplayName; AudioPlayerManager.Instance.SpawnOnServer(random.EnemyName, list2.ToArray(), playerScript.isInsideFactory); EnemyNametagManager.Instance.SpawnNametagsOnServer(EnemyNametagType.Twitch, sender, playerScript, list.ToArray()); return true; } List<EnemyData> spawnedEnemiesData = new List<EnemyData>(); for (int j = 0; j < amount; j++) { EnemyData random2 = Content.EnemyDataList.GetRandom(playerScript, forTwitchEvent: true); if (random2 == null) { random2 = Content.EnemyDataList.GetRandom(playerScript); } if (random2 == null) { Plugin.logger.LogError((object)"Failed to spawn enemies for Twitch event. EnemyData is null."); continue; } EnemyType enemyType2 = random2.EnemyType; if (!IsValidEnemyType(enemyType2)) { Plugin.logger.LogError((object)"Failed to spawn enemies for Twitch event. EnemyType is invalid."); continue; } spawnedEnemiesData.Add(random2); bool value3 = random2.ConfigData.SpawnNearPlayer.Value; bool value4 = random2.ConfigData.SpawnInFrontOfPlayer.Value; Vector3 zero = Vector3.zero; zero = ((value3 && !value4) ? GetSpawnPositionNearPlayer(playerScript, random2) : ((!value4) ? GetRandomSpawnPosition(playerScript) : GetSpawnPositionInFrontOfPlayer(playerScript, random2))); list2.Add(zero); EnemyAI val3 = SpawnEnemyAtPositionOnServer(enemyType2, zero, Plugin.ConfigManager.Monster_SpawnStunned, Plugin.ConfigManager.Monster_StunDuration); list.Add(NetworkObjectReference.op_Implicit(((Component)val3).GetComponent<NetworkObject>())); } if (spawnedEnemiesData.Count == 0) { return false; } enemyDisplayName = "random enemies"; string enemyName = string.Empty; if (spawnedEnemiesData.All((EnemyData _) => _ == spawnedEnemiesData[0])) { enemyDisplayName = spawnedEnemiesData[0].EnemyDisplayName; enemyName = spawnedEnemiesData[0].EnemyName; } AudioPlayerManager.Instance.SpawnOnServer(enemyName, list2.ToArray(), playerScript.isInsideFactory); EnemyNametagManager.Instance.SpawnNametagsOnServer(EnemyNametagType.Twitch, sender, playerScript, list.ToArray()); return true; } public static void PlayTwitchEventsFromQueue() { Utils.StartCoroutine(PlayTwitchEventsFromQueueCoroutine()); } private static IEnumerator PlayTwitchEventsFromQueueCoroutine() { float timer = 0f; while (!CanSpawnEnemy() && timer < 120f) { yield return null; timer += Time.deltaTime; } if (_twitchSubEventQueue.Count == 0 && _twitchBitsEventQueue.Count == 0) { yield break; } yield return (object)new WaitForSeconds(10f); if (!CanSpawnEnemy()) { MessageCanvas.Instance.ShowMessageOnLocalClient("Failed to play monster Twitch events from queue", Color.red); yield break; } MessageCanvas.Instance.ShowMessageOnLocalClient("Playing monster Twitch events from queue"); int subEventLength = _twitchSubEventQueue.Count; foreach (TwitchSubEvent twitchSubEvent in _twitchSubEventQueue) { SpawnEnemyFromSub(twitchSubEvent); yield return (object)new WaitForSeconds(1f); } _twitchSubEventQueue.RemoveRange(0, subEventLength); int bitsEventLength = _twitchBitsEventQueue.Count; foreach (TwitchBitsEvents twitchBitsEvent in _twitchBitsEventQueue) { SpawnEnemyFromBits(twitchBitsEvent); yield return (object)new WaitForSeconds(1f); } _twitchBitsEventQueue.RemoveRange(0, bitsEventLength); } public static EnemyAI SpawnEnemyAtPositionOnServer(EnemyType enemyType, Vector3 position, bool spawnStunned = false, float stunDuration = 0f) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return SpawnEnemyAtPositionOnServer(enemyType, position, Random.Range(0f, 360f), spawnStunned, stunDuration); } public static EnemyAI SpawnEnemyAtPositionOnServer(EnemyType enemyType, Vector3 position, float yRot, bool spawnStunned = false, float stunDuration = 0f) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) if (!NetworkUtils.IsServer) { return null; } if (!IsValidEnemyType(enemyType)) { return null; } GameObject val = Object.Instantiate<GameObject>(enemyType.enemyPrefab, position, Quaternion.Euler(new Vector3(0f, yRot, 0f))); val.GetComponent<NetworkObject>().Spawn(true); EnemyAI component = val.GetComponent<EnemyAI>(); RoundManager.Instance.SpawnedEnemies.Add(component); if (spawnStunned) { component.stunNormalizedTimer = stunDuration; } return component; } public static bool CanSpawnEnemy() { if ((Object)(object)StartOfRound.Instance == (Object)null) { return false; } if (StartOfRound.Instance.inShipPhase) { return false; } if (StartOfRound.Instance.shipIsLeaving) { return false; } if (!StartOfRound.Instance.currentLevel.spawnEnemiesAndScrap) { return false; } PlayerControllerB localPlayerScript = PlayerUtils.GetLocalPlayerScript(); if ((Object)(object)localPlayerScript == (Object)null) { return false; } if (localPlayerScript.isPlayerDead) { return false; } return true; } private static Vector3 GetRandomSpawnPosition(PlayerControllerB playerScript) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)RoundManager.Instance == (Object)null || (Object)(object)playerScript == (Object)null) { return Vector3.zero; } GameObject[] array; if (playerScript.isInsideFactory) { if (RoundManager.Instance.insideAINodes == null || RoundManager.Instance.insideAINodes.Length == 0) { return Vector3.zero; } array = RoundManager.Instance.insideAINodes.Where((GameObject _) => (Object)(object)_ != (Object)null).ToArray(); if (array.Length == 0) { return Vector3.zero; } return array[Random.Range(0, array.Length)].transform.position; } if (RoundManager.Instance.outsideAINodes == null || RoundManager.Instance.outsideAINodes.Length == 0) { return Vector3.zero; } array = RoundManager.Instance.outsideAINodes.Where((GameObject _) => (Object)(object)_ != (Object)null).ToArray(); if (array.Length == 0) { return Vector3.zero; } return array[Random.Range(0, array.Length)].transform.position; } private static Vector3 GetSpawnPositionNearPlayer(PlayerControllerB playerScript, EnemyData enemyData) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) return GetSpawnPositionNearPlayer(playerScript, enemyData.ConfigData.MinDistance.Value, enemyData.ConfigData.MaxDistance.Value); } private static Vector3 GetSpawnPositionNearPlayer(PlayerControllerB playerScript, float minRadius, float maxRadius) { //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_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) bool flag = false; Vector3 position = Vector3.zero; for (int i = 0; i < 50; i++) { if (flag) { break; } if (TryGetRandomPositionInNavMesh(playerScript, ((Component)playerScript).transform.position, minRadius, maxRadius, out position)) { flag = true; } } if (flag) { return position; } return GetRandomSpawnPosition(playerScript); } private static Vector3 GetSpawnPositionInFrontOfPlayer(PlayerControllerB playerScript, EnemyData enemyData) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) return GetSpawnPositionInFrontOfPlayer(playerScript, enemyData.ConfigData.MinDistance.Value, enemyData.ConfigData.MaxDistance.Value); } private static Vector3 GetSpawnPositionInFrontOfPlayer(PlayerControllerB playerScript, float minDistance, float maxDistance) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_009f: 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_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) Transform transform = ((Component)playerScript).transform; float num = maxDistance - minDistance; float num2 = 1.5f; List<Vector3> list = new List<Vector3>(); int num3 = (int)num / (int)num2; if (num3 < 1) { num3 = 1; } for (int i = 0; i < num3; i++) { Vector3 item = transform.position + transform.forward * (minDistance + (float)i * num2); item.y += 0.5f; list.Add(item); } RaycastHit val2 = default(RaycastHit); for (int num4 = list.Count - 1; num4 >= 0; num4--) { int index = Random.Range(0, num4); Vector3 val = list[index]; if (Physics.Raycast(val, Vector3.down, ref val2, 25f)) { val = ((RaycastHit)(ref val2)).point; } if (TryGetRandomPositionInNavMesh(playerScript, val, 0f, num2, out var position)) { return position; } list.RemoveAt(index); } return GetSpawnPositionNearPlayer(playerScript, minDistance, maxDistance); } private static bool TryGetRandomPositionInNavMesh(PlayerControllerB playerScript, Vector3 sourcePosition, float minRadius, float maxRadius, out Vector3 position) { //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_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) position = Vector3.zero; Vector3 val = Random.insideUnitSphere * maxRadius; val += sourcePosition; NavMeshHit val2 = default(NavMeshHit); if (NavMesh.SamplePosition(val, ref val2, maxRadius, 1)) { position = ((NavMeshHit)(ref val2)).position; if (IsYPositionTooHigh(playerScript, position.y)) { return false; } if (Vector3.Distance(sourcePosition, position) <= minRadius) { return false; } return true; } return false; } private static bool IsYPositionTooHigh(PlayerControllerB playerScript, float yPosition) { if (!playerScript.isInsideFactory) { return false; } if (!InteriorHelper.IsFacilityInterior()) { return false; } return yPosition > -210f; } public static EnemyType GetEnemyTypeForCrowdControl(string enemyName) { if (enemyName.Equals("mimic", StringComparison.OrdinalIgnoreCase)) { enemyName = "Masked"; } foreach (EnemyType enemyType in GetEnemyTypes()) { if (enemyType.enemyName.Contains(enemyName, StringComparison.OrdinalIgnoreCase)) { return enemyType; } } try { EnemyType val = Resources.FindObjectsOfTypeAll<EnemyType>().Single((EnemyType x) => x.enemyName.Contains(enemyName, StringComparison.OrdinalIgnoreCase)); if (IsValidEnemyType(val) && NetworkUtils.IsNetworkPrefab(val.enemyPrefab)) { Plugin.Instance.LogInfoExtended("Found EnemyType \"" + val.enemyName + "\" from Resources."); return val; } } catch { } return null; } public static EnemyType GetEnemyType(string enemyName, bool matchCase = false) { StringComparison stringComparison = ((!matchCase) ? StringComparison.OrdinalIgnoreCase : StringComparison.CurrentCulture); foreach (EnemyType enemyType in GetEnemyTypes()) { if (enemyType.enemyName.Equals(enemyName, stringComparison)) { return enemyType; } } try { EnemyType val = Resources.FindObjectsOfTypeAll<EnemyType>().Single((EnemyType x) => x.enemyName.Equals(enemyName, stringComparison)); if (IsValidEnemyType(val) && NetworkUtils.IsNetworkPrefab(val.enemyPrefab)) { Plugin.Instance.LogInfoExtended("Found EnemyType \"" + val.enemyName + "\" from Resources."); return val; } } catch { } return null; } public static List<EnemyType> GetEnemyTypes() { HashSet<EnemyType> hashSet = new HashSet<EnemyType>(new EnemyTypeComparer()); SelectableLevel[] levels = StartOfRound.Instance.levels; foreach (SelectableLevel val in levels) { IEnumerable<EnemyType> enumerable = (from e in val.Enemies.Concat(val.DaytimeEnemies).Concat(val.OutsideEnemies) select e.enemyType).Where(IsValidEnemyType); foreach (EnemyType item in enumerable) { hashSet.Add(item); } } return hashSet.ToList(); } public static bool IsValidEnemyType(EnemyType enemyType) { if ((Object)(object)enemyType == (Object)null) { return false; } if (string.IsNullOrWhiteSpace(enemyType.enemyName)) { return false; } if ((Object)(object)enemyType.enemyPrefab == (Object)null) { return false; } if (enemyType.spawningDisabled) { return false; } return true; } } public class EnemyTypeComparer : IEqualityComparer<EnemyType> { public bool Equals(EnemyType x, EnemyType y) { if ((Object)(object)x == (Object)null || (Object)(object)y == (Object)null) { return false; } return x.enemyName == y.enemyName; } public int GetHashCode(EnemyType obj) { return obj.enemyName?.GetHashCode() ?? 0; } } 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.ShowMessageOnLocalClient("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.ShowMessageOnLocalClient("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(); } } } public enum InteriorType { None, Facility, Mansion, Mineshaft, Other } internal static class InteriorHelper { private static InteriorType interiorType; public static void SetInteriorType() { try { RuntimeDungeon val = Object.FindFirstObjectByType<RuntimeDungeon>((FindObjectsInactive)0); if (!((Object)(object)val == (Object)null)) { DungeonFlow dungeonFlow = val.Generator.DungeonFlow; switch (((Object)dungeonFlow).name) { case "Level1Flow": interiorType = InteriorType.Facility; break; case "Level2Flow": interiorType = InteriorType.Mansion; break; case "Level3Flow": interiorType = InteriorType.Mineshaft; break; default: interiorType = InteriorType.Other; break; } Plugin.Instance.LogInfoExtended("Found interior: " + Utils.GetEnumName(interiorType) + " \"" + ((Object)dungeonFlow).name + "\"."); } } catch { interiorType = InteriorType.None; } } public static bool IsFacilityInterior() { return interiorType == InteriorType.Facility; } } internal static class NetworkUtils { 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 (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", "1.4.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] internal class Plugin : BaseUnityPlugin { private readonly Harmony harmony = new Harmony("com.github.zehsteam.MonsterHotkeys"); internal static Plugin Instance; internal static ManualLogSource logger; internal static SyncedConfigManager ConfigManager; internal static HotkeyInputClass InputActionsInstance; 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(MenuManagerPatch)); harmony.PatchAll(typeof(StartOfRoundPatch)); harmony.PatchAll(typeof(RoundManagerPatch)); harmony.PatchAll(typeof(HUDManagerPatch)); harmony.PatchAll(typeof(PlayerControllerBPatch)); harmony.PatchAll(typeof(EnemyAIPatch)); if (CrowdControlProxy.Enabled) { CrowdControlProxy.PatchAll(harmony); } ConfigManager = new SyncedConfigManager(); InputActionsInstance = new HotkeyInputClass(); Content.Load(); HotkeyListener.SetupKeybindCallbacks(); Content.EnemyDataList.Initialize(); TwitchEvents.Initialize(); EnemyHelper.Initialize(); PlushieManager.Initialize(); NetcodePatcherAwake(); } 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 OnLocalDisconnect() { logger.LogInfo((object)"Local player disconnected. Removing hostConfigData."); ConfigManager.SetHostConfigData(null); } public void SpawnMessageCanvas() { if (!((Object)(object)MessageCanvas.Instance != (Object)null)) { Object.Instantiate<GameObject>(Content.MessageCanvasPrefab); } } public void LogInfoExtended(object data) { if (ConfigManager.ExtendedLogging) { logger.LogInfo(data); } } public void LogWarningExtended(object data) { if (ConfigManager.ExtendedLogging) { logger.LogWarning(data); } } public void LogMessageExtended(object data) { if (ConfigManager.ExtendedLogging) { logger.LogMessage(data); } } } [Serializable] public class SyncedConfigData : INetworkSerializable { public int Plushie_SpawnCount; public float Plushie_DespawnDuration; public bool Plushie_PlaySFXOnCollision; public bool Plushie_AttractDogs; public float Plushie_Scale; public SyncedConfigData() { } public SyncedConfigData(SyncedConfigManager configManager) { Plushie_SpawnCount = configManager.Plushie_SpawnCount; Plushie_DespawnDuration = configManager.Plushie_DespawnDuration; Plushie_PlaySFXOnCollision = configManager.Plushie_PlaySFXOnCollision; Plushie_AttractDogs = configManager.Plushie_AttractDogs; Plushie_Scale = configManager.Plushie_Scale; } public unsafe void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) ((BufferSerializer<int>*)(&serializer))->SerializeValue<int>(ref Plushie_SpawnCount, default(ForPrimitives)); ((BufferSerializer<float>*)(&serializer))->SerializeValue<float>(ref Plushie_DespawnDuration, default(ForPrimitives)); ((BufferSerializer<bool>*)(&serializer))->SerializeValue<bool>(ref Plushie_PlaySFXOnCollision, default(ForPrimitives)); ((BufferSerializer<bool>*)(&serializer))->SerializeValue<bool>(ref Plushie_AttractDogs, default(ForPrimitives)); ((BufferSerializer<float>*)(&serializer))->SerializeValue<float>(ref Plushie_Scale, default(ForPrimitives)); } } public class SyncedConfigManager { private SyncedConfigData _hostConfigData; private ConfigEntry<bool> ExtendedLoggingCfg; private ConfigEntry<bool> Monster_OnlyHostSpawnMonstersCfg; private ConfigEntry<bool> Monster_MuteSpawnSFXCfg; private ConfigEntry<bool> Monster_SpawnStunnedCfg; private ConfigEntry<float> Monster_StunDurationCfg; private ConfigEntry<int> Plushie_SpawnCountCfg; private ConfigEntry<float> Plushie_DespawnDurationCfg; private ConfigEntry<float> Plushie_SFXVolumeCfg; private ConfigEntry<bool> Plushie_PlaySFXOnCollisionCfg; private ConfigEntry<bool> Plushie_AttractDogsCfg; private ConfigEntry<float> Plushie_ScaleCfg; private ConfigEntry<bool> Message_ShowMessagesCfg; private ConfigEntry<bool> Message_ShowSpawnEnemyMessagesCfg; private ConfigEntry<bool> Message_ShowLocalSpawnEnemyMessagesCfg; private ConfigEntry<bool> Message_ShowDetailedTwitchEventSpawnEnemyMessagesCfg; private ConfigEntry<float> Message_DurationCfg; private ConfigEntry<int> Message_FontSizeCfg; private ConfigEntry<int> Message_BackgroundTransparencyCfg; private ConfigEntry<bool> CrowdControl_EnabledCfg; private ConfigEntry<bool> TwitchIntegration_EnabledCfg; private ConfigEntry<string> TwitchIntegration_UsernameCfg; private ConfigEntry<string> TwitchEvent_CheckMessageFromUserCfg; private ConfigEntry<bool> TwitchSubEvent_EnabledCfg; private ConfigEntry<bool> TwitchSubEvent_SpawnAllOfTheSameEnemyCfg; private ConfigEntry<bool> TwitchBitsEvent_EnabledCfg; private ConfigEntry<int> TwitchBitsEvent_MinAmountToSpawnMonsterCfg; private ConfigEntry<int> TwitchBitsEvent_MinAmountToSpawnPlushiesCfg; private ConfigEntry<bool> EnemyNametag_EnabledCfg; private ConfigEntry<bool> EnemyNametag_ShowPlatformCfg; private ConfigEntry<float> EnemyNametag_ScaleMultiplierCfg; private ConfigEntry<int> EnemyNametag_BackgroundTransparencyCfg; internal bool ExtendedLogging { get { return ExtendedLoggingCfg.Value; } set { ExtendedLoggingCfg.Value = value; } } internal bool Monster_OnlyHostSpawnMonsters { get { return Monster_OnlyHostSpawnMonstersCfg.Value; } set { Monster_OnlyHostSpawnMonstersCfg.Value = value; } } internal bool Monster_MuteSpawnSFX { get { return Monster_MuteSpawnSFXCfg.Value; } set { Monster_MuteSpawnSFXCfg.Value = value; } } internal bool Monster_SpawnStunned { get { return Monster_SpawnStunnedCfg.Value; } set { Monster_SpawnStunnedCfg.Value = value; } } internal float Monster_StunDuration { get { return Monster_StunDurationCfg.Value; } set { Monster_StunDurationCfg.Value = value; } } internal int Plushie_SpawnCount { get { return (_hostConfigData == null) ? Plushie_SpawnCountCfg.Value : _hostConfigData.Plushie_SpawnCount; } set { Plushie_SpawnCountCfg.Value = value; SyncedConfigsChanged(); } } internal float Plushie_DespawnDuration { get { float num = ((_hostConfigData == null) ? Plushie_DespawnDurationCfg.Value : _hostConfigData.Plushie_DespawnDuration); return Mathf.Max(num, 0.1f); } set { Plushie_DespawnDurationCfg.Value = value; SyncedConfigsChanged(); } } internal bool Plushie_PlaySFXOnCollision { get { return (_hostConfigData == null) ? Plushie_PlaySFXOnCollisionCfg.Value : _hostConfigData.Plushie_PlaySFXOnCollision; } set { Plushie_PlaySFXOnCollisionCfg.Value = value; SyncedConfigsChanged(); } } internal float Plushie_SFXVolume { get { return Plushie_SFXVolumeCfg.Value; } set { Plushie_SFXVolumeCfg.Value = value; } } internal bool Plushie_AttractDogs { get { return (_hostConfigData == null) ? Plushie_AttractDogsCfg.Value : _hostConfigData.Plushie_AttractDogs; } set { Plushie_AttractDogsCfg.Value = value; SyncedConfigsChanged(); } } internal float Plushie_Scale { get { float num = ((_hostConfigData == null) ? Plushie_ScaleCfg.Value : _hostConfigData.Plushie_Scale); return Mathf.Max(num, 0.1f); } set { Plushie_ScaleCfg.Value = value; SyncedConfigsChanged(); } } internal bool Message_ShowMessages { get { return Message_ShowMessagesCfg.Value; } set { Message_ShowMessagesCfg.Value = value; } } internal bool Message_ShowSpawnEnemyMessages { get { return Message_ShowSpawnEnemyMessagesCfg.Value; } set { Message_ShowSpawnEnemyMessagesCfg.Value = value; } } internal bool Message_ShowLocalSpawnEnemyMessages { get { return Message_ShowLocalSpawnEnemyMessagesCfg.Value; } set { Message_ShowLocalSpawnEnemyMessagesCfg.Value = value; } } internal bool Message_ShowDetailedTwitchEventSpawnEnemyMessages { get { return Message_ShowDetailedTwitchEventSpawnEnemyMessagesCfg.Value; } set { Message_ShowDetailedTwitchEventSpawnEnemyMessagesCfg.Value = value; } } internal float Message_Duration { get { return Mathf.Max(Message_DurationCfg.Value, 0.1f); } set { Message_DurationCfg.Value = value; } } internal int Message_FontSize { get { return Mathf.Max(Message_FontSizeCfg.Value, 1); } set { Message_FontSizeCfg.Value = value; } } internal int Message_BackgroundTransparency { get { return Message_BackgroundTransparencyCfg.Value; } set { Message_BackgroundTransparencyCfg.Value = value; } } internal bool CrowdControl_Enabled { get { return CrowdControl_EnabledCfg.Value; } set { CrowdControl_EnabledCfg.Value = value; } } internal bool TwitchIntegration_Enabled { get { return TwitchIntegration_EnabledCfg.Value; } set { TwitchIntegration_EnabledCfg.Value = value; } } internal string TwitchIntegration_Username { get { return TwitchIntegration_UsernameCfg.Value; } set { TwitchIntegration_UsernameCfg.Value = value; } } internal string TwitchEvent_CheckMessageFromUser { get { return TwitchEvent_CheckMessageFromUserCfg.Value; } set { TwitchEvent_CheckMessageFromUserCfg.Value = value; } } internal bool TwitchSubEvent_Enabled { get { return TwitchSubEvent_EnabledCfg.Value; } set { TwitchSubEvent_EnabledCfg.Value = value; } } internal bool TwitchSubEvent_SpawnAllOfTheSameEnemy { get { return TwitchSubEvent_SpawnAllOfTheSameEnemyCfg.Value; } set { TwitchSubEvent_SpawnAllOfTheSameEnemyCfg.Value = value; } } internal bool TwitchBitsEvent_Enabled { get { return TwitchBitsEvent_EnabledCfg.Value; } set { TwitchBitsEvent_EnabledCfg.Value = value; } } internal int TwitchBitsEvent_MinAmountToSpawnMonster { get { return TwitchBitsEvent_MinAmountToSpawnMonsterCfg.Value; } set { TwitchBitsEvent_MinAmountToSpawnMonsterCfg.Value = value; } } internal int TwitchBitsEvent_MinAmountToSpawnPlushies { get { return TwitchBitsEvent_MinAmountToSpawnPlushiesCfg.Value; } set { TwitchBitsEvent_MinAmountToSpawnPlushiesCfg.Value = value; } } internal bool EnemyNametag_Enabled { get { return EnemyNametag_EnabledCfg.Value; } set { EnemyNametag_EnabledCfg.Value = value; } } internal bool EnemyNametag_ShowPlatform { get { return EnemyNametag_ShowPlatformCfg.Value; } set { EnemyNametag_ShowPlatformCfg.Value = value; } } internal float EnemyNametag_ScaleMultiplier { get { return EnemyNametag_ScaleMultiplierCfg.Value; } set { EnemyNametag_ScaleMultiplierCfg.Value = value; } } internal int EnemyNametag_BackgroundTransparency { get { return EnemyNametag_BackgroundTransparencyCfg.Value; } set { EnemyNametag_BackgroundTransparencyCfg.Value = value; } } public SyncedConfigManager() { BindConfigs(); SetupChangedEvents(); } private void BindConfigs() { ConfigHelper.SkipAutoGen(); ExtendedLoggingCfg = ConfigHelper.Bind("General Settings", "ExtendedLogging", defaultValue: false, requiresRestart: false, "Enable extended logging."); Monster_OnlyHostSpawnMonstersCfg = ConfigHelper.Bind("Monster Settings", "OnlyHostSpawnMonsters", defaultValue: false, requiresRestart: false, "If enabled, only the host can spawn enemies."); Monster_MuteSpawnSFXCfg = ConfigHelper.Bind("Monster Settings", "MuteSpawnSFX", defaultValue: false, requiresRestart: false, "If enabled, the enemy spawn sfx will not play."); Monster_SpawnStunnedCfg = ConfigHelper.Bind("Monster Settings", "SpawnStunned", defaultValue: false, requiresRestart: false, "If enabled, spawned enemies will be stunned for StunDuration seconds."); Monster_StunDurationCfg = ConfigHelper.Bind("Monster Settings", "StunDuration", 6f, requiresRestart: false, "The duration enemies will be stunned for in seconds."); Plushie_SpawnCountCfg = ConfigHelper.Bind("Plushie Settings", "SpawnCount", 30, requiresRestart: false, "The amount of plushies to spawn.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100)); Plushie_DespawnDurationCfg = ConfigHelper.Bind("Plushie Settings", "DespawnDuration", 15f, requiresRestart: false, "The duration in seconds until a plushie gets despawned."); Plushie_SFXVolumeCfg = ConfigHelper.Bind("Plushie Settings", "SFXVolume", 25f, requiresRestart: false, "The volume of the plushie's squeak sound effect.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f)); Plushie_PlaySFXOnCollisionCfg = ConfigHelper.Bind("Plushie Settings", "PlaySFXOnCollision", defaultValue: true, requiresRestart: false, "If enabled, the plushies will play a sound effect when colliding with the environment."); Plushie_AttractDogsCfg = ConfigHelper.Bind("Plushie Settings", "AttractDogs", defaultValue: true, requiresRestart: false, "If enabled, the plushies will attract dogs when making noise."); Plushie_ScaleCfg = ConfigHelper.Bind("Plushie Settings", "Scale", 4f, requiresRestart: false, "The size of the plushies."); Message_ShowMessagesCfg = ConfigHelper.Bind("Message Settings", "ShowMessages", defaultValue: true, requiresRestart: false, "If enabled, will show messages in the bottom right."); Message_ShowSpawnEnemyMessagesCfg = ConfigHelper.Bind("Message Settings", "ShowSpawnEnemyMessages", defaultValue: true, requiresRestart: false, "If enabled, will show a message when someone else spawns an enemy."); Message_ShowLocalSpawnEnemyMessagesCfg = ConfigHelper.Bind("Message Settings", "ShowLocalSpawnEnemyMessages", defaultValue: true, requiresRestart: false, "If enabled, will show a message when you spawn an enemy."); Message_ShowDetailedTwitchEventSpawnEnemyMessagesCfg = ConfigHelper.Bind("Message Settings", "ShowDetailedTwitchEventSpawnEnemyMessages", defaultValue: true, requiresRestart: false, "If enabled, will show a detailed Twitch event spawn enemy messages."); Message_DurationCfg = ConfigHelper.Bind("Message Settings", "Duration", 8f, requiresRestart: false, "The duration of a message in seconds."); Message_FontSizeCfg = ConfigHelper.Bind("Message Settings", "FontSize", 25, requiresRestart: false, "The font size of the messages."); Message_BackgroundTransparencyCfg = ConfigHelper.Bind("Message Settings", "BackgroundTransparency", 192, requiresRestart: false, "The transparency of the message background.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 255)); CrowdControl_EnabledCfg = ConfigHelper.Bind("Crowd Control Integration Settings", "Enabled", defaultValue: true, requiresRestart: false, "If enabled, Crowd Control will be able to spawn enemies anywhere and spawned enemies will have a nametag with the name of the user who spawned that enemy."); TwitchIntegration_EnabledCfg = ConfigHelper.Bind("Twitch Integration Settings", "Enabled", defaultValue: false, requiresRestart: false, "Enable events from Twitch chat."); TwitchIntegration_UsernameCfg = ConfigHelper.Bind("Twitch Integration Settings", "Username", "", requiresRestart: false, "Your Twitch username."); ConfigHelper.AddButton("Twitch Integration Settings", "Refresh Connection", "Click to refresh the connection to Twitch.", "Refresh", TwitchIntegration_Refresh_OnButtonClicked); TwitchEvent_CheckMessageFromUserCfg = ConfigHelper.Bind("Twitch Event Settings", "CheckMessageFromUser", "", requiresRestart: false, "The username of the Twitch bot which will be sending the messages for the Twitch events. The Twitch bot must send specific messages for these events. (See README on the Thunderstore page for full details)"); TwitchSubEvent_EnabledCfg = ConfigHelper.Bind("Twitch Subs Event Settings", "Enabled", defaultValue: true, requiresRestart: false, "If enabled, subs will spawn random enemies. (Requires Twitch Integration to be enabled)"); TwitchSubEvent_SpawnAllOfTheSameEnemyCfg = ConfigHelper.Bind("Twitch Subs Event Settings", "SpawnAllOfTheSameEnemy", defaultValue: true, requiresRestart: false, "If enabled, will only spawn enemies of one type."); TwitchBitsEvent_EnabledCfg = ConfigHelper.Bind("Twitch Bits Event Settings", "Enabled", defaultValue: true, requiresRestart: false, "If enabled, bits will spawn a random enemies or random plushies. (Requires Twitch Integration to be enabled)"); TwitchBitsEvent_MinAmountToSpawnMonsterCfg = ConfigHelper.Bind("Twitch Bits Event Settings", "MinAmountToSpawnMonster", 495, requiresRestart: false, "The min amount of bits to spawn a random enemy."); TwitchBitsEvent_MinAmountToSpawnPlushiesCfg = ConfigHelper.Bind("Twitch Bits Event Settings", "MinAmountToSpawnPlushies", 90, requiresRestart: false, "The min amount of bits to spawn random plushies."); EnemyNametag_EnabledCfg = ConfigHelper.Bind("Enemy Nametag Settings", "Enabled", defaultValue: true, requiresRestart: false, "If enabled, nametags will spawn on enemies spawned by Twitch sub events."); EnemyNametag_ShowPlatformCfg = ConfigHelper.Bind("Enemy Nametag Settings", "ShowPlatform", defaultValue: true, requiresRestart: false, "If enabled, nametags will show which platform the enemy was spawned from."); EnemyNametag_ScaleMultiplierCfg = ConfigHelper.Bind("Enemy Nametag Settings", "ScaleMultiplier", 1f, requiresRestart: false, "The scale multiplier for enemy nametags.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 5f)); EnemyNametag_BackgroundTransparencyCfg = ConfigHelper.Bind("Enemy Nametag Settings", "BackgroundTransparency", 192, requiresRestart: false, "The transparency of the nametag background.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 255)); } private void SetupChangedEvents() { Monster_MuteSpawnSFXCfg.SettingChanged += AudioPlayerManager.OnSettingsChanged; Plushie_SpawnCountCfg.SettingChanged += PlushieManager.OnSettingsChanged; Plushie_SFXVolumeCfg.SettingChanged += Plushie.OnSettingsChanged; Message_FontSizeCfg.SettingChanged += MessageItem.OnSettingsChanged; Message_BackgroundTransparencyCfg.SettingChanged += MessageItem.OnSettingsChanged; TwitchIntegration_EnabledCfg.SettingChanged += TwitchIntegrationEnabled_SettingChanged; TwitchIntegration_UsernameCfg.SettingChanged += TwitchIntegrationUsername_SettingChanged; EnemyNametag_ScaleMultiplierCfg.SettingChanged += EnemyNametag.OnSettingsChanged; EnemyNametag_ShowPlatformCfg.SettingChanged += EnemyNametag.OnSettingsChanged; EnemyNametag_BackgroundTransparencyCfg.SettingChanged += EnemyNametag.OnSettingsChanged; } private void TwitchIntegrationEnabled_SettingChanged(object sender, EventArgs e) { if (TwitchIntegration_Enabled) { TwitchChat.StartReading(); } else { TwitchChat.StopReading(); } } private void TwitchIntegrationUsername_SettingChanged(object sender, EventArgs e) { if (NetworkUtils.IsServer && TwitchIntegration_Enabled) { TwitchChat.StartReading(); } } private void TwitchIntegration_Refresh_OnButtonClicked() { if (TwitchIntegration_Enabled) { TwitchChat.StartReading(); } else { TwitchChat.StopReading(); } } private void ClearUnusedEntries() { ConfigFile config = ((BaseUnityPlugin)Plugin.Instance).Config; PropertyInfo property = ((object)config).GetType().GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.NonPublic); Dictionary<ConfigDefinition, string> dictionary = (Dictionary<ConfigDefinition, string>)property.GetValue(config, null); dictionary.Clear(); config.Save(); } internal void SetHostConfigData(SyncedConfigData syncedConfigData) { if (!NetworkUtils.IsServer) { _hostConfigData = syncedConfigData; } } private void SyncedConfigsChanged() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) if (NetworkUtils.IsServer) { PluginNetworkBehaviour.Instance.SendConfigToPlayerClientRpc(new SyncedConfigData(this)); } } } internal static class TwitchChat { public const string TwitchServer = "irc.chat.twitch.tv"; public const int TwitchPort = 6667; private static TcpClient _tcpClient; private static NetworkStream _stream; private static StreamReader _reader; private static StreamWriter _writer; private static CancellationTokenSource _cts; private static Task _readTask; public static string TwitchChannel => ("#" + Plugin.ConfigManager.TwitchIntegration_Username).Trim(); public static bool IsReading { get; private set; } public static bool IsBusy { get; private set; } public static DateTime? TimeStartedReading { get; private set; } public static Action<TwitchMessage> OnMessage { get; set; } public static async Task StartReading() { Plugin.Instance.LogMessageExtended("[TwitchChat] Trying to start reading."); if (TwitchChannel == "#") { Plugin.Instance.LogMessageExtended("[TwitchChat] Twitch username is empty!"); return; } if (IsBusy) { Plugin.Instance.LogMessageExtended("[TwitchChat] Process is busy."); return; } if (IsReading) { Plugin.Instance.LogMessageExtended("[TwitchChat] You are already reading."); await StopReading(); } IsBusy = true; _cts = new CancellationTokenSource(); CancellationToken token = _cts.Token; try { _tcpClient = new TcpClient("irc.chat.twitch.tv", 6667); _stream = _tcpClient.GetStream(); _reader = new StreamReader(_stream); _writer = new StreamWriter(_stream) { AutoFlush = true }; await _writer.WriteLineAsync("PASS 1337"); await _writer.WriteLineAsync("NICK justinfan123"); await _writer.WriteLineAsync("JOIN " + TwitchChannel); Plugin.Instance.LogMessageExtended("[TwitchChat] Started reading."); IsReading = true; TimeStartedReading = DateTime.Now; } catch (Exception ex) { Exception e = ex; Plugin.logger.LogError((object)$"[TwitchChat] Failed to start reading Twitch chat. {e}"); } finally { IsBusy = false; } _readTask = Task.Run(async delegate { try { while (!token.IsCancellationRequested) { string message = await _reader.ReadLineAsync(); if (message != null) { if (message.StartsWith("PING")) { Plugin.Instance.LogMessageExtended(message); await _writer.WriteLineAsync("PONG " + message.Split(' ')[1]); Plugin.Instance.LogMessageExtended("[TwitchChat] Responded with PONG to keep connection alive."); } else { ParseMessage(message); } } } } catch (TaskCanceledException) { Plugin.logger.LogError((object)"[TwitchChat] StartReading task canceled."); } catch (Exception ex3) { Exception e2 = ex3; if (Plugin.ConfigManager.TwitchIntegration_Enabled) { Plugin.logger.LogError((object)$"[TwitchChat] StartReading task failed. {e2}"); } } finally { IsReading = false; } }, token); } public static async Task StopReading() { Plugin.Instance.LogMessageExtended("[TwitchChat] Trying to stop reading."); if (!IsReading || IsBusy) { Plugin.Instance.LogMessageExtended("[TwitchChat] Not reading or busy. No need to stop or wait for the current process."); return; } IsBusy = true; if (_cts != null) { _cts.Cancel(); try { } catch (TaskCanceledException) { } finally { IsReading = false; TimeStartedReading = null; _reader?.Close(); _writer?.Close(); _stream?.Close(); _tcpClient?.Close(); Plugin.Instance.LogMessageExtended("[TwitchChat] Stopped reading."); } } IsBusy = false; } private static void ParseMessage(string message) { if (message.StartsWith(":tmi.twitch.tv") || message.StartsWith(":justinfan123")) { Plugin.Instance.LogMessageExtended(message); } else if (message.StartsWith(":")) { string[] array = message.Split(' '); string text = array[0].Substring(1).Split('!')[0]; string text2 = array[2]; string text3 = message.Substring(message.IndexOf(text2) + text2.Length + 2); Plugin.Instance.LogMessageExtended($"[TwitchChat] [{DateTime.Now:HH:mm}] info: [{text2}] <{text}>: {text3}"); if (Plugin.ConfigManager.TwitchIntegration_Enabled) { OnMessage?.Invoke(new TwitchMessage(text, text3)); } } } } public struct TwitchMessage { public string Sender; public string Message; public TwitchMessage(string sender, string message) { Sender = sender; Message = message; } } internal static class TwitchEvents { public static Action<TwitchSubEvent> OnSub { get; set; } public static Action<TwitchBitsEvents> OnBits { get; set; } public static void Initialize() { TwitchChat.OnMessage = (Action<TwitchMessage>)Delegate.Combine(TwitchChat.OnMessage, new Action<TwitchMessage>(ParseMessageForSub)); TwitchChat.OnMessage = (Action<TwitchMessage>)Delegate.Combine(TwitchChat.OnMessage, new Action<TwitchMessage>(ParseMessageForBits)); } private static void ParseMessageForSub(TwitchMessage twitchMessage) { if (!Plugin.ConfigManager.TwitchSubEvent_Enabled || !IsCorrectUserForEvents(twitchMessage.Sender)) { return; } string text = twitchMessage.Message.Replace("@", ""); text = text.Replace("(test)", "", StringComparison.OrdinalIgnoreCase); text = text.Replace("An Anonymous Gifter", "Anonymous", StringComparison.OrdinalIgnoreCase); text = text.Trim(); if (!IsSubMessage(text, out var subType)) { return; } try { Match match = Regex.Match(text, "^(\\w+)\\s"); string sender = (match.Success ? match.Groups[1].Value : string.Empty); Match match2 = Regex.Match(text, "gifted\\s(\\d+)\\s"); int amount = ((!match2.Success) ? 1 : int.Parse(match2.Groups[1].Value)); Match match3 = Regex.Match(text, "for\\s(\\d+)\\s+months"); int months = ((!match3.Success) ? 1 : int.Parse(match3.Groups[1].Value)); Match match4 = Regex.Match(text, "gifted a sub to (\\w+)\\s"); string target = (match4.Success ? match4.Groups[1].Value : string.Empty); InvokeActionNextFrame(OnSub, new TwitchSubEvent(sender, subType, 1, amount, months, target)); } catch (Exception arg) { Plugin.logger.LogError((object)$"[TwitchEvents] Failed to parse message for Twitch sub event. {arg}"); } } private static bool IsSubMessage(string message, out TwitchSubType subType) { subType = TwitchSubType.Sub; if (!message.EndsWith("<3")) { return false; } if (message.Contains("just subbed", StringComparison.OrdinalIgnoreCase)) { return true; } if (message.Contains("just resubbed", StringComparison.OrdinalIgnoreCase)) { subType = TwitchSubType.Resub; return true; } if (message.Contains("gifted a sub to", StringComparison.OrdinalIgnoreCase)) { subType = TwitchSubType.Gift; return true; } if (message.Contains("gifted", StringComparison.OrdinalIgnoreCase)) { subType = TwitchSubType.MysteryGift; return true; } return false; } private static void ParseMessageForBits(TwitchMessage twitchMessage) { if (!Plugin.ConfigManager.TwitchBitsEvent_Enabled || !IsCorrectUserForEvents(twitchMessage.Sender)) { return; } string text = twitchMessage.Message.Replace("@", ""); text = text.Replace("(test)", "").Trim(); if (!IsBitsMessage(text)) { return; } try { Match match = Regex.Match(text, "^(\\w+)\\s"); string sender = (match.Success ? match.Groups[1].Value : string.Empty); Match match2 = Regex.Match(text, "just dropped\\s(\\d+)\\s+bits"); int amount = (match2.Success ? int.Parse(match2.Groups[1].Value) : 0); InvokeActionNextFrame(OnBits, new TwitchBitsEvents(sender, amount)); } catch (Exception arg) { Plugin.logger.LogError((object)$"[TwitchEvents] Failed to parse message for Twitch bits event. {arg}"); } } private static bool IsBitsMessage(string message) { if (!message.EndsWith("<3")) { return false; } if (!message.Contains("just dropped", StringComparison.OrdinalIgnoreCase)) { return false; } if (!message.Contains("bits", StringComparison.OrdinalIgnoreCase)) { return false; } return true; } private static bool IsCorrectUserForEvents(string sender) { if (string.IsNullOrWhiteSpace(sender)) { return false; } string value = Plugin.ConfigManager.TwitchEvent_CheckMessageFromUser.Trim(); if (!string.IsNullOrWhiteSpace(value) && sender.Equals(value, StringComparison.OrdinalIgnoreCase)) { return true; } string value2 = Plugin.ConfigManager.TwitchIntegration_Username.Trim(); if (!string.IsNullOrWhiteSpace(value2) && sender.Equals(value2, StringComparison.OrdinalIgnoreCase)) { return true; } return false; } public static void InvokeActionNextFrame<T>(Action<T> action, T data) { Utils.StartCoroutine(InvokeActionNextFrameCoroutine(action, data)); } private static IEnumerator InvokeActionNextFrameCoroutine<T>(Action<T> action, T data) { yield return null; action?.Invoke(data); } } [Serializable] public class TwitchEvent { public string Sender; public TwitchEvent() { } public TwitchEvent(string sender) { Sender = sender; } } [Serializable] public class TwitchSubEvent : TwitchEvent, INetworkSerializable { public TwitchSubType SubType; public int Tier; public int Amount; public int Months; public string Target; public TwitchSubEvent() { } public TwitchSubEvent(string sender, TwitchSubType subType, int tier = 1, int amount = 1, int months = 1, string target = "") : base(sender) { SubType = subType; Tier = tier; Amount = amount; Months = months; Target = target; } public unsafe void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) serializer.SerializeValue(ref Sender, false); ((BufferSerializer<TwitchSubType>*)(&serializer))->SerializeValue<TwitchSubType>(ref SubType, default(ForEnums)); ((BufferSerializer<int>*)(&serializer))->SerializeValue<int>(ref Tier, default(ForPrimitives)); ((BufferSerializer<int>*)(&serializer))->SerializeValue<int>(ref Amount, default(ForPrimitives)); ((BufferSerializer<int>*)(&serializer))->SerializeValue<int>(ref Months, default(ForPrimitives)); serializer.SerializeValue(ref Target, false); } } public enum TwitchSubType { Sub, Resub, Gift, MysteryGift } [Serializable] public class TwitchBitsEvents : TwitchEvent, INetworkSerializable { public int Amount; public TwitchBitsEvents() { } public TwitchBitsEvents(string sender, int amount) : base(sender) { Amount = amount; } public unsafe void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) serializer.SerializeValue(ref Sender, false); ((BufferSerializer<int>*)(&serializer))->SerializeValue<int>(ref Amount, default(ForPrimitives)); } } internal static class Utils { public static bool RandomPercent(float percent) { if (percent <= 0f) { return false; } if (percent >= 100f) { return true; } return Random.value * 100f <= percent; } public static string GetEnumName(object e) { try { return Enum.GetName(e.GetType(), e); } catch { return string.Empty; } } 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 class MyPluginInfo { public const string PLUGIN_GUID = "com.github.zehsteam.MonsterHotkeys"; public const string PLUGIN_NAME = "MonsterHotkeys"; public const string PLUGIN_VERSION = "1.4.0"; } } namespace com.github.zehsteam.MonsterHotkeys.Patches { [HarmonyPatch(typeof(EnemyAI))] internal static class EnemyAIPatch { public static EnemyAI EnemyAttackingLocalPlayer { get; private set; } [HarmonyPatch("KillEnemy")] [HarmonyPrefix] private static void KillEnemyPatch(ref EnemyAI __instance) { if (__instance.enemyType.canDie) { EnemyNametagManager.Instance?.DespawnNametagOnLocalClient(__instance); } } [HarmonyPatch("MeetsStandardPlayerCollisionConditions")] [HarmonyPostfix] private static void MeetsStandardPlayerCollisionConditionsPatch(ref EnemyAI __instance, ref PlayerControllerB __result) { if (PlayerUtils.IsLocalPlayer(__result)) { EnemyAttackingLocalPlayer = __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 add 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(MenuManager))] internal static class MenuManagerPatch { [HarmonyPatch("Start")] [HarmonyPostfix] private static void StartPatch() { if (Plugin.ConfigManager.TwitchIntegration_Enabled && !TwitchChat.IsReading) { TwitchChat.StartReading(); } } } [HarmonyPatch(typeof(PlayerControllerB))] internal static class PlayerControllerBPatch { [HarmonyPatch("KillPlayer")] [HarmonyPostfix] private static void KillPlayerPatch(ref PlayerControllerB __instance) { if (!PlayerUtils.IsLocalPlayer(__instance) || (Object)(object)EnemyAIPatch.EnemyAttackingLocalPlayer == (Object)null) { return; } 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; if (!(declaringType != null)) { continue; } Type type = declaringType; if (declaringType.Name.Contains("<") || declaringType.Name.Contains("+")) { type = declaringType.DeclaringType; } if (type != null && type.IsSubclassOf(typeof(EnemyAI))) { if (!(type != ((object)EnemyAIPatch.EnemyAttackingLocalPlayer).GetType()) && __instance.isPlayerDead) { LocalPlayerDiedToEnemy(); } break; } } } private static void LocalPlayerDiedToEnemy() { EnemyAI enemyAttackingLocalPlayer = EnemyAIPatch.EnemyAttackingLocalPlayer; if (!((Object)(object)enemyAttackingLocalPlayer == (Object)null) && EnemyNametagManager.Instance.EnemyNametagPairs.TryGetValue(enemyAttackingLocalPlayer, out var value)) { EnemyData byEnemyName = Content.EnemyDataList.GetByEnemyName(enemyAttackingLocalPlayer.enemyType.enemyName); string text = (value.Username + " " + value.GetPlatformSpriteText()).Trim(); string text2 = "You died to a " + byEnemyName.EnemyDisplayName + " from " + text; if (!PlayerUtils.IsLocalPlayer(value.PlayerScript) && value.Username != value.PlayerScript.playerUsername) { text2 = text2 + " <color=#9c9c9c>(Spawned from " + value.PlayerScript.playerUsername + ")</color>"; } DeathMessage.Instance?.Show(text2); } } } [HarmonyPatch(typeof(RoundManager))] internal static class RoundManagerPatch { private static bool ShipArrived; [HarmonyPatch("LoadNewLevel")] [HarmonyPostfix] private static void LoadNewLevelPatch() { Plugin.Instance.OnNewLevelLoaded(); } [HarmonyPatch("GenerateNewLevelClientRpc")] [HarmonyPrefix] private static void GenerateNewLevelClientRpcPatch() { if (!NetworkUtils.IsServer) { Plugin.Instance.OnNewLevelLoaded(); } } [HarmonyPatch("FinishGeneratingNewLevelClientRpc")] [HarmonyPostfix] private static void FinishGeneratingNewLevelClientRpcPatch() { if (!ShipArrived) { ShipArrived = true; if (StartOfRound.Instance.currentLevel.spawnEnemiesAndScrap) { EnemyHelper.PlayTwitchEventsFromQueue(); PlushieManager.Instance?.PlayTwitchEventsFromQueue(); Utils.StartCoroutine(ResetShipArrivedAfterTime(10f)); } } } private static IEnumerator ResetShipArrivedAfterTime(float time) { yield return (object)new WaitForSeconds(time); ShipArrived = false; } } [HarmonyPatch(typeof(StartOfRound))] internal static class StartOfRoundPatch { [HarmonyPatch("Awake")] [HarmonyPostfix] private static void AwakePatch() { SpawnNetworkHandler(); } private static void SpawnNetworkHandler() { //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) if (NetworkUtils.IsServer) { GameObject val = Object.Instantiate<GameObject>(Content.NetworkHandlerPrefab, Vector3.zero, Quaternion.identity); val.GetComponent<NetworkObject>().Spawn(false); } } [HarmonyPatch("Start")] [HarmonyPostfix] [HarmonyPriority(0)] private static void StartPatch() { Content.EnemyDataList.AddNewEnemyTypes(); } [HarmonyPatch("OnClientConnect")] [HarmonyPrefix] private static void OnClientConnectPatch(ref ulong clientId) { SendConfigToNewConnectedPlayer(clientId); } private static void SendConfigToNewConnectedPlayer(ulong clientId) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002e: 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_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) if (NetworkUtils.IsServer) { ClientRpcParams val = default(ClientRpcParams); val.Send = new ClientRpcSendParams { TargetClientIds = new <>z__ReadOnlySingleElementList<ulong>(clientId) }; ClientRpcParams clientRpcParams = val; Plugin.logger.LogInfo((object)$"Sending config to client: {clientId}"); PluginNetworkBehaviour.Instance.SendConfigToPlayerClientRpc(new SyncedConfigData(Plugin.ConfigManager), clientRpcParams); } } [HarmonyPatch("OnLocalDisconnect")] [HarmonyPrefix] private static void OnLocalDisconnectPatch() { Plugin.Instance.OnLocalDisconnect(); } } } namespace com.github.zehsteam.MonsterHotkeys.MonoBehaviours { public class AudioPlayer : MonoBehaviour { public AudioSource AudioSource; public AudioClip BeforeSpawnSFX; public AudioClip GenericSpawnSFX; private Coroutine _playSoundCoroutine; public void PlaySound(AudioClip spawnSFX, float volumeScale) { if (_playSoundCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_playSoundCoroutine); } _playSoundCoroutine = ((MonoBehaviour)this).StartCoroutine(PlaySoundCoroutine(spawnSFX, volumeScale)); } private IEnumerator PlaySoundCoroutine(AudioClip spawnSFX, float volumeScale) { if ((Object)(object)spawnSFX == (Object)null) { spawnSFX = GenericSpawnSFX; } AudioSource.PlayOneShot(BeforeSpawnSFX, volumeScale); yield return (object)new WaitForSeconds(BeforeSpawnSFX.length + 0.25f); AudioSource.PlayOneShot(spawnSFX, volumeScale); yield return (object)new WaitForSeconds(spawnSFX.length); } } public class AudioPlayerManager : NetworkBehaviour { public static AudioPlayerManager Instance; public GameObject AudioPlayerPrefab; private Queue<AudioPlayer> _pool = new Queue<AudioPlayer>(); private void Awake() { if ((Object)(object)Instance == (Object)null) { Instance = this; } } private void Start() { UpdateSettings(); } private void CreatePool() { ClearPool(); int num = 100; for (int i = 0; i < num; i++) { GameObject val = Object.Instantiate<GameObject>(AudioPlayerPrefab); val.transform.SetParent(((Component)this).transform); AudioPlayer component = val.GetComponent<AudioPlayer>(); val.SetActive(false); _pool.Enqueue(component); } Plugin.Instance.LogInfoExtended($"Created AudioPlayer pool. (amount: {num})"); } private void ClearPool() { if (_pool.Count == 0) { return; } foreach (AudioPlayer item in _pool) { Object.Destroy((Object)(object)((Component)item).gameObject); } _pool.Clear(); Plugin.Instance.LogInfoExtended("Cleared AudioPlayer pool."); } private AudioPlayer SpawnFromPool(Vector3 position, AudioClip spawnSFX, float volumeScale) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) AudioPlayer audioPlayer = _pool.Dequeue(); ((Component)audioPlayer).gameObject.SetActive(false); ((Component)audioPlayer).gameObject.SetActive(true); ((Component)audioPlayer).transform.position = position; audioPlayer.PlaySound(spawnSFX, volumeScale); _pool.Enqueue(audioPlayer); return audioPlayer; } public void SpawnOnServer(string enemyName, Vector3[] positions, bool inFactory) { if (NetworkUtils.IsServer) { SpawnClientRpc(enemyName, positions, inFactory); SpawnOnLocalClient(enemyName, positions, inFactory); } } [ClientRpc] public void SpawnClientRpc(string enemyName, Vector3[] positions, bool inFactory) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: 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) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)base.__rpc_exec_stage != 2 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val = default(ClientRpcParams); FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendClientRpc(1947173315u, val, (RpcDelivery)0); bool flag = enemyName != null; ((FastBufferWriter)(ref val2)).WriteValueSafe<bool>(ref flag, default(ForPrimitives)); if (flag) { ((FastBufferWriter)(ref val2)).WriteValueSafe(enemyName, false); } bool flag2 = positions != null; ((FastBufferWriter)(ref val2)).WriteValueSafe<bool>(ref flag2, default(ForPrimitives)); if (flag2) { ((FastBufferWriter)(ref val2)).WriteValueSafe(positions); } ((FastBufferWriter)(ref val2)).WriteValueSafe<bool>(ref inFactory, default(ForPrimitives)); ((NetworkBehaviour)this).__endSendClientRpc(ref val2, 1947173315u, val, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 2 && (networkManager.IsClient || networkManager.IsHost) && !NetworkUtils.IsServer) { SpawnOnLocalClient(enemyName, positions, inFactory); } } private void SpawnOnLocalClient(string enemyName, Vector3[] positions, bool inFactory) { //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) if (_pool.Count == 0) { return; } PlayerControllerB localPlayerScript = PlayerUtils.GetLocalPlayerScript(); if ((Object)(object)localPlayerScript == (Object)null) { return; } bool flag = true; if (localPlayerScript.isPlayerDead) { if ((Object)(object)localPlayerScript.spectatedPlayerScript != (Object)null && localPlayerScript.spectatedPlayerScript.isInsideFactory && !inFactory) { flag = false; } } else if (localPlayerScript.isInsideFactory && !inFactory) { flag = false; } if (flag) { AudioClip spawnSFX = null; float num = 0.8f; EnemyData byEnemyName = Content.EnemyDataList.GetByEnemyName(enemyName); if (byEnemyName != null) { spawnSFX = byEnemyName.SpawnSFX; num = byEnemyName.ConfigData.SpawnSFXVolume.Value * 0.01f; } else { num = 0.8f; } foreach (Vector3 position in positions) { SpawnFromPool(position, spawnSFX, num); } } } public void UpdateSettings() { if (Plugin.ConfigManager.Monster_MuteSpawnSFX) { ClearPool(); } else { CreatePool(); } } public static void OnSettingsChanged(object sender, EventArgs e) { if (!((Object)(object)Instance == (Object)null)) { Instance.UpdateSettings(); } } protected override void __initializeVariables() { ((NetworkBehaviour)this).__initializeVariables(); } [RuntimeInitializeOnLoadMethod] internal static void InitializeRPCS_AudioPlayerManager() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown NetworkManager.__rpc_func_table.Add(1947173315u, new RpcReceiveHandler(__rpc_handler_1947173315)); } private static void __rpc_handler_1947173315(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_002f: 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_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_009e: 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_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { bool flag = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref flag, default(ForPrimitives)); string enemyName = null; if (flag) { ((FastBufferReader)(ref reader)).ReadValueSafe(ref enemyName, false); } bool flag2 = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref flag2, default(ForPrimitives)); Vector3[] positions = null; if (flag2) { ((FastBufferReader)(ref reader)).ReadValueSafe(ref positions); } bool inFactory = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref inFactory, default(ForPrimitives)); target.__rpc_exec_stage = (__RpcExecStage)2; ((AudioPlayerManager)(object)target).SpawnClientRpc(enemyName, positions, inFactory); target.__rpc_exec_stage = (__RpcExecStage)0; } } [MethodImpl(MethodImplOptions.NoInlining)] protected internal override string __getTypeName() { return "AudioPlayerManager"; } } public class DeathMessage : MonoBehaviour { public static DeathMessage Instance; public TextMeshProUGUI TextUGUI; public CanvasGroup CanvasGroup;