Decompiled source of HardAntiCheat v2.0.2

HardAntiCheat.dll

Decompiled 16 minutes ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
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.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using UnityEngine;

[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.0.2.0")]
[assembly: AssemblyInformationalVersion("2.0.2+3da468022bbabca82d9756ce7784eb1f331c1970")]
[assembly: AssemblyProduct("HardAntiCheat")]
[assembly: AssemblyTitle("HardAntiCheat")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.0.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 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 static class Util
	{
		public static bool IsHost(NetworkBehaviour instance)
		{
			Player component = ((Component)instance).GetComponent<Player>();
			return (Object)(object)component != (Object)null && component._isHostPlayer;
		}
	}
	[BepInPlugin("com.HardAntiCheat.sftwre", "HardAntiCheat", "2.0.2")]
	[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<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<bool> EnableCooldownChecks;

		public static ConfigEntry<bool> EnableReviveChecks;

		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;

		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, PlayerAirborneData> ServerPlayerAirborneStates = new Dictionary<uint, PlayerAirborneData>();

		public static readonly Dictionary<uint, float> ServerPlayerInitialSpeeds = 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>();

		private void Awake()
		{
			//IL_0324: Unknown result type (might be due to invalid IL or missing references)
			//IL_032e: Expected O, but got Unknown
			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 to enable or disable all anti-cheat modules.");
			DisableForHost = ((BaseUnityPlugin)this).Config.Bind<bool>("1. General", "Disable Detections for Host", true, "If true, the player hosting the server will not be checked for infractions. Recommended for hosts who use admin commands.");
			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 to prevent it from growing infinitely.");
			EnableMovementChecks = ((BaseUnityPlugin)this).Config.Bind<bool>("2. Movement Detections", "Enable Teleport/Distance Checks", true, "Checks the final result of player movement to catch physics-based speed hacks and teleports.");
			MaxEffectiveSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("2. Movement Detections", "Max Effective Speed", 100f, "The maximum plausible speed (units per second) a player can move. Increase this if lagging players get false flagged.");
			MovementGraceBuffer = ((BaseUnityPlugin)this).Config.Bind<float>("2. Movement Detections", "Movement Grace Buffer", 10f, "A flat distance buffer added to the calculation to account for dashes, knockbacks, and small lag spikes.");
			MovementTimeThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("2. Movement Detections", "Movement Time Threshold", 5.5f, "The time (in seconds) between position checks. Higher values are more lenient on lag but less precise.");
			TeleportDistanceThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("2. Movement Detections", "Teleport Distance Threshold", 50f, "Any movement faster than plausible that also covers more than this distance is logged as a 'Teleport' instead of a 'Speed Hack'.");
			EnableAirborneChecks = ((BaseUnityPlugin)this).Config.Bind<bool>("2. Movement Detections", "Enable Fly/Infinite Jump Checks", true, "Checks if players are airborne for an impossibly long time and have an invalid number of max jumps.");
			EnableSpeedChecks = ((BaseUnityPlugin)this).Config.Bind<bool>("2. Movement Detections", "Enable Base Speed Stat Audits", true, "Continuously checks if a player's base movement speed stat has been illegally modified and reverts it.");
			JumpThreshold = ((BaseUnityPlugin)this).Config.Bind<int>("2. Movement Detections", "Jump threshold", 8, "The maximum number of jumps a player is allowed to perform before returning to the ground.");
			SpeedHackDetectionCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("2. Movement Detections", "Speed Hack Detection Cooldown", 2f, "How long (in seconds) the anti-cheat will wait before logging another speed stat infraction for the same player. Prevents log spam.");
			JumpHackDetectionCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("2. Movement Detections", "Jump Hack Detection Cooldown", 2f, "How long (in seconds) the anti-cheat will wait before logging another jump stat infraction for the same player. Prevents log spam.");
			AirborneHackDetectionCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("2. Movement Detections", "Airborne Hack Detection Cooldown", 10f, "How long (in seconds) the anti-cheat will wait before logging another airborne infraction for the same player. Prevents log spam.");
			EnableExperienceChecks = ((BaseUnityPlugin)this).Config.Bind<bool>("3. Stat Detections", "Enable Experience/Level Checks", true, "Prevents players from gaining huge amounts of XP or multiple levels at once based on the 'Max Plausible XP Gain' limit.");
			MaxPlausibleXPGain = ((BaseUnityPlugin)this).Config.Bind<int>("3. Stat Detections", "Max Plausible XP Gain", 77000, "The maximum amount of XP a player can gain in a single transaction. Adjust this based on your server's max XP rewards.");
			EnableCooldownChecks = ((BaseUnityPlugin)this).Config.Bind<bool>("4. Combat Detections", "Enable Skill Cooldown Checks", true, "Silently enforces server-side cooldowns, blocking premature skill usage.");
			EnableReviveChecks = ((BaseUnityPlugin)this).Config.Bind<bool>("4. Combat Detections", "Enable Self-Revive Checks", true, "Prevents players from reviving themselves while dead.");
			EnablePunishmentSystem = ((BaseUnityPlugin)this).Config.Bind<bool>("5. Punishments", "Enable Punishment System", true, "If enabled, the server will automatically take action against players who accumulate too many infractions.");
			WarningsUntilAction = ((BaseUnityPlugin)this).Config.Bind<int>("5. Punishments", "Infractions Until Action", 5, "Number of infractions a player can commit before the selected action is taken.");
			ActionType = ((BaseUnityPlugin)this).Config.Bind<string>("5. Punishments", "Action Type", "Kick", new ConfigDescription("The action to take when a player reaches the infraction limit.", (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, "Master switch for detailed infraction logs. If false, a minimal log is created. If true, uses the options below.");
			LogPlayerName = ((BaseUnityPlugin)this).Config.Bind<bool>("6. Logging", "Log Player Name", true, "Include the player's name in detailed logs.");
			LogPlayerID = ((BaseUnityPlugin)this).Config.Bind<bool>("6. Logging", "Log Player ID", true, "Include the player's SteamID/netId in detailed logs.");
			LogInfractionDetails = ((BaseUnityPlugin)this).Config.Bind<bool>("6. Logging", "Log Infraction Details", true, "Include the specific reason/details of the infraction in detailed logs.");
			LogInfractionCount = ((BaseUnityPlugin)this).Config.Bind<bool>("6. Logging", "Log Infraction Count", true, "Include the player's current warning count in detailed logs.");
			((BaseUnityPlugin)this).Config.SettingChanged += OnSettingChanged;
			CheckAndArchiveLogFile();
			harmony.PatchAll();
			Log.LogInfo((object)("[HardAntiCheat] has been loaded. Infractions will be logged to: " + InfractionLogPath));
		}

		public void OnDestroy()
		{
			((BaseUnityPlugin)this).Config.SettingChanged -= OnSettingChanged;
			harmony.UnpatchSelf();
		}

		private void OnSettingChanged(object sender, SettingChangedEventArgs e)
		{
			Log.LogInfo((object)$"Configuration setting changed: {e.ChangedSetting.Definition.Key} = {e.ChangedSetting.BoxedValue}");
		}

		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 text = Path.Combine(Path.GetDirectoryName(InfractionLogPath), $"{Path.GetFileNameWithoutExtension(InfractionLogPath)}_ARCHIVED_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.txt");
						File.Move(InfractionLogPath, text);
						Log.LogInfo((object)$"Infraction log exceeded {MaxLogFileSizeMB.Value}MB and was archived to: {text}");
					}
				}
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Error while checking/archiving log file: " + ex.Message));
			}
		}

		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) || !((Object)(object)HostConsole._current != (Object)null) || ((NetworkBehaviour)component).connectionToClient == null)
				{
					return;
				}
				HC_PeerListEntry val = 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)
				{
					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));
					}
					HostConsole._current._selectedPeerEntry = val;
					if (text3 == "kick")
					{
						HostConsole._current.Init_ServerMessage("[HAC]: " + text4);
						HostConsole._current.Kick_Peer();
					}
					else
					{
						HostConsole._current.Init_ServerMessage("[HAC]: " + text4);
						HostConsole._current.Ban_Peer();
					}
					ServerPlayerInfractionCount.Remove(netId);
				}
				else
				{
					Log.LogError((object)$"Could not find PeerListEntry for player {text} (netId: {netId}) to take action.");
				}
			}
			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)
		{
			ServerRemainingCooldowns.Remove(netId);
			ServerPlayerPositions.Remove(netId);
			ServerPlayerStats.Remove(netId);
			ServerPlayerAirborneStates.Remove(netId);
			ServerPlayerInitialSpeeds.Remove(netId);
			ServerPlayerInfractionCount.Remove(netId);
			ServerPlayerGracePeriod.Remove(netId);
			ServerPunishmentCooldown.Remove(netId);
			ServerSpeedCheckCooldowns.Remove(netId);
			ServerJumpCheckCooldowns.Remove(netId);
			ServerAirborneCheckCooldowns.Remove(netId);
		}
	}
	[HarmonyPatch(typeof(PlayerMove), "Start")]
	public static class PlayerSpawnPatch
	{
		private const float GRACE_PERIOD_SECONDS = 3f;

		private static bool hasServerInitialized;

		public static void Postfix(PlayerMove __instance)
		{
			if (NetworkServer.active)
			{
				if (!hasServerInitialized)
				{
					Main.Log.LogInfo((object)"First player has spawned. HardAntiCheat server-side modules are now active and monitoring players.");
					hasServerInitialized = true;
				}
				uint netId = ((NetworkBehaviour)__instance).netId;
				Main.ServerPlayerGracePeriod[netId] = Time.time + 3f;
				if (!Main.ServerPlayerInitialSpeeds.ContainsKey(netId))
				{
					Main.ServerPlayerInitialSpeeds[netId] = __instance.Network_movSpeed;
					Main.Log.LogInfo((object)$"[{netId}] Recorded initial move speed for player: {__instance.Network_movSpeed}");
				}
			}
		}
	}
	[HarmonyPatch]
	public static class ServerAuthorityValidationPatch
	{
		[HarmonyPatch(typeof(StatusEntity), "Cmd_RevivePlayer")]
		[HarmonyPrefix]
		public static bool ValidateRevive(StatusEntity __instance, Player _p)
		{
			if (Main.DisableForHost.Value && Util.IsHost((NetworkBehaviour)(object)__instance))
			{
				return true;
			}
			if (!NetworkServer.active || !Main.EnableAntiCheat.Value || !Main.EnableReviveChecks.Value)
			{
				return true;
			}
			if (((NetworkBehaviour)__instance).netId == ((NetworkBehaviour)_p).netId)
			{
				Main.LogInfraction((NetworkBehaviour)(object)__instance, "Unauthorized Action (Self-Revive)", "Player attempted to revive themselves. Blocked.");
				return false;
			}
			return true;
		}

		[HarmonyPatch(typeof(StatusEntity), "Cmd_ReplenishAll")]
		[HarmonyPrefix]
		public static bool ValidateReplenish(StatusEntity __instance)
		{
			if (Main.DisableForHost.Value && Util.IsHost((NetworkBehaviour)(object)__instance))
			{
				return true;
			}
			if (!NetworkServer.active || !Main.EnableAntiCheat.Value || !Main.EnableReviveChecks.Value)
			{
				return true;
			}
			if (__instance.Network_currentHealth <= 0)
			{
				Main.LogInfraction((NetworkBehaviour)(object)__instance, "Unauthorized Action (Replenish while Dead)", "Player attempted to replenish HP/MP while dead. Blocked.");
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Transform), "SetPositionAndRotation")]
	public static class TransformValidationPatch
	{
		public static bool Prefix(Transform __instance)
		{
			if (!NetworkServer.active || !Main.EnableAntiCheat.Value || !Main.EnableMovementChecks.Value)
			{
				return true;
			}
			PlayerMove component = ((Component)__instance).GetComponent<PlayerMove>();
			if ((Object)(object)component != (Object)null && !Util.IsHost((NetworkBehaviour)(object)component))
			{
				Main.LogInfraction((NetworkBehaviour)(object)component, "Movement Hack (Illegal Teleport Method)", "Player directly called Transform.SetPositionAndRotation.");
				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 ((Object)(object)component != (Object)null && Main.DisableForHost.Value && component._isHostPlayer)
			{
				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 ((Object)(object)component != (Object)null && Main.DisableForHost.Value && component._isHostPlayer)
			{
				return true;
			}
			Main.LogInfraction(__instance, "Movement Hack (Illegal Teleport Command)", "Player directly called a Teleport command.");
			return false;
		}
	}
	[HarmonyPatch(typeof(PlayerMove), "Init_Jump")]
	public static class JumpValidationPatch
	{
		public static bool Prefix(PlayerMove __instance)
		{
			//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_00a8: Unknown result type (might be due to invalid IL or missing references)
			if (Main.DisableForHost.Value && Util.IsHost((NetworkBehaviour)(object)__instance))
			{
				return true;
			}
			if (!NetworkServer.active || !Main.EnableAntiCheat.Value || !Main.EnableAirborneChecks.Value)
			{
				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(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;

		public static void Postfix(PlayerMove __instance)
		{
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0361: Unknown result type (might be due to invalid IL or missing references)
			//IL_0362: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: 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_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0456: Unknown result type (might be due to invalid IL or missing references)
			//IL_0457: Unknown result type (might be due to invalid IL or missing references)
			//IL_0466: Unknown result type (might be due to invalid IL or missing references)
			//IL_04db: 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_04b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0520: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_030e: Unknown result type (might be due to invalid IL or missing references)
			//IL_032b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0330: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			if ((Main.DisableForHost.Value && Util.IsHost((NetworkBehaviour)(object)__instance)) || !NetworkServer.active || !Main.EnableAntiCheat.Value || AtlyssNetworkManager._current._soloMode)
			{
				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))
			{
				if (__instance._movSpeed >= Main.MaxEffectiveSpeed.Value)
				{
					Main.LogInfraction((NetworkBehaviour)(object)__instance, "Stat Manipulation (Move Speed)", $"Detected illegal move speed of {__instance._movSpeed}. Reverting to initial speed of {value2}.");
					Main.ServerSpeedCheckCooldowns[netId] = Time.time + Main.SpeedHackDetectionCooldown.Value;
				}
				else if (__instance._movSpeed < 20f)
				{
					Main.Log.LogMessage((object)"Yo chill yo u went too low, were not flagging u for this jsut be careful next time okay? good boy/girl");
					__instance._movSpeed = value2;
				}
			}
			Vector3 position = ((Component)__instance).transform.position;
			if (Main.EnableMovementChecks.Value)
			{
				if (Main.ServerPlayerPositions.TryGetValue(netId, out var value3) && position != value3.Position)
				{
					float num = Time.time - value3.Timestamp;
					if (num > Main.MovementTimeThreshold.Value)
					{
						float num2 = Vector3.Distance(value3.Position, position);
						float num3 = Main.MaxEffectiveSpeed.Value * num + Main.MovementGraceBuffer.Value;
						if (num2 > num3)
						{
							string cheatType = ((num2 > Main.TeleportDistanceThreshold.Value) ? "Movement Hack (Teleport)" : "Movement Hack (Speed)");
							string text = $"Moved {num2:F1} units in {num:F2}s. Reverting position.";
							foreach (NetworkConnectionToClient value5 in NetworkServer.connections.Values)
							{
								if ((Object)(object)((value5 != null) ? ((NetworkConnection)value5).identity : null) == (Object)null || ((NetworkConnection)value5).identity.netId == netId || !(Vector3.Distance(position, ((Component)((NetworkConnection)value5).identity).transform.position) < 1f))
								{
									continue;
								}
								text += " Teleported directly to another player.";
								cheatType = "Movement Hack (Teleport)";
								break;
							}
							Main.LogInfraction((NetworkBehaviour)(object)__instance, cheatType, text);
							((Component)__instance).transform.position = value3.Position;
							Main.ServerPlayerPositions[netId] = new PlayerPositionData
							{
								Position = value3.Position,
								Timestamp = Time.time
							};
							return;
						}
					}
				}
				Main.ServerPlayerPositions[netId] = new PlayerPositionData
				{
					Position = position,
					Timestamp = Time.time
				};
			}
			if (!Main.EnableAirborneChecks.Value)
			{
				return;
			}
			if ((!Main.ServerJumpCheckCooldowns.ContainsKey(netId) || Time.time > Main.ServerJumpCheckCooldowns[netId]) && __instance._maxJumps >= Main.JumpThreshold.Value)
			{
				Main.LogInfraction((NetworkBehaviour)(object)__instance, "Stat Manipulation (Max Jumps)", $"Client reported _maxJumps of {__instance._maxJumps}. Reverting to {Main.JumpThreshold.Value}.");
				__instance._maxJumps = Main.JumpThreshold.Value;
				Main.ServerJumpCheckCooldowns[netId] = Time.time + Main.JumpHackDetectionCooldown.Value;
			}
			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 value4 = playerAirborneData2;
			if (__instance.RayGroundCheck())
			{
				value4.AirTime = 0f;
				value4.ServerSideJumpCount = 0;
				value4.LastGroundedPosition = position;
				value4.VerticalStallTime = 0f;
			}
			else
			{
				value4.AirTime += Time.deltaTime;
				if (Mathf.Abs(position.y - value4.LastVerticalPosition) < 0.05f)
				{
					value4.VerticalStallTime += Time.deltaTime;
				}
				else
				{
					value4.VerticalStallTime = 0f;
				}
			}
			value4.LastVerticalPosition = position.y;
			if (value4.AirTime > 10f)
			{
				if (value4.VerticalStallTime < 0.5f && (!Main.ServerAirborneCheckCooldowns.ContainsKey(netId) || Time.time > Main.ServerAirborneCheckCooldowns[netId]))
				{
					Main.LogInfraction((NetworkBehaviour)(object)__instance, "Movement Hack (Fly/Sustained Jump)", $"Airborne for {value4.AirTime:F1} seconds. Reverting to last ground position.");
					Main.ServerAirborneCheckCooldowns[netId] = Time.time + Main.AirborneHackDetectionCooldown.Value;
				}
				((Component)__instance).transform.position = value4.LastGroundedPosition;
				value4.AirTime = 0f;
				value4.ServerSideJumpCount = 0;
				value4.VerticalStallTime = 0f;
			}
			Main.ServerPlayerAirborneStates[netId] = value4;
		}
	}
	[HarmonyPatch]
	public static class ExperienceValidationPatch
	{
		[HarmonyPatch(typeof(PlayerStats), "set_Network_currentExp")]
		[HarmonyPrefix]
		public static bool ValidateExperienceChange(PlayerStats __instance, ref int value)
		{
			if (Main.DisableForHost.Value && Util.IsHost((NetworkBehaviour)(object)__instance))
			{
				return true;
			}
			if (!NetworkServer.active || !Main.EnableAntiCheat.Value || !Main.EnableExperienceChecks.Value)
			{
				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 > Main.MaxPlausibleXPGain.Value)
			{
				Main.LogInfraction((NetworkBehaviour)(object)__instance, "Stat Manipulation (Experience)", $"Attempted to gain {num} XP at once. Blocked.");
				value = experience;
			}
			PlayerStatsData value3 = Main.ServerPlayerStats[netId];
			value3.Experience = value;
			Main.ServerPlayerStats[netId] = value3;
			return true;
		}

		[HarmonyPatch(typeof(PlayerStats), "set_Network_currentLevel")]
		[HarmonyPrefix]
		public static bool ValidateLevelChange(PlayerStats __instance, ref int value)
		{
			if (Main.DisableForHost.Value && Util.IsHost((NetworkBehaviour)(object)__instance))
			{
				return true;
			}
			if (!NetworkServer.active || !Main.EnableAntiCheat.Value || !Main.EnableExperienceChecks.Value)
			{
				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)
		{
			if (Main.DisableForHost.Value && Util.IsHost((NetworkBehaviour)(object)__instance))
			{
				return true;
			}
			if (!NetworkServer.active || !Main.EnableAntiCheat.Value || !Main.EnableCooldownChecks.Value)
			{
				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 + " like a h4xX0r. Detected as hel.");
				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(typeof(AtlyssNetworkManager), "OnServerDisconnect")]
	public static class PlayerDisconnectPatch
	{
		public static void Postfix(NetworkConnectionToClient _conn)
		{
			if ((Object)(object)((_conn != null) ? ((NetworkConnection)_conn).identity : null) != (Object)null)
			{
				uint netId = ((NetworkConnection)_conn).identity.netId;
				Main.ClearAllPlayerData(netId);
			}
		}
	}
	internal static class ModInfo
	{
		public const string GUID = "com.HardAntiCheat.sftwre";

		public const string NAME = "HardAntiCheat";

		public const string VERSION = "2.0.2";
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}