Decompiled source of TwitchTrolling v1.6.0
com.github.zehsteam.MetadataUtils.dll
Decompiled a week agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Logging; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.SceneManagement; using com.github.zehsteam.MetadataUtils.Modules; using com.github.zehsteam.MetadataUtils.Objects; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Zehs")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © 2025 Zehs")] [assembly: AssemblyFileVersion("1.1.0.0")] [assembly: AssemblyInformationalVersion("1.1.0+45627603d3869d4ee4f5fb1b7e7df530461a2c7c")] [assembly: AssemblyProduct("MetadataUtils")] [assembly: AssemblyTitle("com.github.zehsteam.MetadataUtils")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace com.github.zehsteam.MetadataUtils { internal static class Logger { public static ManualLogSource ManualLogSource { get; private set; } public static void Initialize(ManualLogSource manualLogSource) { ManualLogSource = manualLogSource; } public static void LogDebug(object data) { Log((LogLevel)32, data); } public static void LogInfo(object data) { Log((LogLevel)16, data); } public static void LogWarning(object data) { Log((LogLevel)4, data); } public static void LogError(object data) { Log((LogLevel)2, data); } public static void LogFatal(object data) { Log((LogLevel)1, data); } public static void Log(LogLevel logLevel, object data) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) ManualLogSource manualLogSource = ManualLogSource; if (manualLogSource != null) { manualLogSource.Log(logLevel, data); } } } [BepInPlugin("com.github.zehsteam.MetadataUtils", "MetadataUtils", "1.1.0")] internal class Plugin : BaseUnityPlugin { internal static Plugin Instance { get; private set; } private void Awake() { Instance = this; Logger.Initialize(Logger.CreateLogSource("com.github.zehsteam.MetadataUtils")); Logger.LogInfo("MetadataUtils has awoken!"); MetadataRegistry.Initialize(); } } public static class MyPluginInfo { public const string PLUGIN_GUID = "com.github.zehsteam.MetadataUtils"; public const string PLUGIN_NAME = "MetadataUtils"; public const string PLUGIN_VERSION = "1.1.0"; } } namespace com.github.zehsteam.MetadataUtils.Objects { public class Metadata { private Dictionary<string, object> _entries = new Dictionary<string, object>(); public Scene Scene { get; private set; } public Metadata(Scene scene) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) Scene = scene; } public bool Has(string key) { return _entries.ContainsKey(key); } public T Get<T>(string key, T defaultValue = default(T)) { if (TryGet<T>(key, out var value)) { return value; } return defaultValue; } public bool TryGet<T>(string key, out T value) { if (_entries.TryGetValue(key, out var value2) && value2 is T val) { value = val; return true; } value = default(T); return false; } public void Set<T>(string key, T value) { _entries[key] = value; } public void Set(Metadata metadata) { if (metadata != null) { _entries = metadata._entries; } } public bool Remove(string key) { return _entries.Remove(key); } } } namespace com.github.zehsteam.MetadataUtils.Modules { public static class MetadataRegistry { private static readonly Dictionary<Object, Metadata> _entries = new Dictionary<Object, Metadata>(); internal static void Initialize() { SceneManager.sceneUnloaded += HandleSceneUnloaded; } public static bool HasMetadata(Object obj) { return _entries.ContainsKey(obj); } public static Metadata GetOrCreate(Object obj) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) if (_entries.TryGetValue(obj, out var value)) { return value; } Scene scene = ExtractScene(obj); Metadata metadata = new Metadata(scene); _entries[obj] = metadata; return metadata; } public static bool TryGet(Object obj, out Metadata metadata) { return _entries.TryGetValue(obj, out metadata); } public static bool Remove(Object obj) { return _entries.Remove(obj); } private static Scene ExtractScene(Object obj) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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) GameObject val = (GameObject)(object)((obj is GameObject) ? obj : null); if (val != null) { return val.scene; } Component val2 = (Component)(object)((obj is Component) ? obj : null); if (val2 != null) { return val2.gameObject.scene; } return default(Scene); } private static void RemoveMetadataForScene(Scene scene) { //IL_0023: 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) Dictionary<Object, Metadata> dictionary = new Dictionary<Object, Metadata>(_entries); foreach (KeyValuePair<Object, Metadata> item in dictionary) { if (item.Value.Scene == scene) { _entries.Remove(item.Key); } } } private static void HandleSceneUnloaded(Scene scene) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) RemoveMetadataForScene(scene); } } } namespace com.github.zehsteam.MetadataUtils.Extensions { public static class ComponentExtensions { private const bool _defaultTargetGameObject = true; public static bool HasMetadata(this Component component, bool targetGameObject = true) { return MetadataRegistry.HasMetadata(GetObject(component, targetGameObject)); } public static Metadata GetOrCreateMetadata(this Component component, bool targetGameObject = true) { return MetadataRegistry.GetOrCreate(GetObject(component, targetGameObject)); } public static bool TryGetMetadata(this Component component, out Metadata metadata, bool targetGameObject = true) { return MetadataRegistry.TryGet(GetObject(component, targetGameObject), out metadata); } public static bool RemoveMetadata(this Component component, bool targetGameObject = true) { return MetadataRegistry.Remove(GetObject(component, targetGameObject)); } private static Object GetObject(Component component, bool targetGameObject) { if (!targetGameObject) { return (Object)(object)component; } return (Object)(object)component.gameObject; } } public static class GameObjectExtensions { public static bool HasMetadata(this GameObject gameObject) { return MetadataRegistry.HasMetadata((Object)(object)gameObject); } public static Metadata GetOrCreateMetadata(this GameObject gameObject) { return MetadataRegistry.GetOrCreate((Object)(object)gameObject); } public static bool TryGetMetadata(this GameObject gameObject, out Metadata metadata) { return MetadataRegistry.TryGet((Object)(object)gameObject, out metadata); } public static bool RemoveMetadata(this GameObject gameObject) { return MetadataRegistry.Remove((Object)(object)gameObject); } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }
com.github.zehsteam.PlayerDamageTracker.dll
Decompiled a week agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Mono.Cecil; using Mono.Cecil.Cil; using Photon.Pun; using UnityEngine; using com.github.zehsteam.MetadataUtils.Extensions; using com.github.zehsteam.MetadataUtils.Objects; using com.github.zehsteam.PlayerDamageTracker.Extensions; using com.github.zehsteam.PlayerDamageTracker.Helpers; using com.github.zehsteam.PlayerDamageTracker.Modules; using com.github.zehsteam.PlayerDamageTracker.Patches; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Zehs")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © 2025 Zehs")] [assembly: AssemblyFileVersion("1.1.0.0")] [assembly: AssemblyInformationalVersion("1.1.0+a499261de8bc0668ccaabdb241bb139052d1cd57")] [assembly: AssemblyProduct("PlayerDamageTracker")] [assembly: AssemblyTitle("com.github.zehsteam.PlayerDamageTracker")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace com.github.zehsteam.PlayerDamageTracker { internal static class Logger { public static ManualLogSource ManualLogSource { get; private set; } public static void Initialize(ManualLogSource manualLogSource) { ManualLogSource = manualLogSource; } public static void LogDebug(object data) { Log((LogLevel)32, data); } public static void LogInfo(object data) { Log((LogLevel)16, data); } public static void LogWarning(object data) { Log((LogLevel)4, data); } public static void LogError(object data) { Log((LogLevel)2, data); } public static void LogFatal(object data) { Log((LogLevel)1, data); } public static void Log(LogLevel logLevel, object data) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) ManualLogSource manualLogSource = ManualLogSource; if (manualLogSource != null) { manualLogSource.Log(logLevel, data); } } } [BepInPlugin("com.github.zehsteam.PlayerDamageTracker", "PlayerDamageTracker", "1.1.0")] internal class Plugin : BaseUnityPlugin { private readonly Harmony _harmony = new Harmony("com.github.zehsteam.PlayerDamageTracker"); internal static Plugin Instance { get; private set; } private void Awake() { Instance = this; Logger.Initialize(Logger.CreateLogSource("com.github.zehsteam.PlayerDamageTracker")); Logger.LogInfo("PlayerDamageTracker has awoken!"); _harmony.PatchAll(typeof(PlayerHealthPatch)); _harmony.PatchAll(typeof(HurtColliderPatch)); _harmony.PatchAll(typeof(ParticleScriptExplosionPatch)); _harmony.PatchAll(typeof(ItemGrenadeDuctTapedPatch)); ((Object)this).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)this); } private void Start() { HurtOtherPatcher.PatchAll(_harmony); } } public static class MyPluginInfo { public const string PLUGIN_GUID = "com.github.zehsteam.PlayerDamageTracker"; public const string PLUGIN_NAME = "PlayerDamageTracker"; public const string PLUGIN_VERSION = "1.1.0"; } } namespace com.github.zehsteam.PlayerDamageTracker.Patches { [HarmonyPatch(typeof(HurtCollider))] internal static class HurtColliderPatch { [HarmonyPatch("PlayerHurt")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> PlayerHurtTranspiler(IEnumerable<CodeInstruction> instructions) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown string text = "HurtColliderPatch: [PlayerHurt Transpiler]"; MethodInfo methodInfo = AccessTools.Method(typeof(PlayerHealth), "Hurt", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(PlayerHealthExtensions), "HurtWithCaller", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null) { Logger.LogError(text + " Failed to create transpiler. Required methods not found."); return instructions; } List<CodeInstruction> list = new List<CodeInstruction>(); foreach (CodeInstruction instruction in instructions) { if (CodeInstructionExtensions.Calls(instruction, methodInfo)) { list.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Add(new CodeInstruction(OpCodes.Call, (object)methodInfo2)); Logger.LogDebug(text + " Replaced calls to " + methodInfo.Name + " with " + methodInfo2.Name); } else { list.Add(instruction); } } return list.AsEnumerable(); } } internal static class HurtOtherPatcher { private static readonly MethodInfo _hurtOtherMethod = AccessTools.Method(typeof(PlayerHealth), "HurtOther", (Type[])null, (Type[])null); private static readonly FieldInfo _hurtOtherCallerField = AccessTools.Field(typeof(PlayerHealthPatch), "HurtOtherCaller"); private static bool _patched; private static int _transpilersCreated; public static void PatchAll(Harmony harmony) { if (_patched) { return; } _patched = true; LogInfo("Running patcher..."); if (_hurtOtherMethod == null) { LogError("Required methods not found for patcher."); return; } IEnumerable<Assembly> validAssemblies = GetValidAssemblies(); LogInfo($"Found {validAssemblies.Count()} valid assemblies."); foreach (Assembly item in validAssemblies) { LogDebug("Found assembly: " + item.FullName); } _transpilersCreated = 0; Parallel.ForEach(validAssemblies, delegate(Assembly assembly) { PatchAssembly(assembly, harmony); }); LogInfo($"Created {_transpilersCreated} transpilers."); LogInfo("Patcher finished."); } private static void PatchAssembly(Assembly assembly, Harmony harmony) { LogDebug("Patching assembly: " + assembly.FullName); IEnumerable<Type> validClasses = GetValidClasses(assembly); Parallel.ForEach(validClasses, delegate(Type type) { PatchClass(type, harmony); }); } private static void PatchClass(Type type, Harmony harmony) { LogDebug("Patching class: " + type.FullName); IEnumerable<MethodInfo> validMethods = GetValidMethods(type); Parallel.ForEach(validMethods, delegate(MethodInfo method) { PatchMethod(method, harmony); }); } private static void PatchMethod(MethodInfo method, Harmony harmony) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown try { if (ReflectionHelper.IsCoroutineMethod(method)) { MethodInfo coroutineMoveNextMethod = ReflectionHelper.GetCoroutineMoveNextMethod(method); if (coroutineMoveNextMethod == null) { return; } harmony.Patch((MethodBase)coroutineMoveNextMethod, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(HurtOtherPatcher), "Transpiler", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); LogDebug($"Patched coroutine: {coroutineMoveNextMethod}"); } else { harmony.Patch((MethodBase)method, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(HurtOtherPatcher), "Transpiler", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); LogDebug("Patched method: " + method.Name); } Interlocked.Increment(ref _transpilersCreated); } catch (Exception arg) { LogError($"Failed to patch method: {method}\n\n{arg}"); } } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown if (_hurtOtherMethod == null) { LogError("Required methods not found for transpiler."); return instructions; } List<CodeInstruction> list = new List<CodeInstruction>(instructions); for (int num = list.Count - 1; num >= 0; num--) { CodeInstruction val = list[num]; if (CodeInstructionExtensions.Calls(val, _hurtOtherMethod)) { int num2 = ILHelper.FindArgLoadStart(list, _hurtOtherMethod, num); list.Insert(num2, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Insert(num2 + 1, new CodeInstruction(OpCodes.Stsfld, (object)_hurtOtherCallerField)); } } return list.AsEnumerable(); } private static IEnumerable<Assembly> GetValidAssemblies() { return AppDomain.CurrentDomain.GetAssemblies().Where(IsValidAssembly); } private static bool IsValidAssembly(Assembly assembly) { if (assembly == null || assembly.IsDynamic) { return false; } if (assembly == Assembly.GetExecutingAssembly()) { return false; } string[] values = new string[6] { "System.", "giosuel.Imperium", "giosuel.Librarium", "MMHOOK_", "UnityExplorer.", "UniverseLib.Mono" }; if (assembly.FullName.StartsWithAny(values, StringComparison.OrdinalIgnoreCase)) { return false; } if (assembly.Location.StartsWith(Paths.PluginPath, StringComparison.OrdinalIgnoreCase)) { return true; } if (assembly.FullName.StartsWith("Assembly-CSharp")) { return true; } return false; } private static IEnumerable<Type> GetValidClasses(Assembly assembly) { if (assembly == null) { return Array.Empty<Type>(); } try { return assembly.GetTypes().Where(IsValidClass); } catch (ReflectionTypeLoadException ex) { LogWarning("Error loading types from assembly " + assembly.FullName + ": " + ex.Message); return Array.Empty<Type>(); } } private static bool IsValidClass(Type type) { if (type == null) { return false; } if (!type.IsClass || type.IsAbstract) { return false; } if (type == typeof(PlayerHealth)) { return false; } if (typeof(MonoBehaviour).IsAssignableFrom(type)) { return true; } return false; } private static IEnumerable<MethodInfo> GetValidMethods(Type type) { return type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Where(IsValidMethod); } private static bool IsValidMethod(MethodInfo method) { if (method == null) { return false; } if (method.IsGenericMethod || method.DeclaringType.IsGenericType) { return false; } return ILHelper.MethodCallsMethod(method, _hurtOtherMethod); } private static void LogDebug(object data) { Log((LogLevel)32, data); } private static void LogInfo(object data) { Log((LogLevel)16, data); } private static void LogWarning(object data) { Log((LogLevel)4, data); } private static void LogError(object data) { Log((LogLevel)2, data); } private static void Log(LogLevel logLevel, object data) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) Logger.Log(logLevel, string.Format("{0}: {1}", "HurtOtherPatcher", data)); } } [HarmonyPatch(typeof(ItemGrenadeDuctTaped))] internal static class ItemGrenadeDuctTapedPatch { [HarmonyPatch("Explosion")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> ExplosionTranspiler(IEnumerable<CodeInstruction> instructions) { //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Expected O, but got Unknown //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Expected O, but got Unknown //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Expected O, but got Unknown //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Expected O, but got Unknown string text = "ItemGrenadeDuctTapedPatch: [Explosion Transpiler]"; MethodInfo methodInfo = AccessTools.Method(typeof(Object), "Instantiate", new Type[3] { typeof(GameObject), typeof(Vector3), typeof(Quaternion) }, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(ItemGrenadeDuctTapedPatch), "InstantiateReplacement", (Type[])null, (Type[])null); MethodInfo methodInfo3 = AccessTools.Method(typeof(PhotonNetwork), "Instantiate", (Type[])null, (Type[])null); MethodInfo methodInfo4 = AccessTools.Method(typeof(ItemGrenadeDuctTapedPatch), "PhotonNetworkInstantiateReplacement", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null || methodInfo3 == null || methodInfo4 == null) { Logger.LogError(text + " Failed to create transpiler. Required methods not found."); return instructions; } List<CodeInstruction> list = new List<CodeInstruction>(); foreach (CodeInstruction instruction in instructions) { if (CodeInstructionExtensions.Calls(instruction, methodInfo)) { list.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Add(new CodeInstruction(OpCodes.Call, (object)methodInfo2)); Logger.LogDebug(text + " Replaced calls to " + methodInfo.Name + " with " + methodInfo2.Name); } else if (CodeInstructionExtensions.Calls(instruction, methodInfo3)) { list.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Add(new CodeInstruction(OpCodes.Call, (object)methodInfo4)); Logger.LogDebug(text + " Replaced calls to " + methodInfo3.Name + " with " + methodInfo4.Name); } else { list.Add(instruction); } } return list.AsEnumerable(); } private static GameObject InstantiateReplacement(GameObject prefab, Vector3 position, Quaternion rotation, object caller = null) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate<GameObject>(prefab, position, rotation); AddMetadata(caller, val); return val; } private static GameObject PhotonNetworkInstantiateReplacement(string prefabName, Vector3 position, Quaternion rotation, byte group = 0, object[] data = null, object caller = null) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) GameObject val = PhotonNetwork.Instantiate(prefabName, position, rotation, group, data); AddMetadata(caller, val); return val; } private static void AddMetadata(object caller, GameObject gameObject) { if (caller != null && !((Object)(object)gameObject == (Object)null)) { ItemGrenadeDuctTaped val = (ItemGrenadeDuctTaped)((caller is ItemGrenadeDuctTaped) ? caller : null); PhysGrabObject val2 = default(PhysGrabObject); PhysGrabObject val3 = default(PhysGrabObject); if (val != null && ((Component)val).TryGetComponent<PhysGrabObject>(ref val2) && ComponentExtensions.HasMetadata((Component)(object)val2, true) && gameObject.TryGetComponent<PhysGrabObject>(ref val3)) { Metadata orCreateMetadata = ComponentExtensions.GetOrCreateMetadata((Component)(object)val2, true); Metadata orCreateMetadata2 = ComponentExtensions.GetOrCreateMetadata((Component)(object)val3, true); orCreateMetadata2.Set(orCreateMetadata); } } } } [HarmonyPatch(typeof(ParticleScriptExplosion))] internal static class ParticleScriptExplosionPatch { private class Cleanup : MonoBehaviour { private ParticlePrefabExplosion _particlePrefabExplosion; private void Awake() { _particlePrefabExplosion = ((Component)this).GetComponent<ParticlePrefabExplosion>(); } private void OnDestroy() { Explosions.Remove(_particlePrefabExplosion.HurtCollider); } } public static Dictionary<HurtCollider, Metadata> Explosions { get; private set; } = new Dictionary<HurtCollider, Metadata>(); [HarmonyPatch("Start")] [HarmonyPostfix] private static void StartPatch(ParticleScriptExplosion __instance) { Metadata val = null; PhysGrabObject val2 = default(PhysGrabObject); if (((Component)__instance).TryGetComponent<PhysGrabObject>(ref val2) && ComponentExtensions.HasMetadata((Component)(object)val2, true)) { val = ComponentExtensions.GetOrCreateMetadata((Component)(object)val2, true); } EnemyBang val3 = default(EnemyBang); if (((Component)__instance).TryGetComponent<EnemyBang>(ref val3) && ComponentExtensions.HasMetadata((Component)(object)val3, true)) { val = ComponentExtensions.GetOrCreateMetadata((Component)(object)val3, true); } if (val != null) { Metadata orCreateMetadata = ComponentExtensions.GetOrCreateMetadata((Component)(object)__instance, true); orCreateMetadata.Set<Metadata>("ParentMetadata", val); } } [HarmonyPatch("Spawn")] [HarmonyPostfix] private static void SpawnPatch(ParticleScriptExplosion __instance, ref ParticlePrefabExplosion __result) { Metadata val = default(Metadata); Metadata value = default(Metadata); if (ComponentExtensions.TryGetMetadata((Component)(object)__instance, ref val, true) && val.TryGet<Metadata>("ParentMetadata", ref value)) { Explosions[__result.HurtCollider] = value; ((Component)__result).gameObject.AddComponent<Cleanup>(); } } } [HarmonyPatch(typeof(PlayerHealth))] internal static class PlayerHealthPatch { public static object HurtOtherCaller; [HarmonyPatch("HurtOther")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> HurtOtherTranspiler(IEnumerable<CodeInstruction> instructions) { return GetHurtOtherTranspilerInstructions("PlayerHealthPatch: [HurtOther Transpiler]", instructions); } [HarmonyPatch("HurtOtherRPC")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> HurtOtherRPCTranspiler(IEnumerable<CodeInstruction> instructions) { return GetHurtOtherTranspilerInstructions("PlayerHealthPatch: [HurtOtherRPC Transpiler]", instructions); } private static IEnumerable<CodeInstruction> GetHurtOtherTranspilerInstructions(string logHeader, IEnumerable<CodeInstruction> instructions) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(PlayerHealth), "Hurt", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(PlayerHealthExtensions), "HurtWithCaller", (Type[])null, (Type[])null); FieldInfo fieldInfo = AccessTools.Field(typeof(PlayerHealthPatch), "HurtOtherCaller"); if (methodInfo == null || methodInfo2 == null || fieldInfo == null) { Logger.LogError(logHeader + " Failed to create transpiler. Required methods not found."); return instructions; } List<CodeInstruction> list = new List<CodeInstruction>(); foreach (CodeInstruction instruction in instructions) { if (CodeInstructionExtensions.Calls(instruction, methodInfo)) { list.Add(new CodeInstruction(OpCodes.Ldsfld, (object)fieldInfo)); list.Add(new CodeInstruction(OpCodes.Call, (object)methodInfo2)); Logger.LogDebug(logHeader + " Replaced calls to " + methodInfo.Name + " with " + methodInfo2.Name); } else { list.Add(instruction); } } return list.AsEnumerable(); } } } namespace com.github.zehsteam.PlayerDamageTracker.Modules { public static class Events { public static event Action<EnemyParent> OnDamagedByEnemy; public static event Action<PhysGrabObject> OnDamagedByPhysGrabObject; public static event Action<Metadata> OnDamagedByExplosion; public static event Action<HurtCollider> OnDamagedByOther; public static event Action<EnemyParent> OnKilledByEnemy; public static event Action<PhysGrabObject> OnKilledByPhysGrabObject; public static event Action<Metadata> OnKilledByExplosion; public static event Action<HurtCollider> OnKilledByOther; internal static void InvokeOnDamagedByEnemy(EnemyParent enemyParent) { Events.OnDamagedByEnemy?.Invoke(enemyParent); } internal static void InvokeOnDamagedByPhysGrabObject(PhysGrabObject physGrabObject) { Events.OnDamagedByPhysGrabObject?.Invoke(physGrabObject); } internal static void InvokeOnDamagedByExplosion(Metadata metadata) { Events.OnDamagedByExplosion?.Invoke(metadata); } internal static void InvokeOnDamagedByOther(HurtCollider hurtCollider) { Events.OnDamagedByOther?.Invoke(hurtCollider); } internal static void InvokeOnKilledByEnemy(EnemyParent enemyParent) { Events.OnKilledByEnemy?.Invoke(enemyParent); } internal static void InvokeOnKilledByPhysGrabObject(PhysGrabObject physGrabObject) { Events.OnKilledByPhysGrabObject?.Invoke(physGrabObject); } internal static void InvokeOnKilledByExplosion(Metadata metadata) { Events.OnKilledByExplosion?.Invoke(metadata); } internal static void InvokeOnKilledByOther(HurtCollider hurtCollider) { Events.OnKilledByOther?.Invoke(hurtCollider); } } } namespace com.github.zehsteam.PlayerDamageTracker.Helpers { internal static class ILHelper { private static DefaultAssemblyResolver _cachedResolver; private static Dictionary<string, ModuleDefinition> _cachedModules = new Dictionary<string, ModuleDefinition>(); private static DefaultAssemblyResolver GetCachedResolver() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown if (_cachedResolver != null) { return _cachedResolver; } DefaultAssemblyResolver val = new DefaultAssemblyResolver(); ((BaseAssemblyResolver)val).AddSearchDirectory(Paths.ManagedPath); ((BaseAssemblyResolver)val).AddSearchDirectory(Paths.BepInExAssemblyDirectory); ((BaseAssemblyResolver)val).AddSearchDirectory(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)); string[] directories = Directory.GetDirectories(Paths.PluginPath, "*", SearchOption.AllDirectories); foreach (string text in directories) { ((BaseAssemblyResolver)val).AddSearchDirectory(text); } _cachedResolver = val; return _cachedResolver; } public static IEnumerable<Instruction> GetInstructions(MethodInfo method) { if (method == null) { return Array.Empty<Instruction>(); } try { ModuleDefinition moduleDefinition = GetModuleDefinition(method.DeclaringType.Assembly); if (moduleDefinition == null) { return Array.Empty<Instruction>(); } TypeDefinition type = moduleDefinition.GetType(method.DeclaringType.FullName); MethodDefinition val = ((type != null) ? ((IEnumerable<MethodDefinition>)type.Methods).FirstOrDefault((Func<MethodDefinition, bool>)((MethodDefinition m) => ((MemberReference)m).Name == method.Name)) : null); if (val == null || val.Body == null) { Logger.LogWarning("ILHelper: Failed to get IL for method: " + method.Name); return Array.Empty<Instruction>(); } return (IEnumerable<Instruction>)val.Body.Instructions; } catch (Exception arg) { Logger.LogWarning($"ILHelper: Exception while processing method {method.Name}: {arg}"); return Array.Empty<Instruction>(); } } public static IEnumerable<Instruction> GetCoroutineInstructions(MethodInfo method) { if (method == null) { return Array.Empty<Instruction>(); } try { ModuleDefinition moduleDefinition = GetModuleDefinition(method.DeclaringType.Assembly); if (moduleDefinition == null) { return Array.Empty<Instruction>(); } TypeDefinition type = moduleDefinition.GetType(method.DeclaringType.FullName); TypeDefinition val = ((IEnumerable<TypeDefinition>)type.NestedTypes).FirstOrDefault((Func<TypeDefinition, bool>)((TypeDefinition t) => ((MemberReference)t).Name.Contains("<" + method.Name + ">"))); if (val == null) { Logger.LogWarning("ILHelper: State machine type for " + method.Name + " not found."); return Array.Empty<Instruction>(); } MethodDefinition val2 = ((IEnumerable<MethodDefinition>)val.Methods).FirstOrDefault((Func<MethodDefinition, bool>)((MethodDefinition m) => ((MemberReference)m).Name == "MoveNext")); if (val2 == null) { Logger.LogWarning("ILHelper: MoveNext method not found in state machine: " + ((MemberReference)val).Name); return Array.Empty<Instruction>(); } return (IEnumerable<Instruction>)val2.Body.Instructions; } catch (Exception arg) { Logger.LogWarning($"ILHelper: Exception while processing coroutine method {method.Name}: {arg}"); return Array.Empty<Instruction>(); } } public static ModuleDefinition GetModuleDefinition(Assembly assembly) { //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Expected O, but got Unknown if (assembly == null) { return null; } try { if (TryGetCachedModuleDefinition(assembly, out var module)) { return module; } DefaultAssemblyResolver cachedResolver = GetCachedResolver(); if (!string.IsNullOrEmpty(assembly.Location) && File.Exists(assembly.Location)) { ModuleDefinition val = ModuleDefinition.ReadModule(assembly.Location, new ReaderParameters { AssemblyResolver = (IAssemblyResolver)(object)cachedResolver }); CacheModuleDefinition(assembly, val); return val; } string text = assembly.GetName().Name + ".dll"; string text2 = Path.Combine(Paths.ManagedPath, text); if (File.Exists(text2)) { Logger.LogDebug("ILHelper: Attempting to load " + text + " from Managed path: " + text2); ModuleDefinition val2 = ModuleDefinition.ReadModule(text2, new ReaderParameters { AssemblyResolver = (IAssemblyResolver)(object)cachedResolver }); CacheModuleDefinition(assembly, val2); return val2; } Logger.LogWarning("ILHelper: Assembly location for " + assembly.FullName + " is null or invalid. Attempting to load from memory."); if (assembly.IsDynamic) { Logger.LogWarning("ILHelper: Cannot process dynamic assembly: " + assembly.FullName); return null; } byte[] buffer = File.ReadAllBytes(assembly.ManifestModule.FullyQualifiedName); using MemoryStream memoryStream = new MemoryStream(buffer); ModuleDefinition val3 = ModuleDefinition.ReadModule((Stream)memoryStream, new ReaderParameters { AssemblyResolver = (IAssemblyResolver)(object)cachedResolver }); CacheModuleDefinition(assembly, val3); return val3; } catch (Exception arg) { Logger.LogWarning($"ILHelper: Failed to get ModuleDefinition for assembly {assembly.FullName}. {arg}"); return null; } } private static ModuleDefinition GetCachedModuleDefinition(Assembly assembly) { if (assembly == null) { return null; } if (_cachedModules.TryGetValue(assembly.FullName, out var value)) { return value; } return null; } private static bool TryGetCachedModuleDefinition(Assembly assembly, out ModuleDefinition module) { module = GetCachedModuleDefinition(assembly); return module != null; } private static void CacheModuleDefinition(Assembly assembly, ModuleDefinition module) { if (!(assembly == null) && module != null && assembly.FullName.StartsWith("Assembly-CSharp")) { _cachedModules[assembly.FullName] = module; } } public static bool MethodCallsMethod(MethodInfo method, MethodInfo targetMethod) { return InstructionsCallsMethod(GetInstructions(method), targetMethod); } public static bool MethodCallsEitherMethods(MethodInfo method, MethodInfo[] targetMethods) { if (ReflectionHelper.IsCoroutineMethod(method)) { return InstructionsCallsEitherMethods(GetCoroutineInstructions(method), targetMethods); } return InstructionsCallsEitherMethods(GetInstructions(method), targetMethods); } public static bool InstructionsCallsMethod(IEnumerable<Instruction> instructions, MethodInfo targetMethod) { return InstructionsCallsEitherMethods(instructions, new MethodInfo[1] { targetMethod }); } public static bool InstructionsCallsEitherMethods(IEnumerable<Instruction> instructions, MethodInfo[] targetMethods) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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_002f: Invalid comparison between Unknown and I4 //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Invalid comparison between Unknown and I4 if (instructions == null || targetMethods == null || targetMethods.Length == 0) { return false; } foreach (Instruction instruction in instructions) { OpCode opCode = instruction.OpCode; if ((int)((OpCode)(ref opCode)).Code != 39) { opCode = instruction.OpCode; if ((int)((OpCode)(ref opCode)).Code != 110) { continue; } } object operand = instruction.Operand; MethodReference val = (MethodReference)((operand is MethodReference) ? operand : null); if (val == null) { continue; } try { MethodDefinition val2 = val.Resolve(); if (val2 == null) { continue; } foreach (MethodInfo methodInfo in targetMethods) { if (!(methodInfo == null) && ((MemberReference)val2).Name == methodInfo.Name && ((MemberReference)val2.DeclaringType).FullName == methodInfo.DeclaringType.FullName) { return true; } } } catch (Exception arg) { Logger.LogWarning($"ILHelper: Error while processing IL instructions. {arg}"); } } return false; } public static int FindArgLoadStart(List<CodeInstruction> instructions, MethodInfo method, int callIndex) { if (method == null) { return -1; } int num = method.GetParameters().Length; int num2 = 0; for (int num3 = callIndex - 1; num3 >= 0; num3--) { CodeInstruction val = instructions[num3]; if (val.opcode.Name.StartsWith("ld")) { num2++; if (num2 == num) { return num3; } } } return callIndex; } } internal static class ReflectionHelper { public static object GetClassInstanceFromCaller(object caller) { if (caller == null) { return null; } Type type = caller.GetType(); Type declaringType = type.DeclaringType; if (declaringType == null) { return caller; } Logger.LogDebug("ReflectionHelper: Analyzing caller type: " + type.FullName + ", parent type: " + declaringType.FullName); FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { object value = fieldInfo.GetValue(caller); if (value != null && declaringType.IsAssignableFrom(value.GetType())) { Logger.LogDebug("ReflectionHelper: Found parent instance of type " + value.GetType().FullName + " in field " + fieldInfo.Name); return value; } if (value != null && IsCompilerGeneratedClass(value.GetType())) { object classInstanceFromCaller = GetClassInstanceFromCaller(value); if (classInstanceFromCaller != null) { return classInstanceFromCaller; } } } Logger.LogDebug("ReflectionHelper: No parent instance found for " + type.FullName + ", returning original caller."); return caller; } private static bool IsCompilerGeneratedClass(Type type) { if (type.Name.Contains("<") && type.Name.Contains(">")) { return Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute)); } return false; } public static bool IsCoroutineMethod(MethodInfo method) { return method?.ReturnType == typeof(IEnumerator); } public static MethodInfo GetCoroutineMoveNextMethod(MethodInfo method) { return method?.DeclaringType.GetNestedTypes(BindingFlags.Instance | BindingFlags.NonPublic).FirstOrDefault((Type t) => t.Name.Contains("<" + method.Name + ">"))?.GetMethod("MoveNext", BindingFlags.Instance | BindingFlags.NonPublic); } } } namespace com.github.zehsteam.PlayerDamageTracker.Extensions { internal static class HurtColliderExtensions { public static bool TryGetEnemyParent(this HurtCollider hurtCollider, out EnemyParent enemyParent) { if ((Object)(object)hurtCollider == (Object)null) { enemyParent = null; return false; } return ((Object)(object)hurtCollider).TryGetComponentInParents<EnemyParent>(out enemyParent); } public static bool TryGetPhysGrabObject(this HurtCollider hurtCollider, out PhysGrabObject physGrabObject) { if ((Object)(object)hurtCollider == (Object)null) { physGrabObject = null; return false; } return ((Object)(object)hurtCollider).TryGetComponentInParents<PhysGrabObject>(out physGrabObject); } public static bool TryGetExplosionMetadata(this HurtCollider hurtCollider, out Metadata metadata) { if ((Object)(object)hurtCollider == (Object)null) { metadata = null; return false; } return ParticleScriptExplosionPatch.Explosions.TryGetValue(hurtCollider, out metadata); } } internal static class ObjectExtensions { public static bool TryGetComponentInParent<T>(this Object obj, out T result) where T : Component { if (!TryGetTransform(obj, out var transform)) { result = default(T); return false; } result = ((Component)transform).GetComponentInParent<T>(); return (Object)(object)result != (Object)null; } public static T GetComponentInParents<T>(this Object obj) where T : Component { Transform val = GetTransform(obj); T result = default(T); while ((Object)(object)val != (Object)null) { if (((Component)val).TryGetComponent<T>(ref result)) { return result; } val = val.parent; } return default(T); } public static bool TryGetComponentInParents<T>(this Object obj, out T result) where T : Component { result = obj.GetComponentInParents<T>(); return (Object)(object)result != (Object)null; } public static string GetHierarchyPath(this Object obj) { if (!TryGetTransform(obj, out var transform)) { return string.Empty; } return transform.GetHierarchyPath(); } private static Transform GetTransform(Object obj) { Component val = (Component)(object)((obj is Component) ? obj : null); if (val == null) { GameObject val2 = (GameObject)(object)((obj is GameObject) ? obj : null); if (val2 != null) { return val2.transform; } return null; } return val.transform; } private static bool TryGetTransform(Object obj, out Transform transform) { transform = GetTransform(obj); return (Object)(object)transform != (Object)null; } } internal static class PlayerHealthExtensions { public static void HurtWithCaller(this PlayerHealth playerHealth, int damage, bool savingGrace, int enemyIndex, object caller) { if ((Object)(object)playerHealth == (Object)null) { return; } playerHealth.Hurt(damage, savingGrace, enemyIndex); if (damage <= 0 || caller == null) { return; } Logger.LogDebug($"PlayerHealthExtensions: HurtWithCaller() player: \"{SemiFunc.PlayerGetName(playerHealth.playerAvatar)}\", damage: {damage}, savingGrace: {savingGrace}, enemyIndex: {enemyIndex}, caller: \"{caller.GetType().FullName}\""); HurtCollider val = (HurtCollider)((caller is HurtCollider) ? caller : null); if (val != null) { HurtByHurtCollider(playerHealth, damage, savingGrace, enemyIndex, val); return; } Component val2 = (Component)((caller is Component) ? caller : null); Enemy enemy = default(Enemy); if (val2 != null && val2.TryGetComponent<Enemy>(ref enemy)) { HurtByEnemy(playerHealth, damage, savingGrace, enemyIndex, enemy); } else { Logger.LogDebug("PlayerHealthExtensions: HurtWithCaller() Failed to identify caller."); } } private static void HurtByHurtCollider(PlayerHealth playerHealth, int damage, bool savingGrace, int enemyIndex, HurtCollider hurtCollider) { bool deadSet = playerHealth.playerAvatar.deadSet; PhysGrabObject physGrabObject; Metadata metadata; if (hurtCollider.TryGetEnemyParent(out var enemyParent)) { Logger.LogDebug("PlayerHealthExtensions: HurtByHurtCollider() You were damaged by an enemy! \"" + enemyParent.enemyName + "\""); Events.InvokeOnDamagedByEnemy(enemyParent); if (deadSet) { Events.InvokeOnKilledByEnemy(enemyParent); } } else if (hurtCollider.TryGetPhysGrabObject(out physGrabObject)) { Logger.LogDebug("PlayerHealthExtensions: HurtByHurtCollider() You were damaged by a PhysGrabObject! \"" + ((Object)physGrabObject).name + "\""); Events.InvokeOnDamagedByPhysGrabObject(physGrabObject); if (deadSet) { Events.InvokeOnKilledByPhysGrabObject(physGrabObject); } } else if (hurtCollider.TryGetExplosionMetadata(out metadata)) { Logger.LogDebug("PlayerHealthExtensions: HurtByHurtCollider() You were damaged by an explosion!"); Events.InvokeOnDamagedByExplosion(metadata); if (deadSet) { Events.InvokeOnKilledByExplosion(metadata); } } else { Logger.LogDebug("PlayerHealthExtensions: HurtByHurtCollider() You were damaged by something else. \"" + ((Object)(object)hurtCollider).GetHierarchyPath() + "\""); Events.InvokeOnDamagedByOther(hurtCollider); if (deadSet) { Events.InvokeOnKilledByOther(hurtCollider); } } } private static void HurtByEnemy(PlayerHealth playerHealth, int damage, bool savingGrace, int enemyIndex, Enemy enemy) { bool deadSet = playerHealth.playerAvatar.deadSet; EnemyParent enemyParent = enemy.EnemyParent; Logger.LogDebug("PlayerHealthExtensions: HurtByEnemy() You were damaged by an enemy! \"" + enemyParent.enemyName + "\""); Events.InvokeOnDamagedByEnemy(enemyParent); if (deadSet) { Events.InvokeOnKilledByEnemy(enemyParent); } } } public static class StringExtensions { public static bool EqualsAny(this string input, string[] values, StringComparison comparisonType = StringComparison.CurrentCulture) { if (input == null) { throw new ArgumentNullException("input"); } if (values == null) { throw new ArgumentNullException("values"); } foreach (string value in values) { if (input.Equals(value, comparisonType)) { return true; } } return false; } public static bool ContainsAny(this string input, string[] values, StringComparison comparisonType = StringComparison.CurrentCulture) { if (input == null) { throw new ArgumentNullException("input"); } if (values == null) { throw new ArgumentNullException("values"); } foreach (string value in values) { if (input.Contains(value, comparisonType)) { return true; } } return false; } public static bool StartsWithAny(this string input, string[] values, StringComparison comparisonType = StringComparison.CurrentCulture) { if (input == null) { throw new ArgumentNullException("input"); } if (values == null) { throw new ArgumentNullException("values"); } foreach (string value in values) { if (input.StartsWith(value, comparisonType)) { return true; } } return false; } } internal static class TransformExtensions { public static string GetHierarchyPath(this Transform transform) { if ((Object)(object)transform.parent == (Object)null) { return ((Object)transform).name; } return transform.parent.GetHierarchyPath() + "/" + ((Object)transform).name; } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }
com.github.zehsteam.TwitchTrolling.dll
Decompiled a week ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using MenuLib; using MenuLib.MonoBehaviors; using MenuLib.Structs; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Photon.Pun; using REPOLib.Extensions; using REPOLib.Modules; using TMPro; using TwitchChatAPI; using TwitchChatAPI.Enums; using TwitchChatAPI.Objects; using UnityEngine; using UnityEngine.AI; using UnityEngine.Networking; using UnityEngine.Serialization; using UnityEngine.UI; using com.github.zehsteam.MetadataUtils.Extensions; using com.github.zehsteam.MetadataUtils.Objects; using com.github.zehsteam.PlayerDamageTracker.Modules; using com.github.zehsteam.TwitchTrolling.Dependencies; using com.github.zehsteam.TwitchTrolling.Extensions; using com.github.zehsteam.TwitchTrolling.Helpers; using com.github.zehsteam.TwitchTrolling.MEvents; using com.github.zehsteam.TwitchTrolling.MEvents.BaseEvents; using com.github.zehsteam.TwitchTrolling.Managers; using com.github.zehsteam.TwitchTrolling.MonoBehaviours; using com.github.zehsteam.TwitchTrolling.Objects; using com.github.zehsteam.TwitchTrolling.Patches; using com.github.zehsteam.TwitchTrolling.Twitch; using com.github.zehsteam.TwitchTrolling.Twitch.Commands; using com.github.zehsteam.TwitchTrolling.Twitch.Commands.Objects; using com.github.zehsteam.TwitchTrolling.Twitch.Helpers; using com.github.zehsteam.TwitchTrolling.Twitch.Objects; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("REPOLib")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Zehs")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © 2025 Zehs")] [assembly: AssemblyDescription("Let Twitch chat spawn monsters and trigger events with custom bit amounts and subs. Highly configurable, easy to use, no extension or app needed.")] [assembly: AssemblyFileVersion("1.6.0.0")] [assembly: AssemblyInformationalVersion("1.6.0+4b5bcb8df9a0bbbf787f384c0be7c0de7018a372")] [assembly: AssemblyProduct("TwitchTrolling")] [assembly: AssemblyTitle("com.github.zehsteam.TwitchTrolling")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.6.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace com.github.zehsteam.TwitchTrolling { internal static class Assets { public static GameObject PluginManagerPrefab { get; private set; } public static GameObject PluginHUDPrefab { get; private set; } public static GameObject EnemyNametagWorldCanvasPrefab { get; private set; } public static GameObject TruckPropsPrefab { get; private set; } public static GameObject AudioEnemySpawnPrefab { get; private set; } public static PrefabRef ModCreditsPrefabRef { get; private set; } public static EnemyConfigEntryDefaultValuesList EnemyConfigEntryDefaultValuesList { get; private set; } public static EnemySpawnSFXList EnemySpawnSFXList { get; private set; } public static MEventSFXList MEventSFXList { get; private set; } public static void Load() { string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); string text = "twitchtrolling_assets"; string text2 = Path.Combine(directoryName, text); if (!File.Exists(text2)) { Logger.LogFatal("Failed to load assets. AssetBundle file could not be found at path \"" + text2 + "\". Make sure the \"" + text + "\" file is in the same folder as the mod's DLL file."); } else { AssetBundle val = AssetBundle.LoadFromFile(text2); if ((Object)(object)val == (Object)null) { Logger.LogFatal("Failed to load assets. AssetBundle is null."); } else { OnAssetBundleLoaded(val); } } } private static void OnAssetBundleLoaded(AssetBundle assetBundle) { PluginManagerPrefab = LoadAsset<GameObject>("PluginManager", assetBundle); PluginHUDPrefab = LoadAsset<GameObject>("PluginHUD", assetBundle); EnemyNametagWorldCanvasPrefab = LoadAsset<GameObject>("EnemyNametagWorldCanvas", assetBundle); TruckPropsPrefab = LoadAsset<GameObject>("TruckProps", assetBundle); AudioEnemySpawnPrefab = LoadAsset<GameObject>("AudioEnemySpawn", assetBundle); Utilities.FixAudioMixerGroups(AudioEnemySpawnPrefab); ModCreditsPrefabRef = NetworkPrefabs.RegisterNetworkPrefab(LoadAsset<GameObject>("TwitchTrolling ModCredits", assetBundle)); EnemyConfigEntryDefaultValuesList = LoadAsset<EnemyConfigEntryDefaultValuesList>("EnemyConfigEntryDefaultValuesList", assetBundle); EnemySpawnSFXList = LoadAsset<EnemySpawnSFXList>("EnemySpawnSFXList", assetBundle); MEventSFXList = LoadAsset<MEventSFXList>("MEventSFXList", assetBundle); } private static T LoadAsset<T>(string name, AssetBundle assetBundle) where T : Object { if (string.IsNullOrWhiteSpace(name)) { Logger.LogError("Failed to load asset of type \"" + typeof(T).Name + "\" from AssetBundle. Name is null or whitespace."); return default(T); } if ((Object)(object)assetBundle == (Object)null) { Logger.LogError("Failed to load asset of type \"" + typeof(T).Name + "\" with name \"" + name + "\" from AssetBundle. AssetBundle is null."); return default(T); } T val = assetBundle.LoadAsset<T>(name); if ((Object)(object)val == (Object)null) { Logger.LogError("Failed to load asset of type \"" + typeof(T).Name + "\" with name \"" + name + "\" from AssetBundle. No asset found with that type and name."); return default(T); } return val; } private static bool TryLoadAsset<T>(string name, AssetBundle assetBundle, out T asset) where T : Object { asset = LoadAsset<T>(name, assetBundle); return (Object)(object)asset != (Object)null; } } internal static class Logger { public static ManualLogSource ManualLogSource { get; private set; } public static void Initialize(ManualLogSource manualLogSource) { ManualLogSource = manualLogSource; } public static void LogDebug(object data) { Log((LogLevel)32, data); } public static void LogInfo(object data, bool extended = false) { Log((LogLevel)16, data, extended); } public static void LogWarning(object data, bool extended = false) { Log((LogLevel)4, data, extended); } public static void LogError(object data, bool extended = false, bool showMessage = false) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) Log((LogLevel)2, data, extended); if (showMessage) { MessageManager.Instance?.ShowMessage(data.ToString(), Color.red); } } public static void LogFatal(object data, bool extended = false) { Log((LogLevel)1, data, extended); } public static void Log(LogLevel logLevel, object data, bool extended = false) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (!extended || IsExtendedLoggingEnabled()) { ManualLogSource manualLogSource = ManualLogSource; if (manualLogSource != null) { manualLogSource.Log(logLevel, data); } } } public static bool IsExtendedLoggingEnabled() { if (ConfigManager.ExtendedLogging == null) { return false; } return ConfigManager.ExtendedLogging.Value; } } internal static class Menu { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static BuilderDelegate <>9__5_0; public static BuilderDelegate <>9__5_1; public static BuilderDelegate <>9__5_2; public static Action <>9__5_3; internal void <Initialize>b__5_0(Transform parent) { CreateMainButtonForMainMenu(parent); } internal void <Initialize>b__5_1(Transform parent) { CreateMainButtonForLobbyAndEscapeMenu(parent); } internal void <Initialize>b__5_2(Transform parent) { CreateMainButtonForLobbyAndEscapeMenu(parent); } internal void <Initialize>b__5_3() { PageManager.OnPageStatusChanged -= HandlePageStatusChanged; PageManager.OnPageCreated -= HandlePageCreated; } } private static REPOPopupPage _popupPage; private static REPOLabel _pageStatusLabel; private static REPOLabel _pageUrlLabel; private static REPOButton _createPageButton; private static REPOButton _copyPageURLButton; public static void Initialize() { //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) //IL_001f: Expected O, but got Unknown //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown object obj = <>c.<>9__5_0; if (obj == null) { BuilderDelegate val = delegate(Transform parent) { CreateMainButtonForMainMenu(parent); }; <>c.<>9__5_0 = val; obj = (object)val; } MenuAPI.AddElementToMainMenu((BuilderDelegate)obj); object obj2 = <>c.<>9__5_1; if (obj2 == null) { BuilderDelegate val2 = delegate(Transform parent) { CreateMainButtonForLobbyAndEscapeMenu(parent); }; <>c.<>9__5_1 = val2; obj2 = (object)val2; } MenuAPI.AddElementToLobbyMenu((BuilderDelegate)obj2); object obj3 = <>c.<>9__5_2; if (obj3 == null) { BuilderDelegate val3 = delegate(Transform parent) { CreateMainButtonForLobbyAndEscapeMenu(parent); }; <>c.<>9__5_2 = val3; obj3 = (object)val3; } MenuAPI.AddElementToEscapeMenu((BuilderDelegate)obj3); PageManager.OnPageStatusChanged += HandlePageStatusChanged; PageManager.OnPageCreated += HandlePageCreated; Application.quitting += delegate { PageManager.OnPageStatusChanged -= HandlePageStatusChanged; PageManager.OnPageCreated -= HandlePageCreated; }; } private static REPOButton CreateMainButtonForMainMenu(Transform parent) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) float num = 35f; float num2 = 0f; if (SpawnManagerProxy.Enabled) { num2 += 55f; } return CreateMainButton(parent, Vector2.op_Implicit(new Vector2(550f, num + num2))); } private static REPOButton CreateMainButtonForLobbyAndEscapeMenu(Transform parent) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) float num = 0f; num += 145f; if (MoreHeadProxy.Enabled) { num += 100f; } return CreateMainButton(parent, Vector2.op_Implicit(new Vector2(num, 0f))); } private static REPOButton CreateMainButton(Transform parent, Vector3 localPosition) { //IL_0021: 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) return MenuAPI.CreateREPOButton("Twitch Trolling", (Action)HandleMainButtonClick, parent, Vector2.op_Implicit(localPosition)); } private static void CreateMenu() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Expected O, but got Unknown //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Expected O, but got Unknown //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Expected O, but got Unknown //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Expected O, but got Unknown _popupPage = MenuAPI.CreateREPOPopupPage("Twitch Trolling", (PresetSide)0, false, true, 0f); REPOPopupPage popupPage = _popupPage; Padding maskPadding = _popupPage.maskPadding; maskPadding.top = 35f; popupPage.maskPadding = maskPadding; float xPosition = 75f; float yPosition = 270f; _popupPage.AddElement((BuilderDelegate)delegate(Transform parent) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) _pageStatusLabel = MenuAPI.CreateREPOLabel("Page Status:", parent, new Vector2(xPosition, yPosition)); ((Component)_pageStatusLabel).transform.localScale = Vector3.one * 0.7f; }); yPosition -= 40f; _popupPage.AddElement((BuilderDelegate)delegate(Transform parent) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) _pageUrlLabel = MenuAPI.CreateREPOLabel(string.Empty, parent, new Vector2(xPosition, yPosition)); ((Component)_pageUrlLabel).transform.localScale = Vector3.one * 0.5f; }); yPosition -= 60f; _popupPage.AddElement((BuilderDelegate)delegate(Transform parent) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) _createPageButton = MenuAPI.CreateREPOButton("Create Page", (Action)HandleCreatePageButtonClick, parent, Vector2.op_Implicit(new Vector3(xPosition, yPosition))); }); _popupPage.AddElement((BuilderDelegate)delegate(Transform parent) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) _copyPageURLButton = MenuAPI.CreateREPOButton("Copy Page URL", (Action)HandleCopyPageURLButtonClick, parent, Vector2.op_Implicit(new Vector3(xPosition, yPosition))); ((Component)_copyPageURLButton).gameObject.SetActive(false); }); yPosition = 35f; _popupPage.AddElement((BuilderDelegate)delegate(Transform parent) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) MenuAPI.CreateREPOButton("Close", (Action)HandleCloseButtonClick, parent, new Vector2(xPosition, yPosition)); }); _popupPage.OpenPage(false); HandlePageStatusChanged(); PageManager.CheckPageStatus(); PageManager.VerifyTwitchChannel(); } private static void HandleMainButtonClick() { CreateMenu(); } private static void HandleCloseButtonClick() { REPOPopupPage popupPage = _popupPage; if (popupPage != null) { popupPage.ClosePage(true); } } private static void HandleCreatePageButtonClick() { REPOButton createPageButton = _createPageButton; if (createPageButton != null) { ((Component)createPageButton).gameObject.SetActive(false); } PageManager.CreatePage(); } private static void HandleCopyPageURLButtonClick() { if (PageManager.HasPage) { GUIUtility.systemCopyBuffer = PageManager.PageURL; } } private static void HandlePageStatusChanged() { if ((Object)(object)_popupPage == (Object)null) { return; } bool hasPage = PageManager.HasPage; ((Component)_createPageButton).gameObject.SetActive(!hasPage); ((Component)_copyPageURLButton).gameObject.SetActive(hasPage); if (hasPage) { ((TMP_Text)_pageStatusLabel.labelTMP).text = "Page Status: <color=#00FF00>ONLINE</color>"; string text = PageManager.PageURL.Replace("?id", "\n?id"); ((TMP_Text)_pageUrlLabel.labelTMP).text = "<color=#FFFFFF>" + text + "</color>"; return; } ((TMP_Text)_pageStatusLabel.labelTMP).text = "Page Status: <color=#FF0000>OFFLINE</color>"; if (!PageManager.IsCreatePageEnabled(out var reason)) { string text2 = "<size=25><color=#FF0000>" + reason + "</color></size>"; ((TMP_Text)_pageUrlLabel.labelTMP).text = "You are unable to create a page! Reason:\n" + text2; ((Component)_createPageButton).gameObject.SetActive(false); } else { ((TMP_Text)_pageUrlLabel.labelTMP).text = "Create a page to share your prices\nwith your viewers!"; } } private static void HandlePageCreated(string pageUrl) { HandlePageStatusChanged(); } } [BepInPlugin("com.github.zehsteam.TwitchTrolling", "TwitchTrolling", "1.6.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] internal class Plugin : BaseUnityPlugin { private readonly Harmony _harmony = new Harmony("com.github.zehsteam.TwitchTrolling"); internal static Plugin Instance { get; private set; } internal static JsonSave GlobalSave { get; private set; } internal static JsonSave LocalSave { get; private set; } private void Awake() { Instance = this; Logger.Initialize(Logger.CreateLogSource("com.github.zehsteam.TwitchTrolling")); Logger.LogInfo("TwitchTrolling has awoken!"); _harmony.PatchAll(typeof(RunManagerPatch)); _harmony.PatchAll(typeof(LevelGeneratorPatch)); _harmony.PatchAll(typeof(EnemyDirectorPatch)); _harmony.PatchAll(typeof(HUDCanvasPatch)); _harmony.PatchAll(typeof(TruckScreenTextPatch)); _harmony.PatchAll(typeof(PlayerControllerPatch)); _harmony.PatchAll(typeof(ItemDronePatch)); _harmony.PatchAll(typeof(FanTrapPatch)); _harmony.PatchAll(typeof(ItemRubberDuckPatch)); _harmony.PatchAll(typeof(EnemyDuckPatch)); GlobalSave = new JsonSave(Utils.GetPluginPersistentDataPath(), "GlobalSave"); LocalSave = new JsonSave(Paths.ConfigPath, "TwitchTrolling_Save.json"); Assets.Load(); ConfigManager.Initialize(((BaseUnityPlugin)this).Config); PluginManager.Spawn(); TwitchIntegrationManager.Initialize(); Menu.Initialize(); PageManager.Initialize(); PlayerHelper.Initialize(); TwitchSimulateCheerCommand.Register(); TwitchSimulateSubCommand.Register(); } } internal static class Utils { [CompilerGenerated] private sealed class <InvokeAfterDurationCoroutine>d__5 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public TimeSpan duration; public Action action; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <InvokeAfterDurationCoroutine>d__5(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds((float)duration.TotalSeconds); <>1__state = 1; return true; case 1: <>1__state = -1; action?.Invoke(); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public static string GetPluginPersistentDataPath() { return Path.Combine(Application.persistentDataPath, "TwitchTrolling"); } public static ConfigFile CreateConfigFile(BaseUnityPlugin plugin, string path, string name = null, bool saveOnInit = false) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown BepInPlugin metadata = MetadataHelper.GetMetadata((object)plugin); if (name == null) { name = metadata.GUID; } name += ".cfg"; return new ConfigFile(Path.Combine(path, name), saveOnInit, metadata); } public static ConfigFile CreateLocalConfigFile(BaseUnityPlugin plugin, string name = null, bool saveOnInit = false) { return CreateConfigFile(plugin, Paths.ConfigPath, name, saveOnInit); } public static ConfigFile CreateGlobalConfigFile(BaseUnityPlugin plugin, string name = null, bool saveOnInit = false) { string pluginPersistentDataPath = GetPluginPersistentDataPath(); if (name == null) { name = "global"; } return CreateConfigFile(plugin, pluginPersistentDataPath, name, saveOnInit); } public static string GetTextWithReadableColor(string text, string hexColor, string backgroundHexColor = "#000000") { if (string.IsNullOrWhiteSpace(hexColor)) { hexColor = "#FFFFFF"; } if (string.IsNullOrWhiteSpace(backgroundHexColor)) { backgroundHexColor = "#000000"; } string readableColor = ColorHelper.GetReadableColor(hexColor, backgroundHexColor); return "<color=" + readableColor + ">" + text + "</color>"; } [IteratorStateMachine(typeof(<InvokeAfterDurationCoroutine>d__5))] public static IEnumerator InvokeAfterDurationCoroutine(TimeSpan duration, Action action) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <InvokeAfterDurationCoroutine>d__5(0) { duration = duration, action = action }; } } public static class MyPluginInfo { public const string PLUGIN_GUID = "com.github.zehsteam.TwitchTrolling"; public const string PLUGIN_NAME = "TwitchTrolling"; public const string PLUGIN_VERSION = "1.6.0"; } } namespace com.github.zehsteam.TwitchTrolling.Twitch { internal static class TwitchEventHandler { public static void Initialize() { try { API.OnMessage += HandleMessage; API.OnCheer += HandleCheer; API.OnSub += HandleSub; API.OnRaid += HandleRaid; Application.quitting += delegate { API.OnMessage -= HandleMessage; API.OnCheer -= HandleCheer; API.OnSub -= HandleSub; API.OnRaid -= HandleRaid; }; } catch { Logger.LogFatal("TwitchEventHandler: Failed to initialize."); throw; } } public static void HandleMessage(TwitchMessage twitchMessage) { } public static void HandleCheer(TwitchCheerEvent cheerEvent) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (!TwitchIntegrationManager.IsCheerEventEnabled) { return; } if (cheerEvent == null) { Logger.LogError("TwitchEventHandler: Failed to handle cheer. TwitchCheerEvent is null."); return; } if (!CanHandleEvents()) { ShowUnableToHandleEventsMessage(); return; } if (!TwitchIntegrationManager.CanPlayEvents()) { TwitchEventQueue.Enqueue(cheerEvent); return; } bool value = ConfigManager.Enemy_Enabled.Value; ViewerData viewerData = new ViewerData(((TwitchEvent)cheerEvent).User); int cheerAmount = cheerEvent.CheerAmount; int spawnCount = 1; int bitsUsed; if (value && EnemyConfigManager.HasEnemies() && EnemyConfigManager.TryGetConfigEntriesThatMatchBitsAmount(cheerAmount, out var list)) { string targetEnemyName = string.Empty; if (list.TryGetRandom(out var enemyConfigEntry)) { targetEnemyName = enemyConfigEntry.EnemyName; } bitsUsed = cheerAmount; SpawnEnemyFromBits(viewerData, bitsUsed, spawnCount, targetEnemyName); return; } if (MEventManager.Enabled && MEventManager.HasEvents()) { float num = ConfigManager.Event_BitsForRandomEvent.Value; if (MEventManager.TryGetEvent(cheerAmount, out var mEvent)) { mEvent.ExecuteEvent(viewerData, PlayerAvatar.instance, cheerAmount); return; } if (ConfigManager.Event_EnableBitsForRandomEvent.Value && (float)cheerAmount == num && MEventManager.TryGetRandomEvent(out mEvent)) { mEvent.ExecuteEvent(viewerData, PlayerAvatar.instance, cheerAmount); return; } } bool value2 = ConfigManager.TwitchCheerEvent_EnableBitsForRandomEnemy.Value; if (!value || !value2 || !EnemyConfigManager.HasEnemies()) { TwitchIntegrationManager.AddAccumulatedBits(viewerData, cheerAmount); return; } int accumulatedBits = TwitchIntegrationManager.GetAccumulatedBits(viewerData); cheerAmount += accumulatedBits; int value3 = ConfigManager.TwitchCheerEvent_BitsForRandomEnemy.Value; if (cheerAmount < value3) { TwitchIntegrationManager.SetAccumulatedBits(viewerData, cheerAmount); return; } spawnCount = Mathf.FloorToInt((float)(cheerAmount / value3)); int num2 = cheerAmount % value3; bitsUsed = cheerAmount - num2; TwitchIntegrationManager.SetAccumulatedBits(viewerData, num2); SpawnEnemyFromBits(viewerData, bitsUsed, spawnCount, string.Empty); } public static void HandleSub(TwitchSubEvent subEvent) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Invalid comparison between Unknown and I4 //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Invalid comparison between Unknown and I4 //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Invalid comparison between Unknown and I4 //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Invalid comparison between Unknown and I4 //IL_00c2: Unknown result type (might be due to invalid IL or missing references) if (!TwitchIntegrationManager.IsSubEventEnabled || !ConfigManager.Enemy_Enabled.Value) { return; } if (subEvent == null) { Logger.LogError("Failed to handle sub. TwitchSubEvent is null."); return; } if (!CanHandleEvents()) { ShowUnableToHandleEventsMessage(); return; } if (!TwitchIntegrationManager.CanPlayEvents()) { TwitchEventQueue.Enqueue(subEvent); return; } int num = 1; if ((int)subEvent.Type == 3) { num = subEvent.GiftCount; } string targetEnemyName = string.Empty; int num2 = 1; if (EnemyConfigManager.TryGetConfigEntriesThatMatchSubsAmount(num, out var list)) { if (list.TryGetRandom(out var enemyConfigEntry)) { targetEnemyName = enemyConfigEntry.EnemyName; } } else { num2 = num; } if ((int)subEvent.Tier < 2) { num2 *= ConfigManager.TwitchSubEvent_Tier1EnemySpawnCountMultiplier.Value; } else if ((int)subEvent.Tier == 2) { num2 *= ConfigManager.TwitchSubEvent_Tier2EnemySpawnCountMultiplier.Value; } else if ((int)subEvent.Tier == 3) { num2 *= ConfigManager.TwitchSubEvent_Tier3EnemySpawnCountMultiplier.Value; } ViewerSpawnData viewerSpawnData = new ViewerSpawnData(((TwitchEvent)subEvent).User, num2, GetSpawnReason(subEvent), targetEnemyName); Logger.LogInfo("HandleSub:\n" + JsonConvert.SerializeObject((object)viewerSpawnData, (Formatting)1), extended: true); EnemyManager.SpawnEnemy(viewerSpawnData); } public static void HandleRaid(TwitchRaidEvent raidEvent) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) if (TwitchIntegrationManager.IsRaidEventEnabled && ConfigManager.Enemy_Enabled.Value) { if (raidEvent == null) { Logger.LogError("TwitchEventHandler: Failed to handle raid. TwitchRaidEvent is null."); return; } if (!CanHandleEvents()) { ShowUnableToHandleEventsMessage(); return; } if (!TwitchIntegrationManager.CanPlayEvents()) { TwitchEventQueue.Enqueue(raidEvent); return; } int value = ConfigManager.TwitchRaidEvent_ViewersPerRandomEnemy.Value; int value2 = ConfigManager.TwitchRaidEvent_MaxEnemySpawnCount.Value; int spawnCount = Mathf.Clamp(raidEvent.ViewerCount / value, 1, value2); string spawnReason = $"by raiding with {raidEvent.ViewerCount} viewers"; ViewerSpawnData viewerSpawnData = new ViewerSpawnData(((TwitchEvent)raidEvent).User, spawnCount, spawnReason); Logger.LogInfo("HandleRaid:\n" + JsonConvert.SerializeObject((object)viewerSpawnData, (Formatting)1), extended: true); EnemyManager.SpawnEnemy(viewerSpawnData); } } private static string GetSpawnReason(TwitchSubEvent subEvent) { //IL_0010: 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_004c: Invalid comparison between Unknown and I4 //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Invalid comparison between Unknown and I4 //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected I4, but got Unknown //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Invalid comparison between Unknown and I4 //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected I4, but got Unknown //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected I4, but got Unknown //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Expected I4, but got Unknown if (subEvent == null) { return string.Empty; } string result = string.Empty; if ((int)subEvent.Type == 0) { result = (((int)subEvent.Tier != 0) ? $"by subbing at tier {(int)subEvent.Tier}" : "by subbing with prime"); } else if ((int)subEvent.Type == 1) { result = (((int)subEvent.Tier != 0) ? $"by resubbing at tier {(int)subEvent.Tier} for {subEvent.CumulativeMonths} months" : $"by resubbing with prime for {subEvent.CumulativeMonths} months"); } else if ((int)subEvent.Type == 2) { result = $"by gifting a tier {(int)subEvent.Tier} sub to {subEvent.RecipientUser}"; } else if ((int)subEvent.Type == 3) { result = $"by gifting {subEvent.GiftCount} tier {(int)subEvent.Tier} subs"; } return result; } private static void SpawnEnemyFromBits(ViewerData viewer, int bitsUsed, int spawnCount, string targetEnemyName) { string spawnReason = $"by cheering {bitsUsed} bits"; ViewerSpawnData viewerSpawnData = new ViewerSpawnData(viewer, spawnCount, spawnReason, targetEnemyName); EnemyManager.SpawnEnemy(viewerSpawnData); } public static void ShowUnableToHandleEventsMessage() { MessageManager.Instance?.ShowMessage("<color=#FFFF00>Warning!</color> Triggering Twitch events is not currently supported on non-host clients\nDisable Twitch Chat API to hide these warnings"); } public static bool CanHandleEvents() { if (!PhotonNetwork.InRoom) { return true; } return SemiFunc.IsMasterClientOrSingleplayer(); } } internal static class TwitchEventQueue { [CompilerGenerated] private sealed class <PlayQueuedEventsCoroutine>d__17 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public TimeSpan initialDelay; private TimeSpan <delayBetweenEvents>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <PlayQueuedEventsCoroutine>d__17(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Expected O, but got Unknown //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Expected O, but got Unknown //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Expected O, but got Unknown TwitchCheerEvent result; TwitchSubEvent result2; switch (<>1__state) { default: return false; case 0: <>1__state = -1; Logger.LogInfo("TwitchEventQueue: Started playing queued events.", extended: true); Logger.LogInfo($"TwitchEventQueue: Playing queued events after {(float)initialDelay.TotalSeconds} seconds.", extended: true); <>2__current = (object)new WaitForSeconds((float)initialDelay.TotalSeconds); <>1__state = 1; return true; case 1: <>1__state = -1; if (!TwitchEventHandler.CanHandleEvents()) { return false; } if (!TwitchIntegrationManager.CanPlayEvents()) { Logger.LogWarning("TwitchEventQueue: Failed to play queued events. You are not allowed to play events at this time."); return false; } if (!HasQueuedEvents()) { Logger.LogInfo("TwitchEventQueue: No events in the queue to play.", extended: true); return false; } MessageManager.Instance?.ShowMessage("Playing Twitch events from the queue"); <delayBetweenEvents>5__2 = TimeSpan.FromSeconds(0.5); goto IL_00d7; case 2: <>1__state = -1; goto IL_00d7; case 3: <>1__state = -1; goto IL_011b; case 4: { <>1__state = -1; break; } IL_00d7: if (TwitchIntegrationManager.IsCheerEventEnabled && CheerQueue.TryDequeue(out result)) { TwitchEventHandler.HandleCheer(result); <>2__current = (object)new WaitForSeconds((float)<delayBetweenEvents>5__2.TotalSeconds); <>1__state = 2; return true; } goto IL_011b; IL_011b: if (TwitchIntegrationManager.IsSubEventEnabled && SubQueue.TryDequeue(out result2)) { TwitchEventHandler.HandleSub(result2); <>2__current = (object)new WaitForSeconds((float)<delayBetweenEvents>5__2.TotalSeconds); <>1__state = 3; return true; } break; } if (TwitchIntegrationManager.IsRaidEventEnabled && RaidQueue.TryDequeue(out var result3)) { TwitchEventHandler.HandleRaid(result3); <>2__current = (object)new WaitForSeconds((float)<delayBetweenEvents>5__2.TotalSeconds); <>1__state = 4; return true; } Logger.LogInfo("TwitchEventQueue: Finished plyaing queued events.", extended: true); SaveData(); _playQueuedEventsCoroutine = null; return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static Coroutine _playQueuedEventsCoroutine; public static Queue<TwitchCheerEvent> CheerQueue { get; private set; } = new Queue<TwitchCheerEvent>(); public static Queue<TwitchSubEvent> SubQueue { get; private set; } = new Queue<TwitchSubEvent>(); public static Queue<TwitchRaidEvent> RaidQueue { get; private set; } = new Queue<TwitchRaidEvent>(); public static void LoadData() { Logger.LogInfo("TwitchEventQueue: Loading saved data..."); try { if (Plugin.GlobalSave.TryLoad<string>("CheerQueue", out var value)) { CheerQueue = JsonConvertHelper.DeserializeQueue<TwitchCheerEvent>(value); Logger.LogInfo("TwitchEventQueue: Loaded CheerQueue JSON data:\n\n" + value, extended: true); } if (Plugin.GlobalSave.TryLoad<string>("SubQueue", out value)) { SubQueue = JsonConvertHelper.DeserializeQueue<TwitchSubEvent>(value); Logger.LogInfo("TwitchEventQueue: Loaded SubQueue JSON data:\n\n" + value, extended: true); } if (Plugin.GlobalSave.TryLoad<string>("RaidQueue", out value)) { RaidQueue = JsonConvertHelper.DeserializeQueue<TwitchRaidEvent>(value); Logger.LogInfo("TwitchEventQueue: Loaded RaidQueue JSON data:\n\n" + value, extended: true); } Logger.LogInfo("TwitchEventQueue: Finished loading saved data."); } catch (Exception arg) { Logger.LogError($"TwitchEventQueue: Failed to load saved data. {arg}"); } } public static void SaveData() { Logger.LogInfo("TwitchEventQueue: Saving data...", extended: true); try { Plugin.GlobalSave.Save("CheerQueue", JsonConvertHelper.SerializeQueue(CheerQueue)); Plugin.GlobalSave.Save("SubQueue", JsonConvertHelper.SerializeQueue(SubQueue)); Plugin.GlobalSave.Save("RaidQueue", JsonConvertHelper.SerializeQueue(RaidQueue)); Logger.LogInfo("TwitchEventQueue: Saved data.", extended: true); } catch (Exception arg) { Logger.LogError($"TwitchEventQueue: Failed to save data. {arg}"); } } public static void PlayQueuedEvents() { PlayQueuedEvents(TimeSpan.Zero); } public static void PlayQueuedEvents(TimeSpan initialDelay) { if (!TwitchIntegrationManager.IsEnabled) { Logger.LogWarning("TwitchEventQueue: Failed to play queued events. Twitch integration is not enabled."); return; } if ((Object)(object)PluginManager.Instance == (Object)null) { Logger.LogError("TwitchEventQueue: Failed to play queued events. PluginManager instance is null."); return; } if (!TwitchIntegrationManager.CanPlayEvents()) { Logger.LogWarning("TwitchEventQueue: Failed to play queued events. You are not allowed to play events at this time."); return; } if (_playQueuedEventsCoroutine != null) { ((MonoBehaviour)PluginManager.Instance).StopCoroutine(_playQueuedEventsCoroutine); } _playQueuedEventsCoroutine = ((MonoBehaviour)PluginManager.Instance).StartCoroutine(PlayQueuedEventsCoroutine(initialDelay)); } [IteratorStateMachine(typeof(<PlayQueuedEventsCoroutine>d__17))] private static IEnumerator PlayQueuedEventsCoroutine(TimeSpan initialDelay) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <PlayQueuedEventsCoroutine>d__17(0) { initialDelay = initialDelay }; } public static bool HasQueuedEvents() { if (CheerQueue.Count <= 0 && SubQueue.Count <= 0) { return RaidQueue.Count > 0; } return true; } public static void Enqueue(TwitchCheerEvent cheerEvent) { if (!CheerQueue.Contains(cheerEvent)) { CheerQueue.Enqueue(cheerEvent); SaveData(); ShowEnqueueMessage((TwitchEvent)(object)cheerEvent, "cheer"); } } public static void Enqueue(TwitchSubEvent subEvent) { if (!SubQueue.Contains(subEvent)) { SubQueue.Enqueue(subEvent); SaveData(); ShowEnqueueMessage((TwitchEvent)(object)subEvent, "sub"); } } public static void Enqueue(TwitchRaidEvent raidEvent) { if (!RaidQueue.Contains(raidEvent)) { RaidQueue.Enqueue(raidEvent); SaveData(); ShowEnqueueMessage((TwitchEvent)(object)raidEvent, "raid"); } } private static void ShowEnqueueMessage(TwitchEvent twitchEvent, string eventName) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) string displayNameWithColor = twitchEvent.User.GetDisplayNameWithColor(); string message = "Added Twitch " + eventName + " event from " + displayNameWithColor + " to queue"; MessageManager.Instance?.ShowMessage(message); } } internal static class TwitchIntegrationManager { public static Dictionary<string, int> AccumulatedBits { get; private set; } = new Dictionary<string, int>(); public static bool IsEnabled => ConfigManager.TwitchIntegration_Enabled.Value; public static bool IsCheerEventEnabled { get { if (IsEnabled) { return ConfigManager.TwitchCheerEvent_Enabled.Value; } return false; } } public static bool IsSubEventEnabled { get { if (IsEnabled) { return ConfigManager.TwitchSubEvent_Enabled.Value; } return false; } } public static bool IsRaidEventEnabled { get { if (IsEnabled) { return ConfigManager.TwitchRaidEvent_Enabled.Value; } return false; } } public static void Initialize() { LoadData(); Application.quitting += SaveData; TwitchEventHandler.Initialize(); } private static void LoadData() { Logger.LogInfo("TwitchIntegrationManager: Loading saved data..."); try { TwitchEventQueue.LoadData(); LoadAccumulatedBits(); Logger.LogInfo("TwitchIntegrationManager: Finished loading saved data."); } catch (Exception arg) { Logger.LogError($"TwitchIntegrationManager: Failed to load saved data. {arg}"); } } public static void SaveData() { Logger.LogInfo("TwitchIntegrationManager: Saving data..."); try { TwitchEventQueue.SaveData(); SaveAccumulatedBits(); Logger.LogInfo("TwitchIntegrationManager: Saved data."); } catch (Exception arg) { Logger.LogError($"TwitchIntegrationManager: Failed to save data. {arg}"); } } private static void LoadAccumulatedBits() { try { if (Plugin.GlobalSave.TryLoad<string>("AccumulatedBits", out var value)) { AccumulatedBits = JsonConvert.DeserializeObject<Dictionary<string, int>>(value); Logger.LogInfo("TwitchIntegrationManager: Loaded AccumulatedBits JSON data:\n\n" + value, extended: true); } } catch (Exception arg) { Logger.LogError($"TwitchIntegrationManager: Failed to load AccumulatedBits from saved data. {arg}"); } } public static void SaveAccumulatedBits() { Plugin.GlobalSave.Save("AccumulatedBits", JsonConvert.SerializeObject((object)AccumulatedBits)); } public static int GetAccumulatedBits(ViewerData viewer) { if (viewer == null) { return 0; } return GetAccumulatedBits(viewer.Username); } public static int GetAccumulatedBits(string username) { return AccumulatedBits.GetValueOrDefault(username.ToLower(), 0); } public static void SetAccumulatedBits(ViewerData viewer, int value) { if (viewer != null) { if (value <= 0) { AccumulatedBits.Remove(viewer.Username); } else { AccumulatedBits[viewer.Username] = value; } SaveAccumulatedBits(); } } public static void AddAccumulatedBits(ViewerData viewer, int value) { int accumulatedBits = GetAccumulatedBits(viewer); SetAccumulatedBits(viewer, accumulatedBits + value); } public static bool CanPlayEvents() { if (!IsEnabled) { return false; } return EnemyManager.CanSpawnEnemies(); } } } namespace com.github.zehsteam.TwitchTrolling.Twitch.Objects { [Serializable] public class ViewerData { public string UserId { get; } public string Username => DisplayName.ToLower(); public string DisplayName { get; } public string Color { get; } public ViewerData(string userId, string displayName, string color) { UserId = userId; DisplayName = displayName; Color = color; } public ViewerData(TwitchUser twitchUser) { UserId = ((TwitchUser)(ref twitchUser)).UserId; DisplayName = ((TwitchUser)(ref twitchUser)).DisplayName; Color = ((TwitchUser)(ref twitchUser)).Color; } public string GetDisplayNameWithColor() { return Utils.GetTextWithReadableColor(DisplayName, Color); } } [Serializable] public class ViewerSpawnData { public ViewerData Viewer { get; private set; } public int SpawnCount { get; private set; } public string SpawnReason { get; private set; } public string TargetEnemyName { get; private set; } public int TotalSpawnCount { get; private set; } public ViewerSpawnData(ViewerData viewer, int spawnCount, string spawnReason, string targetEnemyName = "") { Viewer = viewer; SpawnCount = spawnCount; SpawnReason = spawnReason; TargetEnemyName = targetEnemyName; } public ViewerSpawnData(TwitchUser twitchUser, int spawnCount, string spawnReason, string targetEnemyName = "") { //IL_0007: Unknown result type (might be due to invalid IL or missing references) Viewer = new ViewerData(twitchUser); SpawnCount = spawnCount; SpawnReason = spawnReason; TargetEnemyName = targetEnemyName; } public void SetTargetEnemyName(string value) { TargetEnemyName = value; } public void SetTotalSpawnCount(int value) { TotalSpawnCount = value; } } } namespace com.github.zehsteam.TwitchTrolling.Twitch.Helpers { internal static class TwitchHelper { public static TwitchUser CreateTwitchUser(bool isVIP = false, bool isSubscriber = false, bool isModerator = false, bool isBroadcaster = false) { //IL_0043: 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_002a: Unknown result type (might be due to invalid IL or missing references) if (PlayerHelper.TryGetLocalPlayer(out var playerAvatar)) { string steamID = playerAvatar.steamID; string displayName = SemiFunc.PlayerGetName(playerAvatar); string color = ColorHelper.ColorToHex(SemiFunc.PlayerGetColorFromSteamID(steamID)); return CreateTwitchUser(steamID, displayName, color, isVIP, isSubscriber, isModerator, isBroadcaster); } return CreateTwitchUser("0", "Unknown", "#FFFFFF", isVIP, isSubscriber, isModerator, isBroadcaster); } public static TwitchUser CreateTwitchUser(string userId, string displayName, string color = "#FFFFFF", bool isVIP = false, bool isSubscriber = false, bool isModerator = false, bool isBroadcaster = false) { //IL_0002: 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) TwitchUser result = default(TwitchUser); ((TwitchUser)(ref result)).UserId = userId; ((TwitchUser)(ref result)).Username = displayName.ToLower(); ((TwitchUser)(ref result)).DisplayName = displayName; ((TwitchUser)(ref result)).Color = color; ((TwitchUser)(ref result)).IsVIP = isVIP; ((TwitchUser)(ref result)).IsSubscriber = isSubscriber; ((TwitchUser)(ref result)).IsModerator = isModerator; ((TwitchUser)(ref result)).IsBroadcaster = isBroadcaster; return result; } } } namespace com.github.zehsteam.TwitchTrolling.Twitch.Commands { internal static class TwitchSimulateCheerCommand { public static void Register() { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown ChatCommand val = new ChatCommand("cheer", "Simulate a Twitch cheer for TwitchTrolling", (Action<bool, string[]>)Execute, (Func<bool, string, string[], List<string>>)Suggest, (Func<bool>)IsEnabled, false); Commands.RegisterCommand(val); } private static void Execute(bool isDebugConsole, string[] args) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown int cheerAmount = ConfigManager.TwitchCheerEvent_BitsForRandomEnemy.Value; if (args.Length >= 1 && int.TryParse(args[0], out var result)) { cheerAmount = result; } TwitchCheerEvent cheerEvent = new TwitchCheerEvent { User = TwitchHelper.CreateTwitchUser(), CheerAmount = cheerAmount }; TwitchEventHandler.HandleCheer(cheerEvent); DebugCommandHandler instance = DebugCommandHandler.instance; if (instance != null) { instance.CommandSuccessEffect(); } } private static List<string> Suggest(bool isDebugConsole, string partial, string[] args) { List<SuggestEntry> list = new List<SuggestEntry>(); List<CombinedSuggestEntry> list2 = new List<CombinedSuggestEntry>(); foreach (EnemyConfigEntry enabledConfigEntry in EnemyConfigManager.EnabledConfigEntries) { list.Add(new SuggestEntry(enabledConfigEntry.EnemyName, enabledConfigEntry.BitsToSpawn.Value)); } foreach (MEvent enabledEvent in MEventManager.EnabledEvents) { list.Add(new SuggestEntry(enabledEvent.Name, enabledEvent.BitsPrice.Value)); } foreach (SuggestEntry item in list) { int price = item.Price; string name = item.Name; bool flag = true; foreach (CombinedSuggestEntry item2 in list2) { if (item2.Price == price) { item2.Names.Add(name); flag = false; break; } } if (flag) { list2.Add(new CombinedSuggestEntry(name, price)); } } List<string> list3 = (from x in list2 where x.Matches(args) orderby x.Price select x.GetText()).ToList(); if (ConfigManager.Event_EnableBitsForRandomEvent.Value) { CombinedSuggestEntry combinedSuggestEntry = new CombinedSuggestEntry("RANDOM EVENT", ConfigManager.Event_BitsForRandomEvent.Value); if (combinedSuggestEntry.Matches(args)) { list3.Insert(0, combinedSuggestEntry.GetText()); } } if (ConfigManager.TwitchCheerEvent_EnableBitsForRandomEnemy.Value) { CombinedSuggestEntry combinedSuggestEntry2 = new CombinedSuggestEntry("RANDOM ENEMY", ConfigManager.TwitchCheerEvent_BitsForRandomEnemy.Value); if (combinedSuggestEntry2.Matches(args)) { list3.Insert(0, combinedSuggestEntry2.GetText()); } } return list3; } private static bool IsEnabled() { if (SemiFunc.IsSplashScreen() || SemiFunc.IsMainMenu()) { return false; } if (SemiFunc.RunIsLobbyMenu()) { return false; } if (SemiFunc.RunIsTutorial()) { return false; } if (!SemiFunc.IsMasterClientOrSingleplayer()) { return false; } return true; } } internal static class TwitchSimulateSubCommand { public static void Register() { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown ChatCommand val = new ChatCommand("sub", "Simulate a Twitch sub or gift subs for TwitchTrolling", (Action<bool, string[]>)Execute, (Func<bool, string, string[], List<string>>)Suggest, (Func<bool>)IsEnabled, false); Commands.RegisterCommand(val); } private static void Execute(bool isDebugConsole, string[] args) { //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) //IL_001e: 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_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown int giftCount = 1; if (args.Length != 0 && int.TryParse(args[0], out var result)) { giftCount = result; } TwitchSubEvent subEvent = new TwitchSubEvent { User = TwitchHelper.CreateTwitchUser(), Type = (SubType)3, Tier = (SubTier)1, GiftCount = giftCount }; TwitchEventHandler.HandleSub(subEvent); DebugCommandHandler instance = DebugCommandHandler.instance; if (instance != null) { instance.CommandSuccessEffect(); } } private static List<string> Suggest(bool isDebugConsole, string partial, string[] args) { List<SuggestEntry> list = new List<SuggestEntry>(); List<CombinedSuggestEntry> list2 = new List<CombinedSuggestEntry>(); foreach (EnemyConfigEntry enabledConfigEntry in EnemyConfigManager.EnabledConfigEntries) { list.Add(new SuggestEntry(enabledConfigEntry.EnemyName, enabledConfigEntry.SubsToSpawn.Value)); } foreach (SuggestEntry item in list) { int price = item.Price; string name = item.Name; bool flag = true; foreach (CombinedSuggestEntry item2 in list2) { if (item2.Price == price) { item2.Names.Add(name); flag = false; break; } } if (flag) { list2.Add(new CombinedSuggestEntry(name, price)); } } return (from x in list2 where x.Matches(args) orderby x.Price select x.GetText()).ToList(); } private static bool IsEnabled() { if (SemiFunc.IsSplashScreen() || SemiFunc.IsMainMenu()) { return false; } if (SemiFunc.RunIsLobbyMenu()) { return false; } if (SemiFunc.RunIsTutorial()) { return false; } if (!SemiFunc.IsMasterClientOrSingleplayer()) { return false; } return true; } } } namespace com.github.zehsteam.TwitchTrolling.Twitch.Commands.Objects { internal class CombinedSuggestEntry { public List<string> Names = new List<string>(); public int Price; public CombinedSuggestEntry(string name, int price) { Names = new List<string>(1) { name }; Price = price; } public string GetText() { return $"{Price} - {GetNames()}"; } public string GetNames() { if (Names.Count == 1) { return Names[0]; } string text = string.Empty; int num = 60; int num2 = Names.Count; for (int i = 0; i < Names.Count; i++) { string text2 = string.Empty; if (i > 0) { text2 += ", "; } text2 += Names[i]; if ((text + text2).Length > num) { break; } text += text2; num2--; } if (num2 > 0) { text = text.Substring(0, Math.Min(text.Length, num)); text += $"... +{num2}"; } return text; } public bool Matches(string[] args) { string value = string.Join(" ", args); if (Price.ToString().StartsWith(value)) { return true; } if (Names.Any((string x) => x.Contains(value, StringComparison.OrdinalIgnoreCase))) { return true; } if (value.StartsWith(Price.ToString(), StringComparison.OrdinalIgnoreCase) && GetText().StartsWith(value, StringComparison.OrdinalIgnoreCase)) { return true; } return false; } } internal struct SuggestEntry { public string Name { get; set; } public int Price { get; set; } public SuggestEntry(string name, int price) { Name = name; Price = price; } } } namespace com.github.zehsteam.TwitchTrolling.Patches { [HarmonyPatch(typeof(EnemyDirector))] internal static class EnemyDirectorPatch { private static bool _patchedStart; [HarmonyPatch("Start")] [HarmonyPostfix] private static void StartPatch() { if (!_patchedStart) { _patchedStart = true; EnemyConfigManager.Initialize(); PageManager.UpdatePageFirstTime(); } } } [HarmonyPatch(typeof(EnemyDuck))] internal static class EnemyDuckPatch { public static List<EnemyDuck> DucksToBypassStunAggroOnce = new List<EnemyDuck>(); public static void Reset() { DucksToBypassStunAggroOnce = new List<EnemyDuck>(); } [HarmonyPatch("StateStun")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> StateStunTranspiler(IEnumerable<CodeInstruction> instructions) { //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Expected O, but got Unknown string text = "EnemyDuckPatch: [StateStun Transpiler]"; MethodInfo methodInfo = AccessTools.Method(typeof(EnemyDuck), "UpdateState", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(EnemyDuckPatch), "StateStun_UpdateState", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null) { Logger.LogError(text + " Failed to create transpiler. Required methods not found."); return instructions; } List<CodeInstruction> list = new List<CodeInstruction>(); foreach (CodeInstruction instruction in instructions) { if (CodeInstructionExtensions.Calls(instruction, methodInfo)) { list.Add(new CodeInstruction(OpCodes.Call, (object)methodInfo2)); Logger.LogInfo(text + " Replaced " + methodInfo.Name + " call with " + methodInfo2.Name + ".", extended: true); } else { list.Add(instruction); } } return list.AsEnumerable(); } private static void StateStun_UpdateState(EnemyDuck enemyDuck, State state) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_002b: Unknown result type (might be due to invalid IL or missing references) if ((int)state == 11 && DucksToBypassStunAggroOnce.Contains(enemyDuck)) { DucksToBypassStunAggroOnce.Remove(enemyDuck); enemyDuck.UpdateState((State)1); } else { enemyDuck.UpdateState(state); } } } [HarmonyPatch(typeof(FanTrap))] internal static class FanTrapPatch { public static List<FanTrap> FansToBypassIdle = new List<FanTrap>(); [HarmonyPatch("SetState")] [HarmonyPrefix] private static bool SetStatePatch(FanTrap __instance, States state) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if ((int)state != 0) { return true; } if (FansToBypassIdle.Contains(__instance)) { return false; } return true; } } [HarmonyPatch(typeof(HUDCanvas))] internal static class HUDCanvasPatch { [HarmonyPatch("Awake")] [HarmonyPostfix] private static void AwakePatch(HUDCanvas __instance) { Transform parent = ((Component)__instance).transform.Find("HUD"); PluginHUD.Spawn(parent); } } [HarmonyPatch(typeof(ItemDrone))] internal static class ItemDronePatch { public static List<PhysGrabObject> IgnorePhysGrabObjects = new List<PhysGrabObject>(); [HarmonyPatch("NewRayHitPointLogic")] [HarmonyPrefix] private static bool NewRayHitPointLogicPatch(ItemDrone __instance, int photonViewId, Transform newMagnetTarget) { PhysGrabObject physGrabObject = ((!((Object)(object)newMagnetTarget != (Object)null)) ? ((Component)PhotonView.Find(photonViewId)).gameObject.GetComponent<PhysGrabObject>() : ((Component)newMagnetTarget).GetComponent<PhysGrabObject>()); return CanAttachToPhysGrabObject(__instance, physGrabObject); } [HarmonyPatch("GetHighestParentWithRigidbody")] [HarmonyPostfix] private static void GetHighestParentWithRigidbodyPatch(ItemDrone __instance, ref Transform __result) { PhysGrabObject physGrabObject = default(PhysGrabObject); if (!((Object)(object)__result == (Object)null) && ((Component)__result).TryGetComponent<PhysGrabObject>(ref physGrabObject) && !CanAttachToPhysGrabObject(__instance, physGrabObject)) { __result = null; } } private static bool CanAttachToPhysGrabObject(ItemDrone itemDrone, PhysGrabObject physGrabObject) { if ((Object)(object)itemDrone == (Object)null || (Object)(object)physGrabObject == (Object)null) { return true; } if (IsSameDroneType(itemDrone, physGrabObject)) { return false; } if (IgnorePhysGrabObjects.Contains(physGrabObject)) { return false; } return true; } private static bool IsSameDroneType(ItemDrone itemDrone, PhysGrabObject physGrabObject) { if ((Object)(object)itemDrone == (Object)null || (Object)(object)physGrabObject == (Object)null) { return false; } ItemAttributes val = default(ItemAttributes); if (!((Component)physGrabObject).TryGetComponent<ItemAttributes>(ref val)) { return false; } return itemDrone.itemAttributes.itemName == val.itemName; } } [HarmonyPatch(typeof(ItemRubberDuck))] internal static class ItemRubberDuckPatch { public static List<ItemRubberDuck> SpecialRubberDucks = new List<ItemRubberDuck>(); [HarmonyPatch("Quack")] [HarmonyPostfix] private static void QuackPatch(ItemRubberDuck __instance) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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 (SpecialRubberDucks.Contains(__instance) && SemiFunc.IsMasterClientOrSingleplayer() && !(__instance.itemBattery.batteryLife <= 0f) && !__instance.physGrabObject.grabbed) { Vector3 velocity = __instance.rb.velocity; if (((Vector3)(ref velocity)).magnitude >= 20f) { Rigidbody rb = __instance.rb; rb.velocity *= 5f; __instance.rb.AddTorque(Random.insideUnitSphere * 40f); } } } } [HarmonyPatch(typeof(LevelGenerator))] internal static class LevelGeneratorPatch { [HarmonyPatch("EnemySetup")] [HarmonyPostfix] private static void EnemySetupPatch() { EnemyManager.ResetViewerEnemies(); EnemyDuckPatch.Reset(); if (TwitchIntegrationManager.CanPlayEvents()) { TwitchEventQueue.PlayQueuedEvents(TimeSpan.FromSeconds(10.0)); } } } [HarmonyPatch(typeof(PlayerController))] internal static class PlayerControllerPatch { private static bool _usingCustomSpeed; private static float _timeCustomSpeedEnd = float.NegativeInfinity; private static bool _usingCustomGravity; private static float _timeCustomGravityEnd = float.NegativeInfinity; [HarmonyPatch("Update")] [HarmonyPostfix] private static void UpdatePatch() { if (_usingCustomSpeed && !IsSpeedOverwritten()) { _usingCustomSpeed = false; ResetSpeed(); } if (_usingCustomGravity && !IsGravityOverwritten()) { _usingCustomGravity = false; ResetGravity(); } } public static void OverrideSpeed(float value, TimeSpan duration) { if (!((Object)(object)PlayerController.instance == (Object)null)) { _usingCustomSpeed = true; SetSpeed(value); _timeCustomSpeedEnd = Time.realtimeSinceStartup + (float)duration.TotalSeconds; } } private static bool IsSpeedOverwritten() { return Time.realtimeSinceStartup < _timeCustomSpeedEnd; } private static void SetSpeed(float value) { if (!((Object)(object)PlayerController.instance == (Object)null)) { value += 5f; PlayerController.instance.CrouchSpeed = value; PlayerController.instance.MoveSpeed = value; PlayerController.instance.SprintSpeed = value; } } private static void ResetSpeed() { if (!((Object)(object)PlayerAvatar.instance == (Object)null) && !((Object)(object)StatsManager.instance == (Object)null)) { PlayerController.instance.OverrideSpeed(1f, 0.1f); MessageManager.Instance?.ShowMessage("Your speed has been reset"); } } public static void OverrideGravity(float value, TimeSpan duration) { if (!((Object)(object)PlayerController.instance == (Object)null)) { _usingCustomGravity = true; SetGravity(value); _timeCustomGravityEnd = Time.realtimeSinceStartup + (float)duration.TotalSeconds; } } private static bool IsGravityOverwritten() { return Time.realtimeSinceStartup < _timeCustomGravityEnd; } private static void SetGravity(float value) { if (!((Object)(object)PlayerController.instance == (Object)null)) { PlayerController.instance.CustomGravity = value; } } private static void ResetGravity() { if (!((Object)(object)PlayerAvatar.instance == (Object)null) && !((Object)(object)StatsManager.instance == (Object)null)) { PlayerController.instance.CustomGravity = PlayerController.instance.playerOriginalCustomGravity; } } } [HarmonyPatch(typeof(RunManager))] internal static class RunManagerPatch { private static bool _patchedAwake; [HarmonyPatch("Awake")] [HarmonyPostfix] private static void AwakePatch(RunManager __instance) { if (!_patchedAwake) { _patchedAwake = true; MEventManager.Initialize(); } } } [HarmonyPatch(typeof(TruckScreenText))] internal static class TruckScreenTextPatch { [HarmonyPatch("Start")] [HarmonyPostfix] private static void StartPatch() { SpawnTruckProps(); } private static void SpawnTruckProps() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (TryGetTruckMeshTransform(out var transform)) { GameObject val = Object.Instantiate<GameObject>(Assets.TruckPropsPrefab); val.transform.SetParent(transform); val.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); Logger.LogInfo("TruckScreenTextPatch: Spawned truck props.", extended: true); } } private static bool TryGetTruckMeshTransform(out Transform transform) { transform = null; if ((Object)(object)TruckScreenText.instance == (Object)null) { Logger.LogInfo("TruckScreenTextPatch: Failed to get truck mesh transform. TruckScreenText instance is null."); return false; } try { transform = ((Component)TruckScreenText.instance).transform.parent.Find("Mesh"); return true; } catch (Exception arg) { Logger.LogInfo($"TruckScreenTextPatch: Failed to get truck mesh transform. {arg}"); return false; } } } } namespace com.github.zehsteam.TwitchTrolling.Objects { [Serializable] public class AudioPlayerFactory { public enum AudioUseMode { Single, Reuse } private static Dictionary<AudioPlayerType, Queue<AudioPlayer>> _audioPlayerPool = new Dictionary<AudioPlayerType, Queue<AudioPlayer>>(); public AudioPlayer AudioPlayer; public AudioPlayerType Type; public AudioUseMode UseMode; public float Volume = 1f; public float MaxDistance = 15f; public bool IsPlaying => AudioPlayer?.IsPlaying ?? false; public float Play(AudioClip audioClip, Vector3 position, bool loop = false) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) AssignAudioPlayer(); if (UseMode != AudioUseMode.Reuse) { loop = false; } return AudioPlayer?.Play(audioClip, position, Volume, MaxDistance, loop) ?? 0f; } public float Play(AudioClip audioClip, Transform transform, bool loop = false) { AssignAudioPlayer(); if (UseMode != AudioUseMode.Reuse) { loop = false; } return AudioPlayer?.Play(audioClip, transform, Volume, MaxDistance, loop) ?? 0f; } public void Stop() { AudioPlayer?.Stop(); } public void SetTargetTransform(Transform targetTransform) { AudioPlayer?.SetTargetTransform(targetTransform); } public void SetTargetPosition(Vector3 targetPosition) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) AudioPlayer?.SetTargetPosition(targetPosition); } private void AssignAudioPlayer() { if (UseMode == AudioUseMode.Single) { AudioPlayer = GetAudioPlayer(); } else if (UseMode == AudioUseMode.Reuse) { if ((Object)(object)AudioPlayer == (Object)null || (Object)(object)((Component)AudioPlayer).gameObject == (Object)null) { AudioPlayer = GetAudioPlayer(); } if (!((Object)(object)AudioPlayer == (Object)null) && !((Component)AudioPlayer).gameObject.activeSelf) { ((Component)AudioPlayer).gameObject.SetActive(true); } } } private GameObject GetAudioPrefab() { if ((Object)(object)AudioManager.instance == (Object)null) { return null; } return (GameObject)(Type switch { AudioPlayerType.Default => AudioManager.instance.AudioDefault, AudioPlayerType.EnemySpawn => Assets.AudioEnemySpawnPrefab, _ => null, }); } private AudioPlayer GetAudioPlayer() { if (!_audioPlayerPool.TryGetValue(Type, out var value) || value.Count == 0) { return CreateAudioPlayer(); } AudioPlayer audioPlayer = value.Dequeue(); if ((Object)(object)audioPlayer == (Object)null || (Object)(object)((Component)audioPlayer).gameObject == (Object)null) { return CreateAudioPlayer(); } ((Component)audioPlayer).gameObject.SetActive(false); ((Component)audioPlayer).gameObject.SetActive(true); return audioPlayer; } private AudioPlayer CreateAudioPlayer() { if ((Object)(object)AudioManager.instance == (Object)null) { return null; } GameObject audioPrefab = GetAudioPrefab(); if ((Object)(object)audioPrefab == (Object)null) { return null; } GameObject val = Object.Instantiate<GameObject>(audioPrefab); ((Object)val).name = $"AudioPlayer {Type}"; AudioPlayer audioPlayer = val.AddComponent<AudioPlayer>(); audioPlayer.Type = Type; if ((Object)(object)PluginManager.Instance != (Object)null) { val.transform.SetParent(PluginManager.Instance.AudioPlayerContainerTransform); } return audioPlayer; } public static void AddToPool(AudioPlayer audioPlayer) { if (!((Object)(object)audioPlayer == (Object)null) && !((Object)(object)((Component)audioPlayer).gameObject == (Object)null)) { if (!_audioPlayerPool.TryGetValue(audioPlayer.Type, out var value)) { value = new Queue<AudioPlayer>(); _audioPlayerPool.Add(audioPlayer.Type, value); } value.Enqueue(audioPlayer); ((Component)audioPlayer).gameObject.SetActive(false); } } } public class EnemyConfigEntry { private readonly EnemyConfigEntryDefaultValues _defaultValues; public string EnemyName { get; private set; } public ConfigEntry<bool> Enabled { get; private set; } public ConfigEntry<int> SpawnCount { get; private set; } public ConfigEntry<int> BitsToSpawn { get; private set; } public ConfigEntry<int> SubsToSpawn { get; private set; } public EnemyConfigEntry(string enemyName) { _defaultValues = new EnemyConfigEntryDefaultValues(enemyName); Initialize(); } public EnemyConfigEntry(EnemyConfigEntryDefaultValues defaultValues) { _defaultValues = defaultValues; Initialize(); } private void Initialize() { if (_defaultValues != null) { EnemyName = _defaultValues.EnemyName; BindConfigs(); } } private void BindConfigs() { string text = "Enemy: " + EnemyName; Enabled = EnemyConfigManager.ConfigFile.Bind<bool>(text, "Enabled", _defaultValues.Enabled, "Enable the " + EnemyName + " to be able to spawn."); SpawnCount = EnemyConfigManager.ConfigFile.Bind(text, "SpawnCount", _defaultValues.SpawnCount, "The amount of " + EnemyName + " to spawn.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20)); BitsToSpawn = EnemyConfigManager.ConfigFile.Bind(text, "BitsToSpawn", _defaultValues.BitsToSpawn, "The amount of bits to spawn " + EnemyName + ".", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000)); SubsToSpawn = EnemyConfigManager.ConfigFile.Bind(text, "SubsToSpawn", _defaultValues.SubsToSpawn, "The amount of subs to spawn " + EnemyName + ".", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10)); Enabled.SettingChanged += delegate { PageManager.UpdatePage(); }; SpawnCount.SettingChanged += delegate { PageManager.UpdatePage(); }; BitsToSpawn.SettingChanged += delegate { PageManager.UpdatePage(); }; SubsToSpawn.SettingChanged += delegate { PageManager.UpdatePage(); }; } public bool EnemyNameEquals(string enemyName) { return EnemyName.Equals(enemyName, StringComparison.OrdinalIgnoreCase); } public JObject GetCardJSON() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Expected O, but got Unknown int num = 1; int value = SpawnCount.Value; if (EnemyName.Equals("Banger", StringComparison.OrdinalIgnoreCase)) { num = 3; } if (EnemyName.Equals("Gnome", StringComparison.OrdinalIgnoreCase)) { num = 4; } JObject val = new JObject { ["name"] = JToken.op_Implicit(EnemyName), ["price"] = JToken.op_Implicit(BitsToSpawn.Value), ["spawnCount"] = JToken.op_Implicit(num * value) }; if (ConfigManager.TwitchSubEvent_Enabled.Value) { val.Add("subPrice", JToken.op_Implicit(SubsToSpawn.Value)); } return val; } } [Serializable] public class EnemyConfigEntryDefaultValues { public string EnemyName; public bool Enabled = true; public int SpawnCount = 1; public int BitsToSpawn = 350; public int SubsToSpawn = 1; public EnemyConfigEntryDefaultValues(string enemyName) { EnemyName = enemyName; } public EnemyConfigEntryDefaultValues(string enemyName, bool enabled, int spawnCount, int bitsToSpawn, int subsToSpawn) : this(enemyName) { Enabled = enabled; SpawnCount = spawnCount; BitsToSpawn = bitsToSpawn; SubsToSpawn = subsToSpawn; } } [CreateAssetMenu(fileName = "EnemyConfigEntryDefaultValuesList", menuName = "TwitchTrolling/EnemyConfigEntryDefaultValuesList")] public class EnemyConfigEntryDefaultValuesList : ScriptableObject { public EnemyConfigEntryDefaultValues[] List = Array.Empty<EnemyConfigEntryDefaultValues>(); } [Serializable] public class EnemySpawnSFX { public string EnemyName; public AudioClip SpawnSFX; public EnemySpawnSFX(string enemyName, AudioClip spawnSFX) { EnemyName = enemyName; SpawnSFX = spawnSFX; } } [CreateAssetMenu(fileName = "EnemySpawnSFXList", menuName = "TwitchTrolling/EnemySpawnSFXList")] public class EnemySpawnSFXList : ScriptableObject { public AudioClip GenericSpawnSFX; public EnemySpawnSFX[] List = Array.Empty<EnemySpawnSFX>(); public AudioClip GetSpawnSFX(string enemyName) { EnemySpawnSFX[] list = List; foreach (EnemySpawnSFX enemySpawnSFX in list) { if (enemySpawnSFX.EnemyName.Equals(enemyName, StringComparison.OrdinalIgnoreCase)) { return enemySpawnSFX.SpawnSFX; } } return GenericSpawnSFX; } } internal class JsonSave { private JObject _data; public string DirectoryPath { get; private set; } public string FileName { get; private set; } public string FilePath => Path.Combine(DirectoryPath, FileName); public JsonSave(string directoryPath, string fileName) { DirectoryPath = directoryPath; FileName = fileName; _data = ReadFile(); } public bool KeyExists(string key) { if (_data == null) { Logger.LogError("KeyExists: Data is null. Ensure the save file is properly loaded."); return false; } return _data.ContainsKey(key); } public T Load<T>(string key, T defaultValue = default(T), bool readFile = false) { if (TryLoad<T>(key, out var value, readFile)) { return value; } return defaultValue; } public bool TryLoad<T>(string key, out T value, bool readFile = false) { //IL_0058: Expected O, but got Unknown value = default(T); if (readFile) { _data = ReadFile(); } if (_data == null) { Logger.LogError("Load: Data is null. Returning default value for key: " + key + "."); return false; } JToken val = default(JToken); if (_data.TryGetValue(key, ref val)) { try { value = val.ToObject<T>(); return true; } catch (JsonException val2) { JsonException val3 = val2; Logger.LogError("Load: JSON Conversion Error for key: " + key + ". " + ((Exception)(object)val3).Message); } catch (ArgumentNullException ex) { Logger.LogError("Load: Argument Null Error for key: " + key + ". " + ex.Message); } catch (Exception ex2) { Logger.LogError("Load: Unexpected Error for key: " + key + ". " + ex2.Message); } return false; } Logger.LogWarning("Load: Key '" + key + "' does not exist. Returning default value.", extended: true); return false; } public bool Save<T>(string key, T value) { if (_data == null) { Logger.LogError("Save: Data is null. Cannot save key: " + key + "."); return false; } try { JToken val = JToken.FromObject((object)value); if (_data.ContainsKey(key)) { _data[key] = val; } else { _data.Add(key, val); } return WriteFile(_data); } catch (Exception ex) { Logger.LogError("Save: Error saving key: " + key + ". " + ex.Message); return false; } } private JObject ReadFile() { //IL_0070: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Expected O, but got Unknown try { if (!File.Exists(FilePath)) { Logger.LogWarning("ReadFile: Save file does not exist at \"" + FilePath + "\". Initializing with an empty file.", extended: true); return new JObject(); } using FileStream stream = new FileStream(FilePath, FileMode.Open, FileAccess.Read); using StreamReader streamReader = new StreamReader(stream, Encoding.UTF8); return JObject.Parse(streamReader.ReadToEnd()); } catch (JsonException val) { JsonException val2 = val; Logger.LogError("ReadFile: JSON Parsing Error for file: \"" + FilePath + "\". " + ((Exception)(object)val2).Message); } catch (Exception ex) { Logger.LogError("ReadFile: Unexpected Error for file: \"" + FilePath + "\". " + ex.Message); } return new JObject(); } private bool WriteFile(JObject data) { try { if (!Directory.Exists(DirectoryPath)) { Directory.CreateDirectory(DirectoryPath); } File.WriteAllText(FilePath, ((object)data).ToString(), Encoding.UTF8); return true; } catch (Exception ex) { Logger.LogError("WriteFile: Unexpected Error for file: \"" + FilePath + "\". " + ex.Message); } return false; } } internal class JsonSaveValue<T> : ObservableValue<T> { public JsonSave JsonSave { get; private set; } public string Key { get; private set; } public T DefaultValue { get; private set; } public bool ReadFile { get; private set; } public bool HasValue { get { T value; return TryLoad(out value); } } public JsonSaveValue(JsonSave jsonSave, string key, T defaultValue = default(T), bool readFile = false) : base(default(T)) { JsonSave = jsonSave; Key = key; DefaultValue = defaultValue; ReadFile = readFile; CustomValueGetter = Load; CustomValueSetter = Save; } private T Load() { return JsonSave.Load(Key, DefaultValue, ReadFile); } private bool TryLoad(out T value) { return JsonSave.TryLoad<T>(Key, out value, ReadFile); } private void Save(T value) { if (!object.Equals(value, base.Value)) { JsonSave.Save(Key, value); } } } internal class ObservableValue<T> { protected T _value; protected Func<T> CustomValueGetter; protected Action<T> CustomValueSetter; public T Value { get { return GetValue(); } set { SetValue(value); } } public event Action<T> OnValueChanged; public ObservableValue(T initialValue = default(T)) { _value = initialValue; } private T GetValue() { if (CustomValueGetter != null) { _value = CustomValueGetter(); } return _value; } private void SetValue(T value) { if (!object.Equals(_value, value)) { _value = value; CustomValueSetter?.Invoke(value); this.OnValueChanged?.Invoke(value); } } } public class QueueJsonConverter<T> : JsonConverter { public override bool CanConvert(Type objectType) { return objectType == typeof(Queue<T>); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { Queue<T> source = (Queue<T>)value; serializer.Serialize(writer, (object)source.ToList()); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { List<T> collection = serializer.Deserialize<List<T>>(reader); return new Queue<T>(collection); } } } namespace com.github.zehsteam.TwitchTrolling.MonoBehaviours { public enum AudioPlayerType { Default, EnemySpawn } public class AudioPlayer : MonoBehaviour { [CompilerGenerated] private sealed class <PoolAfterDurationCoroutine>d__18 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public TimeSpan duration; public AudioPlayer <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <PoolAfterDurationCoroutine>d__18(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown int num = <>1__state; AudioPlayer audioPlayer = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds((float)duration.TotalSeconds); <>1__state = 1; return true; case 1: <>1__state = -1; AudioPlayerFactory.AddToPool(audioPlayer); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public const float DefaultVolume = 1f; public const float DefaultMaxDistance = 15f; private AudioSource _audioSource; public AudioPlayerType Type; public Transform TargetTransform; public Vector3 TargetPosition; public AudioSource AudioSource { get { if (_audioSource == null) { _audioSource = ((Component)this).GetComponent<AudioSource>(); } return _audioSource; } private set { _audioSource = value; } } public bool IsPlaying { get { AudioSource audioSource = AudioSource; if (audioSource == null) { return false; } return audioSource.isPlaying; } } private void Start() { AudioSource.dopplerLevel = 0f; } private void Update() { UpdatePosition(); UpdateSpatialBlend(); } private void UpdatePosition() { //IL_0026: 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_001a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)TargetTransform != (Object)null) { TargetPosition = TargetTransform.position; } ((Component)this).transform.position = TargetPosition; } private void UpdateSpatialBlend() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) float spatialBlend = 1f; PlayerAvatar localPlayer = PlayerHelper.GetLocalPlayer(); if (!((Object)(object)localPlayer == (Object)null)) { float num = Vector3.Distance(((Component)this).transform.position, ((Component)localPlayer.localCamera).transform.position); if (num <= 0.5f) { spatialBlend = 0f; } AudioSource.spatialBlend = spatialBlend; } } public float Play(AudioClip audioClip, Vector3 position, float volume = 1f, float maxDistance = 15f, bool loop = false) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) SetTargetPosition(position); return Play(audioClip, volume, maxDistance, loop); } public float Play(AudioClip audioClip, Transform transform, float volume = 1f, float maxDistance = 15f, bool loop = false) { SetTargetTransform(transform); return Play(audioClip, volume, maxDistance, loop); } private float Play(AudioClip audioClip, float volume = 1f, float maxDistance = 15f, bool loop = false) { if ((Object)(object)AudioSource == (Object)null) { if ((Object)(object)((Component)this).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)this).gameObject); } return 0f; } if ((Object)(object)audioClip == (Object)null) { AudioPlayerFactory.AddToPool(this); return 0f; } AudioSource.clip = audioClip; AudioSource.volume = volume; AudioSource.maxDistance = maxDistance; AudioSource.loop = loop; if (loop) { if (!AudioSource.isPlaying) { AudioSource.Play(); } } else { AudioSource.PlayOneShot(audioClip, volume); TimeSpan duration = TimeSpan.FromSeconds(audioClip.length + 0.1f); ((MonoBehaviour)this).StartCoroutine(PoolAfterDurationCoroutine(duration)); } return audioClip.length; } [IteratorStateMachine(typeof(<PoolAfterDurationCoroutine>d__18))] private IEnumerator PoolAfterDurationCoroutine(TimeSpan duration) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <PoolAfterDurationCoroutine>d__18(0) { <>4__this = this, duration = duration }; } public void Stop() { AudioSource audioSource = AudioSource; if (audioSource != null) { audioSource.Stop(); } } public void SetTargetTransform(Transform targetTransform) { TargetTransform = targetTransform; } public void SetTargetPosition(Vector3 targetPosition) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) TargetTransform = null; TargetPosition = targetPosition; } } public class BrowserLink : MonoBehaviour { [SerializeField] public string _url; public void OpenLink() { Application.OpenURL(_url); } } public class DeathMessage : MonoBehaviour { [CompilerGenerated] private sealed class <ShowCoroutine>d__26 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public DeathMessage <>4__this; public TimeSpan duration; private float <fadeOutDuration>5__2; private float <timer>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ShowCoroutine>d__26(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown int num = <>1__state; DeathMessage deathMessage = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; deathMessage._canvasGroup.alpha = 1f; <>2__current = (object)new WaitForSeconds((float)duration.TotalSeconds); <>1__state = 1; return true; case 1: <>1__state = -1; <fadeOutDuration>5__2 = 1f; <timer>5__3 = 0f; break; case 2: <>1__state = -1; <timer>5__3 += Time.deltaTime; break; } if (<timer>5__3 < <fadeOutDuration>5__2) { float num2 = 1f / <fadeOutDuration>5__2 * <timer>5__3; float alpha = 1f + -1f * num2; deathMessage._canvasGroup.alpha = alpha; <>2__current = null; <>1__state = 2; return true; } deathMessage._canvasGroup.alpha = 0f; deathMessage._showCoroutine = null; return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [SerializeField] private TextMeshProUGUI _textUGUI; [SerializeField] private Image _backgroundImage; [SerializeField] private CanvasGroup _canvasGroup; private Coroutine _showCoroutine; public static DeathMessage Instance { get; private set; } public static bool IsEnabled => ConfigManager.DeathMessage_Enabled.Value; public static bool ShowPlatformIcon => ConfigManager.DeathMessage_ShowPlatformIcon.Value; public static float Duration => ConfigManager.DeathMessage_Duration.Value; public static float FontSize => ConfigManager.DeathMessage_FontSize.Value; public static int BackgroundTransparency => ConfigManager.DeathMessage_BackgroundTransparency.Value; private void Awake() { if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this) { Object.Destroy((Object)(object)((Component)this).gameObject); } else { Instance = this; } } private void Start() { _canvasGroup.alpha = 0f; } public void Show(EnemyParent enemyParent, ViewerData viewerData) { if (!((Object)(object)enemyParent == (Object)null) && viewerData != null) { string text = (ShowPlatformIcon ? "<sprite=0>" : string.Empty); string message = ("You died to a <color=#FF0000>" + enemyParent.enemyName + "</color> from " + viewerData.GetDisplayNameWithColor() + " " + text).Trim(); Show(message); } } public void Show(PhysGrabObject physGrabObject, ViewerData viewerData) { if (!((Object)(object)physGrabObject == (Object)null) && viewerData != null) { string text = ((Object)physGrabObject).name.TrimStart("Valuable ").TrimEnd("(Clone)").Trim(); string text2 = (ShowPlatformIcon ? "<sprite=0>" : string.Empty); string message = ("You died to a <color=#FF0000>" + text + "</color> from " + viewerData.GetDisplayNameWithColor() + " " + text2).Trim(); Show(message); } } public void ShowForExplosion(ViewerData viewerData, string sourceName = "") { if (viewerData != null) { string text = (ShowPlatformIcon ? "<sprite=0>" : string.Empty); string text2 = ((!string.IsNullOrEmpty(sourceName)) ? ("<color=#FF0000>" + sourceName + " (Explosion)</color>") : "<color=#FF0000>explosion</color>"); string message = ("You died to an " + text2 + " from " + viewerData.GetDisplayNameWithColor() + " " + text).Trim(); Show(message); } } public void Show(string message) { Show(message, TimeSpan.FromSeconds(Duration)); } public void Show(string message, TimeSpan duration) { if (IsEnabled) { UseConfigSettings(); if (_showCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_showCoroutine); } ((TMP_Text)_textUGUI).text = message; _showCoroutine = ((MonoBehaviour)this).StartCoroutine(ShowCoroutine(duration)); } } private void UseConfigSettings() { ((TMP_Text)_textUGUI).fontSize = FontSize; _backgroundImage.SetAlpha(BackgroundTransparency); } [IteratorStateMachine(typeof(<ShowCoroutine>d__26))] private IEnumerator ShowCoroutine(TimeSpan duration) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <ShowCoroutine>d__26(0) { <>4__this = this, duration = duration }; } } public class EnemyNametag : MonoBehaviour { [SerializeField] private TextMeshProUGUI _usernameText; [SerializeField] public Image _backgroundImage; [SerializeField] public CanvasGroup _canvasGroup; private static readonly float _heightOffset = 0.5f; private static readonly float _minSize = 0.75f; private static readonly float _maxSize = 1.5f; private RectTransform _rectTransform; private Transform _enemyTransform; private object _enemyScript; private bool _continuouslyCalculatePosition; private float _continuouslyCalculatePositionTimer; private float _continuouslyCalculatePositionCooldown = 0.1f; public static List<EnemyNametag> Instances { get; private set; } = new List<EnemyNametag>(); public static bool ShowPlatformIcon => ConfigManager.EnemyNametag_ShowPlatformIcon.Value; public static float SizeMultiplier => ConfigManager.EnemyNametag_SizeMultiplier.Value; public static int BackgroundTransparency => ConfigManager.EnemyNametag_BackgroundTransparency.Value; public EnemyParent EnemyParent { get; private set; } public ViewerData Viewer { get; private set; } private void OnEnable() { Instances.AddSingleInstance(this); } private void OnDisable() { Instances.Remove(this); } public void SetData(EnemyParent enemyParent, ViewerData viewerData) { EnemyParent = enemyParent; Viewer = viewerData; if (IsEnemyTypeElsa()) { _enemyScript = ((Component)enemyParent).GetComponentInChildren<EnemyElsa>(true); _continuouslyCalculatePosition = true; } if (IsEnemyTypeOogly()) { _enemyScript = ((Component)enemyParent).GetComponentInChildren<EnemyOogly>(true); _continuouslyCalculatePosition = true; } } private void Start() { if ((Object)(object)EnemyParent == (Object)null) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } _rectTransform = ((Component)this).GetComponent<RectTransform>(); _enemyTransform = GetEnemyTransform(); bool flag = false; if (IsEnemyTypePeeper()) { flag = true; ((Transform)_rectTransform).SetParent(((Component)EnemyParent.Enemy).transform); } if (!flag) { ((Transform)_rectTransform).SetParent(_enemyTransform); } CalculatePosition(); UseConfigSettings(); } private void Update() { if ((Object)(object)EnemyParent == (Object)null) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } if (!IsEnemyEnabled()) { _canvasGroup.alpha = 0f; return; } if (IsEnemyTypeHidden()) { Update_HiddenEnemy(); } else { _canvasGroup.alpha = 1f; } if (_continuouslyCalculatePosition) { _continuouslyCalculatePositionTimer += Time.deltaTime; if (_continuouslyCalculatePositionTimer >= _continuouslyCalculatePositionCooldown) { CalculatePosition(); _continuouslyCalculatePositionTimer = 0f; } } } private void Update_HiddenEnemy() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) float alpha = 0f; if (TryGetEnemyTransform(out var transform)) { Vector3 origin = transform.position + new Vector3(0f, 1f, 0f); if (PlayerHelper.AnyPlayersNearby(origin, 5f)) { alpha = 1f; } } _canvasGroup.alpha = alpha; } private void LateUpdate() { LookAtLocalCamera(); } private bool IsEnemyTypeHidden() { return EnemyParent.enemyName.Equals("Hidden", StringComparison.OrdinalIgnoreCase); } private bool IsEnemyTypePeeper() { return EnemyParent.enemyName.Equals("Peeper", StringComparison.OrdinalIgnoreCase); } private bool IsEnemyTypeElsa() { return EnemyParent.enemyName.Equals("Elsa", StringComparison.OrdinalIgnoreCase); } private bool IsEnemyTypeOogly() { return EnemyParent.enemyName.Equals("Oogly", StringComparison.OrdinalIgnoreCase); } private bool IsEnemyEnabled() { return EnemyParent.EnableObject.activeSelf; } private Transform GetEnemyTransform() { if ((Object)(object)EnemyParent == (Object)null || (Object)(object)EnemyParent.EnableObject == (Object)null) { return null; } EnemyRigidbody componentInChildren = EnemyParent.EnableObject.GetComponentInChildren<EnemyRigidbody>(); if ((Object)(object)componentInChildren != (Object)null) { return ((Component)componentInChildren).transform; } return ((Component)EnemyParent).transform; } private bool TryGetEnemyTransform(out Transform transform) { transform = GetEnemyTransform(); return (Object)(object)transform != (Object)null; } private void LookAtLocalCamera() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) PlayerAvatar localPlayer = PlayerHelper.GetLocalPlayer(); if (!((Object)(object)localPlayer == (Object)null)) { ((Component)this).transform.LookAt(((Component)this).transform.position + ((Component)localPlayer.localCamera).transform.forward); } } private void CalculatePosition() { //IL_001d: 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_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) if (IsEnemyTypePeeper()) { ((Transform)_rectTransform).localPosition = new Vector3(0f, 0f, 0.85f); return; } Transform val = _enemyTransform; if (IsEnemyTypeElsa() && _enemyScript != null) { object enemyScript = _enemyScript; EnemyElsa val2 = (EnemyElsa)((enemyScript is EnemyElsa) ? enemyScript : null); if (val2 != null && !val2.IsBig()) { val = val2.smallColliderTransform; } } if (IsEnemyTypeOogly() && _enemyScript != null) { object enemyScript2 = _enemyScript; EnemyOogly val3 = (EnemyOogly)((enemyScript2 is EnemyOogly) ? enemyScript2 : null); if (val3 != null && (Object)(object)val3.targetPlayer == (Object)null) { ((Transform)_rectTransform).localPosition = new Vector3(0f, -1.5f, 0f); return; } } Collider[] componentsInChildren = ((Component)val).GetComponentsInChildren<Collider>(); if (componentsInChildren == null || componentsInChildren.Length == 0) { Logger.LogWarning("EnemyNametag: No colliders found on the enemy."); return; } float num = float.MinValue; Collider[] array = componentsInChildren; foreach (Collider val4 in array) { if (!val4.isTrigger) { Bounds bounds = val4.bounds; float y = ((Bounds)(ref bounds)).max.y; if (y > num) { num = y; } } } float num2 = num + _heightOffset; Vector3 localPosition = default(Vector3); ((Vector3)(ref localPosition))..ctor(0f, num2 - _enemyTransform.position.y, 0f); ((Transform)_rectTransform).localPosition = localPosition; } public void CalculateScale() { //IL_0023: 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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) Collider[] componentsInChildren = ((Component)_enemyTransform).GetComponentsInChildren<Collider>(true); if (componentsInChildren == null || componentsInChildren.Length == 0) { Logger.LogWarning("EnemyNametag: No colliders found on the enemy."); return; } Bounds bounds = componentsInChildren[0].bounds; Collider[] array = componentsInChildren; foreach (Collider val in array) { if (!val.isTrigger) { (