Decompiled source of Jester v0.2.0

BepInEx/plugins/JesterMod.dll

Decompiled 12 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using BepInEx.Unity.IL2CPP.Configuration;
using HarmonyLib;
using Hazel;
using Il2CppSystem.Collections.Generic;
using InnerNet;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("JesterMod")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("JesterMod")]
[assembly: AssemblyTitle("JesterMod")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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;
		}
	}
}
namespace JesterMod
{
	[HarmonyPatch(typeof(RoleManager), "SelectRoles")]
	internal static class JesterAssignmentPatch
	{
		private static bool assignmentBroadcastForCurrentGame;

		internal static void ResetForNewRound()
		{
			assignmentBroadcastForCurrentGame = false;
			Plugin.JesterPlayerId = null;
			Plugin.JesterVentingAllowed = false;
			JesterWinSystem.ResetForNewGame();
			JesterExileMessagePatch.ResetForNewGame();
		}

		[HarmonyPostfix]
		private static void Postfix()
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Invalid comparison between Unknown and I4
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Expected O, but got Unknown
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Expected O, but got Unknown
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Invalid comparison between Unknown and I4
			if (assignmentBroadcastForCurrentGame)
			{
				ManualLogSource? pluginLogger = Plugin.PluginLogger;
				if (pluginLogger != null)
				{
					pluginLogger.LogInfo((object)"Jester assignment skipped: role selection already processed for this round.");
				}
				return;
			}
			AmongUsClient instance = AmongUsClient.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				ManualLogSource? pluginLogger2 = Plugin.PluginLogger;
				if (pluginLogger2 != null)
				{
					pluginLogger2.LogWarning((object)"Jester assignment skipped: AmongUsClient.Instance was unavailable.");
				}
				return;
			}
			bool flag = default(bool);
			if ((int)((InnerNetClient)instance).NetworkMode != 1)
			{
				ManualLogSource pluginLogger3 = Plugin.PluginLogger;
				if (pluginLogger3 != null)
				{
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(60, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Jester assignment skipped: session mode is ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<NetworkModes>(((InnerNetClient)instance).NetworkMode);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", not OnlineGame.");
					}
					pluginLogger3.LogInfo(val);
				}
				return;
			}
			if (!((InnerNetClient)instance).AmHost)
			{
				ManualLogSource? pluginLogger4 = Plugin.PluginLogger;
				if (pluginLogger4 != null)
				{
					pluginLogger4.LogInfo((object)"Jester assignment skipped: this client is not the host.");
				}
				return;
			}
			if (((InnerNetClient)instance).IsGamePublic)
			{
				ManualLogSource? pluginLogger5 = Plugin.PluginLogger;
				if (pluginLogger5 != null)
				{
					pluginLogger5.LogInfo((object)"Jester assignment skipped: the online lobby is public.");
				}
				return;
			}
			assignmentBroadcastForCurrentGame = true;
			List<PlayerControl> list = new List<PlayerControl>();
			Enumerator<PlayerControl> enumerator = PlayerControl.AllPlayerControls.GetEnumerator();
			while (enumerator.MoveNext())
			{
				PlayerControl current = enumerator.Current;
				if (!((Object)(object)current == (Object)null) && !current.notRealPlayer && !((Object)(object)current.Data == (Object)null) && !current.Data.Disconnected && !((Object)(object)current.Data.Role == (Object)null) && (int)current.Data.Role.Role <= 0)
				{
					list.Add(current);
				}
			}
			if (list.Count == 0)
			{
				Plugin.JesterPlayerId = null;
				ManualLogSource? pluginLogger6 = Plugin.PluginLogger;
				if (pluginLogger6 != null)
				{
					pluginLogger6.LogWarning((object)"Jester assignment skipped: no connected base-Crewmate players were available.");
				}
				return;
			}
			int index = Random.Range(0, list.Count);
			PlayerControl val2 = list[index];
			Plugin.JesterPlayerId = val2.PlayerId;
			Plugin.JesterVentingAllowed = Plugin.JesterCanVent?.Value ?? false;
			ManualLogSource pluginLogger7 = Plugin.PluginLogger;
			if (pluginLogger7 != null)
			{
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(144, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Assigned Jester metadata in a private online lobby to base-Crewmate player ");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ID=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<byte>(val2.PlayerId);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", name=\"");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(val2.Data.PlayerName);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("\". ");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("JesterCanVent=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(Plugin.JesterVentingAllowed);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(". The game's actual role was not changed.");
				}
				pluginLogger7.LogInfo(val);
			}
			if (!assignmentBroadcastForCurrentGame)
			{
				assignmentBroadcastForCurrentGame = true;
				JesterWinSystem.BroadcastAssignment(val2.PlayerId, Plugin.JesterVentingAllowed);
			}
		}
	}
	[HarmonyPatch(typeof(AmongUsClient), "StartGame")]
	internal static class JesterRoundResetPatch
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			JesterAssignmentPatch.ResetForNewRound();
			ManualLogSource? pluginLogger = Plugin.PluginLogger;
			if (pluginLogger != null)
			{
				pluginLogger.LogInfo((object)"[JESTER] Role and victory state reset for a new round.");
			}
		}
	}
	[HarmonyPatch(typeof(ExileController), "WrapUp")]
	internal static class JesterExileDetectionPatch
	{
		[HarmonyPostfix]
		private static void Postfix(ExileController __instance)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected O, but got Unknown
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Expected O, but got Unknown
			JesterWinSystem.OnExileWrapUp(__instance);
			if ((Object)(object)__instance == (Object)null)
			{
				ManualLogSource? pluginLogger = Plugin.PluginLogger;
				if (pluginLogger != null)
				{
					pluginLogger.LogWarning((object)"Jester exile detection skipped: ExileController instance was null.");
				}
				return;
			}
			NetworkedPlayerInfo networkedPlayer;
			bool flag = default(bool);
			try
			{
				networkedPlayer = __instance.initData.networkedPlayer;
			}
			catch (Exception ex)
			{
				ManualLogSource pluginLogger2 = Plugin.PluginLogger;
				if (pluginLogger2 != null)
				{
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(62, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Jester exile detection skipped: exile data was unavailable (");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.GetType().Name);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(").");
					}
					pluginLogger2.LogWarning(val);
				}
				return;
			}
			if ((Object)(object)networkedPlayer == (Object)null)
			{
				ManualLogSource? pluginLogger3 = Plugin.PluginLogger;
				if (pluginLogger3 != null)
				{
					pluginLogger3.LogInfo((object)"Jester exile detection skipped: exile data did not contain a player.");
				}
				return;
			}
			byte playerId = networkedPlayer.PlayerId;
			string text = networkedPlayer.PlayerName ?? "<unknown>";
			byte? jesterPlayerId = Plugin.JesterPlayerId;
			if (jesterPlayerId.HasValue)
			{
				byte valueOrDefault = jesterPlayerId.GetValueOrDefault();
				if (true)
				{
					bool flag2 = playerId == valueOrDefault;
					ManualLogSource pluginLogger4 = Plugin.PluginLogger;
					if (pluginLogger4 != null)
					{
						BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(76, 4, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Exile completed: player ID=");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<byte>(playerId);
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", name=\"");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(text);
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("\"; ");
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("matches selected Jester=");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<bool>(flag2);
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" (Jester ID=");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<byte>(valueOrDefault);
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(").");
						}
						pluginLogger4.LogInfo(val2);
					}
					return;
				}
			}
			ManualLogSource? pluginLogger5 = Plugin.PluginLogger;
			if (pluginLogger5 != null)
			{
				pluginLogger5.LogInfo((object)($"Exile completed: player ID={playerId}, name=\"{text}\"; " + "Jester match=unknown. Detection skipped because no Jester player ID is stored."));
			}
		}
	}
	[HarmonyPatch(typeof(ExileController), "Begin", new Type[] { typeof(InitProperties) })]
	internal static class JesterExileMessagePatch
	{
		private static readonly HashSet<byte> ChangedExileMessages = new HashSet<byte>();

		internal static void ResetForNewGame()
		{
			ChangedExileMessages.Clear();
		}

		[HarmonyPostfix]
		private static void Postfix(ExileController __instance, InitProperties __0)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Invalid comparison between Unknown and I4
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Expected O, but got Unknown
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Expected O, but got Unknown
			AmongUsClient instance = AmongUsClient.Instance;
			if ((Object)(object)instance == (Object)null || (int)((InnerNetClient)instance).NetworkMode != 1 || ((InnerNetClient)instance).IsGamePublic || (Object)(object)__instance == (Object)null || __0 == null || __0.voteTie)
			{
				return;
			}
			NetworkedPlayerInfo networkedPlayer = __0.networkedPlayer;
			if ((Object)(object)networkedPlayer == (Object)null)
			{
				return;
			}
			byte? jesterPlayerId = Plugin.JesterPlayerId;
			if (!jesterPlayerId.HasValue)
			{
				return;
			}
			byte valueOrDefault = jesterPlayerId.GetValueOrDefault();
			if (networkedPlayer.PlayerId != valueOrDefault || ChangedExileMessages.Contains(valueOrDefault))
			{
				return;
			}
			string text = networkedPlayer.PlayerName ?? "<unknown>";
			string text2 = text + " was the Jester.";
			bool flag = default(bool);
			try
			{
				__instance.completeString = text2;
				if ((Object)(object)__instance.Text != (Object)null)
				{
					((TMP_Text)__instance.Text).text = text2;
				}
				ChangedExileMessages.Add(valueOrDefault);
				ManualLogSource pluginLogger = Plugin.PluginLogger;
				if (pluginLogger != null)
				{
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(52, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[JESTER] Local exile message set for player ID=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<byte>(valueOrDefault);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": \"");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text2);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("\".");
					}
					pluginLogger.LogInfo(val);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource pluginLogger2 = Plugin.PluginLogger;
				if (pluginLogger2 != null)
				{
					BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(47, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[JESTER] Could not update host exile text (");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.GetType().Name);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(": ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(").");
					}
					pluginLogger2.LogWarning(val2);
				}
			}
		}
	}
	[HarmonyPatch(typeof(GameStartManager), "Update")]
	internal static class JesterLobbyRpcProbePatch
	{
		private static int lastLobbyGameId = int.MinValue;

		private static bool probeSentForLobby;

		[HarmonyPostfix]
		private static void Postfix(GameStartManager __instance)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Invalid comparison between Unknown and I4
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Expected O, but got Unknown
			ConfigEntry<bool>? lobbyRpcProbeEnabled = Plugin.LobbyRpcProbeEnabled;
			if (lobbyRpcProbeEnabled == null || !lobbyRpcProbeEnabled.Value)
			{
				return;
			}
			ConfigEntry<KeyboardShortcut>? lobbyRpcProbeShortcut = Plugin.LobbyRpcProbeShortcut;
			if (lobbyRpcProbeShortcut == null)
			{
				return;
			}
			KeyboardShortcut value = lobbyRpcProbeShortcut.Value;
			if (!((KeyboardShortcut)(ref value)).IsDown())
			{
				return;
			}
			AmongUsClient instance = AmongUsClient.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				ManualLogSource? pluginLogger = Plugin.PluginLogger;
				if (pluginLogger != null)
				{
					pluginLogger.LogWarning((object)"[LOBBY RPC TEST] Refused: AmongUsClient.Instance is unavailable.");
				}
				return;
			}
			if ((int)((InnerNetClient)instance).NetworkMode != 1 || !((InnerNetClient)instance).AmHost || ((InnerNetClient)instance).IsGamePublic)
			{
				ManualLogSource? pluginLogger2 = Plugin.PluginLogger;
				if (pluginLogger2 != null)
				{
					pluginLogger2.LogWarning((object)"[LOBBY RPC TEST] Refused: test requires the local host in a private online lobby.");
				}
				return;
			}
			if ((Object)(object)__instance == (Object)null || (int)__instance.startState != 0 || ((Object)(object)GameManager.Instance != (Object)null && GameManager.Instance.GameHasStarted))
			{
				ManualLogSource? pluginLogger3 = Plugin.PluginLogger;
				if (pluginLogger3 != null)
				{
					pluginLogger3.LogWarning((object)"[LOBBY RPC TEST] Refused: the lobby is starting or a game is already active.");
				}
				return;
			}
			int gameId = ((InnerNetClient)instance).GameId;
			if (lastLobbyGameId != gameId)
			{
				lastLobbyGameId = gameId;
				probeSentForLobby = false;
			}
			if (probeSentForLobby)
			{
				ManualLogSource pluginLogger4 = Plugin.PluginLogger;
				if (pluginLogger4 != null)
				{
					bool flag = default(bool);
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(68, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[LOBBY RPC TEST] Ignored: a probe was already sent in lobby GameId=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(gameId);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
					}
					pluginLogger4.LogInfo(val);
				}
				return;
			}
			PlayerControl localPlayer = PlayerControl.LocalPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				ManualLogSource? pluginLogger5 = Plugin.PluginLogger;
				if (pluginLogger5 != null)
				{
					pluginLogger5.LogWarning((object)"[LOBBY RPC TEST] Refused: the host's local player is unavailable.");
				}
				return;
			}
			PlayerControl val2 = null;
			Enumerator<PlayerControl> enumerator = PlayerControl.AllPlayerControls.GetEnumerator();
			while (enumerator.MoveNext())
			{
				PlayerControl current = enumerator.Current;
				if (!((Object)(object)current == (Object)null) && !current.notRealPlayer && !((Object)(object)current.Data == (Object)null) && !current.Data.Disconnected)
				{
					if ((Object)(object)val2 == (Object)null || current.PlayerId != localPlayer.PlayerId)
					{
						val2 = current;
					}
					if (current.PlayerId != localPlayer.PlayerId)
					{
						break;
					}
				}
			}
			if ((Object)(object)val2 == (Object)null)
			{
				ManualLogSource? pluginLogger6 = Plugin.PluginLogger;
				if (pluginLogger6 != null)
				{
					pluginLogger6.LogWarning((object)"[LOBBY RPC TEST] Refused: no connected real player was available to identify.");
				}
				return;
			}
			probeSentForLobby = true;
			ManualLogSource? pluginLogger7 = Plugin.PluginLogger;
			if (pluginLogger7 != null)
			{
				pluginLogger7.LogInfo((object)($"[LOBBY RPC TEST] Starting one-shot probe in GameId={gameId}: sending connected player ID={val2.PlayerId}, name=\"{val2.Data.PlayerName}\". " + "No match will be started and no Among Us role will be changed."));
			}
			JesterWinSystem.BroadcastAssignment(val2.PlayerId);
		}
	}
	internal static class JesterPracticeTest
	{
		private static bool isRunning;

		internal static void TryRunIfRequested()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Invalid comparison between Unknown and I4
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			if (isRunning)
			{
				return;
			}
			ConfigEntry<bool>? practiceTestEnabled = Plugin.PracticeTestEnabled;
			if (practiceTestEnabled == null || !practiceTestEnabled.Value)
			{
				return;
			}
			ConfigEntry<KeyboardShortcut>? practiceTestShortcut = Plugin.PracticeTestShortcut;
			if (practiceTestShortcut == null)
			{
				return;
			}
			KeyboardShortcut value = practiceTestShortcut.Value;
			if (!((KeyboardShortcut)(ref value)).IsDown())
			{
				return;
			}
			ManualLogSource? pluginLogger = Plugin.PluginLogger;
			if (pluginLogger != null)
			{
				pluginLogger.LogInfo((object)"[SIMULATION ONLY] Practice Jester victory logic test requested. Checking safety gates.");
			}
			AmongUsClient instance = AmongUsClient.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				ManualLogSource? pluginLogger2 = Plugin.PluginLogger;
				if (pluginLogger2 != null)
				{
					pluginLogger2.LogWarning((object)"[SIMULATION ONLY] Test failed safely: AmongUsClient.Instance is unavailable; no game action was taken.");
				}
				return;
			}
			ManualLogSource? pluginLogger3 = Plugin.PluginLogger;
			if (pluginLogger3 != null)
			{
				pluginLogger3.LogInfo((object)"[SIMULATION ONLY] Safety check PASS: AmongUsClient.Instance is available.");
			}
			if ((int)((InnerNetClient)instance).NetworkMode != 2)
			{
				ManualLogSource? pluginLogger4 = Plugin.PluginLogger;
				if (pluginLogger4 != null)
				{
					pluginLogger4.LogWarning((object)($"[SIMULATION ONLY] Test refused: session mode is {((InnerNetClient)instance).NetworkMode}, not FreePlay. " + "No game action was taken."));
				}
				return;
			}
			ManualLogSource? pluginLogger5 = Plugin.PluginLogger;
			if (pluginLogger5 != null)
			{
				pluginLogger5.LogInfo((object)"[SIMULATION ONLY] Safety check PASS: session is FreePlay; online sessions are excluded.");
			}
			if (((InnerNetClient)instance).IsGameOver)
			{
				ManualLogSource? pluginLogger6 = Plugin.PluginLogger;
				if (pluginLogger6 != null)
				{
					pluginLogger6.LogWarning((object)"[SIMULATION ONLY] Test refused: the current FreePlay session is already over. No game action was taken.");
				}
				return;
			}
			ManualLogSource? pluginLogger7 = Plugin.PluginLogger;
			if (pluginLogger7 != null)
			{
				pluginLogger7.LogInfo((object)"[SIMULATION ONLY] Safety check PASS: current game is not over.");
			}
			PlayerControl localPlayer = PlayerControl.LocalPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				ManualLogSource? pluginLogger8 = Plugin.PluginLogger;
				if (pluginLogger8 != null)
				{
					pluginLogger8.LogWarning((object)"[SIMULATION ONLY] Test failed safely: local player is unavailable; no game action was taken.");
				}
				return;
			}
			ManualLogSource? pluginLogger9 = Plugin.PluginLogger;
			if (pluginLogger9 != null)
			{
				pluginLogger9.LogInfo((object)"[SIMULATION ONLY] Safety check PASS: local player is available for a simulated ID.");
			}
			RunEligibilityChecks(localPlayer.PlayerId);
		}

		private static void RunEligibilityChecks(byte simulatedJesterId)
		{
			isRunning = true;
			try
			{
				byte value = (byte)((simulatedJesterId != byte.MaxValue) ? ((byte)(simulatedJesterId + 1)) : 0);
				ManualLogSource? pluginLogger = Plugin.PluginLogger;
				if (pluginLogger != null)
				{
					pluginLogger.LogInfo((object)($"[SIMULATION ONLY] Starting dry run with simulated Jester ID={simulatedJesterId}. " + "The stored game Jester ID will not be changed."));
				}
				int num = 0;
				int num2 = 7;
				num += Check("matching Jester exile after a non-tied vote", expectedAllowed: true, tie: false, simulatedJesterId, simulatedJesterId, matchingVoteWasRecorded: true, gameAlreadyEnded: false, victoryAlreadyTriggered: false);
				num += Check("tied vote is rejected", expectedAllowed: false, tie: true, simulatedJesterId, simulatedJesterId, matchingVoteWasRecorded: true, gameAlreadyEnded: false, victoryAlreadyTriggered: false);
				num += Check("another player's exile is rejected", expectedAllowed: false, tie: false, simulatedJesterId, value, matchingVoteWasRecorded: true, gameAlreadyEnded: false, victoryAlreadyTriggered: false);
				num += Check("missing Jester ID is rejected", expectedAllowed: false, tie: false, null, simulatedJesterId, matchingVoteWasRecorded: true, gameAlreadyEnded: false, victoryAlreadyTriggered: false);
				num += Check("already-ended game is rejected", expectedAllowed: false, tie: false, simulatedJesterId, simulatedJesterId, matchingVoteWasRecorded: true, gameAlreadyEnded: true, victoryAlreadyTriggered: false);
				num += Check("duplicate victory is rejected", expectedAllowed: false, tie: false, simulatedJesterId, simulatedJesterId, matchingVoteWasRecorded: true, gameAlreadyEnded: false, victoryAlreadyTriggered: true);
				num += Check("exile without a matching completed vote is rejected", expectedAllowed: false, tie: false, simulatedJesterId, simulatedJesterId, matchingVoteWasRecorded: false, gameAlreadyEnded: false, victoryAlreadyTriggered: false);
				bool flag = num == num2;
				ManualLogSource? pluginLogger2 = Plugin.PluginLogger;
				if (pluginLogger2 != null)
				{
					pluginLogger2.LogInfo((object)($"[SIMULATION ONLY] Dry run {(flag ? "PASSED" : "FAILED")}: {num}/{num2} eligibility checks passed. No RPC was sent, " + "RpcEndGame was not called, no winner data was changed, and no actual victory occurred."));
				}
			}
			catch (Exception ex)
			{
				ManualLogSource? pluginLogger3 = Plugin.PluginLogger;
				if (pluginLogger3 != null)
				{
					pluginLogger3.LogError((object)($"[SIMULATION ONLY] Dry run failed safely ({ex.GetType().Name}: {ex.Message}). " + "No RPC or game-end request was made by the test."));
				}
			}
			finally
			{
				isRunning = false;
			}
		}

		private static int Check(string label, bool expectedAllowed, bool tie, byte? jesterId, byte? exiledId, bool matchingVoteWasRecorded, bool gameAlreadyEnded, bool victoryAlreadyTriggered)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			string reason;
			bool flag = JesterWinSystem.IsVictoryEligible(tie, jesterId, exiledId, matchingVoteWasRecorded, gameAlreadyEnded, victoryAlreadyTriggered, out reason);
			bool flag2 = flag == expectedAllowed;
			ManualLogSource pluginLogger = Plugin.PluginLogger;
			if (pluginLogger != null)
			{
				bool flag3 = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(65, 5, ref flag3);
				if (flag3)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[SIMULATION ONLY] Validation ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(flag2 ? "PASS" : "FAIL");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(label);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("; ");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("eligible=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(flag);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", expected=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(expectedAllowed);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", reason=\"");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(reason);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("\".");
				}
				pluginLogger.LogInfo(val);
			}
			return flag2 ? 1 : 0;
		}
	}
	[HarmonyPatch(typeof(IntroCutscene), "BeginCrewmate")]
	internal static class JesterNeutralRevealPatch
	{
		[HarmonyPostfix]
		private static void Postfix(IntroCutscene __instance)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			if (IsLocalJester() && !((Object)(object)__instance == (Object)null) && !((Object)(object)__instance.TeamTitle == (Object)null))
			{
				((TMP_Text)__instance.TeamTitle).text = "NEUTRAL";
				((Graphic)__instance.TeamTitle).color = new Color(0.58f, 0.58f, 0.58f, 1f);
				ManualLogSource? pluginLogger = Plugin.PluginLogger;
				if (pluginLogger != null)
				{
					pluginLogger.LogInfo((object)"[JESTER] Neutral category reveal configured for the selected player's client.");
				}
			}
		}

		internal static bool IsLocalJester()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Invalid comparison between Unknown and I4
			AmongUsClient instance = AmongUsClient.Instance;
			PlayerControl localPlayer = PlayerControl.LocalPlayer;
			int result;
			if ((Object)(object)instance != (Object)null && (int)((InnerNetClient)instance).NetworkMode == 1 && !((InnerNetClient)instance).IsGamePublic && (Object)(object)localPlayer != (Object)null)
			{
				byte? jesterPlayerId = Plugin.JesterPlayerId;
				if (jesterPlayerId.HasValue)
				{
					byte valueOrDefault = jesterPlayerId.GetValueOrDefault();
					result = ((localPlayer.PlayerId == valueOrDefault) ? 1 : 0);
					goto IL_0053;
				}
			}
			result = 0;
			goto IL_0053;
			IL_0053:
			return (byte)result != 0;
		}
	}
	[HarmonyPatch(typeof(IntroCutscene), "ShowRole")]
	internal static class JesterRoleRevealPatch
	{
		[HarmonyPostfix]
		private static void Postfix(IntroCutscene __instance)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			if (JesterNeutralRevealPatch.IsLocalJester() && !((Object)(object)__instance == (Object)null))
			{
				if ((Object)(object)__instance.RoleText != (Object)null)
				{
					((TMP_Text)__instance.RoleText).text = "JESTER";
					((Graphic)__instance.RoleText).color = new Color(0.68f, 0.32f, 0.95f, 1f);
				}
				if ((Object)(object)__instance.RoleBlurbText != (Object)null)
				{
					((TMP_Text)__instance.RoleBlurbText).text = "Get voted out to win!";
				}
				ManualLogSource? pluginLogger = Plugin.PluginLogger;
				if (pluginLogger != null)
				{
					pluginLogger.LogInfo((object)"[JESTER] Purple Jester role reveal configured with the voted-out-to-win description.");
				}
			}
		}
	}
	[HarmonyPatch(typeof(RoleBehaviour), "get_CanVent")]
	internal static class JesterVentPermissionPatch
	{
		[HarmonyPostfix]
		private static void Postfix(RoleBehaviour __instance, ref bool __result)
		{
			if ((Object)(object)__instance == (Object)null || (Object)(object)__instance.Player == (Object)null)
			{
				return;
			}
			byte? jesterPlayerId = Plugin.JesterPlayerId;
			if (jesterPlayerId.HasValue)
			{
				byte valueOrDefault = jesterPlayerId.GetValueOrDefault();
				if (__instance.Player.PlayerId == valueOrDefault)
				{
					__result = Plugin.JesterVentingAllowed;
				}
			}
		}
	}
	internal static class JesterWinSystem
	{
		private enum CustomRpcMessage : byte
		{
			AssignJester = 1,
			JesterVictory
		}

		[HarmonyPatch(typeof(PlayerControl), "HandleRpc")]
		private static class JesterCustomRpcPatch
		{
			[HarmonyPrefix]
			private static bool Prefix(PlayerControl __instance, byte callId, MessageReader reader)
			{
				//IL_029b: Unknown result type (might be due to invalid IL or missing references)
				//IL_02a2: Expected O, but got Unknown
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_0038: Invalid comparison between Unknown and I4
				//IL_0107: Unknown result type (might be due to invalid IL or missing references)
				//IL_010e: Expected O, but got Unknown
				//IL_0094: Unknown result type (might be due to invalid IL or missing references)
				//IL_009b: Expected O, but got Unknown
				//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
				//IL_01b8: Expected O, but got Unknown
				//IL_022c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0233: Expected O, but got Unknown
				if (callId != 200)
				{
					return true;
				}
				AmongUsClient instance = AmongUsClient.Instance;
				if ((Object)(object)__instance == (Object)null || (Object)(object)instance == (Object)null || (int)((InnerNetClient)instance).NetworkMode != 1 || ((InnerNetClient)instance).IsGamePublic)
				{
					ManualLogSource? pluginLogger = Plugin.PluginLogger;
					if (pluginLogger != null)
					{
						pluginLogger.LogWarning((object)"[JESTER][RPC] Rejected custom message: sender unavailable or session is not a private online lobby.");
					}
					return false;
				}
				int ownerId = ((InnerNetObject)__instance).OwnerId;
				int hostId = ((InnerNetClient)instance).HostId;
				bool flag = default(bool);
				if (ownerId != hostId)
				{
					ManualLogSource pluginLogger2 = Plugin.PluginLogger;
					if (pluginLogger2 != null)
					{
						BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(83, 2, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[JESTER][RPC] Rejected custom message from sender OwnerId=");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(ownerId);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("; ");
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("expected lobby HostId=");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(hostId);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
						}
						pluginLogger2.LogWarning(val);
					}
					return false;
				}
				ManualLogSource pluginLogger3 = Plugin.PluginLogger;
				if (pluginLogger3 != null)
				{
					BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(74, 3, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[JESTER][RPC] Sender validation passed: OwnerId=");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(ownerId);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" matches HostId=");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(hostId);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("; ");
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("callId=");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<byte>(callId);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(".");
					}
					pluginLogger3.LogInfo(val2);
				}
				try
				{
					CustomRpcMessage customRpcMessage = (CustomRpcMessage)reader.ReadByte();
					byte playerId = reader.ReadByte();
					if (customRpcMessage != CustomRpcMessage.AssignJester && customRpcMessage != CustomRpcMessage.JesterVictory)
					{
						ManualLogSource pluginLogger4 = Plugin.PluginLogger;
						if (pluginLogger4 != null)
						{
							BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(52, 1, ref flag);
							if (flag)
							{
								((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[JESTER][RPC] Rejected unknown custom message type=");
								((BepInExLogInterpolatedStringHandler)val).AppendFormatted<byte>((byte)customRpcMessage);
								((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
							}
							pluginLogger4.LogWarning(val);
						}
						return false;
					}
					switch (customRpcMessage)
					{
					case CustomRpcMessage.AssignJester:
					{
						byte b = reader.ReadByte();
						if (b > 1)
						{
							ManualLogSource pluginLogger5 = Plugin.PluginLogger;
							if (pluginLogger5 != null)
							{
								BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(54, 1, ref flag);
								if (flag)
								{
									((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[JESTER][RPC] Assignment rejected: invalid vent flag=");
									((BepInExLogInterpolatedStringHandler)val).AppendFormatted<byte>(b);
									((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
								}
								pluginLogger5.LogWarning(val);
							}
							return false;
						}
						ReceiveJesterAssignment(playerId, b == 1);
						break;
					}
					case CustomRpcMessage.JesterVictory:
						ReceiveJesterVictory(playerId);
						break;
					}
				}
				catch (Exception ex)
				{
					ManualLogSource pluginLogger6 = Plugin.PluginLogger;
					if (pluginLogger6 != null)
					{
						BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(42, 1, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[JESTER] Could not read custom message (");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.GetType().Name);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(").");
						}
						pluginLogger6.LogWarning(val);
					}
				}
				return false;
			}
		}

		[HarmonyPatch(typeof(LogicGameFlowNormal), "CheckEndCriteria")]
		private static class PreserveJesterEndCheckPatch
		{
			[HarmonyPrefix]
			private static bool Prefix()
			{
				AmongUsClient instance = AmongUsClient.Instance;
				return (Object)(object)instance == (Object)null || !((InnerNetClient)instance).AmHost || (!jesterWasVotedOut && !jesterVictoryTriggered);
			}
		}

		[HarmonyPatch(typeof(AmongUsClient), "OnGameEnd")]
		private static class JesterCachedWinnerPatch
		{
			[HarmonyPrefix]
			private static void Prefix(EndGameResult endGameResult)
			{
				TryApplySoleWinner(endGameResult, logSuccess: false);
			}

			[HarmonyPostfix]
			private static void Postfix(EndGameResult endGameResult)
			{
				TryApplySoleWinner(endGameResult, logSuccess: true);
			}
		}

		[HarmonyPatch(typeof(EndGameManager), "SetEverythingUp")]
		private static class JesterWinnerScreenPatch
		{
			[HarmonyPostfix]
			private static void Postfix(EndGameManager __instance)
			{
				//IL_0052: Unknown result type (might be due to invalid IL or missing references)
				if (jesterVictoryActive && !((Object)(object)__instance == (Object)null) && !((Object)(object)__instance.WinText == (Object)null))
				{
					((TMP_Text)__instance.WinText).text = "JESTER WINS!";
					((Graphic)__instance.WinText).color = new Color(0.68f, 0.32f, 0.95f, 1f);
					ManualLogSource? pluginLogger = Plugin.PluginLogger;
					if (pluginLogger != null)
					{
						pluginLogger.LogInfo((object)"[JESTER] Custom winner screen configured with the Jester as the sole cached winner and a purple title.");
					}
				}
			}
		}

		private const byte CustomRpcCallId = 200;

		private static bool jesterWasVotedOut;

		private static bool jesterVictoryTriggered;

		private static bool jesterVictoryActive;

		internal static bool IsVictoryEligible(bool voteTie, byte? jesterId, byte? exiledPlayerId, bool matchingVoteWasRecorded, bool gameAlreadyEnded, bool victoryAlreadyTriggered, out string reason)
		{
			if (voteTie)
			{
				reason = "the vote was tied";
				return false;
			}
			if (jesterId.HasValue)
			{
				byte valueOrDefault = jesterId.GetValueOrDefault();
				if (true)
				{
					if (exiledPlayerId.HasValue)
					{
						byte valueOrDefault2 = exiledPlayerId.GetValueOrDefault();
						if (true)
						{
							if (!matchingVoteWasRecorded)
							{
								reason = "the completed vote did not record a Jester exile";
								return false;
							}
							if (valueOrDefault2 != valueOrDefault)
							{
								reason = "the exiled player does not match the selected Jester";
								return false;
							}
							if (gameAlreadyEnded)
							{
								reason = "the game had already ended";
								return false;
							}
							if (victoryAlreadyTriggered)
							{
								reason = "a Jester victory was already triggered";
								return false;
							}
							reason = "all Jester exile victory eligibility checks passed";
							return true;
						}
					}
					reason = "no player was exiled";
					return false;
				}
			}
			reason = "no Jester player ID is stored";
			return false;
		}

		internal static void ResetForNewGame()
		{
			jesterWasVotedOut = false;
			jesterVictoryTriggered = false;
			jesterVictoryActive = false;
			Plugin.JesterVentingAllowed = false;
		}

		internal static void OnVoteCompleted(NetworkedPlayerInfo exiled, bool tie)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Invalid comparison between Unknown and I4
			AmongUsClient instance = AmongUsClient.Instance;
			if ((Object)(object)instance == (Object)null || (int)((InnerNetClient)instance).NetworkMode != 1 || !((InnerNetClient)instance).AmHost || ((InnerNetClient)instance).IsGamePublic)
			{
				return;
			}
			int num;
			if (!tie && (Object)(object)exiled != (Object)null)
			{
				byte? jesterPlayerId = Plugin.JesterPlayerId;
				if (jesterPlayerId.HasValue)
				{
					byte valueOrDefault = jesterPlayerId.GetValueOrDefault();
					num = ((exiled.PlayerId == valueOrDefault) ? 1 : 0);
					goto IL_0063;
				}
			}
			num = 0;
			goto IL_0063;
			IL_0063:
			jesterWasVotedOut = (byte)num != 0;
			if (jesterWasVotedOut)
			{
				ManualLogSource? pluginLogger = Plugin.PluginLogger;
				if (pluginLogger != null)
				{
					pluginLogger.LogInfo((object)($"[JESTER] Non-tied vote selected the Jester (ID={exiled.PlayerId}); " + "waiting for the exile sequence to finish."));
				}
			}
		}

		internal static void OnExileWrapUp(ExileController? exileController)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Invalid comparison between Unknown and I4
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02be: Expected O, but got Unknown
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Expected O, but got Unknown
			AmongUsClient instance = AmongUsClient.Instance;
			if ((Object)(object)instance == (Object)null || (int)((InnerNetClient)instance).NetworkMode != 1 || !((InnerNetClient)instance).AmHost || ((InnerNetClient)instance).IsGamePublic)
			{
				return;
			}
			if ((Object)(object)exileController == (Object)null || exileController.initData == null)
			{
				jesterWasVotedOut = false;
				return;
			}
			InitProperties initData = exileController.initData;
			NetworkedPlayerInfo networkedPlayer = initData.networkedPlayer;
			bool flag = default(bool);
			if ((Object)(object)networkedPlayer != (Object)null && networkedPlayer.Disconnected)
			{
				jesterWasVotedOut = false;
				ManualLogSource pluginLogger = Plugin.PluginLogger;
				if (pluginLogger != null)
				{
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(60, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[JESTER] Victory skipped: exiled PlayerId=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<byte>(networkedPlayer.PlayerId);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" was disconnected.");
					}
					pluginLogger.LogInfo(val);
				}
				return;
			}
			byte? exiledPlayerId = (((Object)(object)networkedPlayer == (Object)null) ? ((byte?)null) : new byte?(networkedPlayer.PlayerId));
			if (!IsVictoryEligible(initData.voteTie, Plugin.JesterPlayerId, exiledPlayerId, jesterWasVotedOut, ((InnerNetClient)instance).IsGameOver, jesterVictoryTriggered, out string reason))
			{
				jesterWasVotedOut = false;
				if (reason == "the game had already ended")
				{
					ManualLogSource? pluginLogger2 = Plugin.PluginLogger;
					if (pluginLogger2 != null)
					{
						pluginLogger2.LogInfo((object)"[JESTER] Victory skipped: the game had already ended before exile wrap-up.");
					}
				}
				else if (reason == "a Jester victory was already triggered")
				{
					ManualLogSource? pluginLogger3 = Plugin.PluginLogger;
					if (pluginLogger3 != null)
					{
						pluginLogger3.LogInfo((object)"[JESTER] Duplicate victory trigger ignored; this game already triggered the Jester result.");
					}
				}
				return;
			}
			byte value = Plugin.JesterPlayerId.Value;
			string value2 = ((networkedPlayer != null) ? networkedPlayer.PlayerName : null) ?? "<unknown>";
			ManualLogSource? pluginLogger4 = Plugin.PluginLogger;
			if (pluginLogger4 != null)
			{
				pluginLogger4.LogInfo((object)($"[JESTER] Victory detected: selected Jester ID={value}, name=\"{value2}\" " + "was exiled after a non-tied vote."));
			}
			jesterVictoryTriggered = true;
			jesterVictoryActive = true;
			jesterWasVotedOut = false;
			try
			{
				BroadcastVictory(value);
				GameManager.Instance.RpcEndGame((GameOverReason)0, false);
				ManualLogSource? pluginLogger5 = Plugin.PluginLogger;
				if (pluginLogger5 != null)
				{
					pluginLogger5.LogInfo((object)($"[JESTER] Victory end-game request sent for player ID={value}. " + "The stock reason is only the transition trigger; custom winner handling is active."));
				}
			}
			catch (Exception ex)
			{
				jesterVictoryTriggered = false;
				jesterVictoryActive = false;
				ManualLogSource pluginLogger6 = Plugin.PluginLogger;
				if (pluginLogger6 != null)
				{
					BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(35, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[JESTER] Victory trigger failed: ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.GetType().Name);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(": ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
					}
					pluginLogger6.LogError(val2);
				}
			}
		}

		internal static void ReceiveJesterAssignment(byte playerId)
		{
			ReceiveJesterAssignment(playerId, canVent: false);
		}

		internal static void ReceiveJesterAssignment(byte playerId, bool canVent)
		{
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Expected O, but got Unknown
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			GameData instance = GameData.Instance;
			NetworkedPlayerInfo val = ((instance != null) ? instance.GetPlayerById(playerId) : null);
			bool flag = default(bool);
			if ((Object)(object)val == (Object)null || val.Disconnected)
			{
				ManualLogSource pluginLogger = Plugin.PluginLogger;
				if (pluginLogger != null)
				{
					BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(71, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[JESTER][RPC] Assignment rejected: PlayerId=");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<byte>(playerId);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" is not a connected player.");
					}
					pluginLogger.LogWarning(val2);
				}
				return;
			}
			ResetForNewGame();
			Plugin.JesterPlayerId = playerId;
			Plugin.JesterVentingAllowed = canVent;
			ManualLogSource pluginLogger2 = Plugin.PluginLogger;
			if (pluginLogger2 != null)
			{
				BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(72, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[JESTER][RPC] Assignment received and stored: PlayerId=");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<byte>(playerId);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(", JesterCanVent=");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<bool>(canVent);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(".");
				}
				pluginLogger2.LogInfo(val3);
			}
		}

		internal static void ReceiveJesterVictory(byte playerId)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Expected O, but got Unknown
			byte? jesterPlayerId = Plugin.JesterPlayerId;
			bool flag = default(bool);
			if (jesterPlayerId.HasValue)
			{
				byte valueOrDefault = jesterPlayerId.GetValueOrDefault();
				if (valueOrDefault == playerId)
				{
					if (jesterVictoryTriggered)
					{
						ManualLogSource? pluginLogger = Plugin.PluginLogger;
						if (pluginLogger != null)
						{
							pluginLogger.LogInfo((object)"[JESTER] Duplicate victory message ignored.");
						}
						return;
					}
					jesterVictoryTriggered = true;
					jesterVictoryActive = true;
					ManualLogSource pluginLogger2 = Plugin.PluginLogger;
					if (pluginLogger2 != null)
					{
						BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(66, 1, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[JESTER][RPC] Host victory result accepted for assigned PlayerId=");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<byte>(playerId);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
						}
						pluginLogger2.LogInfo(val);
					}
					return;
				}
			}
			ManualLogSource pluginLogger3 = Plugin.PluginLogger;
			if (pluginLogger3 != null)
			{
				BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(83, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[JESTER] Victory message rejected: ID=");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<byte>(playerId);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" does not match the stored Jester assignment.");
				}
				pluginLogger3.LogWarning(val2);
			}
		}

		internal static void BroadcastAssignment(byte playerId, bool canVent = false)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Invalid comparison between Unknown and I4
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Expected O, but got Unknown
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			AmongUsClient instance = AmongUsClient.Instance;
			if ((Object)(object)instance == (Object)null || (int)((InnerNetClient)instance).NetworkMode != 1 || !((InnerNetClient)instance).AmHost || ((InnerNetClient)instance).IsGamePublic)
			{
				ManualLogSource? pluginLogger = Plugin.PluginLogger;
				if (pluginLogger != null)
				{
					pluginLogger.LogWarning((object)"[JESTER][RPC] Assignment send skipped: a private online lobby host is required.");
				}
				return;
			}
			bool flag = default(bool);
			try
			{
				ManualLogSource pluginLogger2 = Plugin.PluginLogger;
				if (pluginLogger2 != null)
				{
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(97, 4, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[JESTER][RPC] Host attempting assignment broadcast: ");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("callId=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<byte>((byte)200);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", message=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<byte>((byte)1);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", ");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("PlayerId=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<byte>(playerId);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", JesterCanVent=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(canVent);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
					}
					pluginLogger2.LogInfo(val);
				}
				Broadcast(CustomRpcMessage.AssignJester, playerId, canVent);
			}
			catch (Exception ex)
			{
				ManualLogSource pluginLogger3 = Plugin.PluginLogger;
				if (pluginLogger3 != null)
				{
					BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(115, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[JESTER] Could not synchronize the assignment to other modded clients ");
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("(");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.GetType().Name);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("). Their Jester result may not be available.");
					}
					pluginLogger3.LogWarning(val2);
				}
			}
		}

		private static void BroadcastVictory(byte playerId)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			ManualLogSource pluginLogger = Plugin.PluginLogger;
			if (pluginLogger != null)
			{
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(71, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[JESTER][RPC] Host attempting victory broadcast for PlayerId=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<byte>(playerId);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", callId=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<byte>((byte)200);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				pluginLogger.LogInfo(val);
			}
			Broadcast(CustomRpcMessage.JesterVictory, playerId);
		}

		private static void Broadcast(CustomRpcMessage message, byte playerId, bool canVent = false)
		{
			AmongUsClient instance = AmongUsClient.Instance;
			PlayerControl localPlayer = PlayerControl.LocalPlayer;
			if ((Object)(object)instance == (Object)null || !((InnerNetClient)instance).AmHost || (Object)(object)localPlayer == (Object)null)
			{
				throw new InvalidOperationException("The host client or its local player was unavailable for the custom Jester message.");
			}
			MessageWriter val = ((InnerNetClient)instance).StartRpcImmediately(((InnerNetObject)localPlayer).NetId, (byte)200, (SendOption)1, -1);
			val.Write((byte)message);
			val.Write(playerId);
			if (message == CustomRpcMessage.AssignJester)
			{
				val.Write((byte)(canVent ? 1u : 0u));
			}
			((InnerNetClient)instance).FinishRpcImmediately(val);
		}

		private static bool TryApplySoleWinner(EndGameResult result, bool logSuccess)
		{
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Expected O, but got Unknown
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Expected O, but got Unknown
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Expected O, but got Unknown
			if (jesterVictoryActive)
			{
				byte? jesterPlayerId = Plugin.JesterPlayerId;
				byte valueOrDefault = default(byte);
				int num;
				if (jesterPlayerId.HasValue)
				{
					valueOrDefault = jesterPlayerId.GetValueOrDefault();
					num = 1;
				}
				else
				{
					num = 0;
				}
				if (num != 0)
				{
					if (result == null || (Object)(object)GameData.Instance == (Object)null)
					{
						ManualLogSource? pluginLogger = Plugin.PluginLogger;
						if (pluginLogger != null)
						{
							pluginLogger.LogWarning((object)"[JESTER] Could not replace cached winners: end-game result or GameData was unavailable.");
						}
						return false;
					}
					NetworkedPlayerInfo playerById = GameData.Instance.GetPlayerById(valueOrDefault);
					bool flag = default(bool);
					if ((Object)(object)playerById == (Object)null)
					{
						ManualLogSource pluginLogger2 = Plugin.PluginLogger;
						if (pluginLogger2 != null)
						{
							BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(68, 1, ref flag);
							if (flag)
							{
								((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[JESTER] Could not replace cached winners: player ID=");
								((BepInExLogInterpolatedStringHandler)val).AppendFormatted<byte>(valueOrDefault);
								((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" was not found.");
							}
							pluginLogger2.LogWarning(val);
						}
						return false;
					}
					List<CachedPlayerData> val2 = new List<CachedPlayerData>();
					val2.Add(new CachedPlayerData(playerById));
					EndGameResult.CachedWinners = val2;
					if (logSuccess)
					{
						ManualLogSource pluginLogger3 = Plugin.PluginLogger;
						if (pluginLogger3 != null)
						{
							BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(73, 2, ref flag);
							if (flag)
							{
								((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[JESTER] End-game result now has exactly one cached winner: ");
								((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("ID=");
								((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<byte>(valueOrDefault);
								((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(", name=\"");
								((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(playerById.PlayerName);
								((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("\".");
							}
							pluginLogger3.LogInfo(val3);
						}
					}
					return true;
				}
			}
			return false;
		}
	}
	[BepInPlugin("com.jestermod.plugin", "Jester Mod", "0.2.0")]
	public sealed class Plugin : BasePlugin
	{
		private const string PluginGuid = "com.jestermod.plugin";

		private const string PluginName = "Jester Mod";

		private const string PluginVersion = "0.2.0";

		private const string ModRegistrationGuid = "75cdfc2c-1367-4b16-a36d-b53f8637a3f5";

		internal static ManualLogSource? PluginLogger { get; private set; }

		internal static byte? JesterPlayerId { get; set; }

		internal static ConfigEntry<bool>? PracticeTestEnabled { get; private set; }

		internal static ConfigEntry<KeyboardShortcut>? PracticeTestShortcut { get; private set; }

		internal static ConfigEntry<bool>? LobbyRpcProbeEnabled { get; private set; }

		internal static ConfigEntry<KeyboardShortcut>? LobbyRpcProbeShortcut { get; private set; }

		internal static ConfigEntry<bool>? JesterCanVent { get; private set; }

		internal static bool JesterVentingAllowed { get; set; }

		public override void Load()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Expected O, but got Unknown
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			PluginLogger = ((BasePlugin)this).Log;
			CurrentModRegistration.ModRegistrationGuidString = "75cdfc2c-1367-4b16-a36d-b53f8637a3f5";
			ManualLogSource log = ((BasePlugin)this).Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(44, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Among Us mod registration GUID configured: ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("75cdfc2c-1367-4b16-a36d-b53f8637a3f5");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
			}
			log.LogInfo(val);
			PracticeTestEnabled = ((BasePlugin)this).Config.Bind<bool>("Testing", "EnablePracticeVictoryTest", false, "Enables the local-only Jester victory logic test. Keep disabled during normal play.");
			PracticeTestShortcut = ((BasePlugin)this).Config.Bind<KeyboardShortcut>("Testing", "RunPracticeVictoryTest", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "Key used to run the simulated Jester exile test in FreePlay.");
			LobbyRpcProbeEnabled = ((BasePlugin)this).Config.Bind<bool>("Testing", "EnablePrivateLobbyRpcProbe", false, "Enables a one-shot Jester ID RPC probe in a private online lobby. This does not start a game.");
			LobbyRpcProbeShortcut = ((BasePlugin)this).Config.Bind<KeyboardShortcut>("Testing", "SendPrivateLobbyRpcProbe", new KeyboardShortcut((KeyCode)290, Array.Empty<KeyCode>()), "Key used by the host to send one connected player's ID to modded clients in the current private lobby.");
			JesterCanVent = ((BasePlugin)this).Config.Bind<bool>("Jester", "JesterCanVent", false, "Whether the selected Jester may use vents. The host's value is sent with the assignment to modded clients.");
			JesterVentingAllowed = false;
			ManualLogSource log2 = ((BasePlugin)this).Log;
			val = new BepInExInfoLogInterpolatedStringHandler(39, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("JesterCanVent loaded: ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(JesterCanVent.Value);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" (default false).");
			}
			log2.LogInfo(val);
			new Harmony("com.jestermod.plugin").PatchAll();
			((BasePlugin)this).Log.LogInfo((object)"Jester Mod plugin loaded successfully.");
		}
	}
	[HarmonyPatch(typeof(ModManager), "Awake")]
	internal static class JesterModStampPatch
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			try
			{
				ModManager instance = DestroyableSingleton<ModManager>.Instance;
				if ((Object)(object)instance != (Object)null)
				{
					instance.ShowModStamp();
					ManualLogSource? pluginLogger = Plugin.PluginLogger;
					if (pluginLogger != null)
					{
						pluginLogger.LogInfo((object)"Among Us gameplay mod stamp shown.");
					}
				}
				else
				{
					ManualLogSource? pluginLogger2 = Plugin.PluginLogger;
					if (pluginLogger2 != null)
					{
						pluginLogger2.LogWarning((object)"Mod stamp skipped: ModManager.Instance was unavailable after Awake.");
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource pluginLogger3 = Plugin.PluginLogger;
				if (pluginLogger3 != null)
				{
					bool flag = default(bool);
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(34, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Mod stamp could not be shown (");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.GetType().Name);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(").");
					}
					pluginLogger3.LogWarning(val);
				}
			}
		}
	}
	[HarmonyPatch(typeof(HudManager), "Update")]
	internal static class JesterPracticeTestHotkeyPatch
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			JesterPracticeTest.TryRunIfRequested();
		}
	}
	[HarmonyPatch(typeof(MeetingHud), "VotingComplete")]
	internal static class MeetingHudVotingCompletePatch
	{
		[HarmonyPostfix]
		private static void Postfix(NetworkedPlayerInfo exiled, bool tie)
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Expected O, but got Unknown
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			JesterWinSystem.OnVoteCompleted(exiled, tie);
			bool flag = default(bool);
			if ((Object)(object)exiled == (Object)null)
			{
				ManualLogSource pluginLogger = Plugin.PluginLogger;
				if (pluginLogger != null)
				{
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(53, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Meeting voting completed: tie=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(tie);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("; no player was exiled.");
					}
					pluginLogger.LogInfo(val);
				}
				return;
			}
			ManualLogSource pluginLogger2 = Plugin.PluginLogger;
			if (pluginLogger2 != null)
			{
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(76, 5, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Meeting voting completed: tie=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(tie);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("; exiled player ID=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<byte>(exiled.PlayerId);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", ");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("name=\"");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(exiled.PlayerName);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("\", color=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(exiled.ColorName);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", net ID=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<uint>(((InnerNetObject)exiled).NetId);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				pluginLogger2.LogInfo(val);
			}
		}
	}
}