Decompiled source of TwitchTrolling v1.4.2
com.github.zehsteam.MetadataUtils.dll
Decompiled 3 days 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.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+e18b3cf4d103ba20bb4385f1727a56854df7a059")] [assembly: AssemblyProduct("MetadataUtils")] [assembly: AssemblyTitle("com.github.zehsteam.MetadataUtils")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.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.0.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.0.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 3 days 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.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+645ad2c775e80a45c7ba4a15a73d5d7474c98f9c")] [assembly: AssemblyProduct("PlayerDamageTracker")] [assembly: AssemblyTitle("com.github.zehsteam.PlayerDamageTracker")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.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.0.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.0.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 3 days 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.Commands; 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.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.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.4.2.0")] [assembly: AssemblyInformationalVersion("1.4.2+d69a5d2c270cfa746c5a7886d99da7b9c8c36dab")] [assembly: AssemblyProduct("TwitchTrolling")] [assembly: AssemblyTitle("com.github.zehsteam.TwitchTrolling")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.4.2.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 GameObject ModCreditsPrefab { 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); ModCreditsPrefab = LoadAsset<GameObject>("TwitchTrolling ModCredits", assetBundle); NetworkPrefabs.RegisterNetworkPrefab(((Object)ModCreditsPrefab).name, ModCreditsPrefab); 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 ConfigManager { public static ConfigFile ConfigFile { get; private set; } public static ConfigEntry<bool> ExtendedLogging { get; private set; } public static ConfigEntry<bool> TwitchIntegration_Enabled { get; private set; } public static ConfigEntry<bool> TwitchSubEvent_Enabled { get; private set; } public static ConfigEntry<int> TwitchSubEvent_Tier1EnemySpawnCountMultiplier { get; private set; } public static ConfigEntry<int> TwitchSubEvent_Tier2EnemySpawnCountMultiplier { get; private set; } public static ConfigEntry<int> TwitchSubEvent_Tier3EnemySpawnCountMultiplier { get; private set; } public static ConfigEntry<bool> TwitchCheerEvent_Enabled { get; private set; } public static ConfigEntry<bool> TwitchCheerEvent_EnableBitsForRandomEnemy { get; private set; } public static ConfigEntry<int> TwitchCheerEvent_BitsForRandomEnemy { get; private set; } public static ConfigEntry<bool> TwitchRaidEvent_Enabled { get; private set; } public static ConfigEntry<int> TwitchRaidEvent_ViewersPerRandomEnemy { get; private set; } public static ConfigEntry<int> TwitchRaidEvent_MaxEnemySpawnCount { get; private set; } public static ConfigEntry<bool> Enemy_Enabled { get; private set; } public static ConfigEntry<bool> Enemy_SpawnDespawned { get; private set; } public static ConfigEntry<float> Enemy_MinSpawnDistance { get; private set; } public static ConfigEntry<float> Enemy_MaxSpawnDistance { get; private set; } public static ConfigEntry<bool> Event_Enabled { get; private set; } public static ConfigEntry<bool> Event_EnableBitsForRandomEvent { get; private set; } public static ConfigEntry<int> Event_BitsForRandomEvent { get; private set; } public static ConfigEntry<bool> Message_Enabled { get; private set; } public static ConfigEntry<float> Message_Duration { get; private set; } public static ConfigEntry<int> Message_FontSize { get; private set; } public static ConfigEntry<int> Message_BackgroundTransparency { get; private set; } public static ConfigEntry<bool> DeathMessage_Enabled { get; private set; } public static ConfigEntry<bool> DeathMessage_ShowPlatformIcon { get; private set; } public static ConfigEntry<float> DeathMessage_Duration { get; private set; } public static ConfigEntry<int> DeathMessage_FontSize { get; private set; } public static ConfigEntry<int> DeathMessage_BackgroundTransparency { get; private set; } public static ConfigEntry<bool> EnemyNametag_Enabled { get; private set; } public static ConfigEntry<bool> EnemyNametag_ShowPlatformIcon { get; private set; } public static ConfigEntry<float> EnemyNametag_SizeMultiplier { get; private set; } public static ConfigEntry<int> EnemyNametag_BackgroundTransparency { get; private set; } public static void Initialize(ConfigFile configFile) { ConfigFile = configFile; BindConfigs(); MigrateOldConfigEntries(); ForceEnableEnemies(); } private static void BindConfigs() { ExtendedLogging = ConfigFile.Bind<bool>("- General -", "ExtendedLogging", false, "Enable extended logging."); TwitchIntegration_Enabled = ConfigFile.Bind<bool>("- Twitch Integration -", "Enabled", true, "If enabled, Twitch integration will be enabled to spawn enemies from Subs, Cheers, and Raids."); TwitchIntegration_Enabled.SettingChanged += delegate { PageManager.UpdatePage(); }; TwitchSubEvent_Enabled = ConfigFile.Bind<bool>("- Twitch Sub Event -", "Enabled", true, "If enabled, Twitch subs will be able to spawn enemies."); TwitchSubEvent_Tier1EnemySpawnCountMultiplier = ConfigFile.Bind("- Twitch Sub Event -", "Tier1EnemySpawnCountMultiplier", 1, "The amount to multiply the enemy spawn count for tier 1 subs.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 30)); TwitchSubEvent_Tier2EnemySpawnCountMultiplier = ConfigFile.Bind("- Twitch Sub Event -", "Tier2EnemySpawnCountMultiplier", 5, "The amount to multiply the enemy spawn count for tier 2 subs.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 30)); TwitchSubEvent_Tier3EnemySpawnCountMultiplier = ConfigFile.Bind("- Twitch Sub Event -", "Tier3EnemySpawnCountMultiplier", 10, "The amount to multiply the enemy spawn count for tier 3 subs.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 30)); TwitchSubEvent_Enabled.SettingChanged += delegate { PageManager.UpdatePage(); }; TwitchSubEvent_Tier1EnemySpawnCountMultiplier.SettingChanged += delegate { PageManager.UpdatePage(); }; TwitchSubEvent_Tier2EnemySpawnCountMultiplier.SettingChanged += delegate { PageManager.UpdatePage(); }; TwitchSubEvent_Tier3EnemySpawnCountMultiplier.SettingChanged += delegate { PageManager.UpdatePage(); }; TwitchCheerEvent_Enabled = ConfigFile.Bind<bool>("- Twitch Cheer Event -", "Enabled", true, "If enabled, Twitch cheers will be able to spawn enemies."); TwitchCheerEvent_EnableBitsForRandomEnemy = ConfigFile.Bind<bool>("- Twitch Cheer Event -", "EnableBitsForRandomEnemy", true, "If enabled, viewers can spawn random enemies with bits."); TwitchCheerEvent_BitsForRandomEnemy = ConfigFile.Bind("- Twitch Cheer Event -", "BitsForRandomEnemy", 350, "The min amount of bits to spawn a random enemy.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000)); TwitchCheerEvent_Enabled.SettingChanged += delegate { PageManager.UpdatePage(); }; TwitchCheerEvent_EnableBitsForRandomEnemy.SettingChanged += delegate { PageManager.UpdatePage(); }; TwitchCheerEvent_BitsForRandomEnemy.SettingChanged += delegate { PageManager.UpdatePage(); }; TwitchRaidEvent_Enabled = ConfigFile.Bind<bool>("- Twitch Raid Event -", "Enabled", true, "If enabled, Twitch raids will be able to spawn enemies."); TwitchRaidEvent_ViewersPerRandomEnemy = ConfigFile.Bind("- Twitch Raid Event -", "ViewersPerRandomEnemy", 5, "The amount of viewers for each random enemy spawn.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100)); TwitchRaidEvent_MaxEnemySpawnCount = ConfigFile.Bind("- Twitch Raid Event -", "MaxEnemySpawnCount", 20, "The max amount of enemies that can spawn from a raid.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100)); Enemy_Enabled = ConfigFile.Bind<bool>("- Enemy -", "Enabled", true, "If enabled, Twitch events will be able to spawn enemies."); Enemy_SpawnDespawned = ConfigFile.Bind<bool>("- Enemy -", "SpawnDespawned", false, "If enabled, enemies will spawn despawned."); Enemy_MinSpawnDistance = ConfigFile.Bind("- Enemy -", "MinSpawnDistance", 25f, "The min distance an enemy can spawn from the local player. (meters)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f)); Enemy_MaxSpawnDistance = ConfigFile.Bind("- Enemy -", "MaxSpawnDistance", 300f, "The max distance an enemy can spawn from the local player. (meters)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 500f)); Enemy_Enabled.SettingChanged += delegate { PageManager.UpdatePage(); }; Event_Enabled = ConfigFile.Bind<bool>("- Event -", "Enabled", true, "If enabled, Twitch cheers will be able to trigger events."); Event_EnableBitsForRandomEvent = ConfigFile.Bind<bool>("- Event -", "EnableBitsForRandomEvent", true, "If enabled, viewers can trigger random events with bits."); Event_BitsForRandomEvent = ConfigFile.Bind("- Event -", "BitsForRandomEvent", 150, "The amount of bits to trigger a random event.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000)); Event_Enabled.SettingChanged += delegate { PageManager.UpdatePage(); }; Event_EnableBitsForRandomEvent.SettingChanged += delegate { PageManager.UpdatePage(); }; Event_BitsForRandomEvent.SettingChanged += delegate { PageManager.UpdatePage(); }; Message_Enabled = ConfigFile.Bind<bool>("- Message -", "Enabled", true, "If enabled, will show messages in the bottom right."); Message_Duration = ConfigFile.Bind("- Message -", "Duration", 10f, "The duration of a message. (seconds)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f)); Message_FontSize = ConfigFile.Bind("- Message -", "FontSize", 12, "The font size of the messages.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 50)); Message_BackgroundTransparency = ConfigFile.Bind("- Message -", "BackgroundTransparency", 192, "The transparency of the message background.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 255)); Message_FontSize.SettingChanged += delegate { MessageItem.OnConfigSettingsChanged(); }; Message_BackgroundTransparency.SettingChanged += delegate { MessageItem.OnConfigSettingsChanged(); }; DeathMessage_Enabled = ConfigFile.Bind<bool>("- Death Message -", "Enabled", true, "If enabled, will show a message when you die to an enemy spawned from a viewer."); DeathMessage_ShowPlatformIcon = ConfigFile.Bind<bool>("- Death Message -", "ShowPlatformIcon", true, "If enabled, will show which platform the enemy was spawned from."); DeathMessage_Duration = ConfigFile.Bind("- Death Message -", "Duration", 8f, "The duration of the death message. (seconds)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f)); DeathMessage_FontSize = ConfigFile.Bind("- Death Message -", "FontSize", 16, "The font size of the death message.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 50)); DeathMessage_BackgroundTransparency = ConfigFile.Bind("- Death Message -", "BackgroundTransparency", 192, "The transparency of the death message background.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 255)); EnemyNametag_Enabled = ConfigFile.Bind<bool>("- Enemy Nametag -", "Enabled", true, "If enabled, enemies will spawn with a nametag of the viewer that spawned that enemy."); EnemyNametag_ShowPlatformIcon = ConfigFile.Bind<bool>("- Enemy Nametag -", "ShowPlatformIcon", true, "If enabled, nametags will show which platform the enemy was spawned from."); EnemyNametag_SizeMultiplier = ConfigFile.Bind("- Enemy Nametag -", "SizeMultiplier", 0.75f, "The size multiplier for enemy nametags.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 5f)); EnemyNametag_BackgroundTransparency = ConfigFile.Bind("- Enemy Nametag -", "BackgroundTransparency", 192, "The transparency of the nametag background.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 255)); EnemyNametag_ShowPlatformIcon.SettingChanged += delegate { EnemyNametag.OnConfigSettingsChanged(); }; EnemyNametag_SizeMultiplier.SettingChanged += delegate { EnemyNametag.OnConfigSettingsChanged(); }; EnemyNametag_BackgroundTransparency.SettingChanged += delegate { EnemyNametag.OnConfigSettingsChanged(); }; } private static void MigrateOldConfigEntries() { Dictionary<ConfigDefinition, string> dictionary = new Dictionary<ConfigDefinition, string>(ConfigFile.GetOrphanedConfigEntries()); foreach (KeyValuePair<ConfigDefinition, string> item in dictionary) { MigrateOldConfigEntry(item.Key, item.Value); } } private static void MigrateOldConfigEntry(ConfigDefinition configDefinition, string value) { string section = configDefinition.Section; string key = configDefinition.Key; StringComparison comparisonType = StringComparison.OrdinalIgnoreCase; if (section.Equals("- Twitch Cheer Event -", comparisonType)) { if (key.Equals("MinAmountForRandomEnemy", comparisonType)) { ConfigFile.MigrateConfigEntry<int>(configDefinition, value, TwitchCheerEvent_BitsForRandomEnemy); } } else if (section.Equals("- Event -", comparisonType)) { if (key.Equals("AmountForRandomEvent", comparisonType)) { ConfigFile.MigrateConfigEntry<int>(configDefinition, value, Event_BitsForRandomEvent); } } else { ConfigFile.Save(); } } private static void ForceEnableEnemies() { string key = "ForceEnabledEnemies"; if (!Plugin.LocalSave.Load(key, defaultValue: false)) { Plugin.LocalSave.Save(key, value: true); Enemy_Enabled.Value = true; } } } internal static class EnemyConfigManager { public static ConfigFile ConfigFile => ConfigManager.ConfigFile; public static List<EnemyConfigEntry> ConfigEntries { get; private set; } = new List<EnemyConfigEntry>(); public static List<EnemyConfigEntry> EnabledConfigEntries => ConfigEntries.Where((EnemyConfigEntry x) => x.Enabled.Value).ToList(); public static void Initialize() { EnemyConfigEntryDefaultValues[] list = Assets.EnemyConfigEntryDefaultValuesList.List; foreach (EnemyConfigEntryDefaultValues defaultValues in list) { RegisterConfigEntry(defaultValues); } EnemyParent val = default(EnemyParent); foreach (EnemySetup allEnemy in Enemies.AllEnemies) { if (EnemySetupExtensions.TryGetEnemyParent(allEnemy, ref val)) { RegisterConfigEntry(val.enemyName); } } } public static void RegisterConfigEntry(string enemyName) { if (!HasConfigEntry(enemyName)) { EnemyConfigEntry item = new EnemyConfigEntry(enemyName); ConfigEntries.Add(item); } } public static void RegisterConfigEntry(EnemyConfigEntryDefaultValues defaultValues) { if (!HasConfigEntry(defaultValues.EnemyName)) { EnemyConfigEntry item = new EnemyConfigEntry(defaultValues); ConfigEntries.Add(item); } } public static bool HasEnemies() { return EnabledConfigEntries.Count > 0; } public static bool HasConfigEntry(string enemyName) { return ConfigEntries.Any((EnemyConfigEntry x) => x.EnemyNameEquals(enemyName)); } public static EnemyConfigEntry GetConfigEntry(string enemyName) { return ConfigEntries.FirstOrDefault((EnemyConfigEntry x) => x.EnemyNameEquals(enemyName)); } public static bool TryGetConfigEntry(string enemyName, out EnemyConfigEntry configEntry) { configEntry = GetConfigEntry(enemyName); return configEntry != null; } public static List<EnemyConfigEntry> GetConfigEntriesThatMatchBitsAmount(int bitsAmount, bool includeDisable = false) { List<EnemyConfigEntry> list = new List<EnemyConfigEntry>(); foreach (EnemyConfigEntry configEntry in ConfigEntries) { if ((includeDisable || configEntry.Enabled.Value) && configEntry.BitsToSpawn.Value == bitsAmount) { list.Add(configEntry); } } return list; } public static bool TryGetConfigEntriesThatMatchBitsAmount(int bitsAmount, out List<EnemyConfigEntry> list, bool includeDisable = false) { list = GetConfigEntriesThatMatchBitsAmount(bitsAmount, includeDisable); return list.Any(); } public static List<EnemyConfigEntry> GetConfigEntriesThatMatchSubsAmount(int subsAmount, bool includeDisable = false) { List<EnemyConfigEntry> list = new List<EnemyConfigEntry>(); foreach (EnemyConfigEntry configEntry in ConfigEntries) { if ((includeDisable || configEntry.Enabled.Value) && configEntry.SubsToSpawn.Value == subsAmount) { list.Add(configEntry); } } return list; } public static bool TryGetConfigEntriesThatMatchSubsAmount(int subsAmount, out List<EnemyConfigEntry> list, bool includeDisable = false) { list = GetConfigEntriesThatMatchSubsAmount(subsAmount, includeDisable); return list.Any(); } } internal static class EnemyManager { private static AudioPlayerFactory _audioPlayerFactory; public static Dictionary<EnemyParent, ViewerData> ViewerEnemies { get; private set; } public static bool SpawnDespawned => ConfigManager.Enemy_SpawnDespawned.Value; public static float MinSpawnDistance => ConfigManager.Enemy_MinSpawnDistance.Value; public static float MaxSpawnDistance => ConfigManager.Enemy_MaxSpawnDistance.Value; static EnemyManager() { ViewerEnemies = new Dictionary<EnemyParent, ViewerData>(); _audioPlayerFactory = new AudioPlayerFactory { Type = AudioPlayerType.EnemySpawn, MaxDistance = 30f }; } public static void ResetViewerEnemies() { ViewerEnemies.Clear(); } public static void SpawnEnemy(ViewerSpawnData viewerSpawnData) { if (viewerSpawnData == null) { Logger.LogError("EnemyManager: Failed to spawn enemies. ViewerSpawnData is null.", extended: false, showMessage: true); return; } if (!CanSpawnEnemies()) { Logger.LogError("EnemyManager: Failed to spawn enemies. You are not allowed to spawn enemies at this time.", extended: false, showMessage: true); return; } List<EnemyConfigEntry> entries = new List<EnemyConfigEntry>(); for (int i = 0; i < viewerSpawnData.SpawnCount; i++) { if (EnemyConfigManager.TryGetConfigEntry(viewerSpawnData.TargetEnemyName, out var configEntry)) { entries.Add(configEntry); } else { entries.Add(EnemyConfigManager.ConfigEntries.GetRandom()); } } if (entries.Count < 1) { Logger.LogError("EnemyManager: Failed to spawn enemies. No enemies where found to spawn.", extended: false, showMessage: true); return; } if (entries.All((EnemyConfigEntry x) => x == entries[0])) { viewerSpawnData.SetTargetEnemyName(entries[0].EnemyName); } int num = entries.Sum((EnemyConfigEntry x) => x.SpawnCount.Value); viewerSpawnData.SetTotalSpawnCount(num); if (num < 1) { Logger.LogError("EnemyManager: Failed to spawn enemies. Total spawn count is less than 1.", extended: false, showMessage: true); return; } foreach (EnemyConfigEntry item in entries) { SpawnEnemy(item, viewerSpawnData.Viewer); } MessageManager.Instance?.ShowSpawnEnemyMessage(viewerSpawnData); Logger.LogInfo($"\n\n{viewerSpawnData.Viewer.DisplayName} spawned {num}x enemies {viewerSpawnData.SpawnReason}\n", extended: true); } private static void SpawnEnemy(EnemyConfigEntry configEntry, ViewerData viewerData) { if (configEntry == null) { Logger.LogError("EnemyManager: Failed to spawn enemies. EnemyConfigEntry is null.", extended: false, showMessage: true); return; } if (viewerData == null) { Logger.LogError("EnemyManager: Failed to spawn enemies. ViewerData is null.", extended: false, showMessage: true); return; } string enemyName = configEntry.EnemyName; int value = configEntry.SpawnCount.Value; if (value < 1) { Logger.LogError("EnemyManager: Failed to spawn enemy \"" + enemyName + "\". Spawn count is less than 1.", extended: false, showMessage: true); return; } EnemySetup enemySetup = default(EnemySetup); if (!Enemies.TryGetEnemyByName(enemyName, ref enemySetup)) { Logger.LogError("EnemyManager: Failed to spawn enemy \"" + enemyName + "\". EnemySetup is null.", extended: false, showMessage: true); return; } for (int i = 0; i < value; i++) { SpawnEnemy(enemySetup, viewerData); } } private static void SpawnEnemy(EnemySetup enemySetup, ViewerData viewerData) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)enemySetup == (Object)null) { Logger.LogError("EnemyManager: Failed to spawn enemies. EnemySetup is null.", extended: false, showMessage: true); return; } if (viewerData == null) { Logger.LogError("EnemyManager: Failed to spawn enemies. ViewerData is null.", extended: false, showMessage: true); return; } EnemyParent val = default(EnemyParent); if (!EnemySetupExtensions.TryGetEnemyParent(enemySetup, ref val)) { Logger.LogError("EnemyManager: Failed to spawn enemy. EnemyParent is null.", extended: false, showMessage: true); return; } Vector3 randomSpawnPosition = GetRandomSpawnPosition(); List<EnemyParent> list = Enemies.SpawnEnemy(enemySetup, randomSpawnPosition, Quaternion.identity, SpawnDespawned); PlayerAvatar localPlayer = PlayerHelper.GetLocalPlayer(); EnemyNametag enemyNametag = default(EnemyNametag); foreach (EnemyParent item in list) { ViewerEnemies.Add(item, viewerData); ParticleScriptExplosion[] componentsInChildren = ((Component)item).GetComponentsInChildren<ParticleScriptExplosion>(true); foreach (ParticleScriptExplosion component in componentsInChildren) { ((Component)(object)component).SetViewerMetadata(viewerData); } GameObject val2 = Object.Instantiate<GameObject>(Assets.EnemyNametagWorldCanvasPrefab); if (val2.TryGetComponent<EnemyNametag>(ref enemyNametag)) { enemyNametag.SetData(item, viewerData); } AudioClip spawnSFX = Assets.EnemySpawnSFXList.GetSpawnSFX(item.enemyName); _audioPlayerFactory?.Play(spawnSFX, ((Component)item).transform.position); if ((Object)(object)localPlayer != (Object)null) { float num = Vector3.Distance(((Component)item).transform.position, ((Component)localPlayer).transform.position); Logger.LogInfo($"Spawned \"{item.enemyName}\" {num} meters away from you.", extended: true); } } } private static Vector3 GetRandomSpawnPosition() { //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_0019: 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_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)LevelGenerator.Instance == (Object)null) { Logger.LogError("EnemyManager: Failed to get valid spawn position. LevelGenerator instance is null.", extended: false, showMessage: true); return Vector3.zero; } Vector3 val = Vector3.zero; float minSpawnDistance = MinSpawnDistance; float maxSpawnDistance = MaxSpawnDistance; if (PlayerHelper.TryGetLocalPlayer(out var playerAvatar)) { val = ((Component)playerAvatar).transform.position; } LevelPoint val2 = SemiFunc.LevelPointGet(val, minSpawnDistance, maxSpawnDistance); if ((Object)(object)val2 == (Object)null) { val2 = SemiFunc.LevelPointGet(val, Mathf.Min(minSpawnDistance, 25f), float.MaxValue); if ((Object)(object)val2 == (Object)null) { return val; } } return ((Component)val2).transform.position; } public static bool CanSpawnEnemies() { if (!SemiFunc.IsMasterClientOrSingleplayer()) { return false; } if (!LevelHelper.CurrentLevelHasEnemies()) { return false; } if (!PlayerHelper.IsLocalPlayerAlive()) { return false; } return true; } public static ViewerData GetViewerData(EnemyParent enemyParent) { if ((Object)(object)enemyParent == (Object)null) { return null; } if (ViewerEnemies.TryGetValue(enemyParent, out var value)) { return value; } return null; } public static bool TryGetViewerData(EnemyParent enemyParent, out ViewerData viewerData) { viewerData = GetViewerData(enemyParent); return viewerData != 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_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) float num = 22f; float num2 = 0f; float num3 = 35f; num2 += num3; if (SpawnManagerProxy.Enabled) { num2 += num3; } 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(); } } internal static class PageManager { internal enum TwitchChannelStatus { None, Accepted, NotLive, NotAffiliateOrPartner, Banned, FailedToCheck } [CompilerGenerated] private sealed class <CheckPageStatusCoroutine>d__27 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; private UnityWebRequest <request>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <CheckPageStatusCoroutine>d__27(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <request>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Invalid comparison between Unknown and I4 //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Invalid comparison between Unknown and I4 bool result; try { switch (<>1__state) { default: result = false; break; case 0: { <>1__state = -1; string pageId = GetPageId(); string pageAccessToken = GetPageAccessToken(); if (string.IsNullOrEmpty(pageId) || string.IsNullOrEmpty(pageAccessToken)) { HasPage = false; PageManager.OnPageStatusChanged?.Invoke(); result = false; break; } string text = "https://twitchtrolling.up.railway.app/api/pages/" + pageId; <request>5__2 = UnityWebRequest.Get(text); <>1__state = -3; <>2__current = <request>5__2.SendWebRequest(); <>1__state = 1; result = true; break; } case 1: <>1__state = -3; if ((int)<request>5__2.result == 3 && <request>5__2.responseCode == 404) { Logger.LogWarning("Page not found (404). Clearing saved page ID and access token."); SavePageId(string.Empty); SavePageAccessToken(string.Empty); HasPage = false; PageManager.OnPageStatusChanged?.Invoke(); result = false; } else if ((int)<request>5__2.result != 1) { Logger.LogWarning("Page status check failed: " + <request>5__2.error); HasPage = false; PageManager.OnPageStatusChanged?.Invoke(); result = false; } else { HasPage = true; PageManager.OnPageStatusChanged?.Invoke(); result = false; } <>m__Finally1(); break; } } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<request>5__2 != null) { ((IDisposable)<request>5__2).Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <CreatePageCoroutine>d__28 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; private UnityWebRequest <request>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <CreatePageCoroutine>d__28(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <request>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Invalid comparison between Unknown and I4 bool result; try { switch (<>1__state) { default: result = false; break; case 0: { <>1__state = -1; if (!IsCreatePageEnabled(out var reason)) { Logger.LogError("You are unable to create a page: " + reason); result = false; break; } string text4 = "https://twitchtrolling.up.railway.app/api/pages"; string s = JsonConvert.SerializeObject((object)GetDataForPage()); <request>5__2 = new UnityWebRequest(text4, "POST"); <>1__state = -3; byte[] bytes = Encoding.UTF8.GetBytes(s); <request>5__2.uploadHandler = (UploadHandler)new UploadHandlerRaw(bytes); <request>5__2.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer(); <request>5__2.SetRequestHeader("Content-Type", "application/json"); <request>5__2.SetRequestHeader("Authorization", "Bearer d74c6ba6-4584-4969-8af9-066549673563"); <>2__current = <request>5__2.SendWebRequest(); <>1__state = 1; result = true; break; } case 1: { <>1__state = -3; if ((int)<request>5__2.result != 1) { Logger.LogError("Failed to create page: " + <request>5__2.error); PageManager.OnPageStatusChanged?.Invoke(); result = false; } else { string text = <request>5__2.downloadHandler.text; JObject val; try { val = JObject.Parse(text); } catch (Exception ex) { Logger.LogError("Failed to parse create page response: " + ex.Message); PageManager.OnPageStatusChanged?.Invoke(); result = false; goto IL_0213; } string text2 = ((object)val["id"])?.ToString(); string text3 = ((object)val["accessToken"])?.ToString(); if (string.IsNullOrEmpty(text2) || string.IsNullOrEmpty(text3)) { Logger.LogError("Create page response missing required fields."); PageManager.OnPageStatusChanged?.Invoke(); result = false; } else { SavePageId(text2); SavePageAccessToken(text3); HasPage = true; _updatePageDataFirstTime = true; PageManager.OnPageCreated?.Invoke(PageURL); result = false; } } goto IL_0213; } IL_0213: <>m__Finally1(); break; } } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<request>5__2 != null) { ((IDisposable)<request>5__2).Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <UpdatePageCoroutine>d__29 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public TimeSpan delay; private UnityWebRequest <request>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <UpdatePageCoroutine>d__29(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 2) { try { } finally { <>m__Finally1(); } } <request>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Invalid comparison between Unknown and I4 //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected O, but got Unknown //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Expected O, but got Unknown bool result; try { switch (<>1__state) { default: result = false; break; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds((float)delay.TotalSeconds); <>1__state = 1; result = true; break; case 1: { <>1__state = -1; string pageId = GetPageId(); string pageAccessToken = GetPageAccessToken(); if (string.IsNullOrEmpty(pageId) || string.IsNullOrEmpty(pageAccessToken)) { Logger.LogWarning("UpdatePage: Missing Page ID or Access Token."); result = false; break; } string text = "https://twitchtrolling.up.railway.app/api/pages/" + pageId; string s = JsonConvert.SerializeObject((object)GetDataForPage()); <request>5__2 = new UnityWebRequest(text, "PUT"); <>1__state = -3; byte[] bytes = Encoding.UTF8.GetBytes(s); <request>5__2.uploadHandler = (UploadHandler)new UploadHandlerRaw(bytes); <request>5__2.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer(); <request>5__2.SetRequestHeader("Content-Type", "application/json"); <request>5__2.SetRequestHeader("Authorization", "Bearer " + pageAccessToken); <>2__current = <request>5__2.SendWebRequest(); <>1__state = 2; result = true; break; } case 2: <>1__state = -3; if ((int)<request>5__2.result != 1) { Logger.LogError("Failed to update page: " + <request>5__2.error); result = false; } else { Logger.LogInfo("Page updated successfully.", extended: true); result = false; } <>m__Finally1(); break; } } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<request>5__2 != null) { ((IDisposable)<request>5__2).Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <VerifyTwitchChannelCoroutine>d__41 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; private UnityWebRequest <request>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <VerifyTwitchChannelCoroutine>d__41(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <request>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Invalid comparison between Unknown and I4 //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Invalid comparison between Unknown and I4 //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Expected O, but got Unknown //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Invalid comparison between Unknown and I4 bool result; try { JObject val2; switch (<>1__state) { default: result = false; break; case 0: { <>1__state = -1; _twitchChannelStatus = TwitchChannelStatus.None; if ((int)API.ConnectionState != 2) { PageManager.OnPageStatusChanged?.Invoke(); result = false; break; } string channel = API.Channel; if (channel.Equals("CritHaxXoG", StringComparison.OrdinalIgnoreCase)) { _twitchChannelStatus = TwitchChannelStatus.Accepted; PageManager.OnPageStatusChanged?.Invoke(); result = false; break; } string text2 = "https://api.ivr.fi/v2/twitch/user?login=" + channel; <request>5__2 = UnityWebRequest.Get(text2); <>1__state = -3; <request>5__2.SetRequestHeader("User-Agent", "TwitchTrolling/1.4.2"); <>2__current = <request>5__2.SendWebRequest(); <>1__state = 1; result = true; break; } case 1: { <>1__state = -3; if ((int)<request>5__2.result != 1) { Logger.LogError("VerifyTwitchChannel: Failed to verify Twitch channel."); _twitchChannelStatus = TwitchChannelStatus.FailedToCheck; PageManager.OnPageStatusChanged?.Invoke(); result = false; } else { string text = <request>5__2.downloadHandler.text; try { JArray val = JArray.Parse(text); if (((JContainer)val).Count != 0) { val2 = (JObject)val[0]; goto IL_019c; } Logger.LogWarning("VerifyTwitchChannel: No user found with the specified login."); _twitchChannelStatus = TwitchChannelStatus.FailedToCheck; PageManager.OnPageStatusChanged?.Invoke(); result = false; } catch (Exception ex) { Logger.LogError("VerifyTwitchChannel: Failed to parse Twitch user response: " + ex.Message); _twitchChannelStatus = TwitchChannelStatus.FailedToCheck; PageManager.OnPageStatusChanged?.Invoke(); result = false; } } goto IL_0283; } IL_019c: if (((JToken)val2).Value<bool>((object)"banned")) { _twitchChannelStatus = TwitchChannelStatus.Banned; PageManager.OnPageStatusChanged?.Invoke(); result = false; } else { JObject val3 = (JObject)(((object)((JToken)val2).Value<JObject>((object)"roles")) ?? ((object)new JObject())); bool valueOrDefault = ((JToken)val3).Value<bool?>((object)"isAffiliate").GetValueOrDefault(); bool valueOrDefault2 = ((JToken)val3).Value<bool?>((object)"isPartner").GetValueOrDefault(); if (!valueOrDefault && !valueOrDefault2) { _twitchChannelStatus = TwitchChannelStatus.NotAffiliateOrPartner; PageManager.OnPageStatusChanged?.Invoke(); result = false; } else if (val2["stream"] == null || (int)val2["stream"].Type == 10) { _twitchChannelStatus = TwitchChannelStatus.NotLive; PageManager.OnPageStatusChanged?.Invoke(); result = false; } else { _twitchChannelStatus = TwitchChannelStatus.Accepted; PageManager.OnPageStatusChanged?.Invoke(); result = false; } } goto IL_0283; IL_0283: <>m__Finally1(); break; } } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<request>5__2 != null) { ((IDisposable)<request>5__2).Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private const string _apiOrigin = "https://twitchtrolling.up.railway.app"; private const string _createPageToken = "d74c6ba6-4584-4969-8af9-066549673563"; private static bool _updatePageDataFirstTime; private static float _lastUpdatePageTime = float.NegativeInfinity; private const float _updatePageCooldown = 0.1f; private static string _previousChannel; private static TwitchChannelStatus _twitchChannelStatus; public static bool HasPage { get; private set; } public static string PageId => GetPageId(); public static string PageURL { get { if (!HasPage) { return string.Empty; } return "https://twitchtrolling.com/page?id=" + PageId; } } public static event Action OnPageStatusChanged; public static event Action<string> OnPageCreated; public static void Initialize() { API.OnConnect += HandleTwitchOnConnect; Application.quitting += delegate { API.OnConnect -= HandleTwitchOnConnect; }; _previousChannel = API.Channel; CheckPageStatus(); VerifyTwitchChannel(); } public static void CheckPageStatus() { PluginManager instance = PluginManager.Instance; if (instance != null) { ((MonoBehaviour)instance).StartCoroutine(CheckPageStatusCoroutine()); } } public static void CreatePage() { PluginManager instance = PluginManager.Instance; if (instance != null) { ((MonoBehaviour)instance).StartCoroutine(CreatePageCoroutine()); } } public static void UpdatePage() { if (HasPage) { float num = 0.1f; float realtimeSinceStartup = Time.realtimeSinceStartup; if (!(realtimeSinceStartup - _lastUpdatePageTime < num)) { _lastUpdatePageTime = realtimeSinceStartup; ((MonoBehaviour)PluginManager.Instance).StartCoroutine(UpdatePageCoroutine(TimeSpan.FromSeconds(num))); } } } public static void UpdatePageFirstTime() { if (!_updatePageDataFirstTime) { _updatePageDataFirstTime = true; UpdatePage(); } } [IteratorStateMachine(typeof(<CheckPageStatusCoroutine>d__27))] private static IEnumerator CheckPageStatusCoroutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <CheckPageStatusCoroutine>d__27(0); } [IteratorStateMachine(typeof(<CreatePageCoroutine>d__28))] private static IEnumerator CreatePageCoroutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <CreatePageCoroutine>d__28(0); } [IteratorStateMachine(typeof(<UpdatePageCoroutine>d__29))] private static IEnumerator UpdatePageCoroutine(TimeSpan delay) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <UpdatePageCoroutine>d__29(0) { delay = delay }; } private static JObject GetDataForPage() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown JObject val = new JObject { ["channel"] = JToken.op_Implicit(API.Channel), ["enemies"] = (JToken)(object)GetEnemyDataForPage(), ["events"] = (JToken)(object)GetEventDataForPage() }; if (ConfigManager.TwitchSubEvent_Enabled.Value) { val.Add("subEnemySpawnCountMultipliers", (JToken)(object)GetSubEnemySpawnCountMultipliers()); } return val; } private static JObject GetSubEnemySpawnCountMultipliers() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_001f: 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_0054: Expected O, but got Unknown return new JObject { ["tier1"] = JToken.op_Implicit(ConfigManager.TwitchSubEvent_Tier1EnemySpawnCountMultiplier.Value), ["tier2"] = JToken.op_Implicit(ConfigManager.TwitchSubEvent_Tier2EnemySpawnCountMultiplier.Value), ["tier3"] = JToken.op_Implicit(ConfigManager.TwitchSubEvent_Tier3EnemySpawnCountMultiplier.Value) }; } private static JArray GetEnemyDataForPage() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown JArray val = new JArray(); if (!TwitchIntegrationManager.IsEnabled || !TwitchIntegrationManager.IsCheerEventEnabled) { return val; } if (!ConfigManager.Enemy_Enabled.Value) { return val; } if (ConfigManager.TwitchCheerEvent_EnableBitsForRandomEnemy.Value && EnemyConfigManager.EnabledConfigEntries.Count > 1) { JObject val2 = new JObject { ["name"] = JToken.op_Implicit("Random Enemy"), ["price"] = JToken.op_Implicit(ConfigManager.TwitchCheerEvent_BitsForRandomEnemy.Value) }; val.Add((JToken)(object)val2); } foreach (EnemyConfigEntry configEntry in EnemyConfigManager.ConfigEntries) { if (configEntry.Enabled.Value) { val.Add((JToken)(object)configEntry.GetCardJSON()); } } return val; } private static JArray GetEventDataForPage() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown JArray val = new JArray(); if (!TwitchIntegrationManager.IsEnabled || !TwitchIntegrationManager.IsCheerEventEnabled) { return val; } if (!MEventManager.Enabled) { return val; } if (ConfigManager.Event_EnableBitsForRandomEvent.Value && MEventManager.EnabledEvents.Count > 1) { JObject val2 = new JObject { ["name"] = JToken.op_Implicit("Random Event"), ["price"] = JToken.op_Implicit(ConfigManager.Event_BitsForRandomEvent.Value) }; val.Add((JToken)(object)val2); } foreach (MEvent @event in MEventManager.Events) { if (@event.Enabled.Value) { val.Add((JToken)(object)@event.GetCardJSON()); } } return val; } private static string GetPageId() { return Plugin.GlobalSave.Load("PageId", string.Empty); } private static string GetPageAccessToken() { return Plugin.GlobalSave.Load("PageAccessToken", string.Empty); } private static void SavePageId(string pageId) { Plugin.GlobalSave.Save("PageId", pageId); } private static void SavePageAccessToken(string accessToken) { Plugin.GlobalSave.Save("PageAccessToken", accessToken); } private static void HandleTwitchOnConnect() { string channel = API.Channel; if (!(_previousChannel == channel)) { _previousChannel = channel; VerifyTwitchChannel(); UpdatePage(); } } public static bool IsCreatePageEnabled(out string reason) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 reason = string.Empty; if ((int)API.ConnectionState != 2) { reason = "You are not connected to Twitch!"; return false; } if (_twitchChannelStatus == TwitchChannelStatus.None) { reason = "Your Twitch channel does not meet the requirements!"; return false; } if (_twitchChannelStatus == TwitchChannelStatus.NotLive) { reason = "You are not live!"; return false; } if (_twitchChannelStatus == TwitchChannelStatus.NotAffiliateOrPartner) { reason = "Your Twitch channel is not affiliate or partner!"; return false; } if (_twitchChannelStatus == TwitchChannelStatus.Banned) { reason = "Your Twitch channel is banned!"; return false; } return true; } public static void VerifyTwitchChannel() { PluginManager instance = PluginManager.Instance; if (instance != null) { ((MonoBehaviour)instance).StartCoroutine(VerifyTwitchChannelCoroutine()); } } [IteratorStateMachine(typeof(<VerifyTwitchChannelCoroutine>d__41))] private static IEnumerator VerifyTwitchChannelCoroutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <VerifyTwitchChannelCoroutine>d__41(0); } } [BepInPlugin("com.github.zehsteam.TwitchTrolling", "TwitchTrolling", "1.4.2")] [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(); } } 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.4.2"; } } 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 { [CommandExecution("Simulate Cheer", "Simulate Twitch cheers.", true, false)] [CommandAlias("simulatecheer")] [CommandAlias("simcheer")] [CommandAlias("scheer")] [CommandAlias("cheer")] public static void SimulateCheer(string args) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown int cheerAmount = ConfigManager.TwitchCheerEvent_BitsForRandomEnemy.Value; if (int.TryParse(args, out var result)) { cheerAmount = result; } TwitchCheerEvent cheerEvent = new TwitchCheerEvent { User = TwitchHelper.CreateTwitchUser(), CheerAmount = cheerAmount }; TwitchEventHandler.HandleCheer(cheerEvent); } } internal static class TwitchSimulateSubCommand { [CommandExecution("Simulate Sub", "Simulate Twitch subscriptions.", true, false)] [CommandAlias("simulatesub")] [CommandAlias("simsub")] [CommandAlias("ssub")] [CommandAlias("sub")] public static void SimulateSubs(string args) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown int giftCount = 1; if (int.TryParse(args, out var result)) { giftCount = result; } TwitchSubEvent subEvent = new TwitchSubEvent { User = TwitchHelper.CreateTwitchUser(), Type = (SubType)3, Tier = (SubTier)1, GiftCount = giftCount }; TwitchEventHandler.HandleSub(subEvent); } } } 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 refer