using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using CodeTalker;
using CodeTalker.Networking;
using CodeTalker.Packets;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using Steamworks;
using UnityEngine;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("com.HardAntiCheat.sftwre")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("2.3.2.0")]
[assembly: AssemblyInformationalVersion("2.3.2+ce5d905125637476bd99e27790ad7fe526c8a074")]
[assembly: AssemblyProduct("HardAntiCheat")]
[assembly: AssemblyTitle("HardAntiCheat")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.3.2.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace HardAntiCheat
{
public class HAC_ModListRequest : BinaryPacketBase
{
public override string PacketSignature => "HAC_Request_V6";
public ulong TargetSteamID { get; set; }
public override byte[] Serialize()
{
using MemoryStream memoryStream = new MemoryStream();
using BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
binaryWriter.Write(TargetSteamID);
return memoryStream.ToArray();
}
public override void Deserialize(byte[] data)
{
using MemoryStream input = new MemoryStream(data);
using BinaryReader binaryReader = new BinaryReader(input);
TargetSteamID = binaryReader.ReadUInt64();
}
}
public class HAC_ModListResponse : BinaryPacketBase
{
public override string PacketSignature => "HAC_Response_V6";
public List<string> ClientModGUIDs { get; set; }
public override byte[] Serialize()
{
using MemoryStream memoryStream = new MemoryStream();
using BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
if (ClientModGUIDs == null)
{
binaryWriter.Write(0);
}
else
{
binaryWriter.Write(ClientModGUIDs.Count);
foreach (string clientModGUID in ClientModGUIDs)
{
binaryWriter.Write(clientModGUID ?? "");
}
}
return memoryStream.ToArray();
}
public override void Deserialize(byte[] data)
{
using MemoryStream input = new MemoryStream(data);
using BinaryReader binaryReader = new BinaryReader(input);
int num = binaryReader.ReadInt32();
ClientModGUIDs = new List<string>();
for (int i = 0; i < num; i++)
{
ClientModGUIDs.Add(binaryReader.ReadString());
}
}
}
public struct PlayerPositionData
{
public Vector3 Position;
public float Timestamp;
}
public struct PlayerStatsData
{
public int Level;
public int Experience;
}
public struct PlayerAirborneData
{
public float AirTime;
public Vector3 LastGroundedPosition;
public int ServerSideJumpCount;
public float LastVerticalPosition;
public float VerticalStallTime;
}
public struct PlayerMovementStats
{
public List<float> RecentSpeeds;
public float TimeAtMaxSpeed;
}
[BepInPlugin("com.HardAntiCheat.sftwre", "HardAntiCheat", "2.3.2")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Main : BaseUnityPlugin
{
private readonly Harmony harmony = new Harmony("com.HardAntiCheat.sftwre");
internal static ManualLogSource Log;
internal static string InfractionLogPath;
public static ConfigEntry<bool> EnableAntiCheat;
public static ConfigEntry<bool> DisableForHost;
public static ConfigEntry<string> TrustedSteamIDs;
public static ConfigEntry<bool> EnableModBlacklist;
public static ConfigEntry<string> BlacklistedModGUIDs;
public static ConfigEntry<float> VerificationTimeout;
public static ConfigEntry<int> MaxLogFileSizeMB;
public static ConfigEntry<bool> EnableMovementChecks;
public static ConfigEntry<float> MaxEffectiveSpeed;
public static ConfigEntry<float> MovementGraceBuffer;
public static ConfigEntry<float> MovementTimeThreshold;
public static ConfigEntry<float> TeleportDistanceThreshold;
public static ConfigEntry<bool> EnableAirborneChecks;
public static ConfigEntry<bool> EnableSpeedChecks;
public static ConfigEntry<float> SpeedHackDetectionCooldown;
public static ConfigEntry<float> JumpHackDetectionCooldown;
public static ConfigEntry<float> AirborneHackDetectionCooldown;
public static ConfigEntry<bool> EnableExperienceChecks;
public static ConfigEntry<int> JumpThreshold;
public static ConfigEntry<int> MaxPlausibleXPGain;
public static ConfigEntry<int> MaxXPGainPerWindow;
public static ConfigEntry<float> XPGainWindowSeconds;
public static ConfigEntry<bool> EnableCooldownChecks;
public static ConfigEntry<bool> EnableReviveChecks;
public static ConfigEntry<bool> EnableSpamChecks;
public static ConfigEntry<float> MinConsumableInterval;
public static ConfigEntry<float> MinWeaponSwapInterval;
public static ConfigEntry<float> MinBlockInterval;
public static ConfigEntry<bool> EnablePunishmentSystem;
public static ConfigEntry<int> WarningsUntilAction;
public static ConfigEntry<string> ActionType;
public static ConfigEntry<bool> EnableDetailedLogs;
public static ConfigEntry<bool> LogPlayerName;
public static ConfigEntry<bool> LogPlayerID;
public static ConfigEntry<bool> LogInfractionCount;
public static ConfigEntry<bool> LogInfractionDetails;
private static readonly HashSet<ulong> WhitelistedUsers = new HashSet<ulong>();
private static readonly HashSet<string> ServerBlacklistedGUIDs = new HashSet<string>();
internal static readonly Dictionary<ulong, Coroutine> PendingVerification = new Dictionary<ulong, Coroutine>();
internal static readonly HashSet<ulong> VerifiedSteamIDs = new HashSet<ulong>();
public static readonly Dictionary<uint, Dictionary<string, float>> ServerRemainingCooldowns = new Dictionary<uint, Dictionary<string, float>>();
public static readonly Dictionary<uint, PlayerPositionData> ServerPlayerPositions = new Dictionary<uint, PlayerPositionData>();
public static readonly Dictionary<uint, PlayerStatsData> ServerPlayerStats = new Dictionary<uint, PlayerStatsData>();
public static readonly Dictionary<uint, List<(float Timestamp, int Amount)>> XpGainHistory = new Dictionary<uint, List<(float, int)>>();
public static readonly Dictionary<uint, PlayerAirborneData> ServerPlayerAirborneStates = new Dictionary<uint, PlayerAirborneData>();
public static readonly Dictionary<uint, float> ServerPlayerInitialSpeeds = new Dictionary<uint, float>();
public static readonly Dictionary<uint, PlayerMovementStats> ServerPlayerMovementStats = new Dictionary<uint, PlayerMovementStats>();
public static readonly Dictionary<uint, float> ServerPlayerMovementTimers = new Dictionary<uint, float>();
public static readonly Dictionary<uint, int> ServerPlayerInfractionCount = new Dictionary<uint, int>();
public static readonly Dictionary<uint, float> ServerPlayerGracePeriod = new Dictionary<uint, float>();
public static readonly Dictionary<uint, float> ServerPunishmentCooldown = new Dictionary<uint, float>();
public static readonly Dictionary<uint, float> ServerSpeedCheckCooldowns = new Dictionary<uint, float>();
public static readonly Dictionary<uint, float> ServerJumpCheckCooldowns = new Dictionary<uint, float>();
public static readonly Dictionary<uint, float> ServerAirborneCheckCooldowns = new Dictionary<uint, float>();
public static readonly Dictionary<uint, float> AuthorizedSelfRevives = new Dictionary<uint, float>();
public static readonly Dictionary<uint, float> LastConsumableTime = new Dictionary<uint, float>();
public static readonly Dictionary<uint, float> LastWeaponSwapTime = new Dictionary<uint, float>();
public static readonly Dictionary<uint, float> LastBlockTime = new Dictionary<uint, float>();
public static readonly Dictionary<uint, float> StaminaCheckTimer = new Dictionary<uint, float>();
public static Main Instance { get; private set; }
private void Awake()
{
//IL_048b: Unknown result type (might be due to invalid IL or missing references)
//IL_0495: Expected O, but got Unknown
Instance = this;
Log = ((BaseUnityPlugin)this).Logger;
string fullName = Directory.GetParent(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location)).FullName;
string text = Path.Combine(fullName, "HardAntiCheat");
Directory.CreateDirectory(text);
InfractionLogPath = Path.Combine(text, "HardAntiCheat_InfractionLog.txt");
EnableAntiCheat = ((BaseUnityPlugin)this).Config.Bind<bool>("1. General", "Enable AntiCheat", true, "Master switch.");
DisableForHost = ((BaseUnityPlugin)this).Config.Bind<bool>("1. General", "Disable Detections for Host", true, "If true, the host is exempt.");
TrustedSteamIDs = ((BaseUnityPlugin)this).Config.Bind<string>("1. General", "Trusted SteamIDs", "", "Comma-separated list of exempt SteamIDs.");
MaxLogFileSizeMB = ((BaseUnityPlugin)this).Config.Bind<int>("1. General", "Max Log File Size (MB)", 5, "If the infraction log exceeds this size, it will be archived on startup.");
EnableModBlacklist = ((BaseUnityPlugin)this).Config.Bind<bool>("1. General", "Enable Mod Blacklist", true, "If true, clients sending a mod GUID found in the Blacklist will be kicked.");
BlacklistedModGUIDs = ((BaseUnityPlugin)this).Config.Bind<string>("1. General", "Blacklisted Mod GUIDs", "com.cheat.menu,another.bad.mod", "Comma-separated list of Mod GUIDs that are strictly forbidden.");
VerificationTimeout = ((BaseUnityPlugin)this).Config.Bind<float>("1. General", "Verification Timeout", 25f, "Seconds to wait for client mod list before kicking.");
EnableMovementChecks = ((BaseUnityPlugin)this).Config.Bind<bool>("2. Movement", "Enable Teleport Checks", true, "Checks movement distance.");
MaxEffectiveSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("2. Movement", "Max Effective Speed", 100f, "Max plausible speed.");
MovementGraceBuffer = ((BaseUnityPlugin)this).Config.Bind<float>("2. Movement", "Movement Grace Buffer", 10f, "Distance buffer.");
MovementTimeThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("2. Movement", "Movement Time Threshold", 5.5f, "Time between checks.");
TeleportDistanceThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("2. Movement", "Teleport Threshold", 50f, "Distance to log as teleport.");
EnableAirborneChecks = ((BaseUnityPlugin)this).Config.Bind<bool>("2. Movement", "Enable Fly Checks", true, "Checks airtime.");
EnableSpeedChecks = ((BaseUnityPlugin)this).Config.Bind<bool>("2. Movement", "Enable Speed Stat Checks", true, "Checks base move speed.");
JumpThreshold = ((BaseUnityPlugin)this).Config.Bind<int>("2. Movement", "Jump Threshold", 8, "Max jumps allowed.");
SpeedHackDetectionCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("2. Movement", "Speed Check Cooldown", 2f, "Log cooldown.");
JumpHackDetectionCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("2. Movement", "Jump Check Cooldown", 2f, "Log cooldown.");
AirborneHackDetectionCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("2. Movement", "Airborne Check Cooldown", 10f, "Log cooldown.");
EnableExperienceChecks = ((BaseUnityPlugin)this).Config.Bind<bool>("3. Stats", "Enable XP Checks", true, "Checks XP gain.");
MaxPlausibleXPGain = ((BaseUnityPlugin)this).Config.Bind<int>("3. Stats", "Max XP Gain", 77000, "Max XP in one go.");
MaxXPGainPerWindow = ((BaseUnityPlugin)this).Config.Bind<int>("3. Stats", "Max XP Rate", 150000, "Max XP over time.");
XPGainWindowSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("3. Stats", "XP Window", 30f, "Time window for XP rate.");
EnableCooldownChecks = ((BaseUnityPlugin)this).Config.Bind<bool>("4. Combat", "Enable Cooldown Checks", true, "Enforce skill cooldowns.");
EnableReviveChecks = ((BaseUnityPlugin)this).Config.Bind<bool>("4. Combat", "Enable Revive Checks", true, "Prevent self-revive.");
EnableSpamChecks = ((BaseUnityPlugin)this).Config.Bind<bool>("4. Combat", "Enable Spam Checks", true, "Prevents macro-spamming items/swaps/blocking.");
MinConsumableInterval = ((BaseUnityPlugin)this).Config.Bind<float>("4. Combat", "Min Consumable Interval", 0.4f, "Min seconds between using items.");
MinWeaponSwapInterval = ((BaseUnityPlugin)this).Config.Bind<float>("4. Combat", "Min Weapon Swap Interval", 0.25f, "Min seconds between switching weapons.");
MinBlockInterval = ((BaseUnityPlugin)this).Config.Bind<float>("4. Combat", "Min Block Interval", 0.1f, "Min seconds between block inputs (Prevents Parry Botting).");
EnablePunishmentSystem = ((BaseUnityPlugin)this).Config.Bind<bool>("5. Punishment", "Enable Auto-Punish", true, "Kick/Ban on infractions.");
WarningsUntilAction = ((BaseUnityPlugin)this).Config.Bind<int>("5. Punishment", "Infractions Limit", 5, "Warnings before action.");
ActionType = ((BaseUnityPlugin)this).Config.Bind<string>("5. Punishment", "Action Type", "Kick", new ConfigDescription("Action to take", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "Kick", "Ban" }), Array.Empty<object>()));
EnableDetailedLogs = ((BaseUnityPlugin)this).Config.Bind<bool>("6. Logging", "Enable Detailed Logs", true, "Log details.");
LogPlayerName = ((BaseUnityPlugin)this).Config.Bind<bool>("6. Logging", "Log Name", true, "");
LogPlayerID = ((BaseUnityPlugin)this).Config.Bind<bool>("6. Logging", "Log ID", true, "");
LogInfractionCount = ((BaseUnityPlugin)this).Config.Bind<bool>("6. Logging", "Log Count", true, "");
LogInfractionDetails = ((BaseUnityPlugin)this).Config.Bind<bool>("6. Logging", "Log Details", true, "");
CheckAndArchiveLogFile();
ParseTrustedSteamIDs();
ParseBlacklistedMods();
TrustedSteamIDs.SettingChanged += delegate
{
ParseTrustedSteamIDs();
};
BlacklistedModGUIDs.SettingChanged += delegate
{
ParseBlacklistedMods();
};
harmony.PatchAll();
Log.LogInfo((object)string.Format("[{0}] loaded. Blacklist Mode: {1}", "HardAntiCheat", EnableModBlacklist.Value));
}
public static void OnClientReceivedRequest(PacketHeader header, BinaryPacketBase packet)
{
if (packet is HAC_ModListRequest hAC_ModListRequest && ulong.TryParse(Player._mainPlayer?._steamID, out var result) && hAC_ModListRequest.TargetSteamID == result)
{
List<string> clientModGUIDs = Chainloader.PluginInfos.Keys.ToList();
HAC_ModListResponse hAC_ModListResponse = new HAC_ModListResponse
{
ClientModGUIDs = clientModGUIDs
};
CodeTalkerNetwork.SendNetworkPacket(header.SenderID, (BinaryPacketBase)(object)hAC_ModListResponse, (CompressionType)0, CompressionLevel.Fastest);
}
}
public static void OnServerReceivedResponse(PacketHeader header, BinaryPacketBase packet)
{
if (!NetworkServer.active || !(packet is HAC_ModListResponse hAC_ModListResponse))
{
return;
}
ulong senderID = header.SenderID;
if (!PendingVerification.TryGetValue(senderID, out Coroutine value))
{
return;
}
if (!EnableModBlacklist.Value)
{
AuthorizePlayer(senderID, value);
return;
}
List<string> source = hAC_ModListResponse.ClientModGUIDs ?? new List<string>();
List<string> source2 = source.Where((string clientMod) => ServerBlacklistedGUIDs.Contains(clientMod)).ToList();
if (source2.Any())
{
string text = "Blacklisted Mods Detected: " + string.Join(", ", source2.Take(3));
Log.LogWarning((object)$"[HAC] Kicking {senderID}. {text}");
PunishVerificationFailure(senderID, text);
}
else
{
AuthorizePlayer(senderID, value);
}
}
private static void AuthorizePlayer(ulong steamId, Coroutine coroutine)
{
if ((Object)(object)Instance != (Object)null && coroutine != null)
{
((MonoBehaviour)Instance).StopCoroutine(coroutine);
}
PendingVerification.Remove(steamId);
VerifiedSteamIDs.Add(steamId);
}
public IEnumerator SendRequestWithDelay(Player player, ulong steamId)
{
yield return (object)new WaitForSeconds(3f);
if (!((Object)(object)player == (Object)null))
{
HAC_ModListRequest req = new HAC_ModListRequest
{
TargetSteamID = steamId
};
CodeTalkerNetwork.SendNetworkPacket(player, (BinaryPacketBase)(object)req, (CompressionType)0, CompressionLevel.Fastest);
Coroutine kickRoutine = ((MonoBehaviour)this).StartCoroutine(KickClientAfterDelay(player));
PendingVerification[steamId] = kickRoutine;
}
}
public IEnumerator KickClientAfterDelay(Player player)
{
if (!((Object)(object)player == (Object)null) && ulong.TryParse(player._steamID, out var steamId))
{
yield return (object)new WaitForSeconds(VerificationTimeout.Value);
if ((Object)(object)player != (Object)null && !VerifiedSteamIDs.Contains(steamId))
{
string reason = "Handshake Timeout. Client did not report mod list in time.";
PunishVerificationFailure(steamId, reason);
}
PendingVerification.Remove(steamId);
}
}
private static void PunishVerificationFailure(ulong steamId, string reason)
{
if (PendingVerification.TryGetValue(steamId, out Coroutine value))
{
if ((Object)(object)Instance != (Object)null)
{
((MonoBehaviour)Instance).StopCoroutine(value);
}
PendingVerification.Remove(steamId);
}
VerifiedSteamIDs.Remove(steamId);
Player playerBySteamID = GetPlayerBySteamID(steamId);
if ((Object)(object)playerBySteamID != (Object)null && ((NetworkBehaviour)playerBySteamID).connectionToClient != null)
{
Log.LogWarning((object)("[HAC] Kicking " + playerBySteamID._nickname + ". Reason: " + reason));
if ((Object)(object)HostConsole._current != (Object)null)
{
HostConsole._current.Init_ServerMessage("[HAC]: Kicked " + playerBySteamID._nickname + ". " + reason);
}
((NetworkConnection)((NetworkBehaviour)playerBySteamID).connectionToClient).Disconnect();
}
}
private static void ParseBlacklistedMods()
{
ServerBlacklistedGUIDs.Clear();
string value = BlacklistedModGUIDs.Value;
if (!string.IsNullOrWhiteSpace(value))
{
string[] array = value.Split(',');
string[] array2 = array;
foreach (string text in array2)
{
string text2 = text.Trim();
if (!string.IsNullOrEmpty(text2))
{
ServerBlacklistedGUIDs.Add(text2);
}
}
}
Log.LogInfo((object)$"[HAC] Blacklist updated. {ServerBlacklistedGUIDs.Count} mods banned.");
}
private static void ParseTrustedSteamIDs()
{
WhitelistedUsers.Clear();
string[] array = TrustedSteamIDs.Value.Split(',');
string[] array2 = array;
foreach (string text in array2)
{
if (ulong.TryParse(text.Trim(), out var result))
{
WhitelistedUsers.Add(result);
}
}
}
public static bool IsPlayerExempt(Player player)
{
if ((Object)(object)player == (Object)null)
{
return false;
}
if (DisableForHost.Value && player._isHostPlayer)
{
return true;
}
if (!string.IsNullOrEmpty(player._steamID) && ulong.TryParse(player._steamID, out var result) && WhitelistedUsers.Contains(result))
{
return true;
}
return false;
}
private static Player GetPlayerBySteamID(ulong steamId)
{
Player val = default(Player);
foreach (NetworkConnectionToClient value in NetworkServer.connections.Values)
{
if ((Object)(object)((NetworkConnection)value).identity != (Object)null && ((Component)((NetworkConnection)value).identity).TryGetComponent<Player>(ref val) && ulong.TryParse(val._steamID, out var result) && result == steamId)
{
return val;
}
}
return null;
}
private void CheckAndArchiveLogFile()
{
try
{
if (File.Exists(InfractionLogPath))
{
FileInfo fileInfo = new FileInfo(InfractionLogPath);
long num = (long)MaxLogFileSizeMB.Value * 1024L * 1024;
if (fileInfo.Length > num)
{
string destFileName = Path.Combine(Path.GetDirectoryName(InfractionLogPath), $"{Path.GetFileNameWithoutExtension(InfractionLogPath)}_ARCHIVED_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.txt");
File.Move(InfractionLogPath, destFileName);
}
}
}
catch
{
}
}
public static void LogInfraction(NetworkBehaviour instance, string cheatType, string details)
{
uint netId = instance.netId;
if (ServerPunishmentCooldown.TryGetValue(netId, out var value) && Time.time < value)
{
return;
}
ServerPunishmentCooldown.Remove(netId);
if (!ServerPlayerInfractionCount.ContainsKey(netId))
{
ServerPlayerInfractionCount[netId] = 0;
}
ServerPlayerInfractionCount[netId]++;
int num = ServerPlayerInfractionCount[netId];
int value2 = WarningsUntilAction.Value;
Player component = ((Component)instance).GetComponent<Player>();
string text = component?._nickname ?? "Unknown";
string text2 = component?._steamID ?? $"netId:{netId}";
if (EnablePunishmentSystem.Value && !AtlyssNetworkManager._current._soloMode && num >= value2)
{
if (!NetworkServer.active || !((Object)(object)component != (Object)null) || ((NetworkBehaviour)component).connectionToClient == null)
{
return;
}
ServerPunishmentCooldown[netId] = Time.time + 60f;
string text3 = ActionType.Value.ToLower();
string text4 = $"Player {text} (ID: {text2}) was automatically {text3.ToUpper()}ed for reaching {num}/{value2} infractions.";
Log.LogWarning((object)text4);
try
{
File.AppendAllText(InfractionLogPath, $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] [PUNISHMENT] " + text4 + Environment.NewLine);
}
catch (Exception ex)
{
Log.LogError((object)("Failed to write punishment to log: " + ex.Message));
}
if ((Object)(object)HostConsole._current != (Object)null)
{
HostConsole._current.Init_ServerMessage("[HAC]: " + text4);
}
if (text3 == "kick")
{
((NetworkConnection)((NetworkBehaviour)component).connectionToClient).Disconnect();
}
else
{
HC_PeerListEntry val = null;
if ((Object)(object)HostConsole._current != (Object)null)
{
foreach (HC_PeerListEntry peerListEntry in HostConsole._current._peerListEntries)
{
if ((Object)(object)peerListEntry._netId != (Object)null && peerListEntry._netId.netId == netId)
{
val = peerListEntry;
break;
}
}
}
if ((Object)(object)val != (Object)null)
{
HostConsole._current._selectedPeerEntry = val;
HostConsole._current.Ban_Peer();
}
else
{
((NetworkConnection)((NetworkBehaviour)component).connectionToClient).Disconnect();
Log.LogError((object)$"Could not find PeerListEntry for player {text} (netId: {netId}) to BAN, kicked instead.");
}
}
ServerPlayerInfractionCount.Remove(netId);
}
else if (EnableDetailedLogs.Value)
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}]");
List<string> list = new List<string>();
if (LogPlayerName.Value)
{
list.Add("Player: " + text);
}
if (LogPlayerID.Value)
{
list.Add("ID: " + text2);
}
if (list.Any())
{
stringBuilder.Append(" " + string.Join(" | ", list));
}
stringBuilder.Append(" | Type: " + cheatType);
if (LogInfractionDetails.Value)
{
stringBuilder.Append(" | Details: " + details);
}
if (LogInfractionCount.Value)
{
stringBuilder.Append($" | Warning {num}/{value2}");
}
string text5 = stringBuilder.ToString();
Log.LogWarning((object)text5);
try
{
File.AppendAllText(InfractionLogPath, text5 + Environment.NewLine);
}
catch (Exception ex2)
{
Log.LogError((object)("Failed to write to infraction log: " + ex2.Message));
}
}
}
public static void ClearAllPlayerData(uint netId, ulong steamId)
{
ServerRemainingCooldowns.Remove(netId);
ServerPlayerPositions.Remove(netId);
ServerPlayerStats.Remove(netId);
XpGainHistory.Remove(netId);
ServerPlayerAirborneStates.Remove(netId);
ServerPlayerInitialSpeeds.Remove(netId);
ServerPlayerMovementStats.Remove(netId);
ServerPlayerMovementTimers.Remove(netId);
ServerPlayerInfractionCount.Remove(netId);
ServerPlayerGracePeriod.Remove(netId);
ServerPunishmentCooldown.Remove(netId);
ServerSpeedCheckCooldowns.Remove(netId);
ServerJumpCheckCooldowns.Remove(netId);
ServerAirborneCheckCooldowns.Remove(netId);
LastConsumableTime.Remove(netId);
LastWeaponSwapTime.Remove(netId);
LastBlockTime.Remove(netId);
StaminaCheckTimer.Remove(netId);
if (PendingVerification.TryGetValue(steamId, out Coroutine value))
{
if ((Object)(object)Instance != (Object)null)
{
((MonoBehaviour)Instance).StopCoroutine(value);
}
PendingVerification.Remove(steamId);
}
VerifiedSteamIDs.Remove(steamId);
}
}
[HarmonyPatch(typeof(PlayerMove), "Start")]
public static class PlayerSpawnPatch
{
private const float GRACE_PERIOD_SECONDS = 3f;
public static void Postfix(PlayerMove __instance)
{
//IL_0090: 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)
if (!NetworkServer.active)
{
return;
}
uint netId = ((NetworkBehaviour)__instance).netId;
Player component = ((Component)__instance).GetComponent<Player>();
if ((Object)(object)((Component)__instance).gameObject.GetComponent<HoneypotComponent>() == (Object)null)
{
((Component)__instance).gameObject.AddComponent<HoneypotComponent>();
}
Main.ServerPlayerGracePeriod[netId] = Time.time + 3f;
if (!Main.ServerPlayerInitialSpeeds.ContainsKey(netId))
{
Main.ServerPlayerInitialSpeeds[netId] = __instance.Network_movSpeed;
}
Main.ServerPlayerPositions[netId] = new PlayerPositionData
{
Position = ((Component)__instance).transform.position,
Timestamp = Time.time
};
Main.ServerPlayerMovementStats[netId] = new PlayerMovementStats
{
RecentSpeeds = new List<float>(),
TimeAtMaxSpeed = 0f
};
Main.ServerPlayerMovementTimers[netId] = Time.time;
if (Main.EnableModBlacklist.Value && (Object)(object)component != (Object)null && !((NetworkBehaviour)component).isLocalPlayer && ulong.TryParse(component._steamID, out var result))
{
if (Main.IsPlayerExempt(component))
{
Main.Log.LogInfo((object)("Player " + component._nickname + " is exempt. Skipping checks."));
Main.VerifiedSteamIDs.Add(result);
}
else if (!Main.PendingVerification.ContainsKey(result) && !Main.VerifiedSteamIDs.Contains(result))
{
((MonoBehaviour)Main.Instance).StartCoroutine(Main.Instance.SendRequestWithDelay(component, result));
}
}
}
}
[HarmonyPatch(typeof(PlayerInventory), "Cmd_UseConsumable")]
public static class PlayerInventory_UseConsumable_Patch
{
public static bool Prefix(PlayerInventory __instance)
{
if (!NetworkServer.active || !Main.EnableAntiCheat.Value || !Main.EnableSpamChecks.Value)
{
return true;
}
Player component = ((Component)__instance).GetComponent<Player>();
if (Main.IsPlayerExempt(component))
{
return true;
}
uint netId = ((NetworkBehaviour)__instance).netId;
float time = Time.time;
if (Main.LastConsumableTime.TryGetValue(netId, out var value) && time - value < Main.MinConsumableInterval.Value)
{
return false;
}
Main.LastConsumableTime[netId] = time;
return true;
}
}
[HarmonyPatch(typeof(PlayerCombat), "Cmd_QuickSwapWeapon")]
public static class PlayerCombat_QuickSwap_Patch
{
public static bool Prefix(PlayerCombat __instance)
{
if (!NetworkServer.active || !Main.EnableAntiCheat.Value || !Main.EnableSpamChecks.Value)
{
return true;
}
Player component = ((Component)__instance).GetComponent<Player>();
if (Main.IsPlayerExempt(component))
{
return true;
}
uint netId = ((NetworkBehaviour)__instance).netId;
float time = Time.time;
if (Main.LastWeaponSwapTime.TryGetValue(netId, out var value) && time - value < Main.MinWeaponSwapInterval.Value)
{
return false;
}
Main.LastWeaponSwapTime[netId] = time;
return true;
}
}
[HarmonyPatch(typeof(PlayerCombat), "Cmd_ApplyBlockCondition")]
public static class PlayerCombat_Block_Patch
{
public static bool Prefix(PlayerCombat __instance, bool _isTrue)
{
if (!_isTrue || !NetworkServer.active || !Main.EnableAntiCheat.Value || !Main.EnableSpamChecks.Value)
{
return true;
}
Player component = ((Component)__instance).GetComponent<Player>();
if (Main.IsPlayerExempt(component))
{
return true;
}
uint netId = ((NetworkBehaviour)__instance).netId;
float time = Time.time;
if (Main.LastBlockTime.TryGetValue(netId, out var value) && time - value < Main.MinBlockInterval.Value)
{
return false;
}
Main.LastBlockTime[netId] = time;
return true;
}
}
[HarmonyPatch(typeof(PlayerMove), "Update")]
public static class MovementAndAirborneValidationPatch
{
private const float MAX_ALLOWED_AIR_TIME = 10f;
private const float VERTICAL_STALL_TOLERANCE = 0.05f;
private const float VERTICAL_STALL_GRACE_PERIOD = 0.5f;
private const float MAX_FLIGHT_HEIGHT = 4240f;
private const int STATS_BUFFER_SIZE = 20;
private const float STATS_ANALYSIS_INTERVAL = 2f;
public static void Postfix(PlayerMove __instance)
{
//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
//IL_02e6: Unknown result type (might be due to invalid IL or missing references)
//IL_03f1: Unknown result type (might be due to invalid IL or missing references)
//IL_03f2: Unknown result type (might be due to invalid IL or missing references)
//IL_0323: Unknown result type (might be due to invalid IL or missing references)
//IL_0328: Unknown result type (might be due to invalid IL or missing references)
//IL_0443: Unknown result type (might be due to invalid IL or missing references)
//IL_0444: Unknown result type (might be due to invalid IL or missing references)
//IL_0453: Unknown result type (might be due to invalid IL or missing references)
//IL_049a: Unknown result type (might be due to invalid IL or missing references)
//IL_049b: Unknown result type (might be due to invalid IL or missing references)
//IL_04b5: Unknown result type (might be due to invalid IL or missing references)
//IL_04e2: Unknown result type (might be due to invalid IL or missing references)
//IL_03d3: Unknown result type (might be due to invalid IL or missing references)
//IL_0201: Unknown result type (might be due to invalid IL or missing references)
//IL_0206: Unknown result type (might be due to invalid IL or missing references)
//IL_0208: Unknown result type (might be due to invalid IL or missing references)
//IL_0214: Unknown result type (might be due to invalid IL or missing references)
//IL_021b: Unknown result type (might be due to invalid IL or missing references)
//IL_0220: Unknown result type (might be due to invalid IL or missing references)
//IL_057a: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)AtlyssNetworkManager._current == (Object)null || !NetworkServer.active || !Main.EnableAntiCheat.Value || AtlyssNetworkManager._current._soloMode || (Object)(object)__instance == (Object)null)
{
return;
}
Player component = ((Component)__instance).GetComponent<Player>();
if ((Object)(object)component == (Object)null || Main.IsPlayerExempt(component))
{
return;
}
uint netId = ((NetworkBehaviour)__instance).netId;
if (Main.ServerPlayerGracePeriod.TryGetValue(netId, out var value))
{
if (Time.time < value)
{
return;
}
Main.ServerPlayerGracePeriod.Remove(netId);
}
if (Main.EnableSpeedChecks.Value && (!Main.ServerSpeedCheckCooldowns.ContainsKey(netId) || Time.time > Main.ServerSpeedCheckCooldowns[netId]) && Main.ServerPlayerInitialSpeeds.TryGetValue(netId, out var value2) && __instance._movSpeed > value2 * 1.5f)
{
Main.LogInfraction((NetworkBehaviour)(object)__instance, "Stat Manipulation (Move Speed)", $"Detected illegal move speed of {__instance._movSpeed}. Reverting.");
__instance.Reset_MoveSpeed();
Main.ServerSpeedCheckCooldowns[netId] = Time.time + Main.SpeedHackDetectionCooldown.Value;
}
if (Main.EnableExperienceChecks.Value)
{
StatusEntity component2 = ((Component)__instance).GetComponent<StatusEntity>();
PlayerStats component3 = ((Component)__instance).GetComponent<PlayerStats>();
if ((Object)(object)component2 != (Object)null && (Object)(object)component3 != (Object)null)
{
int maxStamina = component3._statStruct._maxStamina;
if (component2.Network_currentStamina >= maxStamina - 1 && __instance.RayGroundCheck())
{
if (Main.ServerPlayerInitialSpeeds.TryGetValue(netId, out var value3))
{
Rigidbody component4 = ((Component)__instance).GetComponent<Rigidbody>();
if ((Object)(object)component4 != (Object)null)
{
Vector3 velocity = component4.velocity;
Vector3 val = new Vector3(velocity.x, 0f, velocity.z);
float magnitude = ((Vector3)(ref val)).magnitude;
if (magnitude > value3 * 1.2f)
{
if (!Main.StaminaCheckTimer.ContainsKey(netId))
{
Main.StaminaCheckTimer[netId] = Time.time;
}
if (Time.time - Main.StaminaCheckTimer[netId] > 3f)
{
Main.LogInfraction((NetworkBehaviour)(object)__instance, "Stat Manipulation (Infinite Stamina)", "Sustained high speed with full stamina.");
Main.StaminaCheckTimer[netId] = Time.time + 5f;
}
}
else
{
Main.StaminaCheckTimer[netId] = Time.time;
}
}
}
}
else
{
Main.StaminaCheckTimer[netId] = Time.time;
}
}
}
Vector3 position = ((Component)__instance).transform.position;
if (Main.EnableMovementChecks.Value)
{
if (Main.ServerPlayerPositions.TryGetValue(netId, out var value4))
{
float num = Time.time - value4.Timestamp;
float num2 = Vector3.Distance(value4.Position, position);
if (num > Main.MovementTimeThreshold.Value)
{
float value5;
float num3 = (Main.ServerPlayerInitialSpeeds.TryGetValue(netId, out value5) ? value5 : 50f) * 1.5f * num + Main.MovementGraceBuffer.Value;
if (num2 > num3)
{
string cheatType = ((num2 > Main.TeleportDistanceThreshold.Value) ? "Movement Hack (Teleport)" : "Movement Hack (Speed Mismatch)");
string details = $"Moved {num2:F1} units in {num:F2}s (Expected max: {num3:F1}). Reverting position.";
Main.LogInfraction((NetworkBehaviour)(object)__instance, cheatType, details);
((Component)component).transform.position = value4.Position;
}
}
}
Main.ServerPlayerPositions[netId] = new PlayerPositionData
{
Position = position,
Timestamp = Time.time
};
}
if (!Main.EnableAirborneChecks.Value)
{
return;
}
PlayerAirborneData playerAirborneData2;
if (!Main.ServerPlayerAirborneStates.ContainsKey(netId))
{
PlayerAirborneData playerAirborneData = default(PlayerAirborneData);
playerAirborneData.AirTime = 0f;
playerAirborneData.LastGroundedPosition = position;
playerAirborneData.ServerSideJumpCount = 0;
playerAirborneData.LastVerticalPosition = position.y;
playerAirborneData.VerticalStallTime = 0f;
playerAirborneData2 = playerAirborneData;
}
else
{
playerAirborneData2 = Main.ServerPlayerAirborneStates[netId];
}
PlayerAirborneData value6 = playerAirborneData2;
if (__instance.RayGroundCheck())
{
value6.AirTime = 0f;
value6.LastGroundedPosition = position;
}
else
{
value6.AirTime += Time.deltaTime;
}
if (position.y > 4240f)
{
Main.LogInfraction((NetworkBehaviour)(object)__instance, "Movement Hack (Fly)", "Exceeded maximum height limit. Reverting.");
((Component)__instance).transform.position = value6.LastGroundedPosition;
return;
}
if (value6.AirTime > 10f)
{
if (!Main.ServerAirborneCheckCooldowns.ContainsKey(netId) || Time.time > Main.ServerAirborneCheckCooldowns[netId])
{
Main.LogInfraction((NetworkBehaviour)(object)__instance, "Movement Hack (Fly)", $"Airborne for {value6.AirTime:F1} seconds. Reverting.");
Main.ServerAirborneCheckCooldowns[netId] = Time.time + Main.AirborneHackDetectionCooldown.Value;
}
((Component)__instance).transform.position = value6.LastGroundedPosition;
value6.AirTime = 0f;
}
Main.ServerPlayerAirborneStates[netId] = value6;
}
}
[HarmonyPatch]
public static class ItemUsageValidationPatch
{
[HarmonyPatch(typeof(PlayerInventory), "UserCode_Cmd_UseConsumable__ItemData")]
[HarmonyPrefix]
public static void GrantTokenOnTearUsage(PlayerInventory __instance, ItemData _itemData)
{
if (NetworkServer.active && _itemData != null && _itemData._itemName == "Angela's Tear")
{
Main.AuthorizedSelfRevives[((NetworkBehaviour)__instance).netId] = Time.time;
}
}
}
[HarmonyPatch]
public static class ServerAuthorityValidationPatch
{
[HarmonyPatch(typeof(StatusEntity), "Cmd_RevivePlayer")]
[HarmonyPrefix]
public static bool ValidateRevive(StatusEntity __instance, StatusEntity _statusEntity)
{
if (!NetworkServer.active || !Main.EnableAntiCheat.Value || !Main.EnableReviveChecks.Value)
{
return true;
}
Player component = ((Component)_statusEntity).GetComponent<Player>();
if ((Object)(object)component == (Object)null)
{
return true;
}
if (Main.IsPlayerExempt(component))
{
return true;
}
if (((NetworkBehaviour)__instance).netId == ((NetworkBehaviour)_statusEntity).netId)
{
Main.LogInfraction((NetworkBehaviour)(object)__instance, "Unauthorized Action (Direct Self-Revive)", "Blocked direct call to self-revive.");
return false;
}
return true;
}
[HarmonyPatch(typeof(StatusEntity), "Cmd_ReplenishAll")]
[HarmonyPrefix]
public static bool ValidateReplenish(StatusEntity __instance)
{
Player component = ((Component)__instance).GetComponent<Player>();
if (!NetworkServer.active || !Main.EnableAntiCheat.Value || !Main.EnableReviveChecks.Value)
{
return true;
}
if (Main.IsPlayerExempt(component))
{
return true;
}
if (__instance.Network_currentHealth <= 0)
{
uint netId = ((NetworkBehaviour)component).netId;
if (Main.AuthorizedSelfRevives.TryGetValue(netId, out var value) && Time.time - value < 1.5f)
{
Main.AuthorizedSelfRevives.Remove(netId);
return true;
}
Main.LogInfraction((NetworkBehaviour)(object)__instance, "Unauthorized Action (Replenish while Dead)", "Blocked replenish call - was not authorized by UI button press.");
return false;
}
return true;
}
}
[HarmonyPatch(typeof(NetworkTransformBase), "CmdTeleport", new Type[]
{
typeof(Vector3),
typeof(Quaternion)
})]
public static class CmdTeleportValidationPatch2
{
public static bool Prefix(NetworkBehaviour __instance)
{
if (!NetworkServer.active || !Main.EnableAntiCheat.Value || !Main.EnableMovementChecks.Value)
{
return true;
}
Player component = ((Component)__instance).GetComponent<Player>();
if (Main.IsPlayerExempt(component))
{
return true;
}
Main.LogInfraction(__instance, "Movement Hack (Illegal Teleport Command)", "Player directly called a Teleport command.");
return false;
}
}
[HarmonyPatch(typeof(NetworkTransformBase), "CmdTeleport", new Type[] { typeof(Vector3) })]
public static class CmdTeleportValidationPatch
{
public static bool Prefix(NetworkBehaviour __instance)
{
if (!NetworkServer.active || !Main.EnableAntiCheat.Value || !Main.EnableMovementChecks.Value)
{
return true;
}
Player component = ((Component)__instance).GetComponent<Player>();
if (Main.IsPlayerExempt(component))
{
return true;
}
Main.LogInfraction(__instance, "Movement Hack (Illegal Teleport Command)", "Player directly called a Teleport command.");
return false;
}
}
public class HoneypotComponent : NetworkBehaviour
{
[Command]
public void Cmd_ExecuteDebugBypass()
{
if (!ulong.TryParse(((Component)this).GetComponent<Player>()._steamID, out var result))
{
return;
}
Main.Log.LogWarning((object)$"HONEYPOT TRIGGERED by SteamID {result}. Banning immediately.");
if ((Object)(object)HostConsole._current != (Object)null)
{
HC_PeerListEntry val = null;
foreach (HC_PeerListEntry peerListEntry in HostConsole._current._peerListEntries)
{
if ((Object)(object)peerListEntry._netId != (Object)null && peerListEntry._netId.netId == ((NetworkBehaviour)this).netId)
{
val = peerListEntry;
break;
}
}
if ((Object)(object)val != (Object)null)
{
HostConsole._current._selectedPeerEntry = val;
HostConsole._current.Ban_Peer();
}
}
else
{
((NetworkConnection)((NetworkBehaviour)this).connectionToClient).Disconnect();
}
}
}
[HarmonyPatch(typeof(PlayerMove), "Init_Jump")]
public static class JumpValidationPatch
{
public static bool Prefix(PlayerMove __instance)
{
//IL_0088: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: 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)
Player component = ((Component)__instance).GetComponent<Player>();
if (!NetworkServer.active || !Main.EnableAntiCheat.Value || !Main.EnableAirborneChecks.Value)
{
return true;
}
if (Main.IsPlayerExempt(component))
{
return true;
}
uint netId = ((NetworkBehaviour)__instance).netId;
if (!Main.ServerPlayerAirborneStates.ContainsKey(netId))
{
Main.ServerPlayerAirborneStates[netId] = new PlayerAirborneData
{
AirTime = 0f,
LastGroundedPosition = ((Component)__instance).transform.position,
ServerSideJumpCount = 0,
LastVerticalPosition = ((Component)__instance).transform.position.y,
VerticalStallTime = 0f
};
}
PlayerAirborneData value = Main.ServerPlayerAirborneStates[netId];
if (value.ServerSideJumpCount >= Main.JumpThreshold.Value)
{
return false;
}
value.ServerSideJumpCount++;
Main.ServerPlayerAirborneStates[netId] = value;
return true;
}
}
[HarmonyPatch]
public static class ExperienceValidationPatch
{
[HarmonyPatch(typeof(PlayerStats), "set_Network_currentExp")]
[HarmonyPrefix]
public static bool ValidateExperienceChange(PlayerStats __instance, ref int value)
{
Player component = ((Component)__instance).GetComponent<Player>();
if (!NetworkServer.active || !Main.EnableAntiCheat.Value || !Main.EnableExperienceChecks.Value)
{
return true;
}
if (Main.IsPlayerExempt(component))
{
return true;
}
uint netId = ((NetworkBehaviour)__instance).netId;
if (!Main.ServerPlayerStats.TryGetValue(netId, out var value2))
{
Main.ServerPlayerStats[netId] = new PlayerStatsData
{
Experience = value,
Level = __instance.Network_currentLevel
};
return true;
}
int experience = value2.Experience;
int num = value - experience;
if (num <= 0)
{
PlayerStatsData value3 = Main.ServerPlayerStats[netId];
value3.Experience = value;
Main.ServerPlayerStats[netId] = value3;
return true;
}
if (num > Main.MaxPlausibleXPGain.Value)
{
Main.LogInfraction((NetworkBehaviour)(object)__instance, "Stat Manipulation (Experience)", $"Attempted to gain {num} XP at once (Limit: {Main.MaxPlausibleXPGain.Value}). Blocked.");
value = experience;
return false;
}
if (IsXpGainRateExceeded(netId, num))
{
Main.LogInfraction((NetworkBehaviour)(object)__instance, "Stat Manipulation (XP Rate)", "Attempted to gain XP too quickly. Blocked.");
value = experience;
return false;
}
PlayerStatsData value4 = Main.ServerPlayerStats[netId];
value4.Experience = value;
Main.ServerPlayerStats[netId] = value4;
return true;
}
private static bool IsXpGainRateExceeded(uint netId, int gain)
{
if (!Main.XpGainHistory.ContainsKey(netId))
{
Main.XpGainHistory[netId] = new List<(float, int)>();
}
List<(float, int)> list = Main.XpGainHistory[netId];
float currentTime = Time.time;
float window = Main.XPGainWindowSeconds.Value;
list.RemoveAll(((float Timestamp, int Amount) entry) => currentTime - entry.Timestamp > window);
int num = list.Sum<(float, int)>(((float Timestamp, int Amount) entry) => entry.Amount);
if (num + gain > Main.MaxXPGainPerWindow.Value)
{
return true;
}
list.Add((currentTime, gain));
return false;
}
[HarmonyPatch(typeof(PlayerStats), "set_Network_currentLevel")]
[HarmonyPrefix]
public static bool ValidateLevelChange(PlayerStats __instance, ref int value)
{
Player component = ((Component)__instance).GetComponent<Player>();
if (!NetworkServer.active || !Main.EnableAntiCheat.Value || !Main.EnableExperienceChecks.Value)
{
return true;
}
if (Main.IsPlayerExempt(component))
{
return true;
}
uint netId = ((NetworkBehaviour)__instance).netId;
if (!Main.ServerPlayerStats.TryGetValue(netId, out var value2))
{
Main.ServerPlayerStats[netId] = new PlayerStatsData
{
Experience = __instance.Network_currentExp,
Level = value
};
return true;
}
int level = value2.Level;
int num = value - level;
if (num > 1)
{
Main.LogInfraction((NetworkBehaviour)(object)__instance, "Stat Manipulation (Level)", $"Attempted to jump from level {level} to {value}. Blocked.");
value = level;
}
PlayerStatsData value3 = Main.ServerPlayerStats[netId];
value3.Level = value;
Main.ServerPlayerStats[netId] = value3;
return true;
}
}
[HarmonyPatch]
public static class CombatValidationPatch
{
[HarmonyPatch(typeof(PlayerCasting), "Update")]
[HarmonyPostfix]
public static void CooldownUpdate(PlayerCasting __instance)
{
if (!NetworkServer.active || !Main.EnableAntiCheat.Value || !Main.EnableCooldownChecks.Value)
{
return;
}
uint netId = ((NetworkBehaviour)__instance).netId;
if (!Main.ServerRemainingCooldowns.TryGetValue(netId, out Dictionary<string, float> value))
{
return;
}
List<string> list = new List<string>();
List<string> list2 = new List<string>(value.Keys);
foreach (string item in list2)
{
float num = Time.deltaTime + Time.deltaTime * __instance._cooldownMod;
float num2 = value[item] - num;
if (num2 <= 0f)
{
list.Add(item);
}
else
{
value[item] = num2;
}
}
foreach (string item2 in list)
{
value.Remove(item2);
}
}
[HarmonyPatch(typeof(PlayerCasting), "Server_CastSkill")]
[HarmonyPrefix]
public static bool UnifiedCooldownValidation(PlayerCasting __instance)
{
Player component = ((Component)__instance).GetComponent<Player>();
if (!NetworkServer.active || !Main.EnableAntiCheat.Value || !Main.EnableCooldownChecks.Value)
{
return true;
}
if (Main.IsPlayerExempt(component))
{
return true;
}
ScriptableSkill currentCastSkill = __instance._currentCastSkill;
if ((Object)(object)currentCastSkill == (Object)null)
{
return true;
}
uint netId = ((NetworkBehaviour)__instance).netId;
if (Main.ServerRemainingCooldowns.TryGetValue(netId, out Dictionary<string, float> value) && value.ContainsKey(((Object)currentCastSkill).name))
{
__instance.Server_InterruptCast();
Main.LogInfraction((NetworkBehaviour)(object)__instance, "Skill Manipulation", "Attempted to cast " + ((Object)currentCastSkill).name + " while on cooldown.");
return false;
}
if (!Main.ServerRemainingCooldowns.ContainsKey(netId))
{
Main.ServerRemainingCooldowns[netId] = new Dictionary<string, float>();
}
Main.ServerRemainingCooldowns[netId][((Object)currentCastSkill).name] = currentCastSkill._skillRankParams._baseCooldown;
return true;
}
}
[HarmonyPatch]
public static class NetworkLifecyclePatches
{
private static bool serverListenersRegistered;
[HarmonyPostfix]
[HarmonyPatch(typeof(AtlyssNetworkManager), "OnStartServer")]
public static void OnStartServer_Postfix()
{
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
Main.Log.LogInfo((object)"Server started. Behavioral checks active.");
if (Main.EnableModBlacklist.Value && !serverListenersRegistered)
{
serverListenersRegistered = true;
CSteamID steamID = SteamUser.GetSteamID();
if (((CSteamID)(ref steamID)).IsValid())
{
Main.VerifiedSteamIDs.Add(steamID.m_SteamID);
}
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(AtlyssNetworkManager), "OnStopClient")]
public static void OnStopClient_Postfix()
{
serverListenersRegistered = false;
Main.VerifiedSteamIDs.Clear();
Main.PendingVerification.Clear();
Main.Log.LogInfo((object)"Client stopped. HAC listeners and data cleared.");
}
}
[HarmonyPatch(typeof(AtlyssNetworkManager), "OnServerDisconnect")]
public static class PlayerDisconnectPatch
{
public static void Postfix(NetworkConnectionToClient _conn)
{
if (_conn != null && (Object)(object)((NetworkConnection)_conn).identity != (Object)null)
{
uint netId = ((NetworkConnection)_conn).identity.netId;
if (ulong.TryParse(((Component)((NetworkConnection)_conn).identity).GetComponent<Player>()?._steamID, out var result))
{
Main.ClearAllPlayerData(netId, result);
}
}
}
}
[HarmonyPatch(typeof(Button), "Press")]
public static class ButtonPressValidationPatch
{
private static DeathPromptManager _deathPromptManagerInstance;
public static bool Prefix(Button __instance)
{
if ((Object)(object)_deathPromptManagerInstance == (Object)null)
{
_deathPromptManagerInstance = Object.FindObjectOfType<DeathPromptManager>();
if ((Object)(object)_deathPromptManagerInstance == (Object)null)
{
return true;
}
}
Button value = Traverse.Create((object)_deathPromptManagerInstance).Field<Button>("_useTearButton").Value;
if ((Object)(object)value != (Object)null && (Object)(object)__instance == (Object)(object)value)
{
Player mainPlayer = Player._mainPlayer;
if ((Object)(object)mainPlayer != (Object)null)
{
PlayerInventory component = ((Component)mainPlayer).GetComponent<PlayerInventory>();
if ((Object)(object)component != (Object)null)
{
foreach (ItemData heldItem in component._heldItems)
{
if (heldItem != null && heldItem._itemName == "Angela's Tear")
{
component.Cmd_UseConsumable(heldItem);
return true;
}
}
}
}
}
return true;
}
}
internal static class ModInfo
{
public const string GUID = "com.HardAntiCheat.sftwre";
public const string NAME = "HardAntiCheat";
public const string VERSION = "2.3.2";
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}