Decompiled source of TwitchTrolling v1.2.0

com.github.zehsteam.TwitchTrolling.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using MenuLib;
using MenuLib.MonoBehaviors;
using MenuLib.Structs;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Photon.Pun;
using REPOLib.Commands;
using REPOLib.Extensions;
using REPOLib.Modules;
using TMPro;
using TwitchChatAPI;
using TwitchChatAPI.Enums;
using TwitchChatAPI.Objects;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Networking;
using UnityEngine.Serialization;
using UnityEngine.UI;
using com.github.zehsteam.TwitchTrolling.Dependencies;
using com.github.zehsteam.TwitchTrolling.Extensions;
using com.github.zehsteam.TwitchTrolling.Helpers;
using com.github.zehsteam.TwitchTrolling.MEvents;
using com.github.zehsteam.TwitchTrolling.MEvents.BaseEvents;
using com.github.zehsteam.TwitchTrolling.MonoBehaviours;
using com.github.zehsteam.TwitchTrolling.Objects;
using com.github.zehsteam.TwitchTrolling.Patches;
using com.github.zehsteam.TwitchTrolling.Twitch;
using com.github.zehsteam.TwitchTrolling.Twitch.Helpers;
using com.github.zehsteam.TwitchTrolling.Twitch.Objects;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("REPOLib")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Zehs")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © 2025 Zehs")]
[assembly: AssemblyDescription("Let Twitch chat spawn monsters and trigger events with custom bit amounts and subs. Highly configurable, easy to use, no extension or app needed.")]
[assembly: AssemblyFileVersion("1.2.0.0")]
[assembly: AssemblyInformationalVersion("1.2.0+5b294c9d53c10e90587f4d124787d3a75832afd4")]
[assembly: AssemblyProduct("TwitchTrolling")]
[assembly: AssemblyTitle("com.github.zehsteam.TwitchTrolling")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace com.github.zehsteam.TwitchTrolling
{
	internal static class Assets
	{
		public static GameObject PluginManagerPrefab { get; private set; }

		public static GameObject PluginHUDPrefab { get; private set; }

		public static GameObject EnemyNametagWorldCanvasPrefab { get; private set; }

		public static GameObject TruckPropsPrefab { get; private set; }

		public static GameObject AudioEnemySpawnPrefab { get; private set; }

		public static GameObject ModCreditsPrefab { get; private set; }

		public static EnemyConfigEntryDefaultValuesList EnemyConfigEntryDefaultValuesList { get; private set; }

		public static EnemySpawnSFXList EnemySpawnSFXList { get; private set; }

		public static MEventSFXList MEventSFXList { get; private set; }

		public static void Load()
		{
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			string text = "twitchtrolling_assets";
			string text2 = Path.Combine(directoryName, text);
			if (!File.Exists(text2))
			{
				Logger.LogFatal("Failed to load assets. AssetBundle file could not be found at path \"" + text2 + "\". Make sure the \"" + text + "\" file is in the same folder as the mod's DLL file.");
			}
			else
			{
				AssetBundle val = AssetBundle.LoadFromFile(text2);
				if ((Object)(object)val == (Object)null)
				{
					Logger.LogFatal("Failed to load assets. AssetBundle is null.");
				}
				else
				{
					OnAssetBundleLoaded(val);
				}
			}
		}

		private static void OnAssetBundleLoaded(AssetBundle assetBundle)
		{
			PluginManagerPrefab = LoadAsset<GameObject>("PluginManager", assetBundle);
			PluginHUDPrefab = LoadAsset<GameObject>("PluginHUD", assetBundle);
			EnemyNametagWorldCanvasPrefab = LoadAsset<GameObject>("EnemyNametagWorldCanvas", assetBundle);
			TruckPropsPrefab = LoadAsset<GameObject>("TruckProps", assetBundle);
			AudioEnemySpawnPrefab = LoadAsset<GameObject>("AudioEnemySpawn", assetBundle);
			Utilities.FixAudioMixerGroups(AudioEnemySpawnPrefab);
			ModCreditsPrefab = LoadAsset<GameObject>("TwitchTrolling ModCredits", assetBundle);
			NetworkPrefabs.RegisterNetworkPrefab(((Object)ModCreditsPrefab).name, ModCreditsPrefab);
			EnemyConfigEntryDefaultValuesList = LoadAsset<EnemyConfigEntryDefaultValuesList>("EnemyConfigEntryDefaultValuesList", assetBundle);
			EnemySpawnSFXList = LoadAsset<EnemySpawnSFXList>("EnemySpawnSFXList", assetBundle);
			MEventSFXList = LoadAsset<MEventSFXList>("MEventSFXList", assetBundle);
		}

		private static T LoadAsset<T>(string name, AssetBundle assetBundle) where T : Object
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				Logger.LogError("Failed to load asset of type \"" + typeof(T).Name + "\" from AssetBundle. Name is null or whitespace.");
				return default(T);
			}
			if ((Object)(object)assetBundle == (Object)null)
			{
				Logger.LogError("Failed to load asset of type \"" + typeof(T).Name + "\" with name \"" + name + "\" from AssetBundle. AssetBundle is null.");
				return default(T);
			}
			T val = assetBundle.LoadAsset<T>(name);
			if ((Object)(object)val == (Object)null)
			{
				Logger.LogError("Failed to load asset of type \"" + typeof(T).Name + "\" with name \"" + name + "\" from AssetBundle. No asset found with that type and name.");
				return default(T);
			}
			return val;
		}

		private static bool TryLoadAsset<T>(string name, AssetBundle assetBundle, out T asset) where T : Object
		{
			asset = LoadAsset<T>(name, assetBundle);
			return (Object)(object)asset != (Object)null;
		}
	}
	internal static class ConfigManager
	{
		public static ConfigFile ConfigFile { get; private set; }

		public static ConfigEntry<bool> ExtendedLogging { get; private set; }

		public static ConfigEntry<bool> TwitchIntegration_Enabled { get; private set; }

		public static ConfigEntry<bool> TwitchSubEvent_Enabled { get; private set; }

		public static ConfigEntry<int> TwitchSubEvent_Tier2EnemySpawnCountMultiplier { get; private set; }

		public static ConfigEntry<int> TwitchSubEvent_Tier3EnemySpawnCountMultiplier { get; private set; }

		public static ConfigEntry<bool> TwitchCheerEvent_Enabled { get; private set; }

		public static ConfigEntry<int> TwitchCheerEvent_MinAmountForRandomEnemy { get; private set; }

		public static ConfigEntry<bool> TwitchRaidEvent_Enabled { get; private set; }

		public static ConfigEntry<int> TwitchRaidEvent_ViewersPerRandomEnemy { get; private set; }

		public static ConfigEntry<int> TwitchRaidEvent_MaxEnemySpawnCount { get; private set; }

		public static ConfigEntry<bool> Enemy_SpawnDespawned { get; private set; }

		public static ConfigEntry<float> Enemy_MinSpawnDistance { get; private set; }

		public static ConfigEntry<float> Enemy_MaxSpawnDistance { get; private set; }

		public static ConfigEntry<bool> Event_Enabled { get; private set; }

		public static ConfigEntry<int> Event_AmountForRandomEvent { get; private set; }

		public static ConfigEntry<bool> Message_Enabled { get; private set; }

		public static ConfigEntry<float> Message_Duration { get; private set; }

		public static ConfigEntry<int> Message_FontSize { get; private set; }

		public static ConfigEntry<int> Message_BackgroundTransparency { get; private set; }

		public static ConfigEntry<bool> DeathMessage_Enabled { get; private set; }

		public static ConfigEntry<bool> DeathMessage_ShowPlatformIcon { get; private set; }

		public static ConfigEntry<float> DeathMessage_Duration { get; private set; }

		public static ConfigEntry<int> DeathMessage_FontSize { get; private set; }

		public static ConfigEntry<int> DeathMessage_BackgroundTransparency { get; private set; }

		public static ConfigEntry<bool> EnemyNametag_Enabled { get; private set; }

		public static ConfigEntry<bool> EnemyNametag_ShowPlatformIcon { get; private set; }

		public static ConfigEntry<float> EnemyNametag_SizeMultiplier { get; private set; }

		public static ConfigEntry<int> EnemyNametag_BackgroundTransparency { get; private set; }

		public static void Initialize(ConfigFile configFile)
		{
			ConfigFile = configFile;
			BindConfigs();
		}

		private static void BindConfigs()
		{
			ExtendedLogging = ConfigFile.Bind<bool>("- General -", "ExtendedLogging", false, "Enable extended logging.");
			TwitchIntegration_Enabled = ConfigFile.Bind<bool>("- Twitch Integration -", "Enabled", true, "If enabled, Twitch integration will be enabled to spawn enemies from Subs, Cheers, and Raids.");
			TwitchSubEvent_Enabled = ConfigFile.Bind<bool>("- Twitch Sub Event -", "Enabled", true, "If enabled, Twitch subs will be able to spawn enemies.");
			TwitchSubEvent_Tier2EnemySpawnCountMultiplier = ConfigFile.Bind("- Twitch Sub Event -", "Tier2EnemySpawnCountMultiplier", 5, "The amount to multiply the enemy spawn count for tier 2 subs.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 30));
			TwitchSubEvent_Tier3EnemySpawnCountMultiplier = ConfigFile.Bind("- Twitch Sub Event -", "Tier3EnemySpawnCountMultiplier", 10, "The amount to multiply the enemy spawn count for tier 3 subs.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 30));
			TwitchCheerEvent_Enabled = ConfigFile.Bind<bool>("- Twitch Cheer Event -", "Enabled", true, "If enabled, Twitch cheers will be able to spawn enemies.");
			TwitchCheerEvent_MinAmountForRandomEnemy = ConfigFile.Bind("- Twitch Cheer Event -", "MinAmountForRandomEnemy", 350, "The min amount of bits for a random enemy spawn.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000));
			TwitchCheerEvent_MinAmountForRandomEnemy.SettingChanged += delegate
			{
				PageManager.UpdatePage();
			};
			TwitchRaidEvent_Enabled = ConfigFile.Bind<bool>("- Twitch Raid Event -", "Enabled", true, "If enabled, Twitch raids will be able to spawn enemies.");
			TwitchRaidEvent_ViewersPerRandomEnemy = ConfigFile.Bind("- Twitch Raid Event -", "ViewersPerRandomEnemy", 5, "The amount of viewers for each random enemy spawn.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100));
			TwitchRaidEvent_MaxEnemySpawnCount = ConfigFile.Bind("- Twitch Raid Event -", "MaxEnemySpawnCount", 20, "The max amount of enemies that can spawn from a raid.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100));
			Enemy_SpawnDespawned = ConfigFile.Bind<bool>("- Enemy -", "SpawnDespawned", false, "If enabled, enemies will spawn despawned.");
			Enemy_MinSpawnDistance = ConfigFile.Bind("- Enemy -", "MinSpawnDistance", 25f, "The min distance an enemy can spawn from the local player. (meters)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f));
			Enemy_MaxSpawnDistance = ConfigFile.Bind("- Enemy -", "MaxSpawnDistance", 300f, "The max distance an enemy can spawn from the local player. (meters)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 500f));
			Event_Enabled = ConfigFile.Bind<bool>("- Event -", "Enabled", true, "If enabled, Twitch cheers will be able to trigger events.");
			Event_AmountForRandomEvent = ConfigFile.Bind("- Event -", "AmountForRandomEvent", 150, "The amount of bits for a random event.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000));
			Event_AmountForRandomEvent.SettingChanged += delegate
			{
				PageManager.UpdatePage();
			};
			Message_Enabled = ConfigFile.Bind<bool>("- Message -", "Enabled", true, "If enabled, will show messages in the bottom right.");
			Message_Duration = ConfigFile.Bind("- Message -", "Duration", 10f, "The duration of a message. (seconds)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f));
			Message_FontSize = ConfigFile.Bind("- Message -", "FontSize", 12, "The font size of the messages.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 50));
			Message_BackgroundTransparency = ConfigFile.Bind("- Message -", "BackgroundTransparency", 192, "The transparency of the message background.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 255));
			Message_FontSize.SettingChanged += delegate
			{
				MessageItem.OnConfigSettingsChanged();
			};
			Message_BackgroundTransparency.SettingChanged += delegate
			{
				MessageItem.OnConfigSettingsChanged();
			};
			DeathMessage_Enabled = ConfigFile.Bind<bool>("- Death Message -", "Enabled", true, "If enabled, will show a message when you die to an enemy spawned from a viewer.");
			DeathMessage_ShowPlatformIcon = ConfigFile.Bind<bool>("- Death Message -", "ShowPlatformIcon", true, "If enabled, will show which platform the enemy was spawned from.");
			DeathMessage_Duration = ConfigFile.Bind("- Death Message -", "Duration", 5f, "The duration of the death message. (seconds)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f));
			DeathMessage_FontSize = ConfigFile.Bind("- Death Message -", "FontSize", 16, "The font size of the death message.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 50));
			DeathMessage_BackgroundTransparency = ConfigFile.Bind("- Death Message -", "BackgroundTransparency", 192, "The transparency of the death message background.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 255));
			EnemyNametag_Enabled = ConfigFile.Bind<bool>("- Enemy Nametag -", "Enabled", true, "If enabled, enemies will spawn with a nametag of the viewer that spawned that enemy.");
			EnemyNametag_ShowPlatformIcon = ConfigFile.Bind<bool>("- Enemy Nametag -", "ShowPlatformIcon", true, "If enabled, nametags will show which platform the enemy was spawned from.");
			EnemyNametag_SizeMultiplier = ConfigFile.Bind("- Enemy Nametag -", "SizeMultiplier", 0.75f, "The size multiplier for enemy nametags.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 5f));
			EnemyNametag_BackgroundTransparency = ConfigFile.Bind("- Enemy Nametag -", "BackgroundTransparency", 192, "The transparency of the nametag background.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 255));
			EnemyNametag_ShowPlatformIcon.SettingChanged += delegate
			{
				EnemyNametag.OnConfigSettingsChanged();
			};
			EnemyNametag_SizeMultiplier.SettingChanged += delegate
			{
				EnemyNametag.OnConfigSettingsChanged();
			};
			EnemyNametag_BackgroundTransparency.SettingChanged += delegate
			{
				EnemyNametag.OnConfigSettingsChanged();
			};
		}
	}
	internal static class EnemyConfigManager
	{
		public static ConfigFile ConfigFile => ConfigManager.ConfigFile;

		public static List<EnemyConfigEntry> ConfigEntries { get; private set; } = new List<EnemyConfigEntry>();


		public static void Initialize()
		{
			EnemyConfigEntryDefaultValues[] list = Assets.EnemyConfigEntryDefaultValuesList.List;
			foreach (EnemyConfigEntryDefaultValues defaultValues in list)
			{
				RegisterConfigEntry(defaultValues);
			}
			EnemyParent val = default(EnemyParent);
			foreach (EnemySetup allEnemy in Enemies.AllEnemies)
			{
				if (EnemySetupExtensions.TryGetEnemyParent(allEnemy, ref val))
				{
					RegisterConfigEntry(val.enemyName);
				}
			}
		}

		public static void RegisterConfigEntry(string enemyName)
		{
			if (!HasConfigEntry(enemyName))
			{
				EnemyConfigEntry item = new EnemyConfigEntry(enemyName);
				ConfigEntries.Add(item);
			}
		}

		public static void RegisterConfigEntry(EnemyConfigEntryDefaultValues defaultValues)
		{
			if (!HasConfigEntry(defaultValues.EnemyName))
			{
				EnemyConfigEntry item = new EnemyConfigEntry(defaultValues);
				ConfigEntries.Add(item);
			}
		}

		public static bool HasEnemies()
		{
			foreach (EnemyConfigEntry configEntry in ConfigEntries)
			{
				if (configEntry.Enabled.Value)
				{
					return true;
				}
			}
			return false;
		}

		public static bool HasConfigEntry(string enemyName)
		{
			return ConfigEntries.Any((EnemyConfigEntry x) => x.EnemyNameEquals(enemyName));
		}

		public static EnemyConfigEntry GetConfigEntry(string enemyName)
		{
			return ConfigEntries.FirstOrDefault((EnemyConfigEntry x) => x.EnemyNameEquals(enemyName));
		}

		public static bool TryGetConfigEntry(string enemyName, out EnemyConfigEntry configEntry)
		{
			configEntry = GetConfigEntry(enemyName);
			return configEntry != null;
		}

		public static List<EnemyConfigEntry> GetConfigEntriesThatMatchBitsAmount(int bitsAmount, bool includeDisable = false)
		{
			List<EnemyConfigEntry> list = new List<EnemyConfigEntry>();
			foreach (EnemyConfigEntry configEntry in ConfigEntries)
			{
				if ((includeDisable || configEntry.Enabled.Value) && configEntry.BitsToSpawn.Value == bitsAmount)
				{
					list.Add(configEntry);
				}
			}
			return list;
		}

		public static bool TryGetConfigEntriesThatMatchBitsAmount(int bitsAmount, out List<EnemyConfigEntry> list, bool includeDisable = false)
		{
			list = GetConfigEntriesThatMatchBitsAmount(bitsAmount, includeDisable);
			return list.Any();
		}

		public static List<EnemyConfigEntry> GetConfigEntriesThatMatchSubsAmount(int subsAmount, bool includeDisable = false)
		{
			List<EnemyConfigEntry> list = new List<EnemyConfigEntry>();
			foreach (EnemyConfigEntry configEntry in ConfigEntries)
			{
				if ((includeDisable || configEntry.Enabled.Value) && configEntry.SubsToSpawn.Value == subsAmount)
				{
					list.Add(configEntry);
				}
			}
			return list;
		}

		public static bool TryGetConfigEntriesThatMatchSubsAmount(int subsAmount, out List<EnemyConfigEntry> list, bool includeDisable = false)
		{
			list = GetConfigEntriesThatMatchSubsAmount(subsAmount, includeDisable);
			return list.Any();
		}
	}
	internal static class EnemyManager
	{
		private static AudioPlayerFactory _audioPlayerFactory;

		public static Dictionary<EnemyParent, ViewerData> ViewerEnemies { get; private set; }

		public static bool SpawnDespawned => ConfigManager.Enemy_SpawnDespawned.Value;

		public static float MinSpawnDistance => ConfigManager.Enemy_MinSpawnDistance.Value;

		public static float MaxSpawnDistance => ConfigManager.Enemy_MaxSpawnDistance.Value;

		static EnemyManager()
		{
			ViewerEnemies = new Dictionary<EnemyParent, ViewerData>();
			_audioPlayerFactory = new AudioPlayerFactory
			{
				Type = AudioPlayerType.EnemySpawn,
				MaxDistance = 30f
			};
		}

		public static void ResetViewerEnemies()
		{
			ViewerEnemies.Clear();
		}

		public static void SpawnEnemy(ViewerSpawnData viewerSpawnData)
		{
			if (viewerSpawnData == null)
			{
				Logger.LogError("EnemyManager: Failed to spawn enemies. ViewerSpawnData is null.", extended: false, showMessage: true);
				return;
			}
			if (!CanSpawnEnemies())
			{
				Logger.LogError("EnemyManager: Failed to spawn enemies. You are not allowed to spawn enemies at this time.", extended: false, showMessage: true);
				return;
			}
			List<EnemyConfigEntry> entries = new List<EnemyConfigEntry>();
			for (int i = 0; i < viewerSpawnData.SpawnCount; i++)
			{
				if (EnemyConfigManager.TryGetConfigEntry(viewerSpawnData.TargetEnemyName, out var configEntry))
				{
					entries.Add(configEntry);
				}
				else
				{
					entries.Add(EnemyConfigManager.ConfigEntries.GetRandom());
				}
			}
			if (entries.Count < 1)
			{
				Logger.LogError("EnemyManager: Failed to spawn enemies. No enemies where found to spawn.", extended: false, showMessage: true);
				return;
			}
			if (entries.All((EnemyConfigEntry x) => x == entries[0]))
			{
				viewerSpawnData.SetTargetEnemyName(entries[0].EnemyName);
			}
			int num = entries.Sum((EnemyConfigEntry x) => x.SpawnCount.Value);
			viewerSpawnData.SetTotalSpawnCount(num);
			if (num < 1)
			{
				Logger.LogError("EnemyManager: Failed to spawn enemies. Total spawn count is less than 1.", extended: false, showMessage: true);
				return;
			}
			foreach (EnemyConfigEntry item in entries)
			{
				SpawnEnemy(item, viewerSpawnData.Viewer);
			}
			MessageManager.Instance?.ShowSpawnEnemyMessage(viewerSpawnData);
			Logger.LogInfo($"\n\n{viewerSpawnData.Viewer.DisplayName} spawned {num}x enemies {viewerSpawnData.SpawnReason}\n", extended: true);
		}

		private static void SpawnEnemy(EnemyConfigEntry configEntry, ViewerData viewerData)
		{
			if (configEntry == null)
			{
				Logger.LogError("EnemyManager: Failed to spawn enemies. EnemyConfigEntry is null.", extended: false, showMessage: true);
				return;
			}
			if (viewerData == null)
			{
				Logger.LogError("EnemyManager: Failed to spawn enemies. ViewerData is null.", extended: false, showMessage: true);
				return;
			}
			string enemyName = configEntry.EnemyName;
			int value = configEntry.SpawnCount.Value;
			if (value < 1)
			{
				Logger.LogError("EnemyManager: Failed to spawn enemy \"" + enemyName + "\". Spawn count is less than 1.", extended: false, showMessage: true);
				return;
			}
			EnemySetup enemySetup = default(EnemySetup);
			if (!Enemies.TryGetEnemyByName(enemyName, ref enemySetup))
			{
				Logger.LogError("EnemyManager: Failed to spawn enemy \"" + enemyName + "\". EnemySetup is null.", extended: false, showMessage: true);
				return;
			}
			for (int i = 0; i < value; i++)
			{
				SpawnEnemy(enemySetup, viewerData);
			}
		}

		private static void SpawnEnemy(EnemySetup enemySetup, ViewerData viewerData)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)enemySetup == (Object)null)
			{
				Logger.LogError("EnemyManager: Failed to spawn enemies. EnemySetup is null.", extended: false, showMessage: true);
				return;
			}
			if (viewerData == null)
			{
				Logger.LogError("EnemyManager: Failed to spawn enemies. ViewerData is null.", extended: false, showMessage: true);
				return;
			}
			EnemyParent val = default(EnemyParent);
			if (!EnemySetupExtensions.TryGetEnemyParent(enemySetup, ref val))
			{
				Logger.LogError("EnemyManager: Failed to spawn enemy. EnemyParent is null.", extended: false, showMessage: true);
				return;
			}
			Vector3 randomSpawnPosition = GetRandomSpawnPosition();
			List<EnemyParent> list = Enemies.SpawnEnemy(enemySetup, randomSpawnPosition, Quaternion.identity, SpawnDespawned);
			PlayerAvatar localPlayer = PlayerHelper.GetLocalPlayer();
			EnemyNametag enemyNametag = default(EnemyNametag);
			foreach (EnemyParent item in list)
			{
				ViewerEnemies.Add(item, viewerData);
				GameObject val2 = Object.Instantiate<GameObject>(Assets.EnemyNametagWorldCanvasPrefab);
				if (val2.TryGetComponent<EnemyNametag>(ref enemyNametag))
				{
					enemyNametag.SetData(item, viewerData);
				}
				AudioClip spawnSFX = Assets.EnemySpawnSFXList.GetSpawnSFX(item.enemyName);
				_audioPlayerFactory?.Play(spawnSFX, ((Component)item).transform.position);
				if ((Object)(object)localPlayer != (Object)null)
				{
					float num = Vector3.Distance(((Component)item).transform.position, ((Component)localPlayer).transform.position);
					Logger.LogInfo($"Spawned \"{item.enemyName}\" {num} meters away from you.", extended: true);
				}
			}
		}

		private static Vector3 GetRandomSpawnPosition()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)LevelGenerator.Instance == (Object)null)
			{
				Logger.LogError("EnemyManager: Failed to get valid spawn position. LevelGenerator instance is null.", extended: false, showMessage: true);
				return Vector3.zero;
			}
			Vector3 val = Vector3.zero;
			float minSpawnDistance = MinSpawnDistance;
			float maxSpawnDistance = MaxSpawnDistance;
			if (PlayerHelper.TryGetLocalPlayer(out var playerAvatar))
			{
				val = ((Component)playerAvatar).transform.position;
			}
			LevelPoint val2 = SemiFunc.LevelPointGet(val, minSpawnDistance, maxSpawnDistance);
			if ((Object)(object)val2 == (Object)null)
			{
				val2 = SemiFunc.LevelPointGet(val, Mathf.Min(minSpawnDistance, 25f), float.MaxValue);
				if ((Object)(object)val2 == (Object)null)
				{
					return val;
				}
			}
			return ((Component)val2).transform.position;
		}

		public static bool CanSpawnEnemies()
		{
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				return false;
			}
			if (!LevelHelper.CurrentLevelHasEnemies())
			{
				return false;
			}
			if (!PlayerHelper.IsLocalPlayerAlive())
			{
				return false;
			}
			return true;
		}

		public static ViewerData GetViewerData(EnemyParent enemyParent)
		{
			if ((Object)(object)enemyParent == (Object)null)
			{
				return null;
			}
			if (ViewerEnemies.TryGetValue(enemyParent, out var value))
			{
				return value;
			}
			return null;
		}

		public static bool TryGetViewerData(EnemyParent enemyParent, out ViewerData viewerData)
		{
			viewerData = GetViewerData(enemyParent);
			return viewerData != null;
		}
	}
	internal static class Logger
	{
		public static ManualLogSource ManualLogSource { get; private set; }

		public static void Initialize(ManualLogSource manualLogSource)
		{
			ManualLogSource = manualLogSource;
		}

		public static void LogDebug(object data)
		{
			Log((LogLevel)32, data);
		}

		public static void LogInfo(object data, bool extended = false)
		{
			Log((LogLevel)16, data, extended);
		}

		public static void LogWarning(object data, bool extended = false)
		{
			Log((LogLevel)4, data, extended);
		}

		public static void LogError(object data, bool extended = false, bool showMessage = false)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			Log((LogLevel)2, data, extended);
			if (showMessage)
			{
				MessageManager.Instance?.ShowMessage(data.ToString(), Color.red);
			}
		}

		public static void LogFatal(object data, bool extended = false)
		{
			Log((LogLevel)1, data, extended);
		}

		public static void Log(LogLevel logLevel, object data, bool extended = false)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (!extended || IsExtendedLoggingEnabled())
			{
				ManualLogSource manualLogSource = ManualLogSource;
				if (manualLogSource != null)
				{
					manualLogSource.Log(logLevel, data);
				}
			}
		}

		public static bool IsExtendedLoggingEnabled()
		{
			if (ConfigManager.ExtendedLogging == null)
			{
				return false;
			}
			return ConfigManager.ExtendedLogging.Value;
		}
	}
	internal static class Menu
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static BuilderDelegate <>9__5_0;

			public static BuilderDelegate <>9__5_1;

			public static BuilderDelegate <>9__5_2;

			public static Action <>9__5_3;

			internal void <Initialize>b__5_0(Transform parent)
			{
				CreateMainButtonForMainMenu(parent);
			}

			internal void <Initialize>b__5_1(Transform parent)
			{
				CreateMainButtonForLobbyAndEscapeMenu(parent);
			}

			internal void <Initialize>b__5_2(Transform parent)
			{
				CreateMainButtonForLobbyAndEscapeMenu(parent);
			}

			internal void <Initialize>b__5_3()
			{
				PageManager.OnPageStatusChanged -= HandlePageStatusChanged;
				PageManager.OnPageCreated -= HandlePageCreated;
			}
		}

		private static REPOPopupPage _popupPage;

		private static REPOLabel _pageStatusLabel;

		private static REPOLabel _pageUrlLabel;

		private static REPOButton _createPageButton;

		private static REPOButton _copyPageURLButton;

		public static void Initialize()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			object obj = <>c.<>9__5_0;
			if (obj == null)
			{
				BuilderDelegate val = delegate(Transform parent)
				{
					CreateMainButtonForMainMenu(parent);
				};
				<>c.<>9__5_0 = val;
				obj = (object)val;
			}
			MenuAPI.AddElementToMainMenu((BuilderDelegate)obj);
			object obj2 = <>c.<>9__5_1;
			if (obj2 == null)
			{
				BuilderDelegate val2 = delegate(Transform parent)
				{
					CreateMainButtonForLobbyAndEscapeMenu(parent);
				};
				<>c.<>9__5_1 = val2;
				obj2 = (object)val2;
			}
			MenuAPI.AddElementToLobbyMenu((BuilderDelegate)obj2);
			object obj3 = <>c.<>9__5_2;
			if (obj3 == null)
			{
				BuilderDelegate val3 = delegate(Transform parent)
				{
					CreateMainButtonForLobbyAndEscapeMenu(parent);
				};
				<>c.<>9__5_2 = val3;
				obj3 = (object)val3;
			}
			MenuAPI.AddElementToEscapeMenu((BuilderDelegate)obj3);
			PageManager.OnPageStatusChanged += HandlePageStatusChanged;
			PageManager.OnPageCreated += HandlePageCreated;
			Application.quitting += delegate
			{
				PageManager.OnPageStatusChanged -= HandlePageStatusChanged;
				PageManager.OnPageCreated -= HandlePageCreated;
			};
		}

		private static REPOButton CreateMainButtonForMainMenu(Transform parent)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			float num = 22f;
			float num2 = 0f;
			float num3 = 35f;
			num2 += num3;
			if (SpawnManagerProxy.Enabled)
			{
				num2 += num3;
			}
			return CreateMainButton(parent, Vector2.op_Implicit(new Vector2(550f, num + num2)));
		}

		private static REPOButton CreateMainButtonForLobbyAndEscapeMenu(Transform parent)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			float num = 0f;
			num += 145f;
			if (MoreHeadProxy.Enabled)
			{
				num += 100f;
			}
			return CreateMainButton(parent, Vector2.op_Implicit(new Vector2(num, 0f)));
		}

		private static REPOButton CreateMainButton(Transform parent, Vector3 localPosition)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			return MenuAPI.CreateREPOButton("Twitch Trolling", (Action)HandleMainButtonClick, parent, Vector2.op_Implicit(localPosition));
		}

		private static void CreateMenu()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Expected O, but got Unknown
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Expected O, but got Unknown
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Expected O, but got Unknown
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Expected O, but got Unknown
			_popupPage = MenuAPI.CreateREPOPopupPage("Twitch Trolling", (PresetSide)0, false, true, 0f);
			REPOPopupPage popupPage = _popupPage;
			Padding maskPadding = _popupPage.maskPadding;
			maskPadding.top = 35f;
			popupPage.maskPadding = maskPadding;
			float xPosition = 75f;
			float yPosition = 270f;
			_popupPage.AddElement((BuilderDelegate)delegate(Transform parent)
			{
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Unknown result type (might be due to invalid IL or missing references)
				_pageStatusLabel = MenuAPI.CreateREPOLabel("Page Status:", parent, new Vector2(xPosition, yPosition));
				((Component)_pageStatusLabel).transform.localScale = Vector3.one * 0.7f;
			});
			yPosition -= 40f;
			_popupPage.AddElement((BuilderDelegate)delegate(Transform parent)
			{
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Unknown result type (might be due to invalid IL or missing references)
				_pageUrlLabel = MenuAPI.CreateREPOLabel(string.Empty, parent, new Vector2(xPosition, yPosition));
				((Component)_pageUrlLabel).transform.localScale = Vector3.one * 0.5f;
			});
			yPosition -= 60f;
			_popupPage.AddElement((BuilderDelegate)delegate(Transform parent)
			{
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				_createPageButton = MenuAPI.CreateREPOButton("Create Page", (Action)HandleCreatePageButtonClick, parent, Vector2.op_Implicit(new Vector3(xPosition, yPosition)));
			});
			_popupPage.AddElement((BuilderDelegate)delegate(Transform parent)
			{
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				_copyPageURLButton = MenuAPI.CreateREPOButton("Copy Page URL", (Action)HandleCopyPageURLButtonClick, parent, Vector2.op_Implicit(new Vector3(xPosition, yPosition)));
				((Component)_copyPageURLButton).gameObject.SetActive(false);
			});
			yPosition = 35f;
			_popupPage.AddElement((BuilderDelegate)delegate(Transform parent)
			{
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				MenuAPI.CreateREPOButton("Close", (Action)HandleCloseButtonClick, parent, new Vector2(xPosition, yPosition));
			});
			_popupPage.OpenPage(false);
			HandlePageStatusChanged();
			PageManager.CheckPageStatus();
			PageManager.VerifyTwitchChannel();
		}

		private static void HandleMainButtonClick()
		{
			CreateMenu();
		}

		private static void HandleCloseButtonClick()
		{
			REPOPopupPage popupPage = _popupPage;
			if (popupPage != null)
			{
				popupPage.ClosePage(true);
			}
		}

		private static void HandleCreatePageButtonClick()
		{
			REPOButton createPageButton = _createPageButton;
			if (createPageButton != null)
			{
				((Component)createPageButton).gameObject.SetActive(false);
			}
			PageManager.CreatePage();
		}

		private static void HandleCopyPageURLButtonClick()
		{
			if (PageManager.HasPage)
			{
				GUIUtility.systemCopyBuffer = PageManager.PageURL;
			}
		}

		private static void HandlePageStatusChanged()
		{
			if ((Object)(object)_popupPage == (Object)null)
			{
				return;
			}
			bool hasPage = PageManager.HasPage;
			((Component)_createPageButton).gameObject.SetActive(!hasPage);
			((Component)_copyPageURLButton).gameObject.SetActive(hasPage);
			if (hasPage)
			{
				((TMP_Text)_pageStatusLabel.labelTMP).text = "Page Status: <color=#00FF00>ONLINE</color>";
				string text = PageManager.PageURL.Replace("?id", "\n?id");
				((TMP_Text)_pageUrlLabel.labelTMP).text = "<color=#FFFFFF>" + text + "</color>";
				return;
			}
			((TMP_Text)_pageStatusLabel.labelTMP).text = "Page Status: <color=#FF0000>OFFLINE</color>";
			if (!PageManager.IsCreatePageEnabled(out var reason))
			{
				string text2 = "<size=25><color=#FF0000>" + reason + "</color></size>";
				((TMP_Text)_pageUrlLabel.labelTMP).text = "You are unable to create a page! Reason:\n" + text2;
				((Component)_createPageButton).gameObject.SetActive(false);
			}
			else
			{
				((TMP_Text)_pageUrlLabel.labelTMP).text = "Create a page to share your prices\nwith your viewers!";
			}
		}

		private static void HandlePageCreated(string pageUrl)
		{
			HandlePageStatusChanged();
		}
	}
	internal static class PageManager
	{
		internal enum TwitchChannelStatus
		{
			None,
			Accepted,
			NotLive,
			NotAffiliateOrPartner,
			Banned,
			FailedToCheck
		}

		[CompilerGenerated]
		private sealed class <CheckPageStatusCoroutine>d__27 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			private UnityWebRequest <request>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <CheckPageStatusCoroutine>d__27(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<request>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ad: Invalid comparison between Unknown and I4
				//IL_0101: Unknown result type (might be due to invalid IL or missing references)
				//IL_0107: Invalid comparison between Unknown and I4
				bool result;
				try
				{
					switch (<>1__state)
					{
					default:
						result = false;
						break;
					case 0:
					{
						<>1__state = -1;
						string pageId = GetPageId();
						string pageAccessToken = GetPageAccessToken();
						if (string.IsNullOrEmpty(pageId) || string.IsNullOrEmpty(pageAccessToken))
						{
							HasPage = false;
							PageManager.OnPageStatusChanged?.Invoke();
							result = false;
							break;
						}
						string text = "https://twitchtrolling.up.railway.app/api/pages/" + pageId;
						<request>5__2 = UnityWebRequest.Get(text);
						<>1__state = -3;
						<>2__current = <request>5__2.SendWebRequest();
						<>1__state = 1;
						result = true;
						break;
					}
					case 1:
						<>1__state = -3;
						if ((int)<request>5__2.result == 3 && <request>5__2.responseCode == 404)
						{
							Logger.LogWarning("Page not found (404). Clearing saved page ID and access token.");
							SavePageId(string.Empty);
							SavePageAccessToken(string.Empty);
							HasPage = false;
							PageManager.OnPageStatusChanged?.Invoke();
							result = false;
						}
						else if ((int)<request>5__2.result != 1)
						{
							Logger.LogWarning("Page status check failed: " + <request>5__2.error);
							HasPage = false;
							PageManager.OnPageStatusChanged?.Invoke();
							result = false;
						}
						else
						{
							HasPage = true;
							PageManager.OnPageStatusChanged?.Invoke();
							result = false;
						}
						<>m__Finally1();
						break;
					}
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
				return result;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<request>5__2 != null)
				{
					((IDisposable)<request>5__2).Dispose();
				}
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <CreatePageCoroutine>d__28 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			private UnityWebRequest <request>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <CreatePageCoroutine>d__28(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<request>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_005a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0064: Expected O, but got Unknown
				//IL_0082: Unknown result type (might be due to invalid IL or missing references)
				//IL_008c: Expected O, but got Unknown
				//IL_0092: Unknown result type (might be due to invalid IL or missing references)
				//IL_009c: Expected O, but got Unknown
				//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f9: Invalid comparison between Unknown and I4
				bool result;
				try
				{
					switch (<>1__state)
					{
					default:
						result = false;
						break;
					case 0:
					{
						<>1__state = -1;
						if (!IsCreatePageEnabled(out var reason))
						{
							Logger.LogError("You are unable to create a page: " + reason);
							result = false;
							break;
						}
						string text4 = "https://twitchtrolling.up.railway.app/api/pages";
						string s = JsonConvert.SerializeObject((object)GetDataForPage());
						<request>5__2 = new UnityWebRequest(text4, "POST");
						<>1__state = -3;
						byte[] bytes = Encoding.UTF8.GetBytes(s);
						<request>5__2.uploadHandler = (UploadHandler)new UploadHandlerRaw(bytes);
						<request>5__2.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
						<request>5__2.SetRequestHeader("Content-Type", "application/json");
						<request>5__2.SetRequestHeader("Authorization", "Bearer d74c6ba6-4584-4969-8af9-066549673563");
						<>2__current = <request>5__2.SendWebRequest();
						<>1__state = 1;
						result = true;
						break;
					}
					case 1:
						{
							<>1__state = -3;
							if ((int)<request>5__2.result != 1)
							{
								Logger.LogError("Failed to create page: " + <request>5__2.error);
								PageManager.OnPageStatusChanged?.Invoke();
								result = false;
							}
							else
							{
								string text = <request>5__2.downloadHandler.text;
								JObject val;
								try
								{
									val = JObject.Parse(text);
								}
								catch (Exception ex)
								{
									Logger.LogError("Failed to parse create page response: " + ex.Message);
									PageManager.OnPageStatusChanged?.Invoke();
									result = false;
									goto IL_0213;
								}
								string text2 = ((object)val["id"])?.ToString();
								string text3 = ((object)val["accessToken"])?.ToString();
								if (string.IsNullOrEmpty(text2) || string.IsNullOrEmpty(text3))
								{
									Logger.LogError("Create page response missing required fields.");
									PageManager.OnPageStatusChanged?.Invoke();
									result = false;
								}
								else
								{
									SavePageId(text2);
									SavePageAccessToken(text3);
									HasPage = true;
									_updatePageDataFirstTime = true;
									PageManager.OnPageCreated?.Invoke(PageURL);
									result = false;
								}
							}
							goto IL_0213;
						}
						IL_0213:
						<>m__Finally1();
						break;
					}
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
				return result;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<request>5__2 != null)
				{
					((IDisposable)<request>5__2).Dispose();
				}
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <UpdatePageCoroutine>d__29 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public TimeSpan delay;

			private UnityWebRequest <request>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <UpdatePageCoroutine>d__29(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 2)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<request>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0034: Unknown result type (might be due to invalid IL or missing references)
				//IL_003e: Expected O, but got Unknown
				//IL_013e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0144: Invalid comparison between Unknown and I4
				//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ac: Expected O, but got Unknown
				//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d4: Expected O, but got Unknown
				//IL_00da: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e4: Expected O, but got Unknown
				bool result;
				try
				{
					switch (<>1__state)
					{
					default:
						result = false;
						break;
					case 0:
						<>1__state = -1;
						<>2__current = (object)new WaitForSeconds((float)delay.TotalSeconds);
						<>1__state = 1;
						result = true;
						break;
					case 1:
					{
						<>1__state = -1;
						string pageId = GetPageId();
						string pageAccessToken = GetPageAccessToken();
						if (string.IsNullOrEmpty(pageId) || string.IsNullOrEmpty(pageAccessToken))
						{
							Logger.LogWarning("UpdatePage: Missing Page ID or Access Token.");
							result = false;
							break;
						}
						string text = "https://twitchtrolling.up.railway.app/api/pages/" + pageId;
						string s = JsonConvert.SerializeObject((object)GetDataForPage());
						<request>5__2 = new UnityWebRequest(text, "PUT");
						<>1__state = -3;
						byte[] bytes = Encoding.UTF8.GetBytes(s);
						<request>5__2.uploadHandler = (UploadHandler)new UploadHandlerRaw(bytes);
						<request>5__2.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
						<request>5__2.SetRequestHeader("Content-Type", "application/json");
						<request>5__2.SetRequestHeader("Authorization", "Bearer " + pageAccessToken);
						<>2__current = <request>5__2.SendWebRequest();
						<>1__state = 2;
						result = true;
						break;
					}
					case 2:
						<>1__state = -3;
						if ((int)<request>5__2.result != 1)
						{
							Logger.LogError("Failed to update page: " + <request>5__2.error);
							result = false;
						}
						else
						{
							Logger.LogInfo("Page updated successfully.", extended: true);
							result = false;
						}
						<>m__Finally1();
						break;
					}
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
				return result;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<request>5__2 != null)
				{
					((IDisposable)<request>5__2).Dispose();
				}
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <VerifyTwitchChannelCoroutine>d__38 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			private UnityWebRequest <request>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <VerifyTwitchChannelCoroutine>d__38(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<request>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_002b: Invalid comparison between Unknown and I4
				//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b2: Invalid comparison between Unknown and I4
				//IL_0131: Unknown result type (might be due to invalid IL or missing references)
				//IL_0138: Expected O, but got Unknown
				//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
				//IL_021d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0224: Invalid comparison between Unknown and I4
				bool result;
				try
				{
					JObject val2;
					switch (<>1__state)
					{
					default:
						result = false;
						break;
					case 0:
					{
						<>1__state = -1;
						_twitchChannelStatus = TwitchChannelStatus.None;
						if ((int)API.ConnectionState != 2)
						{
							PageManager.OnPageStatusChanged?.Invoke();
							result = false;
							break;
						}
						string channel = API.Channel;
						string text2 = "https://api.ivr.fi/v2/twitch/user?login=" + channel;
						<request>5__2 = UnityWebRequest.Get(text2);
						<>1__state = -3;
						<request>5__2.SetRequestHeader("User-Agent", "TwitchTrolling/1.2.0");
						<>2__current = <request>5__2.SendWebRequest();
						<>1__state = 1;
						result = true;
						break;
					}
					case 1:
						{
							<>1__state = -3;
							if ((int)<request>5__2.result != 1)
							{
								Logger.LogError("VerifyTwitchChannel: Failed to verify Twitch channel.");
								_twitchChannelStatus = TwitchChannelStatus.FailedToCheck;
								PageManager.OnPageStatusChanged?.Invoke();
								result = false;
							}
							else
							{
								string text = <request>5__2.downloadHandler.text;
								try
								{
									JArray val = JArray.Parse(text);
									if (((JContainer)val).Count != 0)
									{
										val2 = (JObject)val[0];
										goto IL_0171;
									}
									Logger.LogWarning("VerifyTwitchChannel: No user found with the specified login.");
									_twitchChannelStatus = TwitchChannelStatus.FailedToCheck;
									PageManager.OnPageStatusChanged?.Invoke();
									result = false;
								}
								catch (Exception ex)
								{
									Logger.LogError("VerifyTwitchChannel: Failed to parse Twitch user response: " + ex.Message);
									_twitchChannelStatus = TwitchChannelStatus.FailedToCheck;
									PageManager.OnPageStatusChanged?.Invoke();
									result = false;
								}
							}
							goto IL_0258;
						}
						IL_0171:
						if (((JToken)val2).Value<bool>((object)"banned"))
						{
							_twitchChannelStatus = TwitchChannelStatus.Banned;
							PageManager.OnPageStatusChanged?.Invoke();
							result = false;
						}
						else
						{
							JObject val3 = (JObject)(((object)((JToken)val2).Value<JObject>((object)"roles")) ?? ((object)new JObject()));
							bool valueOrDefault = ((JToken)val3).Value<bool?>((object)"isAffiliate").GetValueOrDefault();
							bool valueOrDefault2 = ((JToken)val3).Value<bool?>((object)"isPartner").GetValueOrDefault();
							if (!valueOrDefault && !valueOrDefault2)
							{
								_twitchChannelStatus = TwitchChannelStatus.NotAffiliateOrPartner;
								PageManager.OnPageStatusChanged?.Invoke();
								result = false;
							}
							else if (val2["stream"] == null || (int)val2["stream"].Type == 10)
							{
								_twitchChannelStatus = TwitchChannelStatus.NotLive;
								PageManager.OnPageStatusChanged?.Invoke();
								result = false;
							}
							else
							{
								_twitchChannelStatus = TwitchChannelStatus.Accepted;
								PageManager.OnPageStatusChanged?.Invoke();
								result = false;
							}
						}
						goto IL_0258;
						IL_0258:
						<>m__Finally1();
						break;
					}
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
				return result;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<request>5__2 != null)
				{
					((IDisposable)<request>5__2).Dispose();
				}
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private const string _apiOrigin = "https://twitchtrolling.up.railway.app";

		private const string _createPageToken = "d74c6ba6-4584-4969-8af9-066549673563";

		private static bool _updatePageDataFirstTime;

		private static float _lastUpdatePageTime = float.NegativeInfinity;

		private const float _updatePageCooldown = 0.1f;

		private static string _previousChannel;

		private static TwitchChannelStatus _twitchChannelStatus;

		public static bool HasPage { get; private set; }

		public static string PageId => GetPageId();

		public static string PageURL
		{
			get
			{
				if (!HasPage)
				{
					return string.Empty;
				}
				return "https://twitchtrolling.com/page.html?id=" + PageId;
			}
		}

		public static event Action OnPageStatusChanged;

		public static event Action<string> OnPageCreated;

		public static void Initialize()
		{
			API.OnConnect += HandleTwitchOnConnect;
			Application.quitting += delegate
			{
				API.OnConnect -= HandleTwitchOnConnect;
			};
			_previousChannel = API.Channel;
			CheckPageStatus();
			VerifyTwitchChannel();
		}

		public static void CheckPageStatus()
		{
			PluginManager instance = PluginManager.Instance;
			if (instance != null)
			{
				((MonoBehaviour)instance).StartCoroutine(CheckPageStatusCoroutine());
			}
		}

		public static void CreatePage()
		{
			PluginManager instance = PluginManager.Instance;
			if (instance != null)
			{
				((MonoBehaviour)instance).StartCoroutine(CreatePageCoroutine());
			}
		}

		public static void UpdatePage()
		{
			if (HasPage)
			{
				float num = 0.1f;
				float realtimeSinceStartup = Time.realtimeSinceStartup;
				if (!(realtimeSinceStartup - _lastUpdatePageTime < num))
				{
					_lastUpdatePageTime = realtimeSinceStartup;
					((MonoBehaviour)PluginManager.Instance).StartCoroutine(UpdatePageCoroutine(TimeSpan.FromSeconds(num)));
				}
			}
		}

		public static void UpdatePageFirstTime()
		{
			if (!_updatePageDataFirstTime)
			{
				_updatePageDataFirstTime = true;
				UpdatePage();
			}
		}

		[IteratorStateMachine(typeof(<CheckPageStatusCoroutine>d__27))]
		private static IEnumerator CheckPageStatusCoroutine()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <CheckPageStatusCoroutine>d__27(0);
		}

		[IteratorStateMachine(typeof(<CreatePageCoroutine>d__28))]
		private static IEnumerator CreatePageCoroutine()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <CreatePageCoroutine>d__28(0);
		}

		[IteratorStateMachine(typeof(<UpdatePageCoroutine>d__29))]
		private static IEnumerator UpdatePageCoroutine(TimeSpan delay)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <UpdatePageCoroutine>d__29(0)
			{
				delay = delay
			};
		}

		private static JObject GetDataForPage()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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_005d: Expected O, but got Unknown
			//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_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Expected O, but got Unknown
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Expected O, but got Unknown
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Expected O, but got Unknown
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Expected O, but got Unknown
			JObject val = new JObject { ["channel"] = JToken.op_Implicit(API.Channel) };
			JArray val2 = new JArray();
			if (EnemyConfigManager.HasEnemies())
			{
				JObject val3 = new JObject
				{
					["name"] = JToken.op_Implicit("Random Enemy"),
					["price"] = JToken.op_Implicit(ConfigManager.TwitchCheerEvent_MinAmountForRandomEnemy.Value)
				};
				val2.Add((JToken)(object)val3);
			}
			foreach (EnemyConfigEntry configEntry in EnemyConfigManager.ConfigEntries)
			{
				if (configEntry.Enabled.Value)
				{
					JObject val4 = new JObject
					{
						["name"] = JToken.op_Implicit(configEntry.EnemyName),
						["price"] = JToken.op_Implicit(configEntry.BitsToSpawn.Value)
					};
					val2.Add((JToken)(object)val4);
				}
			}
			val["enemies"] = (JToken)(object)val2;
			JArray val5 = new JArray();
			if (MEventManager.HasEvents())
			{
				JObject val6 = new JObject
				{
					["name"] = JToken.op_Implicit("Random Event"),
					["price"] = JToken.op_Implicit(ConfigManager.Event_AmountForRandomEvent.Value)
				};
				val5.Add((JToken)(object)val6);
			}
			foreach (MEvent @event in MEventManager.Events)
			{
				if (@event.Enabled.Value)
				{
					JObject val7 = new JObject
					{
						["name"] = JToken.op_Implicit(@event.Name),
						["price"] = JToken.op_Implicit(@event.BitsPrice.Value)
					};
					val5.Add((JToken)(object)val7);
				}
			}
			val["events"] = (JToken)(object)val5;
			return val;
		}

		private static string GetPageId()
		{
			return Plugin.GlobalSave.Load("PageId", string.Empty);
		}

		private static string GetPageAccessToken()
		{
			return Plugin.GlobalSave.Load("PageAccessToken", string.Empty);
		}

		private static void SavePageId(string pageId)
		{
			Plugin.GlobalSave.Save("PageId", pageId);
		}

		private static void SavePageAccessToken(string accessToken)
		{
			Plugin.GlobalSave.Save("PageAccessToken", accessToken);
		}

		private static void HandleTwitchOnConnect()
		{
			string channel = API.Channel;
			if (!(_previousChannel == channel))
			{
				_previousChannel = channel;
				VerifyTwitchChannel();
				UpdatePage();
			}
		}

		public static bool IsCreatePageEnabled(out string reason)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Invalid comparison between Unknown and I4
			reason = string.Empty;
			if ((int)API.ConnectionState != 2)
			{
				reason = "You are not connected to Twitch!";
				return false;
			}
			if (_twitchChannelStatus == TwitchChannelStatus.None)
			{
				reason = "Your Twitch channel does not meet the requirements!";
				return false;
			}
			if (_twitchChannelStatus == TwitchChannelStatus.NotLive)
			{
				reason = "You are not live!";
				return false;
			}
			if (_twitchChannelStatus == TwitchChannelStatus.NotAffiliateOrPartner)
			{
				reason = "Your Twitch channel is not affiliate or partner!";
				return false;
			}
			if (_twitchChannelStatus == TwitchChannelStatus.Banned)
			{
				reason = "Your Twitch channel is banned!";
				return false;
			}
			return true;
		}

		public static void VerifyTwitchChannel()
		{
			PluginManager instance = PluginManager.Instance;
			if (instance != null)
			{
				((MonoBehaviour)instance).StartCoroutine(VerifyTwitchChannelCoroutine());
			}
		}

		[IteratorStateMachine(typeof(<VerifyTwitchChannelCoroutine>d__38))]
		private static IEnumerator VerifyTwitchChannelCoroutine()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <VerifyTwitchChannelCoroutine>d__38(0);
		}
	}
	[BepInPlugin("com.github.zehsteam.TwitchTrolling", "TwitchTrolling", "1.2.0")]
	[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; }

		private void Awake()
		{
			Instance = this;
			Logger.Initialize(Logger.CreateLogSource("com.github.zehsteam.TwitchTrolling"));
			Logger.LogInfo("TwitchTrolling has awoken!");
			_harmony.PatchAll(typeof(RunManagerPatch));
			_harmony.PatchAll(typeof(LevelGeneratorPatch));
			_harmony.PatchAll(typeof(EnemyDirectorPatch));
			_harmony.PatchAll(typeof(HUDCanvasPatch));
			_harmony.PatchAll(typeof(HurtColliderPatch));
			_harmony.PatchAll(typeof(TruckScreenTextPatch));
			_harmony.PatchAll(typeof(PlayerControllerPatch));
			_harmony.PatchAll(typeof(ItemDronePatch));
			_harmony.PatchAll(typeof(FanTrapPatch));
			_harmony.PatchAll(typeof(ItemRubberDuckPatch));
			_harmony.PatchAll(typeof(EnemyDuckPatch));
			GlobalSave = new JsonSave(Utils.GetPluginPersistentDataPath(), "GlobalSave");
			Assets.Load();
			ConfigManager.Initialize(((BaseUnityPlugin)this).Config);
			PluginManager.Spawn();
			TwitchIntegrationManager.Initialize();
			Menu.Initialize();
			PageManager.Initialize();
		}
	}
	internal static class Utils
	{
		[CompilerGenerated]
		private sealed class <InvokeAfterDurationCoroutine>d__5 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public TimeSpan duration;

			public Action action;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <InvokeAfterDurationCoroutine>d__5(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds((float)duration.TotalSeconds);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					action?.Invoke();
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		public static string GetPluginPersistentDataPath()
		{
			return Path.Combine(Application.persistentDataPath, "TwitchTrolling");
		}

		public static ConfigFile CreateConfigFile(BaseUnityPlugin plugin, string path, string name = null, bool saveOnInit = false)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			BepInPlugin metadata = MetadataHelper.GetMetadata((object)plugin);
			if (name == null)
			{
				name = metadata.GUID;
			}
			name += ".cfg";
			return new ConfigFile(Path.Combine(path, name), saveOnInit, metadata);
		}

		public static ConfigFile CreateLocalConfigFile(BaseUnityPlugin plugin, string name = null, bool saveOnInit = false)
		{
			return CreateConfigFile(plugin, Paths.ConfigPath, name, saveOnInit);
		}

		public static ConfigFile CreateGlobalConfigFile(BaseUnityPlugin plugin, string name = null, bool saveOnInit = false)
		{
			string pluginPersistentDataPath = GetPluginPersistentDataPath();
			if (name == null)
			{
				name = "global";
			}
			return CreateConfigFile(plugin, pluginPersistentDataPath, name, saveOnInit);
		}

		public static string GetTextWithReadableColor(string text, string hexColor, string backgroundHexColor = "#000000")
		{
			if (string.IsNullOrWhiteSpace(hexColor))
			{
				hexColor = "#FFFFFF";
			}
			if (string.IsNullOrWhiteSpace(backgroundHexColor))
			{
				backgroundHexColor = "#000000";
			}
			string readableColor = ColorHelper.GetReadableColor(hexColor, backgroundHexColor);
			return "<color=" + readableColor + ">" + text + "</color>";
		}

		[IteratorStateMachine(typeof(<InvokeAfterDurationCoroutine>d__5))]
		public static IEnumerator InvokeAfterDurationCoroutine(TimeSpan duration, Action action)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <InvokeAfterDurationCoroutine>d__5(0)
			{
				duration = duration,
				action = action
			};
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "com.github.zehsteam.TwitchTrolling";

		public const string PLUGIN_NAME = "TwitchTrolling";

		public const string PLUGIN_VERSION = "1.2.0";
	}
}
namespace com.github.zehsteam.TwitchTrolling.Twitch
{
	internal static class TwitchEventHandler
	{
		public static void Initialize()
		{
			try
			{
				API.OnMessage += HandleMessage;
				API.OnCheer += HandleCheer;
				API.OnSub += HandleSub;
				API.OnRaid += HandleRaid;
				Application.quitting += delegate
				{
					API.OnMessage -= HandleMessage;
					API.OnCheer -= HandleCheer;
					API.OnSub -= HandleSub;
					API.OnRaid -= HandleRaid;
				};
			}
			catch
			{
				Logger.LogFatal("TwitchEventHandler: Failed to initialize.");
				throw;
			}
		}

		public static void HandleMessage(TwitchMessage twitchMessage)
		{
		}

		public static void HandleCheer(TwitchCheerEvent cheerEvent)
		{
			//IL_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 (!CanHandleEvents())
			{
				ShowUnableToHandleEventsMessage();
				return;
			}
			if (!TwitchIntegrationManager.CanPlayEvents())
			{
				TwitchEventQueue.Enqueue(cheerEvent);
				return;
			}
			ViewerData viewerData = new ViewerData(((TwitchEvent)cheerEvent).User);
			int cheerAmount = cheerEvent.CheerAmount;
			string targetEnemyName = string.Empty;
			int spawnCount = 1;
			int bitsUsed;
			if (EnemyConfigManager.HasEnemies() && EnemyConfigManager.TryGetConfigEntriesThatMatchBitsAmount(cheerAmount, out var list))
			{
				if (list.TryGetRandom(out var enemyConfigEntry))
				{
					targetEnemyName = enemyConfigEntry.EnemyName;
				}
				bitsUsed = cheerAmount;
				SpawnEnemyFromBits(viewerData, bitsUsed, spawnCount, targetEnemyName);
				return;
			}
			if (MEventManager.Enabled && MEventManager.HasEvents())
			{
				float num = ConfigManager.Event_AmountForRandomEvent.Value;
				if (MEventManager.TryGetEvent(cheerAmount, out var mEvent))
				{
					mEvent.ExecuteEvent(viewerData, PlayerAvatar.instance, cheerAmount);
					return;
				}
				if ((float)cheerAmount == num && MEventManager.TryGetRandomEvent(out mEvent))
				{
					mEvent.ExecuteEvent(viewerData, PlayerAvatar.instance, cheerAmount);
					return;
				}
			}
			int accumulatedBits = TwitchIntegrationManager.GetAccumulatedBits(viewerData);
			cheerAmount += accumulatedBits;
			int value = ConfigManager.TwitchCheerEvent_MinAmountForRandomEnemy.Value;
			if (cheerAmount < value)
			{
				TwitchIntegrationManager.SetAccumulatedBits(viewerData, cheerAmount);
				return;
			}
			spawnCount = Mathf.FloorToInt((float)(cheerAmount / value));
			int num2 = cheerAmount % value;
			bitsUsed = cheerAmount - num2;
			TwitchIntegrationManager.SetAccumulatedBits(viewerData, num2);
			SpawnEnemyFromBits(viewerData, bitsUsed, spawnCount, targetEnemyName);
		}

		public static void HandleSub(TwitchSubEvent subEvent)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Invalid comparison between Unknown and I4
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Invalid comparison between Unknown and I4
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Invalid comparison between Unknown and I4
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			if (!TwitchIntegrationManager.IsSubEventEnabled)
			{
				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_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_0070: Unknown result type (might be due to invalid IL or missing references)
			if (TwitchIntegrationManager.IsRaidEventEnabled)
			{
				if (raidEvent == null)
				{
					Logger.LogError("TwitchEventHandler: Failed to handle raid. TwitchRaidEvent is null.");
					return;
				}
				if (!CanHandleEvents())
				{
					ShowUnableToHandleEventsMessage();
					return;
				}
				if (!TwitchIntegrationManager.CanPlayEvents())
				{
					TwitchEventQueue.Enqueue(raidEvent);
					return;
				}
				int value = ConfigManager.TwitchRaidEvent_ViewersPerRandomEnemy.Value;
				int value2 = ConfigManager.TwitchRaidEvent_MaxEnemySpawnCount.Value;
				int spawnCount = Mathf.Clamp(raidEvent.ViewerCount / value, 1, value2);
				string spawnReason = $"by raiding with {raidEvent.ViewerCount} viewers";
				ViewerSpawnData viewerSpawnData = new ViewerSpawnData(((TwitchEvent)raidEvent).User, spawnCount, spawnReason);
				Logger.LogInfo("HandleRaid:\n" + JsonConvert.SerializeObject((object)viewerSpawnData, (Formatting)1), extended: true);
				EnemyManager.SpawnEnemy(viewerSpawnData);
			}
		}

		private static string GetSpawnReason(TwitchSubEvent subEvent)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Invalid comparison between Unknown and I4
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Invalid comparison between Unknown and I4
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected I4, but got Unknown
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Invalid comparison between Unknown and I4
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Expected I4, but got Unknown
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Expected I4, but got Unknown
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected I4, but got Unknown
			if (subEvent == null)
			{
				return string.Empty;
			}
			string result = string.Empty;
			if ((int)subEvent.Type == 0)
			{
				result = (((int)subEvent.Tier != 0) ? $"by subbing at tier {(int)subEvent.Tier}" : "by subbing with prime");
			}
			else if ((int)subEvent.Type == 1)
			{
				result = (((int)subEvent.Tier != 0) ? $"by resubbing at tier {(int)subEvent.Tier} for {subEvent.CumulativeMonths} months" : $"by resubbing with prime for {subEvent.CumulativeMonths} months");
			}
			else if ((int)subEvent.Type == 2)
			{
				result = $"by gifting a tier {(int)subEvent.Tier} sub to {subEvent.RecipientUser}";
			}
			else if ((int)subEvent.Type == 3)
			{
				result = $"by gifting {subEvent.GiftCount} tier {(int)subEvent.Tier} subs";
			}
			return result;
		}

		private static void SpawnEnemyFromBits(ViewerData viewer, int bitsUsed, int spawnCount, string targetEnemyName)
		{
			string spawnReason = $"by cheering {bitsUsed} bits";
			ViewerSpawnData viewerSpawnData = new ViewerSpawnData(viewer, spawnCount, spawnReason, targetEnemyName);
			EnemyManager.SpawnEnemy(viewerSpawnData);
		}

		public static void ShowUnableToHandleEventsMessage()
		{
			MessageManager.Instance?.ShowMessage("<color=#FFFF00>Warning!</color> Triggering Twitch events is not currently supported on non-host clients\nDisable Twitch Chat API to hide these warnings");
		}

		public static bool CanHandleEvents()
		{
			if (!PhotonNetwork.InRoom)
			{
				return true;
			}
			return SemiFunc.IsMasterClientOrSingleplayer();
		}
	}
	internal static class TwitchEventQueue
	{
		[CompilerGenerated]
		private sealed class <PlayQueuedEventsCoroutine>d__17 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public TimeSpan initialDelay;

			private TimeSpan <delayBetweenEvents>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <PlayQueuedEventsCoroutine>d__17(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0063: Unknown result type (might be due to invalid IL or missing references)
				//IL_006d: Expected O, but got Unknown
				//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
				//IL_0109: Expected O, but got Unknown
				//IL_0143: Unknown result type (might be due to invalid IL or missing references)
				//IL_014d: Expected O, but got Unknown
				//IL_0187: Unknown result type (might be due to invalid IL or missing references)
				//IL_0191: Expected O, but got Unknown
				TwitchCheerEvent result;
				TwitchSubEvent result2;
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					Logger.LogInfo("TwitchEventQueue: Started playing queued events.", extended: true);
					Logger.LogInfo($"TwitchEventQueue: Playing queued events after {(float)initialDelay.TotalSeconds} seconds.", extended: true);
					<>2__current = (object)new WaitForSeconds((float)initialDelay.TotalSeconds);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					if (!TwitchEventHandler.CanHandleEvents())
					{
						return false;
					}
					if (!TwitchIntegrationManager.CanPlayEvents())
					{
						Logger.LogWarning("TwitchEventQueue: Failed to play queued events. You are not allowed to play events at this time.");
						return false;
					}
					if (!HasQueuedEvents())
					{
						Logger.LogInfo("TwitchEventQueue: No events in the queue to play.", extended: true);
						return false;
					}
					MessageManager.Instance?.ShowMessage("Playing Twitch events from the queue");
					<delayBetweenEvents>5__2 = TimeSpan.FromSeconds(0.5);
					goto IL_00d7;
				case 2:
					<>1__state = -1;
					goto IL_00d7;
				case 3:
					<>1__state = -1;
					goto IL_011b;
				case 4:
					{
						<>1__state = -1;
						break;
					}
					IL_00d7:
					if (TwitchIntegrationManager.IsCheerEventEnabled && CheerQueue.TryDequeue(out result))
					{
						TwitchEventHandler.HandleCheer(result);
						<>2__current = (object)new WaitForSeconds((float)<delayBetweenEvents>5__2.TotalSeconds);
						<>1__state = 2;
						return true;
					}
					goto IL_011b;
					IL_011b:
					if (TwitchIntegrationManager.IsSubEventEnabled && SubQueue.TryDequeue(out result2))
					{
						TwitchEventHandler.HandleSub(result2);
						<>2__current = (object)new WaitForSeconds((float)<delayBetweenEvents>5__2.TotalSeconds);
						<>1__state = 3;
						return true;
					}
					break;
				}
				if (TwitchIntegrationManager.IsRaidEventEnabled && RaidQueue.TryDequeue(out var result3))
				{
					TwitchEventHandler.HandleRaid(result3);
					<>2__current = (object)new WaitForSeconds((float)<delayBetweenEvents>5__2.TotalSeconds);
					<>1__state = 4;
					return true;
				}
				Logger.LogInfo("TwitchEventQueue: Finished plyaing queued events.", extended: true);
				SaveData();
				_playQueuedEventsCoroutine = null;
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private static Coroutine _playQueuedEventsCoroutine;

		public static Queue<TwitchCheerEvent> CheerQueue { get; private set; } = new Queue<TwitchCheerEvent>();


		public static Queue<TwitchSubEvent> SubQueue { get; private set; } = new Queue<TwitchSubEvent>();


		public static Queue<TwitchRaidEvent> RaidQueue { get; private set; } = new Queue<TwitchRaidEvent>();


		public static void LoadData()
		{
			Logger.LogInfo("TwitchEventQueue: Loading saved data...");
			try
			{
				if (Plugin.GlobalSave.TryLoad<string>("CheerQueue", out var value))
				{
					CheerQueue = JsonConvertHelper.DeserializeQueue<TwitchCheerEvent>(value);
					Logger.LogInfo("TwitchEventQueue: Loaded CheerQueue JSON data:\n\n" + value, extended: true);
				}
				if (Plugin.GlobalSave.TryLoad<string>("SubQueue", out value))
				{
					SubQueue = JsonConvertHelper.DeserializeQueue<TwitchSubEvent>(value);
					Logger.LogInfo("TwitchEventQueue: Loaded SubQueue JSON data:\n\n" + value, extended: true);
				}
				if (Plugin.GlobalSave.TryLoad<string>("RaidQueue", out value))
				{
					RaidQueue = JsonConvertHelper.DeserializeQueue<TwitchRaidEvent>(value);
					Logger.LogInfo("TwitchEventQueue: Loaded RaidQueue JSON data:\n\n" + value, extended: true);
				}
				Logger.LogInfo("TwitchEventQueue: Finished loading saved data.");
			}
			catch (Exception arg)
			{
				Logger.LogError($"TwitchEventQueue: Failed to load saved data. {arg}");
			}
		}

		public static void SaveData()
		{
			Logger.LogInfo("TwitchEventQueue: Saving data...", extended: true);
			try
			{
				Plugin.GlobalSave.Save("CheerQueue", JsonConvertHelper.SerializeQueue(CheerQueue));
				Plugin.GlobalSave.Save("SubQueue", JsonConvertHelper.SerializeQueue(SubQueue));
				Plugin.GlobalSave.Save("RaidQueue", JsonConvertHelper.SerializeQueue(RaidQueue));
				Logger.LogInfo("TwitchEventQueue: Saved data.", extended: true);
			}
			catch (Exception arg)
			{
				Logger.LogError($"TwitchEventQueue: Failed to save data. {arg}");
			}
		}

		public static void PlayQueuedEvents()
		{
			PlayQueuedEvents(TimeSpan.Zero);
		}

		public static void PlayQueuedEvents(TimeSpan initialDelay)
		{
			if (!TwitchIntegrationManager.IsEnabled)
			{
				Logger.LogWarning("TwitchEventQueue: Failed to play queued events. Twitch integration is not enabled.");
				return;
			}
			if ((Object)(object)PluginManager.Instance == (Object)null)
			{
				Logger.LogError("TwitchEventQueue: Failed to play queued events. PluginManager instance is null.");
				return;
			}
			if (!TwitchIntegrationManager.CanPlayEvents())
			{
				Logger.LogWarning("TwitchEventQueue: Failed to play queued events. You are not allowed to play events at this time.");
				return;
			}
			if (_playQueuedEventsCoroutine != null)
			{
				((MonoBehaviour)PluginManager.Instance).StopCoroutine(_playQueuedEventsCoroutine);
			}
			_playQueuedEventsCoroutine = ((MonoBehaviour)PluginManager.Instance).StartCoroutine(PlayQueuedEventsCoroutine(initialDelay));
		}

		[IteratorStateMachine(typeof(<PlayQueuedEventsCoroutine>d__17))]
		private static IEnumerator PlayQueuedEventsCoroutine(TimeSpan initialDelay)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <PlayQueuedEventsCoroutine>d__17(0)
			{
				initialDelay = initialDelay
			};
		}

		public static bool HasQueuedEvents()
		{
			if (CheerQueue.Count <= 0 && SubQueue.Count <= 0)
			{
				return RaidQueue.Count > 0;
			}
			return true;
		}

		public static void Enqueue(TwitchCheerEvent cheerEvent)
		{
			if (!CheerQueue.Contains(cheerEvent))
			{
				CheerQueue.Enqueue(cheerEvent);
				SaveData();
				ShowEnqueueMessage((TwitchEvent)(object)cheerEvent, "cheer");
			}
		}

		public static void Enqueue(TwitchSubEvent subEvent)
		{
			if (!SubQueue.Contains(subEvent))
			{
				SubQueue.Enqueue(subEvent);
				SaveData();
				ShowEnqueueMessage((TwitchEvent)(object)subEvent, "sub");
			}
		}

		public static void Enqueue(TwitchRaidEvent raidEvent)
		{
			if (!RaidQueue.Contains(raidEvent))
			{
				RaidQueue.Enqueue(raidEvent);
				SaveData();
				ShowEnqueueMessage((TwitchEvent)(object)raidEvent, "raid");
			}
		}

		private static void ShowEnqueueMessage(TwitchEvent twitchEvent, string eventName)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			string displayNameWithColor = twitchEvent.User.GetDisplayNameWithColor();
			string message = "Added Twitch " + eventName + " event from " + displayNameWithColor + " to queue";
			MessageManager.Instance?.ShowMessage(message);
		}
	}
	internal static class TwitchIntegrationManager
	{
		public static Dictionary<string, int> AccumulatedBits { get; private set; } = new Dictionary<string, int>();


		public static bool IsEnabled => ConfigManager.TwitchIntegration_Enabled.Value;

		public static bool IsCheerEventEnabled
		{
			get
			{
				if (IsEnabled)
				{
					return ConfigManager.TwitchCheerEvent_Enabled.Value;
				}
				return false;
			}
		}

		public static bool IsSubEventEnabled
		{
			get
			{
				if (IsEnabled)
				{
					return ConfigManager.TwitchSubEvent_Enabled.Value;
				}
				return false;
			}
		}

		public static bool IsRaidEventEnabled
		{
			get
			{
				if (IsEnabled)
				{
					return ConfigManager.TwitchRaidEvent_Enabled.Value;
				}
				return false;
			}
		}

		public static void Initialize()
		{
			LoadData();
			Application.quitting += SaveData;
			TwitchEventHandler.Initialize();
		}

		private static void LoadData()
		{
			Logger.LogInfo("TwitchIntegrationManager: Loading saved data...");
			try
			{
				TwitchEventQueue.LoadData();
				LoadAccumulatedBits();
				Logger.LogInfo("TwitchIntegrationManager: Finished loading saved data.");
			}
			catch (Exception arg)
			{
				Logger.LogError($"TwitchIntegrationManager: Failed to load saved data. {arg}");
			}
		}

		public static void SaveData()
		{
			Logger.LogInfo("TwitchIntegrationManager: Saving data...");
			try
			{
				TwitchEventQueue.SaveData();
				SaveAccumulatedBits();
				Logger.LogInfo("TwitchIntegrationManager: Saved data.");
			}
			catch (Exception arg)
			{
				Logger.LogError($"TwitchIntegrationManager: Failed to save data. {arg}");
			}
		}

		private static void LoadAccumulatedBits()
		{
			try
			{
				if (Plugin.GlobalSave.TryLoad<string>("AccumulatedBits", out var value))
				{
					AccumulatedBits = JsonConvert.DeserializeObject<Dictionary<string, int>>(value);
					Logger.LogInfo("TwitchIntegrationManager: Loaded AccumulatedBits JSON data:\n\n" + value, extended: true);
				}
			}
			catch (Exception arg)
			{
				Logger.LogError($"TwitchIntegrationManager: Failed to load AccumulatedBits from saved data. {arg}");
			}
		}

		public static void SaveAccumulatedBits()
		{
			Plugin.GlobalSave.Save("AccumulatedBits", JsonConvert.SerializeObject((object)AccumulatedBits));
		}

		public static int GetAccumulatedBits(ViewerData viewer)
		{
			if (viewer == null)
			{
				return 0;
			}
			return GetAccumulatedBits(viewer.Username);
		}

		public static int GetAccumulatedBits(string username)
		{
			return AccumulatedBits.GetValueOrDefault(username.ToLower(), 0);
		}

		public static void SetAccumulatedBits(ViewerData viewer, int value)
		{
			if (viewer != null)
			{
				if (value <= 0)
				{
					AccumulatedBits.Remove(viewer.Username);
				}
				else
				{
					AccumulatedBits[viewer.Username] = value;
				}
				SaveAccumulatedBits();
			}
		}

		public static bool CanPlayEvents()
		{
			if (!IsEnabled)
			{
				return false;
			}
			return EnemyManager.CanSpawnEnemies();
		}
	}
}
namespace com.github.zehsteam.TwitchTrolling.Twitch.Objects
{
	[Serializable]
	public class ViewerData
	{
		public string UserId { get; }

		public string Username => DisplayName.ToLower();

		public string DisplayName { get; }

		public string Color { get; }

		public ViewerData(string userId, string displayName, string color)
		{
			UserId = userId;
			DisplayName = displayName;
			Color = color;
		}

		public ViewerData(TwitchUser twitchUser)
		{
			UserId = ((TwitchUser)(ref twitchUser)).UserId;
			DisplayName = ((TwitchUser)(ref twitchUser)).DisplayName;
			Color = ((TwitchUser)(ref twitchUser)).Color;
		}

		public string GetDisplayNameWithColor()
		{
			return Utils.GetTextWithReadableColor(DisplayName, Color);
		}
	}
	[Serializable]
	public class ViewerSpawnData
	{
		public ViewerData Viewer { get; private set; }

		public int SpawnCount { get; private set; }

		public string SpawnReason { get; private set; }

		public string TargetEnemyName { get; private set; }

		public int TotalSpawnCount { get; private set; }

		public ViewerSpawnData(ViewerData viewer, int spawnCount, string spawnReason, string targetEnemyName = "")
		{
			Viewer = viewer;
			SpawnCount = spawnCount;
			SpawnReason = spawnReason;
			TargetEnemyName = targetEnemyName;
		}

		public ViewerSpawnData(TwitchUser twitchUser, int spawnCount, string spawnReason, string targetEnemyName = "")
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			Viewer = new ViewerData(twitchUser);
			SpawnCount = spawnCount;
			SpawnReason = spawnReason;
			TargetEnemyName = targetEnemyName;
		}

		public void SetTargetEnemyName(string value)
		{
			TargetEnemyName = value;
		}

		public void SetTotalSpawnCount(int value)
		{
			TotalSpawnCount = value;
		}
	}
}
namespace com.github.zehsteam.TwitchTrolling.Twitch.Helpers
{
	internal static class TwitchHelper
	{
		public static TwitchUser CreateTwitchUser(bool isVIP = false, bool isSubscriber = false, bool isModerator = false, bool isBroadcaster = false)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (PlayerHelper.TryGetLocalPlayer(out var playerAvatar))
			{
				string steamID = playerAvatar.steamID;
				string displayName = SemiFunc.PlayerGetName(playerAvatar);
				string color = ColorHelper.ColorToHex(SemiFunc.PlayerGetColorFromSteamID(steamID));
				return CreateTwitchUser(steamID, displayName, color, isVIP, isSubscriber, isModerator, isBroadcaster);
			}
			return CreateTwitchUser("0", "Unknown", "#FFFFFF", isVIP, isSubscriber, isModerator, isBroadcaster);
		}

		public static TwitchUser CreateTwitchUser(string userId, string displayName, string color = "#FFFFFF", bool isVIP = false, bool isSubscriber = false, bool isModerator = false, bool isBroadcaster = false)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			TwitchUser result = default(TwitchUser);
			((TwitchUser)(ref result)).UserId = userId;
			((TwitchUser)(ref result)).Username = displayName.ToLower();
			((TwitchUser)(ref result)).DisplayName = displayName;
			((TwitchUser)(ref result)).Color = color;
			((TwitchUser)(ref result)).IsVIP = isVIP;
			((TwitchUser)(ref result)).IsSubscriber = isSubscriber;
			((TwitchUser)(ref result)).IsModerator = isModerator;
			((TwitchUser)(ref result)).IsBroadcaster = isBroadcaster;
			return result;
		}
	}
}
namespace com.github.zehsteam.TwitchTrolling.Twitch.Commands
{
	internal static class TwitchSimulateCheerCommand
	{
		[CommandExecution("Simulate Cheer", "Simulate Twitch cheers.", true, false)]
		[CommandAlias("simulatecheer")]
		[CommandAlias("simcheer")]
		[CommandAlias("scheer")]
		[CommandAlias("cheer")]
		public static void SimulateCheer(string args)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			int cheerAmount = ConfigManager.TwitchCheerEvent_MinAmountForRandomEnemy.Value;
			if (int.TryParse(args, out var result))
			{
				cheerAmount = result;
			}
			TwitchCheerEvent cheerEvent = new TwitchCheerEvent
			{
				User = TwitchHelper.CreateTwitchUser(),
				CheerAmount = cheerAmount
			};
			TwitchEventHandler.HandleCheer(cheerEvent);
		}
	}
	internal static class TwitchSimulateSubCommand
	{
		[CommandExecution("Simulate Sub", "Simulate Twitch subscriptions.", true, false)]
		[CommandAlias("simulatesub")]
		[CommandAlias("simsub")]
		[CommandAlias("ssub")]
		[CommandAlias("sub")]
		public static void SimulateSubs(string args)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			int giftCount = 1;
			if (int.TryParse(args, out var result))
			{
				giftCount = result;
			}
			TwitchSubEvent subEvent = new TwitchSubEvent
			{
				User = TwitchHelper.CreateTwitchUser(),
				Type = (SubType)3,
				Tier = (SubTier)1,
				GiftCount = giftCount
			};
			TwitchEventHandler.HandleSub(subEvent);
		}
	}
}
namespace com.github.zehsteam.TwitchTrolling.Patches
{
	[HarmonyPatch(typeof(EnemyDirector))]
	internal static class EnemyDirectorPatch
	{
		private static bool _patchedStart;

		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void StartPatch()
		{
			if (!_patchedStart)
			{
				_patchedStart = true;
				EnemyConfigManager.Initialize();
				PageManager.UpdatePageFirstTime();
			}
		}
	}
	[HarmonyPatch(typeof(EnemyDuck))]
	internal static class EnemyDuckPatch
	{
		public static List<EnemyDuck> DucksToBypassStunAggroOnce = new List<EnemyDuck>();

		public static void Reset()
		{
			DucksToBypassStunAggroOnce = new List<EnemyDuck>();
		}

		[HarmonyPatch("StateStun")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> StateStunTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			string text = "EnemyDuckPatch: [StateStun Transpiler]";
			MethodInfo methodInfo = AccessTools.Method(typeof(EnemyDuck), "UpdateState", (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(EnemyDuckPatch), "StateStun_UpdateState", (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo2 == null)
			{
				Logger.LogError(text + " Failed to create transpiler. Required methods not found.");
				return instructions;
			}
			List<CodeInstruction> list = new List<CodeInstruction>();
			foreach (CodeInstruction instruction in instructions)
			{
				if (CodeInstructionExtensions.Calls(instruction, methodInfo))
				{
					list.Add(new CodeInstruction(OpCodes.Call, (object)methodInfo2));
					Logger.LogInfo(text + " Replaced " + methodInfo.Name + " call with " + methodInfo2.Name + ".", extended: true);
				}
				else
				{
					list.Add(instruction);
				}
			}
			return list.AsEnumerable();
		}

		private static void StateStun_UpdateState(EnemyDuck enemyDuck, State state)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if ((int)state == 11 && DucksToBypassStunAggroOnce.Contains(enemyDuck))
			{
				DucksToBypassStunAggroOnce.Remove(enemyDuck);
				enemyDuck.UpdateState((State)1);
			}
			else
			{
				enemyDuck.UpdateState(state);
			}
		}
	}
	[HarmonyPatch(typeof(FanTrap))]
	internal static class FanTrapPatch
	{
		public static List<FanTrap> FansToBypassIdle = new List<FanTrap>();

		[HarmonyPatch("SetState")]
		[HarmonyPrefix]
		private static bool SetStatePatch(FanTrap __instance, States state)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			if ((int)state != 0)
			{
				return true;
			}
			if (FansToBypassIdle.Contains(__instance))
			{
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(HUDCanvas))]
	internal static class HUDCanvasPatch
	{
		[HarmonyPatch("Awake")]
		[HarmonyPostfix]
		private static void AwakePatch(HUDCanvas __instance)
		{
			Transform parent = ((Component)__instance).transform.Find("HUD").Find("Game Hud");
			PluginHUD.Spawn(parent);
		}
	}
	[HarmonyPatch(typeof(HurtCollider))]
	internal static class HurtColliderPatch
	{
		[HarmonyPatch("PlayerHurt")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> PlayerHurtTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			string text = "HurtColliderPatch: [PlayerHurt Transpiler]";
			MethodInfo methodInfo = AccessTools.Method(typeof(PlayerHealth), "Hurt", (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(PlayerHelper), "HurtWithCaller", (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo2 == null)
			{
				Logger.LogError(text + " Failed to create transpiler. Required methods not found.");
				return instructions;
			}
			List<CodeInstruction> list = new List<CodeInstruction>();
			foreach (CodeInstruction instruction in instructions)
			{
				if (CodeInstructionExtensions.Calls(instruction, methodInfo))
				{
					list.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null));
					list.Add(new CodeInstruction(OpCodes.Call, (object)methodInfo2));
					Logger.LogInfo(text + " Replaced " + methodInfo.Name + " call with " + methodInfo2.Name + ".", extended: true);
				}
				else
				{
					list.Add(instruction);
				}
			}
			return list.AsEnumerable();
		}
	}
	[HarmonyPatch(typeof(ItemDrone))]
	internal static class ItemDronePatch
	{
		public static List<PhysGrabObject> IgnorePhysGrabObjects = new List<PhysGrabObject>();

		[HarmonyPatch("NewRayHitPointLogic")]
		[HarmonyPrefix]
		private static bool NewRayHitPointLogicPatch(ItemDrone __instance, int photonViewId, Transform newMagnetTarget)
		{
			PhysGrabObject physGrabObject = ((!((Object)(object)newMagnetTarget != (Object)null)) ? ((Component)PhotonView.Find(photonViewId)).gameObject.GetComponent<PhysGrabObject>() : ((Component)newMagnetTarget).GetComponent<PhysGrabObject>());
			return CanAttachToPhysGrabObject(__instance, physGrabObject);
		}

		[HarmonyPatch("GetHighestParentWithRigidbody")]
		[HarmonyPostfix]
		private static void GetHighestParentWithRigidbodyPatch(ItemDrone __instance, ref Transform __result)
		{
			PhysGrabObject physGrabObject = default(PhysGrabObject);
			if (!((Object)(object)__result == (Object)null) && ((Component)__result).TryGetComponent<PhysGrabObject>(ref physGrabObject) && !CanAttachToPhysGrabObject(__instance, physGrabObject))
			{
				__result = null;
			}
		}

		private static bool CanAttachToPhysGrabObject(ItemDrone itemDrone, PhysGrabObject physGrabObject)
		{
			if ((Object)(object)itemDrone == (Object)null || (Object)(object)physGrabObject == (Object)null)
			{
				return true;
			}
			if (IsSameDroneType(itemDrone, physGrabObject))
			{
				return false;
			}
			if (IgnorePhysGrabObjects.Contains(physGrabObject))
			{
				return false;
			}
			return true;
		}

		private static bool IsSameDroneType(ItemDrone itemDrone, PhysGrabObject physGrabObject)
		{
			if ((Object)(object)itemDrone == (Object)null || (Object)(object)physGrabObject == (Object)null)
			{
				return false;
			}
			ItemAttributes val = default(ItemAttributes);
			if (!((Component)physGrabObject).TryGetComponent<ItemAttributes>(ref val))
			{
				return false;
			}
			return itemDrone.itemAttributes.itemName == val.itemName;
		}
	}
	[HarmonyPatch(typeof(ItemRubberDuck))]
	internal static class ItemRubberDuckPatch
	{
		public static List<ItemRubberDuck> SpecialRubberDucks = new List<ItemRubberDuck>();

		[HarmonyPatch("Quack")]
		[HarmonyPostfix]
		private static void QuackPatch(ItemRubberDuck __instance)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			if (SpecialRubberDucks.Contains(__instance) && SemiFunc.IsMasterClientOrSingleplayer() && !(__instance.itemBattery.batteryLife <= 0f) && !__instance.physGrabObject.grabbed)
			{
				Vector3 velocity = __instance.rb.velocity;
				if (((Vector3)(ref velocity)).magnitude >= 20f)
				{
					Rigidbody rb = __instance.rb;
					rb.velocity *= 5f;
					__instance.rb.AddTorque(Random.insideUnitSphere * 40f);
				}
			}
		}
	}
	[HarmonyPatch(typeof(LevelGenerator))]
	internal static class LevelGeneratorPatch
	{
		[HarmonyPatch("EnemySetup")]
		[HarmonyPostfix]
		private static void EnemySetupPatch()
		{
			EnemyManager.ResetViewerEnemies();
			EnemyDuckPatch.Reset();
			if (TwitchIntegrationManager.CanPlayEvents())
			{
				TwitchEventQueue.PlayQueuedEvents(TimeSpan.FromSeconds(10.0));
			}
		}
	}
	[HarmonyPatch(typeof(PlayerController))]
	internal static class PlayerControllerPatch
	{
		private static bool _usingCustomSpeed;

		private static float _timeCustomSpeedEnd = float.NegativeInfinity;