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);
}
}
}
}