The BepInEx console will not appear when launching like it does for other games on Thunderstore. This is normal (and helps prevent crashes during startup). You can turn it back on in your BepInEx.cfg file.
Decompiled source of PEAKAntiCheat v1.3.6
PEAKAntiCheat.dll
Decompiled 3 hours 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.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using BepInEx; 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.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [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")] public static class AntiCheatEvents { public static event Action<Player, string, CSteamID, string> OnCheaterDetected; public static void NotifyCheaterDetected(Player player, string reason, CSteamID steamID) { //IL_0021: 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); } } namespace AntiCheatMod; public static class ConfigFileExtensions { public static bool ContainsKey(this ConfigFile config, ConfigDefinition key) { try { PropertyInfo property = ((object)config).GetType().GetProperty("Entries", BindingFlags.Instance | BindingFlags.NonPublic); if (property != null && property.GetValue(config) is IDictionary dictionary) { return dictionary.Contains(key); } ConfigEntry<string> val = config.Bind<string>(key.Section, key.Key, "TEST_DEFAULT", (ConfigDescription)null); bool result = val.Value != "TEST_DEFAULT"; config.Remove(key); return result; } catch { return false; } } } [BepInPlugin("com.hiccup444.anticheat", "PEAK Anticheat", "1.3.6")] public class AntiCheatPlugin : BaseUnityPlugin, IConnectionCallbacks, IMatchmakingCallbacks, IInRoomCallbacks, IOnEventCallback { [CompilerGenerated] private sealed class <>c__DisplayClass46_0 { public CSteamID steamId; public bool receivedUpdate; internal void <WaitForPersonaStateChange>b__0(PersonaStateChange_t param) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0019: 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_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Invalid comparison between Unknown and I4 //IL_003b: 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__71 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public AntiCheatPlugin <>4__this; private Player[] <>s__1; private int <>s__2; private Player <player>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <CheckAllPlayersOnJoin>d__71(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>s__1 = null; <player>5__3 = null; <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: 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; <>s__1 = PhotonNetwork.PlayerList; for (<>s__2 = 0; <>s__2 < <>s__1.Length; <>s__2++) { <player>5__3 = <>s__1[<>s__2]; if (<player>5__3.ActorNumber != PhotonNetwork.LocalPlayer.ActorNumber) { <>4__this.CheckPlayerForCheatMods(<player>5__3); } <player>5__3 = null; } <>s__1 = null; 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__61 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Player player; public AntiCheatPlugin <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <CheckNewPlayerDelayed>d__61(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: 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; <>4__this.CheckPlayerForCheatMods(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__37 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public AntiCheatPlugin <>4__this; private Player[] <>s__1; private int <>s__2; private Player <player>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <CheckPlayersForCheats>d__37(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>s__1 = null; <player>5__3 = null; <>1__state = -2; } private bool MoveNext() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; if (PhotonNetwork.InRoom) { <>s__1 = PhotonNetwork.PlayerList; for (<>s__2 = 0; <>s__2 < <>s__1.Length; <>s__2++) { <player>5__3 = <>s__1[<>s__2]; <>4__this.CheckPlayerForCheatMods(<player>5__3); <player>5__3 = null; } <>s__1 = null; } break; } <>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 <DelayedNameCheck>d__45 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Player player; public float delay; public AntiCheatPlugin <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <DelayedNameCheck>d__45(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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; if (PhotonNetwork.CurrentRoom != null && PhotonNetwork.CurrentRoom.GetPlayer(player.ActorNumber, false) != null && !_detectedPlayers.Contains(player.ActorNumber) && !_nameWarningShown.Contains(player.ActorNumber)) { Logger.LogInfo((object)("Performing delayed name check for " + player.NickName)); <>4__this.CheckSteamNameMatch(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 <SendAntiCheatPingDelayed>d__68 : 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__68(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown 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; <>4__this.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 <SendAntiCheatPingResponse>d__74 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Player targetPlayer; public AntiCheatPlugin <>4__this; private object[] <pingData>5__1; private RaiseEventOptions <opts>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SendAntiCheatPingResponse>d__74(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <pingData>5__1 = null; <opts>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Expected O, but got Unknown //IL_00e1: 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(0.5f); <>1__state = 1; return true; case 1: { <>1__state = -1; if (!PhotonNetwork.IsConnected || !PhotonNetwork.InRoom) { return false; } Room currentRoom = PhotonNetwork.CurrentRoom; if (((currentRoom != null) ? currentRoom.GetPlayer(targetPlayer.ActorNumber, false) : null) == null) { return false; } <pingData>5__1 = new object[3] { PhotonNetwork.LocalPlayer.NickName, PhotonNetwork.LocalPlayer.UserId, "1.3.6" }; RaiseEventOptions val = new RaiseEventOptions(); val.TargetActors = new int[1] { targetPlayer.ActorNumber }; <opts>5__2 = val; PhotonNetwork.RaiseEvent((byte)69, (object)<pingData>5__1, <opts>5__2, SendOptions.SendReliable); Logger.LogInfo((object)("[AntiCheat] Sent anticheat ping response to " + targetPlayer.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__62 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Player newPlayer; public AntiCheatPlugin <>4__this; private object[] <pingData>5__1; private RaiseEventOptions <opts>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SendAntiCheatPingToNewPlayer>d__62(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <pingData>5__1 = null; <opts>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown //IL_00e8: 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.IsConnected || !PhotonNetwork.InRoom || PhotonNetwork.LocalPlayer == null) { return false; } Room currentRoom = PhotonNetwork.CurrentRoom; if (((currentRoom != null) ? currentRoom.GetPlayer(newPlayer.ActorNumber, false) : null) == null) { return false; } <pingData>5__1 = new object[3] { PhotonNetwork.LocalPlayer.NickName, PhotonNetwork.LocalPlayer.UserId, "1.3.6" }; RaiseEventOptions val = new RaiseEventOptions(); val.TargetActors = new int[1] { newPlayer.ActorNumber }; <opts>5__2 = val; PhotonNetwork.RaiseEvent((byte)69, (object)<pingData>5__1, <opts>5__2, SendOptions.SendReliable); Logger.LogInfo((object)("[AntiCheat] Sent anticheat ping to new player " + newPlayer.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 <TrackPlayerItems>d__63 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public AntiCheatPlugin <>4__this; private Character[] <allCharacters>5__1; private Character[] <>s__2; private int <>s__3; private Character <character>5__4; private PhotonView <photonView>5__5; private CharacterData <characterData>5__6; private bool <canBeCooked>5__7; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <TrackPlayerItems>d__63(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <allCharacters>5__1 = null; <>s__2 = null; <character>5__4 = null; <photonView>5__5 = null; <characterData>5__6 = null; <>1__state = -2; } private bool MoveNext() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; if (!PhotonNetwork.InRoom) { break; } <allCharacters>5__1 = Object.FindObjectsOfType<Character>(); <>s__2 = <allCharacters>5__1; for (<>s__3 = 0; <>s__3 < <>s__2.Length; <>s__3++) { <character>5__4 = <>s__2[<>s__3]; <photonView>5__5 = ((Component)<character>5__4).GetComponent<PhotonView>(); if (!((Object)(object)<photonView>5__5 == (Object)null) && <photonView>5__5.Owner != null && !IsBlocked(<photonView>5__5.Owner.ActorNumber)) { <characterData>5__6 = ((Component)<character>5__4).GetComponent<CharacterData>(); if ((Object)(object)<characterData>5__6 != (Object)null && (Object)(object)<characterData>5__6.currentItem != (Object)null) { <canBeCooked>5__7 = (Object)(object)<characterData>5__6.currentItem.cooking != (Object)null && <characterData>5__6.currentItem.cooking.canBeCooked; UpdatePlayerHeldItem(<photonView>5__5.Owner.ActorNumber, ((Object)<characterData>5__6.currentItem).name, <canBeCooked>5__7); } <photonView>5__5 = null; <characterData>5__6 = null; <character>5__4 = null; } } <>s__2 = null; <allCharacters>5__1 = null; break; } <>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__46 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Player player; public CSteamID steamId; public float timeout; public bool blockOnMismatch; public AntiCheatPlugin <>4__this; private <>c__DisplayClass46_0 <>8__1; private float <startTime>5__2; private string <lastKnownSteamName>5__3; private Callback<PersonaStateChange_t> <personaCallback>5__4; private string <freshSteamName>5__5; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <WaitForPersonaStateChange>d__46(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>8__1 = null; <lastKnownSteamName>5__3 = null; <personaCallback>5__4 = null; <freshSteamName>5__5 = null; <>1__state = -2; } private bool MoveNext() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown //IL_015b: 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__DisplayClass46_0(); <>8__1.steamId = steamId; <startTime>5__2 = Time.time; <lastKnownSteamName>5__3 = SteamFriends.GetFriendPersonaName(<>8__1.steamId); <>8__1.receivedUpdate = false; <personaCallback>5__4 = null; <personaCallback>5__4 = Callback<PersonaStateChange_t>.Create((DispatchDelegate<PersonaStateChange_t>)delegate(PersonaStateChange_t param) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0019: 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_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Invalid comparison between Unknown and I4 //IL_003b: 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__4?.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__4?.Dispose(); <freshSteamName>5__5 = SteamFriends.GetFriendPersonaName(<>8__1.steamId); if (<freshSteamName>5__5.ToLower() != player.NickName.ToLower()) { if (blockOnMismatch) { Logger.LogWarning((object)("Name mismatch confirmed after PersonaStateChange: Photon='" + player.NickName + "' vs Steam='" + <freshSteamName>5__5 + "'")); LogVisually("{userColor}" + player.NickName + "</color> {leftColor}confirmed spoofing - real Steam name is '" + <freshSteamName>5__5 + "'!</color>", onlySendOnce: true, sfxJoin: false, sfxLeave: true); if (PhotonNetwork.CurrentRoom != null && PhotonNetwork.CurrentRoom.GetPlayer(player.ActorNumber, false) != null) { BlockPlayer(player, "Name spoofing confirmed - real name: " + <freshSteamName>5__5); } } else if (!_nameWarningShown.Contains(player.ActorNumber)) { Logger.LogWarning((object)("Name mismatch on join after refresh: Photon='" + player.NickName + "' vs Steam='" + <freshSteamName>5__5 + "'")); LogVisually("{userColor}" + player.NickName + "</color> {leftColor}has mismatched Steam name: '" + <freshSteamName>5__5 + "'</color>", onlySendOnce: true, sfxJoin: false, sfxLeave: true); _nameWarningShown.Add(player.ActorNumber); } } 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; private static AntiCheatPlugin Instance; private static ConfigFile Config; private static readonly Dictionary<int, (string itemName, DateTime timestamp, bool wasCookable)> _playerLastHeldItems = new Dictionary<int, (string, DateTime, bool)>(); private const string PLUGIN_VERSION = "1.3.6"; private const byte ANTICHEAT_PING_EVENT = 69; private static readonly HashSet<int> _blockedPlayers = new HashSet<int>(); private static readonly HashSet<int> _detectedPlayers = new HashSet<int>(); private static readonly HashSet<ulong> _whitelistedSteamIDs = new HashSet<ulong>(); private static readonly Dictionary<int, string> _anticheatUsers = new Dictionary<int, string>(); private static readonly HashSet<int> _nameWarningShown = new HashSet<int>(); 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; 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 readonly Dictionary<int, DateTime> _recentlySpawnedPlayers = new Dictionary<int, DateTime>(); private const double SPAWN_GRACE_PERIOD_SECONDS = 5.0; public static bool IsBlocked(int actorNumber) { return _blockedPlayers.Contains(actorNumber); } private void Awake() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Expected O, but got Unknown Instance = this; Logger = ((BaseUnityPlugin)this).Logger; Config = new ConfigFile(Path.Combine(Paths.ConfigPath, "com.hiccup444.PEAKanticheat.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"); bool flag = true; ConfigDefinition val = new ConfigDefinition("General", "AutoPunishCheaters"); if (Config.ContainsKey(val)) { ConfigEntry<bool> val2 = Config.Bind<bool>("General", "AutoPunishCheaters", true, "DEPRECATED - Use AutoBlockCheaters instead"); flag = val2.Value; Config.Remove(val); Logger.LogInfo((object)$"[CONFIG MIGRATION] Migrated AutoPunishCheaters ({flag}) to AutoBlockCheaters"); } AutoBlockCheaters = Config.Bind<bool>("General", "AutoBlockCheaters", flag, "Automatically block all RPCs from detected cheaters (replaces AutoPunishCheaters)"); 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')"); ParseWhitelist(); Config.Save(); Logger.LogInfo((object)"[PEAKAntiCheat] Protection active! (RPC Blocking Mode)"); if (_whitelistedSteamIDs.Count > 0) { Logger.LogInfo((object)$"[PEAKAntiCheat] Loaded {_whitelistedSteamIDs.Count} whitelisted Steam IDs"); } Harmony val3 = new Harmony("com.hiccup444.PEAKanticheat"); val3.PatchAll(); PhotonNetwork.AddCallbackTarget((object)this); ((MonoBehaviour)this).StartCoroutine(CheckPlayersForCheats()); ((MonoBehaviour)this).StartCoroutine(TrackPlayerItems()); SceneManager.sceneLoaded += OnSceneLoaded; } private void Update() { while (_queuedLogs.Count != 0) { (string, bool, bool, bool) tuple = _queuedLogs.Peek(); if (!LogVisually(tuple.Item1, tuple.Item2, tuple.Item3, tuple.Item4)) { break; } _queuedLogs.Dequeue(); } } private void OnDestroy() { PhotonNetwork.RemoveCallbackTarget((object)this); SceneManager.sceneLoaded -= OnSceneLoaded; } private static void ParseWhitelist() { _whitelistedSteamIDs.Clear(); string value = WhitelistedSteamIDs.Value; if (string.IsNullOrWhiteSpace(value)) { return; } string[] array = value.Split(new char[1] { ',' }); string[] array2 = array; foreach (string text in array2) { string text2 = text.Trim(); if (ulong.TryParse(text2, out var result)) { _whitelistedSteamIDs.Add(result); Logger.LogInfo((object)$"[WHITELIST] Added Steam ID to whitelist: {result}"); } else if (!string.IsNullOrEmpty(text2)) { Logger.LogWarning((object)("[WHITELIST] Invalid Steam ID format: " + text2)); } } } 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) { Logger.LogInfo((object)$"[PlayerHadItem] Checking actor {actorNumber} for item containing '{itemNamePart}' within {withinSeconds} seconds (cookable check: {checkCookable})"); if (_playerLastHeldItems.TryGetValue(actorNumber, out (string, DateTime, bool) value)) { double totalSeconds = (DateTime.Now - value.Item2).TotalSeconds; Logger.LogInfo((object)$"[PlayerHadItem] Found item: {value.Item1}, held {totalSeconds:F2} seconds ago"); if (totalSeconds <= (double)withinSeconds) { if (checkCookable) { Logger.LogInfo((object)$"[PlayerHadItem] Within time window. Was cookable? {value.Item3}"); return value.Item3; } bool flag = value.Item1.Contains(itemNamePart.ToLower()); Logger.LogInfo((object)$"[PlayerHadItem] Within time window. Contains '{itemNamePart}'? {flag}"); return flag; } Logger.LogInfo((object)$"[PlayerHadItem] Outside time window ({totalSeconds:F2} > {withinSeconds})"); } else { Logger.LogInfo((object)$"[PlayerHadItem] No item history found for actor {actorNumber}"); } return false; } public static bool PlayerHadCookableItem(int actorNumber, float withinSeconds = 2f) { return PlayerHadItem(actorNumber, "", withinSeconds, checkCookable: true); } public static bool LogVisually(string message, bool onlySendOnce = false, bool sfxJoin = false, bool sfxLeave = false) { //IL_0399: Unknown result type (might be due to invalid IL or missing references) //IL_0413: Unknown result type (might be due to invalid IL or missing references) if (!ShowVisualLogs.Value) { return true; } if (!Object.op_Implicit((Object)(object)_connectionLog)) { _connectionLog = Object.FindObjectOfType<PlayerConnectionLog>(); if (Object.op_Implicit((Object)(object)_connectionLog)) { 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); if (_getColorTagMethod == null) { Logger.LogWarning((object)"GetColorTag method not found!"); } if (_addMessageMethod == null) { Logger.LogWarning((object)"AddMessage method not found!"); } if (_currentLogField == null) { Logger.LogWarning((object)"currentLog field not found!"); } } } if (!Object.op_Implicit((Object)(object)_connectionLog) || _getColorTagMethod == null || _addMessageMethod == null) { _queuedLogs.Enqueue((message, onlySendOnce, sfxJoin, sfxLeave)); return false; } try { StringBuilder stringBuilder = new StringBuilder(message); FieldInfo field = ((object)_connectionLog).GetType().GetField("joinedColor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo field2 = ((object)_connectionLog).GetType().GetField("leftColor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo field3 = ((object)_connectionLog).GetType().GetField("userColor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && field2 != null && field3 != null) { object value = field.GetValue(_connectionLog); object value2 = field2.GetValue(_connectionLog); object value3 = field3.GetValue(_connectionLog); string text = (string)_getColorTagMethod.Invoke(_connectionLog, new object[1] { value }); string text2 = (string)_getColorTagMethod.Invoke(_connectionLog, new object[1] { value2 }); string 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; } } _addMessageMethod.Invoke(_connectionLog, new object[1] { message }); FieldInfo field4 = ((object)_connectionLog).GetType().GetField("sfxJoin", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo field5 = ((object)_connectionLog).GetType().GetField("sfxLeave", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (sfxJoin && field4 != null) { object value4 = field4.GetValue(_connectionLog); value4?.GetType().GetMethod("Play", new Type[1] { typeof(Vector3) })?.Invoke(value4, new object[1] { Vector3.zero }); } if (sfxLeave && field5 != null) { object value5 = field5.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 BlockPlayer(Player cheater, string reason) { //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) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01db: 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_026e: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_025b: 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"); } else if (cheater.IsMasterClient) { Logger.LogWarning((object)("[BLOCK PREVENTED] Attempted to block master client " + cheater.NickName + " for: " + reason)); } else { if (_detectedPlayers.Contains(cheater.ActorNumber)) { return; } Logger.LogWarning((object)("CHEATER DETECTED: " + cheater.NickName + " - Reason: " + reason)); _detectedPlayers.Add(cheater.ActorNumber); CSteamID nil = CSteamID.Nil; PlayerIdentity playerIdentity = _knownPlayerIdentities.Find((PlayerIdentity p) => p.ActorNumber == cheater.ActorNumber); if (playerIdentity != null) { nil = playerIdentity.SteamID; Logger.LogWarning((object)$"[Detection] Found identity for Actor #{cheater.ActorNumber}: PhotonName={playerIdentity.PhotonName}, SteamID={nil}"); if (nil == CSteamID.Nil) { Logger.LogWarning((object)("[Detection] WARNING: Stored SteamID is NIL for " + playerIdentity.PhotonName + ".")); } } else { Logger.LogWarning((object)$"[Detection] No identity found for Actor #{cheater.ActorNumber}, attempting fallback SteamID lookup..."); nil = GetPlayerSteamID(cheater); if (nil == CSteamID.Nil) { Logger.LogWarning((object)("[Detection] Fallback GetPlayerSteamID() returned NIL for " + cheater.NickName + ".")); } } if (nil != CSteamID.Nil && _whitelistedSteamIDs.Contains(nil.m_SteamID)) { Logger.LogInfo((object)$"[WHITELIST] Player {cheater.NickName} (Steam ID: {nil}) is whitelisted - not blocking"); LogVisually("{userColor}" + cheater.NickName + "</color> {joinedColor}is whitelisted - no action taken</color>"); AntiCheatEvents.NotifyCheaterDetected(cheater, reason + " (WHITELISTED)", nil); return; } AntiCheatEvents.NotifyCheaterDetected(cheater, reason, nil); if (!AutoBlockCheaters.Value) { Logger.LogInfo((object)("Auto-blocking disabled - only logging cheater: " + cheater.NickName)); LogVisually("{userColor}" + cheater.NickName + "</color> {leftColor}detected - " + reason + " (no action taken)</color>", onlySendOnce: false, sfxJoin: false, sfxLeave: true); } else if (!_blockedPlayers.Contains(cheater.ActorNumber)) { _blockedPlayers.Add(cheater.ActorNumber); LogVisually("{userColor}" + cheater.NickName + "</color> {leftColor}RPC blocked - " + reason + "</color>", onlySendOnce: false, sfxJoin: false, sfxLeave: true); Logger.LogInfo((object)$"All RPCs from {cheater.NickName} (Actor #{cheater.ActorNumber}) are now blocked"); } } } public static void SoftLockPlayer(Player cheater, string reason) { BlockPlayer(cheater, reason); } public static bool IsSoftLocked(int actorNumber) { return IsBlocked(actorNumber); } public static void AddToBlockList(int actorNumber) { if (!_blockedPlayers.Contains(actorNumber)) { _blockedPlayers.Add(actorNumber); Logger.LogInfo((object)$"Added actor #{actorNumber} to RPC block list"); } } public static void AddToSoftLockList(int actorNumber) { AddToBlockList(actorNumber); } private static CSteamID GetPlayerSteamID(Player player) { //IL_0549: Unknown result type (might be due to invalid IL or missing references) //IL_054e: Unknown result type (might be due to invalid IL or missing references) //IL_0552: 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_0035: 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_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: 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_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_03fb: Unknown result type (might be due to invalid IL or missing references) //IL_0400: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_02ba: Unknown result type (might be due to invalid IL or missing references) //IL_0418: Unknown result type (might be due to invalid IL or missing references) //IL_041d: Unknown result type (might be due to invalid IL or missing references) //IL_0511: Unknown result type (might be due to invalid IL or missing references) //IL_0516: Unknown result type (might be due to invalid IL or missing references) //IL_043e: Unknown result type (might be due to invalid IL or missing references) //IL_0443: Unknown result type (might be due to invalid IL or missing references) //IL_0379: Unknown result type (might be due to invalid IL or missing references) //IL_0391: Unknown result type (might be due to invalid IL or missing references) //IL_0396: Unknown result type (might be due to invalid IL or missing references) //IL_0335: Unknown result type (might be due to invalid IL or missing references) //IL_0355: Unknown result type (might be due to invalid IL or missing references) //IL_035a: Unknown result type (might be due to invalid IL or missing references) //IL_0499: Unknown result type (might be due to invalid IL or missing references) //IL_04a3: Unknown result type (might be due to invalid IL or missing references) //IL_04b6: Unknown result type (might be due to invalid IL or missing references) //IL_04d1: Unknown result type (might be due to invalid IL or missing references) //IL_04d3: 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; } Type type = ((object)service).GetType(); FieldInfo field = type.GetField("m_currentLobby", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) { Logger.LogError((object)"[GetPlayerSteamID] Could not find m_currentLobby field via reflection."); return CSteamID.Nil; } CSteamID val = (CSteamID)field.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); Logger.LogInfo((object)$"[GetPlayerSteamID] Found Steam user: Name='{friendPersonaName}', SteamID={lobbyMemberByIndex}"); if (!dictionary.ContainsKey(friendPersonaName)) { dictionary[friendPersonaName] = new List<CSteamID>(); } dictionary[friendPersonaName].Add(lobbyMemberByIndex); list.Add(lobbyMemberByIndex); } 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>(); Player[] playerList = PhotonNetwork.PlayerList; foreach (Player val2 in playerList) { if (val2.NickName == player.NickName) { list3.Add(val2); } } Logger.LogInfo((object)$"[GetPlayerSteamID] Found {list3.Count} Photon players with name '{player.NickName}'."); if (list3.Count > list2.Count) { Logger.LogWarning((object)$"[GetPlayerSteamID] More Photon players ({list3.Count}) than Steam players ({list2.Count}) for name '{player.NickName}'. Returning NIL as it's likely spoofed."); return CSteamID.Nil; } list3.Sort((Player a, Player b) => a.ActorNumber.CompareTo(b.ActorNumber)); int num = list3.FindIndex((Player p) => p.ActorNumber == player.ActorNumber); if (num >= 0 && num < list2.Count) { Logger.LogInfo((object)$"[GetPlayerSteamID] Matched ActorNumber {player.ActorNumber} to SteamID {list2[num]} (index {num})."); return list2[num]; } Logger.LogWarning((object)$"[GetPlayerSteamID] Could not find matching ActorNumber for {player.NickName}. Returning first available SteamID: {list2[0]}"); return list2[0]; } Logger.LogInfo((object)("[GetPlayerSteamID] No exact match for '" + player.NickName + "', checking for unassigned Steam IDs...")); int num2 = PhotonNetwork.PlayerList.Length; if (num2 > numLobbyMembers) { Logger.LogWarning((object)$"[GetPlayerSteamID] More Photon players ({num2}) than Steam lobby members ({numLobbyMembers}). Possible spoofer."); return CSteamID.Nil; } foreach (CSteamID item in list) { bool flag = false; foreach (PlayerIdentity knownPlayerIdentity in _knownPlayerIdentities) { if (knownPlayerIdentity.SteamID == item && knownPlayerIdentity.ActorNumber != player.ActorNumber) { flag = true; break; } } if (!flag) { bool flag2 = SteamFriends.RequestUserInformation(item, true); string friendPersonaName2 = SteamFriends.GetFriendPersonaName(item); Logger.LogWarning((object)$"[GetPlayerSteamID] Found unassigned Steam ID {item} (name: '{friendPersonaName2}', needs refresh: {flag2})"); return item; } } 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] Exception while resolving Steam ID for " + player.NickName + ": " + ex.Message)); return CSteamID.Nil; } } [IteratorStateMachine(typeof(<CheckPlayersForCheats>d__37))] private IEnumerator CheckPlayersForCheats() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <CheckPlayersForCheats>d__37(0) { <>4__this = this }; } private static List<CSteamID> GetSteamIDsForName(string steamName) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) try { SteamLobbyHandler service = GameHandler.GetService<SteamLobbyHandler>(); if (service == null) { return new List<CSteamID>(); } Type type = ((object)service).GetType(); FieldInfo field = type.GetField("m_currentLobby", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) { return new List<CSteamID>(); } CSteamID val = (CSteamID)field.GetValue(service); if (val == CSteamID.Nil) { return new List<CSteamID>(); } int numLobbyMembers = SteamMatchmaking.GetNumLobbyMembers(val); 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 (friendPersonaName == steamName) { list.Add(lobbyMemberByIndex); } } return list; } catch (Exception ex) { Logger.LogError((object)("Error getting SteamIDs for name " + steamName + ": " + ex.Message)); return new List<CSteamID>(); } } 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; } private void CheckPlayerForCheatMods(Player player) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: 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_00b9: 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) if (player.ActorNumber == PhotonNetwork.LocalPlayer.ActorNumber || _detectedPlayers.Contains(player.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)); } List<Player> list = new List<Player>(); Player[] playerList = PhotonNetwork.PlayerList; foreach (Player val in playerList) { if (val.ActorNumber != player.ActorNumber && val.NickName == player.NickName) { list.Add(val); } } if (list.Count > 0) { if (player.NickName.ToLower() == PhotonNetwork.LocalPlayer.NickName.ToLower()) { Logger.LogWarning((object)(player.NickName + " joined with the same name as the local player! This can cause character assignment issues.")); LogVisually("{userColor}" + player.NickName + "</color> {leftColor}joined with your name - possible impersonator!</color>", onlySendOnce: true, sfxJoin: false, sfxLeave: true); BlockPlayer(player, "Name impersonation - using local player's name"); return; } Logger.LogInfo((object)("Duplicate Photon name '" + player.NickName + "' found, but enough matching Steam names exist. Allowing.")); } if (player.IsMasterClient) { Logger.LogInfo((object)("[CHECK SKIPPED] Not checking master client " + player.NickName + " for cheat mods")); } 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); BlockPlayer(player, "Cherry cheat mod user"); } 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); BlockPlayer(player, "Cherry cheat mod owner"); } 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); BlockPlayer(player, "Atlas cheat mod user"); } 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); BlockPlayer(player, "Atlas cheat mod owner"); } else if (CheckSteamNames.Value) { CheckSteamNameMatch(player); } } private void CheckSteamNameMatch(Player player) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: 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_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) if (_nameWarningShown.Contains(player.ActorNumber)) { return; } PlayerIdentity playerIdentity = _knownPlayerIdentities.Find((PlayerIdentity p) => p.ActorNumber == player.ActorNumber); if (playerIdentity != null && playerIdentity.SteamID != CSteamID.Nil) { if (SteamFriends.RequestUserInformation(playerIdentity.SteamID, true)) { Logger.LogInfo((object)$"Requesting fresh Steam data for {player.NickName} (Actor #{player.ActorNumber}, SteamID: {playerIdentity.SteamID})"); ((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); _nameWarningShown.Add(player.ActorNumber); } return; } SteamLobbyHandler service = GameHandler.GetService<SteamLobbyHandler>(); CSteamID val = default(CSteamID); if (service == null || !service.InSteamLobby(ref val)) { return; } int numLobbyMembers = SteamMatchmaking.GetNumLobbyMembers(val); bool flag = false; int num = 0; for (int i = 0; i < numLobbyMembers; i++) { CSteamID lobbyMemberByIndex = SteamMatchmaking.GetLobbyMemberByIndex(val, i); if (SteamFriends.RequestUserInformation(lobbyMemberByIndex, true)) { num++; } string friendPersonaName2 = SteamFriends.GetFriendPersonaName(lobbyMemberByIndex); if (friendPersonaName2 == player.NickName) { flag = true; break; } } if (num > 0 && !flag) { Logger.LogInfo((object)$"{num} Steam members need data refresh. Delaying name check for {player.NickName}"); ((MonoBehaviour)this).StartCoroutine(DelayedNameCheck(player, 3f)); } else if (!flag && !_nameWarningShown.Contains(player.ActorNumber)) { Logger.LogWarning((object)(player.NickName + " has no matching Steam name in lobby!")); LogVisually("{userColor}" + player.NickName + "</color> {leftColor}has no matching Steam name in lobby!</color>", onlySendOnce: true, sfxJoin: false, sfxLeave: true); _nameWarningShown.Add(player.ActorNumber); } } [IteratorStateMachine(typeof(<DelayedNameCheck>d__45))] private IEnumerator DelayedNameCheck(Player player, float delay) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <DelayedNameCheck>d__45(0) { <>4__this = this, player = player, delay = delay }; } [IteratorStateMachine(typeof(<WaitForPersonaStateChange>d__46))] private IEnumerator WaitForPersonaStateChange(Player player, CSteamID steamId, float timeout, bool blockOnMismatch = true) { //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) //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <WaitForPersonaStateChange>d__46(0) { <>4__this = this, player = player, steamId = steamId, timeout = timeout, blockOnMismatch = blockOnMismatch }; } public void OnMasterClientSwitched(Player newMasterClient) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) Logger.LogInfo((object)$"{newMasterClient.NickName} (#{newMasterClient.ActorNumber}) is the new master client!"); if (newMasterClient.ActorNumber == PhotonNetwork.LocalPlayer.ActorNumber || PhotonNetwork.LocalPlayer.IsMasterClient) { return; } SteamLobbyHandler service = GameHandler.GetService<SteamLobbyHandler>(); CSteamID val = default(CSteamID); if (service != null && service.InSteamLobby(ref val) && SteamMatchmaking.GetLobbyOwner(val) == SteamUser.GetSteamID()) { Logger.LogWarning((object)("Master client stolen by: " + newMasterClient.NickName)); LogVisually("{userColor}" + newMasterClient.NickName + "</color> {leftColor}tried to take master client</color>", onlySendOnce: false, sfxJoin: false, sfxLeave: true); BlockPlayer(newMasterClient, "Stole master client"); if (!PhotonNetwork.LocalPlayer.IsMasterClient) { PhotonNetwork.SetMasterClient(PhotonNetwork.LocalPlayer); Logger.LogInfo((object)"Reclaimed master client after blocking cheater"); } } } public void OnConnected() { } public void OnConnectedToMaster() { } public void OnDisconnected(DisconnectCause cause) { } public void OnRegionListReceived(RegionHandler regionHandler) { } public void OnCustomAuthenticationResponse(Dictionary<string, object> data) { } public void OnCustomAuthenticationFailed(string debugMessage) { } public void OnFriendListUpdate(List<FriendInfo> friendList) { } public void OnCreatedRoom() { } public void OnCreateRoomFailed(short returnCode, string message) { } public void OnJoinRoomFailed(short returnCode, string message) { } public void OnJoinRandomFailed(short returnCode, string message) { } public void OnLeftRoom() { _knownPlayerIdentities.Clear(); _blockedPlayers.Clear(); _detectedPlayers.Clear(); _playerLastHeldItems.Clear(); _anticheatUsers.Clear(); _nameWarningShown.Clear(); } public void OnPlayerEnteredRoom(Player newPlayer) { OnPlayerSpawned(newPlayer.ActorNumber); ((MonoBehaviour)this).StartCoroutine(CheckNewPlayerDelayed(newPlayer)); if (newPlayer.ActorNumber != PhotonNetwork.LocalPlayer.ActorNumber) { ((MonoBehaviour)this).StartCoroutine(SendAntiCheatPingToNewPlayer(newPlayer)); } } [IteratorStateMachine(typeof(<CheckNewPlayerDelayed>d__61))] private IEnumerator CheckNewPlayerDelayed(Player player) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <CheckNewPlayerDelayed>d__61(0) { <>4__this = this, player = player }; } [IteratorStateMachine(typeof(<SendAntiCheatPingToNewPlayer>d__62))] private IEnumerator SendAntiCheatPingToNewPlayer(Player newPlayer) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <SendAntiCheatPingToNewPlayer>d__62(0) { <>4__this = this, newPlayer = newPlayer }; } [IteratorStateMachine(typeof(<TrackPlayerItems>d__63))] private IEnumerator TrackPlayerItems() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <TrackPlayerItems>d__63(0) { <>4__this = this }; } public void OnPlayerLeftRoom(Player otherPlayer) { _knownPlayerIdentities.RemoveAll((PlayerIdentity p) => p.ActorNumber == otherPlayer.ActorNumber); _playerLastHeldItems.Remove(otherPlayer.ActorNumber); _recentlySpawnedPlayers.Remove(otherPlayer.ActorNumber); if (_blockedPlayers.Contains(otherPlayer.ActorNumber)) { _blockedPlayers.Remove(otherPlayer.ActorNumber); Logger.LogInfo((object)("Removed " + otherPlayer.NickName + " from RPC block list (disconnected)")); } if (_detectedPlayers.Contains(otherPlayer.ActorNumber)) { _detectedPlayers.Remove(otherPlayer.ActorNumber); Logger.LogInfo((object)("Removed " + otherPlayer.NickName + " from detected list (disconnected)")); } if (_anticheatUsers.ContainsKey(otherPlayer.ActorNumber)) { _anticheatUsers.Remove(otherPlayer.ActorNumber); Logger.LogInfo((object)("Removed " + otherPlayer.NickName + " from anticheat users list (disconnected)")); } if (_nameWarningShown.Contains(otherPlayer.ActorNumber)) { _nameWarningShown.Remove(otherPlayer.ActorNumber); } } public void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps) { //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0158: 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_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) if (!((Dictionary<object, object>)(object)changedProps).ContainsKey((object)"name") && !((Dictionary<object, object>)(object)changedProps).ContainsKey((object)"NickName")) { return; } Logger.LogInfo((object)$"Player {targetPlayer.ActorNumber} changed their name mid-game to {targetPlayer.NickName}"); if (targetPlayer.ActorNumber == PhotonNetwork.LocalPlayer.ActorNumber) { return; } PlayerIdentity playerIdentity = _knownPlayerIdentities.Find((PlayerIdentity p) => p.ActorNumber == targetPlayer.ActorNumber); if (playerIdentity != null && playerIdentity.PhotonName != targetPlayer.NickName) { Logger.LogWarning((object)$"{targetPlayer.ActorNumber} changed their Photon name from {playerIdentity.PhotonName} to {targetPlayer.NickName} - definite spoof attempt"); LogVisually("{userColor}" + targetPlayer.NickName + "</color> {leftColor}changed name mid-game from '" + playerIdentity.PhotonName + "' - spoofing detected!</color>", onlySendOnce: true, sfxJoin: false, sfxLeave: true); BlockPlayer(targetPlayer, "Mid-game name change - spoofing"); return; } CSteamID val = playerIdentity?.SteamID ?? GetPlayerSteamID(targetPlayer); if (val != CSteamID.Nil) { if (SteamFriends.RequestUserInformation(val, true)) { ((MonoBehaviour)this).StartCoroutine(WaitForPersonaStateChange(targetPlayer, val, 5f)); } else { string friendPersonaName = SteamFriends.GetFriendPersonaName(val); if (friendPersonaName.ToLower() != targetPlayer.NickName.ToLower()) { Logger.LogWarning((object)("Mid-game name change doesn't match Steam: Photon='" + targetPlayer.NickName + "' vs Steam='" + friendPersonaName + "'")); LogVisually("{userColor}" + targetPlayer.NickName + "</color> {leftColor}changed name mid-game - doesn't match Steam name '" + friendPersonaName + "'!</color>", onlySendOnce: true, sfxJoin: false, sfxLeave: true); BlockPlayer(targetPlayer, "Mid-game name spoofing - Steam name: " + friendPersonaName); } } } CheckPlayerForCheatMods(targetPlayer); } public void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged) { } public void OnJoinedRoom() { Logger.LogInfo((object)"Joined room - checking all existing players for cheats/spoofing"); OnPlayerSpawned(PhotonNetwork.LocalPlayer.ActorNumber); Logger.LogInfo((object)"Added local player to spawn grace period on room join"); ((MonoBehaviour)this).StartCoroutine(CheckAllPlayersOnJoin()); ((MonoBehaviour)this).StartCoroutine(SendAntiCheatPingDelayed()); } [IteratorStateMachine(typeof(<SendAntiCheatPingDelayed>d__68))] private IEnumerator SendAntiCheatPingDelayed() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <SendAntiCheatPingDelayed>d__68(0) { <>4__this = this }; } private void SendAntiCheatPing() { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown //IL_006b: Unknown result type (might be due to invalid IL or missing references) if (!PhotonNetwork.IsConnected || !PhotonNetwork.InRoom || PhotonNetwork.LocalPlayer == null) { Logger.LogWarning((object)"[AntiCheat] Cannot send ping - not in a room yet"); return; } object[] array = new object[3] { PhotonNetwork.LocalPlayer.NickName, PhotonNetwork.LocalPlayer.UserId, "1.3.6" }; RaiseEventOptions val = new RaiseEventOptions { Receivers = (ReceiverGroup)0 }; PhotonNetwork.RaiseEvent((byte)69, (object)array, val, SendOptions.SendReliable); Logger.LogInfo((object)"[AntiCheat] Sent anticheat detection ping to other players"); } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { if (((Scene)(ref scene)).name.Contains("Level")) { Player[] playerList = PhotonNetwork.PlayerList; foreach (Player val in playerList) { OnPlayerSpawned(val.ActorNumber); } if (PhotonNetwork.InRoom && PhotonNetwork.LocalPlayer != null) { OnPlayerSpawned(PhotonNetwork.LocalPlayer.ActorNumber); } Logger.LogInfo((object)("Entered game scene '" + ((Scene)(ref scene)).name + "' - granting spawn grace period to all players including local")); } } [IteratorStateMachine(typeof(<CheckAllPlayersOnJoin>d__71))] private IEnumerator CheckAllPlayersOnJoin() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <CheckAllPlayersOnJoin>d__71(0) { <>4__this = this }; } public void OnEvent(EventData photonEvent) { if (photonEvent.Code == 69) { HandleAntiCheatPing(photonEvent); } } private void HandleAntiCheatPing(EventData eventData) { if (!(eventData.CustomData is object[] array) || array.Length < 3) { return; } string text = array[0] as string; string text2 = array[1] as string; string text3 = array[2] as string; if (text == null || text3 == null) { return; } Player val = null; Player[] playerList = PhotonNetwork.PlayerList; foreach (Player val2 in playerList) { if (val2.NickName == text && val2.ActorNumber == eventData.Sender) { val = val2; break; } } if (val == null) { Logger.LogWarning((object)("[AntiCheat] Received ping from unknown player: " + text)); } else if (!_anticheatUsers.ContainsKey(val.ActorNumber)) { _anticheatUsers[val.ActorNumber] = text3; Logger.LogInfo((object)("[AntiCheat] " + val.NickName + " has PEAK Anticheat v" + text3)); LogVisually("{joinedColor}" + val.NickName + " has PEAK Anticheat v" + text3 + "</color>", onlySendOnce: true, sfxJoin: true); if (val.ActorNumber != PhotonNetwork.LocalPlayer.ActorNumber) { ((MonoBehaviour)this).StartCoroutine(SendAntiCheatPingResponse(val)); } } } [IteratorStateMachine(typeof(<SendAntiCheatPingResponse>d__74))] private IEnumerator SendAntiCheatPingResponse(Player targetPlayer) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <SendAntiCheatPingResponse>d__74(0) { <>4__this = this, targetPlayer = targetPlayer }; } } public class PlayerIdentity { public string PhotonName; public int ActorNumber; public CSteamID SteamID; public PlayerIdentity(string photonName, int actorNumber, CSteamID steamID) { //IL_0017: 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) PhotonName = photonName; ActorNumber = actorNumber; SteamID = steamID; } } [HarmonyPatch] public static class RPCDetection { public enum OwnershipCondition { IsMasterClient, IsViewOwner, IsMasterClientOrViewOwner } public class RPCPattern { public string MethodId { get; set; } public string Description { get; set; } public Func<object[], bool> ParameterCheck { get; set; } public bool RequiresMasterClient { get; set; } } private static Dictionary<int, DateTime> _lastOwnershipRequest = new Dictionary<int, DateTime>(); private static Dictionary<int, int> _ownershipRequestCount = new Dictionary<int, int>(); private static readonly byte keyByte0 = 0; private static Dictionary<int, Dictionary<int, int>> _eventRateCounts = new Dictionary<int, Dictionary<int, int>>(); private static Dictionary<int, DateTime> _eventRateTimestamps = new Dictionary<int, DateTime>(); private const int SUSPICIOUS_EVENT_THRESHOLD = 10; private static bool IsRpcValid(PhotonView view, Player sender, OwnershipCondition ownershipCondition, Func<bool> validCondition = null) { if (sender == null) { return true; } switch (ownershipCondition) { case OwnershipCondition.IsMasterClient: if (sender.IsMasterClient) { return true; } break; case OwnershipCondition.IsViewOwner: if ((Object)(object)view != (Object)null && view.Owner != null && sender.ActorNumber == view.Owner.ActorNumber) { return true; } break; case OwnershipCondition.IsMasterClientOrViewOwner: if (sender.IsMasterClient || ((Object)(object)view != (Object)null && view.Owner != null && sender.ActorNumber == view.Owner.ActorNumber)) { return true; } break; } return validCondition?.Invoke() ?? true; } [HarmonyPatch(typeof(PhotonNetwork), "OnEvent")] [HarmonyPrefix] public static bool PreOnEvent(EventData photonEvent) { int sender = photonEvent.Sender; if (sender > 0 && AntiCheatPlugin.IsBlocked(sender)) { return false; } bool flag = false; if (sender > 0 && (photonEvent.Code == 204 || photonEvent.Code == 209 || photonEvent.Code == 210 || photonEvent.Code == 212)) { if (!_eventRateCounts.ContainsKey(sender)) { _eventRateCounts[sender] = new Dictionary<int, int>(); _eventRateTimestamps[sender] = DateTime.Now; } if ((DateTime.Now - _eventRateTimestamps[sender]).TotalSeconds >= 1.0) { _eventRateCounts[sender].Clear(); _eventRateTimestamps[sender] = DateTime.Now; } if (!_eventRateCounts[sender].ContainsKey(photonEvent.Code)) { _eventRateCounts[sender][photonEvent.Code] = 0; } _eventRateCounts[sender][photonEvent.Code]++; if (_eventRateCounts[sender][photonEvent.Code] >= 10) { flag = true; AntiCheatPlugin.Logger.LogWarning((object)$"[SUSPICIOUS RATE] Actor #{sender} sent {_eventRateCounts[sender][photonEvent.Code]} events (code {photonEvent.Code}) in 1 second!"); } } if (PhotonNetwork.IsMasterClient && flag) { switch (photonEvent.Code) { case 204: AntiCheatPlugin.Logger.LogWarning((object)$"[HIGH RATE DESTROY EVENT] From actor #{sender}"); break; case 209: AntiCheatPlugin.Logger.LogWarning((object)$"[HIGH RATE OWNERSHIP REQUEST] From actor #{sender}"); break; case 210: AntiCheatPlugin.Logger.LogWarning((object)$"[HIGH RATE OWNERSHIP TRANSFER] From actor #{sender}"); break; case 212: AntiCheatPlugin.Logger.LogWarning((object)$"[HIGH RATE OWNERSHIP UPDATE] From actor #{sender}"); break; } } if (photonEvent.Code == 210) { int[] array = (int[])photonEvent.CustomData; if (array != null && array.Length >= 2) { int num = array[0]; int num2 = array[1]; if (AntiCheatPlugin.IsBlocked(sender)) { AntiCheatPlugin.Logger.LogWarning((object)$"[OWNERSHIP BLOCKED] Blocked player (Actor #{sender}) tried to transfer ownership of view {num}"); return false; } if (_ownershipRequestCount.ContainsKey(sender)) { if (_lastOwnershipRequest.ContainsKey(sender) && (DateTime.Now - _lastOwnershipRequest[sender]).TotalSeconds < 1.0) { _ownershipRequestCount[sender]++; if (_ownershipRequestCount[sender] > 10) { Room currentRoom = PhotonNetwork.CurrentRoom; Player val = ((currentRoom != null) ? currentRoom.GetPlayer(sender, false) : null); if (val != null && !val.IsLocal) { AntiCheatPlugin.Logger.LogWarning((object)$"[MASS OWNERSHIP DETECTED] {val.NickName} attempted {_ownershipRequestCount[sender]} ownership transfers in 1 second!"); if (PhotonNetwork.IsMasterClient) { AntiCheatPlugin.LogVisually("{userColor}" + val.NickName + "</color> {leftColor}attempted mass ownership theft!</color>", onlySendOnce: false, sfxJoin: false, sfxLeave: true); AntiCheatPlugin.BlockPlayer(val, "Mass ownership theft attempt"); } return false; } } } else { _ownershipRequestCount[sender] = 1; } } else { _ownershipRequestCount[sender] = 1; } _lastOwnershipRequest[sender] = DateTime.Now; PhotonView val2 = PhotonView.Find(num); if ((Object)(object)val2 != (Object)null && val2.Owner != null && val2.Owner.IsLocal && num2 != PhotonNetwork.LocalPlayer.ActorNumber) { Room currentRoom2 = PhotonNetwork.CurrentRoom; Player val3 = ((currentRoom2 != null) ? currentRoom2.GetPlayer(sender, false) : null); if (val3 != null && !val3.IsMasterClient) { AntiCheatPlugin.Logger.LogWarning((object)$"[OWNERSHIP THEFT BLOCKED] {val3.NickName} tried to steal ownership of your view {num}!"); if (PhotonNetwork.IsMasterClient) { AntiCheatPlugin.LogVisually("{userColor}" + val3.NickName + "</color> {leftColor}tried to steal your character!</color>", onlySendOnce: false, sfxJoin: false, sfxLeave: true); AntiCheatPlugin.BlockPlayer(val3, "Attempted ownership theft"); } return false; } } if (photonEvent.Code == 204) { object customData = photonEvent.CustomData; Hashtable val4 = (Hashtable)((customData is Hashtable) ? customData : null); if (val4 != null && val4.ContainsKey((byte)0)) { int num3 = (int)val4[(byte)0]; PhotonView val5 = PhotonView.Find(num3); if ((Object)(object)val5 != (Object)null && val5.IsMine && sender != PhotonNetwork.LocalPlayer.ActorNumber) { Room currentRoom3 = PhotonNetwork.CurrentRoom; Player val6 = ((currentRoom3 != null) ? currentRoom3.GetPlayer(sender, false) : null); AntiCheatPlugin.Logger.LogError((object)$"[DESTROY BLOCKED] {((val6 != null) ? val6.NickName : null) ?? $"Actor {sender}"} tried to destroy your object (ViewID: {num3})!"); if ((Object)(object)((Component)val5).GetComponent<Character>() != (Object)null) { AntiCheatPlugin.Logger.LogError((object)"[CHARACTER DESTROY BLOCKED] They tried to destroy YOUR CHARACTER!"); if (PhotonNetwork.IsMasterClient && val6 != null) { AntiCheatPlugin.LogVisually("{userColor}" + val6.NickName + "</color> {leftColor}tried to destroy your character!</color>", onlySendOnce: false, sfxJoin: false, sfxLeave: true); AntiCheatPlugin.BlockPlayer(val6, "Attempted to destroy your character"); } } return false; } } } return true; } } return true; } [HarmonyPatch(typeof(PhotonView), "TransferOwnership", new Type[] { typeof(Player) })] [HarmonyPrefix] public static bool PreTransferOwnership(PhotonView __instance, Player newOwner) { if ((Object)(object)((Component)__instance).GetComponent<Character>() != (Object)null) { Player owner = __instance.Owner; if (owner != null && owner.ActorNumber != PhotonNetwork.LocalPlayer.ActorNumber && newOwner.ActorNumber == PhotonNetwork.LocalPlayer.ActorNumber) { AntiCheatPlugin.Logger.LogError((object)("[BLOCKED] Attempted to steal character ownership from " + owner.NickName + "!")); return false; } } return true; } [HarmonyPatch(typeof(PhotonView), "RequestOwnership")] [HarmonyPrefix] public static bool PreRequestOwnership(PhotonView __instance) { if ((Object)(object)((Component)__instance).GetComponent<Character>() != (Object)null && !__instance.IsMine && !PhotonNetwork.IsMasterClient) { ManualLogSource logger = AntiCheatPlugin.Logger; Player owner = __instance.Owner; logger.LogError((object)("[BLOCKED] Attempted to request ownership of character owned by " + ((owner != null) ? owner.NickName : null) + "!")); return false; } return true; } [HarmonyPatch(typeof(PhotonNetwork), "Destroy", new Type[] { typeof(PhotonView) })] [HarmonyPrefix] public static bool PrePhotonDestroy(PhotonView targetView) { if ((Object)(object)targetView == (Object)null) { return true; } if ((Object)(object)((Component)targetView).GetComponent<Character>() != (Object)null && !targetView.IsMine && !PhotonNetwork.LocalPlayer.IsMasterClient) { ManualLogSource logger = AntiCheatPlugin.Logger; Player owner = targetView.Owner; logger.LogError((object)("[BLOCKED] Attempted to destroy character owned by " + ((owner != null) ? owner.NickName : null) + "!")); return false; } return true; } [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPrefix] public static bool PreOwnerActorNrSetter(PhotonView __instance, int value) { if (AntiCheatPlugin.IsInSpawnGracePeriod(value)) { AntiCheatPlugin.Logger.LogInfo((object)$"[SPAWN GRACE] Allowing ownership change to actor #{value} during spawn period"); return true; } if (AntiCheatPlugin.IsBlocked(value)) { AntiCheatPlugin.Logger.LogWarning((object)$"[BLOCKED] Blocked player (actor #{value}) tried to take ownership of view {__instance.ViewID}"); return false; } if ((Object)(object)((Component)__instance).GetComponent<Character>() != (Object)null && __instance.IsMine) { Character component = ((Component)__instance).GetComponent<Character>(); if (__instance.CreatorActorNr == 0 || __instance.Owner == null || ((Object)(object)component != (Object)null && !((Behaviour)component).isActiveAndEnabled)) { AntiCheatPlugin.Logger.LogInfo((object)$"[SPAWN] Allowing ownership change for uninitialized character to actor #{value}"); return true; } if (value != PhotonNetwork.LocalPlayer.ActorNumber) { Room currentRoom = PhotonNetwork.CurrentRoom; Player val = ((currentRoom != null) ? currentRoom.GetPlayer(value, false) : null); AntiCheatPlugin.Logger.LogError((object)("[CHARACTER THEFT BLOCKED] " + (((val != null) ? val.NickName : null) ?? $"Actor {value}") + " tried to steal your character!")); if (PhotonNetwork.IsMasterClient && val != null) { AntiCheatPlugin.LogVisually("{userColor}" + val.NickName + "</color> {leftColor}tried to steal your character!</color>", onlySendOnce: false, sfxJoin: false, sfxLeave: true); AntiCheatPlugin.BlockPlayer(val, "Character ownership theft attempt"); } return false; } } if (__instance.Owner != null && __instance.Owner.IsLocal && value != PhotonNetwork.LocalPlayer.ActorNumber) { AntiCheatPlugin.Logger.LogInfo((object)$"[OWNERSHIP] Actor #{value} taking ownership of view {__instance.ViewID} (was ours)"); } return true; } [HarmonyPatch(typeof(Campfire), "SetFireWoodCount")] [HarmonyPrefix] public static bool PreCampfireSetFireWoodCount(Campfire __instance, int count, PhotonMessageInfo info) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Invalid comparison between Unknown and I4 //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) if (AntiCheatPlugin.VerboseRPCLogging.Value) { ManualLogSource logger = AntiCheatPlugin.Logger; Player sender = info.Sender; logger.LogInfo((object)$"Campfire.SetFireWoodCount called by {((sender != null) ? sender.NickName : null)} with count: {count}"); } PhotonView component = ((Component)__instance).GetComponent<PhotonView>(); if (info.Sender == null || info.Sender.IsMasterClient) { return true; } if ((int)__instance.state == 2) { return true; } if ((Object)(object)component != (Object)null && info.Sender.ActorNumber == component.Owner.ActorNumber) { return true; } Character[] array = Object.FindObjectsOfType<Character>(); Character[] array2 = array; foreach (Character val in array2) { PhotonView component2 = ((Component)val).GetComponent<PhotonView>(); if ((Object)(object)component2 != (Object)null && component2.Owner != null && component2.Owner.ActorNumber == info.Sender.ActorNumber) { if ((Object)(object)val.data.currentItem != (Object)null && val.data.currentItem.cooking.canBeCooked) { if (AntiCheatPlugin.VerboseRPCLogging.Value) { AntiCheatPlugin.Logger.LogInfo((object)("[CAMPFIRE ALLOWED] " + info.Sender.NickName + " is holding a cookable item")); } return true; } break; } } if (AntiCheatPlugin.PlayerHadCookableItem(info.Sender.ActorNumber)) { if (AntiCheatPlugin.VerboseRPCLogging.Value) { AntiCheatPlugin.Logger.LogInfo((object)("[CAMPFIRE ALLOWED] " + info.Sender.NickName + " recently had a cookable item")); } return true; } AntiCheatPlugin.Logger.LogWarning((object)$"{info.Sender.NickName} (#{info.Sender.ActorNumber}) tried to set the log count to {count} for the {__instance.advanceToSegment} campfire without a cookable item!"); AntiCheatPlugin.LogVisually("{userColor}" + info.Sender.NickName + "</color> {leftColor}attempted to modify campfire logs without cookable item!</color>", onlySendOnce: false, sfxJoin: false, sfxLeave: true); AntiCheatPlugin.BlockPlayer(info.Sender, "Campfire log manipulation - no cookable item"); if (PhotonNetwork.IsMasterClient) { __instance.FireWoodCount = 3; } return false; } [HarmonyPatch(typeof(Campfire), "Extinguish_Rpc")] [HarmonyPrefix] public static bool PreCampfireExtinguish_Rpc(Campfire __instance, PhotonMessageInfo info) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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) //IL_00b0: 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_00db: 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_00ff: Unknown result type (might be due to invalid IL or missing references) if (info.Sender == null || info.Sender.IsMasterClient) { return true; } if (AntiCheatPlugin.VerboseRPCLogging.Value) { ManualLogSource logger = AntiCheatPlugin.Logger; Player sender = info.Sender; logger.LogInfo((object)("Campfire.Extinguish_Rpc called by " + ((sender != null) ? sender.NickName : null))); } PhotonView component = ((Component)__instance).GetComponent<PhotonView>(); bool flag = info.Sender == null || ((Object)(object)component != (Object)null && info.Sender.ActorNumber == component.Owner.ActorNumber); if (!flag) { AntiCheatPlugin.Logger.LogWarning((object)$"{info.Sender.NickName} (#{info.Sender.ActorNumber}) tried to extinguish the {__instance.advanceToSegment} campfire!"); AntiCheatPlugin.LogVisually($"{{userColor}}{info.Sender.NickName}</color> {{leftColor}}attempted to extinguish the {__instance.advanceToSegment} campfire!</color>", onlySendOnce: false, sfxJoin: false, sfxLeave: true); AntiCheatPlugin.BlockPlayer(info.Sender, "Unauthorized campfire extinguish"); return false; } return flag; } [HarmonyPatch(typeof(Campfire), "Light_Rpc")] [HarmonyPrefix] public static bool PreCampfireLight_Rpc(Campfire __instance, PhotonMessageInfo info) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) if (AntiCheatPlugin.VerboseRPCLogging.Value) { ManualLogSource logger = AntiCheatPlugin.Logger; Player sender = info.Sender; logger.LogInfo((object)("Campfire.Light_Rpc called by " + ((sender != null) ? sender.NickName : null))); } if (info.Sender == null || info.Sender.IsMasterClient) { return true; } string text = default(string); if (__instance.EveryoneInRange(ref text)) { if (AntiCheatPlugin.VerboseRPCLogging.Value) { AntiCheatPlugin.Logger.LogInfo((object)("[LIGHT CAMPFIRE ALLOWED] " + info.Sender.NickName + " lit campfire - everyone in range")); } return true; } AntiCheatPlugin.Logger.LogWarning((object)$"[LIGHT CAMPFIRE DETECTED] {info.Sender.NickName} attempted to light {__instance.advanceToSegment} campfire with players out of range!"); if (!string.IsNullOrEmpty(text)) { AntiCheatPlugin.Logger.LogWarning((object)("[LIGHT CAMPFIRE] Out of range players: " + text)); } if (PhotonNetwork.IsMasterClient) { AntiCheatPlugin.LogVisually($"{{userColor}}{info.Sender.NickName}</color> {{leftColor}}tried to light {__instance.advanceToSegment} campfire with players out of range!</color>", onlySendOnce: false, sfxJoin: false, sfxLeave: true); } return false; } [HarmonyPatch(typeof(PhotonNetwork), "RaiseEventInternal")] [HarmonyPrefix] internal static bool PreRaiseEventInternal(byte eventCode, object eventContent, RaiseEventOptions raiseEventOptions, SendOptions sendOptions) { Player localPlayer = PhotonNetwork.LocalPlayer; if (localPlayer != null && AntiCheatPlugin.IsBlocked(localPlayer.ActorNumber)) { switch (eventCode) { case 200: case 202: case 204: case 207: case 209: case 210: case 212: return false; } } if (eventCode == 204) { Hashtable val = (Hashtable)((eventContent is Hashtable) ? eventContent : null); if (val != null && val.ContainsKey((byte)0)) { int num = (int)val[(byte)0]; PhotonView val2 = PhotonView.Find(num); if ((Object)(object)val2 != (Object)null && val2.Owner != null && localPlayer != null && val2.Owner.ActorNumber != localPlayer.ActorNumber && !localPlayer.IsMasterClient) { AntiCheatPlugin.Logger.LogWarning((object)$"[DESTROY BLOCKED] {localPlayer.NickName} tried to destroy view {num} owned by {val2.Owner.NickName}"); return false; } } } return true; } [HarmonyPatch(typeof(PhotonNetwork), "RemoveInstantiatedGO")] [HarmonyPrefix] internal static bool PreRemoveInstantiatedGO(GameObject go, bool localOnly) { if ((Object)(object)go == (Object)null) { return true; } PhotonView component = go.GetComponent<PhotonView>(); if ((Object)(object)component != (Object)null && component.Owner != null) { Player localPlayer = PhotonNetwork.LocalPlayer; if (localPlayer != null && AntiCheatPlugin.IsBlocked(localPlayer.ActorNumber)) { if (component.Owner.ActorNumber == localPlayer.ActorNumber) { return true; } AntiCheatPlugin.Logger.LogWarning((object)("[DESTROY BLOCKED] Blocked player tried to remove " + ((Object)go).name + " owned by " + component.Owner.NickName)); return false; } } return true; } [HarmonyPatch(typeof(Character), "RPCA_ReviveAtPosition")] [HarmonyPrefix] public static bool PreCharacterRPCA_ReviveAtPosition(Character __instance, PhotonMessageInfo info) { //IL_0019: 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_008a: 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_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_0344: Unknown result type (might be due to invalid IL or missing references) //IL_0372: Unknown result type (might be due to invalid IL or missing references) if (AntiCheatPlugin.VerboseRPCLogging.Value) { ManualLogSource logger = AntiCheatPlugin.Logger; Player sender = info.Sender; string obj = ((sender != null) ? sender.NickName : null); PhotonView component = ((Component)__instance).GetComponent<PhotonView>(); object obj2; if (component == null) { obj2 = null; } else { Player owner = component.Owner; obj2 = ((owner != null) ? owner.NickName : null); } logger.LogInfo((object)("Character.RPCA_ReviveAtPosition called by " + obj + " on " + (string?)obj2)); } PhotonView component2 = ((Component)__instance).GetComponent<PhotonView>(); object obj3; if (component2 == null) { obj3 = null; } else { Player owner2 = component2.Owner; obj3 = ((owner2 != null) ? owner2.NickName : null); } if (obj3 == null) { obj3 = "Unknown"; } string text = (string)obj3; if (info.Sender == null || info.Sender.IsMasterClient) { return true; } if ((Object)(object)component2 != (Object)null && component2.Owner != null) { AntiCheatPlugin.Logger.LogInfo((object)$"[REVIVE DEBUG] Target: {text} (Actor #{component2.Owner.ActorNumber}), Sender: {info.Sender.NickName} (Actor #{info.Sender.ActorNumber})"); AntiCheatPlugin.Logger.LogInfo((object)$"[REVIVE DEBUG] Is target in grace period? {AntiCheatPlugin.IsInSpawnGracePeriod(component2.Owner.ActorNumber)}"); AntiCheatPlugin.Logger.LogInfo((object)$"[REVIVE DEBUG] Is sender in grace period? {AntiCheatPlugin.IsInSpawnGracePeriod(info.Sender.ActorNumber)}"); } if ((Object)(object)component2 != (Object)null && component2.Owner != null && AntiCheatPlugin.IsInSpawnGracePeriod(component2.Owner.ActorNumber)) { AntiCheatPlugin.Logger.LogInfo((object)("[SPAWN TELEPORT ALLOWED] " + info.Sender.NickName + " teleported " + text + " who is in spawn grace period.")); return true; } if (AntiCheatPlugin.IsInSpawnGracePeriod(info.Sender.ActorNumber)) { AntiCheatPlugin.Logger.LogInfo((object)("[SPAWN TELEPORT ALLOWED] " + info.Sender.NickName + " (in spawn grace period) teleported " + text + " who is in spawn grace period.")); return true; } if (AntiCheatPlugin.PlayerHadItem(info.Sender.ActorNumber, "scout") && AntiCheatPlugin.PlayerHadItem(info.Sender.ActorNumber, "effigy")) { if (AntiCheatPlugin.VerboseRPCLogging.Value) { AntiCheatPlugin.Logger.LogInfo((object)(info.Sender.NickName + " used Scout Effigy to revive " + text + " - legitimate")); } return true; } ManualLogSource logger2 = AntiCheatPlugin.Logger; object[] obj4 = new object[4] { info.Sender.NickName, info.Sender.ActorNumber, text, null }; int? obj5; if (component2 == null) { obj5 = null; } else { Player owner3 = component2.Owner; obj5 = ((owner3 != null) ? new int?(owner3.ActorNumber) : null); } obj4[3] = obj5; logger2.LogWarning((object)string.Format("{0} (#{1}) attempted to revive {2} (#{3}) without permission!", obj4)); AntiCheatPlugin.LogVisually("{userColor}" + info.Sender.NickName + "</color> {leftColor}tried to revive</color> {userColor}" + text + "</color> {leftColor}without permission!</color>", onlySendOnce: false, sfxJoin: false, sfxLeave: true); AntiCheatPlugin.BlockPlayer(info.Sender, "Unauthorized revive of " + text); return false; } [HarmonyPatch(typeof(Character), "WarpPlayerRPC")] [HarmonyPrefix] public static bool PreWarpPlayerRPC(Character __instance, Vector3 position, bool poof, PhotonMessageInfo info) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0094: 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_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_0317: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_0334: Unknown result type (might be due to invalid IL or missing references) //IL_039d: Unknown result type (might be due to invalid IL or missing references) //IL_0363: Unknown result type (might be due to invalid IL or missing references) //IL_036f: Unknown result type (might be due to invalid IL or missing references) //IL_0413: Unknown result type (might be due to invalid IL or missing references) //IL_03e4: Unknown result type (might be due to invalid IL or missing references) PhotonView component = ((Component)__instance).GetComponent<PhotonView>(); object obj; if (component == null) { obj = null; } else { Player owner = component.Owner; obj = ((owner != null) ? owner.NickName : null); } if (obj == null) { obj = "Unknown"; } string text = (string)obj; if (info.Sender == null || info.Sender.IsMasterClient) { return true; } if ((Object)(object)component != (Object)null && component.Owner != null) { AntiCheatPlugin.Logger.LogInfo((object)$"[WARP DEBUG] Target: {text} (Actor #{component.Owner.ActorNumber}), Sender: {info.Sender.NickName} (Actor #{info.Sender.ActorNumber})"); AntiCheatPlugin.Logger.LogInfo((object)$"[WARP DEBUG] Is target in grace period? {AntiCheatPlugin.IsInSpawnGracePeriod(component.Owner.ActorNumber)}"); AntiCheatPlugin.Logger.LogInfo((object)$"[WARP DEBUG] Is sender in grace period? {AntiCheatPlugin.IsInSpawnGracePeriod(info.Sender.ActorNumber)}"); AntiCheatPlugin.Logger.LogInfo((object)$"[WARP DEBUG] Position: {position}"); } if (float.IsInfinity(position.x) || float.IsInfinity(position.y) || float.IsInfinity(position.z) || float.IsNegativeInfinity(position.x) || float.IsNegativeInfinity(position.y) || float.IsNegativeInfinity(position.z)) { AntiCheatPlugin.Logger.LogError((object)("[BLACK SCREEN BLOCKED] " + info.Sender.NickName + " tried to warp " + text + " to infinity!")); if (PhotonNetwork.IsMasterClient) { if ((Object)(object)component != (Object)null && component.IsMine) { AntiCheatPlugin.LogVisually("{userColor}" + info.Sender.NickName + "</color> {leftColor}tried to black screen YOU!</color>", onlySendOnce: false, sfxJoin: false, sfxLeave: true); } else { AntiCheatPlugin.LogVisually("{userColor}" + info.Sender.NickName + "</color> {leftColor}tried to black screen</color> {userColor}" + text + "</color>{leftColor}!</color>", onlySendOnce: false, sfxJoin: false, sfxLeave: true); } } AntiCheatPlugin.BlockPlayer(info.Sender, "Black screen attempt on " + text); return false; } if ((Object)(object)component != (Object)null && component.Owner != null && AntiCheatPlugin.IsInSpawnGracePeriod(component.Owner.ActorNumber)) { AntiCheatPlugin.Logger.LogInfo((object)$"[SPAWN TELEPORT ALLOWED] {info.Sender.NickName} teleported {text} who is in spawn grace period to {position}"); return true; } if (AntiCheatPlugin.IsInSpawnGracePeriod(info.Sender.ActorNumber)) { AntiCheatPlugin.Logger.LogInfo((object)$"[SPAWN TELEPORT ALLOWED] {info.Sender.NickName} (in spawn grace period) teleported {text} to {position}"); return true; } if (AntiCheatPlugin.PlayerHadItem(info.Sender.ActorNumber, "scout") && AntiCheatPlugin.PlayerHadItem(info.Sender.ActorNumber, "effigy")) { AntiCheatPlugin.Logger.LogInfo((object)$"[WARP ALLOWED] {info.Sender.NickName} used Scout Effigy to warp {text} to {position}"); return true; } AntiCheatPlugin.Logger.LogWarning((object)("[WARP BLOCKED] " + info.Sender.NickName + " attempted to warp " + text + " without Scout Effigy!")); if (PhotonNetwork.IsMasterClient) { AntiCheatPlugin.LogVisually("{userColor}" + info.Sender.NickName + "</color> {leftColor}tried to warp</color> {userColor}" + text + "</color> {leftColor}without Scout Effigy!</color>", onlySendOnc