Decompiled source of PEAKAntiCheat v1.4.7
PEAKAntiCheat.dll
Decompiled 5 months 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