The BepInEx console will not appear when launching like it does for other games on Thunderstore (you can turn it back on in your BepInEx.cfg file). If your PEAK crashes on startup, add -dx12 to your launch parameters.
Decompiled source of PEAKAntiCheat v1.4.7
PEAKAntiCheat.dll
Decompiled a month ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Photon.Pun; using Photon.Realtime; using Steamworks; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("NoiseSuppression")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("NoiseSuppression")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("c99807f0-dbec-4945-968a-6be06a6d91f2")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace AntiCheatMod; public static class InviteLinkGenerator { [CompilerGenerated] private sealed class <GenerateInviteLinkDelayed>d__2 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <GenerateInviteLinkDelayed>d__2(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(2f); <>1__state = 1; return true; case 1: <>1__state = -1; if (!PhotonNetwork.InRoom) { Debug.LogWarning((object)"[PEAK AntiCheat] No longer in room, skipping invite link generation"); return false; } if (!PhotonNetwork.IsMasterClient) { Debug.Log((object)"[PEAK AntiCheat] Not master client, skipping invite link generation"); return false; } if (_linkGenerated) { Debug.Log((object)"[PEAK AntiCheat] Invite link already generated for this room"); return false; } try { if (!SteamManager.Initialized) { Debug.LogWarning((object)"[PEAK AntiCheat] Steam not initialized, cannot create invite link"); return false; } SteamLobbyHandler service = GameHandler.GetService<SteamLobbyHandler>(); if (service == null) { Debug.LogWarning((object)"[PEAK AntiCheat] SteamLobbyHandler not found"); return false; } CSteamID val = default(CSteamID); if (!service.InSteamLobby(ref val)) { Debug.LogWarning((object)"[PEAK AntiCheat] Not in a Steam lobby"); return false; } CSteamID lobbyOwner = SteamMatchmaking.GetLobbyOwner(val); if (lobbyOwner == CSteamID.Nil) { Debug.LogWarning((object)"[PEAK AntiCheat] Could not get lobby owner"); return false; } string text2 = (GUIUtility.systemCopyBuffer = $"steam://joinlobby/3527290/{val}/{lobbyOwner}"); _linkGenerated = true; Debug.Log((object)("[PEAK AntiCheat] Invite link copied to clipboard: " + text2)); AntiCheatPlugin.LogVisually("Invite link copied to clipboard!"); } catch (Exception ex) { Debug.LogError((object)("[PEAK AntiCheat] Error creating invite link: " + ex.Message)); } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static bool _linkGenerated; public static void OnJoinedRoom() { _linkGenerated = false; if ((Object)(object)AntiCheatPlugin.Instance != (Object)null) { ((MonoBehaviour)AntiCheatPlugin.Instance).StartCoroutine(GenerateInviteLinkDelayed()); } } [IteratorStateMachine(typeof(<GenerateInviteLinkDelayed>d__2))] private static IEnumerator GenerateInviteLinkDelayed() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <GenerateInviteLinkDelayed>d__2(0); } } public enum AntiCheatNetEvent : byte { DetectionReport = 100, BlockListUpdate, DetectionSettingsUpdate, WhitelistUpdate, SyncRequest, SyncResponse, CheatModDetected, KickPlayer } public static class AntiCheatEvents { public static event Action<Player, string, CSteamID, string> OnCheaterDetected; public static event Action<DetectionType, Player, string> OnDetectionTriggered; public static event Action<Player, bool> OnPlayerBlockStatusChanged; public static event Action<Player> OnPlayerKicked; public static void NotifyCheaterDetected(Player player, string reason, CSteamID steamID) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) string arg = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); AntiCheatEvents.OnCheaterDetected?.Invoke(player, reason, steamID, arg); } public static void NotifyDetectionTriggered(DetectionType type, Player player, string reason) { AntiCheatEvents.OnDetectionTriggered?.Invoke(type, player, reason); } public static void NotifyPlayerBlockStatusChanged(Player player, bool isBlocked) { AntiCheatEvents.OnPlayerBlockStatusChanged?.Invoke(player, isBlocked); } public static void NotifyPlayerKicked(Player player) { AntiCheatEvents.OnPlayerKicked?.Invoke(player); } } [BepInPlugin("com.hiccup444.anticheat", "PEAK Anticheat", "1.4.7")] public class AntiCheatPlugin : BaseUnityPlugin, IConnectionCallbacks, IMatchmakingCallbacks, IInRoomCallbacks, IOnEventCallback { [CompilerGenerated] private sealed class <>c__DisplayClass89_0 { public CSteamID steamId; public bool receivedUpdate; internal void <WaitForPersonaStateChange>b__0(PersonaStateChange_t param) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) if (param.m_ulSteamID == steamId.m_SteamID && (param.m_nChangeFlags & 1) != 0) { receivedUpdate = true; Logger.LogInfo((object)$"Received PersonaStateChange for {steamId} - name was updated"); } } } [CompilerGenerated] private sealed class <CheckAllPlayersOnJoin>d__124 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public AntiCheatPlugin <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <CheckAllPlayersOnJoin>d__124(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown int num = <>1__state; AntiCheatPlugin antiCheatPlugin = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(3f); <>1__state = 1; return true; case 1: { <>1__state = -1; Player[] playerList = PhotonNetwork.PlayerList; foreach (Player val in playerList) { if (val.ActorNumber != PhotonNetwork.LocalPlayer.ActorNumber) { antiCheatPlugin.CheckPlayerForCheatMods(val); } } return false; } } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <CheckNewPlayerDelayed>d__105 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public AntiCheatPlugin <>4__this; public Player player; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <CheckNewPlayerDelayed>d__105(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown int num = <>1__state; AntiCheatPlugin antiCheatPlugin = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(2f); <>1__state = 1; return true; case 1: <>1__state = -1; antiCheatPlugin.CheckPlayerForCheatMods(player); ((MonoBehaviour)antiCheatPlugin).StartCoroutine(antiCheatPlugin.SecondaryCheatModCheck(player)); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <CheckPlayersForCheats>d__85 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public AntiCheatPlugin <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <CheckPlayersForCheats>d__85(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown int num = <>1__state; AntiCheatPlugin antiCheatPlugin = <>4__this; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; if (PhotonNetwork.InRoom) { Player[] playerList = PhotonNetwork.PlayerList; foreach (Player player in playerList) { antiCheatPlugin.CheckPlayerForCheatMods(player); } } } else { <>1__state = -1; } <>2__current = (object)new WaitForSeconds(5f); <>1__state = 1; return true; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <CheckPlayersWithoutAnticheat>d__125 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <CheckPlayersWithoutAnticheat>d__125(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; if (PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient && AutoBlockNoAnticheat) { DateTime now = DateTime.Now; List<int> list = new List<int>(); Player[] playerList = PhotonNetwork.PlayerList; foreach (Player val in playerList) { if (val.ActorNumber == PhotonNetwork.LocalPlayer.ActorNumber || val.IsMasterClient) { continue; } DateTime value; if (!_anticheatUsers.ContainsKey(val.ActorNumber) && !_playersWithoutAnticheat.ContainsKey(val.ActorNumber)) { CSteamID playerSteamID = GetPlayerSteamID(val); if (playerSteamID != CSteamID.Nil && BlockingManager.IsWhitelisted(playerSteamID.m_SteamID)) { Logger.LogInfo((object)("[AntiCheat] Player " + val.NickName + " is whitelisted - not tracking for anticheat timeout")); BlockingManager.GrantImmunity(val.ActorNumber); } else if (BlockingManager.IsBlocked(val.ActorNumber)) { Logger.LogInfo((object)("[AntiCheat] Player " + val.NickName + " is already blocked - not tracking for anticheat timeout")); } } else if (!_anticheatUsers.ContainsKey(val.ActorNumber) && _playersWithoutAnticheat.TryGetValue(val.ActorNumber, out value) && (now - value).TotalSeconds >= 10.0 && !BlockingManager.IsBlocked(val.ActorNumber)) { list.Add(val.ActorNumber); } else if (BlockingManager.IsBlocked(val.ActorNumber) && _playersWithoutAnticheat.ContainsKey(val.ActorNumber)) { Logger.LogInfo((object)("[AntiCheat] Player " + val.NickName + " is already blocked - removing from anticheat timeout tracking")); _playersWithoutAnticheat.Remove(val.ActorNumber); } } foreach (int item in list) { Room currentRoom = PhotonNetwork.CurrentRoom; Player val2 = ((currentRoom != null) ? currentRoom.GetPlayer(item, false) : null); if (val2 != null) { if (!BlockingManager.HasImmunity(item)) { Logger.LogWarning((object)("[AUTO BLOCK] Player " + val2.NickName + " has no anticheat - auto-blocking")); LogVisually("{userColor}" + val2.NickName + "</color> {leftColor}has no anticheat - auto-blocked</color>", onlySendOnce: false, sfxJoin: false, sfxLeave: true); BlockPlayer(val2, "No anticheat installed", DetectionType.SteamIDSpoofing); } else { Logger.LogInfo((object)$"[AUTO BLOCK] Skipping auto-block for immune player {val2.NickName} (Actor #{item})"); } _playersWithoutAnticheat.Remove(item); } } } } else { <>1__state = -1; } <>2__current = (object)new WaitForSeconds(2f); <>1__state = 1; return true; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <RemoveDetectionFromRecent>d__55 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public float delay; public string detectionKey; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <RemoveDetectionFromRecent>d__55(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(delay); <>1__state = 1; return true; case 1: <>1__state = -1; _recentDetections.Remove(detectionKey); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <SecondaryCheatModCheck>d__108 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Player player; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SecondaryCheatModCheck>d__108(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown //IL_0093: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(5f); <>1__state = 1; return true; case 1: <>1__state = -1; if (PhotonNetwork.IsMasterClient && player.ActorNumber != PhotonNetwork.LocalPlayer.ActorNumber) { object[] array = new object[1] { player.ActorNumber }; RaiseEventOptions val = new RaiseEventOptions(); val.TargetActors = new int[1] { player.ActorNumber }; PhotonNetwork.RaiseEvent((byte)70, (object)array, val, SendOptions.SendReliable); Logger.LogInfo((object)("[SECONDARY CHECK] Sent secondary cheat mod check to " + player.NickName)); } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <SendAntiCheatPingDelayed>d__122 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public AntiCheatPlugin <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SendAntiCheatPingDelayed>d__122(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown int num = <>1__state; AntiCheatPlugin antiCheatPlugin = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; Logger.LogInfo((object)"[AntiCheat] SendAntiCheatPingDelayed started - waiting 1 second..."); <>2__current = (object)new WaitForSeconds(1f); <>1__state = 1; return true; case 1: <>1__state = -1; Logger.LogInfo((object)"[AntiCheat] SendAntiCheatPingDelayed finished waiting - calling SendAntiCheatPing"); antiCheatPlugin.SendAntiCheatPing(); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <SendAntiCheatPingToAllExistingPlayers>d__107 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SendAntiCheatPingToAllExistingPlayers>d__107(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Expected O, but got Unknown //IL_00ea: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(1f); <>1__state = 1; return true; case 1: { <>1__state = -1; if (!PhotonNetwork.IsConnected || !PhotonNetwork.InRoom || PhotonNetwork.LocalPlayer == null) { return false; } Player[] array = PhotonNetwork.CurrentRoom.Players.Values.Where((Player p) => p.ActorNumber != PhotonNetwork.LocalPlayer.ActorNumber).ToArray(); if (array.Length == 0) { return false; } object[] array2 = new object[3] { PhotonNetwork.LocalPlayer.NickName, PhotonNetwork.LocalPlayer.UserId, "1.4.7" }; Player[] array3 = array; foreach (Player val in array3) { RaiseEventOptions val2 = new RaiseEventOptions(); val2.TargetActors = new int[1] { val.ActorNumber }; RaiseEventOptions val3 = val2; PhotonNetwork.RaiseEvent((byte)69, (object)array2, val3, SendOptions.SendReliable); Logger.LogInfo((object)("[AntiCheat] Sent anticheat ping to existing player " + val.NickName)); } return false; } } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <SendAntiCheatPingToNewPlayer>d__106 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Player newPlayer; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SendAntiCheatPingToNewPlayer>d__106(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Expected O, but got Unknown //IL_00be: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(1f); <>1__state = 1; return true; case 1: { <>1__state = -1; if (!PhotonNetwork.IsConnected || !PhotonNetwork.InRoom || PhotonNetwork.LocalPlayer == null) { return false; } Room currentRoom = PhotonNetwork.CurrentRoom; if (((currentRoom != null) ? currentRoom.GetPlayer(newPlayer.ActorNumber, false) : null) == null) { return false; } object[] array = new object[3] { PhotonNetwork.LocalPlayer.NickName, PhotonNetwork.LocalPlayer.UserId, "1.4.7" }; RaiseEventOptions val = new RaiseEventOptions(); val.TargetActors = new int[1] { newPlayer.ActorNumber }; RaiseEventOptions val2 = val; PhotonNetwork.RaiseEvent((byte)69, (object)array, val2, SendOptions.SendReliable); Logger.LogInfo((object)("[AntiCheat] Sent anticheat ping to new player " + newPlayer.NickName)); if (AutoBlockNoAnticheat && !_anticheatUsers.ContainsKey(newPlayer.ActorNumber)) { _playersWithoutAnticheat[newPlayer.ActorNumber] = DateTime.Now; Logger.LogInfo((object)("[AntiCheat] Started tracking " + newPlayer.NickName + " for anticheat timeout (10s from ping)")); } return false; } } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <SendSyncToAllClients>d__91 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SendSyncToAllClients>d__91(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Expected O, but got Unknown //IL_00dc: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(1f); <>1__state = 1; return true; case 1: <>1__state = -1; if (PhotonNetwork.IsMasterClient) { Logger.LogInfo((object)"[MASTER CLIENT] Sending sync data to all clients"); int[] array = (from b in BlockingManager.GetAllBlockedPlayers() select b.ActorNumber).ToArray(); object[] array2 = DetectionManager.SerializeSettings(); long[] array3 = (from id in BlockingManager.GetWhitelistedSteamIDs() select (long)id).ToArray(); object[] array4 = new object[3] { array, array2, array3 }; RaiseEventOptions val = new RaiseEventOptions { Receivers = (ReceiverGroup)0 }; PhotonNetwork.RaiseEvent((byte)105, (object)array4, val, SendOptions.SendReliable); } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <SendUnauthorizedBananaSlipToMaster>d__119 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SendUnauthorizedBananaSlipToMaster>d__119(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(3f); <>1__state = 1; return true; case 1: { <>1__state = -1; Character val = null; Character[] array = Object.FindObjectsOfType<Character>(); foreach (Character val2 in array) { PhotonView component = ((Component)val2).GetComponent<PhotonView>(); if ((Object)(object)component != (Object)null && component.Owner != null && component.Owner.IsMasterClient) { val = val2; break; } } if ((Object)(object)val == (Object)null) { Logger.LogWarning((object)"[AntiCheat] Could not find master client's character for cheat mod detection"); return false; } PhotonView component2 = ((Component)val).GetComponent<PhotonView>(); if ((Object)(object)component2 == (Object)null) { Logger.LogWarning((object)"[AntiCheat] Master client's character has no PhotonView"); return false; } BananaPeel val3 = Object.FindFirstObjectByType<BananaPeel>(); if ((Object)(object)val3 == (Object)null) { val3 = PhotonNetwork.Instantiate("0_Items/Berrynana Peel Pink Variant", val.Head, Quaternion.identity, (byte)0, (object[])null).GetComponent<BananaPeel>(); Logger.LogWarning((object)"[AntiCheat] Spawned banana peel for cheat detection"); } Logger.LogWarning((object)$"[AntiCheat] Cheat mod detected - sending unauthorized banana slip RPC to banana peel (ViewID: {((Component)val3).GetComponent<PhotonView>().ViewID})"); ((Component)val3).GetComponent<PhotonView>().RPC("RPCA_TriggerBanana", (RpcTarget)0, new object[1] { component2.ViewID }); Logger.LogWarning((object)"[AntiCheat] Unauthorized banana slip RPC sent - should trigger detection on master client"); return false; } } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <SendUnauthorizedBananaSlipToMasterDelayed>d__121 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public AntiCheatPlugin <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SendUnauthorizedBananaSlipToMasterDelayed>d__121(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown int num = <>1__state; AntiCheatPlugin antiCheatPlugin = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(5f); <>1__state = 1; return true; case 1: <>1__state = -1; <>2__current = ((MonoBehaviour)antiCheatPlugin).StartCoroutine(antiCheatPlugin.SendUnauthorizedBananaSlipToMaster()); <>1__state = 2; return true; case 2: <>1__state = -1; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <ShowAnticheatLoadedMessage>d__49 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; private float <roomTimeout>5__2; private float <roomElapsed>5__3; private float <timeout>5__4; private float <elapsed>5__5; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ShowAnticheatLoadedMessage>d__49(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; _startupMessageShown = true; <>2__current = (object)new WaitForSeconds(0.25f); <>1__state = 1; return true; case 1: <>1__state = -1; <roomTimeout>5__2 = 10f; <roomElapsed>5__3 = 0f; goto IL_0096; case 2: <>1__state = -1; <roomElapsed>5__3 += 0.25f; goto IL_0096; case 3: { <>1__state = -1; <elapsed>5__5 += 0.25f; _connectionLog = Object.FindObjectOfType<PlayerConnectionLog>(); if ((Object)(object)_connectionLog != (Object)null) { Logger.LogInfo((object)"[PEAKAntiCheat] Found PlayerConnectionLog, initializing reflection cache"); InitializeReflectionCache(); } break; } IL_0096: if (!PhotonNetwork.InRoom && <roomElapsed>5__3 < <roomTimeout>5__2) { <>2__current = (object)new WaitForSeconds(0.25f); <>1__state = 2; return true; } if (!PhotonNetwork.InRoom) { Logger.LogWarning((object)"[PEAKAntiCheat] Not in room after timeout, skipping anticheat loaded message"); return false; } if (!PhotonNetwork.IsMasterClient) { Logger.LogInfo((object)"[PEAKAntiCheat] Not master client, skipping anticheat loaded message"); return false; } <timeout>5__4 = 5f; <elapsed>5__5 = 0f; break; } if ((Object)(object)_connectionLog == (Object)null && <elapsed>5__5 < <timeout>5__4) { <>2__current = (object)new WaitForSeconds(0.25f); <>1__state = 3; return true; } if ((Object)(object)_connectionLog != (Object)null) { Logger.LogInfo((object)"[PEAKAntiCheat] Showing anticheat loaded message"); LogVisually("{joinedColor}Anticheat loaded! Press F2 to open manager.</color>", onlySendOnce: false, sfxJoin: true); } else { Logger.LogWarning((object)"[PEAKAntiCheat] PlayerConnectionLog not found after timeout, message will be queued"); LogVisually("{joinedColor}Anticheat loaded! Press F2 to open manager.</color>", onlySendOnce: false, sfxJoin: true); } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <TestUIGameObject>d__48 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <TestUIGameObject>d__48(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(2f); <>1__state = 1; return true; case 1: { <>1__state = -1; GameObject val = GameObject.Find("AntiCheatUI"); if ((Object)(object)val != (Object)null) { Logger.LogInfo((object)$"[PEAKAntiCheat] Found UI GameObject: {((Object)val).name}, Active: {val.activeInHierarchy}"); AntiCheatUI component = val.GetComponent<AntiCheatUI>(); if ((Object)(object)component != (Object)null) { Logger.LogInfo((object)$"[PEAKAntiCheat] Found UI component: {((Behaviour)component).enabled}"); } else { Logger.LogWarning((object)"[PEAKAntiCheat] UI component not found!"); } } else { Logger.LogWarning((object)"[PEAKAntiCheat] UI GameObject not found!"); } return false; } } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <TrackModListOptOut>d__145 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <TrackModListOptOut>d__145(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(3f); <>1__state = 1; return true; case 1: <>1__state = -1; foreach (Player value in PhotonNetwork.CurrentRoom.Players.Values) { if (value.ActorNumber != PhotonNetwork.LocalPlayer.ActorNumber && !_playerModLists.ContainsKey(value.ActorNumber)) { _playersOptedOutOfModSharing.Add(value.ActorNumber); Logger.LogInfo((object)("[PEAKAntiCheat] Player " + value.NickName + " has opted out of mod sharing")); } } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <TrackPlayerCoordinates>d__110 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public AntiCheatPlugin <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <TrackPlayerCoordinates>d__110(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) int num = <>1__state; AntiCheatPlugin antiCheatPlugin = <>4__this; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; if (PhotonNetwork.InRoom) { Character[] array = Object.FindObjectsOfType<Character>(); foreach (Character val in array) { PhotonView component = ((Component)val).GetComponent<PhotonView>(); if (!((Object)(object)component == (Object)null) && component.Owner != null && !IsBlocked(component.Owner.ActorNumber)) { Vector3 position = ((Component)val).transform.position; _playerLastKnownCoordinates[component.Owner.ActorNumber] = position; _playerCoordinateTimestamps[component.Owner.ActorNumber] = DateTime.Now; if (PhotonNetwork.IsMasterClient) { antiCheatPlugin.CheckAndRescuePlayerFromInfinity(val, component.Owner); } } } } } else { <>1__state = -1; } <>2__current = (object)new WaitForSeconds(10f); <>1__state = 1; return true; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <TrackPlayerItems>d__109 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <TrackPlayerItems>d__109(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; if (PhotonNetwork.InRoom) { Character[] array = Object.FindObjectsOfType<Character>(); foreach (Character val in array) { PhotonView component = ((Component)val).GetComponent<PhotonView>(); if (!((Object)(object)component == (Object)null) && component.Owner != null && !IsBlocked(component.Owner.ActorNumber)) { CharacterData component2 = ((Component)val).GetComponent<CharacterData>(); if ((Object)(object)component2 != (Object)null && (Object)(object)component2.currentItem != (Object)null) { bool wasCookable = (Object)(object)component2.currentItem.cooking != (Object)null && component2.currentItem.cooking.canBeCooked; UpdatePlayerHeldItem(component.Owner.ActorNumber, ((Object)component2.currentItem).name, wasCookable); } } } } } else { <>1__state = -1; } <>2__current = (object)new WaitForSeconds(2f); <>1__state = 1; return true; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <WaitForPersonaStateChange>d__89 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public CSteamID steamId; public Player player; private <>c__DisplayClass89_0 <>8__1; public float timeout; public bool blockOnMismatch; private float <startTime>5__2; private Callback<PersonaStateChange_t> <personaCallback>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <WaitForPersonaStateChange>d__89(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>8__1 = null; <personaCallback>5__3 = null; <>1__state = -2; } private bool MoveNext() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Unknown result type (might be due to invalid IL or missing references) //IL_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>8__1 = new <>c__DisplayClass89_0(); <>8__1.steamId = steamId; <startTime>5__2 = Time.time; <>8__1.receivedUpdate = false; <personaCallback>5__3 = null; <personaCallback>5__3 = Callback<PersonaStateChange_t>.Create((DispatchDelegate<PersonaStateChange_t>)delegate(PersonaStateChange_t param) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) if (param.m_ulSteamID == <>8__1.steamId.m_SteamID && (param.m_nChangeFlags & 1) != 0) { <>8__1.receivedUpdate = true; Logger.LogInfo((object)$"Received PersonaStateChange for {<>8__1.steamId} - name was updated"); } }); break; case 1: <>1__state = -1; if (PhotonNetwork.CurrentRoom == null || PhotonNetwork.CurrentRoom.GetPlayer(player.ActorNumber, false) == null) { Logger.LogInfo((object)("Player " + player.NickName + " left before name verification completed")); <personaCallback>5__3?.Dispose(); return false; } break; } if (!<>8__1.receivedUpdate && Time.time - <startTime>5__2 < timeout) { <>2__current = (object)new WaitForSeconds(0.1f); <>1__state = 1; return true; } <personaCallback>5__3?.Dispose(); string friendPersonaName = SteamFriends.GetFriendPersonaName(<>8__1.steamId); if (friendPersonaName.ToLower() != player.NickName.ToLower()) { if (blockOnMismatch) { Logger.LogWarning((object)("Name mismatch confirmed after PersonaStateChange: Photon='" + player.NickName + "' vs Steam='" + friendPersonaName + "'")); LogVisually("{userColor}" + player.NickName + "</color> {leftColor}confirmed spoofing - real Steam name is '" + friendPersonaName + "'!</color>", onlySendOnce: true, sfxJoin: false, sfxLeave: true); if (PhotonNetwork.CurrentRoom != null && PhotonNetwork.CurrentRoom.GetPlayer(player.ActorNumber, false) != null) { DetectionManager.RecordDetection(DetectionType.SteamNameMismatch, player, "Name spoofing confirmed - real name: " + friendPersonaName); } } else { Logger.LogWarning((object)("Name mismatch on join after refresh: Photon='" + player.NickName + "' vs Steam='" + friendPersonaName + "'")); LogVisually("{userColor}" + player.NickName + "</color> {leftColor}has mismatched Steam name: '" + friendPersonaName + "'</color>", onlySendOnce: true, sfxJoin: false, sfxLeave: true); DetectionManager.RecordDetection(DetectionType.SteamNameMismatch, player, "Name mismatch: Photon='" + player.NickName + "' vs Steam='" + friendPersonaName + "'"); } } else { Logger.LogInfo((object)("Name verification passed for " + player.NickName + " after fresh data")); LogVisually("{userColor}" + player.NickName + "</color> {joinedColor}name verified successfully</color>", onlySendOnce: true); } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public static ManualLogSource Logger; public static ConfigFile Config; private static readonly Dictionary<int, (string itemName, DateTime timestamp, bool wasCookable)> _playerLastHeldItems = new Dictionary<int, (string, DateTime, bool)>(); private static readonly Dictionary<int, Vector3> _playerLastKnownCoordinates = new Dictionary<int, Vector3>(); private static readonly Dictionary<int, DateTime> _playerCoordinateTimestamps = new Dictionary<int, DateTime>(); private const float COORDINATE_UPDATE_INTERVAL = 10f; private static readonly Dictionary<int, GameObject> _blockedPlayerHeldItems = new Dictionary<int, GameObject>(); private const string PLUGIN_VERSION = "1.4.7"; private const byte ANTICHEAT_PING_EVENT = 69; private static ConfigEntry<bool> ShowVisualLogs; private static ConfigEntry<bool> CheckSteamNames; public static ConfigEntry<bool> AutoBlockCheaters; public static ConfigEntry<bool> VerboseRPCLogging; private static ConfigEntry<string> WhitelistedSteamIDs; public static ConfigEntry<KeyboardShortcut> UIToggleKey; private static PlayerConnectionLog _connectionLog; private static readonly Queue<(string message, bool onlySendOnce, bool sfxJoin, bool sfxLeave)> _queuedLogs = new Queue<(string, bool, bool, bool)>(8); private static readonly List<PlayerIdentity> _knownPlayerIdentities = new List<PlayerIdentity>(); private static MethodInfo _getColorTagMethod; private static MethodInfo _addMessageMethod; private static FieldInfo _currentLogField; private static FieldInfo _joinedColorField; private static FieldInfo _leftColorField; private static FieldInfo _userColorField; private static FieldInfo _sfxJoinField; private static FieldInfo _sfxLeaveField; private static Func<object, string> _getColorTagDelegate; private static Action<object, string> _addMessageDelegate; private static FieldInfo _currentLobbyField; private static readonly Dictionary<int, DateTime> _recentlySpawnedPlayers = new Dictionary<int, DateTime>(); private const double SPAWN_GRACE_PERIOD_SECONDS = 5.0; private static readonly Dictionary<int, string> _anticheatUsers = new Dictionary<int, string>(); private static readonly Dictionary<int, string[]> _playerModLists = new Dictionary<int, string[]>(); private static readonly HashSet<int> _playersOptedOutOfModSharing = new HashSet<int>(); private static readonly HashSet<string> _recentDetections = new HashSet<string>(); private static readonly HashSet<int> _detectedCheatModUsers = new HashSet<int>(); private static bool _startupMessageShown = false; private static readonly Dictionary<int, DateTime> _playersWithoutAnticheat = new Dictionary<int, DateTime>(); private const float ANTICHEAT_TIMEOUT_SECONDS = 10f; private static DateTime _lastMasterClientChange = DateTime.MinValue; private const float MASTER_CLIENT_CHANGE_COOLDOWN_SECONDS = 30f; public static ConfigEntry<bool> ShareModList; private const string DEV_STEAM_ID = "STEAM_0:0:143296685"; public static AntiCheatPlugin Instance { get; private set; } public static bool AutoKickBlockedPlayers { get; set; } = false; public static bool AutoBlockNoAnticheat { get; set; } = false; private void Awake() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) Instance = this; Logger = ((BaseUnityPlugin)this).Logger; Config = new ConfigFile(Path.Combine(Paths.ConfigPath, "com.hiccup444.anticheat.cfg"), true); ShowVisualLogs = Config.Bind<bool>("General", "ShowVisualLogs", true, "Show anti-cheat messages in the connection log"); CheckSteamNames = Config.Bind<bool>("General", "CheckSteamNames", true, "Check if Photon names match Steam names"); AutoBlockCheaters = Config.Bind<bool>("General", "AutoBlockCheaters", true, "Automatically block all RPCs from detected cheaters"); VerboseRPCLogging = Config.Bind<bool>("Debug", "VerboseRPCLogging", false, "Log all RPC calls for debugging"); WhitelistedSteamIDs = Config.Bind<string>("General", "WhitelistedSteamIDs", "", "Comma-separated list of Steam IDs that should never be RPC blocked (e.g. '76561198012345678,76561198087654321')"); UIToggleKey = Config.Bind<KeyboardShortcut>("General", "UIToggleKey", new KeyboardShortcut((KeyCode)283, Array.Empty<KeyCode>()), "Key to toggle the anti-cheat UI (default: F2)"); ShareModList = Config.Bind<bool>("General", "ShareModList", true, "Share your mod list with the host (enabled by default)"); ParseWhitelist(); Config.Save(); InitializeDetectionManager(); InitializeEventHandlers(); Logger.LogInfo((object)"[PEAKAntiCheat] Protection active! (RPC Blocking Mode)"); new Harmony("com.hiccup444.PEAKanticheat").PatchAll(); PhotonNetwork.AddCallbackTarget((object)this); ((MonoBehaviour)this).StartCoroutine(CheckPlayersForCheats()); ((MonoBehaviour)this).StartCoroutine(TrackPlayerItems()); ((MonoBehaviour)this).StartCoroutine(TrackPlayerCoordinates()); ((MonoBehaviour)this).StartCoroutine(CheckPlayersWithoutAnticheat()); SceneManager.activeSceneChanged += OnSceneChanged; } private void OnSceneChanged(Scene oldScene, Scene newScene) { Logger.LogInfo((object)("[PEAKAntiCheat] Scene changed from " + ((Scene)(ref oldScene)).name + " to " + ((Scene)(ref newScene)).name)); if (((Scene)(ref newScene)).name.Contains("Airport") || ((Scene)(ref newScene)).name.Contains("Level")) { Logger.LogInfo((object)("[PEAKAntiCheat] Game scene detected: " + ((Scene)(ref newScene)).name + " - creating UI")); CreateUI(); if (((Scene)(ref newScene)).name.Contains("Airport") && !_startupMessageShown) { ((MonoBehaviour)this).StartCoroutine(ShowAnticheatLoadedMessage()); } } if (((Scene)(ref newScene)).name.Contains("Level")) { Player[] playerList = PhotonNetwork.PlayerList; for (int i = 0; i < playerList.Length; i++) { OnPlayerSpawned(playerList[i].ActorNumber); } if (PhotonNetwork.InRoom && PhotonNetwork.LocalPlayer != null) { OnPlayerSpawned(PhotonNetwork.LocalPlayer.ActorNumber); } Logger.LogInfo((object)("Entered game scene '" + ((Scene)(ref newScene)).name + "' - granting spawn grace period to all players including local")); } } private void CreateUI() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown if ((Object)(object)GameObject.Find("AntiCheatUI") != (Object)null) { Logger.LogInfo((object)"[PEAKAntiCheat] UI already exists, skipping creation"); return; } Logger.LogInfo((object)"[PEAKAntiCheat] Creating UI..."); GameObject val = new GameObject("AntiCheatUI"); Logger.LogInfo((object)$"[PEAKAntiCheat] UI GameObject created: {((Object)val).name}, Active: {val.activeInHierarchy}"); AntiCheatUI antiCheatUI = val.AddComponent<AntiCheatUI>(); Logger.LogInfo((object)$"[PEAKAntiCheat] UI component added: {(Object)(object)antiCheatUI != (Object)null}, Component enabled: {((antiCheatUI != null) ? new bool?(((Behaviour)antiCheatUI).enabled) : null)}"); val.SetActive(true); Logger.LogInfo((object)$"[PEAKAntiCheat] UI GameObject activated: {val.activeInHierarchy}"); if ((Object)(object)antiCheatUI != (Object)null) { Logger.LogInfo((object)"[PEAKAntiCheat] Manually calling Start method on UI component"); ((Component)antiCheatUI).SendMessage("Start", (SendMessageOptions)1); } Object.DontDestroyOnLoad((Object)(object)val); Logger.LogInfo((object)"[PEAKAntiCheat] UI set to persist across scenes"); Logger.LogInfo((object)"[PEAKAntiCheat] UI creation completed"); ((MonoBehaviour)this).StartCoroutine(TestUIGameObject()); } [IteratorStateMachine(typeof(<TestUIGameObject>d__48))] private IEnumerator TestUIGameObject() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <TestUIGameObject>d__48(0); } [IteratorStateMachine(typeof(<ShowAnticheatLoadedMessage>d__49))] private IEnumerator ShowAnticheatLoadedMessage() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <ShowAnticheatLoadedMessage>d__49(0); } private void InitializeDetectionManager() { bool flag = false; ConfigEntry<string> obj = Config.Bind<string>("UI", "GroupSliders", "", "Saved group slider settings"); ConfigEntry<string> val = Config.Bind<string>("UI", "IndividualSliders", "", "Saved individual slider settings"); if (!string.IsNullOrEmpty(obj.Value) || !string.IsNullOrEmpty(val.Value)) { flag = true; Logger.LogInfo((object)"[PEAKAntiCheat] UI settings detected - skipping default detection initialization"); } if (!flag) { Logger.LogInfo((object)"[PEAKAntiCheat] No UI settings found - initializing with default detection settings"); DetectionManager.SetDetectionSettings(DetectionType.CherryMod, new DetectionSettings(isEnabled: true, AutoBlockCheaters.Value, ShowVisualLogs.Value)); DetectionManager.SetDetectionSettings(DetectionType.AtlasMod, new DetectionSettings(isEnabled: true, AutoBlockCheaters.Value, ShowVisualLogs.Value)); DetectionManager.SetDetectionSettings(DetectionType.SteamNameMismatch, new DetectionSettings(CheckSteamNames.Value, AutoBlockCheaters.Value, ShowVisualLogs.Value)); DetectionManager.SetDetectionSettings(DetectionType.NameImpersonation, new DetectionSettings(isEnabled: true, AutoBlockCheaters.Value, ShowVisualLogs.Value)); DetectionManager.SetDetectionSettings(DetectionType.MidGameNameChange, new DetectionSettings(isEnabled: true, AutoBlockCheaters.Value, ShowVisualLogs.Value)); DetectionManager.SetDetectionSettings(DetectionType.SteamIDSpoofing, new DetectionSettings(isEnabled: true, AutoBlockCheaters.Value, ShowVisualLogs.Value)); DetectionManager.SetDetectionSettings(DetectionType.OwnershipTheft, new DetectionSettings(isEnabled: true, AutoBlockCheaters.Value, ShowVisualLogs.Value)); DetectionManager.SetDetectionSettings(DetectionType.UnauthorizedDestroy, new DetectionSettings(isEnabled: true, AutoBlockCheaters.Value, ShowVisualLogs.Value)); DetectionManager.SetDetectionSettings(DetectionType.RateLimitExceeded, new DetectionSettings(isEnabled: true, AutoBlockCheaters.Value, ShowVisualLogs.Value)); DetectionManager.SetDetectionSettings(DetectionType.UnauthorizedKill, new DetectionSettings(isEnabled: true, AutoBlockCheaters.Value, ShowVisualLogs.Value)); DetectionManager.SetDetectionSettings(DetectionType.UnauthorizedRevive, new DetectionSettings(isEnabled: true, AutoBlockCheaters.Value, ShowVisualLogs.Value)); DetectionManager.SetDetectionSettings(DetectionType.UnauthorizedWarp, new DetectionSettings(isEnabled: true, AutoBlockCheaters.Value, ShowVisualLogs.Value)); DetectionManager.SetDetectionSettings(DetectionType.UnauthorizedStatusEffect, new DetectionSettings(isEnabled: true, AutoBlockCheaters.Value, ShowVisualLogs.Value)); DetectionManager.SetDetectionSettings(DetectionType.UnauthorizedMovement, new DetectionSettings(isEnabled: true, AutoBlockCheaters.Value, ShowVisualLogs.Value)); DetectionManager.SetDetectionSettings(DetectionType.UnauthorizedEmote, new DetectionSettings(isEnabled: true, AutoBlockCheaters.Value, ShowVisualLogs.Value)); DetectionManager.SetDetectionSettings(DetectionType.UnauthorizedItemDrop, new DetectionSettings(isEnabled: true, AutoBlockCheaters.Value, ShowVisualLogs.Value)); DetectionManager.SetDetectionSettings(DetectionType.UnauthorizedCampfireModification, new DetectionSettings(isEnabled: true, AutoBlockCheaters.Value, ShowVisualLogs.Value)); DetectionManager.SetDetectionSettings(DetectionType.UnauthorizedFlareLighting, new DetectionSettings(isEnabled: true, AutoBlockCheaters.Value, ShowVisualLogs.Value)); DetectionManager.SetDetectionSettings(DetectionType.UnauthorizedBananaSlip, new DetectionSettings(isEnabled: true, AutoBlockCheaters.Value, ShowVisualLogs.Value)); DetectionManager.SetDetectionSettings(DetectionType.MasterClientTheft, new DetectionSettings(isEnabled: true, AutoBlockCheaters.Value, ShowVisualLogs.Value)); DetectionManager.SetDetectionSettings(DetectionType.InfinityWarp, new DetectionSettings(isEnabled: true, AutoBlockCheaters.Value, ShowVisualLogs.Value)); } } private void InitializeEventHandlers() { DetectionManager.OnDetectionOccurred += OnDetectionOccurred; PlayerManager.OnPlayerAdded += OnPlayerAdded; PlayerManager.OnPlayerStatusChanged += OnPlayerStatusChanged; BlockingManager.OnPlayerBlocked += OnPlayerBlocked; BlockingManager.OnPlayerUnblocked += OnPlayerUnblocked; } private void Update() { RPCDetection.ProcessPendingItemChecks(); if (_queuedLogs.Count > 0) { var (message, onlySendOnce, sfxJoin, sfxLeave) = _queuedLogs.Dequeue(); LogVisually(message, onlySendOnce, sfxJoin, sfxLeave, allowNonMaster: true); } } private void OnDestroy() { PhotonNetwork.RemoveCallbackTarget((object)this); SceneManager.activeSceneChanged -= OnSceneChanged; DetectionManager.OnDetectionOccurred -= OnDetectionOccurred; PlayerManager.OnPlayerAdded -= OnPlayerAdded; PlayerManager.OnPlayerStatusChanged -= OnPlayerStatusChanged; BlockingManager.OnPlayerBlocked -= OnPlayerBlocked; BlockingManager.OnPlayerUnblocked -= OnPlayerUnblocked; } private void OnDetectionOccurred(DetectionResult result) { if (result.Target == null) { return; } if (DetectionManager.ShouldLogToConsole(result.Type)) { Logger.LogWarning((object)$"[DETECTION] {result.Target.NickName} ({result.Type}): {result.Reason}"); } if (!PhotonNetwork.IsMasterClient) { ReportDetectionToMaster(result.Type, result.Target, result.Reason); return; } DetectionSettings detectionSettings = DetectionManager.GetDetectionSettings(result.Type); if (detectionSettings.IsEnabled) { LogVisually("{userColor}" + result.Target.NickName + "</color> {leftColor}" + result.Reason + "</color>", onlySendOnce: false, sfxJoin: false, sfxLeave: true); if (detectionSettings.AutoBlock) { BlockPlayer(result.Target, result.Reason, result.Type); LogVisually($"{{userColor}}{result.Target.NickName}</color> {{leftColor}}was auto-blocked for {result.Type}</color>", onlySendOnce: false, sfxJoin: false, sfxLeave: true); } else if (detectionSettings.ShowVisualWarning) { string text = $"{result.Target.ActorNumber}_{result.Type}"; if (!_recentDetections.Contains(text)) { LogVisually($"{{userColor}}{result.Target.NickName}</color> {{leftColor}}detected - {result.Type} - no action taken</color>", onlySendOnce: false, sfxJoin: false, sfxLeave: true); _recentDetections.Add(text); ((MonoBehaviour)this).StartCoroutine(RemoveDetectionFromRecent(text, 30f)); } } } PlayerManager.AddDetectionReason(result.Target.ActorNumber, result.Reason); } [IteratorStateMachine(typeof(<RemoveDetectionFromRecent>d__55))] private IEnumerator RemoveDetectionFromRecent(string detectionKey, float delay) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <RemoveDetectionFromRecent>d__55(0) { detectionKey = detectionKey, delay = delay }; } private void OnPlayerAdded(PlayerInfo playerInfo) { Logger.LogInfo((object)$"[PLAYER ADDED] {playerInfo.PhotonName} (Actor #{playerInfo.ActorNumber})"); } private void OnPlayerStatusChanged(PlayerInfo playerInfo) { Logger.LogInfo((object)$"[STATUS CHANGE] {playerInfo.PhotonName}: {playerInfo.Status}"); } private void OnPlayerBlocked(BlockEntry blockEntry) { Logger.LogWarning((object)("[PLAYER BLOCKED] " + blockEntry.PlayerName + ": " + blockEntry.SpecificReason)); } private void OnPlayerUnblocked(int actorNumber) { Logger.LogInfo((object)$"[PLAYER UNBLOCKED] Actor #{actorNumber}"); _detectedCheatModUsers.Remove(actorNumber); Room currentRoom = PhotonNetwork.CurrentRoom; Player val = ((currentRoom != null) ? currentRoom.GetPlayer(actorNumber, false) : null); if (val != null) { string item = $"{val.NickName}_{actorNumber}_AtlasMod"; _recentDetections.Remove(item); item = $"{val.NickName}_{actorNumber}_CherryMod"; _recentDetections.Remove(item); } RPCDetection.ClearFlagCounts(actorNumber); BlockingManager.GrantImmunity(actorNumber); Logger.LogInfo((object)$"[PLAYER UNBLOCKED] Granted immunity to Actor #{actorNumber} to prevent re-detection"); } public static void BlockPlayer(Player cheater, string reason, DetectionType? detectionType = null) { //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) if (cheater.ActorNumber == PhotonNetwork.LocalPlayer.ActorNumber) { Logger.LogInfo((object)"Not blocking local player"); return; } if (cheater.IsMasterClient) { Logger.LogWarning((object)("[BLOCK PREVENTED] Attempted to block master client " + cheater.NickName + " for: " + reason)); return; } bool flag = true; if (!((!detectionType.HasValue) ? AutoBlockCheaters.Value : DetectionManager.ShouldAutoBlock(detectionType.Value))) { Logger.LogInfo((object)("Auto-blocking disabled for this detection - only logging cheater: " + cheater.NickName)); return; } Logger.LogWarning((object)("CHEATER DETECTED: " + cheater.NickName + " - Reason: " + reason)); CSteamID nil = CSteamID.Nil; nil = _knownPlayerIdentities.Find((PlayerIdentity p) => p.ActorNumber == cheater.ActorNumber)?.SteamID ?? GetPlayerSteamID(cheater); AntiCheatEvents.NotifyCheaterDetected(cheater, reason, nil); BlockingManager.BlockPlayer(cheater, reason, BlockReason.AutoDetection, nil, detectionType); Logger.LogInfo((object)$"All RPCs from {cheater.NickName} (Actor #{cheater.ActorNumber}) are now blocked"); } public static bool IsBlocked(int actorNumber) { return BlockingManager.IsBlocked(actorNumber); } public static bool HasAnticheat(int actorNumber) { return _anticheatUsers.ContainsKey(actorNumber); } public static string GetAnticheatVersion(int actorNumber) { if (!_anticheatUsers.TryGetValue(actorNumber, out var value)) { return null; } return value; } public static bool AreKicksAllowed() { if (_lastMasterClientChange == DateTime.MinValue) { return true; } double totalSeconds = (DateTime.Now - _lastMasterClientChange).TotalSeconds; bool num = totalSeconds >= 30.0; if (!num) { Logger.LogWarning((object)$"[KICK SECURITY] Kicks disabled - master client changed {totalSeconds:F1} seconds ago (cooldown: {30f}s)"); } return num; } public static void UpdatePlayerHeldItem(int actorNumber, string itemName, bool wasCookable = false) { if (!string.IsNullOrEmpty(itemName)) { _playerLastHeldItems[actorNumber] = (itemName.ToLower(), DateTime.Now, wasCookable); } } public static bool PlayerHadItem(int actorNumber, string itemNamePart, float withinSeconds = 2f, bool checkCookable = false) { if (_playerLastHeldItems.TryGetValue(actorNumber, out (string, DateTime, bool) value) && (DateTime.Now - value.Item2).TotalSeconds <= (double)withinSeconds) { if (checkCookable) { return value.Item3; } return value.Item1.Contains(itemNamePart.ToLower()); } return false; } public static bool PlayerHadCookableItem(int actorNumber, float withinSeconds = 2f) { return PlayerHadItem(actorNumber, "", withinSeconds, checkCookable: true); } private static void InitializeReflectionCache() { if ((Object)(object)_connectionLog == (Object)null) { _connectionLog = Object.FindObjectOfType<PlayerConnectionLog>(); if ((Object)(object)_connectionLog == (Object)null) { Logger.LogWarning((object)"[PEAKAntiCheat] PlayerConnectionLog not found in scene"); return; } Logger.LogInfo((object)"[PEAKAntiCheat] Found PlayerConnectionLog, setting up reflection cache"); } Type type = ((object)_connectionLog).GetType(); _getColorTagMethod = type.GetMethod("GetColorTag", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _addMessageMethod = type.GetMethod("AddMessage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _currentLogField = type.GetField("currentLog", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _joinedColorField = type.GetField("joinedColor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _leftColorField = type.GetField("leftColor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _userColorField = type.GetField("userColor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _sfxJoinField = type.GetField("sfxJoin", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _sfxLeaveField = type.GetField("sfxLeave", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); try { if (_getColorTagMethod != null) { _getColorTagDelegate = (Func<object, string>)Delegate.CreateDelegate(typeof(Func<object, string>), _connectionLog, _getColorTagMethod); } if (_addMessageMethod != null) { _addMessageDelegate = (Action<object, string>)Delegate.CreateDelegate(typeof(Action<object, string>), _connectionLog, _addMessageMethod); } } catch (Exception ex) { Logger.LogWarning((object)("[Reflection Cache] Failed to create delegates, falling back to direct reflection: " + ex.Message)); _getColorTagDelegate = null; _addMessageDelegate = null; } } public static bool LogVisually(string message, bool onlySendOnce = false, bool sfxJoin = false, bool sfxLeave = false, bool allowNonMaster = false) { //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_0371: Unknown result type (might be due to invalid IL or missing references) if (!PhotonNetwork.IsMasterClient && !allowNonMaster && !message.Contains("has anticheat installed")) { return true; } if (!ShowVisualLogs.Value) { return true; } if ((Object)(object)_connectionLog == (Object)null || _getColorTagMethod == null || _addMessageMethod == null) { InitializeReflectionCache(); } if (!Object.op_Implicit((Object)(object)_connectionLog) || _getColorTagMethod == null || _addMessageMethod == null) { Logger.LogWarning((object)$"[PEAKAntiCheat] LogVisually failed - ConnectionLog: {(Object)(object)_connectionLog != (Object)null}, GetColorTagMethod: {_getColorTagMethod != null}, AddMessageMethod: {_addMessageMethod != null}"); _queuedLogs.Enqueue((message, onlySendOnce, sfxJoin, sfxLeave)); return false; } try { StringBuilder stringBuilder = new StringBuilder(message); if (_joinedColorField != null && _leftColorField != null && _userColorField != null) { object value = _joinedColorField.GetValue(_connectionLog); object value2 = _leftColorField.GetValue(_connectionLog); object value3 = _userColorField.GetValue(_connectionLog); string text = ""; string text2 = ""; string text3 = ""; if (_getColorTagDelegate != null) { text = _getColorTagDelegate(value); text2 = _getColorTagDelegate(value2); text3 = _getColorTagDelegate(value3); } else if (_getColorTagMethod != null) { text = (string)_getColorTagMethod.Invoke(_connectionLog, new object[1] { value }); text2 = (string)_getColorTagMethod.Invoke(_connectionLog, new object[1] { value2 }); text3 = (string)_getColorTagMethod.Invoke(_connectionLog, new object[1] { value3 }); } stringBuilder.Replace("{joinedColor}", text ?? ""); stringBuilder.Replace("{leftColor}", text2 ?? ""); stringBuilder.Replace("{userColor}", text3 ?? ""); } message = stringBuilder.ToString(); if (onlySendOnce && _currentLogField != null) { string text4 = _currentLogField.GetValue(_connectionLog) as string; if (!string.IsNullOrEmpty(text4) && text4.Contains(message)) { return true; } } if (_addMessageDelegate != null) { _addMessageDelegate(_connectionLog, message); } else { _addMessageMethod.Invoke(_connectionLog, new object[1] { message }); } if (sfxJoin && _sfxJoinField != null) { object value4 = _sfxJoinField.GetValue(_connectionLog); value4?.GetType().GetMethod("Play", new Type[1] { typeof(Vector3) })?.Invoke(value4, new object[1] { Vector3.zero }); } if (sfxLeave && _sfxLeaveField != null) { object value5 = _sfxLeaveField.GetValue(_connectionLog); value5?.GetType().GetMethod("Play", new Type[1] { typeof(Vector3) })?.Invoke(value5, new object[1] { Vector3.zero }); } return true; } catch (Exception ex) { Logger.LogError((object)("Error in LogVisually: " + ex.Message)); return false; } } public static void OnPlayerSpawned(int actorNumber) { _recentlySpawnedPlayers[actorNumber] = DateTime.Now; Logger.LogInfo((object)$"Tracking spawn for actor #{actorNumber}"); } public static bool IsInSpawnGracePeriod(int actorNumber) { if (_recentlySpawnedPlayers.ContainsKey(actorNumber)) { if ((DateTime.Now - _recentlySpawnedPlayers[actorNumber]).TotalSeconds <= 5.0) { return true; } _recentlySpawnedPlayers.Remove(actorNumber); } return false; } [HarmonyPatch(typeof(PlayerConnectionLog), "OnPlayerEnteredRoom")] [HarmonyPrefix] public static bool PreOnPlayerEnteredRoom(PlayerConnectionLog __instance, Player newPlayer) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) if (newPlayer.IsLocal || newPlayer.NickName == "Bing Bong") { return true; } bool flag = false; try { CSteamID playerSteamID = GetPlayerSteamID(newPlayer); if (playerSteamID != CSteamID.Nil) { string text = ((object)(CSteamID)(ref playerSteamID)).ToString(); flag = text == "STEAM_0:0:143296685"; if (flag) { Logger.LogInfo((object)("[DEV JOIN] Detected dev joining: " + newPlayer.NickName + " (Steam ID: " + text + ")")); } } } catch (Exception ex) { Logger.LogWarning((object)("[DEV JOIN] Error checking Steam ID for " + newPlayer.NickName + ": " + ex.Message)); } if (flag) { try { FieldInfo field = ((object)__instance).GetType().GetField("userColor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo field2 = ((object)__instance).GetType().GetField("joinedColor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo field3 = ((object)__instance).GetType().GetField("sfxJoin", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); MethodInfo method = ((object)__instance).GetType().GetMethod("AddMessage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); MethodInfo method2 = ((object)__instance).GetType().GetMethod("GetColorTag", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && field2 != null && method != null && method2 != null) { Color val = (Color)field.GetValue(__instance); Color val2 = (Color)field2.GetValue(__instance); string text2 = (string)method2.Invoke(__instance, new object[1] { val }); string obj = (string)method2.Invoke(__instance, new object[1] { val2 }); string newValue = text2 + " [Anticheat Dev] " + newPlayer.NickName + "</color>"; string text3 = obj + LocalizedText.GetText("JOINEDTHEEXPEDITION", true).Replace("#", newValue) + "</color>"; method.Invoke(__instance, new object[1] { text3 }); if (field3 != null) { object value = field3.GetValue(__instance); value?.GetType().GetMethod("Play", new Type[1] { typeof(Vector3) })?.Invoke(value, new object[1] { Vector3.zero }); } Logger.LogInfo((object)("[DEV JOIN] Custom dev join message displayed for " + newPlayer.NickName)); return false; } } catch (Exception ex2) { Logger.LogError((object)("[DEV JOIN] Error creating custom dev message: " + ex2.Message)); } } return true; } private static CSteamID GetPlayerSteamID(Player player) { //IL_042d: Unknown result type (might be due to invalid IL or missing references) //IL_0432: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0436: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_031f: Unknown result type (might be due to invalid IL or missing references) //IL_0324: Unknown result type (might be due to invalid IL or missing references) //IL_0356: Unknown result type (might be due to invalid IL or missing references) //IL_035b: Unknown result type (might be due to invalid IL or missing references) //IL_035d: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_036d: Unknown result type (might be due to invalid IL or missing references) //IL_0390: Unknown result type (might be due to invalid IL or missing references) //IL_0395: Unknown result type (might be due to invalid IL or missing references) //IL_0399: Unknown result type (might be due to invalid IL or missing references) //IL_03b2: Unknown result type (might be due to invalid IL or missing references) //IL_03c3: Unknown result type (might be due to invalid IL or missing references) //IL_03c5: Unknown result type (might be due to invalid IL or missing references) //IL_03fc: Unknown result type (might be due to invalid IL or missing references) //IL_0401: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Unknown result type (might be due to invalid IL or missing references) //IL_02a3: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Unknown result type (might be due to invalid IL or missing references) try { SteamLobbyHandler service = GameHandler.GetService<SteamLobbyHandler>(); if (service == null) { Logger.LogWarning((object)"[GetPlayerSteamID] SteamLobbyHandler not found."); return CSteamID.Nil; } if (_currentLobbyField == null) { _currentLobbyField = ((object)service).GetType().GetField("m_currentLobby", BindingFlags.Instance | BindingFlags.NonPublic); } if (_currentLobbyField == null) { Logger.LogError((object)"[GetPlayerSteamID] Could not find m_currentLobby field via reflection."); return CSteamID.Nil; } CSteamID val = (CSteamID)_currentLobbyField.GetValue(service); if (val == CSteamID.Nil) { Logger.LogWarning((object)"[GetPlayerSteamID] Current Steam lobby is NIL."); return CSteamID.Nil; } int numLobbyMembers = SteamMatchmaking.GetNumLobbyMembers(val); Logger.LogInfo((object)$"[GetPlayerSteamID] Scanning {numLobbyMembers} Steam lobby members for match with Photon name '{player.NickName}'."); Dictionary<string, List<CSteamID>> dictionary = new Dictionary<string, List<CSteamID>>(); List<CSteamID> list = new List<CSteamID>(); for (int i = 0; i < numLobbyMembers; i++) { CSteamID lobbyMemberByIndex = SteamMatchmaking.GetLobbyMemberByIndex(val, i); string friendPersonaName = SteamFriends.GetFriendPersonaName(lobbyMemberByIndex); if (!dictionary.ContainsKey(friendPersonaName)) { dictionary[friendPersonaName] = new List<CSteamID>(); } dictionary[friendPersonaName].Add(lobbyMemberByIndex); list.Add(lobbyMemberByIndex); } Player[] playerList; if (dictionary.ContainsKey(player.NickName)) { List<CSteamID> list2 = dictionary[player.NickName]; Logger.LogInfo((object)string.Format("[GetPlayerSteamID] Found {0} Steam players with name '{1}': {2}", list2.Count, player.NickName, string.Join(", ", list2))); List<Player> list3 = new List<Player>(); playerList = PhotonNetwork.PlayerList; foreach (Player val2 in playerList) { if (val2.NickName == player.NickName) { list3.Add(val2); } } if (list2.Count == 1 && list3.Count == 1) { Logger.LogInfo((object)$"[GetPlayerSteamID] Unique match found: {player.NickName} -> {list2[0]}"); return list2[0]; } if (list2.Count > 1) { HashSet<CSteamID> hashSet = new HashSet<CSteamID>(); playerList = PhotonNetwork.PlayerList; foreach (Player val3 in playerList) { if (val3.ActorNumber != player.ActorNumber) { CSteamID playerSteamID = GetPlayerSteamID(val3); if (playerSteamID != CSteamID.Nil) { hashSet.Add(playerSteamID); } } } foreach (CSteamID item in list2) { if (!hashSet.Contains(item)) { Logger.LogInfo((object)$"[GetPlayerSteamID] Found unassigned Steam ID for {player.NickName}: {item}"); return item; } } Logger.LogWarning((object)("[GetPlayerSteamID] No unassigned Steam IDs found for " + player.NickName)); } } int num = PhotonNetwork.PlayerList.Length; if (num > numLobbyMembers) { Logger.LogWarning((object)$"[GetPlayerSteamID] More Photon players ({num}) than Steam lobby members ({numLobbyMembers}). Possible spoofer."); return CSteamID.Nil; } HashSet<CSteamID> hashSet2 = new HashSet<CSteamID>(); playerList = PhotonNetwork.PlayerList; foreach (Player val4 in playerList) { if (val4.ActorNumber != player.ActorNumber) { CSteamID playerSteamID2 = GetPlayerSteamID(val4); if (playerSteamID2 != CSteamID.Nil) { hashSet2.Add(playerSteamID2); } } } foreach (CSteamID item2 in list) { if (!hashSet2.Contains(item2)) { Logger.LogInfo((object)$"[GetPlayerSteamID] Found unassigned Steam ID for {player.NickName}: {item2}"); return item2; } } Logger.LogWarning((object)$"[GetPlayerSteamID] No unassigned Steam IDs found. All {numLobbyMembers} lobby members are accounted for."); return CSteamID.Nil; } catch (Exception ex) { Logger.LogError((object)("[GetPlayerSteamID] Error getting Steam ID for " + player.NickName + ": " + ex.Message)); return CSteamID.Nil; } } private static void ParseWhitelist() { string value = WhitelistedSteamIDs.Value; if (string.IsNullOrWhiteSpace(value)) { return; } string[] array = value.Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (ulong.TryParse(text, out var result)) { BlockingManager.AddToWhitelist(result); Logger.LogInfo((object)$"[WHITELIST] Added Steam ID to whitelist: {result}"); } else if (!string.IsNullOrEmpty(text)) { Logger.LogWarning((object)("[WHITELIST] Invalid Steam ID format: " + text)); } } } [IteratorStateMachine(typeof(<CheckPlayersForCheats>d__85))] private IEnumerator CheckPlayersForCheats() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <CheckPlayersForCheats>d__85(0) { <>4__this = this }; } private void CheckPlayerForCheatMods(Player player) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0297: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_0322: Unknown result type (might be due to invalid IL or missing references) //IL_0328: Unknown result type (might be due to invalid IL or missing references) if (player.ActorNumber == PhotonNetwork.LocalPlayer.ActorNumber) { return; } if (!_knownPlayerIdentities.Exists((PlayerIdentity p) => p.ActorNumber == player.ActorNumber)) { CSteamID playerSteamID = GetPlayerSteamID(player); Logger.LogInfo((object)$"[Identity Log] Joined: PhotonName={player.NickName} | ActorNumber={player.ActorNumber} | SteamName={SteamFriends.GetFriendPersonaName(playerSteamID)} | SteamID={playerSteamID}"); _knownPlayerIdentities.Add(new PlayerIdentity(player.NickName, player.ActorNumber, playerSteamID)); } if (!player.IsMasterClient && !_detectedCheatModUsers.Contains(player.ActorNumber)) { if (BlockingManager.HasImmunity(player.ActorNumber)) { Logger.LogInfo((object)("[CHEAT MOD CHECK] Skipping " + player.NickName + " - player has immunity")); } else if (((Dictionary<object, object>)(object)player.CustomProperties).ContainsKey((object)"CherryUser")) { Logger.LogWarning((object)(player.NickName + " is using the Cherry cheat mod!")); LogVisually("{userColor}" + player.NickName + "</color> {leftColor}is using the Cherry cheat mod!</color>", onlySendOnce: true, sfxJoin: false, sfxLeave: true); DetectionManager.RecordDetection(DetectionType.CherryMod, player, "Cherry cheat mod user"); _detectedCheatModUsers.Add(player.ActorNumber); } else if (((Dictionary<object, object>)(object)player.CustomProperties).ContainsKey((object)"CherryOwner")) { Logger.LogWarning((object)(player.NickName + " is the Owner of the Cherry cheat mod!")); LogVisually("{userColor}" + player.NickName + "</color> {leftColor}is the Owner of the Cherry cheat mod!</color>", onlySendOnce: true, sfxJoin: false, sfxLeave: true); DetectionManager.RecordDetection(DetectionType.CherryMod, player, "Cherry cheat mod owner"); _detectedCheatModUsers.Add(player.ActorNumber); } else if (((Dictionary<object, object>)(object)player.CustomProperties).ContainsKey((object)"AtlUser")) { Logger.LogWarning((object)(player.NickName + " is using the Atlas cheat mod!")); LogVisually("{userColor}" + player.NickName + "</color> {leftColor}is using the Atlas cheat mod!</color>", onlySendOnce: true, sfxJoin: false, sfxLeave: true); DetectionManager.RecordDetection(DetectionType.AtlasMod, player, "Atlas cheat mod user"); _detectedCheatModUsers.Add(player.ActorNumber); } else if (((Dictionary<object, object>)(object)player.CustomProperties).ContainsKey((object)"AtlOwner")) { Logger.LogWarning((object)(player.NickName + " is the Owner of the Atlas cheat mod!")); LogVisually("{userColor}" + player.NickName + "</color> {leftColor}is the Owner of the Atlas cheat mod!</color>", onlySendOnce: true, sfxJoin: false, sfxLeave: true); DetectionManager.RecordDetection(DetectionType.AtlasMod, player, "Atlas cheat mod owner"); _detectedCheatModUsers.Add(player.ActorNumber); } else if (CheckSteamNames.Value) { CheckSteamNameMatch(player); } } } private void CheckSteamNameMatch(Player player) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) PlayerIdentity playerIdentity = _knownPlayerIdentities.Find((PlayerIdentity p) => p.ActorNumber == player.ActorNumber); if (playerIdentity == null || !(playerIdentity.SteamID != CSteamID.Nil)) { return; } CheckForSteamIDSpoofing(player, playerIdentity.SteamID); if (SteamFriends.RequestUserInformation(playerIdentity.SteamID, true)) { ((MonoBehaviour)this).StartCoroutine(WaitForPersonaStateChange(player, playerIdentity.SteamID, 5f, blockOnMismatch: false)); return; } string friendPersonaName = SteamFriends.GetFriendPersonaName(playerIdentity.SteamID); if (!(friendPersonaName.ToLower() == player.NickName.ToLower())) { Logger.LogWarning((object)("Name mismatch detected on join: Photon='" + player.NickName + "' vs Steam='" + friendPersonaName + "'")); LogVisually("{userColor}" + player.NickName + "</color> {leftColor}has mismatched Steam name: '" + friendPersonaName + "'</color>", onlySendOnce: true, sfxJoin: false, sfxLeave: true); DetectionManager.RecordDetection(DetectionType.SteamNameMismatch, player, "Name mismatch: Photon='" + player.NickName + "' vs Steam='" + friendPersonaName + "'"); } } private void CheckForSteamIDSpoofing(Player player, CSteamID playerSteamID) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) if (!PhotonNetwork.IsMasterClient || player.IsMasterClient) { return; } CSteamID steamID = SteamUser.GetSteamID(); if (playerSteamID == steamID) { Logger.LogError((object)("[STEAM ID SPOOFING DETECTED] " + player.NickName + " is spoofing the master client's Steam ID!")); LogVisually("{userColor}" + player.NickName + "</color> {leftColor}is spoofing the master client's Steam ID!</color>", onlySendOnce: false, sfxJoin: false, sfxLeave: true); bool num = DetectionManager.ShouldAutoBlock(DetectionType.SteamIDSpoofing); if (DetectionManager.ShouldShowVisualWarning(DetectionType.SteamIDSpoofing)) { LogVisually("{userColor}" + player.NickName + "</color> {leftColor}is spoofing the master client's Steam ID!</color>", onlySendOnce: false, sfxJoin: false, sfxLeave: true); } if (num) { BlockPlayer(player, "Steam ID spoofing - pretending to be master client", DetectionType.SteamIDSpoofing); } DetectionManager.RecordDetection(DetectionType.SteamIDSpoofing, player, "Spoofed master client's Steam ID"); } } [IteratorStateMachine(typeof(<WaitForPersonaStateChange>d__89))] private IEnumerator WaitForPersonaStateChange(Player player, CSteamID steamId, float timeout, bool blockOnMismatch = true) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <WaitForPersonaStateChange>d__89(0) { player = player, steamId = steamId, timeout = timeout, blockOnMismatch = blockOnMismatch }; } public void OnMasterClientSwitched(Player newMasterClient) { //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: Expected O, but got Unknown //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) Logger.LogInfo((object)$"{newMasterClient.NickName} (#{newMasterClient.ActorNumber}) is the new master client!"); _lastMasterClientChange = DateTime.Now; Logger.LogInfo((object)$"[MASTER CLIENT] Master client change recorded - kicks disabled for {30f} seconds"); PlayerManager.HandleMasterClientSwitch(newMasterClient); bool flag = false; if (newMasterClient.ActorNumber == PhotonNetwork.LocalPlayer.ActorNumber) { Logger.LogInfo((object)"[MASTER CLIENT] Local player became master client - legitimate switch"); flag = true; CreateUI(); ((MonoBehaviour)this).StartCoroutine(SendSyncToAllClients()); } else { SteamLobbyHandler service = GameHandler.GetService<SteamLobbyHandler>(); CSteamID val = default(CSteamID); if (service != null && service.InSteamLobby(ref val)) { CSteamID lobbyOwner = SteamMatchmaking.GetLobbyOwner(val); bool flag2 = false; Player[] playerList = PhotonNetwork.PlayerList; for (int i = 0; i < playerList.Length; i++) { if (GetPlayerSteamID(playerList[i]) == lobbyOwner) { flag2 = true; break; } } if (flag2) { Logger.LogError((object)("[MASTER CLIENT THEFT DETECTED] " + newMasterClient.NickName + " stole master client while original master is still in room!")); LogVisually("{userColor}" + newMasterClient.NickName + "</color> {leftColor}stole master client while original master is still here!</color>", onlySendOnce: false, sfxJoin: false, sfxLeave: true); bool num = DetectionManager.ShouldAutoBlock(DetectionType.MasterClientTheft); if (DetectionManager.ShouldShowVisualWarning(DetectionType.MasterClientTheft)) { LogVisually("{userColor}" + newMasterClient.NickName + "</color> {leftColor}stole master client while original master is still here!</color>", onlySendOnce: false, sfxJoin: false, sfxLeave: true); } if (num) { BlockPlayer(newMasterClient, "Master client theft - original master still in room", DetectionType.MasterClientTheft); } DetectionManager.RecordDetection(DetectionType.MasterClientTheft, newMasterClient, "Stole master client while original master still present"); if (lobbyOwner == SteamUser.GetSteamID()) { Logger.LogInfo((object)"[MASTER CLIENT] Taking master client back from thief"); PhotonNetwork.SetMasterClient(PhotonNetwork.LocalPlayer); GameObject val2 = GameObject.Find("AntiCheatUI"); if ((Object)(object)val2 != (Object)null) { AntiCheatUI component = val2.GetComponent<AntiCheatUI>(); if ((Object)(object)component != (Object)null) { component.OnMasterClientRecovered(); } } } } else { Logger.LogInfo((object)"[MASTER CLIENT] Original master left - likely legitimate switch"); flag = true; } } else if (_anticheatUsers.ContainsKey(newMasterClient.ActorNumber)) { Logger.LogInfo((object)("[MASTER CLIENT] New master client " + newMasterClient.NickName + " has anticheat - likely legitimate switch")); flag = true; } else { Logger.LogWarning((object)("[MASTER CLIENT] New master client " + newMasterClient.NickName + " does not have anticheat - potential theft")); LogVisually("{userColor}" + newMasterClient.NickName + "</color> {leftColor}became master client without anticheat!</color>", onlySendOnce: false, sfxJoin: false, sfxLeave: true); DetectionManager.RecordDetection(DetectionType.MasterClientTheft, newMasterClient, "Became master client without anticheat"); } } if (flag && _anticheatUsers.ContainsKey(newMasterClient.ActorNumber)) { Logger.LogInfo((object)("[MASTER CLIENT] Syncing with new master client " + newMasterClient.NickName)); if (!PhotonNetwork.IsMasterClient) { PhotonNetwork.RaiseEvent((byte)104, (object)null, new RaiseEventOptions { Receivers = (ReceiverGroup)2 }, SendOptions.SendReliable); } } } [IteratorStateMachine(typeof(<SendSyncToAllClients>d__91))] private IEnumerator