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.Serialization; 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.Converters; 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; using com.github.zehsteam.TwitchTrolling.Website; using com.github.zehsteam.TwitchTrolling.Website.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.9.0.0")] [assembly: AssemblyInformationalVersion("1.9.0+22c7ddd753dd9f4476ca7995a4f1aa2c47deedbc")] [assembly: AssemblyProduct("TwitchTrolling")] [assembly: AssemblyTitle("com.github.zehsteam.TwitchTrolling")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.9.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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("PluginManager", assetBundle); PluginHUDPrefab = LoadAsset("PluginHUD", assetBundle); EnemyNametagWorldCanvasPrefab = LoadAsset("EnemyNametagWorldCanvas", assetBundle); TruckPropsPrefab = LoadAsset("TruckProps", assetBundle); AudioEnemySpawnPrefab = LoadAsset("AudioEnemySpawn", assetBundle); Utilities.FixAudioMixerGroups(AudioEnemySpawnPrefab); ModCreditsPrefabRef = NetworkPrefabs.RegisterNetworkPrefab(LoadAsset("TwitchTrolling ModCredits", assetBundle)); EnemyConfigEntryDefaultValuesList = LoadAsset("EnemyConfigEntryDefaultValuesList", assetBundle); EnemySpawnSFXList = LoadAsset("EnemySpawnSFXList", assetBundle); MEventSFXList = LoadAsset("MEventSFXList", assetBundle); } private static T LoadAsset(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(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(string name, AssetBundle assetBundle, out T asset) where T : Object { asset = LoadAsset(name, assetBundle); return (Object)(object)asset != (Object)null; } } internal static class Logger { public static ManualLogSource ManualLogSource { get; private set; } public static bool IsExtendedLoggingEnabled => ConfigManager.Misc_ExtendedLogging?.Value ?? false; 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 LogMessage(object data, bool extended = false) { Log((LogLevel)8, 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) { Log((LogLevel)2, data, extended, showMessage); } 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, bool showMessage = false) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0026: 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_003e: Expected I4, but got Unknown //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) if (extended && !IsExtendedLoggingEnabled) { return; } ManualLogSource manualLogSource = ManualLogSource; if (manualLogSource != null) { manualLogSource.Log(logLevel, data); } if (showMessage) { Color color = Color.white; switch (logLevel - 1) { case 0: color = Color.red; break; case 1: color = Color.red; break; case 3: color = Color.yellow; break; } MessageManager.Instance?.ShowMessage(data.ToString(), color); } } } 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 b__6_0(Transform parent) { CreateMainButtonForMainMenu(parent); } internal void b__6_1(Transform parent) { CreateMainButtonForLobbyAndEscapeMenu(parent); } internal void b__6_2(Transform parent) { CreateMainButtonForLobbyAndEscapeMenu(parent); } internal void b__6_3() { PageManager.OnValidateTwitchChannelResult -= HandleValidateTwitchChannelResult; PageManager.OnCheckPageExistsResult -= HandleCheckPageExistsResult; PageManager.OnCreatePageResult -= HandleCreatePageResult; } } 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.OnValidateTwitchChannelResult += HandleValidateTwitchChannelResult; PageManager.OnCheckPageExistsResult += HandleCheckPageExistsResult; PageManager.OnCreatePageResult += HandleCreatePageResult; Application.quitting += delegate { PageManager.OnValidateTwitchChannelResult -= HandleValidateTwitchChannelResult; PageManager.OnCheckPageExistsResult -= HandleCheckPageExistsResult; PageManager.OnCreatePageResult -= HandleCreatePageResult; }; } 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); UpdateMenu(); PageManager.CheckPageExists(); if (SemiFunc.IsMasterClientOrSingleplayer()) { PageManager.ValidateTwitchChannel(); } } private static void HandleMainButtonClick() { CreateMenu(); } private static void HandleCloseButtonClick() { REPOPopupPage popupPage = _popupPage; if (popupPage != null) { popupPage.ClosePage(true); } } private static void HandleCreatePageButtonClick() { if (!SemiFunc.IsMasterClientOrSingleplayer()) { Logger.LogError("You are unable to create a page because you are not the host!", extended: false, showMessage: true); return; } REPOButton createPageButton = _createPageButton; if (createPageButton != null) { ((Component)createPageButton).gameObject.SetActive(false); } PageManager.CreatePage(); } private static void HandleCopyPageURLButtonClick() { if (PageManager.HasPage) { GUIUtility.systemCopyBuffer = PageManager.CurrentPage.PageUrl; } } private static void HandleSettingsButtonClick() { HandleCloseButtonClick(); REPOConfigHelper.OpenSettingsMenu("TwitchTrolling"); } private static void SetPageStatus(bool isOnline) { if (isOnline) { ((TMP_Text)_pageStatusLabel.labelTMP).text = "Page Status: ONLINE"; } else { ((TMP_Text)_pageStatusLabel.labelTMP).text = "Page Status: OFFLINE"; } } private static void SetMessagePageUrl(string url) { string text = url.Replace("?id", "\n?id"); ((TMP_Text)_pageUrlLabel.labelTMP).text = "" + text + ""; ((TMP_Text)_pageUrlLabel.labelTMP).fontStyle = (FontStyles)1; } private static void SetMessageCreatePageError(string reason) { SetMessageError("You are unable to create a page! Reason:", reason); } private static void SetMessageError(string header, string reason) { SetMessage(header + "\n" + reason + ""); } private static void SetMessage(string message) { ((TMP_Text)_pageUrlLabel.labelTMP).text = message; ((TMP_Text)_pageUrlLabel.labelTMP).fontStyle = (FontStyles)17; } private static void UpdateMenu(object serverResponseObj = null) { if ((Object)(object)_popupPage == (Object)null) { return; } bool hasPage = PageManager.HasPage; ((Component)_createPageButton).gameObject.SetActive(!hasPage); ((Component)_copyPageURLButton).gameObject.SetActive(hasPage); SetPageStatus(hasPage); if (hasPage) { SetMessagePageUrl(PageManager.CurrentPage.PageUrl); } ValidateTwitchChannelResponse lastValidateTwitchChannelResponse = PageManager.LastValidateTwitchChannelResponse; if (lastValidateTwitchChannelResponse != null && !lastValidateTwitchChannelResponse.Success) { SetMessageError("Twitch validation error:", lastValidateTwitchChannelResponse.Error + "\n"); ((Component)_createPageButton).gameObject.SetActive(false); ((Component)_copyPageURLButton).gameObject.SetActive(false); } else { if (hasPage) { return; } if (!SemiFunc.IsMasterClientOrSingleplayer()) { SetMessageCreatePageError("You are not the host"); ((Component)_createPageButton).gameObject.SetActive(false); } else if (serverResponseObj is ServerResponse serverResponse) { if (!serverResponse.Success) { SetMessageCreatePageError(serverResponse.Error); ((Component)_createPageButton).gameObject.SetActive(false); } } else { SetMessage("Create a page to share your prices\nwith your viewers!"); } } } private static void HandleValidateTwitchChannelResult(ValidateTwitchChannelResponse response) { UpdateMenu(response); } private static void HandleCheckPageExistsResult(CheckPageExistsRequestResponse response) { UpdateMenu(); } private static void HandleCreatePageResult(ServerResponse response) { UpdateMenu(response); } } [BepInPlugin("com.github.zehsteam.TwitchTrolling", "TwitchTrolling", "1.9.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!"); GlobalSave = new JsonSave(Utils.GetPluginPersistentDataPath(), "GlobalSave"); LocalSave = new JsonSave(Paths.ConfigPath, "TwitchTrolling_Save.json"); ConfigManager.Initialize(((BaseUnityPlugin)this).Config); _harmony.PatchAll(typeof(NetworkManager_Patches)); _harmony.PatchAll(typeof(NetworkConnect_Patches)); _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)); Assets.Load(); CoroutineRunner.Spawn(); PluginManager.Spawn(); TwitchIntegrationManager.Initialize(); Menu.Initialize(); PlayerHelper.Initialize(); TwitchSimulateCheerCommand.Register(); TwitchSimulateSubCommand.Register(); PageManager.Initialize(); } } internal static class Utils { 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); } public static IEnumerator InvokeAfterDurationCoroutine(TimeSpan duration, Action action) { yield return (object)new WaitForSeconds((float)duration.TotalSeconds); action?.Invoke(); } } 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.9.0"; } } namespace com.github.zehsteam.TwitchTrolling.Website { internal class PageDataSaveHelper { public static PageData LoadData() { if (!Plugin.GlobalSave.TryLoad("UrlId", out var value) || string.IsNullOrWhiteSpace(value)) { return null; } if (!Plugin.GlobalSave.TryLoad("AccessToken", out var value2) || string.IsNullOrWhiteSpace(value2)) { return null; } return new PageData(value, value2); } public static bool TryLoadData(out PageData pageData) { pageData = LoadData(); return pageData != null; } public static void SaveData(PageData pageData) { if (pageData != null) { Plugin.GlobalSave.Save("UrlId", pageData.UrlId); Plugin.GlobalSave.Save("AccessToken", pageData.AccessToken); } } public static void DeleteData() { Plugin.GlobalSave.Delete("UrlId"); Plugin.GlobalSave.Delete("AccessToken"); } } internal static class PageManager { public static readonly string ConvexUrl = "https://brainy-mockingbird-121.convex.site"; public static readonly string WebsiteUrl = "https://twitchtrolling.com"; public static readonly string CreatePageToken = "f404cdd4-f52d-45cf-9147-f3775f73b02f"; private static string _previousChannel; private static PagePayload _lastSentPagePayload; private static List _lastSentEffectsPayload = new List(); private static float _timeSincePageUpdateCalled; private static float _pageUpdateCooldown = 0.1f; public static PageData CurrentPage { get; private set; } public static bool HasPage => CurrentPage != null; public static ValidateTwitchChannelResponse LastValidateTwitchChannelResponse { get; private set; } public static event Action OnValidateTwitchChannelResult; public static event Action OnCheckPageExistsResult; public static event Action> OnCreatePageResult; public static void Initialize() { API.OnConnect += HandleTwitchChatAPIOnConnect; Application.quitting += delegate { API.OnConnect -= HandleTwitchChatAPIOnConnect; }; _previousChannel = API.Channel; CheckPageExists(); ValidateTwitchChannel(); } public static void ValidateTwitchChannel() { TwitchRequestHelper.ValidateTwitchChannel(API.Channel, HandleValidateTwitchChannelResult); } public static void CheckPageExists() { PageData pageData; if (HasPage) { PageRequestHelper.CheckPageExists(CurrentPage, HandleCheckPageExistsResult); } else if (PageDataSaveHelper.TryLoadData(out pageData)) { PageRequestHelper.CheckPageExists(pageData, HandleCheckPageExistsResult); } } public static void CreatePage() { if (!HasPage) { PageRequestHelper.CreatePage(GetPagePayload(), HandleCreatePageResult); } } public static void UpdatePage() { UpdatePage(updateEffects: true, EffectsAction.Update); } private static void UpdatePage(bool updateEffects, EffectsAction effectsAction) { if (HasPage) { float pageUpdateCooldown = _pageUpdateCooldown; float realtimeSinceStartup = Time.realtimeSinceStartup; if (!(realtimeSinceStartup - _timeSincePageUpdateCalled < pageUpdateCooldown)) { _timeSincePageUpdateCalled = realtimeSinceStartup; CoroutineRunner.Start(UpdatePageAfterDelay_Coroutine(pageUpdateCooldown, updateEffects, effectsAction)); } } } private static IEnumerator UpdatePageAfterDelay_Coroutine(float delay, bool updateEffects = true, EffectsAction effectsAction = EffectsAction.Update) { yield return (object)new WaitForSeconds(delay); PagePayload pagePayload = GetPagePayload(); if (!pagePayload.Equals(_lastSentPagePayload)) { PageRequestHelper.UpdatePage(CurrentPage, pagePayload, HandleUpdatePageResult); } if (updateEffects) { SetOrUpdateEffects(effectsAction); } } public static void SetEffects() { SetOrUpdateEffects(EffectsAction.Set); } private static void SetOrUpdateEffects(EffectsAction action) { if (!HasPage) { return; } List list; if (action == EffectsAction.Set) { list = GetEffectsPayload(); } else { list = GetChangedEffectsPayload(); if (list.Count == 0) { return; } } PageRequestHelper.SetOrUpdateEffects(action, CurrentPage, list, HandleSetOrUpdateEffectsResult); } private static void HandleTwitchChatAPIOnConnect() { string channel = API.Channel; if (!channel.Equals(_previousChannel, StringComparison.OrdinalIgnoreCase)) { _previousChannel = channel; ValidateTwitchChannel(); UpdatePage(); } } private static void HandleValidateTwitchChannelResult(ValidateTwitchChannelResponse response) { LastValidateTwitchChannelResponse = response; PageManager.OnValidateTwitchChannelResult?.Invoke(response); } private static void HandleCheckPageExistsResult(CheckPageExistsRequestResponse response) { if (response.ServerResponse.Success) { if (!HasPage) { CurrentPage = response.PageData; UpdatePage(updateEffects: true, EffectsAction.Set); } } else { CurrentPage = null; PageDataSaveHelper.DeleteData(); } PageManager.OnCheckPageExistsResult?.Invoke(response); } private static void HandleCreatePageResult(ServerResponse response) { if (response.Success) { CurrentPage = response.Data.ToPageData(); _lastSentPagePayload = GetPagePayload(); _lastSentEffectsPayload = new List(); PageDataSaveHelper.SaveData(CurrentPage); SetOrUpdateEffects(EffectsAction.Set); MessageManager.Instance?.ShowMessage("Please share the page url with your viewers"); MessageManager.Instance?.ShowMessage("It is recommended that you pin it in your chat"); } PageManager.OnCreatePageResult?.Invoke(response); } private static void HandleUpdatePageResult(UpdatePageResponse response) { if (response.ServerResponse.Success) { _lastSentPagePayload = response.PagePayload; } } private static void HandleSetOrUpdateEffectsResult(EffectRequestResponse response) { if (response.ServerResponse.Success) { _lastSentEffectsPayload = response.EffectsPayload; } } private static PagePayload GetPagePayload() { return new PagePayload { Username = API.Channel, IsHost = SemiFunc.IsMasterClientOrSingleplayer(), IsEnemiesEnabled = ConfigManager.Enemy_Enabled.Value, IsEventsEnabled = MEventManager.Enabled, IsCheerEnabled = TwitchIntegrationManager.IsCheerEventEnabled, IsSubEnabled = TwitchIntegrationManager.IsSubEventEnabled, IsRaidEnabled = TwitchIntegrationManager.IsRaidEventEnabled, Tier1SubEnemyMultiplier = ConfigManager.TwitchSubEvent_Tier1EnemySpawnCountMultiplier.Value, Tier2SubEnemyMultiplier = ConfigManager.TwitchSubEvent_Tier2EnemySpawnCountMultiplier.Value, Tier3SubEnemyMultiplier = ConfigManager.TwitchSubEvent_Tier3EnemySpawnCountMultiplier.Value, RaidViewersPerEnemy = ConfigManager.TwitchRaidEvent_ViewersPerRandomEnemy.Value, RaidMaxEnemySpawnCount = ConfigManager.TwitchRaidEvent_MaxEnemySpawnCount.Value }; } private static List GetEffectsPayload() { List effectsPayload = EnemyConfigManager.GetEffectsPayload(); List effectsPayload2 = MEventManager.GetEffectsPayload(); List list = new List(effectsPayload.Count + effectsPayload2.Count); list.AddRange(effectsPayload); list.AddRange(effectsPayload2); return list; } private static List GetChangedEffectsPayload() { List lastSentEffectsPayload = _lastSentEffectsPayload; List effectsPayload = GetEffectsPayload(); List list = new List(); foreach (EffectPayload currentEffect in effectsPayload) { if (!lastSentEffectsPayload.Any((EffectPayload x) => x.Equals(currentEffect))) { list.Add(currentEffect); } } return list; } } internal static class PageRequestHelper { public static void CheckPageExists(PageData pageData, Action resultCallback) { CoroutineRunner.Start(CheckPageExists_Coroutine(pageData, resultCallback)); } private static IEnumerator CheckPageExists_Coroutine(PageData pageData, Action resultCallback) { if (pageData == null) { yield break; } string text = PageManager.ConvexUrl + "/page/exists?urlId=" + Uri.EscapeDataString(pageData.UrlId); UnityWebRequest request = UnityWebRequest.Get(text); try { request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer(); yield return request.SendWebRequest(); if ((int)request.result == 2) { Failed("Failed to connect to server"); yield break; } if ((int)request.result == 4) { Failed("Failed to process response from server"); yield break; } string text2 = request.downloadHandler.text; if (Logger.IsExtendedLoggingEnabled) { Logger.LogInfo("[CheckPageExists_Coroutine] Server response:\n\n" + text2 + "\n", extended: true); } if (!TryParseResponse(text2, out var response, out var errorMessage)) { Failed(errorMessage); yield break; } if (Logger.IsExtendedLoggingEnabled) { Logger.LogInfo("[CheckPageExists_Coroutine] Parsed response:\n\n" + JsonConvert.SerializeObject((object)response, (Formatting)1) + "\n", extended: true); } resultCallback?.Invoke(new CheckPageExistsRequestResponse(response, pageData)); } finally { ((IDisposable)request)?.Dispose(); } void Failed(string message) { Logger.LogError("Failed to check page exists: " + message, extended: false, showMessage: true); resultCallback?.Invoke(new CheckPageExistsRequestResponse(ServerResponse.Failed(message), null)); } } public static void CreatePage(PagePayload payload, Action> resultCallback) { CoroutineRunner.Start(CreatePage_Coroutine(payload, resultCallback)); } private static IEnumerator CreatePage_Coroutine(PagePayload payload, Action> resultCallback) { string s = JsonConvert.SerializeObject((object)payload); string text = PageManager.ConvexUrl + "/page"; UnityWebRequest request = new UnityWebRequest(text, "POST"); try { byte[] bytes = Encoding.UTF8.GetBytes(s); request.uploadHandler = (UploadHandler)new UploadHandlerRaw(bytes); request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer(); request.SetRequestHeader("Content-Type", "application/json"); request.SetRequestHeader("Authorization", "Bearer " + PageManager.CreatePageToken); yield return request.SendWebRequest(); if ((int)request.result == 2) { Failed("Failed to connect to server"); yield break; } if ((int)request.result == 4) { Failed("Failed to process response from server"); yield break; } string text2 = request.downloadHandler.text; if (Logger.IsExtendedLoggingEnabled) { Logger.LogInfo("[CreatePage_Coroutine] Server response:\n\n" + text2 + "\n", extended: true); } if (!TryParseResponse(text2, out ServerResponse response, out string errorMessage)) { Failed(errorMessage); yield break; } if (Logger.IsExtendedLoggingEnabled) { Logger.LogInfo("[CreatePage_Coroutine] Parsed response:\n\n" + JsonConvert.SerializeObject((object)response, (Formatting)1) + "\n", extended: true); } resultCallback?.Invoke(response); } finally { ((IDisposable)request)?.Dispose(); } void Failed(string message) { Logger.LogError("Failed to create page: " + message, extended: false, showMessage: true); resultCallback?.Invoke(ServerResponse.Failed(message)); } } public static void UpdatePage(PageData pageData, PagePayload payload, Action resultCallback) { CoroutineRunner.Start(UpdatePage_Coroutine(pageData, payload, resultCallback)); } private static IEnumerator UpdatePage_Coroutine(PageData pageData, PagePayload payload, Action resultCallback) { if (pageData == null) { yield break; } string s = JsonConvert.SerializeObject((object)payload); string text = PageManager.ConvexUrl + "/page?urlId=" + Uri.EscapeDataString(pageData.UrlId); UnityWebRequest request = new UnityWebRequest(text, "PATCH"); try { byte[] bytes = Encoding.UTF8.GetBytes(s); request.uploadHandler = (UploadHandler)new UploadHandlerRaw(bytes); request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer(); request.SetRequestHeader("Content-Type", "application/json"); request.SetRequestHeader("Authorization", "Bearer " + pageData.AccessToken); yield return request.SendWebRequest(); if ((int)request.result == 2) { Failed("Failed to connect to server"); yield break; } if ((int)request.result == 4) { Failed("Failed to process response from server"); yield break; } string text2 = request.downloadHandler.text; if (Logger.IsExtendedLoggingEnabled) { Logger.LogInfo("[UpdatePage_Coroutine] Server response:\n\n" + text2 + "\n", extended: true); } if (!TryParseResponse(text2, out var response, out var errorMessage)) { Failed(errorMessage); yield break; } if (Logger.IsExtendedLoggingEnabled) { Logger.LogInfo("[UpdatePage_Coroutine] Parsed response:\n\n" + JsonConvert.SerializeObject((object)response, (Formatting)1) + "\n", extended: true); } resultCallback?.Invoke(new UpdatePageResponse(response, payload)); } finally { ((IDisposable)request)?.Dispose(); } void Failed(string message) { Logger.LogError("Failed to update page: " + message, extended: false, showMessage: true); resultCallback?.Invoke(new UpdatePageResponse(ServerResponse.Failed(message), payload)); } } public static void SetOrUpdateEffects(EffectsAction action, PageData pageData, List payload, Action resultCallback) { CoroutineRunner.Start(SetOrUpdateEffects_Coroutine(action, pageData, payload, resultCallback)); } private static IEnumerator SetOrUpdateEffects_Coroutine(EffectsAction action, PageData pageData, List payload, Action resultCallback) { if (pageData == null || (action == EffectsAction.Update && payload.Count == 0)) { yield break; } string s = JsonConvert.SerializeObject((object)payload); string text = PageManager.ConvexUrl + "/page/effects?urlId=" + Uri.EscapeDataString(pageData.UrlId); UnityWebRequest request = new UnityWebRequest(text, action switch { EffectsAction.Set => "PUT", EffectsAction.Update => "PATCH", _ => throw new ArgumentOutOfRangeException("action", $"Unsupported action: {action}"), }); try { byte[] bytes = Encoding.UTF8.GetBytes(s); request.uploadHandler = (UploadHandler)new UploadHandlerRaw(bytes); request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer(); request.SetRequestHeader("Content-Type", "application/json"); request.SetRequestHeader("Authorization", "Bearer " + pageData.AccessToken); yield return request.SendWebRequest(); if ((int)request.result == 2) { Failed("Failed to connect to server"); yield break; } if ((int)request.result == 4) { Failed("Failed to process response from server"); yield break; } string text2 = request.downloadHandler.text; if (Logger.IsExtendedLoggingEnabled) { Logger.LogInfo("[SetOrUpdateEffects_Coroutine] Server response:\n\n" + text2 + "\n", extended: true); } if (!TryParseResponse(text2, out var response, out var errorMessage)) { Failed(errorMessage); yield break; } if (Logger.IsExtendedLoggingEnabled) { Logger.LogInfo("[SetOrUpdateEffects_Coroutine] Parsed response:\n\n" + JsonConvert.SerializeObject((object)response, (Formatting)1) + "\n", extended: true); } resultCallback?.Invoke(new EffectRequestResponse(response, payload)); } finally { ((IDisposable)request)?.Dispose(); } void Failed(string message) { Logger.LogError("Failed to " + action.ToString().ToLower() + " page effects: " + message, extended: false, showMessage: true); resultCallback?.Invoke(new EffectRequestResponse(ServerResponse.Failed(message), payload)); } } private static bool TryParseResponse(string json, out ServerResponse response, out string errorMessage) { try { response = JsonConvert.DeserializeObject>(json); errorMessage = null; return true; } catch (Exception ex) { response = null; errorMessage = "Failed to parse response from server: " + ex.Message; return false; } } private static bool TryParseResponse(string json, out ServerResponse response, out string errorMessage) { try { response = JsonConvert.DeserializeObject(json); errorMessage = null; return true; } catch (Exception ex) { response = null; errorMessage = "Failed to parse response from server: " + ex.Message; return false; } } } internal static class TwitchRequestHelper { public static void ValidateTwitchChannel(string username, Action resultCallback) { CoroutineRunner.Start(ValidateTwitchChannel_Coroutine(username, resultCallback)); } private static IEnumerator ValidateTwitchChannel_Coroutine(string username, Action resultCallback) { if (username.Equals("CritHaxXoG", StringComparison.OrdinalIgnoreCase)) { resultCallback?.Invoke(ValidateTwitchChannelResponse.Succeeded()); yield break; } string text = "https://api.ivr.fi/v2/twitch/user?login=" + Uri.EscapeDataString(username); UnityWebRequest request = UnityWebRequest.Get(text); try { request.SetRequestHeader("User-Agent", "TwitchTrolling/1.9.0"); request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer(); yield return request.SendWebRequest(); if ((int)request.result == 2) { Failed("Failed to connect to Twitch API server"); yield break; } if ((int)request.result == 4) { Failed("Failed to process response from Twitch API server"); yield break; } if ((int)request.result == 3) { Failed($"Twitch API server returned error {request.responseCode}"); yield break; } if ((int)request.result != 1) { Failed($"Twitch API server returned error {request.responseCode}"); yield break; } string text2 = request.downloadHandler.text; JObject val2; try { JArray val = JArray.Parse(text2); if (((JContainer)val).Count == 0) { Failed("Twitch user not found"); yield break; } val2 = (JObject)val[0]; } catch (Exception data) { Failed("Failed to parse response from Twitch API server"); Logger.LogError(data); yield break; } if (((JToken)val2).Value((object)"banned")) { Failed("Twitch user is banned"); yield break; } JObject val3 = (JObject)(((object)((JToken)val2).Value((object)"roles")) ?? ((object)new JObject())); bool valueOrDefault = ((JToken)val3).Value((object)"isAffiliate") == true; bool valueOrDefault2 = ((JToken)val3).Value((object)"isPartner") == true; if (!valueOrDefault && !valueOrDefault2) { Failed("Twitch user is not affiliate or partner"); yield break; } JObject val4 = ((JToken)val2).Value((object)"stream"); if (val4 == null) { Failed("Twitch user is not live"); yield break; } JObject val5 = (JObject)(((object)((JToken)val4).Value((object)"game")) ?? ((object)new JObject())); string text3 = ((JToken)val5).Value((object)"displayName") ?? string.Empty; string text4 = "R.E.P.O."; if (!text3.Equals(text4, StringComparison.OrdinalIgnoreCase)) { Failed("Twitch user is not in the " + text4 + " category"); } else { resultCallback?.Invoke(ValidateTwitchChannelResponse.Succeeded()); } } finally { ((IDisposable)request)?.Dispose(); } void Failed(string message) { Logger.LogError("Twitch validation error: " + message, extended: false, showMessage: true); resultCallback?.Invoke(ValidateTwitchChannelResponse.Failed(message)); } } } } namespace com.github.zehsteam.TwitchTrolling.Website.Objects { public class CheckPageExistsRequestResponse { public ServerResponse ServerResponse { get; private set; } public PageData PageData { get; private set; } public CheckPageExistsRequestResponse(ServerResponse serverResponse, PageData pageData) { ServerResponse = serverResponse; PageData = pageData; } } public record struct CreatePageResult { [JsonProperty("urlId")] public string UrlId { get; set; } [JsonProperty("accessToken")] public string AccessToken { get; set; } public readonly PageData ToPageData() { return new PageData(UrlId, AccessToken); } } [JsonConverter(typeof(StringEnumConverter))] public enum EffectType { [EnumMember(Value = "enemy")] Enemy, [EnumMember(Value = "event")] Event } public record struct EffectPayload { [JsonProperty("type")] public EffectType Type { get; set; } [JsonProperty("name")] public string Name { get; set; } [JsonProperty("isEnabled")] public bool IsEnabled { get; set; } [JsonProperty(/*Could not decode attribute arguments.*/)] public int? SpawnCount { get; set; } [JsonProperty("bitPrice")] public int BitPrice { get; set; } [JsonProperty(/*Could not decode attribute arguments.*/)] public int? SubPrice { get; set; } } public class EffectRequestResponse { public ServerResponse ServerResponse { get; set; } public List EffectsPayload { get; set; } = new List(); public EffectRequestResponse(ServerResponse serverResponse, List effectsPayload) { ServerResponse = serverResponse; EffectsPayload = effectsPayload; } } public enum EffectsAction { Set, Update } public class PageData { public string UrlId { get; set; } public string AccessToken { get; set; } public string PageUrl => PageManager.WebsiteUrl + "/page?id=" + UrlId; public PageData(string urlId, string accessToken) { UrlId = urlId; AccessToken = accessToken; } } public record struct PagePayload { [JsonProperty("username")] public string Username { get; set; } [JsonProperty("isHost")] public bool IsHost { get; set; } [JsonProperty("isEnemiesEnabled")] public bool IsEnemiesEnabled { get; set; } [JsonProperty("isEventsEnabled")] public bool IsEventsEnabled { get; set; } [JsonProperty("isCheerEnabled")] public bool IsCheerEnabled { get; set; } [JsonProperty("isSubEnabled")] public bool IsSubEnabled { get; set; } [JsonProperty("isRaidEnabled")] public bool IsRaidEnabled { get; set; } [JsonProperty("tier1SubEnemyMultiplier")] public int Tier1SubEnemyMultiplier { get; set; } [JsonProperty("tier2SubEnemyMultiplier")] public int Tier2SubEnemyMultiplier { get; set; } [JsonProperty("tier3SubEnemyMultiplier")] public int Tier3SubEnemyMultiplier { get; set; } [JsonProperty("raidViewersPerEnemy")] public int RaidViewersPerEnemy { get; set; } [JsonProperty("raidMaxEnemySpawnCount")] public int RaidMaxEnemySpawnCount { get; set; } } public class ServerResponse { [JsonProperty("success")] public bool Success { get; set; } [JsonProperty("data")] public T Data { get; set; } [JsonProperty("error")] public string Error { get; set; } public static ServerResponse Succeeded() { return new ServerResponse { Success = true }; } public static ServerResponse Succeeded(T data) { return new ServerResponse { Success = true, Data = data }; } public static ServerResponse Failed(string error) { return new ServerResponse { Success = false, Error = error }; } } public class ServerResponse : ServerResponse { public new static ServerResponse Succeeded() { return new ServerResponse { Success = true }; } public new static ServerResponse Succeeded(JObject data) { return new ServerResponse { Success = true, Data = data }; } public new static ServerResponse Failed(string error) { return new ServerResponse { Success = false, Error = error }; } } public class UpdatePageResponse { public ServerResponse ServerResponse { get; private set; } public PagePayload PagePayload { get; private set; } public UpdatePageResponse(ServerResponse serverResponse, PagePayload pagePayload) { ServerResponse = serverResponse; PagePayload = pagePayload; } } public class ValidateTwitchChannelResponse { public bool Success { get; set; } public string Error { get; set; } public static ValidateTwitchChannelResponse Succeeded() { return new ValidateTwitchChannelResponse { Success = true }; } public static ValidateTwitchChannelResponse Failed(string error) { return new ValidateTwitchChannelResponse { Success = false, Error = error }; } } } 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 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 GetProductsForPrice(int value) { List list = new List(); 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("Warning! 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 { private static Coroutine _playQueuedEventsCoroutine; public static Queue CheerQueue { get; private set; } = new Queue(); public static Queue SubQueue { get; private set; } = new Queue(); public static Queue RaidQueue { get; private set; } = new Queue(); public static void LoadData() { Logger.LogInfo("TwitchEventQueue: Loading saved data..."); try { if (Plugin.GlobalSave.TryLoad("CheerQueue", out var value)) { CheerQueue = JsonConvertHelper.DeserializeQueue(value); Logger.LogInfo("TwitchEventQueue: Loaded CheerQueue JSON data:\n\n" + value, extended: true); } if (Plugin.GlobalSave.TryLoad("SubQueue", out value)) { SubQueue = JsonConvertHelper.DeserializeQueue(value); Logger.LogInfo("TwitchEventQueue: Loaded SubQueue JSON data:\n\n" + value, extended: true); } if (Plugin.GlobalSave.TryLoad("RaidQueue", out value)) { RaidQueue = JsonConvertHelper.DeserializeQueue(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)); } private static IEnumerator PlayQueuedEventsCoroutine(TimeSpan initialDelay) { Logger.LogInfo("TwitchEventQueue: Started playing queued events.", extended: true); Logger.LogInfo($"TwitchEventQueue: Playing queued events after {(float)initialDelay.TotalSeconds} seconds.", extended: true); yield return (object)new WaitForSeconds((float)initialDelay.TotalSeconds); if (!TwitchEventHandler.CanHandleEvents()) { yield break; } if (!TwitchIntegrationManager.CanPlayEvents()) { Logger.LogWarning("TwitchEventQueue: Failed to play queued events. You are not allowed to play events at this time."); yield break; } if (!HasQueuedEvents()) { Logger.LogInfo("TwitchEventQueue: No events in the queue to play.", extended: true); yield break; } MessageManager.Instance?.ShowMessage("Playing Twitch events from the queue"); TimeSpan delayBetweenEvents = TimeSpan.FromSeconds(0.5); TwitchCheerEvent result; while (TwitchIntegrationManager.IsCheerEventEnabled && CheerQueue.TryDequeue(out result)) { TwitchEventHandler.HandleCheer(result); yield return (object)new WaitForSeconds((float)delayBetweenEvents.TotalSeconds); } TwitchSubEvent result2; while (TwitchIntegrationManager.IsSubEventEnabled && SubQueue.TryDequeue(out result2)) { TwitchEventHandler.HandleSub(result2); yield return (object)new WaitForSeconds((float)delayBetweenEvents.TotalSeconds); } TwitchRaidEvent result3; while (TwitchIntegrationManager.IsRaidEventEnabled && RaidQueue.TryDequeue(out result3)) { TwitchEventHandler.HandleRaid(result3); yield return (object)new WaitForSeconds((float)delayBetweenEvents.TotalSeconds); } Logger.LogInfo("TwitchEventQueue: Finished plyaing queued events.", extended: true); SaveData(); _playQueuedEventsCoroutine = null; } 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 AccumulatedBits { get; private set; } = new Dictionary(); 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("AccumulatedBits", out var value)) { AccumulatedBits = JsonConvert.DeserializeObject>(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)Execute, (Func>)Suggest, (Func)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 Suggest(bool isDebugConsole, string partial, string[] args) { List list = new List(); List list2 = new List(); 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 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)Execute, (Func>)Suggest, (Func)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 Suggest(bool isDebugConsole, string partial, string[] args) { List list = new List(); List list2 = new List(); 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 Names = new List(); public int Price; public CombinedSuggestEntry(string name, int price) { Names = new List(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.SetEffects(); } } } [HarmonyPatch(typeof(EnemyDuck))] internal static class EnemyDuckPatch { public static List DucksToBypassStunAggroOnce = new List(); public static void Reset() { DucksToBypassStunAggroOnce = new List(); } [HarmonyPatch("StateStun")] [HarmonyTranspiler] private static IEnumerable StateStunTranspiler(IEnumerable 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 list = new List(); 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 FansToBypassIdle = new List(); [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 IgnorePhysGrabObjects = new List(); [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() : ((Component)newMagnetTarget).GetComponent()); 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(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(ref val)) { return false; } return itemDrone.itemAttributes.itemName == val.itemName; } } [HarmonyPatch(typeof(ItemRubberDuck))] internal static class ItemRubberDuckPatch { public static List SpecialRubberDucks = new List(); [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(NetworkConnect))] internal static class NetworkConnect_Patches { [HarmonyPatch("OnJoinedRoom")] [HarmonyPostfix] private static void OnJoinedRoom_Patch() { PageManager.UpdatePage(); } } [HarmonyPatch(typeof(NetworkManager))] internal static class NetworkManager_Patches { [HarmonyPatch("LeavePhotonRoom")] [HarmonyPostfix] private static void LeavePhotonRoom_Patch() { PageManager.UpdatePage(); } } [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(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> _audioPlayerPool = new Dictionary>(); 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(audioPrefab); ((Object)val).name = $"AudioPlayer {Type}"; AudioPlayer audioPlayer = val.AddComponent(); 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(); _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 Enabled { get; private set; } public ConfigEntry SpawnCount { get; private set; } public ConfigEntry BitsToSpawn { get; private set; } public ConfigEntry 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(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(1, 20)); BitsToSpawn = EnemyConfigManager.ConfigFile.Bind(text, "BitsToSpawn", _defaultValues.BitsToSpawn, "The amount of bits to spawn " + EnemyName + ".", (AcceptableValueBase)(object)new AcceptableValueRange(1, 1000)); SubsToSpawn = EnemyConfigManager.ConfigFile.Bind(text, "SubsToSpawn", _defaultValues.SubsToSpawn, "The amount of subs to spawn " + EnemyName + ".", (AcceptableValueBase)(object)new AcceptableValueRange(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 EffectPayload GetEffectPayload() { int num = 1; int value = SpawnCount.Value; if (EnemyName.Equals("Banger", StringComparison.OrdinalIgnoreCase)) { num = 3; } if (EnemyName.Equals("Gnome", StringComparison.OrdinalIgnoreCase)) { num = 4; } int value2 = num * value; return new EffectPayload { Type = EffectType.Enemy, Name = EnemyName, IsEnabled = Enabled.Value, SpawnCount = value2, BitPrice = BitsToSpawn.Value, SubPrice = SubsToSpawn.Value }; } } [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(); } [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(); 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(string key, T defaultValue = default(T), bool readFile = false) { if (TryLoad(key, out var value, readFile)) { return value; } return defaultValue; } public bool TryLoad(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(); return true; } catch (JsonException ex) { JsonException ex2 = ex; Logger.LogError("Load: JSON Conversion Error for key: " + key + ". " + ((Exception)(object)ex2).Message); } catch (ArgumentNullException ex3) { Logger.LogError("Load: Argument Null Error for key: " + key + ". " + ex3.Message); } catch (Exception ex4) { Logger.LogError("Load: Unexpected Error for key: " + key + ". " + ex4.Message); } return false; } Logger.LogWarning("Load: Key '" + key + "' does not exist. Returning default value.", extended: true); return false; } public bool Save(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; } } public bool Delete(string key) { if (_data == null) { Logger.LogError("Delete: Data is null. Cannot delete key: " + key + "."); return false; } if (_data.Remove(key)) { return WriteFile(_data); } Logger.LogWarning("Delete: Key '" + key + "' does not exist. No action taken.", extended: true); 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 ex) { JsonException ex2 = ex; Logger.LogError("ReadFile: JSON Parsing Error for file: \"" + FilePath + "\". " + ((Exception)(object)ex2).Message); } catch (Exception ex3) { Logger.LogError("ReadFile: Unexpected Error for file: \"" + FilePath + "\". " + ex3.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 : ObservableValue { 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(Key, out value, ReadFile); } private void Save(T value) { if (!object.Equals(value, base.Value)) { JsonSave.Save(Key, value); } } } internal class ObservableValue { protected T _value; protected Func CustomValueGetter; protected Action CustomValueSetter; public T Value { get { return GetValue(); } set { SetValue(value); } } public event Action 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 : JsonConverter { public override bool CanConvert(Type objectType) { return objectType == typeof(Queue); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { Queue source = (Queue)value; serializer.Serialize(writer, (object)source.ToList()); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { List collection = serializer.Deserialize>(reader); return new Queue(collection); } } } namespace com.github.zehsteam.TwitchTrolling.MonoBehaviours { public enum AudioPlayerType { Default, EnemySpawn } public class AudioPlayer : MonoBehaviour { 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(); } 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; } private IEnumerator PoolAfterDurationCoroutine(TimeSpan duration) { yield return (object)new WaitForSeconds((float)duration.TotalSeconds); AudioPlayerFactory.AddToPool(this); } 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 { private static CoroutineRunner _instance; 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(); } 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 { [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 ? "" : string.Empty); string message = ("You died to a " + enemyParent.enemyName + " 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 ? "" : string.Empty); string message = ("You died to a " + text + " from " + viewerData.GetDisplayNameWithColor() + " " + text2).Trim(); Show(message); } } public void ShowForExplosion(ViewerData viewerData, string sourceName = "") { if (viewerData != null) { string text = (ShowPlatformIcon ? "" : string.Empty); string text2 = ((!string.IsNullOrEmpty(sourceName)) ? ("" + sourceName + " (Explosion)") : "explosion"); 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); } private IEnumerator ShowCoroutine(TimeSpan duration) { _canvasGroup.alpha = 1f; yield return (object)new WaitForSeconds((float)duration.TotalSeconds); float fadeOutDuration = 1f; for (float timer = 0f; timer < fadeOutDuration; timer += Time.deltaTime) { float num = 1f / fadeOutDuration * timer; float alpha = 1f + -1f * num; _canvasGroup.alpha = alpha; yield return null; } _canvasGroup.alpha = 0f; _showCoroutine = null; } } 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 Instances { get; private set; } = new List(); public static bool ShowPlatformIcon => ConfigManager.EnemyNametag_ShowPlatformIcon.Value; public static float SizeMultiplier => ConfigManager.EnemyNametag_SizeMultiplier.Value; public static int BackgroundTransparency => ConfigManager.EnemyNametag_BackgroundTransparency.Value; public EnemyParent EnemyParent { get; private set; } public ViewerData Viewer { get; private set; } private void OnEnable() { Instances.AddSingleInstance(this); } private void OnDisable() { Instances.Remove(this); } public void SetData(EnemyParent enemyParent, ViewerData viewerData) { EnemyParent = enemyParent; Viewer = viewerData; if (IsEnemyTypeElsa()) { _enemyScript = ((Component)enemyParent).GetComponentInChildren(true); _continuouslyCalculatePosition = true; } if (IsEnemyTypeOogly()) { _enemyScript = ((Component)enemyParent).GetComponentInChildren(true); _continuouslyCalculatePosition = true; } } private void Start() { if ((Object)(object)EnemyParent == (Object)null) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } _rectTransform = ((Component)this).GetComponent(); _enemyTransform = GetEnemyTransform(); bool flag = false; if (IsEnemyTypePeeper()) { flag = true; ((Transform)_rectTransform).SetParent(((Component)EnemyParent.Enemy).transform); } if (!flag) { ((Transform)_rectTransform).SetParent(_enemyTransform); } CalculatePosition(); UseConfigSettings(); } private void Update() { if ((Object)(object)EnemyParent == (Object)null) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } if (!IsEnemyEnabled()) { _canvasGroup.alpha = 0f; return; } if (IsEnemyTypeHidden()) { Update_HiddenEnemy(); } else { _canvasGroup.alpha = 1f; } if (_continuouslyCalculatePosition) { _continuouslyCalculatePositionTimer += Time.deltaTime; if (_continuouslyCalculatePositionTimer >= _continuouslyCalculatePositionCooldown) { CalculatePosition(); _continuouslyCalculatePositionTimer = 0f; } } } private void Update_HiddenEnemy() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) float alpha = 0f; if (TryGetEnemyTransform(out var transform)) { Vector3 origin = transform.position + new Vector3(0f, 1f, 0f); if (PlayerHelper.AnyPlayersNearby(origin, 5f)) { alpha = 1f; } } _canvasGroup.alpha = alpha; } private void LateUpdate() { LookAtLocalCamera(); } private bool IsEnemyTypeHidden() { return EnemyParent.enemyName.Equals("Hidden", StringComparison.OrdinalIgnoreCase); } private bool IsEnemyTypePeeper() { return EnemyParent.enemyName.Equals("Peeper", StringComparison.OrdinalIgnoreCase); } private bool IsEnemyTypeElsa() { return EnemyParent.enemyName.Equals("Elsa", StringComparison.OrdinalIgnoreCase); } private bool IsEnemyTypeOogly() { return EnemyParent.enemyName.Equals("Oogly", StringComparison.OrdinalIgnoreCase); } private bool IsEnemyEnabled() { return EnemyParent.EnableObject.activeSelf; } private Transform GetEnemyTransform() { if ((Object)(object)EnemyParent == (Object)null || (Object)(object)EnemyParent.EnableObject == (Object)null) { return null; } EnemyRigidbody componentInChildren = EnemyParent.EnableObject.GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null) { return ((Component)componentInChildren).transform; } return ((Component)EnemyParent).transform; } private bool TryGetEnemyTransform(out Transform transform) { transform = GetEnemyTransform(); return (Object)(object)transform != (Object)null; } private void LookAtLocalCamera() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) PlayerAvatar localPlayer = PlayerHelper.GetLocalPlayer(); if (!((Object)(object)localPlayer == (Object)null)) { ((Component)this).transform.LookAt(((Component)this).transform.position + ((Component)localPlayer.localCamera).transform.forward); } } private void CalculatePosition() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) if (IsEnemyTypePeeper()) { ((Transform)_rectTransform).localPosition = new Vector3(0f, 0f, 0.85f); return; } Transform val = _enemyTransform; if (IsEnemyTypeElsa() && _enemyScript != null) { object enemyScript = _enemyScript; EnemyElsa val2 = (EnemyElsa)((enemyScript is EnemyElsa) ? enemyScript : null); if (val2 != null && !val2.IsBig()) { val = val2.smallColliderTransform; } } if (IsEnemyTypeOogly() && _enemyScript != null) { object enemyScript2 = _enemyScript; EnemyOogly val3 = (EnemyOogly)((enemyScript2 is EnemyOogly) ? enemyScript2 : null); if (val3 != null && (Object)(object)val3.targetPlayer == (Object)null) { ((Transform)_rectTransform).localPosition = new Vector3(0f, -1.5f, 0f); return; } } Collider[] componentsInChildren = ((Component)val).GetComponentsInChildren(); if (componentsInChildren == null || componentsInChildren.Length == 0) { Logger.LogWarning("EnemyNametag: No colliders found on the enemy."); return; } float num = float.MinValue; Collider[] array = componentsInChildren; foreach (Collider val4 in array) { if (!val4.isTrigger) { Bounds bounds = val4.bounds; float y = ((Bounds)(ref bounds)).max.y; if (y > num) { num = y; } } } float num2 = num + _heightOffset; Vector3 localPosition = default(Vector3); ((Vector3)(ref localPosition))..ctor(0f, num2 - _enemyTransform.position.y, 0f); ((Transform)_rectTransform).localPosition = localPosition; } public void CalculateScale() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) Collider[] componentsInChildren = ((Component)_enemyTransform).GetComponentsInChildren(true); if (componentsInChildren == null || componentsInChildren.Length == 0) { Logger.LogWarning("EnemyNametag: No colliders found on the enemy."); return; } Bounds bounds = componentsInChildren[0].bounds; Collider[] array = componentsInChildren; foreach (Collider val in array) { if (!val.isTrigger) { ((Bounds)(ref bounds)).Encapsulate(val.bounds); } } Vector3 size = ((Bounds)(ref bounds)).size; float num = ((Vector3)(ref size)).magnitude * 0.5f; num = Mathf.Clamp(num, _minSize, _maxSize); ((Component)this).transform.localScale = Vector3.one * num * SizeMultiplier; } private void UpdateNametagText() { if (Viewer != null) { ((TMP_Text)_usernameText).text = (GetPlatformSpriteText() + " " + Viewer.DisplayName).Trim(); } } public string GetPlatformSpriteText() { if (!ShowPlatformIcon) { return string.Empty; } return ""; } private void SetBackgroundTransparency(int value) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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_002c: Unknown result type (might be due to invalid IL or missing references) Color32 val = Color32.op_Implicit(((Graphic)_backgroundImage).color); val.a = (byte)Mathf.Clamp(value, 0, 255); ((Graphic)_backgroundImage).color = Color32.op_Implicit(val); } private void UseConfigSettings() { UpdateNametagText(); SetBackgroundTransparency(BackgroundTransparency); CalculateScale(); } public static void OnConfigSettingsChanged() { foreach (EnemyNametag instance in Instances) { instance.UseConfigSettings(); } } } public class IgnoreItemDrone : MonoBehaviour { private PhysGrabObject _physGrabObject; private void Awake() { _physGrabObject = ((Component)this).GetComponent(); if ((Object)(object)_physGrabObject == (Object)null) { Object.Destroy((Object)(object)this); } } private void OnEnable() { if (!((Object)(object)_physGrabObject == (Object)null)) { ItemDronePatch.IgnorePhysGrabObjects.AddSingleInstance(_physGrabObject); } } private void OnDisable() { if (!((Object)(object)_physGrabObject == (Object)null)) { ItemDronePatch.IgnorePhysGrabObjects.Remove(_physGrabObject); } } } public class MessageItem : MonoBehaviour { [SerializeField] private TextMeshProUGUI _textUGUI; [SerializeField] private Image _backgroundImage; [SerializeField] private CanvasGroup _canvasGroup; private Coroutine _playAnimationCoroutine; public static List Instances { get; private set; } = new List(); public static float Duration => ConfigManager.Message_Duration.Value; public static float FontSize => ConfigManager.Message_FontSize.Value; public static int BackgroundTransparency => ConfigManager.Message_BackgroundTransparency.Value; private void OnEnable() { Instances.AddSingleInstance(this); UseConfigSettings(); if (_playAnimationCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_playAnimationCoroutine); } _playAnimationCoroutine = ((MonoBehaviour)this).StartCoroutine(PlayAnimationCoroutine()); } private void OnDisable() { Instances.Remove(this); if (_playAnimationCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_playAnimationCoroutine); } } private IEnumerator PlayAnimationCoroutine() { _canvasGroup.alpha = 1f; yield return (object)new WaitForSeconds(Duration); float fadeOutDuration = 1f; for (float timer = 0f; timer < fadeOutDuration; timer += Time.deltaTime) { float num = 1f / fadeOutDuration * timer; float alpha = 1f + -1f * num; _canvasGroup.alpha = alpha; yield return null; } _canvasGroup.alpha = 0f; yield return null; ((Component)this).gameObject.SetActive(false); _playAnimationCoroutine = null; } public void SetText(string message) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) SetText(message, Color.white); } public void SetText(string message, Color color) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) ((TMP_Text)_textUGUI).text = message.Trim(); ((Graphic)_textUGUI).color = color; } private void UseConfigSettings() { ((TMP_Text)_textUGUI).fontSize = FontSize; _backgroundImage.SetAlpha(BackgroundTransparency); } public static void OnConfigSettingsChanged() { foreach (MessageItem instance in Instances) { instance.UseConfigSettings(); } } } public class MessageManager : MonoBehaviour { [SerializeField] private RectTransform _messageListTransform; [SerializeField] public RectTransform _messageItemPrefab; private readonly Queue _pool = new Queue(); private readonly int _poolSize = 30; public static MessageManager Instance { get; private set; } public static bool IsEnabled => ConfigManager.Message_Enabled.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() { CreatePool(); } private void CreatePool() { for (int i = 0; i < _poolSize; i++) { RectTransform val = Object.Instantiate(_messageItemPrefab); ((Transform)val).SetParent((Transform)(object)_messageListTransform); ((Component)val).gameObject.SetActive(false); _pool.Enqueue(val); } } public void ShowSpawnEnemyMessage(ViewerSpawnData viewerSpawnData) { string text = ((!string.IsNullOrEmpty(viewerSpawnData.TargetEnemyName)) ? viewerSpawnData.TargetEnemyName : ((viewerSpawnData.TotalSpawnCount <= 1) ? "random enemy" : "random enemies")); string displayNameWithColor = viewerSpawnData.Viewer.GetDisplayNameWithColor(); string message = $"{displayNameWithColor} spawned {viewerSpawnData.TotalSpawnCount}x {text} {viewerSpawnData.SpawnReason}"; ShowMessage(message); } public void ShowExecuteMEventMessage(ViewerData viewerData, MEvent mEvent) { ShowExecuteMEventMessage(viewerData, mEvent, mEvent.BitsPrice.Value); } public void ShowExecuteMEventMessage(ViewerData viewerData, MEvent mEvent, int bitsPaid) { string displayNameWithColor = viewerData.GetDisplayNameWithColor(); string message = $"{displayNameWithColor} triggered {mEvent.Name} by cheering {bitsPaid} bits"; ShowMessage(message); } public void ShowMessage(string message) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) ShowMessage(message, Color.white); } public void ShowMessage(string message, Color color) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) if (IsEnabled) { SpawnMessageItemFromPool(message, color); } } private RectTransform SpawnMessageItemFromPool(string text, Color color) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) if (_pool.Count == 0) { Logger.LogError("MessageManager: Failed to spawn MessageItem from pool. MessageItem pool is empty."); return null; } RectTransform val = _pool.Dequeue(); if ((Object)(object)val == (Object)null) { return null; } ((Component)val).gameObject.SetActive(false); ((Component)val).gameObject.SetActive(true); ((Transform)val).SetAsLastSibling(); MessageItem messageItem = default(MessageItem); if (((Component)val).TryGetComponent(ref messageItem)) { messageItem.SetText(text, color); } _pool.Enqueue(val); return val; } } public class PluginHUD : MonoBehaviour { public static PluginHUD Instance { get; private set; } public static void Spawn(Transform parent) { if (!((Object)(object)Instance != (Object)null)) { Object.Instantiate(Assets.PluginHUDPrefab, parent); } } private void Awake() { if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } Instance = this; ((Object)((Component)this).gameObject).name = "TwitchTrolling HUD"; Logger.LogInfo("Instantiated \"" + ((Object)((Component)this).gameObject).name + "\"", extended: true); } } public class PluginManager : MonoBehaviour { public Transform AudioPlayerContainerTransform; public static PluginManager Instance { get; private set; } public static void Spawn() { //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) if (!((Object)(object)Instance != (Object)null)) { GameObject val = Object.Instantiate(Assets.PluginManagerPrefab); val.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); ((Object)val).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); return; } Instance = this; ((Object)((Component)this).gameObject).name = "TwitchTrolling Manager"; Logger.LogInfo("Instantiated \"" + ((Object)((Component)this).gameObject).name + "\"", extended: true); } } public class TruckProps : MonoBehaviour { [SerializeField] private Transform _modCreditsPositionTransform; public static TruckProps Instance { get; private set; } private void Awake() { if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } Instance = this; ((Object)((Component)this).gameObject).name = "TwitchTrolling TruckProps"; Logger.LogInfo("Instantiated \"" + ((Object)((Component)this).gameObject).name + "\"", extended: true); } private void Start() { SpawnModCredits(); } private void SpawnModCredits() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.IsMasterClientOrSingleplayer() && !((Object)(object)_modCreditsPositionTransform == (Object)null)) { Vector3 position = _modCreditsPositionTransform.position; Quaternion rotation = _modCreditsPositionTransform.rotation; NetworkPrefabs.SpawnNetworkPrefab(Assets.ModCreditsPrefabRef, position, rotation, (byte)0, (object[])null); } } } } namespace com.github.zehsteam.TwitchTrolling.MEvents { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] public class MEventRegisterAttribute : Attribute { } public static class MEventManager { public static readonly List Events = new List(); public static bool Enabled => ConfigManager.Event_Enabled.Value; public static List EnabledEvents => Events.Where((MEvent x) => x.Enabled.Value).ToList(); public static ConfigFile ConfigFile => ConfigManager.ConfigFile; internal static void Initialize() { IEnumerable enumerable = from type in AccessTools.AllTypes() where type.IsClass && !type.IsAbstract && type.IsSubclassOf(typeof(MEvent)) && type.HasCustomAttribute() select type; foreach (Type item in enumerable) { if (Activator.CreateInstance(item) is MEvent mEvent) { RegisterEvent(mEvent); } } } public static void RegisterEvent(MEvent mEvent) { if (mEvent == null) { Logger.LogError("MEventManager: Failed to register event. MEvent is null."); return; } if (Events.Contains(mEvent)) { Logger.LogError("MEventManager: Failed to register event \"" + mEvent.Name + "\". There is already an event registered with the same name."); return; } mEvent.InitializeInternal(ConfigFile); Events.Add(mEvent); Logger.LogInfo("MEventManager: Registered event \"" + mEvent.Name + "\"", extended: true); } public static bool HasEvents() { return EnabledEvents.Count > 0; } public static bool TryGetEvents(int bitsPrice, out List mEvents) { mEvents = Events.Where((MEvent x) => x.IsMatch(bitsPrice)).ToList(); return mEvents.Count != 0; } public static bool TryGetEvent(int bitsPrice, out MEvent mEvent) { if (!TryGetEvents(bitsPrice, out var mEvents)) { mEvent = null; return false; } mEvent = mEvents[Random.Range(0, mEvents.Count)]; return true; } public static bool TryGetRandomEvent(out MEvent mEvent) { if (EnabledEvents.Count == 0) { mEvent = null; return false; } mEvent = EnabledEvents[Random.Range(0, EnabledEvents.Count)]; return mEvent != null; } public static MEventSFX GetEventSFX(string eventName) { return Assets.MEventSFXList?.GetEventSFX(eventName) ?? null; } public static bool TryGetEventSFX(string eventName, out MEventSFX eventSFX) { eventSFX = GetEventSFX(eventName); return eventSFX != null; } public static List GetEffectsPayload() { List list = new List(); EffectPayload item = new EffectPayload { Type = EffectType.Event, Name = "Random Event", IsEnabled = ConfigManager.Event_EnableBitsForRandomEvent.Value, BitPrice = ConfigManager.Event_BitsForRandomEvent.Value }; list.Add(item); foreach (MEvent @event in Events) { list.Add(@event.GetEffectPayload()); } return list; } } [Serializable] public class MEventSFX { public string EventName; [FormerlySerializedAs("MainAudioClip")] public AdvancedSFX MainSFX; public AdvancedSFXWithName[] AdditionalSFXList = Array.Empty(); public AudioClip MainAudioClip => MainSFX?.AudioClip ?? null; public AudioClip GetAdditionalAudioClip(string name) { return AdditionalSFXList.FirstOrDefault((AdvancedSFXWithName x) => x.Name.Equals(name, StringComparison.OrdinalIgnoreCase))?.AudioClip ?? null; } public bool TryGetAdditionalAudioClip(string name, out AudioClip audioClip) { audioClip = GetAdditionalAudioClip(name); return (Object)(object)audioClip != (Object)null; } } [Serializable] public class AdvancedSFXWithName : AdvancedSFX { public string Name; } [Serializable] public class AdvancedSFX { [SerializeField] private AudioClip _audioClip; [Range(0f, 3f)] public float VolumeMultiplier = 1f; private readonly Dictionary _cachedAudioClips = new Dictionary(); public AudioClip AudioClip { get { return GetAudioClip(); } set { _audioClip = value; } } public bool HasAudioClip => (Object)(object)AudioClip != (Object)null; public float Length { get { AudioClip audioClip = AudioClip; if (audioClip == null) { return 0f; } return audioClip.length; } } private AudioClip GetAudioClip() { if (VolumeMultiplier == 1f) { return _audioClip; } if (_cachedAudioClips.TryGetValue(VolumeMultiplier, out var value)) { return value; } value = AudioClipUtils.ScaleVolume(_audioClip, VolumeMultiplier); _cachedAudioClips[VolumeMultiplier] = value; return value; } } [CreateAssetMenu(fileName = "MEventSFXList", menuName = "TwitchTrolling/MEventSFXList")] public class MEventSFXList : ScriptableObject { public MEventSFX[] List = Array.Empty(); public MEventSFX GetEventSFX(string eventName) { return List.FirstOrDefault((MEventSFX x) => x.EventName.Equals(eventName, StringComparison.OrdinalIgnoreCase)); } public bool TryGetEventSFX(string eventName, out MEventSFX eventSFX) { eventSFX = GetEventSFX(eventName); return eventSFX != null; } } } namespace com.github.zehsteam.TwitchTrolling.MEvents.Events { [MEventRegister] internal class AggroBeaconEvent : MEvent { public override string Name => "Aggro Beacon"; public override bool EnabledByDefault => true; public override int DefaultBitsPrice => 133; public override int DefaultEventSFXVolume => 200; public ConfigEntry Duration { get; private set; } public ConfigEntry Pulses { get; private set; } public ConfigEntry Radius { get; private set; } protected override void RegisterConfigs(ConfigFile configFile) { Duration = configFile.Bind(base.ConfigSection, "Duration", 10f, "", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 30f)); Pulses = configFile.Bind(base.ConfigSection, "Pulses", 10, "", (AcceptableValueBase)(object)new AcceptableValueRange(1, 100)); Radius = configFile.Bind(base.ConfigSection, "Radius", 100f, "", (AcceptableValueBase)(object)new AcceptableValueRange(10f, 250f)); } protected override void Execute(ViewerData viewerData, PlayerAvatar targetPlayerAvatar) { StartCoroutine(BeaconCoroutine(targetPlayerAvatar)); } private IEnumerator BeaconCoroutine(PlayerAvatar targetPlayerAvatar) { Vector3 position = ((Component)targetPlayerAvatar).transform.position; float value = Duration.Value; int pulses = Pulses.Value; float radius = Radius.Value; float timeBetweenPulses = value / (float)pulses; for (int i = 0; i < pulses; i++) { EnemyDirector instance = EnemyDirector.instance; if (instance != null) { instance.SetInvestigate(position, radius, false); } yield return (object)new WaitForSeconds(timeBetweenPulses); } } protected override int? GetSpawnCount() { return null; } } [MEventRegister] internal class AnimalCrateEvent : MEventPhysTrapDrop { private PrefabRef _valuableObjectRef; public override string Name => "Animal Crate"; public override bool EnabledByDefault => true; public override int DefaultBitsPrice => 257; public override int DefaultEventSFXVolume => 200; public override float DefaultDuration => 30f; public override int DefaultSpawnCount => 3; public override float DefaultRadius => 3f; public override bool DefaultGrabbable => true; protected override void Execute(ViewerData viewerData, PlayerAvatar targetPlayerAvatar) { if (_valuableObjectRef == null) { _valuableObjectRef = ValuableHelper.GetValuableByName("Valuable Manor Animal Crate"); } base.Execute(viewerData, targetPlayerAvatar); } public override GameObject SpawnPhysObject(Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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) //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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) position += new Vector3(0f, 2.239f, 1.214f); Quaternion val = Quaternion.Euler(180f, 0f, 0f); return Valuables.SpawnValuable(_valuableObjectRef, position, val); } protected override IEnumerator PhysObjectCoroutine(PhysGrabObject physGrabObject) { yield return base.PhysObjectCoroutine(physGrabObject); AnimalCrateTrap val = default(AnimalCrateTrap); if (((Component)physGrabObject).TryGetComponent(ref val)) { val.TrapActivate(); } } } [MEventRegister] internal class BottleEvent : MEventPhysTrapDrop { private PrefabRef _valuableObjectRef; public override string Name => "Bottle"; public override bool EnabledByDefault => true; public override int DefaultBitsPrice => 111; public override int DefaultEventSFXVolume => 200; public override float DefaultDuration => 15f; public override int DefaultSpawnCount => 13; public override float DefaultRadius => 3f; public override bool DefaultGrabbable => true; protected override void Execute(ViewerData viewerData, PlayerAvatar targetPlayerAvatar) { if (_valuableObjectRef == null) { _valuableObjectRef = ValuableHelper.GetValuableByName("Valuable Manor Bottle"); } base.Execute(viewerData, targetPlayerAvatar); } public override GameObject SpawnPhysObject(Vector3 position) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) return Valuables.SpawnValuable(_valuableObjectRef, position, Random.rotation); } } [MEventRegister] internal class ChompBookEvent : MEventPhysTrapDrop { private PrefabRef _valuableObjectRef; public override string Name => "Chomp Book"; public override bool EnabledByDefault => true; public override int DefaultBitsPrice => 233; public override int DefaultEventSFXVolume => 200; public override float DefaultDuration => 15f; public override int DefaultSpawnCount => 1; public override float DefaultRadius => 3f; public override bool DefaultGrabbable => true; protected override void Execute(ViewerData viewerData, PlayerAvatar targetPlayerAvatar) { if (_valuableObjectRef == null) { _valuableObjectRef = ValuableHelper.GetValuableByName("Valuable Wizard Chomp Book"); } base.Execute(viewerData, targetPlayerAvatar); } public override GameObject SpawnPhysObject(Vector3 position) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) return Valuables.SpawnValuable(_valuableObjectRef, position, Random.rotation); } } [MEventRegister] internal class ClownEvent : MEventPhysObjectDrop { private PrefabRef _valuableObjectRef; public override string Name => "Clown"; public override bool EnabledByDefault => true; public override int DefaultBitsPrice => 254; public override int DefaultEventSFXVolume => 200; public override float DefaultDuration => 60f; public override int DefaultSpawnCount => 3; public override float DefaultRadius => 2.5f; public override bool DefaultGrabbable => true; public override void Initialize() { base.Initialize(); HasDuration = false; } protected override void Execute(ViewerData viewerData, PlayerAvatar targetPlayerAvatar) { if (_valuableObjectRef == null) { _valuableObjectRef = ValuableHelper.GetValuableByName("Valuable Manor Clown"); } base.Execute(viewerData, targetPlayerAvatar); } public override GameObject SpawnPhysObject(Vector3 position) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) return Valuables.SpawnValuable(_valuableObjectRef, position, Random.rotation); } protected override IEnumerator PhysObjectCoroutine(PhysGrabObject physGrabObject) { yield return null; ClownTrap val = default(ClownTrap); if (((Component)physGrabObject).TryGetComponent(ref val)) { val.WarningCount = 0; val.TouchNose(); } } } [MEventRegister] internal class DuctTapedGrenadesEvent : MEventPhysItemDrop { private Item _item; public override string Name => "Duct Taped Grenades"; public override bool EnabledByDefault => true; public override int DefaultBitsPrice => 255; public override int DefaultEventSFXVolume => 200; public override float DefaultDuration => 60f; public override int DefaultSpawnCount => 3; public override float DefaultRadius => 3f; public override bool DefaultGrabbable => true; public override bool DefaultEquippable => false; public override void Initialize() { base.Initialize(); HasDuration = false; } protected override void Execute(ViewerData viewerData, PlayerAvatar targetPlayerAvatar) { if (_item == null) { _item = ItemHelper.GetItemByName("Duct Taped Grenades"); } base.Execute(viewerData, targetPlayerAvatar); } public override GameObject SpawnPhysObject(Vector3 position) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) return Items.SpawnItem(_item, position, Random.rotation); } protected override IEnumerator PhysObjectCoroutine(PhysGrabObject physGrabObject) { yield return null; ItemGrenade val = default(ItemGrenade); if (((Component)physGrabObject).TryGetComponent(ref val)) { ToggleItem(val.itemToggle, value: true); } } } [MEventRegister] internal class DumgolfsStaffEvent : MEventPhysObjectDrop { private PrefabRef _valuableObjectRef; public override string Name => "Dumgolfs Staff"; public override bool EnabledByDefault => true; public override int DefaultBitsPrice => 263; public override int DefaultEventSFXVolume => 200; public override float DefaultDuration => 10f; public override int DefaultSpawnCount => 2; public override float DefaultRadius => 3f; public override bool DefaultGrabbable => true; protected override void Execute(ViewerData viewerData, PlayerAvatar targetPlayerAvatar) { if (_valuableObjectRef == null) { _valuableObjectRef = ValuableHelper.GetValuableByName("Valuable Wizard Dumgolfs Staff"); } base.Execute(viewerData, targetPlayerAvatar); } public override GameObject SpawnPhysObject(Vector3 position) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(-80f, 0f, Random.Range(0f, 360f)); return Valuables.SpawnValuable(_valuableObjectRef, position, Quaternion.Euler(val)); } protected override IEnumerator PhysObjectCoroutine(PhysGrabObject physGrabObject) { yield return null; ValuableWizardStaff val = default(ValuableWizardStaff); if (!((Object)(object)physGrabObject == (Object)null) && ((Component)physGrabObject).TryGetComponent(ref val)) { float value = base.Duration.Value; if (SemiFunc.IsMultiplayer()) { val.photonView.RPC("StaffLaserRPC", (RpcTarget)0, new object[1] { value }); } else { val.StaffLaserRPC(value, default(PhotonMessageInfo)); } } } } [MEventRegister] internal class FanEvent : MEventPhysObjectDrop { private class FanTrapBypassIdle : MonoBehaviour { private FanTrap _fanTrap; private void Awake() { _fanTrap = ((Component)this).GetComponent(); } private void OnEnable() { FanTrapPatch.FansToBypassIdle.AddSingleInstance(_fanTrap); } private void OnDisable() { FanTrapPatch.FansToBypassIdle.Remove(_fanTrap); } } private PrefabRef _valuableObjectRef; public override string Name => "Fan"; public override bool EnabledByDefault => true; public override int DefaultBitsPrice => 126; public override int DefaultEventSFXVolume => 200; public override float DefaultDuration => 15f; public override int DefaultSpawnCount => 5; public override float DefaultRadius => 3f; public override bool DefaultGrabbable => true; protected override void Execute(ViewerData viewerData, PlayerAvatar targetPlayerAvatar) { if (_valuableObjectRef == null) { _valuableObjectRef = ValuableHelper.GetValuableByName("Valuable Arctic Fan"); } base.Execute(viewerData, targetPlayerAvatar); } public override GameObject SpawnPhysObject(Vector3 position) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) return Valuables.SpawnValuable(_valuableObjectRef, position, Random.rotation); } protected override IEnumerator PhysObjectCoroutine(PhysGrabObject physGrabObject) { yield return null; FanTrap fanTrap = default(FanTrap); if ((Object)(object)physGrabObject == (Object)null || !((Component)physGrabObject).TryGetComponent(ref fanTrap)) { yield break; } ((Component)fanTrap).gameObject.AddComponent(); yield return null; fanTrap.physgrabobject.grabbed = true; fanTrap.StateActive(); for (int i = 0; (float)i < 5f; i++) { yield return (object)new WaitForSeconds(0.1f); if ((int)fanTrap.currentState != 1) { fanTrap.physgrabobject.grabbed = true; fanTrap.stateStart = true; fanTrap.currentState = (States)1; fanTrap.StateActive(); } } } } [MEventRegister] internal class FlamethrowerEvent : MEventPhysObjectDrop { private PrefabRef _valuableObjectRef; public override string Name => "Flamethrower"; public override bool EnabledByDefault => true; public override int DefaultBitsPrice => 112; public override int DefaultEventSFXVolume => 200; public override float DefaultDuration => 15f; public override int DefaultSpawnCount => 3; public override float DefaultRadius => 3f; public override bool DefaultGrabbable => true; protected override void Execute(ViewerData viewerData, PlayerAvatar targetPlayerAvatar) { if (_valuableObjectRef == null) { _valuableObjectRef = ValuableHelper.GetValuableByName("Valuable Arctic Flamethrower"); } base.Execute(viewerData, targetPlayerAvatar); } public override GameObject SpawnPhysObject(Vector3 position) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) return Valuables.SpawnValuable(_valuableObjectRef, position, Random.rotation); } protected override IEnumerator PhysObjectCoroutine(PhysGrabObject physGrabObject) { yield return null; FlamethrowerValuable val = default(FlamethrowerValuable); if (!((Object)(object)physGrabObject == (Object)null) && ((Component)physGrabObject).TryGetComponent(ref val)) { val.fuelTimer = base.Duration.Value; val.GrabTrigger(); } } } [MEventRegister] internal class FrogEvent : MEventPhysTrapDrop { private PrefabRef _valuableObjectRef; public override string Name => "Frog"; public override bool EnabledByDefault => true; public override int DefaultBitsPrice => 113; public override int DefaultEventSFXVolume => 200; public override float DefaultDuration => 15f; public override int DefaultSpawnCount => 8; public override float DefaultRadius => 3f; public override bool DefaultGrabbable => true; protected override void Execute(ViewerData viewerData, PlayerAvatar targetPlayerAvatar) { if (_valuableObjectRef == null) { _valuableObjectRef = ValuableHelper.GetValuableByName("Valuable Manor Frog"); } base.Execute(viewerData, targetPlayerAvatar); } public override GameObject SpawnPhysObject(Vector3 position) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(0f, Random.Range(0f, 360f), 0f); return Valuables.SpawnValuable(_valuableObjectRef, position, Quaternion.Euler(val)); } } [MEventRegister] internal class IceSawEvent : MEventPhysTrapDrop { private PrefabRef _valuableObject; public override string Name => "Ice Saw"; public override bool EnabledByDefault => true; public override int DefaultBitsPrice => 114; public override int DefaultEventSFXVolume => 200; public override float DefaultDuration => 15f; public override int DefaultSpawnCount => 3; public override float DefaultRadius => 3f; public override bool DefaultGrabbable => true; protected override void Execute(ViewerData viewerData, PlayerAvatar targetPlayerAvatar) { if (_valuableObject == null) { _valuableObject = ValuableHelper.GetValuableByName("Valuable Arctic Ice Saw"); } base.Execute(viewerData, targetPlayerAvatar); } public override GameObject SpawnPhysObject(Vector3 position) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) return Valuables.SpawnValuable(_valuableObject, position, Random.rotation); } } [MEventRegister] internal class MinefieldEvent : MEventMinefield { private Item _item; public override string Name => "Minefield"; public override bool EnabledByDefault => true; public override int DefaultBitsPrice => 455; public override int DefaultEventSFXVolume => 200; public override int DefaultMaxSpawnCount => 10; public override float DefaultRadius => 10f; public override float DefaultSpacing => 2.699999f; public ConfigEntry Duration { get; private set; } protected override void RegisterConfigs(ConfigFile configFile) { base.RegisterConfigs(configFile); Duration = configFile.Bind(base.ConfigSection, "Duration", 30f, "", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 300f)); } protected override void Execute(ViewerData viewerData, PlayerAvatar targetPlayerAvatar) { if (_item == null) { _item = ItemHelper.GetItemByName("Explosive Mine"); } base.Execute(viewerData, targetPlayerAvatar); } public override GameObject SpawnPhysObject(Vector3 position) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) GameObject val = Items.SpawnItem(_item, position, Quaternion.identity); val.AddComponent(); ItemMine itemMine = default(ItemMine); if (val.TryGetComponent(ref itemMine)) { StartCoroutine(ActivateCoroutine(itemMine)); } return val; } private IEnumerator ActivateCoroutine(ItemMine itemMine) { yield return null; if (!((Object)(object)itemMine == (Object)null)) { itemMine.physGrabObject.grabDisableTimer = 1000f; Object.Destroy((Object)(object)itemMine.itemEquippable); ToggleItem(itemMine.itemToggle, value: true); yield return (object)new WaitForSeconds(Duration.Value); if (!((Object)(object)itemMine == (Object)null)) { itemMine.physGrabObject.DestroyPhysGrabObject(); } } } } [MEventRegister] internal class PlayerSpeedEvent : MEvent { private AudioPlayerFactory _musicAudioPlayerFactory; private Coroutine _musicCoroutine; public override string Name => "Player Speed"; public override bool EnabledByDefault => true; public override int DefaultBitsPrice => 260; public override int DefaultEventSFXVolume => 200; public ConfigEntry SpeedUpgradeLevel { get; private set; } public ConfigEntry Duration { get; private set; } public override void Initialize() { AutoPlayMainAudioClip = false; } protected override void RegisterConfigs(ConfigFile configFile) { SpeedUpgradeLevel = configFile.Bind(base.ConfigSection, "SpeedUpgradeLevel", 20, "", (AcceptableValueBase)(object)new AcceptableValueRange(1, 100)); Duration = configFile.Bind(base.ConfigSection, "Duration", 30f, "", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 300f)); } protected override void Execute(ViewerData viewerData, PlayerAvatar targetPlayerAvatar) { if ((Object)(object)PlayerAvatar.instance != (Object)(object)targetPlayerAvatar) { return; } PlayerControllerPatch.OverrideSpeed(SpeedUpgradeLevel.Value, TimeSpan.FromSeconds(Duration.Value)); if (base.EventSFX == null) { return; } if (_musicAudioPlayerFactory == null) { _musicAudioPlayerFactory = new AudioPlayerFactory { UseMode = AudioPlayerFactory.AudioUseMode.Reuse, Volume = 0.75f }; } if (_musicAudioPlayerFactory.IsPlaying) { PlayMusic(((Component)targetPlayerAvatar.localCamera).transform, TimeSpan.FromSeconds(Duration.Value)); } else if (base.EventSFX.MainSFX != null) { PlayMainAudioClip(targetPlayerAvatar); StartCoroutine(Utils.InvokeAfterDurationCoroutine(TimeSpan.FromSeconds(base.EventSFX.MainSFX.Length), delegate { PlayMusic(((Component)targetPlayerAvatar.localCamera).transform, TimeSpan.FromSeconds(Duration.Value - base.EventSFX.MainSFX.Length)); })); } } private void PlayMusic(Transform parentTransform, TimeSpan duration) { if (_musicCoroutine != null) { StopCoroutine(_musicCoroutine); } _musicCoroutine = StartCoroutine(PlayMusicCoroutine(parentTransform, duration)); } private IEnumerator PlayMusicCoroutine(Transform parentTransform, TimeSpan duration) { if (base.EventSFX != null && base.EventSFX.TryGetAdditionalAudioClip("Music", out var audioClip)) { _musicAudioPlayerFactory.Play(audioClip, parentTransform, loop: true); yield return (object)new WaitForSeconds((float)duration.TotalSeconds); _musicAudioPlayerFactory.Stop(); _musicCoroutine = null; } } protected override int? GetSpawnCount() { return null; } } [MEventRegister] internal class PropaneTankEvent : MEventPhysTrapDrop { private PrefabRef _valuableObjectRef; public override string Name => "Propane Tank"; public override bool EnabledByDefault => true; public override int DefaultBitsPrice => 204; public override int DefaultEventSFXVolume => 200; public override float DefaultDuration => 15f; public override int DefaultSpawnCount => 5; public override float DefaultRadius => 3f; public override bool DefaultGrabbable => true; protected override void Execute(ViewerData viewerData, PlayerAvatar targetPlayerAvatar) { if (_valuableObjectRef == null) { _valuableObjectRef = ValuableHelper.GetValuableByName("Valuable Arctic Propane Tank"); } base.Execute(viewerData, targetPlayerAvatar); } public override GameObject SpawnPhysObject(Vector3 position) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) return Valuables.SpawnValuable(_valuableObjectRef, position, Random.rotation); } } [MEventRegister] internal class PsychoEvent : MEventPhysTrapDrop { private PrefabRef _valuableObjectRef; public override string Name => "Psycho"; public override bool EnabledByDefault => true; public override int DefaultBitsPrice => 69; public override int DefaultEventSFXVolume => 200; public override float DefaultDuration => 30f; public override int DefaultSpawnCount => 1; public override float DefaultRadius => 3f; public override bool DefaultGrabbable => true; protected override void Execute(ViewerData viewerData, PlayerAvatar targetPlayerAvatar) { if (_valuableObjectRef == null) { _valuableObjectRef = ValuableHelper.GetValuableByName("Valuable Psycho"); } base.Execute(viewerData, targetPlayerAvatar); } public override GameObject SpawnPhysObject(Vector3 position) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(0f, Random.Range(0f, 360f), 0f); return Valuables.SpawnValuable(_valuableObjectRef, position, Quaternion.Euler(val)); } } [MEventRegister] internal class RollDroneEvent : MEventMinefield { private Item _item; public override string Name => "Roll Drone"; public override bool EnabledByDefault => true; public override int DefaultBitsPrice => 259; public override int DefaultEventSFXVolume => 200; public override int DefaultMaxSpawnCount => 20; public override float DefaultRadius => 10f; public override float DefaultSpacing => 2.5f; public ConfigEntry Duration { get; private set; } public override void Initialize() { MinDistanceFromPlayer = 0f; } protected override void RegisterConfigs(ConfigFile configFile) { base.RegisterConfigs(configFile); Duration = configFile.Bind(base.ConfigSection, "Duration", 30f, "", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 300f)); } protected override void Execute(ViewerData viewerData, PlayerAvatar targetPlayerAvatar) { if (_item == null) { _item = ItemHelper.GetItemByName("Roll Drone"); } base.Execute(viewerData, targetPlayerAvatar); } public override GameObject SpawnPhysObject(Vector3 position) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) GameObject val = Items.SpawnItem(_item, position, Random.rotation); ItemDrone itemDrone = default(ItemDrone); if (val.TryGetComponent(ref itemDrone)) { StartCoroutine(ActivateCoroutine(itemDrone)); } return val; } private IEnumerator ActivateCoroutine(ItemDrone itemDrone) { yield return null; if (!((Object)(object)itemDrone == (Object)null)) { itemDrone.itemBattery.isUnchargable = true; ItemBattery itemBattery = itemDrone.itemBattery; itemBattery.batteryLife *= 100f; ItemBattery itemBattery2 = itemDrone.itemBattery; itemBattery2.batteryLifeInt *= 100; itemDrone.physGrabObject.grabDisableTimer = 1000f; Object.Destroy((Object)(object)itemDrone.itemEquippable); ToggleItem(itemDrone.itemToggle, value: true); yield return (object)new WaitForSeconds(Duration.Value); if (!((Object)(object)itemDrone == (Object)null)) { itemDrone.physGrabObject.DestroyPhysGrabObject(); } } } } [MEventRegister] internal class RubberDuckEvent : MEventPhysItemDrop { public class ItemRubberDuckSpecial : MonoBehaviour { private ItemRubberDuck _itemRubberDuck; private void Awake() { _itemRubberDuck = ((Component)this).GetComponent(); if ((Object)(object)_itemRubberDuck == (Object)null) { Object.Destroy((Object)(object)this); } } private void OnEnable() { ItemRubberDuckPatch.SpecialRubberDucks.AddSingleInstance(_itemRubberDuck); } private void OnDisable() { ItemRubberDuckPatch.SpecialRubberDucks.Remove(_itemRubberDuck); } } private Item _item; public override string Name => "Rubber Duck"; public override bool EnabledByDefault => true; public override int DefaultBitsPrice => 256; public override int DefaultEventSFXVolume => 200; public override float DefaultDuration => 30f; public override int DefaultSpawnCount => 5; public override float DefaultRadius => 3f; public override bool DefaultGrabbable => true; public override bool DefaultEquippable => false; public ConfigEntry InitialForce { get; private set; } public ConfigEntry MinVelocity { get; private set; } protected override void RegisterConfigs(ConfigFile configFile) { base.RegisterConfigs(configFile); InitialForce = configFile.Bind(base.ConfigSection, "InitialForce", 35f, "", (AcceptableValueBase)(object)new AcceptableValueRange(10f, 200f)); MinVelocity = configFile.Bind(base.ConfigSection, "MinVelocity", 10f, "", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f)); } protected override void Execute(ViewerData viewerData, PlayerAvatar targetPlayerAvatar) { if (_item == null) { _item = ItemHelper.GetItemByName("Rubber Duck"); } base.Execute(viewerData, targetPlayerAvatar); } public override GameObject SpawnPhysObject(Vector3 position) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) GameObject val = Items.SpawnItem(_item, position, Random.rotation); val.AddComponent(); return val; } protected override IEnumerator PhysObjectCoroutine(PhysGrabObject physGrabObject) { yield return null; ItemRubberDuck itemRubberDuck = default(ItemRubberDuck); if (!((Component)physGrabObject).TryGetComponent(ref itemRubberDuck)) { yield break; } itemRubberDuck.itemBattery.isUnchargable = true; yield return (object)new WaitForSeconds(0.1f); yield return (object)new WaitForFixedUpdate(); if ((Object)(object)itemRubberDuck == (Object)null) { yield break; } float value = InitialForce.Value; Rigidbody rigidbody = itemRubberDuck.rb; Vector3 onUnitSphere = Random.onUnitSphere; rigidbody.AddForce(onUnitSphere * value, (ForceMode)1); while (true) { yield return (object)new WaitForFixedUpdate(); if (!((Object)(object)rigidbody == (Object)null)) { float value2 = MinVelocity.Value; Vector3 velocity = rigidbody.velocity; float magnitude = ((Vector3)(ref velocity)).magnitude; if (magnitude < value2) { rigidbody.velocity *= value2 - magnitude; } continue; } break; } } } [MEventRegister] internal class ZeroGravityOrbEvent : MEvent { public class ZeroGravityOrbLevitation : MonoBehaviour { public const float DefaultDuration = 4f; public const float DefaultForce = 10f; public const bool DefaultTumblePlayer = true; public const float DefaultEnemyStunDuration = 5f; public float Duration = 4f; public float Force = 10f; public bool TumblePlayer = true; public float EnemyStunDuration = 5f; private List _playerAvatars = new List(); private List _physGrabObjects = new List(); private ItemOrb _itemOrb; private float _playerForceMultiplier = 3f; private void Start() { _itemOrb = ((Component)this).GetComponent(); } private void FixedUpdate() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (_itemOrb.itemActive) { UpdateTargetsInRange(((Component)this).transform.position, _itemOrb.orbRadius); } } private void UpdateTargetsInRange(Vector3 position, float radius) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) List list = SemiFunc.PlayerGetAllPlayerAvatarWithinRange(radius, position, false, default(LayerMask)); List list2 = SemiFunc.PhysGrabObjectGetAllWithinRange(radius, position, false, default(LayerMask), (PhysGrabObject)null); _playerAvatars.RemoveAll(_playerAvatars.GetMissingFrom(list)); _physGrabObjects.RemoveAll(_physGrabObjects.GetMissingFrom(list2)); foreach (PlayerAvatar item in list) { if (_playerAvatars.AddSingleInstance(item)) { HandleTargetInRange(item); } } foreach (PhysGrabObject item2 in list2) { if (_physGrabObjects.AddSingleInstance(item2)) { HandleTargetInRange(item2); } } } private void HandleTargetInRange(PlayerAvatar playerAvatar) { if (TumblePlayer) { PlayerHelper.PlayerTumble(playerAvatar); } else { ((MonoBehaviour)this).StartCoroutine(LevitatePlayerCoroutine(playerAvatar)); } } private IEnumerator LevitatePlayerCoroutine(PlayerAvatar playerAvatar) { if (!playerAvatar.isLocal || (Object)(object)PlayerController.instance == (Object)null) { yield break; } float force = Force * _playerForceMultiplier * 3f; yield return (object)new WaitForFixedUpdate(); Rigidbody rigidbody = PlayerController.instance.rb; float timer = 0f; while (timer < Duration) { yield return (object)new WaitForFixedUpdate(); timer += Time.fixedDeltaTime; if ((Object)(object)rigidbody == (Object)null || !_playerAvatars.Contains(playerAvatar)) { break; } PlayerControllerPatch.OverrideGravity(0f, TimeSpan.FromSeconds(0.10000000149011612)); LevitateRigidbody(rigidbody, force); } PlayerControllerPatch.OverrideGravity(0f, TimeSpan.FromSeconds(1.5)); } private void HandleTargetInRange(PhysGrabObject physGrabObject) { ((MonoBehaviour)this).StartCoroutine(LevitatePhysObjectCoroutine(physGrabObject)); if (EnemyStunDuration > 0f) { StunEnemy(physGrabObject); } } private void StunEnemy(PhysGrabObject physGrabObject) { EnemyRigidbody val = default(EnemyRigidbody); if (!((Object)(object)physGrabObject == (Object)null) && physGrabObject.isEnemy && ((Component)physGrabObject).TryGetComponent(ref val)) { Enemy enemy = val.enemy; EnemyDuck item = default(EnemyDuck); if (((Component)enemy).TryGetComponent(ref item)) { EnemyDuckPatch.DucksToBypassStunAggroOnce.AddSingleInstance(item); } enemy.StateStunned.Set(EnemyStunDuration); } } private IEnumerator LevitatePhysObjectCoroutine(PhysGrabObject physGrabObject) { if ((Object)(object)physGrabObject == (Object)null) { yield break; } float timer = 0f; while (timer < Duration) { yield return (object)new WaitForFixedUpdate(); timer += Time.fixedDeltaTime; if (!((Object)(object)physGrabObject == (Object)null) && _physGrabObjects.Contains(physGrabObject)) { LevitatePhysObject(physGrabObject); continue; } break; } } private void LevitatePhysObject(PhysGrabObject physGrabObject) { if (!((Object)(object)physGrabObject == (Object)null)) { float num = Force; PlayerTumble val = default(PlayerTumble); if (((Component)physGrabObject).TryGetComponent(ref val)) { num *= _playerForceMultiplier; } LevitateRigidbody(physGrabObject.rb, num); } } private void LevitateRigidbody(Rigidbody rigidbody, float force) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0070: 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) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)rigidbody == (Object)null) && !rigidbody.isKinematic) { rigidbody.AddForce(Vector3.up * Time.fixedDeltaTime * force, (ForceMode)0); rigidbody.AddTorque(Vector3.up * Time.fixedDeltaTime * 0.2f, (ForceMode)0); rigidbody.AddTorque(Vector3.left * Time.fixedDeltaTime * 0.1f, (ForceMode)0); rigidbody.velocity = Vector3.Lerp(rigidbody.velocity, new Vector3(0f, rigidbody.velocity.y, 0f), Time.fixedDeltaTime * 2f); } } } private Item _item; private AudioPlayerFactory _musicAudioPlayerFactory; private Coroutine _musicCoroutine; public override string Name => "Zero Gravity Orb"; public override bool EnabledByDefault => true; public override int DefaultBitsPrice => 195; public override int DefaultEventSFXVolume => 200; public ConfigEntry Duration { get; private set; } public ConfigEntry Radius { get; private set; } public ConfigEntry Levitation { get; private set; } public ConfigEntry LevitationDuration { get; private set; } public ConfigEntry LevitationForce { get; private set; } public ConfigEntry LevitationTumblePlayer { get; private set; } public ConfigEntry LevitationEnemyStunDuration { get; private set; } public override void Initialize() { AutoPlayMainAudioClip = false; } protected override void RegisterConfigs(ConfigFile configFile) { Duration = configFile.Bind(base.ConfigSection, "Duration", 30f, "", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 300f)); Radius = configFile.Bind(base.ConfigSection, "Radius", 10f, "", (AcceptableValueBase)(object)new AcceptableValueRange(2f, 50f)); Levitation = configFile.Bind(base.ConfigSection, "Levitation", true, ""); LevitationDuration = configFile.Bind(base.ConfigSection, "LevitationDuration", 4f, "", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 60f)); LevitationForce = configFile.Bind(base.ConfigSection, "LevitationForce", 10f, "", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 100f)); LevitationTumblePlayer = configFile.Bind(base.ConfigSection, "LevitationTumblePlayer", true, ""); LevitationEnemyStunDuration = configFile.Bind(base.ConfigSection, "LevitationEnemyStunDuration", 5f, "", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 60f)); } protected override void Execute(ViewerData viewerData, PlayerAvatar targetPlayerAvatar) { //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) //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_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) if (_item == null) { _item = ItemHelper.GetItemByName("Zero Gravity Orb"); } Transform transform = ((Component)targetPlayerAvatar).transform; Vector3 val = transform.position + Vector3.up * 0.25f; GameObject gameObject = Items.SpawnItem(_item, val, Random.rotation); ItemOrb itemOrb = default(ItemOrb); if (gameObject.TryGetComponent(ref itemOrb)) { StartCoroutine(ActivateCoroutine(itemOrb)); } if (base.EventSFX == null) { return; } if (_musicAudioPlayerFactory == null) { _musicAudioPlayerFactory = new AudioPlayerFactory { UseMode = AudioPlayerFactory.AudioUseMode.Reuse, Volume = 0.75f }; } if (_musicAudioPlayerFactory.IsPlaying) { PlayMusic(gameObject.transform, TimeSpan.FromSeconds(Duration.Value)); } else if (base.EventSFX.MainSFX != null) { PlayMainAudioClip(targetPlayerAvatar); StartCoroutine(Utils.InvokeAfterDurationCoroutine(TimeSpan.FromSeconds(base.EventSFX.MainSFX.Length), delegate { PlayMusic(gameObject.transform, TimeSpan.FromSeconds(Duration.Value - base.EventSFX.MainSFX.Length)); })); } } private IEnumerator ActivateCoroutine(ItemOrb itemOrb) { itemOrb.orbRadius = Radius.Value; yield return null; if (!((Object)(object)itemOrb == (Object)null)) { itemOrb.itemBattery.isUnchargable = true; ItemBattery itemBattery = itemOrb.itemBattery; itemBattery.batteryLife *= 100f; ItemBattery itemBattery2 = itemOrb.itemBattery; itemBattery2.batteryLifeInt *= 100; itemOrb.physGrabObject.grabDisableTimer = 1000f; Object.Destroy((Object)(object)itemOrb.itemEquippable); ToggleItem(itemOrb.itemToggle, value: true); if (Levitation.Value) { ZeroGravityOrbLevitation zeroGravityOrbLevitation = ((Component)itemOrb).gameObject.AddComponent(); zeroGravityOrbLevitation.Duration = LevitationDuration.Value; zeroGravityOrbLevitation.Force = LevitationForce.Value; zeroGravityOrbLevitation.TumblePlayer = LevitationTumblePlayer.Value; zeroGravityOrbLevitation.EnemyStunDuration = LevitationEnemyStunDuration.Value; } yield return (object)new WaitForSeconds(Duration.Value); if (!((Object)(object)itemOrb == (Object)null)) { itemOrb.physGrabObject.DestroyPhysGrabObject(); } } } private void PlayMusic(Transform parentTransform, TimeSpan duration) { if (_musicCoroutine != null) { StopCoroutine(_musicCoroutine); } _musicCoroutine = StartCoroutine(PlayMusicCoroutine(parentTransform, duration)); } private IEnumerator PlayMusicCoroutine(Transform parentTransform, TimeSpan duration) { if (base.EventSFX != null && base.EventSFX.TryGetAdditionalAudioClip("Music", out var audioClip)) { _musicAudioPlayerFactory.MaxDistance = Mathf.Max(Radius.Value + 10f, 15f); _musicAudioPlayerFactory.Play(audioClip, parentTransform, loop: true); yield return (object)new WaitForSeconds((float)duration.TotalSeconds); _musicAudioPlayerFactory.Stop(); _musicCoroutine = null; } } protected override int? GetSpawnCount() { return 1; } } } namespace com.github.zehsteam.TwitchTrolling.MEvents.BaseEvents { public abstract class MEvent { private MEventSFX _eventSFX; protected AudioPlayerFactory AudioPlayerFactory; protected float Volume = 1f; protected bool AutoPlayMainAudioClip = true; public abstract string Name { get; } public abstract bool EnabledByDefault { get; } public abstract int DefaultBitsPrice { get; } public abstract int DefaultEventSFXVolume { get; } public string ConfigSection => "Event: " + Name; public ConfigEntry Enabled { get; private set; } public ConfigEntry BitsPrice { get; private set; } public ConfigEntry EventSFXVolume { get; private set; } protected MEventSFX EventSFX { get { if (_eventSFX == null) { _eventSFX = GetEventSFX(); } return _eventSFX; } private set { _eventSFX = value; } } public bool IsMatch(int bitsPrice) { if (!Enabled.Value) { return false; } return BitsPrice.Value == bitsPrice; } internal void InitializeInternal(ConfigFile configFile) { Enabled = configFile.Bind(ConfigSection, "Enabled", EnabledByDefault, "Enable or disable this event."); BitsPrice = configFile.Bind(ConfigSection, "BitsPrice", DefaultBitsPrice, "Bits required to trigger this event.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 1000)); EventSFXVolume = configFile.Bind(ConfigSection, "EventSFXVolume", DefaultEventSFXVolume, "The volume of the event sfx.", (AcceptableValueBase)(object)new AcceptableValueRange(100, 500)); Enabled.SettingChanged += delegate { PageManager.UpdatePage(); }; BitsPrice.SettingChanged += delegate { PageManager.UpdatePage(); }; EventSFXVolume.SettingChanged += delegate { HandleEventSFXVolumeChanged(); }; HandleEventSFXVolumeChanged(); Initialize(); RegisterConfigs(configFile); } public virtual void Initialize() { } protected virtual void RegisterConfigs(ConfigFile configFile) { } public bool ExecuteEvent(ViewerData viewerData, PlayerAvatar targetPlayerAvatar) { return ExecuteEvent(viewerData, targetPlayerAvatar, BitsPrice.Value); } public bool ExecuteEvent(ViewerData viewerData, PlayerAvatar targetPlayerAvatar, int bitsPaid) { //IL_0088: Unknown result type (might be due to invalid IL or missing references) try { if (!SemiFunc.IsMasterClientOrSingleplayer()) { throw new UnauthorizedAccessException("Only the master client (host) can execute events."); } if (AudioPlayerFactory == null) { AudioPlayerFactory = CreateAudioPlayerFactory(); } Execute(viewerData, targetPlayerAvatar); if (AutoPlayMainAudioClip) { PlayMainAudioClip(targetPlayerAvatar); } MessageManager.Instance?.ShowExecuteMEventMessage(viewerData, this, bitsPaid); return true; } catch (Exception arg) { Logger.LogError($"MEvent: Failed to trigger event {Name}. {arg}"); MessageManager.Instance?.ShowMessage("Failed to trigger event " + Name, Color.red); return false; } } protected abstract void Execute(ViewerData viewerData, PlayerAvatar targetPlayerAvatar); protected void PlayMainAudioClip(PlayerAvatar targetPlayerAvatar) { if (EventSFX == null) { return; } AudioClip mainAudioClip = EventSFX.MainAudioClip; if (!((Object)(object)mainAudioClip == (Object)null)) { if (AudioPlayerFactory == null) { AudioPlayerFactory = CreateAudioPlayerFactory(); } AudioPlayerFactory.Play(mainAudioClip, ((Component)targetPlayerAvatar.localCamera).transform); } } protected virtual MEventSFX GetEventSFX() { return MEventManager.GetEventSFX(Name); } protected virtual AudioPlayerFactory CreateAudioPlayerFactory() { return new AudioPlayerFactory { Volume = Volume }; } private void HandleEventSFXVolumeChanged() { if (EventSFX != null && EventSFX.MainSFX != null) { EventSFX.MainSFX.VolumeMultiplier = (float)EventSFXVolume.Value * 0.01f; } } protected abstract int? GetSpawnCount(); public EffectPayload GetEffectPayload() { return new EffectPayload { Type = EffectType.Event, Name = Name, IsEnabled = Enabled.Value, SpawnCount = GetSpawnCount(), BitPrice = BitsPrice.Value }; } protected Coroutine StartCoroutine(IEnumerator routine) { return CoroutineRunner.Start(routine) ?? null; } protected void StopCoroutine(Coroutine routine) { CoroutineRunner.Stop(routine); } protected void ToggleItem(ItemToggle itemToggle, bool value) { if (!((Object)(object)itemToggle == (Object)null)) { int num = -1; if ((Object)(object)PlayerAvatar.instance != (Object)null && (Object)(object)PlayerAvatar.instance.photonView != (Object)null) { num = PlayerAvatar.instance.photonView.ViewID; } itemToggle.ToggleItem(value, num); } } } public abstract class MEventMinefield : MEvent { protected float MinDistanceFromPlayer = 2f; public abstract int DefaultMaxSpawnCount { get; } public abstract float DefaultRadius { get; } public abstract float DefaultSpacing { get; } public ConfigEntry MaxSpawnCount { get; private set; } public ConfigEntry Spacing { get; private set; } protected override void RegisterConfigs(ConfigFile configFile) { MaxSpawnCount = configFile.Bind(base.ConfigSection, "MaxSpawnCount", DefaultMaxSpawnCount, "", (AcceptableValueBase)(object)new AcceptableValueRange(1, 100)); Spacing = configFile.Bind(base.ConfigSection, "Spacing", DefaultSpacing, "", (AcceptableValueBase)(object)new AcceptableValueRange(0.25f, 5f)); MaxSpawnCount.SettingChanged += delegate { PageManager.UpdatePage(); }; } protected override void Execute(ViewerData viewerData, PlayerAvatar targetPlayerAvatar) { //IL_0010: 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_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_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) if (!SemiFunc.IsMasterClientOrSingleplayer()) { return; } Transform transform = ((Component)targetPlayerAvatar).transform; Vector3 center = transform.position + Vector3.up * 1f; float value = Spacing.Value; List list = GridUtils.GenerateGridAroundPosition(center, 20f, value, MinDistanceFromPlayer); Logger.LogDebug($"MEventMinefield: Points count {list.Count}"); if (list.Count == 0) { throw new Exception("Could not find any spawn points."); } int value2 = MaxSpawnCount.Value; int num = 0; while (num < value2 && list.Count != 0) { Vector3 val = list[0]; list.RemoveAt(0); bool flag = true; for (int i = 0; i <= 6; i++) { if (!HasObjectInsidePoint(val)) { flag = false; break; } val += Vector3.up * 0.5f; } if (!flag && HasGroundBelowPoint(val) && !HasHurtColliderBelowPoint(val)) { SpawnPhysObject(val).SetViewerMetadata(viewerData); num++; } } if (num == 0) { throw new Exception("Could not spawn any objects."); } Logger.LogDebug($"MEventMinefield: Spawned {num} of {value2} objects."); } private bool HasObjectInsidePoint(Vector3 position, float radius = 0.15f) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return Physics.CheckSphere(position, radius, LayerMask.GetMask(new string[1] { "Default" }), (QueryTriggerInteraction)1); } private bool HasGroundBelowPoint(Vector3 position, float maxDistance = 20f) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) return Physics.Raycast(position, Vector3.down, maxDistance, LayerMask.GetMask(new string[1] { "Default" }), (QueryTriggerInteraction)1); } private bool HasHurtColliderBelowPoint(Vector3 position, float maxDistance = 20f) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) RaycastHit val = default(RaycastHit); HurtCollider val2 = default(HurtCollider); if (Physics.Raycast(position, Vector3.down, ref val, maxDistance, LayerMask.GetMask(new string[2] { "Default", "Triggers" }), (QueryTriggerInteraction)2)) { return ((Component)((RaycastHit)(ref val)).collider).TryGetComponent(ref val2); } return false; } public abstract GameObject SpawnPhysObject(Vector3 position); protected override int? GetSpawnCount() { return MaxSpawnCount.Value; } } public abstract class MEventPhysItemDrop : MEventPhysObjectDrop { protected bool Toggleable; public abstract bool DefaultEquippable { get; } public ConfigEntry Equippable { get; private set; } protected override void RegisterConfigs(ConfigFile configFile) { base.RegisterConfigs(configFile); Equippable = configFile.Bind(base.ConfigSection, "Equippable", DefaultEquippable, ""); } internal override IEnumerator SetPropertiesCoroutine(PhysGrabObject physGrabObject) { yield return base.SetPropertiesCoroutine(physGrabObject); bool flag = Toggleable; ItemEquippable val = default(ItemEquippable); if (Equippable.Value) { flag = true; } else if (((Component)physGrabObject).TryGetComponent(ref val)) { Object.Destroy((Object)(object)val); } ItemToggle val2 = default(ItemToggle); if (!flag && ((Component)physGrabObject).TryGetComponent(ref val2)) { ((Behaviour)val2).enabled = false; } } } public abstract class MEventPhysObjectDrop : MEvent { protected bool HasDuration = true; protected float YOffset = 1f; public abstract float DefaultDuration { get; } public abstract int DefaultSpawnCount { get; } public abstract float DefaultRadius { get; } public abstract bool DefaultGrabbable { get; } public ConfigEntry Duration { get; private set; } public ConfigEntry SpawnCount { get; private set; } public ConfigEntry Radius { get; private set; } public ConfigEntry Grabbable { get; private set; } protected override void RegisterConfigs(ConfigFile configFile) { if (HasDuration) { Duration = configFile.Bind(base.ConfigSection, "Duration", DefaultDuration, "", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 300f)); } SpawnCount = configFile.Bind(base.ConfigSection, "SpawnCount", DefaultSpawnCount, "", (AcceptableValueBase)(object)new AcceptableValueRange(1, 20)); Radius = configFile.Bind(base.ConfigSection, "Radius", DefaultRadius, "", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 10f)); Grabbable = configFile.Bind(base.ConfigSection, "Grabbable", DefaultGrabbable, ""); SpawnCount.SettingChanged += delegate { PageManager.UpdatePage(); }; } protected override void Execute(ViewerData viewerData, PlayerAvatar targetPlayerAvatar) { //IL_0031: 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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.IsMasterClientOrSingleplayer()) { Transform transform = ((Component)targetPlayerAvatar).transform; int value = SpawnCount.Value; float value2 = Radius.Value; float num = 360f / (float)value; Vector3 val = transform.position + Vector3.up * YOffset; float y = transform.eulerAngles.y; Vector3 val2 = default(Vector3); for (int i = 0; i < value; i++) { float num2 = y + (float)i * num; float num3 = num2 * (MathF.PI / 180f); ((Vector3)(ref val2))..ctor(Mathf.Sin(num3) * value2, 0f, Mathf.Cos(num3) * value2); Vector3 position = val + val2; GameObject gameObject = SpawnPhysObject(position); gameObject.SetViewerMetadata(viewerData); StartCoroutine(MainPhysObjectCoroutine(gameObject)); } } } public abstract GameObject SpawnPhysObject(Vector3 position); private IEnumerator MainPhysObjectCoroutine(GameObject gameObject) { PhysGrabObject physGrabObject = default(PhysGrabObject); if (gameObject.TryGetComponent(ref physGrabObject)) { Coroutine coroutine = StartCoroutine(PhysObjectCoroutine(physGrabObject)); StartCoroutine(SetPropertiesCoroutine(physGrabObject)); float num = (HasDuration ? Duration.Value : 10000f); yield return (object)new WaitForSeconds(num); if (coroutine != null) { StopCoroutine(coroutine); } if ((Object)(object)physGrabObject != (Object)null) { DestroyPhysObject(physGrabObject); } } } protected abstract IEnumerator PhysObjectCoroutine(PhysGrabObject physGrabObject); internal virtual IEnumerator SetPropertiesCoroutine(PhysGrabObject physGrabObject) { yield return null; if (!((Object)(object)physGrabObject == (Object)null) && !Grabbable.Value) { physGrabObject.grabDisableTimer = 10000f; } } protected virtual void DestroyPhysObject(PhysGrabObject physGrabObject) { ValuableObject val = default(ValuableObject); if (((Component)physGrabObject).TryGetComponent(ref val) && (Object)(object)physGrabObject.impactDetector != (Object)null) { physGrabObject.impactDetector.DestroyObject(true); } else { physGrabObject.DestroyPhysGrabObject(); } } protected override int? GetSpawnCount() { return SpawnCount.Value; } } public abstract class MEventPhysTrapDrop : MEventPhysObjectDrop { protected override IEnumerator PhysObjectCoroutine(PhysGrabObject physGrabObject) { yield return null; Trap val = default(Trap); if (((Component)physGrabObject).TryGetComponent(ref val)) { float value = base.Duration.Value; val.triggerOnTimer = true; SyncedEventTimer val2 = default(SyncedEventTimer); if (((Component)val).TryGetComponent(ref val2)) { val2.timerMin = value; val2.timerMax = value; } val.TrapActivateSync(); } } } } namespace com.github.zehsteam.TwitchTrolling.Managers { internal static class ConfigManager { public static ConfigFile ConfigFile { get; private set; } public static ConfigEntry Misc_ExtendedLogging { get; private set; } public static ConfigEntry TwitchIntegration_Enabled { get; private set; } public static ConfigEntry TwitchSubEvent_Enabled { get; private set; } public static ConfigEntry TwitchSubEvent_Tier1EnemySpawnCountMultiplier { get; private set; } public static ConfigEntry TwitchSubEvent_Tier2EnemySpawnCountMultiplier { get; private set; } public static ConfigEntry TwitchSubEvent_Tier3EnemySpawnCountMultiplier { get; private set; } public static ConfigEntry TwitchCheerEvent_Enabled { get; private set; } public static ConfigEntry TwitchCheerEvent_EnableBitsForRandomEnemy { get; private set; } public static ConfigEntry TwitchCheerEvent_BitsForRandomEnemy { get; private set; } public static ConfigEntry TwitchRaidEvent_Enabled { get; private set; } public static ConfigEntry TwitchRaidEvent_ViewersPerRandomEnemy { get; private set; } public static ConfigEntry TwitchRaidEvent_MaxEnemySpawnCount { get; private set; } public static ConfigEntry Enemy_Enabled { get; private set; } public static ConfigEntry Enemy_SpawnDespawned { get; private set; } public static ConfigEntry Enemy_MinSpawnDistance { get; private set; } public static ConfigEntry Enemy_MaxSpawnDistance { get; private set; } public static ConfigEntry Event_Enabled { get; private set; } public static ConfigEntry Event_EnableBitsForRandomEvent { get; private set; } public static ConfigEntry Event_BitsForRandomEvent { get; private set; } public static ConfigEntry Message_Enabled { get; private set; } public static ConfigEntry Message_Duration { get; private set; } public static ConfigEntry Message_FontSize { get; private set; } public static ConfigEntry Message_BackgroundTransparency { get; private set; } public static ConfigEntry DeathMessage_Enabled { get; private set; } public static ConfigEntry DeathMessage_ShowPlatformIcon { get; private set; } public static ConfigEntry DeathMessage_Duration { get; private set; } public static ConfigEntry DeathMessage_FontSize { get; private set; } public static ConfigEntry DeathMessage_BackgroundTransparency { get; private set; } public static ConfigEntry EnemyNametag_Enabled { get; private set; } public static ConfigEntry EnemyNametag_ShowPlatformIcon { get; private set; } public static ConfigEntry EnemyNametag_SizeMultiplier { get; private set; } public static ConfigEntry EnemyNametag_BackgroundTransparency { get; private set; } public static void Initialize(ConfigFile configFile) { ConfigFile = configFile; BindConfigs(); MigrateOldConfigEntries(); ForceEnableEnemies(); } private static void BindConfigs() { Misc_ExtendedLogging = ConfigFile.Bind("- Misc -", "ExtendedLogging", false, "Enable extended logging."); TwitchIntegration_Enabled = ConfigFile.Bind("- Twitch Integration -", "Enabled", true, "If enabled, Twitch integration will be enabled to spawn enemies from Subs, Cheers, and Raids."); TwitchIntegration_Enabled.SettingChanged += delegate { PageManager.UpdatePage(); }; TwitchSubEvent_Enabled = ConfigFile.Bind("- Twitch Sub Event -", "Enabled", true, "If enabled, Twitch subs will be able to spawn enemies."); TwitchSubEvent_Tier1EnemySpawnCountMultiplier = ConfigFile.Bind("- Twitch Sub Event -", "Tier1EnemySpawnCountMultiplier", 1, "The amount to multiply the enemy spawn count for tier 1 subs.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 30)); TwitchSubEvent_Tier2EnemySpawnCountMultiplier = ConfigFile.Bind("- Twitch Sub Event -", "Tier2EnemySpawnCountMultiplier", 5, "The amount to multiply the enemy spawn count for tier 2 subs.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 30)); TwitchSubEvent_Tier3EnemySpawnCountMultiplier = ConfigFile.Bind("- Twitch Sub Event -", "Tier3EnemySpawnCountMultiplier", 10, "The amount to multiply the enemy spawn count for tier 3 subs.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 30)); TwitchSubEvent_Enabled.SettingChanged += delegate { PageManager.UpdatePage(); }; TwitchSubEvent_Tier1EnemySpawnCountMultiplier.SettingChanged += delegate { PageManager.UpdatePage(); }; TwitchSubEvent_Tier2EnemySpawnCountMultiplier.SettingChanged += delegate { PageManager.UpdatePage(); }; TwitchSubEvent_Tier3EnemySpawnCountMultiplier.SettingChanged += delegate { PageManager.UpdatePage(); }; TwitchCheerEvent_Enabled = ConfigFile.Bind("- Twitch Cheer Event -", "Enabled", true, "If enabled, Twitch cheers will be able to spawn enemies."); TwitchCheerEvent_EnableBitsForRandomEnemy = ConfigFile.Bind("- Twitch Cheer Event -", "EnableBitsForRandomEnemy", true, "If enabled, viewers can spawn random enemies with bits."); TwitchCheerEvent_BitsForRandomEnemy = ConfigFile.Bind("- Twitch Cheer Event -", "BitsForRandomEnemy", 350, "The min amount of bits to spawn a random enemy.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 1000)); TwitchCheerEvent_Enabled.SettingChanged += delegate { PageManager.UpdatePage(); }; TwitchCheerEvent_EnableBitsForRandomEnemy.SettingChanged += delegate { PageManager.UpdatePage(); }; TwitchCheerEvent_BitsForRandomEnemy.SettingChanged += delegate { PageManager.UpdatePage(); }; TwitchRaidEvent_Enabled = ConfigFile.Bind("- Twitch Raid Event -", "Enabled", true, "If enabled, Twitch raids will be able to spawn enemies."); TwitchRaidEvent_ViewersPerRandomEnemy = ConfigFile.Bind("- Twitch Raid Event -", "ViewersPerRandomEnemy", 5, "The amount of viewers for each random enemy spawn.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 100)); TwitchRaidEvent_MaxEnemySpawnCount = ConfigFile.Bind("- Twitch Raid Event -", "MaxEnemySpawnCount", 20, "The max amount of enemies that can spawn from a raid.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 100)); TwitchRaidEvent_Enabled.SettingChanged += delegate { PageManager.UpdatePage(); }; TwitchRaidEvent_ViewersPerRandomEnemy.SettingChanged += delegate { PageManager.UpdatePage(); }; TwitchRaidEvent_MaxEnemySpawnCount.SettingChanged += delegate { PageManager.UpdatePage(); }; Enemy_Enabled = ConfigFile.Bind("- Enemy -", "Enabled", true, "If enabled, Twitch events will be able to spawn enemies."); Enemy_SpawnDespawned = ConfigFile.Bind("- Enemy -", "SpawnDespawned", false, "If enabled, enemies will spawn despawned."); Enemy_MinSpawnDistance = ConfigFile.Bind("- Enemy -", "MinSpawnDistance", 25f, "The min distance an enemy can spawn from the local player. (meters)", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f)); Enemy_MaxSpawnDistance = ConfigFile.Bind("- Enemy -", "MaxSpawnDistance", 300f, "The max distance an enemy can spawn from the local player. (meters)", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 500f)); Enemy_Enabled.SettingChanged += delegate { PageManager.UpdatePage(); }; Event_Enabled = ConfigFile.Bind("- Event -", "Enabled", true, "If enabled, Twitch cheers will be able to trigger events."); Event_EnableBitsForRandomEvent = ConfigFile.Bind("- Event -", "EnableBitsForRandomEvent", true, "If enabled, viewers can trigger random events with bits."); Event_BitsForRandomEvent = ConfigFile.Bind("- Event -", "BitsForRandomEvent", 150, "The amount of bits to trigger a random event.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 1000)); Event_Enabled.SettingChanged += delegate { PageManager.UpdatePage(); }; Event_EnableBitsForRandomEvent.SettingChanged += delegate { PageManager.UpdatePage(); }; Event_BitsForRandomEvent.SettingChanged += delegate { PageManager.UpdatePage(); }; Message_Enabled = ConfigFile.Bind("- Message -", "Enabled", true, "If enabled, will show messages in the bottom right."); Message_Duration = ConfigFile.Bind("- Message -", "Duration", 10f, "The duration of a message. (seconds)", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 60f)); Message_FontSize = ConfigFile.Bind("- Message -", "FontSize", 12, "The font size of the messages.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 50)); Message_BackgroundTransparency = ConfigFile.Bind("- Message -", "BackgroundTransparency", 192, "The transparency of the message background.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 255)); Message_FontSize.SettingChanged += delegate { MessageItem.OnConfigSettingsChanged(); }; Message_BackgroundTransparency.SettingChanged += delegate { MessageItem.OnConfigSettingsChanged(); }; DeathMessage_Enabled = ConfigFile.Bind("- Death Message -", "Enabled", true, "If enabled, will show a message when you die to an enemy spawned from a viewer."); DeathMessage_ShowPlatformIcon = ConfigFile.Bind("- Death Message -", "ShowPlatformIcon", true, "If enabled, will show which platform the enemy was spawned from."); DeathMessage_Duration = ConfigFile.Bind("- Death Message -", "Duration", 8f, "The duration of the death message. (seconds)", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 60f)); DeathMessage_FontSize = ConfigFile.Bind("- Death Message -", "FontSize", 16, "The font size of the death message.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 50)); DeathMessage_BackgroundTransparency = ConfigFile.Bind("- Death Message -", "BackgroundTransparency", 192, "The transparency of the death message background.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 255)); EnemyNametag_Enabled = ConfigFile.Bind("- Enemy Nametag -", "Enabled", true, "If enabled, enemies will spawn with a nametag of the viewer that spawned that enemy."); EnemyNametag_ShowPlatformIcon = ConfigFile.Bind("- Enemy Nametag -", "ShowPlatformIcon", true, "If enabled, nametags will show which platform the enemy was spawned from."); EnemyNametag_SizeMultiplier = ConfigFile.Bind("- Enemy Nametag -", "SizeMultiplier", 0.75f, "The size multiplier for enemy nametags.", (AcceptableValueBase)(object)new AcceptableValueRange(0.25f, 5f)); EnemyNametag_BackgroundTransparency = ConfigFile.Bind("- Enemy Nametag -", "BackgroundTransparency", 192, "The transparency of the nametag background.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 255)); EnemyNametag_ShowPlatformIcon.SettingChanged += delegate { EnemyNametag.OnConfigSettingsChanged(); }; EnemyNametag_SizeMultiplier.SettingChanged += delegate { EnemyNametag.OnConfigSettingsChanged(); }; EnemyNametag_BackgroundTransparency.SettingChanged += delegate { EnemyNametag.OnConfigSettingsChanged(); }; } private static void MigrateOldConfigEntries() { Dictionary dictionary = new Dictionary(ConfigFile.GetOrphanedConfigEntries()); foreach (KeyValuePair item in dictionary) { MigrateOldConfigEntry(item.Key, item.Value); } ConfigFile.Save(); } private static void MigrateOldConfigEntry(ConfigDefinition configDefinition, string value) { string section = configDefinition.Section; string key = configDefinition.Key; StringComparison comparisonType = StringComparison.OrdinalIgnoreCase; if (section.Equals("- Twitch Cheer Event -", comparisonType)) { if (key.Equals("MinAmountForRandomEnemy", comparisonType)) { ConfigFile.MigrateConfigEntry(configDefinition, value, TwitchCheerEvent_BitsForRandomEnemy); } } else if (section.Equals("- Event -", comparisonType) && key.Equals("AmountForRandomEvent", comparisonType)) { ConfigFile.MigrateConfigEntry(configDefinition, value, Event_BitsForRandomEvent); } } private static void ForceEnableEnemies() { string key = "ForceEnabledEnemies"; if (!Plugin.LocalSave.Load(key, defaultValue: false)) { Plugin.LocalSave.Save(key, value: true); Enemy_Enabled.Value = true; } } } internal static class EnemyConfigManager { public static ConfigFile ConfigFile => ConfigManager.ConfigFile; public static List ConfigEntries { get; private set; } = new List(); public static List EnabledConfigEntries => ConfigEntries.Where((EnemyConfigEntry x) => x.Enabled.Value).ToList(); public static void Initialize() { EnemyConfigEntryDefaultValues[] list = Assets.EnemyConfigEntryDefaultValuesList.List; foreach (EnemyConfigEntryDefaultValues defaultValues in list) { RegisterConfigEntry(defaultValues); } foreach (EnemySetup allEnemy in Enemies.AllEnemies) { if (allEnemy.TryGetEnemyName(out var enemyName)) { RegisterConfigEntry(enemyName); } } } public static void RegisterConfigEntry(string enemyName) { if (!HasConfigEntry(enemyName)) { EnemyConfigEntry item = new EnemyConfigEntry(enemyName); ConfigEntries.Add(item); } } public static void RegisterConfigEntry(EnemyConfigEntryDefaultValues defaultValues) { if (!HasConfigEntry(defaultValues.EnemyName)) { EnemyConfigEntry item = new EnemyConfigEntry(defaultValues); ConfigEntries.Add(item); } } public static bool HasEnemies() { return EnabledConfigEntries.Count > 0; } public static bool HasConfigEntry(string enemyName) { return ConfigEntries.Any((EnemyConfigEntry x) => x.EnemyNameEquals(enemyName)); } public static EnemyConfigEntry GetConfigEntry(string enemyName) { return ConfigEntries.FirstOrDefault((EnemyConfigEntry x) => x.EnemyNameEquals(enemyName)); } public static bool TryGetConfigEntry(string enemyName, out EnemyConfigEntry configEntry) { configEntry = GetConfigEntry(enemyName); return configEntry != null; } public static List GetConfigEntriesThatMatchBitsAmount(int bitsAmount, bool includeDisable = false) { List list = new List(); foreach (EnemyConfigEntry configEntry in ConfigEntries) { if ((includeDisable || configEntry.Enabled.Value) && configEntry.BitsToSpawn.Value == bitsAmount) { list.Add(configEntry); } } return list; } public static bool TryGetConfigEntriesThatMatchBitsAmount(int bitsAmount, out List list, bool includeDisable = false) { list = GetConfigEntriesThatMatchBitsAmount(bitsAmount, includeDisable); return list.Any(); } public static List GetConfigEntriesThatMatchSubsAmount(int subsAmount, bool includeDisable = false) { List list = new List(); foreach (EnemyConfigEntry configEntry in ConfigEntries) { if ((includeDisable || configEntry.Enabled.Value) && configEntry.SubsToSpawn.Value == subsAmount) { list.Add(configEntry); } } return list; } public static bool TryGetConfigEntriesThatMatchSubsAmount(int subsAmount, out List list, bool includeDisable = false) { list = GetConfigEntriesThatMatchSubsAmount(subsAmount, includeDisable); return list.Any(); } public static List GetEffectsPayload() { List list = new List(); EffectPayload item = new EffectPayload { Type = EffectType.Enemy, Name = "Random Enemy", IsEnabled = ConfigManager.TwitchCheerEvent_EnableBitsForRandomEnemy.Value, BitPrice = ConfigManager.TwitchCheerEvent_BitsForRandomEnemy.Value }; list.Add(item); foreach (EnemyConfigEntry configEntry in ConfigEntries) { list.Add(configEntry.GetEffectPayload()); } return list; } } internal static class EnemyManager { private static AudioPlayerFactory _audioPlayerFactory; public static Dictionary ViewerEnemies { get; private set; } public static bool SpawnDespawned => ConfigManager.Enemy_SpawnDespawned.Value; public static float MinSpawnDistance => ConfigManager.Enemy_MinSpawnDistance.Value; public static float MaxSpawnDistance => ConfigManager.Enemy_MaxSpawnDistance.Value; static EnemyManager() { ViewerEnemies = new Dictionary(); _audioPlayerFactory = new AudioPlayerFactory { Type = AudioPlayerType.EnemySpawn, MaxDistance = 30f }; } public static void ResetViewerEnemies() { ViewerEnemies.Clear(); } public static void SpawnEnemy(ViewerSpawnData viewerSpawnData) { if (viewerSpawnData == null) { Logger.LogError("EnemyManager: Failed to spawn enemies. ViewerSpawnData is null.", extended: false, showMessage: true); return; } if (!CanSpawnEnemies()) { Logger.LogError("EnemyManager: Failed to spawn enemies. You are not allowed to spawn enemies at this time.", extended: false, showMessage: true); return; } List entries = new List(); for (int i = 0; i < viewerSpawnData.SpawnCount; i++) { if (EnemyConfigManager.TryGetConfigEntry(viewerSpawnData.TargetEnemyName, out var configEntry)) { entries.Add(configEntry); } else { entries.Add(EnemyConfigManager.ConfigEntries.GetRandom()); } } if (entries.Count < 1) { Logger.LogError("EnemyManager: Failed to spawn enemies. No enemies where found to spawn.", extended: false, showMessage: true); return; } if (entries.All((EnemyConfigEntry x) => x == entries[0])) { viewerSpawnData.SetTargetEnemyName(entries[0].EnemyName); } int num = entries.Sum((EnemyConfigEntry x) => x.SpawnCount.Value); viewerSpawnData.SetTotalSpawnCount(num); if (num < 1) { Logger.LogError("EnemyManager: Failed to spawn enemies. Total spawn count is less than 1.", extended: false, showMessage: true); return; } foreach (EnemyConfigEntry item in entries) { SpawnEnemy(item, viewerSpawnData.Viewer); } MessageManager.Instance?.ShowSpawnEnemyMessage(viewerSpawnData); Logger.LogInfo($"\n\n{viewerSpawnData.Viewer.DisplayName} spawned {num}x enemies {viewerSpawnData.SpawnReason}\n", extended: true); } private static void SpawnEnemy(EnemyConfigEntry configEntry, ViewerData viewerData) { if (configEntry == null) { Logger.LogError("EnemyManager: Failed to spawn enemies. EnemyConfigEntry is null.", extended: false, showMessage: true); return; } if (viewerData == null) { Logger.LogError("EnemyManager: Failed to spawn enemies. ViewerData is null.", extended: false, showMessage: true); return; } string enemyName = configEntry.EnemyName; int value = configEntry.SpawnCount.Value; if (value < 1) { Logger.LogError("EnemyManager: Failed to spawn enemy \"" + enemyName + "\". Spawn count is less than 1.", extended: false, showMessage: true); return; } if (!TryGetEnemyByName(enemyName, out var enemySetup)) { Logger.LogError("EnemyManager: Failed to spawn enemy \"" + enemyName + "\". EnemySetup is null.", extended: false, showMessage: true); return; } for (int i = 0; i < value; i++) { SpawnEnemy(enemySetup, viewerData); } } private static void SpawnEnemy(EnemySetup enemySetup, ViewerData viewerData) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)enemySetup == (Object)null) { Logger.LogError("EnemyManager: Failed to spawn enemies. EnemySetup is null.", extended: false, showMessage: true); return; } if (viewerData == null) { Logger.LogError("EnemyManager: Failed to spawn enemies. ViewerData is null.", extended: false, showMessage: true); return; } EnemyParent val = default(EnemyParent); if (!EnemySetupExtensions.TryGetEnemyParent(enemySetup, ref val)) { Logger.LogError("EnemyManager: Failed to spawn enemy. EnemyParent is null.", extended: false, showMessage: true); return; } Vector3 randomSpawnPosition = GetRandomSpawnPosition(); List list = Enemies.SpawnEnemy(enemySetup, randomSpawnPosition, Quaternion.identity, SpawnDespawned); PlayerAvatar localPlayer = PlayerHelper.GetLocalPlayer(); EnemyNametag enemyNametag = default(EnemyNametag); foreach (EnemyParent item in list) { ViewerEnemies.Add(item, viewerData); ParticleScriptExplosion[] componentsInChildren = ((Component)item).GetComponentsInChildren(true); foreach (ParticleScriptExplosion component in componentsInChildren) { ((Component)(object)component).SetViewerMetadata(viewerData); } GameObject val2 = Object.Instantiate(Assets.EnemyNametagWorldCanvasPrefab); if (val2.TryGetComponent(ref enemyNametag)) { enemyNametag.SetData(item, viewerData); } AudioClip spawnSFX = Assets.EnemySpawnSFXList.GetSpawnSFX(item.enemyName); _audioPlayerFactory?.Play(spawnSFX, ((Component)item).transform.position); if ((Object)(object)localPlayer != (Object)null) { float num = Vector3.Distance(((Component)item).transform.position, ((Component)localPlayer).transform.position); Logger.LogInfo($"Spawned \"{item.enemyName}\" {num} meters away from you.", extended: true); } } } private static Vector3 GetRandomSpawnPosition() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)LevelGenerator.Instance == (Object)null) { Logger.LogError("EnemyManager: Failed to get valid spawn position. LevelGenerator instance is null.", extended: false, showMessage: true); return Vector3.zero; } Vector3 val = Vector3.zero; float minSpawnDistance = MinSpawnDistance; float maxSpawnDistance = MaxSpawnDistance; if (PlayerHelper.TryGetLocalPlayer(out var playerAvatar)) { val = ((Component)playerAvatar).transform.position; } LevelPoint val2 = SemiFunc.LevelPointGet(val, minSpawnDistance, maxSpawnDistance); if ((Object)(object)val2 == (Object)null) { val2 = SemiFunc.LevelPointGet(val, Mathf.Min(minSpawnDistance, 25f), float.MaxValue); if ((Object)(object)val2 == (Object)null) { return val; } } return ((Component)val2).transform.position; } public static bool CanSpawnEnemies() { if (!SemiFunc.IsMasterClientOrSingleplayer()) { return false; } if (!LevelHelper.CurrentLevelHasEnemies()) { return false; } if (!PlayerHelper.IsLocalPlayerAlive()) { return false; } return true; } public static ViewerData GetViewerData(EnemyParent enemyParent) { if ((Object)(object)enemyParent == (Object)null) { return null; } if (ViewerEnemies.TryGetValue(enemyParent, out var value)) { return value; } return null; } public static bool TryGetViewerData(EnemyParent enemyParent, out ViewerData viewerData) { viewerData = GetViewerData(enemyParent); return viewerData != null; } public static EnemySetup GetEnemyByName(string name) { return ((IEnumerable)Enemies.AllEnemies).FirstOrDefault((Func)((EnemySetup x) => x.GetEnemyName() == name)); } public static bool TryGetEnemyByName(string name, out EnemySetup enemySetup) { enemySetup = GetEnemyByName(name); return (Object)(object)enemySetup != (Object)null; } } } namespace com.github.zehsteam.TwitchTrolling.Helpers { internal static class AudioClipUtils { public static AudioClip ScaleVolume(AudioClip clip, float volumeMultiplier) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Invalid comparison between Unknown and I4 if ((Object)(object)clip == (Object)null) { Debug.LogError((object)"AudioClipUtils: AudioClip is null."); return null; } if ((int)clip.loadState != 2) { Debug.LogWarning((object)"AudioClipUtils: AudioClip is not ready to play. This may cause issues."); } float[] array = new float[clip.samples * clip.channels]; clip.GetData(array, 0); for (int i = 0; i < array.Length; i++) { array[i] *= volumeMultiplier; array[i] = Mathf.Clamp(array[i], -1f, 1f); } AudioClip val = AudioClip.Create(((Object)clip).name + "_Scaled", clip.samples, clip.channels, clip.frequency, false); val.SetData(array, 0); return val; } } internal static class ColorHelper { private static readonly float _minContrastRatio = 2f; public static string GetReadableColor(string hexColor, string backgroundHexColor = "#000000") { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_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) //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) Color val = HexToColor(hexColor); Color bgColor = HexToColor(backgroundHexColor); if (!HasGoodContrast(val, bgColor)) { val = AdjustColorForContrast(val, bgColor); } return ColorToHex(val); } public static Color HexToColor(string hex) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) Color result = default(Color); if (!ColorUtility.TryParseHtmlString(hex, ref result)) { return Color.white; } return result; } public static string ColorToHex(Color color) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return "#" + ColorUtility.ToHtmlStringRGB(color); } private static bool HasGoodContrast(Color textColor, Color bgColor) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) float contrastRatio = GetContrastRatio(textColor, bgColor); return contrastRatio >= _minContrastRatio; } private static float GetContrastRatio(Color color1, Color color2) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) float luminance = GetLuminance(color1); float luminance2 = GetLuminance(color2); return (Mathf.Max(luminance, luminance2) + 0.05f) / (Mathf.Min(luminance, luminance2) + 0.05f); } private static float GetLuminance(Color color) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) return 0.2126f * Mathf.Pow(color.r, 2.2f) + 0.7152f * Mathf.Pow(color.g, 2.2f) + 0.0722f * Mathf.Pow(color.b, 2.2f); } private static Color AdjustColorForContrast(Color textColor, Color bgColor) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0012: 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_0010: 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) float contrastRatio = GetContrastRatio(textColor, bgColor); if (contrastRatio >= _minContrastRatio) { return textColor; } RGBToHSL(textColor, out var h, out var s, out var l); float luminance = GetLuminance(bgColor); return HSLToRGB(l: (!(l < 0.5f)) ? Mathf.Max(l - 0.5f, 0f) : Mathf.Min(l + 0.5f, 1f), h: h, s: s); } private static void RGBToHSL(Color color, out float h, out float s, out float l) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) float r = color.r; float g = color.g; float b = color.b; float num = Mathf.Max(new float[3] { r, g, b }); float num2 = Mathf.Min(new float[3] { r, g, b }); float num3 = num - num2; l = (num + num2) / 2f; if (num3 == 0f) { h = 0f; s = 0f; return; } s = ((l > 0.5f) ? (num3 / (2f - num - num2)) : (num3 / (num + num2))); if (num == r) { h = (g - b) / num3 + (float)((g < b) ? 6 : 0); } else if (num == g) { h = (b - r) / num3 + 2f; } else { h = (r - g) / num3 + 4f; } h /= 6f; } private static Color HSLToRGB(float h, float s, float l) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) float num; float num2; float num3; if (s == 0f) { num = (num2 = (num3 = l)); } else { float num4 = ((l < 0.5f) ? (l * (1f + s)) : (l + s - l * s)); float p = 2f * l - num4; num = HueToRGB(p, num4, h + 1f / 3f); num2 = HueToRGB(p, num4, h); num3 = HueToRGB(p, num4, h - 1f / 3f); } return new Color(num, num2, num3); } private static float HueToRGB(float p, float q, float t) { if (t < 0f) { t += 1f; } if (t > 1f) { t -= 1f; } if (t < 1f / 6f) { return p + (q - p) * 6f * t; } if (t < 0.5f) { return q; } if (t < 2f / 3f) { return p + (q - p) * (2f / 3f - t) * 6f; } return p; } } internal class GridUtils { public static List GenerateGridAroundPosition(Vector3 center, float radius, float spacing, float minDistanceFromCenter = 0f) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_005a: 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_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) List list = new List(); int num = Mathf.FloorToInt(radius / spacing); float y = center.y; Vector3 val = default(Vector3); Vector3 item = default(Vector3); for (int i = -num; i <= num; i++) { for (int j = -num; j <= num; j++) { ((Vector3)(ref val))..ctor((float)i * spacing, 0f, (float)j * spacing); ((Vector3)(ref item))..ctor(center.x + val.x, y, center.z + val.z); Vector2 val2 = new Vector2(val.x, val.z); float magnitude = ((Vector2)(ref val2)).magnitude; if (!(magnitude < minDistanceFromCenter) && !(magnitude > radius)) { list.Add(item); } } } return list.OrderBy((Vector3 p) => Vector2.Distance(new Vector2(p.x, p.z), new Vector2(center.x, center.z))).ToList(); } } internal static class ItemHelper { public static Item GetItemByName(string name) { return ((IEnumerable)Items.AllItems).FirstOrDefault((Func)((Item x) => x.itemName == name)); } public static bool TryGetItemByName(string name, out Item item) { item = GetItemByName(name); return (Object)(object)item != (Object)null; } } internal class JsonConvertHelper { public static string SerializeQueue(Queue queue) { if (queue == null) { queue = new Queue(); } return JsonConvert.SerializeObject((object)queue, (JsonConverter[])(object)new JsonConverter[1] { new QueueJsonConverter() }); } public static Queue DeserializeQueue(string value) { if (string.IsNullOrEmpty(value)) { return new Queue(); } return JsonConvert.DeserializeObject>(value, (JsonConverter[])(object)new JsonConverter[1] { new QueueJsonConverter() }); } } internal static class LevelHelper { public static Level GetCurrentLevel() { if ((Object)(object)RunManager.instance == (Object)null) { return null; } return RunManager.instance.levelCurrent; } public static bool CurrentLevelHasEnemies() { Level currentLevel = GetCurrentLevel(); if ((Object)(object)currentLevel == (Object)null) { return false; } return currentLevel.HasEnemies; } } internal static class NavMeshHelper { private static int _attempts = 50; private static float _raycastHeight = 1f; private static float _raycastLength = 50f; private static float _navMeshSampleDistance = 2f; public static bool TryGetPositionInRadius(Vector3 origin, float minDistance, float maxDistance, out Vector3 position) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) Vector3 val2 = default(Vector3); RaycastHit val3 = default(RaycastHit); NavMeshHit val4 = default(NavMeshHit); for (int i = 0; i < _attempts; i++) { Vector2 insideUnitCircle = Random.insideUnitCircle; Vector2 val = ((Vector2)(ref insideUnitCircle)).normalized * Random.Range(minDistance, maxDistance); ((Vector3)(ref val2))..ctor(origin.x + val.x, origin.y + _raycastHeight, origin.z + val.y); if (Physics.Raycast(val2, Vector3.down, ref val3, _raycastLength) && NavMesh.SamplePosition(((RaycastHit)(ref val3)).point, ref val4, _navMeshSampleDistance, -1)) { position = ((NavMeshHit)(ref val4)).position; return true; } } position = Vector3.zero; return false; } public static bool TryGetPositionInDirection(Vector3 origin, Vector3 direction, float minDistance, float maxDistance, out Vector3 position) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000f: 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) //IL_001f: 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_002e: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) RaycastHit val2 = default(RaycastHit); NavMeshHit val3 = default(NavMeshHit); for (int i = 0; i < _attempts; i++) { float num = Random.Range(minDistance, maxDistance); Vector3 val = origin + ((Vector3)(ref direction)).normalized * num + Vector3.up * _raycastHeight; if (Physics.Raycast(val, Vector3.down, ref val2, _raycastLength) && NavMesh.SamplePosition(((RaycastHit)(ref val2)).point, ref val3, _navMeshSampleDistance, -1)) { position = ((NavMeshHit)(ref val3)).position; return true; } } position = Vector3.zero; return false; } } internal static class PlayerHelper { public static void Initialize() { Events.OnKilledByEnemy += HandleKilledByEnemy; Events.OnKilledByPhysGrabObject += HandleKilledByPhysGrabObject; Events.OnKilledByExplosion += HandleKilledByExplosion; Application.quitting += delegate { Events.OnKilledByEnemy -= HandleKilledByEnemy; Events.OnKilledByPhysGrabObject -= HandleKilledByPhysGrabObject; Events.OnKilledByExplosion -= HandleKilledByExplosion; }; } public static PlayerAvatar GetLocalPlayer() { return PlayerAvatar.instance; } public static bool TryGetLocalPlayer(out PlayerAvatar playerAvatar) { playerAvatar = GetLocalPlayer(); return (Object)(object)playerAvatar != (Object)null; } public static bool IsLocalPlayerAlive() { if (TryGetLocalPlayer(out var playerAvatar)) { return !playerAvatar.deadSet; } return false; } public static bool AnyPlayersNearby(Vector3 origin, float radius) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)GameDirector.instance == (Object)null) { return false; } foreach (PlayerAvatar player in GameDirector.instance.PlayerList) { if (!player.deadSet && Vector3.Distance(origin, ((Component)player).transform.position) <= radius) { return true; } } return false; } public static void PlayerTumble(PlayerAvatar playerAvatar, float time = 2f) { if (!((Object)(object)playerAvatar == (Object)null) && !playerAvatar.isDisabled) { if (!playerAvatar.tumble.isTumbling) { playerAvatar.tumble.TumbleRequest(true, false); } playerAvatar.tumble.TumbleOverrideTime(time); } } private static void HandleKilledByEnemy(EnemyParent enemyParent) { if (EnemyManager.TryGetViewerData(enemyParent, out var viewerData)) { DeathMessage.Instance?.Show(enemyParent, viewerData); } } private static void HandleKilledByPhysGrabObject(PhysGrabObject physGrabObject) { Metadata val = default(Metadata); ViewerData viewerData = default(ViewerData); if (ComponentExtensions.TryGetMetadata((Component)(object)physGrabObject, ref val, true) && val.TryGet("ViewerData", ref viewerData)) { DeathMessage.Instance?.Show(physGrabObject, viewerData); } } private static void HandleKilledByExplosion(Metadata metadata) { ViewerData viewerData = default(ViewerData); if (metadata.TryGet("ViewerData", ref viewerData)) { string sourceName = metadata.Get("Name", (string)null); DeathMessage.Instance?.ShowForExplosion(viewerData, sourceName); } } } internal static class ValuableHelper { public static PrefabRef GetValuableByName(string name) { return ((IEnumerable)Valuables.AllValuables).FirstOrDefault((Func)((PrefabRef x) => x.PrefabName == name)); } public static bool TryGetValuableByName(string name, out PrefabRef prefabRef) { prefabRef = GetValuableByName(name); return prefabRef != null; } } } namespace com.github.zehsteam.TwitchTrolling.Extensions { internal static class CollectionExtensions { public static EnemyConfigEntry GetRandom(this IEnumerable list) { if (list == null || !list.Any()) { return null; } EnemyConfigEntry[] array = list.ToArray(); return array[Random.Range(0, array.Length)]; } public static bool TryGetRandom(this IEnumerable list, out EnemyConfigEntry enemyConfigEntry) { enemyConfigEntry = list.GetRandom(); return enemyConfigEntry != null; } public static bool AddSingleInstance(this List list, T item) { if (list == null || item == null) { return false; } if (!list.Contains(item)) { list.Add(item); return true; } return false; } public static List GetMissingFrom(this List list, List other) { if (list == null || other == null) { return new List(); } return list.Where((T x) => !other.Contains(x)).ToList(); } public static void RemoveAll(this List list, List objectsToRemove) { if (list == null || list.Count == 0 || objectsToRemove == null) { return; } foreach (T item in objectsToRemove) { if (item != null) { list.Remove(item); } } } public static IEnumerable SortByShortest(this IEnumerable list) { return list.OrderBy((string s) => s?.Length ?? 0); } public static IEnumerable SortByLongest(this IEnumerable list) { IEnumerable enumerable = list.SortByShortest(); enumerable.Reverse(); return enumerable; } } internal static class ComponentExtensions { public static bool TryGetComponentInParent(this Component component, out T result) where T : Component { if ((Object)(object)component == (Object)null) { result = default(T); return false; } result = component.GetComponentInParent(); return (Object)(object)result != (Object)null; } public static T GetComponentInParents(this Component component) where T : Component { if ((Object)(object)component == (Object)null) { return default(T); } Transform parent = component.transform.parent; T result = default(T); while ((Object)(object)parent != (Object)null) { if (((Component)parent).TryGetComponent(ref result)) { return result; } parent = parent.parent; } return default(T); } public static bool TryGetComponentInParents(this Component component, out T result) where T : Component { result = component.GetComponentInParents(); return (Object)(object)result != (Object)null; } public static void SetViewerMetadata(this Component component, ViewerData viewerData) { if (!((Object)(object)component == (Object)null) && viewerData != null) { component.gameObject.SetViewerMetadata(viewerData); } } } internal static class ConfigEntryExtensions { public static bool SetValue(this ConfigEntry configEntry, string value) { if (configEntry == null) { return false; } try { Type typeFromHandle = typeof(T); if ((object)typeFromHandle != null) { Type type = typeFromHandle; object obj; if (type == typeof(int) && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) { obj = result; } else { Type type2 = typeFromHandle; if (type2 == typeof(float) && float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result2)) { obj = result2; } else { Type type3 = typeFromHandle; if (type3 == typeof(double) && double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result3)) { obj = result3; } else { Type type4 = typeFromHandle; if (type4 == typeof(bool) && bool.TryParse(value, out var result4)) { obj = result4; } else { Type type5 = typeFromHandle; if (type5 == typeof(string)) { obj = value; } else { Type type6 = typeFromHandle; if (!type6.IsEnum || !Enum.TryParse(type6, value, ignoreCase: true, out object result5)) { goto IL_0127; } obj = result5; } } } } } object obj2 = obj; configEntry.Value = (T)obj2; return true; } goto IL_0127; IL_0127: throw new NotSupportedException($"Unsupported config type: {typeof(T)}"); } catch (Exception ex) { Logger.LogError("SetValue failed for key '" + ((ConfigEntryBase)configEntry).Definition.Key + "': " + ex.Message); return false; } } } internal static class ConfigFileExtensions { public static ConfigEntry Bind(this ConfigFile configFile, string section, string key, T defaultValue, string description, AcceptableValueBase acceptableValues) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown return configFile.Bind(section, key, defaultValue, new ConfigDescription(description, acceptableValues, Array.Empty())); } public static Dictionary GetConfigEntries(this ConfigFile configFile) { if (configFile == null) { return new Dictionary(); } if (!(typeof(ConfigFile).GetField("Entries", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(configFile) is Dictionary dictionary)) { return new Dictionary(); } Dictionary dictionary2 = new Dictionary(); foreach (KeyValuePair item in dictionary) { dictionary2[item.Key] = item.Value.BoxedValue?.ToString(); } return dictionary2; } public static Dictionary GetOrphanedConfigEntries(this ConfigFile configFile) { if (configFile == null) { return new Dictionary(); } return (((object)configFile).GetType().GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(configFile, null) as Dictionary) ?? new Dictionary(); } public static bool RemoveOrphaned(this ConfigFile configFile, ConfigDefinition configDefinition) { if (configFile == null || configDefinition == (ConfigDefinition)null) { return false; } if (typeof(ConfigFile).GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(configFile) is IDictionary dictionary) { return dictionary.Remove(configDefinition); } return false; } public static bool MigrateConfigEntry(this ConfigFile configFile, ConfigDefinition oldConfigDefinition, string value, ConfigEntry newConfigEntry) { if (configFile == null || oldConfigDefinition == (ConfigDefinition)null || newConfigEntry == null) { return false; } configFile.RemoveOrphaned(oldConfigDefinition); return newConfigEntry.SetValue(value); } } internal static class EnemySetupExtensions { private static readonly Dictionary _enemySetupEnemyNamePairs = new Dictionary(); public static bool TryGetEnemyName(this EnemySetup enemySetup, out string enemyName) { if (_enemySetupEnemyNamePairs.TryGetValue(enemySetup, out var value)) { enemyName = value; return true; } List list = new List(); EnemyParent val = default(EnemyParent); foreach (PrefabRef spawnObject in enemySetup.spawnObjects) { GameObject prefab = spawnObject.Prefab; if (!((Object)(object)prefab == (Object)null) && prefab.TryGetComponent(ref val)) { list.Add(val.enemyName); } } if (list.Count == 0) { enemyName = string.Empty; return false; } string firstEnemyName = list[0]; if (list.All((string x) => x == firstEnemyName)) { enemyName = firstEnemyName; if (!_enemySetupEnemyNamePairs.ContainsKey(enemySetup)) { _enemySetupEnemyNamePairs.Add(enemySetup, enemyName); } return true; } Logger.LogError("EnemySetupExtensions: Failed to get enemy name from EnemySetup. EnemySetup '" + ((Object)enemySetup).name + "' contains spawn objects that do not all share the same enemy name! (" + string.Join(", ", list) + ")"); enemyName = string.Empty; return false; } public static string GetEnemyName(this EnemySetup enemySetup) { if (enemySetup.TryGetEnemyName(out var enemyName)) { return enemyName; } return string.Empty; } } internal static class GameObjectExtensions { public static void SetViewerMetadata(this GameObject gameObject, ViewerData viewerData) { if (!((Object)(object)gameObject == (Object)null) && viewerData != null) { Metadata orCreateMetadata = GameObjectExtensions.GetOrCreateMetadata(gameObject); orCreateMetadata.Set("ViewerData", viewerData); string text = string.Empty; ValuableObject val = default(ValuableObject); if (gameObject.TryGetComponent(ref val)) { text = ((Object)gameObject).name.TrimStart("Valuable "); } ItemAttributes val2 = default(ItemAttributes); if (gameObject.TryGetComponent(ref val2)) { text = val2.itemName; } Enemy val3 = default(Enemy); if (gameObject.TryGetComponent(ref val3)) { text = val3.EnemyParent.enemyName; } if (string.IsNullOrEmpty(text)) { text = ((Object)gameObject).name; } text = text.TrimEnd("(Clone)").Trim(); orCreateMetadata.Set("Name", text); } } } internal static class HurtColliderExtensions { public static Enemy GetEnemy(this HurtCollider hurtCollider) { if ((Object)(object)hurtCollider == (Object)null) { return null; } return hurtCollider.enemyHost; } public static bool TryGetEnemy(this HurtCollider hurtCollider, out Enemy enemy) { enemy = hurtCollider.GetEnemy(); return (Object)(object)enemy != (Object)null; } public static EnemyParent GetEnemyParent(this HurtCollider hurtCollider) { if (hurtCollider.TryGetEnemy(out var enemy)) { return ((Component)(object)enemy).GetComponentInParents(); } return null; } public static bool TryGetEnemyParent(this HurtCollider hurtCollider, out EnemyParent enemyParent) { enemyParent = hurtCollider.GetEnemyParent(); return (Object)(object)enemyParent != (Object)null; } } internal static class ImageExtensions { public static void SetAlpha(this Image image, int value) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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_002b: 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 (!((Object)(object)image == (Object)null)) { Color32 val = Color32.op_Implicit(((Graphic)image).color); val.a = (byte)Mathf.Clamp(value, 0, 255); ((Graphic)image).color = Color32.op_Implicit(val); } } } internal static class ReflectionExtensions { public static IEnumerable SafeGetMethods(this Type type) { try { return type.GetMethods(); } catch { return Array.Empty(); } } public static T SafeGetCustomAttribute(this MemberInfo member) where T : Attribute { try { return member.GetCustomAttribute(); } catch { return null; } } public static bool HasCustomAttribute(this MemberInfo member) where T : Attribute { try { return member.GetCustomAttribute() != null; } catch { return false; } } } internal static class StringExtensions { public static string TrimStart(this string s, string str) { if (s != null && str != null && s.StartsWith(str)) { return s.Substring(str.Length); } return s; } public static string TrimEnd(this string s, string str) { if (s != null && str != null && s.EndsWith(str)) { return s.Substring(0, s.Length - str.Length); } return s; } public static string RichColor(this string s, string colorHex) { return "" + s + ""; } public static string RichSize(this string s, int size) { return $"{s}"; } } internal static class TwitchUserExtensions { public static string GetDisplayNameWithColor(this TwitchUser twitchUser) { return Utils.GetTextWithReadableColor(((TwitchUser)(ref twitchUser)).DisplayName, ((TwitchUser)(ref twitchUser)).Color); } } } namespace com.github.zehsteam.TwitchTrolling.Dependencies { internal static class MoreHeadProxy { public const string PLUGIN_GUID = "Mhz.REPOMoreHead"; private static bool? _enabled; public static bool Enabled { get { bool valueOrDefault = _enabled == true; if (!_enabled.HasValue) { valueOrDefault = Chainloader.PluginInfos.ContainsKey("Mhz.REPOMoreHead"); _enabled = valueOrDefault; } return _enabled.Value; } } } internal static class SpawnManagerProxy { public const string PLUGIN_GUID = "soundedsquash.spawnmanager"; private static bool? _enabled; public static bool Enabled { get { bool valueOrDefault = _enabled == true; if (!_enabled.HasValue) { valueOrDefault = Chainloader.PluginInfos.ContainsKey("soundedsquash.spawnmanager"); _enabled = valueOrDefault; } return _enabled.Value; } } } } namespace com.github.zehsteam.TwitchTrolling.Dependencies.REPOConfigMod { internal static class REPOConfigHelper { public static void OpenSettingsMenu(string modName) { CoroutineRunner.Start(OpenSettingsMenu_Coroutine(modName)); } private static IEnumerator OpenSettingsMenu_Coroutine(string modName) { ConfigMenu.CreateModMenu(); yield return null; REPOPopupPage popupPageByObjectName = GetPopupPageByObjectName("Menu Page Mods"); if (!((Object)(object)popupPageByObjectName == (Object)null)) { REPOInputField inputFieldByObjectName = GetInputFieldByObjectName(popupPageByObjectName, "Input Field - Mod Search"); string text = ConfigMenu.FixNaming(modName); if (inputFieldByObjectName != null) { inputFieldByObjectName.inputStringSystem.SetValue(text, true); } GetModButton(text, fixNaming: false)?.onClick?.Invoke(); } } private static REPOPopupPage GetPopupPageByObjectName(string name) { return ((IEnumerable)REPOPopupPageLifetime.Instances).FirstOrDefault((Func)((REPOPopupPage x) => ((Object)((Component)x).gameObject).name.Equals(name, StringComparison.OrdinalIgnoreCase))); } private static REPOInputField GetInputFieldByObjectName(REPOPopupPage page, string name) { if ((Object)(object)page == (Object)null) { return null; } REPOInputField[] componentsInChildren = ((Component)page).GetComponentsInChildren(); return ((IEnumerable)componentsInChildren).FirstOrDefault((Func)((REPOInputField x) => ((Object)((Component)x).gameObject).name.Equals(name, StringComparison.OrdinalIgnoreCase))); } private static REPOButton GetModButton(string name, bool fixNaming = true) { if (fixNaming) { name = ConfigMenu.FixNaming(name); } return ((IEnumerable)ConfigMenu.currentModButtons).FirstOrDefault((Func)((REPOButton x) => ((TMP_Text)x.labelTMP).text.Equals(name, StringComparison.OrdinalIgnoreCase))); } } } namespace com.github.zehsteam.TwitchTrolling.Dependencies.MenuLibMod.Patches { [HarmonyPatch(typeof(REPOPopupPage))] internal static class REPOPopupPage_Patches { [HarmonyPatch("Awake")] [HarmonyPrefix] private static void Awake_Patch(REPOPopupPage __instance) { ((Component)__instance).gameObject.AddComponent(); } } } namespace com.github.zehsteam.TwitchTrolling.Dependencies.MenuLibMod.MonoBehaviours { public class REPOPopupPageLifetime : MonoBehaviour { private static readonly List _instances = new List(); private REPOPopupPage _page; public static IReadOnlyList Instances => _instances; public REPOPopupPage Page { get { if (_page == null) { _page = ((Component)this).GetComponent(); } return _page; } } private void OnEnable() { if (!_instances.Contains(Page)) { _instances.Add(Page); } } private void OnDisable() { _instances.Remove(Page); } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }