Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of TwitchTrolling v1.8.0
BepInEx/plugins/com.github.zehsteam.TwitchTrolling.dll
Decompiled a week ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using MenuLib; using MenuLib.MonoBehaviors; using MenuLib.Structs; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Photon.Pun; using REPOConfig; 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.Dependencies.MenuLibMod.MonoBehaviours; using com.github.zehsteam.TwitchTrolling.Dependencies.MenuLibMod.Patches; using com.github.zehsteam.TwitchTrolling.Dependencies.REPOConfigMod; using com.github.zehsteam.TwitchTrolling.Extensions; using com.github.zehsteam.TwitchTrolling.Helpers; using com.github.zehsteam.TwitchTrolling.MEvents; using com.github.zehsteam.TwitchTrolling.MEvents.BaseEvents; using com.github.zehsteam.TwitchTrolling.Managers; using com.github.zehsteam.TwitchTrolling.MonoBehaviours; using com.github.zehsteam.TwitchTrolling.Objects; using com.github.zehsteam.TwitchTrolling.Patches; using com.github.zehsteam.TwitchTrolling.Twitch; using com.github.zehsteam.TwitchTrolling.Twitch.Commands; using com.github.zehsteam.TwitchTrolling.Twitch.Commands.Objects; using com.github.zehsteam.TwitchTrolling.Twitch.Helpers; using com.github.zehsteam.TwitchTrolling.Twitch.Objects; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("MenuLib")] [assembly: IgnoresAccessChecksTo("REPOConfig")] [assembly: IgnoresAccessChecksTo("REPOLib")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Zehs")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © 2026 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.8.0.0")] [assembly: AssemblyInformationalVersion("1.8.0+b3be926623e8c892e615579b6dce64cb54bcc435")] [assembly: AssemblyProduct("TwitchTrolling")] [assembly: AssemblyTitle("com.github.zehsteam.TwitchTrolling")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.8.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace com.github.zehsteam.TwitchTrolling { internal static class Assets { public static GameObject PluginManagerPrefab { get; private set; } public static GameObject PluginHUDPrefab { get; private set; } public static GameObject EnemyNametagWorldCanvasPrefab { get; private set; } public static GameObject TruckPropsPrefab { get; private set; } public static GameObject AudioEnemySpawnPrefab { get; private set; } public static PrefabRef ModCreditsPrefabRef { get; private set; } public static EnemyConfigEntryDefaultValuesList EnemyConfigEntryDefaultValuesList { get; private set; } public static EnemySpawnSFXList EnemySpawnSFXList { get; private set; } public static MEventSFXList MEventSFXList { get; private set; } public static void Load() { string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); string text = "twitchtrolling_assets"; string text2 = Path.Combine(directoryName, text); if (!File.Exists(text2)) { Logger.LogFatal("Failed to load assets. AssetBundle file could not be found at path \"" + text2 + "\". Make sure the \"" + text + "\" file is in the same folder as the mod's DLL file."); } else { AssetBundle val = AssetBundle.LoadFromFile(text2); if ((Object)(object)val == (Object)null) { Logger.LogFatal("Failed to load assets. AssetBundle is null."); } else { OnAssetBundleLoaded(val); } } } private static void OnAssetBundleLoaded(AssetBundle assetBundle) { PluginManagerPrefab = LoadAsset<GameObject>("PluginManager", assetBundle); PluginHUDPrefab = LoadAsset<GameObject>("PluginHUD", assetBundle); EnemyNametagWorldCanvasPrefab = LoadAsset<GameObject>("EnemyNametagWorldCanvas", assetBundle); TruckPropsPrefab = LoadAsset<GameObject>("TruckProps", assetBundle); AudioEnemySpawnPrefab = LoadAsset<GameObject>("AudioEnemySpawn", assetBundle); Utilities.FixAudioMixerGroups(AudioEnemySpawnPrefab); ModCreditsPrefabRef = NetworkPrefabs.RegisterNetworkPrefab(LoadAsset<GameObject>("TwitchTrolling ModCredits", assetBundle)); EnemyConfigEntryDefaultValuesList = LoadAsset<EnemyConfigEntryDefaultValuesList>("EnemyConfigEntryDefaultValuesList", assetBundle); EnemySpawnSFXList = LoadAsset<EnemySpawnSFXList>("EnemySpawnSFXList", assetBundle); MEventSFXList = LoadAsset<MEventSFXList>("MEventSFXList", assetBundle); } private static T LoadAsset<T>(string name, AssetBundle assetBundle) where T : Object { if (string.IsNullOrWhiteSpace(name)) { Logger.LogError("Failed to load asset of type \"" + typeof(T).Name + "\" from AssetBundle. Name is null or whitespace."); return default(T); } if ((Object)(object)assetBundle == (Object)null) { Logger.LogError("Failed to load asset of type \"" + typeof(T).Name + "\" with name \"" + name + "\" from AssetBundle. AssetBundle is null."); return default(T); } T val = assetBundle.LoadAsset<T>(name); if ((Object)(object)val == (Object)null) { Logger.LogError("Failed to load asset of type \"" + typeof(T).Name + "\" with name \"" + name + "\" from AssetBundle. No asset found with that type and name."); return default(T); } return val; } private static bool TryLoadAsset<T>(string name, AssetBundle assetBundle, out T asset) where T : Object { asset = LoadAsset<T>(name, assetBundle); return (Object)(object)asset != (Object)null; } } internal static class Logger { public static ManualLogSource ManualLogSource { get; private set; } public static void Initialize(ManualLogSource manualLogSource) { ManualLogSource = manualLogSource; } public static void LogDebug(object data) { Log((LogLevel)32, data); } public static void LogInfo(object data, bool extended = false) { Log((LogLevel)16, data, extended); } public static void LogWarning(object data, bool extended = false) { Log((LogLevel)4, data, extended); } public static void LogError(object data, bool extended = false, bool showMessage = false) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) Log((LogLevel)2, data, extended); if (showMessage) { MessageManager.Instance?.ShowMessage(data.ToString(), Color.red); } } public static void LogFatal(object data, bool extended = false) { Log((LogLevel)1, data, extended); } public static void Log(LogLevel logLevel, object data, bool extended = false) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (!extended || IsExtendedLoggingEnabled()) { ManualLogSource manualLogSource = ManualLogSource; if (manualLogSource != null) { manualLogSource.Log(logLevel, data); } } } public static bool IsExtendedLoggingEnabled() { if (ConfigManager.ExtendedLogging == null) { return false; } return ConfigManager.ExtendedLogging.Value; } } internal static class Menu { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static BuilderDelegate <>9__6_0; public static BuilderDelegate <>9__6_1; public static BuilderDelegate <>9__6_2; public static Action <>9__6_3; internal void <Initialize>b__6_0(Transform parent) { CreateMainButtonForMainMenu(parent); } internal void <Initialize>b__6_1(Transform parent) { CreateMainButtonForLobbyAndEscapeMenu(parent); } internal void <Initialize>b__6_2(Transform parent) { CreateMainButtonForLobbyAndEscapeMenu(parent); } internal void <Initialize>b__6_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; private static REPOButton _settingsButton; 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__6_0; if (obj == null) { BuilderDelegate val = delegate(Transform parent) { CreateMainButtonForMainMenu(parent); }; <>c.<>9__6_0 = val; obj = (object)val; } MenuAPI.AddElementToMainMenu((BuilderDelegate)obj); object obj2 = <>c.<>9__6_1; if (obj2 == null) { BuilderDelegate val2 = delegate(Transform parent) { CreateMainButtonForLobbyAndEscapeMenu(parent); }; <>c.<>9__6_1 = val2; obj2 = (object)val2; } MenuAPI.AddElementToLobbyMenu((BuilderDelegate)obj2); object obj3 = <>c.<>9__6_2; if (obj3 == null) { BuilderDelegate val3 = delegate(Transform parent) { CreateMainButtonForLobbyAndEscapeMenu(parent); }; <>c.<>9__6_2 = val3; obj3 = (object)val3; } MenuAPI.AddElementToEscapeMenu((BuilderDelegate)obj3); PageManager.OnPageStatusChanged += HandlePageStatusChanged; PageManager.OnPageCreated += HandlePageCreated; Application.quitting += delegate { PageManager.OnPageStatusChanged -= HandlePageStatusChanged; PageManager.OnPageCreated -= HandlePageCreated; }; } private static REPOButton CreateMainButtonForMainMenu(Transform parent) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) float num = 35f; float num2 = 0f; if (SpawnManagerProxy.Enabled) { num2 += 55f; } return CreateMainButton(parent, Vector2.op_Implicit(new Vector2(550f, num + num2))); } private static REPOButton CreateMainButtonForLobbyAndEscapeMenu(Transform parent) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) float num = 0f; num += 145f; if (MoreHeadProxy.Enabled) { num += 100f; } return CreateMainButton(parent, Vector2.op_Implicit(new Vector2(num, 0f))); } private static REPOButton CreateMainButton(Transform parent, Vector3 localPosition) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) return MenuAPI.CreateREPOButton("Twitch Trolling", (Action)HandleMainButtonClick, parent, Vector2.op_Implicit(localPosition)); } private static void CreateMenu() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Expected O, but got Unknown //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Expected O, but got Unknown //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Expected O, but got Unknown //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Expected O, but got Unknown //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_011a: 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 -= 40f; _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) _settingsButton = MenuAPI.CreateREPOButton("Settings", (Action)HandleSettingsButtonClick, parent, Vector2.op_Implicit(new Vector3(xPosition, yPosition))); }); 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 HandleSettingsButtonClick() { HandleCloseButtonClick(); REPOConfigHelper.OpenSettingsMenu("TwitchTrolling"); } 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>"; ((TMP_Text)_pageUrlLabel.labelTMP).fontStyle = (FontStyles)1; 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!"; } ((TMP_Text)_pageUrlLabel.labelTMP).fontStyle = (FontStyles)17; } private static void HandlePageCreated(string pageUrl) { HandlePageStatusChanged(); } } [BepInPlugin("com.github.zehsteam.TwitchTrolling", "TwitchTrolling", "1.8.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] internal class Plugin : BaseUnityPlugin { private readonly Harmony _harmony = new Harmony("com.github.zehsteam.TwitchTrolling"); internal static Plugin Instance { get; private set; } internal static JsonSave GlobalSave { get; private set; } internal static JsonSave LocalSave { get; private set; } private void Awake() { Instance = this; Logger.Initialize(Logger.CreateLogSource("com.github.zehsteam.TwitchTrolling")); Logger.LogInfo("TwitchTrolling has awoken!"); _harmony.PatchAll(typeof(RunManagerPatch)); _harmony.PatchAll(typeof(LevelGeneratorPatch)); _harmony.PatchAll(typeof(EnemyDirectorPatch)); _harmony.PatchAll(typeof(HUDCanvasPatch)); _harmony.PatchAll(typeof(TruckScreenTextPatch)); _harmony.PatchAll(typeof(PlayerControllerPatch)); _harmony.PatchAll(typeof(ItemDronePatch)); _harmony.PatchAll(typeof(FanTrapPatch)); _harmony.PatchAll(typeof(ItemRubberDuckPatch)); _harmony.PatchAll(typeof(EnemyDuckPatch)); _harmony.PatchAll(typeof(REPOPopupPage_Patches)); GlobalSave = new JsonSave(Utils.GetPluginPersistentDataPath(), "GlobalSave"); LocalSave = new JsonSave(Paths.ConfigPath, "TwitchTrolling_Save.json"); Assets.Load(); CoroutineRunner.Spawn(); ConfigManager.Initialize(((BaseUnityPlugin)this).Config); PluginManager.Spawn(); TwitchIntegrationManager.Initialize(); Menu.Initialize(); PageManager.Initialize(); PlayerHelper.Initialize(); TwitchSimulateCheerCommand.Register(); TwitchSimulateSubCommand.Register(); } } internal static class Utils { [CompilerGenerated] private sealed class <InvokeAfterDurationCoroutine>d__5 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public TimeSpan duration; public Action action; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <InvokeAfterDurationCoroutine>d__5(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds((float)duration.TotalSeconds); <>1__state = 1; return true; case 1: <>1__state = -1; action?.Invoke(); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public static string GetPluginPersistentDataPath() { return Path.Combine(Application.persistentDataPath, "TwitchTrolling"); } public static ConfigFile CreateConfigFile(BaseUnityPlugin plugin, string path, string name = null, bool saveOnInit = false) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown BepInPlugin metadata = MetadataHelper.GetMetadata((object)plugin); if (name == null) { name = metadata.GUID; } name += ".cfg"; return new ConfigFile(Path.Combine(path, name), saveOnInit, metadata); } public static ConfigFile CreateLocalConfigFile(BaseUnityPlugin plugin, string name = null, bool saveOnInit = false) { return CreateConfigFile(plugin, Paths.ConfigPath, name, saveOnInit); } public static ConfigFile CreateGlobalConfigFile(BaseUnityPlugin plugin, string name = null, bool saveOnInit = false) { string pluginPersistentDataPath = GetPluginPersistentDataPath(); if (name == null) { name = "global"; } return CreateConfigFile(plugin, pluginPersistentDataPath, name, saveOnInit); } public static string GetTextWithReadableColor(string text, string hexColor, string backgroundHexColor = "#000000") { if (string.IsNullOrWhiteSpace(hexColor)) { hexColor = "#FFFFFF"; } if (string.IsNullOrWhiteSpace(backgroundHexColor)) { backgroundHexColor = "#000000"; } string readableColor = ColorHelper.GetReadableColor(hexColor, backgroundHexColor); return text.RichColor(readableColor); } [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.8.0"; } } namespace com.github.zehsteam.TwitchTrolling.Twitch { internal static class TwitchCheerHandler { public static bool IsEnemySpawnEnabled { get { if (ConfigManager.Enemy_Enabled.Value) { return EnemyConfigManager.HasEnemies(); } return false; } } public static bool IsEventSpawnEnabled { get { if (MEventManager.Enabled) { return MEventManager.HasEvents(); } return false; } } public static void HandleCheer(TwitchCheerEvent cheerEvent) { //IL_0034: 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 (!TwitchEventHandler.CanHandleEvents()) { TwitchEventHandler.ShowUnableToHandleEventsMessage(); return; } if (!TwitchIntegrationManager.CanPlayEvents()) { TwitchEventQueue.Enqueue(cheerEvent); return; } ViewerData viewerData = new ViewerData(((TwitchEvent)cheerEvent).User); int cheerAmount = cheerEvent.CheerAmount; if (!IsEnemySpawnEnabled && !IsEventSpawnEnabled) { MessageManager.Instance?.ShowMessage("Enemy and event spawns are disabled. " + GetAddingAccumulatedBitsMessage(viewerData, cheerAmount)); TwitchIntegrationManager.AddAccumulatedBits(viewerData, cheerAmount); return; } if (TryGetRandomProductForPrice(cheerAmount, out var product)) { switch (product.Type) { case ProductType.Enemy: HandleEnemySpawn(cheerEvent, viewerData, product.ToEnemyConfigEntry()); return; case ProductType.Event: HandleEventSpawn(cheerEvent, viewerData, product.ToMEvent()); return; case ProductType.RandomEnemy: HandleRandomEnemySpawn(cheerEvent, viewerData); return; case ProductType.RandomEvent: HandleRandomEventSpawn(cheerEvent, viewerData); return; } } if (!IsEnemySpawnEnabled) { MessageManager.Instance?.ShowMessage("Enemy spawns are disabled. " + GetAddingAccumulatedBitsMessage(viewerData, cheerAmount)); TwitchIntegrationManager.AddAccumulatedBits(viewerData, cheerAmount); return; } if (!ConfigManager.TwitchCheerEvent_EnableBitsForRandomEnemy.Value) { MessageManager.Instance?.ShowMessage("Random enemy spawns are disabled. " + GetAddingAccumulatedBitsMessage(viewerData, cheerAmount)); TwitchIntegrationManager.AddAccumulatedBits(viewerData, cheerAmount); return; } int accumulatedBits = TwitchIntegrationManager.GetAccumulatedBits(viewerData); int num = accumulatedBits + cheerAmount; int value = ConfigManager.TwitchCheerEvent_BitsForRandomEnemy.Value; if (num < value) { MessageManager.Instance?.ShowMessage(viewerData.GetDisplayNameWithColor() + " didn't cheer enough to spawn anything. " + GetAddingAccumulatedBitsMessage(viewerData, cheerAmount)); TwitchIntegrationManager.AddAccumulatedBits(viewerData, cheerAmount); return; } int spawnCount = Mathf.FloorToInt((float)(num / value)); int num2 = num % value; int accumulatedBitsUsedAmount = Mathf.Max(accumulatedBits - num2, 0); TwitchIntegrationManager.SetAccumulatedBits(viewerData, num2); HandleRandomEnemySpawn(cheerEvent, viewerData, spawnCount, accumulatedBitsUsedAmount); } private static string GetAddingAccumulatedBitsMessage(ViewerData viewer, int addedAmount) { int accumulatedBits = TwitchIntegrationManager.GetAccumulatedBits(viewer); int value = ConfigManager.TwitchCheerEvent_BitsForRandomEnemy.Value; return $"Adding {addedAmount} accumulated bits to {viewer.GetDisplayNameWithColor()} ({accumulatedBits + addedAmount}/{value})"; } private static void HandleEnemySpawn(TwitchCheerEvent cheerEvent, ViewerData viewer, EnemyConfigEntry enemyConfigEntry) { string spawnReason = $"by cheering {cheerEvent.CheerAmount} bits"; ViewerSpawnData viewerSpawnData = new ViewerSpawnData(viewer, 1, spawnReason, enemyConfigEntry.EnemyName); EnemyManager.SpawnEnemy(viewerSpawnData); } private static void HandleRandomEnemySpawn(TwitchCheerEvent cheerEvent, ViewerData viewer, int spawnCount = 1, int accumulatedBitsUsedAmount = 0) { string spawnReason; if (accumulatedBitsUsedAmount > 0) { int accumulatedBits = TwitchIntegrationManager.GetAccumulatedBits(viewer); spawnReason = $"by cheering {cheerEvent.CheerAmount} bits + {accumulatedBitsUsedAmount} accumulated bits. {accumulatedBits} accumulated bits remaining"; } else { spawnReason = $"by cheering {cheerEvent.CheerAmount} bits"; } ViewerSpawnData viewerSpawnData = new ViewerSpawnData(viewer, spawnCount, spawnReason); EnemyManager.SpawnEnemy(viewerSpawnData); } private static void HandleEventSpawn(TwitchCheerEvent cheerEvent, ViewerData viewer, MEvent mEvent) { mEvent.ExecuteEvent(viewer, PlayerAvatar.instance, cheerEvent.CheerAmount); } private static void HandleRandomEventSpawn(TwitchCheerEvent cheerEvent, ViewerData viewer) { if (!MEventManager.TryGetRandomEvent(out var mEvent)) { MessageManager.Instance?.ShowMessage("Failed to find random event. " + GetAddingAccumulatedBitsMessage(viewer, cheerEvent.CheerAmount)); } else { mEvent.ExecuteEvent(viewer, PlayerAvatar.instance, cheerEvent.CheerAmount); } } private static bool TryGetRandomProductForPrice(int value, out Product product) { List<Product> productsForPrice = GetProductsForPrice(value); if (productsForPrice == null || productsForPrice.Count == 0) { product = default(Product); return false; } product = productsForPrice[Random.Range(0, productsForPrice.Count)]; return true; } private static List<Product> GetProductsForPrice(int value) { List<Product> list = new List<Product>(); bool value2 = ConfigManager.TwitchCheerEvent_EnableBitsForRandomEnemy.Value; int value3 = ConfigManager.TwitchCheerEvent_BitsForRandomEnemy.Value; if (value2 && value3 == value) { list.Add(new Product(ProductType.RandomEnemy)); } foreach (EnemyConfigEntry enabledConfigEntry in EnemyConfigManager.EnabledConfigEntries) { if (enabledConfigEntry.BitsToSpawn.Value == value) { list.Add(new Product(enabledConfigEntry)); } } bool value4 = ConfigManager.Event_EnableBitsForRandomEvent.Value; int value5 = ConfigManager.Event_BitsForRandomEvent.Value; if (value4 && value5 == value) { list.Add(new Product(ProductType.RandomEvent)); } foreach (MEvent enabledEvent in MEventManager.EnabledEvents) { if (enabledEvent.BitsPrice.Value == value) { list.Add(new Product(enabledEvent)); } } return list; } } internal enum ProductType { Enemy, Event, RandomEnemy, RandomEvent } internal struct Product { public ProductType Type { get; set; } public object Data { get; set; } public Product(EnemyConfigEntry enemyConfigEntry) { this = default(Product); Type = ProductType.Enemy; Data = enemyConfigEntry; } public Product(MEvent mEvent) { this = default(Product); Type = ProductType.Event; Data = mEvent; } public Product(ProductType type) { this = default(Product); Type = type; } public EnemyConfigEntry ToEnemyConfigEntry() { return Data as EnemyConfigEntry; } public MEvent ToMEvent() { return Data as MEvent; } } 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) { TwitchCheerHandler.HandleCheer(cheerEvent); } 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; } 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_003d: 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) if (PlayerHelper.TryGetLocalPlayer(out var playerAvatar)) { string steamID = playerAvatar.steamID; string displayName = SemiFunc.PlayerGetName(playerAvatar); string color = "#FFFFFF"; return CreateTwitchUser(steamID, displayName, color, isVIP, isSubscriber, isModerator, isBroadcaster); } return CreateTwitchUser("0", "Unknown", "#FFFFFF", isVIP, isSubscriber, isModerator, isBroadcaster); } public static TwitchUser CreateTwitchUser(string userId, string displayName, string color = "#FFFFFF", bool isVIP = false, bool isSubscriber = false, bool isModerator = false, bool isBroadcaster = false) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) TwitchUser result = default(TwitchUser); ((TwitchUser)(ref result)).UserId = userId; ((TwitchUser)(ref result)).Username = displayName.ToLower(); ((TwitchUser)(ref result)).DisplayName = displayName; ((TwitchUser)(ref result)).Color = color; ((TwitchUser)(ref result)).IsVIP = isVIP; ((TwitchUser)(ref result)).IsSubscriber = isSubscriber; ((TwitchUser)(ref result)).IsModerator = isModerator; ((TwitchUser)(ref result)).IsBroadcaster = isBroadcaster; return result; } } } namespace com.github.zehsteam.TwitchTrolling.Twitch.Commands { internal static class TwitchSimulateCheerCommand { public static void Register() { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown ChatCommand val = new ChatCommand("cheer", "Simulate a Twitch cheer for TwitchTrolling", (Action<bool, string[]>)Execute, (Func<bool, string, string[], List<string>>)Suggest, (Func<bool>)IsEnabled, false); Commands.RegisterCommand(val); } private static void Execute(bool isDebugConsole, string[] args) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown int cheerAmount = ConfigManager.TwitchCheerEvent_BitsForRandomEnemy.Value; if (args.Length >= 1 && int.TryParse(args[0], out var result)) { cheerAmount = result; } TwitchCheerEvent cheerEvent = new TwitchCheerEvent { User = TwitchHelper.CreateTwitchUser(), CheerAmount = cheerAmount }; TwitchEventHandler.HandleCheer(cheerEvent); DebugCommandHandler instance = DebugCommandHandler.instance; if (instance != null) { instance.CommandSuccessEffect(); } } private static List<string> Suggest(bool isDebugConsole, string partial, string[] args) { List<SuggestEntry> list = new List<SuggestEntry>(); List<CombinedSuggestEntry> list2 = new List<CombinedSuggestEntry>(); foreach (EnemyConfigEntry enabledConfigEntry in EnemyConfigManager.EnabledConfigEntries) { list.Add(new SuggestEntry(enabledConfigEntry.EnemyName, enabledConfigEntry.BitsToSpawn.Value)); } foreach (MEvent enabledEvent in MEventManager.EnabledEvents) { list.Add(new SuggestEntry(enabledEvent.Name, enabledEvent.BitsPrice.Value)); } foreach (SuggestEntry item in list) { int price = item.Price; string name = item.Name; bool flag = true; foreach (CombinedSuggestEntry item2 in list2) { if (item2.Price == price) { item2.Names.Add(name); flag = false; break; } } if (flag) { list2.Add(new CombinedSuggestEntry(name, price)); } } List<string> list3 = (from x in list2 where x.Matches(args) orderby x.Price select x.GetText()).ToList(); if (ConfigManager.Event_EnableBitsForRandomEvent.Value) { CombinedSuggestEntry combinedSuggestEntry = new CombinedSuggestEntry("RANDOM EVENT", ConfigManager.Event_BitsForRandomEvent.Value); if (combinedSuggestEntry.Matches(args)) { list3.Insert(0, combinedSuggestEntry.GetText()); } } if (ConfigManager.TwitchCheerEvent_EnableBitsForRandomEnemy.Value) { CombinedSuggestEntry combinedSuggestEntry2 = new CombinedSuggestEntry("RANDOM ENEMY", ConfigManager.TwitchCheerEvent_BitsForRandomEnemy.Value); if (combinedSuggestEntry2.Matches(args)) { list3.Insert(0, combinedSuggestEntry2.GetText()); } } return list3; } private static bool IsEnabled() { if (SemiFunc.IsSplashScreen() || SemiFunc.IsMainMenu()) { return false; } if (SemiFunc.RunIsLobbyMenu()) { return false; } if (SemiFunc.RunIsTutorial()) { return false; } if (!SemiFunc.IsMasterClientOrSingleplayer()) { return false; } return true; } } internal static class TwitchSimulateSubCommand { public static void Register() { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown ChatCommand val = new ChatCommand("sub", "Simulate a Twitch sub or gift subs for TwitchTrolling", (Action<bool, string[]>)Execute, (Func<bool, string, string[], List<string>>)Suggest, (Func<bool>)IsEnabled, false); Commands.RegisterCommand(val); } private static void Execute(bool isDebugConsole, string[] args) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown int giftCount = 1; if (args.Length != 0 && int.TryParse(args[0], out var result)) { giftCount = result; } TwitchSubEvent subEvent = new TwitchSubEvent { User = TwitchHelper.CreateTwitchUser(), Type = (SubType)3, Tier = (SubTier)1, GiftCount = giftCount }; TwitchEventHandler.HandleSub(subEvent); DebugCommandHandler instance = DebugCommandHandler.instance; if (instance != null) { instance.CommandSuccessEffect(); } } private static List<string> Suggest(bool isDebugConsole, string partial, string[] args) { List<SuggestEntry> list = new List<SuggestEntry>(); List<CombinedSuggestEntry> list2 = new List<CombinedSuggestEntry>(); foreach (EnemyConfigEntry enabledConfigEntry in EnemyConfigManager.EnabledConfigEntries) { list.Add(new SuggestEntry(enabledConfigEntry.EnemyName, enabledConfigEntry.SubsToSpawn.Value)); } foreach (SuggestEntry item in list) { int price = item.Price; string name = item.Name; bool flag = true; foreach (CombinedSuggestEntry item2 in list2) { if (item2.Price == price) { item2.Names.Add(name); flag = false; break; } } if (flag) { list2.Add(new CombinedSuggestEntry(name, price)); } } return (from x in list2 where x.Matches(args) orderby x.Price select x.GetText()).ToList(); } private static bool IsEnabled() { if (SemiFunc.IsSplashScreen() || SemiFunc.IsMainMenu()) { return false; } if (SemiFunc.RunIsLobbyMenu()) { return false; } if (SemiFunc.RunIsTutorial()) { return false; } if (!SemiFunc.IsMasterClientOrSingleplayer()) { return false; } return true; } } } namespace com.github.zehsteam.TwitchTrolling.Twitch.Commands.Objects { internal class CombinedSuggestEntry { public List<string> Names = new List<string>(); public int Price; public CombinedSuggestEntry(string name, int price) { Names = new List<string>(1) { name }; Price = price; } public string GetText() { return $"{Price} - {GetNames()}"; } public string GetNames() { if (Names.Count == 1) { return Names[0]; } string text = string.Empty; int num = 60; int num2 = Names.Count; for (int i = 0; i < Names.Count; i++) { string text2 = string.Empty; if (i > 0) { text2 += ", "; } text2 += Names[i]; if ((text + text2).Length > num) { break; } text += text2; num2--; } if (num2 > 0) { text = text.Substring(0, Math.Min(text.Length, num)); text += $"... +{num2}"; } return text; } public bool Matches(string[] args) { string value = string.Join(" ", args); if (Price.ToString().StartsWith(value)) { return true; } if (Names.Any((string x) => x.Contains(value, StringComparison.OrdinalIgnoreCase))) { return true; } if (value.StartsWith(Price.ToString(), StringComparison.OrdinalIgnoreCase) && GetText().StartsWith(value, StringComparison.OrdinalIgnoreCase)) { return true; } return false; } } internal struct SuggestEntry { public string Name { get; set; } public int Price { get; set; } public SuggestEntry(string name, int price) { Name = name; Price = price; } } } namespace com.github.zehsteam.TwitchTrolling.Patches { [HarmonyPatch(typeof(EnemyDirector))] internal static class EnemyDirectorPatch { private static bool _patchedStart; [HarmonyPatch("Start")] [HarmonyPostfix] private static void StartPatch() { if (!_patchedStart) { _patchedStart = true; EnemyConfigManager.Initialize(); PageManager.UpdatePageFirstTime(); } } } [HarmonyPatch(typeof(EnemyDuck))] internal static class EnemyDuckPatch { public static List<EnemyDuck> DucksToBypassStunAggroOnce = new List<EnemyDuck>(); public static void Reset() { DucksToBypassStunAggroOnce = new List<EnemyDuck>(); } [HarmonyPatch("StateStun")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> StateStunTranspiler(IEnumerable<CodeInstruction> instructions) { //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Expected O, but got Unknown string text = "EnemyDuckPatch: [StateStun Transpiler]"; MethodInfo methodInfo = AccessTools.Method(typeof(EnemyDuck), "UpdateState", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(EnemyDuckPatch), "StateStun_UpdateState", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null) { Logger.LogError(text + " Failed to create transpiler. Required methods not found."); return instructions; } List<CodeInstruction> list = new List<CodeInstruction>(); foreach (CodeInstruction instruction in instructions) { if (CodeInstructionExtensions.Calls(instruction, methodInfo)) { list.Add(new CodeInstruction(OpCodes.Call, (object)methodInfo2)); Logger.LogInfo(text + " Replaced " + methodInfo.Name + " call with " + methodInfo2.Name + ".", extended: true); } else { list.Add(instruction); } } return list.AsEnumerable(); } private static void StateStun_UpdateState(EnemyDuck enemyDuck, State state) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_002b: Unknown result type (might be due to invalid IL or missing references) if ((int)state == 11 && DucksToBypassStunAggroOnce.Contains(enemyDuck)) { DucksToBypassStunAggroOnce.Remove(enemyDuck); enemyDuck.UpdateState((State)1); } else { enemyDuck.UpdateState(state); } } } [HarmonyPatch(typeof(FanTrap))] internal static class FanTrapPatch { public static List<FanTrap> FansToBypassIdle = new List<FanTrap>(); [HarmonyPatch("SetState")] [HarmonyPrefix] private static bool SetStatePatch(FanTrap __instance, States state) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if ((int)state != 0) { return true; } if (FansToBypassIdle.Contains(__instance)) { return false; } return true; } } [HarmonyPatch(typeof(HUDCanvas))] internal static class HUDCanvasPatch { [HarmonyPatch("Awake")] [HarmonyPostfix] private static void AwakePatch(HUDCanvas __instance) { Transform parent = ((Component)__instance).transform.Find("HUD"); PluginHUD.Spawn(parent); } } [HarmonyPatch(typeof(ItemDrone))] internal static class ItemDronePatch { public static List<PhysGrabObject> IgnorePhysGrabObjects = new List<PhysGrabObject>(); [HarmonyPatch("NewRayHitPointLogic")] [HarmonyPrefix] private static bool NewRayHitPointLogicPatch(ItemDrone __instance, int photonViewId, Transform newMagnetTarget) { PhysGrabObject physGrabObject = ((!((Object)(object)newMagnetTarget != (Object)null)) ? ((Component)PhotonView.Find(photonViewId)).gameObject.GetComponent<PhysGrabObject>() : ((Component)newMagnetTarget).GetComponent<PhysGrabObject>()); return CanAttachToPhysGrabObject(__instance, physGrabObject); } [HarmonyPatch("GetHighestParentWithRigidbody")] [HarmonyPostfix] private static void GetHighestParentWithRigidbodyPatch(ItemDrone __instance, ref Transform __result) { PhysGrabObject physGrabObject = default(PhysGrabObject); if (!((Object)(object)__result == (Object)null) && ((Component)__result).TryGetComponent<PhysGrabObject>(ref physGrabObject) && !CanAttachToPhysGrabObject(__instance, physGrabObject)) { __result = null; } } private static bool CanAttachToPhysGrabObject(ItemDrone itemDrone, PhysGrabObject physGrabObject) { if ((Object)(object)itemDrone == (Object)null || (Object)(object)physGrabObject == (Object)null) { return true; } if (IsSameDroneType(itemDrone, physGrabObject)) { return false; } if (IgnorePhysGrabObjects.Contains(physGrabObject)) { return false; } return true; } private static bool IsSameDroneType(ItemDrone itemDrone, PhysGrabObject physGrabObject) { if ((Object)(object)itemDrone == (Object)null || (Object)(object)physGrabObject == (Object)null) { return false; } ItemAttributes val = default(ItemAttributes); if (!((Component)physGrabObject).TryGetComponent<ItemAttributes>(ref val)) { return false; } return itemDrone.itemAttributes.itemName == val.itemName; } } [HarmonyPatch(typeof(ItemRubberDuck))] internal static class ItemRubberDuckPatch { public static List<ItemRubberDuck> SpecialRubberDucks = new List<ItemRubberDuck>(); [HarmonyPatch("Quack")] [HarmonyPostfix] private static void QuackPatch(ItemRubberDuck __instance) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) if (SpecialRubberDucks.Contains(__instance) && SemiFunc.IsMasterClientOrSingleplayer() && !(__instance.itemBattery.batteryLife <= 0f) && !__instance.physGrabObject.grabbed) { Vector3 velocity = __instance.rb.velocity; if (((Vector3)(ref velocity)).magnitude >= 20f) { Rigidbody rb = __instance.rb; rb.velocity *= 5f; __instance.rb.AddTorque(Random.insideUnitSphere * 40f); } } } } [HarmonyPatch(typeof(LevelGenerator))] internal static class LevelGeneratorPatch { [HarmonyPatch("EnemySetup")] [HarmonyPostfix] private static void EnemySetupPatch() { EnemyManager.ResetViewerEnemies(); EnemyDuckPatch.Reset(); if (TwitchIntegrationManager.CanPlayEvents()) { TwitchEventQueue.PlayQueuedEvents(TimeSpan.FromSeconds(10.0)); } } } [HarmonyPatch(typeof(PlayerController))] internal static class PlayerControllerPatch { private static bool _usingCustomSpeed; private static float _timeCustomSpeedEnd = float.NegativeInfinity; private static bool _usingCustomGravity; private static float _timeCustomGravityEnd = float.NegativeInfinity; [HarmonyPatch("Update")] [HarmonyPostfix] private static void UpdatePatch() { if (_usingCustomSpeed && !IsSpeedOverwritten()) { _usingCustomSpeed = false; ResetSpeed(); } if (_usingCustomGravity && !IsGravityOverwritten()) { _usingCustomGravity = false; ResetGravity(); } } public static void OverrideSpeed(float value, TimeSpan duration) { if (!((Object)(object)PlayerController.instance == (Object)null)) { _usingCustomSpeed = true; SetSpeed(value); _timeCustomSpeedEnd = Time.realtimeSinceStartup + (float)duration.TotalSeconds; } } private static bool IsSpeedOverwritten() { return Time.realtimeSinceStartup < _timeCustomSpeedEnd; } private static void SetSpeed(float value) { if (!((Object)(object)PlayerController.instance == (Object)null)) { value += 5f; PlayerController.instance.CrouchSpeed = value; PlayerController.instance.MoveSpeed = value; PlayerController.instance.SprintSpeed = value; } } private static void ResetSpeed() { if (!((Object)(object)PlayerAvatar.instance == (Object)null) && !((Object)(object)StatsManager.instance == (Object)null)) { PlayerController.instance.OverrideSpeed(1f, 0.1f); MessageManager.Instance?.ShowMessage("Your speed has been reset"); } } public static void OverrideGravity(float value, TimeSpan duration) { if (!((Object)(object)PlayerController.instance == (Object)null)) { _usingCustomGravity = true; SetGravity(value); _timeCustomGravityEnd = Time.realtimeSinceStartup + (float)duration.TotalSeconds; } } private static bool IsGravityOverwritten() { return Time.realtimeSinceStartup < _timeCustomGravityEnd; } private static void SetGravity(float value) { if (!((Object)(object)PlayerController.instance == (Object)null)) { PlayerController.instance.CustomGravity = value; } } private static void ResetGravity() { if (!((Object)(object)PlayerAvatar.instance == (Object)null) && !((Object)(object)StatsManager.instance == (Object)null)) { PlayerController.instance.CustomGravity = PlayerController.instance.playerOriginalCustomGravity; } } } [HarmonyPatch(typeof(RunManager))] internal static class RunManagerPatch { private static bool _patchedAwake; [HarmonyPatch("Awake")] [HarmonyPostfix] private static void AwakePatch(RunManager __instance) { if (!_patchedAwake) { _patchedAwake = true; MEventManager.Initialize(); } } } [HarmonyPatch(typeof(TruckScreenText))] internal static class TruckScreenTextPatch { [HarmonyPatch("Start")] [HarmonyPostfix] private static void StartPatch() { SpawnTruckProps(); } private static void SpawnTruckProps() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (TryGetTruckMeshTransform(out var transform)) { GameObject val = Object.Instantiate<GameObject>(Assets.TruckPropsPrefab); val.transform.SetParent(transform); val.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); Logger.LogInfo("TruckScreenTextPatch: Spawned truck props.", extended: true); } } private static bool TryGetTruckMeshTransform(out Transform transform) { transform = null; if ((Object)(object)TruckScreenText.instance == (Object)null) { Logger.LogInfo("TruckScreenTextPatch: Failed to get truck mesh transform. TruckScreenText instance is null."); return false; } try { transform = ((Component)TruckScreenText.instance).transform.parent.Find("Mesh"); return true; } catch (Exception arg) { Logger.LogInfo($"TruckScreenTextPatch: Failed to get truck mesh transform. {arg}"); return false; } } } } namespace com.github.zehsteam.TwitchTrolling.Objects { [Serializable] public class AudioPlayerFactory { public enum AudioUseMode { Single, Reuse } private static Dictionary<AudioPlayerType, Queue<AudioPlayer>> _audioPlayerPool = new Dictionary<AudioPlayerType, Queue<AudioPlayer>>(); public AudioPlayer AudioPlayer; public AudioPlayerType Type; public AudioUseMode UseMode; public float Volume = 1f; public float MaxDistance = 15f; public bool IsPlaying => AudioPlayer?.IsPlaying ?? false; public float Play(AudioClip audioClip, Vector3 position, bool loop = false) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) AssignAudioPlayer(); if (UseMode != AudioUseMode.Reuse) { loop = false; } return AudioPlayer?.Play(audioClip, position, Volume, MaxDistance, loop) ?? 0f; } public float Play(AudioClip audioClip, Transform transform, bool loop = false) { AssignAudioPlayer(); if (UseMode != AudioUseMode.Reuse) { loop = false; } return AudioPlayer?.Play(audioClip, transform, Volume, MaxDistance, loop) ?? 0f; } public void Stop() { AudioPlayer?.Stop(); } public void SetTargetTransform(Transform targetTransform) { AudioPlayer?.SetTargetTransform(targetTransform); } public void SetTargetPosition(Vector3 targetPosition) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) AudioPlayer?.SetTargetPosition(targetPosition); } private void AssignAudioPlayer() { if (UseMode == AudioUseMode.Single) { AudioPlayer = GetAudioPlayer(); } else if (UseMode == AudioUseMode.Reuse) { if ((Object)(object)AudioPlayer == (Object)null || (Object)(object)((Component)AudioPlayer).gameObject == (Object)null) { AudioPlayer = GetAudioPlayer(); } if (!((Object)(object)AudioPlayer == (Object)null) && !((Component)AudioPlayer).gameObject.activeSelf) { ((Component)AudioPlayer).gameObject.SetActive(true); } } } private GameObject GetAudioPrefab() { if ((Object)(object)AudioManager.instance == (Object)null) { return null; } return (GameObject)(Type switch { AudioPlayerType.Default => AudioManager.instance.AudioDefault, AudioPlayerType.EnemySpawn => Assets.AudioEnemySpawnPrefab, _ => null, }); } private AudioPlayer GetAudioPlayer() { if (!_audioPlayerPool.TryGetValue(Type, out var value) || value.Count == 0) { return CreateAudioPlayer(); } AudioPlayer audioPlayer = value.Dequeue(); if ((Object)(object)audioPlayer == (Object)null || (Object)(object)((Component)audioPlayer).gameObject == (Object)null) { return CreateAudioPlayer(); } ((Component)audioPlayer).gameObject.SetActive(false); ((Component)audioPlayer).gameObject.SetActive(true); return audioPlayer; } private AudioPlayer CreateAudioPlayer() { if ((Object)(object)AudioManager.instance == (Object)null) { return null; } GameObject audioPrefab = GetAudioPrefab(); if ((Object)(object)audioPrefab == (Object)null) { return null; } GameObject val = Object.Instantiate<GameObject>(audioPrefab); ((Object)val).name = $"AudioPlayer {Type}"; AudioPlayer audioPlayer = val.AddComponent<AudioPlayer>(); audioPlayer.Type = Type; if ((Object)(object)PluginManager.Instance != (Object)null) { val.transform.SetParent(PluginManager.Instance.AudioPlayerContainerTransform); } return audioPlayer; } public static void AddToPool(AudioPlayer audioPlayer) { if (!((Object)(object)audioPlayer == (Object)null) && !((Object)(object)((Component)audioPlayer).gameObject == (Object)null)) { if (!_audioPlayerPool.TryGetValue(audioPlayer.Type, out var value)) { value = new Queue<AudioPlayer>(); _audioPlayerPool.Add(audioPlayer.Type, value); } value.Enqueue(audioPlayer); ((Component)audioPlayer).gameObject.SetActive(false); } } } public class EnemyConfigEntry { private readonly EnemyConfigEntryDefaultValues _defaultValues; public string EnemyName { get; private set; } public ConfigEntry<bool> Enabled { get; private set; } public ConfigEntry<int> SpawnCount { get; private set; } public ConfigEntry<int> BitsToSpawn { get; private set; } public ConfigEntry<int> SubsToSpawn { get; private set; } public EnemyConfigEntry(string enemyName) { _defaultValues = new EnemyConfigEntryDefaultValues(enemyName); Initialize(); } public EnemyConfigEntry(EnemyConfigEntryDefaultValues defaultValues) { _defaultValues = defaultValues; Initialize(); } private void Initialize() { if (_defaultValues != null) { EnemyName = _defaultValues.EnemyName; BindConfigs(); } } private void BindConfigs() { string text = "Enemy: " + EnemyName; Enabled = EnemyConfigManager.ConfigFile.Bind<bool>(text, "Enabled", _defaultValues.Enabled, "Enable the " + EnemyName + " to be able to spawn."); SpawnCount = EnemyConfigManager.ConfigFile.Bind(text, "SpawnCount", _defaultValues.SpawnCount, "The amount of " + EnemyName + " to spawn.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20)); BitsToSpawn = EnemyConfigManager.ConfigFile.Bind(text, "BitsToSpawn", _defaultValues.BitsToSpawn, "The amount of bits to spawn " + EnemyName + ".", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000)); SubsToSpawn = EnemyConfigManager.ConfigFile.Bind(text, "SubsToSpawn", _defaultValues.SubsToSpawn, "The amount of subs to spawn " + EnemyName + ".", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10)); Enabled.SettingChanged += delegate { PageManager.UpdatePage(); }; SpawnCount.SettingChanged += delegate { PageManager.UpdatePage(); }; BitsToSpawn.SettingChanged += delegate { PageManager.UpdatePage(); }; SubsToSpawn.SettingChanged += delegate { PageManager.UpdatePage(); }; } public bool EnemyNameEquals(string enemyName) { return EnemyName.Equals(enemyName, StringComparison.OrdinalIgnoreCase); } public JObject GetCardJSON() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Expected O, but got Unknown int num = 1; int value = SpawnCount.Value; if (EnemyName.Equals("Banger", StringComparison.OrdinalIgnoreCase)) { num = 3; } if (EnemyName.Equals("Gnome", StringComparison.OrdinalIgnoreCase)) { num = 4; } JObject val = new JObject { ["name"] = JToken.op_Implicit(EnemyName), ["price"] = JToken.op_Implicit(BitsToSpawn.Value), ["spawnCount"] = JToken.op_Implicit(num * value) }; if (ConfigManager.TwitchSubEvent_Enabled.Value) { val.Add("subPrice", JToken.op_Implicit(SubsToSpawn.Value)); } return val; } } [Serializable] public class EnemyConfigEntryDefaultValues { public string EnemyName; public bool Enabled = true; public int SpawnCount = 1; public int BitsToSpawn = 350; public int SubsToSpawn = 1; public EnemyConfigEntryDefaultValues(string enemyName) { EnemyName = enemyName; } public EnemyConfigEntryDefaultValues(string enemyName, bool enabled, int spawnCount, int bitsToSpawn, int subsToSpawn) : this(enemyName) { Enabled = enabled; SpawnCount = spawnCount; BitsToSpawn = bitsToSpawn; SubsToSpawn = subsToSpawn; } } [CreateAssetMenu(fileName = "EnemyConfigEntryDefaultValuesList", menuName = "TwitchTrolling/EnemyConfigEntryDefaultValuesList")] public class EnemyConfigEntryDefaultValuesList : ScriptableObject { public EnemyConfigEntryDefaultValues[] List = Array.Empty<EnemyConfigEntryDefaultValues>(); } [Serializable] public class EnemySpawnSFX { public string EnemyName; public AudioClip SpawnSFX; public EnemySpawnSFX(string enemyName, AudioClip spawnSFX) { EnemyName = enemyName; SpawnSFX = spawnSFX; } } [CreateAssetMenu(fileName = "EnemySpawnSFXList", menuName = "TwitchTrolling/EnemySpawnSFXList")] public class EnemySpawnSFXList : ScriptableObject { public AudioClip GenericSpawnSFX; public EnemySpawnSFX[] List = Array.Empty<EnemySpawnSFX>(); public AudioClip GetSpawnSFX(string enemyName) { EnemySpawnSFX[] list = List; foreach (EnemySpawnSFX enemySpawnSFX in list) { if (enemySpawnSFX.EnemyName.Equals(enemyName, StringComparison.OrdinalIgnoreCase)) { return enemySpawnSFX.SpawnSFX; } } return GenericSpawnSFX; } } internal class JsonSave { private JObject _data; public string DirectoryPath { get; private set; } public string FileName { get; private set; } public string FilePath => Path.Combine(DirectoryPath, FileName); public JsonSave(string directoryPath, string fileName) { DirectoryPath = directoryPath; FileName = fileName; _data = ReadFile(); } public bool KeyExists(string key) { if (_data == null) { Logger.LogError("KeyExists: Data is null. Ensure the save file is properly loaded."); return false; } return _data.ContainsKey(key); } public T Load<T>(string key, T defaultValue = default(T), bool readFile = false) { if (TryLoad<T>(key, out var value, readFile)) { return value; } return defaultValue; } public bool TryLoad<T>(string key, out T value, bool readFile = false) { //IL_0058: Expected O, but got Unknown value = default(T); if (readFile) { _data = ReadFile(); } if (_data == null) { Logger.LogError("Load: Data is null. Returning default value for key: " + key + "."); return false; } JToken val = default(JToken); if (_data.TryGetValue(key, ref val)) { try { value = val.ToObject<T>(); return true; } catch (JsonException val2) { JsonException val3 = val2; Logger.LogError("Load: JSON Conversion Error for key: " + key + ". " + ((Exception)(object)val3).Message); } catch (ArgumentNullException ex) { Logger.LogError("Load: Argument Null Error for key: " + key + ". " + ex.Message); } catch (Exception ex2) { Logger.LogError("Load: Unexpected Error for key: " + key + ". " + ex2.Message); } return false; } Logger.LogWarning("Load: Key '" + key + "' does not exist. Returning default value.", extended: true); return false; } public bool Save<T>(string key, T value) { if (_data == null) { Logger.LogError("Save: Data is null. Cannot save key: " + key + "."); return false; } try { JToken val = JToken.FromObject((object)value); if (_data.ContainsKey(key)) { _data[key] = val; } else { _data.Add(key, val); } return WriteFile(_data); } catch (Exception ex) { Logger.LogError("Save: Error saving key: " + key + ". " + ex.Message); return false; } } private JObject ReadFile() { //IL_0070: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Expected O, but got Unknown try { if (!File.Exists(FilePath)) { Logger.LogWarning("ReadFile: Save file does not exist at \"" + FilePath + "\". Initializing with an empty file.", extended: true); return new JObject(); } using FileStream stream = new FileStream(FilePath, FileMode.Open, FileAccess.Read); using StreamReader streamReader = new StreamReader(stream, Encoding.UTF8); return JObject.Parse(streamReader.ReadToEnd()); } catch (JsonException val) { JsonException val2 = val; Logger.LogError("ReadFile: JSON Parsing Error for file: \"" + FilePath + "\". " + ((Exception)(object)val2).Message); } catch (Exception ex) { Logger.LogError("ReadFile: Unexpected Error for file: \"" + FilePath + "\". " + ex.Message); } return new JObject(); } private bool WriteFile(JObject data) { try { if (!Directory.Exists(DirectoryPath)) { Directory.CreateDirectory(DirectoryPath); } File.WriteAllText(FilePath, ((object)data).ToString(), Encoding.UTF8); return true; } catch (Exception ex) { Logger.LogError("WriteFile: Unexpected Error for file: \"" + FilePath + "\". " + ex.Message); } return false; } } internal class JsonSaveValue<T> : ObservableValue<T> { public JsonSave JsonSave { get; private set; } public string Key { get; private set; } public T DefaultValue { get; private set; } public bool ReadFile { get; private set; } public bool HasValue { get { T value; return TryLoad(out value); } } public JsonSaveValue(JsonSave jsonSave, string key, T defaultValue = default(T), bool readFile = false) : base(default(T)) { JsonSave = jsonSave; Key = key; DefaultValue = defaultValue; ReadFile = readFile; CustomValueGetter = Load; CustomValueSetter = Save; } private T Load() { return JsonSave.Load(Key, DefaultValue, ReadFile); } private bool TryLoad(out T value) { return JsonSave.TryLoad<T>(Key, out value, ReadFile); } private void Save(T value) { if (!object.Equals(value, base.Value)) { JsonSave.Save(Key, value); } } } internal class ObservableValue<T> { protected T _value; protected Func<T> CustomValueGetter; protected Action<T> CustomValueSetter; public T Value { get { return GetValue(); } set { SetValue(value); } } public event Action<T> OnValueChanged; public ObservableValue(T initialValue = default(T)) { _value = initialValue; } private T GetValue() { if (CustomValueGetter != null) { _value = CustomValueGetter(); } return _value; } private void SetValue(T value) { if (!object.Equals(_value, value)) { _value = value; CustomValueSetter?.Invoke(value); this.OnValueChanged?.Invoke(value); } } } public class QueueJsonConverter<T> : JsonConverter { public override bool CanConvert(Type objectType) { return objectType == typeof(Queue<T>); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { Queue<T> source = (Queue<T>)value; serializer.Serialize(writer, (object)source.ToList()); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { List<T> collection = serializer.Deserialize<List<T>>(reader); return new Queue<T>(collection); } } } namespace com.github.zehsteam.TwitchTrolling.MonoBehaviours { public enum AudioPlayerType { Default, EnemySpawn } public class AudioPlayer : MonoBehaviour { [CompilerGenerated] private sealed class <PoolAfterDurationCoroutine>d__18 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public TimeSpan duration; public AudioPlayer <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <PoolAfterDurationCoroutine>d__18(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown int num = <>1__state; AudioPlayer audioPlayer = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds((float)duration.TotalSeconds); <>1__state = 1; return true; case 1: <>1__state = -1; AudioPlayerFactory.AddToPool(audioPlayer); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public const float DefaultVolume = 1f; public const float DefaultMaxDistance = 15f; private AudioSource _audioSource; public AudioPlayerType Type; public Transform TargetTransform; public Vector3 TargetPosition; public AudioSource AudioSource { get { if (_audioSource == null) { _audioSource = ((Component)this).GetComponent<AudioSource>(); } return _audioSource; } private set { _audioSource = value; } } public bool IsPlaying { get { AudioSource audioSource = AudioSource; if (audioSource == null) { return false; } return audioSource.isPlaying; } } private void Start() { AudioSource.dopplerLevel = 0f; } private void Update() { UpdatePosition(); UpdateSpatialBlend(); } private void UpdatePosition() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)TargetTransform != (Object)null) { TargetPosition = TargetTransform.position; } ((Component)this).transform.position = TargetPosition; } private void UpdateSpatialBlend() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) float spatialBlend = 1f; PlayerAvatar localPlayer = PlayerHelper.GetLocalPlayer(); if (!((Object)(object)localPlayer == (Object)null)) { float num = Vector3.Distance(((Component)this).transform.position, ((Component)localPlayer.localCamera).transform.position); if (num <= 0.5f) { spatialBlend = 0f; } AudioSource.spatialBlend = spatialBlend; } } public float Play(AudioClip audioClip, Vector3 position, float volume = 1f, float maxDistance = 15f, bool loop = false) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) SetTargetPosition(position); return Play(audioClip, volume, maxDistance, loop); } public float Play(AudioClip audioClip, Transform transform, float volume = 1f, float maxDistance = 15f, bool loop = false) { SetTargetTransform(transform); return Play(audioClip, volume, maxDistance, loop); } private float Play(AudioClip audioClip, float volume = 1f, float maxDistance = 15f, bool loop = false) { if ((Object)(object)AudioSource == (Object)null) { if ((Object)(object)((Component)this).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)this).gameObject); } return 0f; } if ((Object)(object)audioClip == (Object)null) { AudioPlayerFactory.AddToPool(this); return 0f; } AudioSource.clip = audioClip; AudioSource.volume = volume; AudioSource.maxDistance = maxDistance; AudioSource.loop = loop; if (loop) { if (!AudioSource.isPlaying) { AudioSource.Play(); } } else { AudioSource.PlayOneShot(audioClip, volume); TimeSpan duration = TimeSpan.FromSeconds(audioClip.length + 0.1f); ((MonoBehaviour)this).StartCoroutine(PoolAfterDurationCoroutine(duration)); } return audioClip.length; } [IteratorStateMachine(typeof(<PoolAfterDurationCoroutine>d__18))] private IEnumerator PoolAfterDurationCoroutine(TimeSpan duration) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <PoolAfterDurationCoroutine>d__18(0) { <>4__this = this, duration = duration }; } public void Stop() { AudioSource audioSource = AudioSource; if (audioSource != null) { audioSource.Stop(); } } public void SetTargetTransform(Transform targetTransform) { TargetTransform = targetTransform; } public void SetTargetPosition(Vector3 targetPosition) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) TargetTransform = null; TargetPosition = targetPosition; } } public class BrowserLink : MonoBehaviour { [SerializeField] public string _url; public void OpenLink() { Application.OpenURL(_url); } } internal class CoroutineRunner : MonoBehaviour { public static CoroutineRunner Instance { get; private set; } public static CoroutineRunner Spawn() { //IL_002b: 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_0039: Expected O, but got Unknown if ((Object)(object)Instance != (Object)null) { return Instance; } GameObject val = new GameObject("TwitchTrolling CoroutineRunner", new Type[1] { typeof(CoroutineRunner) }) { hideFlags = (HideFlags)61 }; Object.DontDestroyOnLoad((Object)(object)val); return val.GetComponent<CoroutineRunner>(); } private void Awake() { if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this) { Object.Destroy((Object)(object)((Component)this).gameObject); } else { Instance = this; } } public static Coroutine Start(IEnumerator routine) { if ((Object)(object)Instance == (Object)null) { CoroutineRunner coroutineRunner = Spawn(); return ((coroutineRunner != null) ? ((MonoBehaviour)coroutineRunner).StartCoroutine(routine) : null) ?? null; } CoroutineRunner instance = Instance; return ((instance != null) ? ((MonoBehaviour)instance).StartCoroutine(routine) : null) ?? null; } public static void Stop(IEnumerator routine) { CoroutineRunner instance = Instance; if (instance != null) { ((MonoBehaviour)instance).StopCoroutine(routine); } } public static void Stop(Coroutine routine) { CoroutineRunner instance = Instance; if (instance != null) { ((MonoBehaviour)instance).StopCoroutine(routine); } } } public class DeathMessage : MonoBehaviour { [CompilerGenerated] private sealed class <ShowCoroutine>d__26 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public DeathMessage <>4__this; public TimeSpan duration; private float <fadeOutDuration>5__2; private float <timer>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ShowCoroutine>d__26(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown int num = <>1__state; DeathMessage deathMessage = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; deathMessage._canvasGroup.alpha = 1f; <>2__current = (object)new WaitForSeconds((float)duration.TotalSeconds); <>1__state = 1; return true; case 1: <>1__state = -1; <fadeOutDuration>5__2 = 1f; <timer>5__3 = 0f; break; case 2: <>1__state = -1; <timer>5__3 += Time.deltaTime; break; } if (<timer>5__3 < <fadeOutDuration>5__2) { float num2 = 1f / <fadeOutDuration>5__2 * <timer>5__3; float alpha = 1f + -1f * num2; deathMessage._canvasGroup.alpha = alpha; <>2__current = null; <>1__state = 2; return true; } deathMessage._canvasGroup.alpha = 0f; deathMessage._showCoroutine = null; return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [SerializeField] private TextMeshProUGUI _textUGUI; [SerializeField] private Image _backgroundImage; [SerializeField] private CanvasGroup _canvasGroup; private Coroutine _showCoroutine; public static DeathMessage Instance { get; private set; } public static bool IsEnabled => ConfigManager.DeathMessage_Enabled.Value; public static bool ShowPlatformIcon => ConfigManager.DeathMessage_ShowPlatformIcon.Value; public static float Duration => ConfigManager.DeathMessage_Duration.Value; public static float FontSize => ConfigManager.DeathMessage_FontSize.Value; public static int BackgroundTransparency => ConfigManager.DeathMessage_BackgroundTransparency.Value; private void Awake() { if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this) { Object.Destroy((Object)(object)((Component)this).gameObject); } else { Instance = this; } } private void Start() { _canvasGroup.alpha = 0f; } public void Show(EnemyParent enemyParent, ViewerData viewerData) { if (!((Object)(object)enemyParent == (Object)null) && viewerData != null) { string text = (ShowPlatformIcon ? "<sprite=0>" : string.Empty); string message = ("You died to a <color=#FF0000>" + enemyParent.enemyName + "</color> from " + viewerData.GetDisplayNameWithColor() + " " + text).Trim(); Show(message); } } public void Show(PhysGrabObject physGrabObject, ViewerData viewerData) { if (!((Object)(object)physGrabObject == (Object)null) && viewerData != null) { string text = ((Object)physGrabObject).name.TrimStart("Valuable ").TrimEnd("(Clone)").Trim(); string text2 = (ShowPlatformIcon ? "<sprite=0>" : string.Empty); string message = ("You died to a <color=#FF0000>" + text + "</color> from " + viewerData.GetDisplayNameWithColor() + " " + text2).Trim(); Show(message); } } public void ShowForExplosion(ViewerData viewerData, string sourceName = "") { if (viewerData != null) { string text = (ShowPlatformIcon ? "<sprite=0>" : string.Empty); string text2 = ((!string.IsNullOrEmpty(sourceName)) ? ("<color=#FF0000>" + sourceName + " (Explosion)</color>") : "<color=#FF0000>explosion</color>"); string message = ("You died to an " + text2 + " from " + viewerData.GetDisplayNameWithColor() + " " + text).Trim(); Show(message); } } public void Show(string message) { Show(message, TimeSpan.FromSeconds(Duration)); } public void Show(string message, TimeSpan duration) { if (IsEnabled) { UseConfigSettings(); if (_showCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_showCoroutine); } ((TMP_Text)_textUGUI).text = message; _showCoroutine = ((MonoBehaviour)this).StartCoroutine(ShowCoroutine(duration)); } } private void UseConfigSettings() { ((TMP_Text)_textUGUI).fontSize = FontSize; _backgroundImage.SetAlpha(BackgroundTransparency); } [IteratorStateMachine(typeof(<ShowCoroutine>d__26))] private IEnumerator ShowCoroutine(TimeSpan duration) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <ShowCoroutine>d__26(0) { <>4__this = this, duration = duration }; } } public class EnemyNametag : MonoBehaviour { [SerializeField] private TextMeshProUGUI _usernameText; [SerializeField] public Image _backgroundImage; [SerializeField] public CanvasGroup _canvasGroup; private static readonly float _heightOffset = 0.5f; private static readonly float _minSize = 0.75f; private static readonly float _maxSize = 1.5f; private RectTransform _rectTransform; private Transform _enemyTransform; private object _enemyScript; private bool _continuouslyCalculatePosition; private float _continuouslyCalculatePositionTimer; private float _continuouslyCalculatePositionCooldown = 0.1f; public static List<EnemyNametag> Instances { get; private set; } = new List<EnemyNametag>(); public static bool ShowPlatformIcon => ConfigManager.EnemyNametag_ShowPlatformIcon.Value; public static float SizeMultiplier => ConfigManager.EnemyNametag_SizeMultiplier.Value; public static int BackgroundTransparency => ConfigManager.EnemyNametag_BackgroundTransparency.Value; public EnemyParent EnemyParent { get; private set; } public ViewerData Viewer { get; private set; } private void OnEnable() { Instances.AddSingleInstance(this); } private void OnDisable() { Instances.Remove(this); } public void SetData(EnemyParent enemyParent, ViewerData viewerData) { EnemyParent = enemyParent; Vie
BepInEx/plugins/com.github.zehsteam.PlayerDamageTracker.dll
Decompiled a week agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Bootstrap; 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.MonoBehaviours; 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 © 2026 Zehs")] [assembly: AssemblyFileVersion("1.2.0.0")] [assembly: AssemblyInformationalVersion("1.2.0+93b733fc51d3908dc7613f65dfd81b662bb274ab")] [assembly: AssemblyProduct("PlayerDamageTracker")] [assembly: AssemblyTitle("com.github.zehsteam.PlayerDamageTracker")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.2.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] [CompilerGenerated] internal sealed class <>z__ReadOnlyList<T> : IEnumerable, ICollection, IList, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T> { int ICollection.Count => _items.Count; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; object IList.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } bool IList.IsFixedSize => true; bool IList.IsReadOnly => true; int IReadOnlyCollection<T>.Count => _items.Count; T IReadOnlyList<T>.this[int index] => _items[index]; int ICollection<T>.Count => _items.Count; bool ICollection<T>.IsReadOnly => true; T IList<T>.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } public <>z__ReadOnlyList(List<T> items) { _items = items; } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)_items).GetEnumerator(); } void ICollection.CopyTo(Array array, int index) { ((ICollection)_items).CopyTo(array, index); } int IList.Add(object value) { throw new NotSupportedException(); } void IList.Clear() { throw new NotSupportedException(); } bool IList.Contains(object value) { return ((IList)_items).Contains(value); } int IList.IndexOf(object value) { return ((IList)_items).IndexOf(value); } void IList.Insert(int index, object value) { throw new NotSupportedException(); } void IList.Remove(object value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } IEnumerator<T> IEnumerable<T>.GetEnumerator() { return ((IEnumerable<T>)_items).GetEnumerator(); } void ICollection<T>.Add(T item) { throw new NotSupportedException(); } void ICollection<T>.Clear() { throw new NotSupportedException(); } bool ICollection<T>.Contains(T item) { return _items.Contains(item); } void ICollection<T>.CopyTo(T[] array, int arrayIndex) { _items.CopyTo(array, arrayIndex); } bool ICollection<T>.Remove(T item) { throw new NotSupportedException(); } int IList<T>.IndexOf(T item) { return _items.IndexOf(item); } void IList<T>.Insert(int index, T item) { throw new NotSupportedException(); } void IList<T>.RemoveAt(int index) { throw new NotSupportedException(); } } 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 LogMessage(object data) { Log((LogLevel)8, 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.2.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!"); ((Object)this).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)this); _harmony.PatchAll(typeof(PlayerHealthPatch)); _harmony.PatchAll(typeof(HurtColliderPatch)); _harmony.PatchAll(typeof(ParticleScriptExplosionPatch)); _harmony.PatchAll(typeof(ItemGrenadeDuctTapedPatch)); PluginHelper.OnStart = (Action)Delegate.Combine(PluginHelper.OnStart, (Action)delegate { HurtOtherPatcher.PatchAll(_harmony); }); PluginHelper.Spawn(); } 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.2.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); } } Logger.LogInfo(text + " Created transpiler!"); 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 int _transpilersCreated; private static bool _patched; public static int TranspilersCreated => _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); } LogInfo("Created transpiler for " + method.GetFullName()); 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() { List<Assembly> list = new List<Assembly>(); list.Add(typeof(MenuManager).Assembly); list.AddRange(DependencyHelper.GetModAssemblies()); return new <>z__ReadOnlyList<Assembly>(list); } private static IEnumerable<Type> GetValidClasses(Assembly assembly) { if (assembly == null) { return Array.Empty<Type>(); } try { return assembly.GetLoadableTypes().Where(IsValidClass); } catch (Exception ex) { LogWarning("Error loading types from assembly " + assembly.FullName + ": " + ex.Message); return Array.Empty<Type>(); } } private static bool IsValidClass(Type type) { try { 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; } catch (Exception ex) { LogWarning("Error loading type " + type.FullName + " from assembly " + type.Assembly.FullName + ": " + ex.Message); 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); } } Logger.LogInfo(text + " Created transpiler!"); 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); } } Logger.LogInfo(logHeader + " Created transpiler!"); return list.AsEnumerable(); } } } namespace com.github.zehsteam.PlayerDamageTracker.MonoBehaviours { internal class PluginHelper : MonoBehaviour { private static PluginHelper _instance; public static Action OnStart; public static void Spawn() { //IL_0026: 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_0034: Expected O, but got Unknown if (!((Object)(object)_instance != (Object)null)) { GameObject val = new GameObject("PlayerDamageTracker PluginHelper", new Type[1] { typeof(PluginHelper) }) { hideFlags = (HideFlags)61 }; Object.DontDestroyOnLoad((Object)(object)val); } } private void Awake() { if ((Object)(object)_instance != (Object)null && (Object)(object)_instance != (Object)(object)this) { Object.Destroy((Object)(object)((Component)this).gameObject); } else { _instance = this; } } private void Start() { OnStart?.Invoke(); } } } 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 { public static class DependencyHelper { public static IEnumerable<Assembly> GetModAssemblies() { List<Assembly> list = new List<Assembly>(); foreach (PluginInfo value in Chainloader.PluginInfos.Values) { if (value == null || (Object)(object)value.Instance == (Object)null) { continue; } try { Assembly assembly = ((object)value.Instance).GetType().Assembly; if (!(assembly == null)) { list.Add(assembly); } } catch (Exception arg) { Logger.LogError($"Failed to get loaded assembly: {arg}"); } } return list; } } internal static class ILHelper { private static DefaultAssemblyResolver _cachedResolver; private static readonly 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.GetFullName()); return Array.Empty<Instruction>(); } return (IEnumerable<Instruction>)val.Body.Instructions; } catch (Exception arg) { Logger.LogWarning(string.Format("[{0}] Exception while processing method {1}: {2}", "ILHelper", method.GetFullName(), 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.GetFullName() + " 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(string.Format("[{0}] Exception while processing coroutine method {1}: {2}", "ILHelper", method.GetFullName(), 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(string.Format("[{0}] Failed to get ModuleDefinition for assembly {1}. {2}", "ILHelper", 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(string.Format("[{0}] Error while processing IL instructions. {1}", "ILHelper", 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 AssemblyExtensions { public static bool IsLocatedInPluginsFolder(this Assembly assembly) { if (assembly == null) { return false; } if (assembly.IsDynamic) { return false; } return assembly.Location.StartsWith(Paths.PluginPath, StringComparison.OrdinalIgnoreCase); } public static IEnumerable<Type> GetLoadableTypes(this Assembly assembly) { if (assembly == null) { return Array.Empty<Type>(); } try { return assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { return ex.Types.Where((Type type) => type != null); } } } 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, bool hurtByHeal, object caller) { if ((Object)(object)playerHealth == (Object)null) { return; } playerHealth.Hurt(damage, savingGrace, enemyIndex, hurtByHeal); 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); } } } internal static class ReflectionExtensions { public static string GetFullName(this MethodInfo methodInfo) { if (methodInfo == null) { return "Method is null"; } Type declaringType = methodInfo.DeclaringType; string name = methodInfo.Name; string name2 = declaringType.Name; string name3 = declaringType.Assembly.GetName().Name; return methodInfo.ReturnType.Name + " " + name + "(), class: " + name2 + ", assembly: " + name3; } } 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) { } } }
BepInEx/plugins/com.github.zehsteam.MetadataUtils.dll
Decompiled a week agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Logging; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.SceneManagement; using com.github.zehsteam.MetadataUtils.Modules; using com.github.zehsteam.MetadataUtils.Objects; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Zehs")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © 2026 Zehs")] [assembly: AssemblyFileVersion("1.1.1.0")] [assembly: AssemblyInformationalVersion("1.1.1+45627603d3869d4ee4f5fb1b7e7df530461a2c7c")] [assembly: AssemblyProduct("MetadataUtils")] [assembly: AssemblyTitle("com.github.zehsteam.MetadataUtils")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.1.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 LogMessage(object data) { Log((LogLevel)8, data); } public static void LogWarning(object data) { Log((LogLevel)4, data); } public static void LogError(object data) { Log((LogLevel)2, data); } public static void LogFatal(object data) { Log((LogLevel)1, data); } public static void Log(LogLevel logLevel, object data) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) ManualLogSource manualLogSource = ManualLogSource; if (manualLogSource != null) { manualLogSource.Log(logLevel, data); } } } [BepInPlugin("com.github.zehsteam.MetadataUtils", "MetadataUtils", "1.1.1")] internal class Plugin : BaseUnityPlugin { internal static Plugin Instance { get; private set; } private void Awake() { Instance = this; Logger.Initialize(Logger.CreateLogSource("com.github.zehsteam.MetadataUtils")); Logger.LogInfo("MetadataUtils has awoken!"); MetadataRegistry.Initialize(); } } public static class MyPluginInfo { public const string PLUGIN_GUID = "com.github.zehsteam.MetadataUtils"; public const string PLUGIN_NAME = "MetadataUtils"; public const string PLUGIN_VERSION = "1.1.1"; } } 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) { } } }