Decompiled source of SpectatorChat v1.1.8

SpectatorChat.dll

Decompiled 4 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
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 System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using LethalCompanyInputUtils.Api;
using Microsoft.CodeAnalysis;
using OPJosMod.ReviveCompany;
using OPJosMod.ReviveCompany.CustomRpc;
using ReservedItemSlotCore.Patches;
using SpectatorChat.API;
using SpectatorChat.Other;
using SpectatorChat.Patch.Chat;
using SpectatorChat.Patch.HUD;
using SpectatorChat.Patch.Other;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("Build")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("5.0.1")]
[assembly: AssemblyInformationalVersion("3.0.0")]
[assembly: AssemblyProduct("SpectatorChat")]
[assembly: AssemblyTitle("SpectatorChat")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("5.0.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 SpectatorChat
{
	[BepInPlugin("Kaguya.SpectatorChat", "SpectatorChat", "1.1.8")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public class InputKey : LcInputActions
		{
			[InputAction("<Keyboard>/r", Name = "ToggleDeathBox")]
			public InputAction ToggleDeathBoxKey { get; set; }
		}

		private const string ModGuid = "Kaguya.SpectatorChat";

		private const string ModName = "SpectatorChat";

		private const string ModVersion = "1.1.8";

		private static readonly List<string> ModId = new List<string>();

		private readonly Harmony _harmony = new Harmony("Kaguya.SpectatorChat");

		private static Plugin Instance;

		public static ManualLogSource mls;

		internal static InputKey InputActionInstance = new InputKey();

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

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

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

		public static bool KeyPressed { get; set; }

		private void Awake()
		{
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = this;
			}
			mls = Logger.CreateLogSource("Kaguya.SpectatorChat");
			mls.LogInfo((object)"SpectatorChat has loaded.");
			LoadConfigs();
			PatchAll();
			LogPatchInfo();
		}

		private void LoadSpecificPatch()
		{
			ModId.Add("OpJosMod.ReviveCompany");
			ModId.Add("FlipMods.ReservedItemSlotCore");
			((MonoBehaviour)this).StartCoroutine(WaitForDependentMod());
		}

		private IEnumerator WaitForDependentMod()
		{
			float startTime = Time.time;
			float timeout = 120f;
			if (!GlobalVariables.Init)
			{
				GlobalVariables.Init = true;
				while (Time.time - startTime <= timeout)
				{
					Dictionary<string, PluginInfo> pluginInfos = Chainloader.PluginInfos;
					int num = 0;
					foreach (string key in pluginInfos.Keys)
					{
						if (key == "OpJosMod.ReviveCompany")
						{
							_harmony.PatchAll(typeof(ReviveCompanyPatch));
							num++;
							mls.LogInfo((object)("Detected " + key + ", Proceeding PostPatch..."));
						}
						else if (key == "FlipMods.ReservedItemSlotCore")
						{
							GlobalVariables.InitReservedItem = true;
							num++;
							mls.LogInfo((object)("Detected " + key + ", Proceeding..."));
						}
					}
					mls.LogInfo((object)$"Mod found. Totally {num} Extra method were executed.");
					yield return (object)new WaitForSeconds(10f);
				}
			}
			mls.LogInfo((object)"Timeout reached or canceled.");
		}

		private void PatchAll()
		{
			_harmony.PatchAll(typeof(EnableChatPatch));
			_harmony.PatchAll(typeof(SubmitChatPatch));
			_harmony.PatchAll(typeof(HUDPatch));
			_harmony.PatchAll(typeof(AddPlayerChatMessagePatch));
			_harmony.PatchAll(typeof(HUDManagerPostfixPatch));
			_harmony.PatchAll(typeof(KillPlayerPostfixPatch));
			_harmony.PatchAll(typeof(HideHUDPostfixPatch));
			_harmony.PatchAll(typeof(SetShipReadyToLandPostfix));
			_harmony.PatchAll(typeof(KeyPatch));
			LoadSpecificPatch();
		}

		private void LoadConfigs()
		{
			ShowClock = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "ShowClock", true, "Show the clock for spectator players.");
			CanLivingPlayerReceiveMessage = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "CanLivingPlayerReceiveMessage", false, "Can living player receive dead player's message.");
			CoroutineDelay = ((BaseUnityPlugin)this).Config.Bind<float>("Settings", "CoroutineDelay", 1f, "How long will the coroutine delay.");
			mls.LogInfo((object)$"Plugin loaded with config: ShowClock: {ShowClock.Value}, CanLivingPlayerReceiveMessage: {CanLivingPlayerReceiveMessage.Value}, CoroutineDelay: {CoroutineDelay.Value}");
		}

		private void LogPatchInfo()
		{
			mls.LogInfo((object)HarmonyAPI.GetPatchInfoAsString(_harmony, AccessTools.Method(typeof(HUDManager), "Awake", (Type[])null, (Type[])null)));
			mls.LogInfo((object)HarmonyAPI.GetPatchInfoAsString(_harmony, AccessTools.Method(typeof(HUDManager), "EnableChat_performed", (Type[])null, (Type[])null)));
			mls.LogInfo((object)HarmonyAPI.GetPatchInfoAsString(_harmony, AccessTools.Method(typeof(HUDManager), "SubmitChat_performed", (Type[])null, (Type[])null)));
			mls.LogInfo((object)HarmonyAPI.GetPatchInfoAsString(_harmony, AccessTools.Method(typeof(PlayerControllerB), "KillPlayer", (Type[])null, (Type[])null)));
			mls.LogInfo((object)HarmonyAPI.GetPatchInfoAsString(_harmony, AccessTools.Method(typeof(PlayerControllerB), "Update", (Type[])null, (Type[])null)));
			mls.LogInfo((object)HarmonyAPI.GetPatchInfoAsString(_harmony, AccessTools.Method(typeof(HUDManager), "HideHUD", (Type[])null, (Type[])null)));
			mls.LogInfo((object)HarmonyAPI.GetPatchInfoAsString(_harmony, AccessTools.Method(typeof(StartOfRound), "SetShipReadyToLand", (Type[])null, (Type[])null)));
			mls.LogInfo((object)HarmonyAPI.GetPatchInfoAsString(_harmony, AccessTools.Method(typeof(CompleteRecievedTasks), "RevivePlayer", (Type[])null, (Type[])null)));
		}
	}
}
namespace SpectatorChat.Patch.Other
{
	internal static class HideHUDPostfixPatch
	{
		[HarmonyPatch(typeof(HUDManager), "HideHUD")]
		private static void Postfix(HUDManager __instance)
		{
			HarmonyAPI.LogCallingMethod("HideHUD");
			if (Generic.Instance.IsCoroutineNull())
			{
				return;
			}
			try
			{
				if (Generic.Instance.StopPermanentTransparent())
				{
					Plugin.mls.LogInfo((object)("Routine stopped successfully. Player " + GlobalVariables.PlayerControllerInstance.playerUsername));
				}
				else
				{
					Plugin.mls.LogInfo((object)("Routine stopped failed. Player " + GlobalVariables.PlayerControllerInstance.playerUsername));
				}
			}
			catch (Exception ex)
			{
				Plugin.mls.LogError((object)(ex.StackTrace + ex.Message));
				throw;
			}
		}
	}
	internal static class KillPlayerPostfixPatch
	{
		[HarmonyPatch(typeof(PlayerControllerB), "KillPlayer")]
		private static void Postfix(PlayerControllerB __instance)
		{
			HarmonyAPI.LogCallingMethod("KillPlayer");
			if (((NetworkBehaviour)__instance).IsOwner && Generic.Instance.StartPermanentTransparent())
			{
				GlobalVariables.PlayerControllerInstance.bleedingHeavily = false;
				GlobalVariables.PlayerControllerInstance.criticallyInjured = false;
				HUDManager.Instance.HUDAnimator.SetTrigger("revealHud");
				Plugin.mls.LogInfo((object)("Routine start successfully. Player " + __instance.playerUsername));
			}
		}
	}
	internal static class ReviveCompanyPatch
	{
		[HarmonyPatch(typeof(CompleteRecievedTasks), "RevivePlayer")]
		private static bool Prefix(ref string playerIdString)
		{
			HarmonyAPI.LogCallingMethod("RevivePlayer");
			if (int.TryParse(playerIdString, out var result))
			{
				GeneralUtil.RevivePlayer(result);
				if (Generic.IsInstanceOwner(playerIdString))
				{
					Plugin.mls.LogInfo((object)$"Player {GlobalVariables.PlayerControllerInstance.playerUsername} has been revived and IsInstanceOwner: {Generic.IsInstanceOwner(playerIdString)}");
					Generic.ClearSpectatorUI(GlobalVariables.HUDManagerInstance);
					if (Generic.Instance.StopPermanentTransparent())
					{
						Plugin.mls.LogInfo((object)("Routine stopped successfully. Player " + GlobalVariables.PlayerControllerInstance.playerUsername));
					}
					else
					{
						Plugin.mls.LogInfo((object)("Routine stopped failed. Player " + GlobalVariables.PlayerControllerInstance.playerUsername));
					}
				}
			}
			else
			{
				Plugin.mls.LogError((object)("Error: Invalid player ID '" + playerIdString + "' did not revive"));
			}
			return false;
		}
	}
}
namespace SpectatorChat.Patch.HUD
{
	[HarmonyPatch(typeof(HUDManager), "Awake")]
	internal static class HUDManagerPostfixPatch
	{
		private static void Postfix(HUDManager __instance)
		{
			HUDManager __instance2 = __instance;
			HarmonyAPI.LogCallingMethod("HUDManager.Awake");
			GlobalVariables.HUDManagerInstance = __instance2;
			if (GlobalVariables.InitReservedItem)
			{
				ReservedItemUI.InitReservedItemUI();
			}
			if (Plugin.ShowClock.Value)
			{
				GlobalVariables.HUDElements = __instance2.HUDElements.Where((HUDElement element) => element != __instance2.HUDElements[1] && element != __instance2.HUDElements[5]).ToArray();
			}
			else
			{
				GlobalVariables.HUDElements = __instance2.HUDElements.Where((HUDElement element) => element != __instance2.HUDElements[1]).ToArray();
			}
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "KillPlayer")]
	internal static class HUDPatch
	{
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			HarmonyAPI.LogCallingMethod("KillPlayer");
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			MethodInfo hideHUDMethod = typeof(HUDManager).GetMethod("HideHUD");
			Plugin.mls.LogInfo((object)"Processing KillPlayer method...");
			int num;
			try
			{
				num = list.FindLastIndex((CodeInstruction i) => i.opcode == OpCodes.Callvirt && i.operand is MethodInfo methodInfo && methodInfo.Equals(hideHUDMethod));
				Plugin.mls.LogInfo((object)$"Index: {num} Code: {list[num]} found.");
				num -= 2;
			}
			catch (Exception ex)
			{
				Plugin.mls.LogError((object)(ex.Message + ex.StackTrace));
				throw;
			}
			try
			{
				Plugin.mls.LogInfo((object)"Patching following codes...");
				for (int j = 0; j <= 2; j++)
				{
					Plugin.mls.LogInfo((object)$"Index: {num + j}, Code: {list[num + j]}");
					list[num + j].opcode = OpCodes.Nop;
				}
				Plugin.mls.LogInfo((object)"Patched codes:");
				for (int k = 0; k <= 2; k++)
				{
					Plugin.mls.LogInfo((object)$"Index: {num + k}, Code: {list[num + k]}");
				}
			}
			catch (Exception ex2)
			{
				Plugin.mls.LogError((object)(ex2.Message + ex2.StackTrace));
				throw;
			}
			finally
			{
				Plugin.mls.LogInfo((object)"Patch success. No any fatal error were raised.");
			}
			foreach (CodeInstruction item in list)
			{
				yield return item;
			}
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "Update")]
	internal static class KeyPatch
	{
		internal static void Postfix(PlayerControllerB __instance)
		{
			if ((!((NetworkBehaviour)__instance).IsOwner || (!__instance.isPlayerControlled && !__instance.isPlayerDead) || (((NetworkBehaviour)__instance).IsServer && !__instance.isHostPlayerObject)) && !__instance.isTestingPlayer)
			{
				return;
			}
			if ((Object)(object)GlobalVariables.PlayerControllerInstance != (Object)(object)__instance || (Object)(object)GlobalVariables.PlayerControllerInstance == (Object)null)
			{
				Plugin.mls.LogInfo((object)$"Player instance has changed due to {(Object)(object)GlobalVariables.PlayerControllerInstance != (Object)(object)__instance} or {(Object)(object)GlobalVariables.PlayerControllerInstance == (Object)null}");
				GlobalVariables.PlayerControllerInstance = __instance;
			}
			if (__instance.isPlayerDead && Plugin.InputActionInstance.ToggleDeathBoxKey.WasPressedThisFrame())
			{
				if (!Plugin.KeyPressed)
				{
					Generic.ToggleSpectatorBoxUI(GlobalVariables.HUDManagerInstance, isVisable: false);
					Plugin.KeyPressed = true;
				}
				else
				{
					Generic.ToggleSpectatorBoxUI(GlobalVariables.HUDManagerInstance, isVisable: true);
					Plugin.KeyPressed = false;
				}
			}
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "SetShipReadyToLand")]
	internal static class SetShipReadyToLandPostfix
	{
		private static void Postfix()
		{
			HarmonyAPI.LogCallingMethod("StartOfRound.SetShipReadyToLand");
			Generic.ClearSpectatorUI(GlobalVariables.HUDManagerInstance);
		}
	}
}
namespace SpectatorChat.Patch.Chat
{
	[HarmonyPatch(typeof(HUDManager), "AddPlayerChatMessageClientRpc")]
	internal static class AddPlayerChatMessagePatch
	{
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
		{
			HarmonyAPI.LogCallingMethod("AddPlayerChatMessageClientRpc");
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			Label label = generator.DefineLabel();
			FieldInfo targetField = typeof(PlayerControllerB).GetField("isPlayerDead");
			Plugin.mls.LogInfo((object)"Processing AddPlayerChatMessageClientRpc method...");
			int num;
			try
			{
				num = list.FindLastIndex((CodeInstruction instruction) => instruction.opcode == OpCodes.Ldfld && instruction.operand is FieldInfo fieldInfo && fieldInfo.Equals(targetField));
				Plugin.mls.LogInfo((object)$"Index: {num} Code: {list[num]} found.");
				num -= 9;
				Plugin.mls.LogInfo((object)$"Got previous IL Code: {list[num]}.");
			}
			catch (Exception ex)
			{
				Plugin.mls.LogError((object)(ex.Message + ex.StackTrace));
				throw;
			}
			try
			{
				Plugin.mls.LogInfo((object)"Patching following codes...");
				for (int i = 0; i <= 11; i++)
				{
					Plugin.mls.LogInfo((object)$"Index: {num + i}, Code: {list[num + i]}");
					list[num + i].opcode = OpCodes.Nop;
				}
				Plugin.mls.LogInfo((object)"Patched codes:");
				for (int j = 0; j <= 11; j++)
				{
					Plugin.mls.LogInfo((object)$"Index: {num + j}, Code: {list[num + j]}");
				}
			}
			catch (Exception ex2)
			{
				Plugin.mls.LogError((object)(ex2.Message + ex2.StackTrace));
				throw;
			}
			finally
			{
				Plugin.mls.LogInfo((object)"Patch success. No any fatal error were raised.");
			}
			Plugin.mls.LogInfo((object)"Now processing patch 2...");
			try
			{
				num = list.FindLastIndex((CodeInstruction instruction) => instruction.opcode == OpCodes.Ldloc_0);
				Plugin.mls.LogInfo((object)$"Index: {num} Code: {list[num]} found.");
				num++;
				Plugin.mls.LogInfo((object)$"Got next IL Code: {list[num]}.");
				list[num + 1].opcode = OpCodes.Nop;
				num++;
				list.InsertRange(num, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[4]
				{
					new CodeInstruction(OpCodes.Callvirt, (object)AccessTools.PropertyGetter(typeof(Plugin), "CanLivingPlayerReceiveMessage")),
					new CodeInstruction(OpCodes.Brtrue_S, (object)label),
					new CodeInstruction(OpCodes.Ret, (object)null),
					CodeInstructionExtensions.WithLabels(new CodeInstruction(OpCodes.Nop, (object)null), new Label[1] { label })
				});
			}
			catch (Exception ex3)
			{
				Plugin.mls.LogError((object)(ex3.Message + ex3.StackTrace));
				throw;
			}
			finally
			{
				Plugin.mls.LogInfo((object)"Patch success. No any fatal error were raised.");
			}
			foreach (CodeInstruction item in list)
			{
				yield return item;
			}
		}
	}
	[HarmonyPatch(typeof(HUDManager), "EnableChat_performed")]
	internal static class EnableChatPatch
	{
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			HarmonyAPI.LogCallingMethod("EnableChat_performed");
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			FieldInfo targetField = typeof(PlayerControllerB).GetField("isPlayerDead");
			Plugin.mls.LogInfo((object)"Processing EnableChat_performed method...");
			int num;
			try
			{
				num = list.FindLastIndex((CodeInstruction instruction) => instruction.opcode == OpCodes.Ldfld && instruction.operand is FieldInfo fieldInfo && fieldInfo.Equals(targetField));
				Plugin.mls.LogInfo((object)$"Index: {num} Code: {list[num]} found.");
				num -= 2;
				Plugin.mls.LogInfo((object)$"Got previous IL Code: {list[num]}.");
			}
			catch (Exception ex)
			{
				Plugin.mls.LogError((object)(ex.Message + ex.StackTrace));
				throw;
			}
			try
			{
				Plugin.mls.LogInfo((object)"Patching following codes...");
				for (int i = 0; i <= 4; i++)
				{
					Plugin.mls.LogInfo((object)$"Index: {num + i}, Code: {list[num + i]}");
					list[num + i].opcode = OpCodes.Nop;
				}
				Plugin.mls.LogInfo((object)"Patched codes:");
				for (int j = 0; j <= 4; j++)
				{
					Plugin.mls.LogInfo((object)$"Index: {num + j}, Code: {list[num + j]}");
				}
			}
			catch (Exception ex2)
			{
				Plugin.mls.LogError((object)(ex2.Message + ex2.StackTrace));
				throw;
			}
			finally
			{
				Plugin.mls.LogInfo((object)"Patch success. No any fatal error were raised.");
			}
			foreach (CodeInstruction item in list)
			{
				yield return item;
			}
		}
	}
	[HarmonyPatch(typeof(HUDManager), "SubmitChat_performed")]
	internal static class SubmitChatPatch
	{
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			HarmonyAPI.LogCallingMethod("SubmitChat_performed");
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			FieldInfo targetField = typeof(PlayerControllerB).GetField("isPlayerDead");
			Plugin.mls.LogInfo((object)"Processing SubmitChat_performed method...");
			int num;
			try
			{
				num = list.FindLastIndex((CodeInstruction instruction) => instruction.opcode == OpCodes.Ldfld && instruction.operand is FieldInfo fieldInfo && fieldInfo.Equals(targetField));
				Plugin.mls.LogInfo((object)$"Index: {num} Code: {list[num]} found.");
				num -= 2;
				Plugin.mls.LogInfo((object)$"Got previous IL Code: {list[num]}.");
			}
			catch (Exception ex)
			{
				Plugin.mls.LogError((object)(ex.Message + ex.StackTrace));
				throw;
			}
			try
			{
				Plugin.mls.LogInfo((object)"Patching following codes...");
				for (int i = 0; i <= 4; i++)
				{
					Plugin.mls.LogInfo((object)$"Index: {num + i}, Code: {list[num + i]}");
					list[num + i].opcode = OpCodes.Nop;
				}
				Plugin.mls.LogInfo((object)"Patched codes:");
				for (int j = 0; j <= 4; j++)
				{
					Plugin.mls.LogInfo((object)$"Index: {num + j}, Code: {list[num + j]}");
				}
			}
			catch (Exception ex2)
			{
				Plugin.mls.LogError((object)(ex2.Message + ex2.StackTrace));
				throw;
			}
			finally
			{
				Plugin.mls.LogInfo((object)"Patch success. No any fatal error were raised.");
			}
			foreach (CodeInstruction item in list)
			{
				yield return item;
			}
		}
	}
}
namespace SpectatorChat.Other
{
	public static class DebugTestClass
	{
		public static void PrintAllVariables()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("Global Variables State:");
			stringBuilder.AppendLine($"Init: {GlobalVariables.Init}");
			stringBuilder.AppendLine($"InitReservedItem: {GlobalVariables.InitReservedItem}");
			stringBuilder.AppendLine("HUDElements: " + ((GlobalVariables.HUDElements != null) ? "Initialized" : "Null"));
			stringBuilder.AppendLine("HUDManagerInstance: " + (((Object)(object)GlobalVariables.HUDManagerInstance != (Object)null) ? "Initialized" : "Null"));
			stringBuilder.AppendLine("ReservedItemSlot: " + ((GlobalVariables.ReservedItemSlots != null) ? "Initialized" : "Null"));
			stringBuilder.AppendLine("PlayerControllerInstance: " + (((Object)(object)GlobalVariables.PlayerControllerInstance != (Object)null) ? "Initialized" : "Null"));
			stringBuilder.AppendLine("CoroutineCancellationTokenSource: " + ((GlobalVariables.CoroutineCancellationTokenSource != null) ? "Initialized" : "Null"));
			Plugin.mls.LogInfo((object)stringBuilder.ToString());
		}
	}
	public class GlobalVariables
	{
		public static CancellationTokenSource? CoroutineCancellationTokenSource;

		public static bool Init { get; set; }

		public static bool InitReservedItem { get; set; }

		public static List<Image>? ReservedItemSlots { get; set; }

		public static HUDElement[]? HUDElements { get; set; }

		public static HUDManager? HUDManagerInstance { get; set; }

		public static PlayerControllerB? PlayerControllerInstance { get; set; }
	}
	public class ReservedItemUI
	{
		public static void InitReservedItemUI()
		{
			if (Generic.IsModLoaded("FlipMods.ReservedItemSlotCore"))
			{
				GlobalVariables.ReservedItemSlots = HUDPatcher.reservedItemSlots;
			}
			else
			{
				GlobalVariables.ReservedItemSlots = null;
			}
		}

		public static void SwitchReservedItemUI(bool hide)
		{
			if (GlobalVariables.ReservedItemSlots == null)
			{
				return;
			}
			if (hide)
			{
				foreach (Image reservedItemSlot in GlobalVariables.ReservedItemSlots)
				{
					((Behaviour)reservedItemSlot).enabled = false;
				}
			}
			foreach (Image reservedItemSlot2 in GlobalVariables.ReservedItemSlots)
			{
				((Behaviour)reservedItemSlot2).enabled = true;
			}
		}
	}
}
namespace SpectatorChat.API
{
	public class Generic : MonoBehaviour
	{
		private static Generic? instance;

		private Coroutine? _permanentTransparentCoroutine;

		public static Generic Instance
		{
			get
			{
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)instance == (Object)null)
				{
					instance = new GameObject("SpectatorChatGeneric").AddComponent<Generic>();
				}
				return instance;
			}
		}

		private void Awake()
		{
			if ((Object)(object)instance == (Object)null)
			{
				instance = this;
			}
			else
			{
				instance = null;
			}
		}

		public static bool IsInstanceOwner(string userId)
		{
			try
			{
				return ulong.Parse(userId) == GlobalVariables.PlayerControllerInstance.playerClientId;
			}
			catch (Exception ex)
			{
				Plugin.mls.LogError((object)(ex.Message + ex.StackTrace));
				return false;
			}
		}

		public bool IsCoroutineNull()
		{
			if (_permanentTransparentCoroutine == null)
			{
				return true;
			}
			return false;
		}

		public bool StartPermanentTransparent()
		{
			Plugin.mls.LogInfo((object)"StartPermanentTransparent() has been called.");
			if (_permanentTransparentCoroutine == null)
			{
				Plugin.mls.LogInfo((object)"Trying to start the coroutine.");
				GlobalVariables.CoroutineCancellationTokenSource = new CancellationTokenSource();
				_permanentTransparentCoroutine = ((MonoBehaviour)this).StartCoroutine(PermanentTransparentCoroutine(GlobalVariables.HUDElements, GlobalVariables.CoroutineCancellationTokenSource));
				return true;
			}
			return false;
		}

		public bool StopPermanentTransparent()
		{
			Plugin.mls.LogInfo((object)"StopPermanentTransparent() has been called.");
			DebugTestClass.PrintAllVariables();
			if (_permanentTransparentCoroutine != null && GlobalVariables.CoroutineCancellationTokenSource != null)
			{
				Plugin.mls.LogInfo((object)"Trying to stop the coroutine.");
				GlobalVariables.CoroutineCancellationTokenSource.Cancel();
				GlobalVariables.CoroutineCancellationTokenSource = null;
				_permanentTransparentCoroutine = null;
				return true;
			}
			return false;
		}

		public static bool IsModLoaded(string guid)
		{
			return Chainloader.PluginInfos.ContainsKey(guid);
		}

		private IEnumerator PermanentTransparentCoroutine(HUDElement[] elements, CancellationTokenSource coroutineCancellationTokenSource)
		{
			while (!coroutineCancellationTokenSource.IsCancellationRequested)
			{
				try
				{
					foreach (HUDElement val in elements)
					{
						if (val.canvasGroup.alpha != 0f)
						{
							val.canvasGroup.alpha = 0f;
						}
					}
					if (IsModLoaded("FlipMods.ReservedItemSlotCore"))
					{
						ReservedItemUI.SwitchReservedItemUI(hide: true);
					}
				}
				catch (Exception ex)
				{
					Plugin.mls.LogError((object)(ex.Message + ex.StackTrace));
				}
				yield return Plugin.CoroutineDelay.Value;
			}
			if (IsModLoaded("FlipMods.ReservedItemSlotCore"))
			{
				ReservedItemUI.SwitchReservedItemUI(hide: false);
			}
			_permanentTransparentCoroutine = null;
		}

		public static void ToggleSpectatorBoxUI(HUDManager instance, bool isVisable)
		{
			try
			{
				if (isVisable)
				{
					for (int i = 0; i < instance.spectatingPlayerBoxes.Count; i++)
					{
						((Component)instance.spectatingPlayerBoxes.ElementAt(i).Key).gameObject.SetActive(true);
					}
				}
				else
				{
					for (int j = 0; j < instance.spectatingPlayerBoxes.Count; j++)
					{
						((Component)instance.spectatingPlayerBoxes.ElementAt(j).Key).gameObject.SetActive(false);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.mls.LogError((object)(ex.Message + ex.StackTrace));
				throw;
			}
		}

		public static void ClearSpectatorUI(HUDManager instance)
		{
			Plugin.mls.LogInfo((object)"Method ClearSpectatorUI called.");
			for (int i = 0; i < instance.spectatingPlayerBoxes.Count; i++)
			{
				((Component)instance.spectatingPlayerBoxes.ElementAt(i).Key).gameObject.SetActive(false);
				instance.boxesAdded--;
			}
			instance.yOffsetAmount = 0f;
			instance.hasGottenPlayerSteamProfilePictures = false;
			instance.hasLoadedSpectateUI = false;
			instance.spectatingPlayerBoxes.Clear();
			if (instance.spectatingPlayerBoxes.Count != 0)
			{
				Plugin.mls.LogInfo((object)"Error. spectatingPlayerBoxes not empty.");
			}
		}
	}
	public static class HarmonyAPI
	{
		public static string GetPatchInfoAsString(Harmony harmony, MethodInfo methodInfo)
		{
			MethodInfo methodInfo2 = methodInfo;
			StringBuilder stringBuilder = new StringBuilder();
			foreach (MethodBase item in from method in harmony.GetPatchedMethods()
				where method == methodInfo2
				select method)
			{
				stringBuilder.AppendLine("Method " + item.DeclaringType.FullName + "." + item.Name + " is patched by:");
				Patches patchInfo = Harmony.GetPatchInfo(item);
				foreach (Patch prefix in patchInfo.Prefixes)
				{
					stringBuilder.AppendLine("- Prefix: " + prefix.owner);
				}
				foreach (Patch postfix in patchInfo.Postfixes)
				{
					stringBuilder.AppendLine("- Postfix: " + postfix.owner);
				}
				foreach (Patch transpiler in patchInfo.Transpilers)
				{
					stringBuilder.AppendLine("- Transpiler: " + transpiler.owner);
				}
			}
			return stringBuilder.ToString();
		}

		public static void LogCallingMethod(string patchName)
		{
			try
			{
				StackFrame[] frames = new StackTrace().GetFrames();
				if (frames != null && frames.Length > 1)
				{
					MethodBase method = frames[1].GetMethod();
					Type? declaringType = method.DeclaringType;
					string text = declaringType?.Namespace;
					string text2 = declaringType?.Name;
					Plugin.mls.LogInfo((object)("Patch " + patchName + " called by: " + text + "." + text2 + "." + method.Name));
				}
				else
				{
					Plugin.mls.LogWarning((object)("Unable to determine calling method for patch: " + patchName));
				}
			}
			catch (Exception ex)
			{
				Plugin.mls.LogError((object)("An error occurred while logging calling method for patch " + patchName + ": " + ex.Message));
			}
		}
	}
}