Decompiled source of HardAntiCheat v2.5.3
HardAntiCheat.dll
Decompiled 2 weeks 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.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 System.Threading.Tasks; 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 Nessie.ATLYSS.EasySettings; using Nessie.ATLYSS.EasySettings.UIElements; using Newtonsoft.Json; using Steamworks; using UnityEngine; using UnityEngine.Events; using UnityEngine.Networking; 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.5.3.0")] [assembly: AssemblyInformationalVersion("2.5.3+331e92aca353ad4f40ff75cc77bdbd3d23df01f4")] [assembly: AssemblyProduct("HardAntiCheat")] [assembly: AssemblyTitle("HardAntiCheat")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.5.3.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 List<string> ClientModNames { get; set; } public List<string> ClientModVersions { get; set; } public override byte[] Serialize() { using MemoryStream memoryStream = new MemoryStream(); using BinaryWriter binaryWriter = new BinaryWriter(memoryStream); int num = ClientModGUIDs?.Count ?? 0; binaryWriter.Write(num); for (int i = 0; i < num; i++) { binaryWriter.Write(ClientModGUIDs[i] ?? string.Empty); binaryWriter.Write(ClientModNames[i] ?? string.Empty); binaryWriter.Write(ClientModVersions[i] ?? string.Empty); } 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>(num); ClientModNames = new List<string>(num); ClientModVersions = new List<string>(num); for (int i = 0; i < num; i++) { ClientModGUIDs.Add(binaryReader.ReadString()); ClientModNames.Add(binaryReader.ReadString()); ClientModVersions.Add(binaryReader.ReadString()); } } } public class HAC_KickMessage : BinaryPacketBase { public override string PacketSignature => "HAC_Kick_V6"; public string Reason { get; set; } public override byte[] Serialize() { using MemoryStream memoryStream = new MemoryStream(); using BinaryWriter binaryWriter = new BinaryWriter(memoryStream); binaryWriter.Write(Reason ?? string.Empty); return memoryStream.ToArray(); } public override void Deserialize(byte[] data) { using MemoryStream input = new MemoryStream(data); using BinaryReader binaryReader = new BinaryReader(input); Reason = 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; } public class ThunderstorePackageV1 { public string uuid4 { get; set; } [JsonProperty("namespace")] public string namespace_name { get; set; } public string name { get; set; } public string full_name { get; set; } public string owner { get; set; } [JsonIgnore] public string latest { get; set; } public bool is_deprecated { get; set; } [JsonProperty("is_flagged")] public bool is_flagged { get; set; } public string date_created { get; set; } public string date_updated { get; set; } public int downloads { get; set; } } public class ThunderstorePackageDetail { public string uuid4 { get; set; } [JsonProperty("namespace")] public string namespace_name { get; set; } public string name { get; set; } public string full_name { get; set; } public string owner { get; set; } [JsonIgnore] public string latest { get; set; } public bool is_deprecated { get; set; } [JsonProperty("is_flagged")] public bool is_flagged { get; set; } public List<string> dependencies { get; set; } public string date_created { get; set; } public string date_updated { get; set; } } public class ThunderstoreModCache { public string BepInExGUID { get; set; } public string ThunderstoreUUID { get; set; } public string Namespace { get; set; } public string Name { get; set; } public bool IsDeprecated { get; set; } public bool IsFlagged { get; set; } public DateTime LastVerified { get; set; } public DateTime FirstSeen { get; set; } } public class ThunderstoreSearchResponse { public string next { get; set; } public string previous { get; set; } public List<ThunderstorePackageV1> results { get; set; } } [BepInPlugin("com.HardAntiCheat.sftwre", "HardAntiCheat", "2.5.3")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Main : BaseUnityPlugin { [CompilerGenerated] private static class <>O { public static BinaryPacketListener <0>__OnClientReceivedRequest; public static BinaryPacketListener <1>__OnReceivedResponse; public static BinaryPacketListener <2>__OnClientReceivedKickMessage; } [CompilerGenerated] private sealed class <>c__DisplayClass104_0 { public List<string> guids; internal bool <VerifyClientModsWithThunderstore>b__0(string req) { return !guids.Contains(req); } } [CompilerGenerated] private sealed class <AutoRefreshThunderstoreDatabase>d__94 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Main <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <AutoRefreshThunderstoreDatabase>d__94(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; if (EnableThunderstoreWhitelist.Value) { Log.LogInfo((object)"[HAC] Auto-refreshing Thunderstore database..."); <>2__current = ((MonoBehaviour)<>4__this).StartCoroutine(<>4__this.FetchThunderstorePackageList()); <>1__state = 2; return true; } break; case 2: <>1__state = -1; break; } <>2__current = (object)new WaitForSeconds(ThunderstoreRefreshInterval.Value * 60f); <>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 <BackgroundVerifyModAsync>d__101 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public string guid; public string name; public string version; public Main <>4__this; private string <lowerGuid>5__1; private string <searchTerm>5__2; private string <aliasName>5__3; private string <searchUrl>5__4; private UnityWebRequest <request>5__5; private string <json>5__6; private List<ThunderstorePackageV1> <results>5__7; private ThunderstorePackageV1 <matchedPkg>5__8; private ThunderstoreSearchResponse <searchResponse>5__9; private List<ThunderstorePackageV1>.Enumerator <>s__10; private ThunderstorePackageV1 <pkg>5__11; private List<string>.Enumerator <>s__12; private string <g>5__13; private List<string>.Enumerator <>s__14; private string <g>5__15; private string <lowerGuidBL>5__16; private string <existing>5__17; private Exception <ex>5__18; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <BackgroundVerifyModAsync>d__101(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <lowerGuid>5__1 = null; <searchTerm>5__2 = null; <aliasName>5__3 = null; <searchUrl>5__4 = null; <request>5__5 = null; <json>5__6 = null; <results>5__7 = null; <matchedPkg>5__8 = null; <searchResponse>5__9 = null; <>s__10 = default(List<ThunderstorePackageV1>.Enumerator); <pkg>5__11 = null; <>s__12 = default(List<string>.Enumerator); <g>5__13 = null; <>s__14 = default(List<string>.Enumerator); <g>5__15 = null; <lowerGuidBL>5__16 = null; <existing>5__17 = null; <ex>5__18 = null; <>1__state = -2; } private bool MoveNext() { //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Invalid comparison between Unknown and I4 try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <lowerGuid>5__1 = guid.ToLower(); if (ThunderstoreKnownPackages.Contains(<lowerGuid>5__1)) { return false; } <searchTerm>5__2 = ((!string.IsNullOrEmpty(name) && name != "Unknown") ? name : guid); if (KnownModAliases.TryGetValue(name, out <aliasName>5__3) || KnownModAliases.TryGetValue(guid, out <aliasName>5__3)) { Log.LogDebug((object)("[HAC] [Background] '" + name + "' (" + guid + ") matched known alias -> searching as '" + <aliasName>5__3 + "'.")); <searchTerm>5__2 = <aliasName>5__3; } <searchUrl>5__4 = "https://thunderstore.io/c/" + ThunderstoreCommunity.Value + "/api/v1/package/?search=" + Uri.EscapeDataString(<searchTerm>5__2); <request>5__5 = UnityWebRequest.Get(<searchUrl>5__4); <>1__state = -3; <request>5__5.SetRequestHeader("Accept", "application/json"); <request>5__5.timeout = 10; <>2__current = <request>5__5.SendWebRequest(); <>1__state = 1; return true; case 1: <>1__state = -3; if ((int)<request>5__5.result == 1) { try { <json>5__6 = <request>5__5.downloadHandler.text; <results>5__7 = null; if (<json>5__6.TrimStart().StartsWith("{")) { <searchResponse>5__9 = JsonConvert.DeserializeObject<ThunderstoreSearchResponse>(<json>5__6); <results>5__7 = <searchResponse>5__9?.results; <searchResponse>5__9 = null; } else { <results>5__7 = JsonConvert.DeserializeObject<List<ThunderstorePackageV1>>(<json>5__6); } <matchedPkg>5__8 = null; if (<results>5__7 != null) { <>s__10 = <results>5__7.GetEnumerator(); try { while (<>s__10.MoveNext()) { <pkg>5__11 = <>s__10.Current; if (PackageMatchesMod(<pkg>5__11, guid, name)) { <matchedPkg>5__8 = <pkg>5__11; break; } <pkg>5__11 = null; } } finally { ((IDisposable)<>s__10).Dispose(); } <>s__10 = default(List<ThunderstorePackageV1>.Enumerator); } if (<matchedPkg>5__8 != null) { ThunderstoreKnownPackages.Add(<lowerGuid>5__1); <>s__12 = <>4__this.GeneratePossibleGUIDs(<matchedPkg>5__8).GetEnumerator(); try { while (<>s__12.MoveNext()) { <g>5__13 = <>s__12.Current; ThunderstoreKnownPackages.Add(<g>5__13.ToLower()); <g>5__13 = null; } } finally { ((IDisposable)<>s__12).Dispose(); } <>s__12 = default(List<string>.Enumerator); if (AutoWhitelistNewMods.Value && !<matchedPkg>5__8.is_deprecated && !<matchedPkg>5__8.is_flagged) { ServerWhitelistedGUIDs.Add(<lowerGuid>5__1); <>s__14 = <>4__this.GeneratePossibleGUIDs(<matchedPkg>5__8).GetEnumerator(); try { while (<>s__14.MoveNext()) { <g>5__15 = <>s__14.Current; ServerWhitelistedGUIDs.Add(<g>5__15.ToLower()); <g>5__15 = null; } } finally { ((IDisposable)<>s__14).Dispose(); } <>s__14 = default(List<string>.Enumerator); } Log.LogDebug((object)("[HAC] [Background] Verified and cached " + name + " (" + guid + ") v" + version + " on Thunderstore.")); } else { Log.LogWarning((object)("[HAC] [Background] '" + name + "' (" + guid + ") v" + version + " was NOT found on Thunderstore. Treating as unknown.")); if (AutoBlacklistUnknownMods.Value) { <lowerGuidBL>5__16 = guid.ToLower(); if (ServerBlacklistedGUIDs.Add(<lowerGuidBL>5__16)) { <existing>5__17 = BlacklistedModGUIDs.Value?.Trim() ?? ""; BlacklistedModGUIDs.Value = (string.IsNullOrEmpty(<existing>5__17) ? <lowerGuidBL>5__16 : (<existing>5__17 + "," + <lowerGuidBL>5__16)); Log.LogWarning((object)("[HAC] [Background] '" + name + "' (" + guid + ") auto-blacklisted and saved to config.")); <existing>5__17 = null; } <lowerGuidBL>5__16 = null; } } <json>5__6 = null; <results>5__7 = null; <matchedPkg>5__8 = null; } catch (Exception ex) { <ex>5__18 = ex; Log.LogWarning((object)("[HAC] [Background] Parse error for '" + guid + "': " + <ex>5__18.Message)); } } else { Log.LogWarning((object)("[HAC] [Background] Failed to verify '" + name + "' (" + guid + ") against Thunderstore: " + <request>5__5.error)); } <>m__Finally1(); <request>5__5 = null; return false; } } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<request>5__5 != null) { ((IDisposable)<request>5__5).Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <DelayedKick>d__109 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Player player; public string reason; public Main <>4__this; private NetworkConnectionToClient <conn>5__1; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <DelayedKick>d__109(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <conn>5__1 = null; <>1__state = -2; } private bool MoveNext() { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; if ((Object)(object)player != (Object)null) { CodeTalkerNetwork.SendNetworkPacket(player, (BinaryPacketBase)(object)new HAC_KickMessage { Reason = reason }, (CompressionType)0, CompressionLevel.Fastest); <conn>5__1 = ((NetworkBehaviour)player).connectionToClient; <>2__current = (object)new WaitForSeconds(0.5f); <>1__state = 1; return true; } break; case 1: <>1__state = -1; if (<conn>5__1 != null) { ((NetworkConnection)<conn>5__1).Disconnect(); } <conn>5__1 = null; break; } 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 <FetchRemoteDatabaseCoroutine>d__113 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Main <>4__this; private UnityWebRequest <webRequest>5__1; private string <content>5__2; private string[] <lines>5__3; private int <added>5__4; private string[] <>s__5; private int <>s__6; private string <line>5__7; private string <trimmed>5__8; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <FetchRemoteDatabaseCoroutine>d__113(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <webRequest>5__1 = null; <content>5__2 = null; <lines>5__3 = null; <>s__5 = null; <line>5__7 = null; <trimmed>5__8 = null; <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <webRequest>5__1 = UnityWebRequest.Get(RemoteDatabaseURL.Value); <>1__state = -3; <>2__current = <webRequest>5__1.SendWebRequest(); <>1__state = 1; return true; case 1: <>1__state = -3; if (<webRequest>5__1.isNetworkError || <webRequest>5__1.isHttpError) { Log.LogError((object)("[HAC] Failed to fetch remote database: " + <webRequest>5__1.error)); } else { <content>5__2 = <webRequest>5__1.downloadHandler.text; <lines>5__3 = <content>5__2.Split(new char[2] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); <added>5__4 = 0; <>s__5 = <lines>5__3; for (<>s__6 = 0; <>s__6 < <>s__5.Length; <>s__6++) { <line>5__7 = <>s__5[<>s__6]; <trimmed>5__8 = <line>5__7.Trim(); if (!string.IsNullOrEmpty(<trimmed>5__8) && !<trimmed>5__8.StartsWith("//") && !<trimmed>5__8.StartsWith("#")) { ServerBlacklistedGUIDs.Add(<trimmed>5__8); <added>5__4++; } <trimmed>5__8 = null; <line>5__7 = null; } <>s__5 = null; Log.LogInfo((object)$"[HAC] Remote database loaded. Added {<added>5__4} blacklisted mods."); <content>5__2 = null; <lines>5__3 = null; } <>m__Finally1(); <webRequest>5__1 = null; return false; } } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<webRequest>5__1 != null) { ((IDisposable)<webRequest>5__1).Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <FetchThunderstorePackageList>d__95 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Main <>4__this; private string <communityUrl>5__1; private UnityWebRequest <request>5__2; private List<ThunderstorePackageV1> <packages>5__3; private int <deprecatedCount>5__4; private List<ThunderstorePackageV1>.Enumerator <>s__5; private ThunderstorePackageV1 <pkg>5__6; private string <fullName>5__7; private List<string> <possibleGUIDs>5__8; private List<string>.Enumerator <>s__9; private string <guid>5__10; private List<string>.Enumerator <>s__11; private string <guid>5__12; private List<string>.Enumerator <>s__13; private string <guid>5__14; private Exception <ex>5__15; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <FetchThunderstorePackageList>d__95(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <communityUrl>5__1 = null; <request>5__2 = null; <packages>5__3 = null; <>s__5 = default(List<ThunderstorePackageV1>.Enumerator); <pkg>5__6 = null; <fullName>5__7 = null; <possibleGUIDs>5__8 = null; <>s__9 = default(List<string>.Enumerator); <guid>5__10 = null; <>s__11 = default(List<string>.Enumerator); <guid>5__12 = null; <>s__13 = default(List<string>.Enumerator); <guid>5__14 = null; <ex>5__15 = null; <>1__state = -2; } private bool MoveNext() { //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Invalid comparison between Unknown and I4 try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <communityUrl>5__1 = "https://thunderstore.io/c/" + ThunderstoreCommunity.Value + "/api/v1/package/"; <request>5__2 = UnityWebRequest.Get(<communityUrl>5__1); <>1__state = -3; <request>5__2.SetRequestHeader("Accept", "application/json"); <request>5__2.timeout = 15; <>2__current = <request>5__2.SendWebRequest(); <>1__state = 1; return true; case 1: <>1__state = -3; if ((int)<request>5__2.result == 1) { try { <packages>5__3 = JsonConvert.DeserializeObject<List<ThunderstorePackageV1>>(<request>5__2.downloadHandler.text); if (<packages>5__3 != null) { ThunderstoreKnownPackages.Clear(); <deprecatedCount>5__4 = 0; <>s__5 = <packages>5__3.GetEnumerator(); try { while (<>s__5.MoveNext()) { <pkg>5__6 = <>s__5.Current; <fullName>5__7 = <pkg>5__6.full_name ?? (<pkg>5__6.namespace_name + "-" + <pkg>5__6.name); ThunderstoreKnownPackages.Add(<fullName>5__7); <possibleGUIDs>5__8 = <>4__this.GeneratePossibleGUIDs(<pkg>5__6); <>s__9 = <possibleGUIDs>5__8.GetEnumerator(); try { while (<>s__9.MoveNext()) { <guid>5__10 = <>s__9.Current; ThunderstoreKnownPackages.Add(<guid>5__10.ToLower()); <guid>5__10 = null; } } finally { ((IDisposable)<>s__9).Dispose(); } <>s__9 = default(List<string>.Enumerator); if (<pkg>5__6.is_deprecated && BlockDeprecatedMods.Value) { <>s__11 = <possibleGUIDs>5__8.GetEnumerator(); try { while (<>s__11.MoveNext()) { <guid>5__12 = <>s__11.Current; ServerBlacklistedGUIDs.Add(<guid>5__12.ToLower()); <guid>5__12 = null; } } finally { ((IDisposable)<>s__11).Dispose(); } <>s__11 = default(List<string>.Enumerator); ServerBlacklistedGUIDs.Add(<fullName>5__7.ToLower()); <deprecatedCount>5__4++; } if (AutoWhitelistNewMods.Value && !<pkg>5__6.is_deprecated && !<pkg>5__6.is_flagged) { <>s__13 = <possibleGUIDs>5__8.GetEnumerator(); try { while (<>s__13.MoveNext()) { <guid>5__14 = <>s__13.Current; ServerWhitelistedGUIDs.Add(<guid>5__14.ToLower()); <guid>5__14 = null; } } finally { ((IDisposable)<>s__13).Dispose(); } <>s__13 = default(List<string>.Enumerator); } <fullName>5__7 = null; <possibleGUIDs>5__8 = null; <pkg>5__6 = null; } } finally { ((IDisposable)<>s__5).Dispose(); } <>s__5 = default(List<ThunderstorePackageV1>.Enumerator); Log.LogInfo((object)$"[HAC] Thunderstore: {<packages>5__3.Count} packages found, {<deprecatedCount>5__4} deprecated mods auto-blacklisted."); } <packages>5__3 = null; } catch (Exception ex) { <ex>5__15 = ex; Log.LogError((object)("[HAC] Failed to parse Thunderstore package list: " + <ex>5__15.Message)); } } else { Log.LogWarning((object)("[HAC] Failed to fetch Thunderstore package list: " + <request>5__2.error + ". Will retry on next refresh.")); } <>m__Finally1(); <request>5__2 = null; return false; } } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<request>5__2 != null) { ((IDisposable)<request>5__2).Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <InitializeThunderstoreDatabase>d__93 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Main <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <InitializeThunderstoreDatabase>d__93(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; Log.LogInfo((object)"[HAC] Initializing Thunderstore package database..."); <>2__current = ((MonoBehaviour)<>4__this).StartCoroutine(<>4__this.FetchThunderstorePackageList()); <>1__state = 1; return true; case 1: <>1__state = -1; isThunderstoreInitialized = true; Log.LogInfo((object)$"[HAC] Thunderstore database initialized with {ThunderstoreKnownPackages.Count} known packages."); 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 <KickClientAfterDelay>d__108 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Player player; public Main <>4__this; private ulong <steamId>5__1; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <KickClientAfterDelay>d__108(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; if ((Object)(object)player == (Object)null || !ulong.TryParse(player._steamID, out <steamId>5__1)) { return false; } <>2__current = (object)new WaitForSeconds(VerificationTimeout.Value); <>1__state = 1; return true; case 1: <>1__state = -1; if ((Object)(object)player != (Object)null && !VerifiedSteamIDs.Contains(<steamId>5__1) && PendingVerification.ContainsKey(<steamId>5__1)) { if (EnableRequiredMods.Value && ServerRequiredGUIDs.Count > 0) { PunishVerificationFailure(<steamId>5__1, "Handshake Timeout. Required mods are missing."); } else { Log.LogInfo((object)$"[HAC] Client {<steamId>5__1} timed out. Assumed Vanilla. Allowing join."); AuthorizePlayer(<steamId>5__1, PendingVerification[<steamId>5__1]); } } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <SendRequestWithDelay>d__107 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Player player; public ulong steamId; public Main <>4__this; private HAC_ModListRequest <req>5__1; private Coroutine <kickRoutine>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SendRequestWithDelay>d__107(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <req>5__1 = null; <kickRoutine>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 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; if ((Object)(object)player == (Object)null) { return false; } <req>5__1 = new HAC_ModListRequest { TargetSteamID = steamId }; CodeTalkerNetwork.SendNetworkPacket(player, (BinaryPacketBase)(object)<req>5__1, (CompressionType)0, CompressionLevel.Fastest); <kickRoutine>5__2 = ((MonoBehaviour)<>4__this).StartCoroutine(<>4__this.KickClientAfterDelay(player)); PendingVerification[steamId] = <kickRoutine>5__2; 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 <StaggeredBackgroundVerify>d__97 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public List<(string guid, string name, string version)> mods; public Main <>4__this; private List<(string guid, string name, string version)>.Enumerator <>s__1; private string <guid>5__2; private string <name>5__3; private string <version>5__4; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <StaggeredBackgroundVerify>d__97(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || (uint)(num - 1) <= 1u) { try { } finally { <>m__Finally1(); } } <>s__1 = default(List<(string, string, string)>.Enumerator); <guid>5__2 = null; <name>5__3 = null; <version>5__4 = null; <>1__state = -2; } private bool MoveNext() { //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>s__1 = mods.GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; <>2__current = (object)new WaitForSeconds(0.75f); <>1__state = 2; return true; case 2: <>1__state = -3; <guid>5__2 = null; <name>5__3 = null; <version>5__4 = null; break; } if (<>s__1.MoveNext()) { (string, string, string) current = <>s__1.Current; <guid>5__2 = current.Item1; <name>5__3 = current.Item2; <version>5__4 = current.Item3; <>2__current = ((MonoBehaviour)<>4__this).StartCoroutine(<>4__this.BackgroundVerifyModAsync(<guid>5__2, <name>5__3, <version>5__4)); <>1__state = 1; return true; } <>m__Finally1(); <>s__1 = default(List<(string, string, string)>.Enumerator); return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; ((IDisposable)<>s__1).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <VerifyClientModsWithThunderstore>d__104 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public ulong steamId; public List<string> guids; public List<string> names; public List<string> versions; public Coroutine timeoutCoroutine; public Main <>4__this; private <>c__DisplayClass104_0 <>8__1; private Dictionary<string, (string name, string version)> <modInfoMap>5__2; private List<string> <unauthorizedMods>5__3; private List<string> <unknownMods>5__4; private int <i>5__5; private List<string>.Enumerator <>s__6; private string <guid>5__7; private string <lowerGuid>5__8; private string <displayName>5__9; private (string name, string version) <info>5__10; private List<string> <missingMods>5__11; private List<(string guid, string name, string version)> <parsedMods>5__12; private List<string>.Enumerator <>s__13; private string <unknownDisplay>5__14; private string <guid>5__15; private string <name>5__16; private string <version>5__17; private int <start>5__18; private int <end>5__19; private int <vIdx>5__20; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <VerifyClientModsWithThunderstore>d__104(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>8__1 = null; <modInfoMap>5__2 = null; <unauthorizedMods>5__3 = null; <unknownMods>5__4 = null; <>s__6 = default(List<string>.Enumerator); <guid>5__7 = null; <lowerGuid>5__8 = null; <displayName>5__9 = null; <info>5__10 = default((string, string)); <missingMods>5__11 = null; <parsedMods>5__12 = null; <>s__13 = default(List<string>.Enumerator); <unknownDisplay>5__14 = null; <guid>5__15 = null; <name>5__16 = null; <version>5__17 = null; <>1__state = -2; } private bool MoveNext() { if (<>1__state != 0) { return false; } <>1__state = -1; <>8__1 = new <>c__DisplayClass104_0(); <>8__1.guids = guids; if (<>8__1.guids == null || <>8__1.guids.Count == 0) { Log.LogInfo((object)$"[HAC] Client {steamId} reported 0 mods. Vanilla client authorized."); AuthorizePlayer(steamId, timeoutCoroutine); return false; } <modInfoMap>5__2 = new Dictionary<string, (string, string)>(); <i>5__5 = 0; while (<i>5__5 < <>8__1.guids.Count) { if (!string.IsNullOrEmpty(<>8__1.guids[<i>5__5])) { <modInfoMap>5__2[<>8__1.guids[<i>5__5].ToLower()] = (names[<i>5__5], versions[<i>5__5]); } <i>5__5++; } <unauthorizedMods>5__3 = new List<string>(); <unknownMods>5__4 = new List<string>(); <>s__6 = <>8__1.guids.GetEnumerator(); try { while (<>s__6.MoveNext()) { <guid>5__7 = <>s__6.Current; <lowerGuid>5__8 = <guid>5__7.ToLower(); if (string.IsNullOrEmpty(<lowerGuid>5__8) || ServerWhitelistedGUIDs.Contains(<lowerGuid>5__8) || ServerRequiredGUIDs.Contains(<guid>5__7)) { continue; } <displayName>5__9 = (<modInfoMap>5__2.TryGetValue(<lowerGuid>5__8, out <info>5__10) ? (<info>5__10.name + " (" + <guid>5__7 + ") v" + <info>5__10.version) : <guid>5__7); if (EnableModBlacklist.Value && ServerBlacklistedGUIDs.Contains(<lowerGuid>5__8)) { <unauthorizedMods>5__3.Add(<displayName>5__9); continue; } if (EnableThunderstoreWhitelist.Value) { if ((isThunderstoreInitialized && ThunderstoreKnownPackages.Contains(<lowerGuid>5__8)) || !isThunderstoreInitialized) { continue; } <unknownMods>5__4.Add(<displayName>5__9); } else if (EnableModWhitelist.Value && !ServerWhitelistedGUIDs.Contains(<lowerGuid>5__8)) { <unauthorizedMods>5__3.Add(<displayName>5__9); } <lowerGuid>5__8 = null; <displayName>5__9 = null; <info>5__10 = default((string, string)); <guid>5__7 = null; } } finally { ((IDisposable)<>s__6).Dispose(); } <>s__6 = default(List<string>.Enumerator); if (<unauthorizedMods>5__3.Any()) { PunishVerificationFailure(steamId, "Unauthorized/Blacklisted Mods Detected: " + string.Join(", ", <unauthorizedMods>5__3.Take(3))); return false; } if (EnableRequiredMods.Value) { <missingMods>5__11 = ServerRequiredGUIDs.Where((string req) => !<>8__1.guids.Contains(req)).ToList(); if (<missingMods>5__11.Any()) { PunishVerificationFailure(steamId, "Missing Required Mods: " + string.Join(", ", <missingMods>5__11.Take(3))); return false; } <missingMods>5__11 = null; } if (<unknownMods>5__4.Any() && isThunderstoreInitialized) { <parsedMods>5__12 = new List<(string, string, string)>(); <>s__13 = <unknownMods>5__4.GetEnumerator(); try { while (<>s__13.MoveNext()) { <unknownDisplay>5__14 = <>s__13.Current; <guid>5__15 = <unknownDisplay>5__14; <name>5__16 = "Unknown"; <version>5__17 = "?"; <start>5__18 = <unknownDisplay>5__14.IndexOf('('); if (<start>5__18 > 0) { <name>5__16 = <unknownDisplay>5__14.Substring(0, <start>5__18).Trim(); <end>5__19 = <unknownDisplay>5__14.IndexOf(')', <start>5__18); if (<end>5__19 > <start>5__18) { <guid>5__15 = <unknownDisplay>5__14.Substring(<start>5__18 + 1, <end>5__19 - <start>5__18 - 1); <vIdx>5__20 = <unknownDisplay>5__14.IndexOf(" v", <end>5__19); if (<vIdx>5__20 > <end>5__19) { <version>5__17 = <unknownDisplay>5__14.Substring(<vIdx>5__20 + 2).Trim(); } } } <parsedMods>5__12.Add((<guid>5__15, <name>5__16, <version>5__17)); <guid>5__15 = null; <name>5__16 = null; <version>5__17 = null; <unknownDisplay>5__14 = null; } } finally { ((IDisposable)<>s__13).Dispose(); } <>s__13 = default(List<string>.Enumerator); Log.LogInfo((object)$"[HAC] Player authorized. {<parsedMods>5__12.Count} mods queued for background Thunderstore verification."); ((MonoBehaviour)Instance).StartCoroutine(<>4__this.StaggeredBackgroundVerify(<parsedMods>5__12)); <parsedMods>5__12 = null; } AuthorizePlayer(steamId, timeoutCoroutine); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private 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<string> BannedSteamIDs; public static ConfigEntry<bool> EnableRequiredMods; public static ConfigEntry<string> RequiredModGUIDs; public static ConfigEntry<bool> EnableModBlacklist; public static ConfigEntry<string> BlacklistedModGUIDs; public static ConfigEntry<bool> EnableModWhitelist; public static ConfigEntry<string> WhitelistedModGUIDs; public static ConfigEntry<bool> EnableRemoteDatabase; public static ConfigEntry<string> RemoteDatabaseURL; public static ConfigEntry<bool> EnableThunderstoreWhitelist; public static ConfigEntry<string> ThunderstoreCommunity; public static ConfigEntry<bool> BlockDeprecatedMods; public static ConfigEntry<float> ThunderstoreRefreshInterval; public static ConfigEntry<float> ThunderstoreCacheTimeout; public static ConfigEntry<bool> AutoWhitelistNewMods; public static ConfigEntry<bool> AutoBlacklistUnknownMods; public static ConfigEntry<float> UnknownModGracePeriod; 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<ulong> ServerBannedUsers = new HashSet<ulong>(); private static readonly HashSet<string> ServerRequiredGUIDs = new HashSet<string>(); private static readonly HashSet<string> ServerBlacklistedGUIDs = new HashSet<string>(); private static readonly HashSet<string> ServerWhitelistedGUIDs = new HashSet<string>(); private static readonly Dictionary<string, ThunderstoreModCache> ThunderstoreCache = new Dictionary<string, ThunderstoreModCache>(); private static readonly HashSet<string> ThunderstoreKnownPackages = new HashSet<string>(); private static readonly Dictionary<string, DateTime> PendingUnknownMods = new Dictionary<string, DateTime>(); private static Coroutine thunderstoreRefreshCoroutine; private static bool isThunderstoreInitialized = false; 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, int> ServerRunningXpTotal = new Dictionary<uint, 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>(); private static readonly Dictionary<string, string> KnownModAliases = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) { { "CodeTalker", "CodeYapper" } }; public static Main Instance { get; private set; } private void Awake() { //IL_068b: Unknown result type (might be due to invalid IL or missing references) //IL_0695: 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."); BannedSteamIDs = ((BaseUnityPlugin)this).Config.Bind<string>("1. General", "Banned SteamIDs", "", "Comma-separated list of SteamIDs that are banned from joining."); 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."); EnableRequiredMods = ((BaseUnityPlugin)this).Config.Bind<bool>("2. Mod Lists", "Enable Required Mods", false, "If true, clients MUST have the mods listed in Required Mod GUIDs."); RequiredModGUIDs = ((BaseUnityPlugin)this).Config.Bind<string>("2. Mod Lists", "Required Mod GUIDs", "", "Comma-separated list of Mod GUIDs that clients must have."); EnableModBlacklist = ((BaseUnityPlugin)this).Config.Bind<bool>("2. Mod Lists", "Enable Mod Blacklist", false, "If true, clients sending a mod GUID found in the Blacklist will be kicked."); BlacklistedModGUIDs = ((BaseUnityPlugin)this).Config.Bind<string>("2. Mod Lists", "Blacklisted Mod GUIDs", "com.cheat.menu,another.bad.mod", "Comma-separated list of Mod GUIDs that are strictly forbidden."); EnableModWhitelist = ((BaseUnityPlugin)this).Config.Bind<bool>("2. Mod Lists", "Enable Mod Whitelist", false, "If true, ONLY mods in the Whitelist are allowed."); WhitelistedModGUIDs = ((BaseUnityPlugin)this).Config.Bind<string>("2. Mod Lists", "Whitelisted Mod GUIDs", "", "Comma-separated list of Mod GUIDs that are permitted."); EnableRemoteDatabase = ((BaseUnityPlugin)this).Config.Bind<bool>("3. Remote Database", "Enable Remote Blacklist DB", false, "Fetch a list of blacklisted mods from a URL."); RemoteDatabaseURL = ((BaseUnityPlugin)this).Config.Bind<string>("3. Remote Database", "Remote Blacklist DB URL", "", "URL to a raw text file containing blacklisted Mod GUIDs."); EnableThunderstoreWhitelist = ((BaseUnityPlugin)this).Config.Bind<bool>("4. Thunderstore", "Enable Thunderstore Whitelist", false, "Automatically whitelist all mods published on Thunderstore."); ThunderstoreCommunity = ((BaseUnityPlugin)this).Config.Bind<string>("4. Thunderstore", "Community Identifier", "atlyss", "Thunderstore community to fetch packages from."); BlockDeprecatedMods = ((BaseUnityPlugin)this).Config.Bind<bool>("4. Thunderstore", "Block Deprecated Mods", true, "Automatically block mods that are deprecated on Thunderstore."); ThunderstoreRefreshInterval = ((BaseUnityPlugin)this).Config.Bind<float>("4. Thunderstore", "Refresh Interval (Minutes)", 30f, "How often to refresh the Thunderstore package list."); ThunderstoreCacheTimeout = ((BaseUnityPlugin)this).Config.Bind<float>("4. Thunderstore", "Cache Timeout (Hours)", 6f, "How long to cache individual package verification results."); AutoWhitelistNewMods = ((BaseUnityPlugin)this).Config.Bind<bool>("4. Thunderstore", "Auto-Whitelist New Mods", true, "Automatically add newly discovered Thunderstore mods to the whitelist."); AutoBlacklistUnknownMods = ((BaseUnityPlugin)this).Config.Bind<bool>("4. Thunderstore", "Auto-Blacklist Unknown Mods", true, "Automatically blacklist mods that cannot be verified on Thunderstore. Persists across restarts."); UnknownModGracePeriod = ((BaseUnityPlugin)this).Config.Bind<float>("4. Thunderstore", "Unknown Mod Grace Period", 30f, "Seconds to wait before kicking for unknown mods."); VerificationTimeout = ((BaseUnityPlugin)this).Config.Bind<float>("5. Handshake", "Verification Timeout", 25f, "Seconds to wait for client mod list before kicking."); EnableMovementChecks = ((BaseUnityPlugin)this).Config.Bind<bool>("6. Movement", "Enable Teleport Checks", true, "Checks movement distance."); MaxEffectiveSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("6. Movement", "Max Effective Speed", 100f, "Max plausible speed."); MovementGraceBuffer = ((BaseUnityPlugin)this).Config.Bind<float>("6. Movement", "Movement Grace Buffer", 10f, "Distance buffer."); MovementTimeThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("6. Movement", "Movement Time Threshold", 5.5f, "Time between checks."); TeleportDistanceThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("6. Movement", "Teleport Threshold", 50f, "Distance to log as teleport."); EnableAirborneChecks = ((BaseUnityPlugin)this).Config.Bind<bool>("6. Movement", "Enable Fly Checks", true, "Checks airtime."); EnableSpeedChecks = ((BaseUnityPlugin)this).Config.Bind<bool>("6. Movement", "Enable Speed Stat Checks", true, "Checks base move speed."); JumpThreshold = ((BaseUnityPlugin)this).Config.Bind<int>("6. Movement", "Jump Threshold", 8, "Max jumps allowed."); SpeedHackDetectionCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("6. Movement", "Speed Check Cooldown", 2f, "Log cooldown."); JumpHackDetectionCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("6. Movement", "Jump Check Cooldown", 2f, "Log cooldown."); AirborneHackDetectionCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("6. Movement", "Airborne Check Cooldown", 10f, "Log cooldown."); EnableExperienceChecks = ((BaseUnityPlugin)this).Config.Bind<bool>("7. Stats", "Enable XP Checks", true, "Checks XP gain."); MaxPlausibleXPGain = ((BaseUnityPlugin)this).Config.Bind<int>("7. Stats", "Max XP Gain", 1000000, "Max XP in one go."); MaxXPGainPerWindow = ((BaseUnityPlugin)this).Config.Bind<int>("7. Stats", "Max XP Rate", 5000000, "Max XP over time."); XPGainWindowSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("7. Stats", "XP Window", 30f, "Time window for XP rate."); EnableCooldownChecks = ((BaseUnityPlugin)this).Config.Bind<bool>("8. Combat", "Enable Cooldown Checks", true, "Enforce skill cooldowns."); EnableReviveChecks = ((BaseUnityPlugin)this).Config.Bind<bool>("8. Combat", "Enable Revive Checks", true, "Prevent self-revive."); EnableSpamChecks = ((BaseUnityPlugin)this).Config.Bind<bool>("8. Combat", "Enable Spam Checks", true, "Prevents macro-spamming items/swaps/blocking."); MinConsumableInterval = ((BaseUnityPlugin)this).Config.Bind<float>("8. Combat", "Min Consumable Interval", 0.4f, "Min seconds between using items."); MinWeaponSwapInterval = ((BaseUnityPlugin)this).Config.Bind<float>("8. Combat", "Min Weapon Swap Interval", 0.25f, "Min seconds between switching weapons."); MinBlockInterval = ((BaseUnityPlugin)this).Config.Bind<float>("8. Combat", "Min Block Interval", 0.1f, "Min seconds between block inputs."); EnablePunishmentSystem = ((BaseUnityPlugin)this).Config.Bind<bool>("9. Punishment", "Enable Auto-Punish", true, "Kick/Ban on infractions."); WarningsUntilAction = ((BaseUnityPlugin)this).Config.Bind<int>("9. Punishment", "Infractions Limit", 5, "Warnings before action."); ActionType = ((BaseUnityPlugin)this).Config.Bind<string>("9. 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>("10. Logging", "Enable Detailed Logs", true, "Log details."); LogPlayerName = ((BaseUnityPlugin)this).Config.Bind<bool>("10. Logging", "Log Name", true, ""); LogPlayerID = ((BaseUnityPlugin)this).Config.Bind<bool>("10. Logging", "Log ID", true, ""); LogInfractionCount = ((BaseUnityPlugin)this).Config.Bind<bool>("10. Logging", "Log Count", true, ""); LogInfractionDetails = ((BaseUnityPlugin)this).Config.Bind<bool>("10. Logging", "Log Details", true, ""); CheckAndArchiveLogFile(); ParseTrustedSteamIDs(); ParseBannedSteamIDs(); ParseRequiredMods(); ParseBlacklistedMods(); ParseWhitelistedMods(); if (EnableRemoteDatabase.Value) { FetchRemoteDatabase(); } TrustedSteamIDs.SettingChanged += delegate { ParseTrustedSteamIDs(); }; BannedSteamIDs.SettingChanged += delegate { ParseBannedSteamIDs(); }; RequiredModGUIDs.SettingChanged += delegate { ParseRequiredMods(); }; BlacklistedModGUIDs.SettingChanged += delegate { ParseBlacklistedMods(); }; WhitelistedModGUIDs.SettingChanged += delegate { ParseWhitelistedMods(); }; RemoteDatabaseURL.SettingChanged += delegate { if (EnableRemoteDatabase.Value) { FetchRemoteDatabase(); } }; EnableThunderstoreWhitelist.SettingChanged += delegate { if (EnableThunderstoreWhitelist.Value) { StartThunderstoreIntegration(); } }; InitEasySettingsSafe(); harmony.PatchAll(); Log.LogInfo((object)string.Format("[{0}] loaded. ReqList: {1} | Blacklist: {2} | Whitelist: {3} | Thunderstore: {4}", "HardAntiCheat", EnableRequiredMods.Value, EnableModBlacklist.Value, EnableModWhitelist.Value, EnableThunderstoreWhitelist.Value)); } private void Start() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown //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_005e: Expected O, but got Unknown object obj = <>O.<0>__OnClientReceivedRequest; if (obj == null) { BinaryPacketListener val = OnClientReceivedRequest; <>O.<0>__OnClientReceivedRequest = val; obj = (object)val; } CodeTalkerNetwork.RegisterBinaryListener<HAC_ModListRequest>((BinaryPacketListener)obj); object obj2 = <>O.<1>__OnReceivedResponse; if (obj2 == null) { BinaryPacketListener val2 = OnReceivedResponse; <>O.<1>__OnReceivedResponse = val2; obj2 = (object)val2; } CodeTalkerNetwork.RegisterBinaryListener<HAC_ModListResponse>((BinaryPacketListener)obj2); object obj3 = <>O.<2>__OnClientReceivedKickMessage; if (obj3 == null) { BinaryPacketListener val3 = OnClientReceivedKickMessage; <>O.<2>__OnClientReceivedKickMessage = val3; obj3 = (object)val3; } CodeTalkerNetwork.RegisterBinaryListener<HAC_KickMessage>((BinaryPacketListener)obj3); if (EnableThunderstoreWhitelist.Value && !isThunderstoreInitialized) { Log.LogInfo((object)"[HAC] Pre-warming Thunderstore cache..."); StartThunderstoreIntegration(); } } private void StartThunderstoreIntegration() { if (EnableThunderstoreWhitelist.Value) { if (thunderstoreRefreshCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(thunderstoreRefreshCoroutine); } thunderstoreRefreshCoroutine = ((MonoBehaviour)this).StartCoroutine(InitializeThunderstoreDatabase()); ((MonoBehaviour)this).StartCoroutine(AutoRefreshThunderstoreDatabase()); } } [IteratorStateMachine(typeof(<InitializeThunderstoreDatabase>d__93))] private IEnumerator InitializeThunderstoreDatabase() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <InitializeThunderstoreDatabase>d__93(0) { <>4__this = this }; } [IteratorStateMachine(typeof(<AutoRefreshThunderstoreDatabase>d__94))] private IEnumerator AutoRefreshThunderstoreDatabase() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <AutoRefreshThunderstoreDatabase>d__94(0) { <>4__this = this }; } [IteratorStateMachine(typeof(<FetchThunderstorePackageList>d__95))] private IEnumerator FetchThunderstorePackageList() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <FetchThunderstorePackageList>d__95(0) { <>4__this = this }; } private List<string> GeneratePossibleGUIDs(ThunderstorePackageV1 pkg) { List<string> list = new List<string>(); string text = (pkg.namespace_name ?? pkg.owner ?? "").Replace("-", ".").Replace(" ", ""); string text2 = (pkg.name ?? "").Replace("-", ".").Replace(" ", ""); if (string.IsNullOrEmpty(text) || string.IsNullOrEmpty(text2)) { return list; } list.Add(text + "." + text2); list.Add("com." + text + "." + text2); list.Add("org." + text + "." + text2); list.Add((text + "." + text2).ToLower()); list.Add(text + "-" + text2); if (!string.IsNullOrEmpty(pkg.full_name)) { list.Add(pkg.full_name); list.Add(pkg.full_name.Replace("-", ".")); } return list.Distinct().ToList(); } [IteratorStateMachine(typeof(<StaggeredBackgroundVerify>d__97))] private IEnumerator StaggeredBackgroundVerify(List<(string guid, string name, string version)> mods) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <StaggeredBackgroundVerify>d__97(0) { <>4__this = this, mods = mods }; } private static string NormalizeForMatch(string s) { if (string.IsNullOrEmpty(s)) { return ""; } return s.ToLower().Replace(" ", "").Replace("_", "") .Replace("-", "") .Replace(".", ""); } private static bool PackageMatchesMod(ThunderstorePackageV1 pkg, string guid, string displayName) { string text = NormalizeForMatch(displayName); string text2 = NormalizeForMatch(guid); string text3 = NormalizeForMatch(pkg.name ?? ""); string text4 = NormalizeForMatch(pkg.full_name ?? ""); string text5 = NormalizeForMatch(pkg.namespace_name ?? pkg.owner ?? ""); if (!string.IsNullOrEmpty(text) && text == text3) { return true; } if (!string.IsNullOrEmpty(text) && text.Length >= 4 && (text4.Contains(text) || (text.Contains(text3) && text3.Length >= 4))) { return true; } if (!string.IsNullOrEmpty(text3) && text3.Length >= 4 && text2.Contains(text3)) { return true; } if (!string.IsNullOrEmpty(text5) && text5.Length >= 4 && text2.Contains(text5)) { return true; } if ((KnownModAliases.TryGetValue(displayName, out string value) || KnownModAliases.TryGetValue(guid, out value)) && NormalizeForMatch(value) == text3) { return true; } return false; } [IteratorStateMachine(typeof(<BackgroundVerifyModAsync>d__101))] private IEnumerator BackgroundVerifyModAsync(string guid, string name, string version) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <BackgroundVerifyModAsync>d__101(0) { <>4__this = this, guid = guid, name = name, version = version }; } 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) { return; } List<string> list = new List<string>(); List<string> list2 = new List<string>(); List<string> list3 = new List<string>(); foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos) { list.Add(pluginInfo.Key); list2.Add(pluginInfo.Value.Metadata.Name); list3.Add(pluginInfo.Value.Metadata.Version.ToString()); } HAC_ModListResponse hAC_ModListResponse = new HAC_ModListResponse { ClientModGUIDs = list, ClientModNames = list2, ClientModVersions = list3 }; CodeTalkerNetwork.SendNetworkPacket(header.SenderID, (BinaryPacketBase)(object)hAC_ModListResponse, (CompressionType)0, CompressionLevel.Fastest); } public static void OnReceivedResponse(PacketHeader header, BinaryPacketBase packet) { if (!(packet is HAC_ModListResponse hAC_ModListResponse)) { return; } ulong senderID = header.SenderID; if (NetworkServer.active) { if (PendingVerification.TryGetValue(senderID, out Coroutine value)) { ((MonoBehaviour)Instance).StartCoroutine(Instance.VerifyClientModsWithThunderstore(senderID, hAC_ModListResponse.ClientModGUIDs ?? new List<string>(), hAC_ModListResponse.ClientModNames ?? new List<string>(), hAC_ModListResponse.ClientModVersions ?? new List<string>(), value)); } } else { if (!EnableModBlacklist.Value) { return; } Player val = ((IEnumerable<Player>)Object.FindObjectsOfType<Player>()).FirstOrDefault((Func<Player, bool>)((Player p) => p._isHostPlayer)); if (!((Object)(object)val != (Object)null) || !(val._steamID == senderID.ToString())) { return; } List<string> source = hAC_ModListResponse.ClientModGUIDs ?? new List<string>(); List<string> list = source.Where((string m) => ServerBlacklistedGUIDs.Contains(m)).ToList(); if (list.Any()) { Log.LogWarning((object)("[HAC] Host is using blacklisted mods: " + string.Join(", ", list) + ". Disconnecting for safety.")); if ((Object)(object)ChatBehaviour._current != (Object)null) { ChatBehaviour._current.New_ChatMessage("<color=red><b>[HAC] Disconnected:</b> Host is using blacklisted mods!</color>"); } if (NetworkClient.active) { NetworkClient.Disconnect(); } } } } [IteratorStateMachine(typeof(<VerifyClientModsWithThunderstore>d__104))] private IEnumerator VerifyClientModsWithThunderstore(ulong steamId, List<string> guids, List<string> names, List<string> versions, Coroutine timeoutCoroutine) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <VerifyClientModsWithThunderstore>d__104(0) { <>4__this = this, steamId = steamId, guids = guids, names = names, versions = versions, timeoutCoroutine = timeoutCoroutine }; } public static void OnClientReceivedKickMessage(PacketHeader header, BinaryPacketBase packet) { if (packet is HAC_KickMessage hAC_KickMessage) { Log.LogWarning((object)("[HAC] Kicked by server. Reason: " + hAC_KickMessage.Reason)); if ((Object)(object)ChatBehaviour._current != (Object)null) { ChatBehaviour._current.New_ChatMessage("<color=red><b>[HAC] Kicked by Server:</b> " + hAC_KickMessage.Reason + "</color>"); } } } 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); } [IteratorStateMachine(typeof(<SendRequestWithDelay>d__107))] public IEnumerator SendRequestWithDelay(Player player, ulong steamId) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <SendRequestWithDelay>d__107(0) { <>4__this = this, player = player, steamId = steamId }; } [IteratorStateMachine(typeof(<KickClientAfterDelay>d__108))] public IEnumerator KickClientAfterDelay(Player player) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <KickClientAfterDelay>d__108(0) { <>4__this = this, player = player }; } [IteratorStateMachine(typeof(<DelayedKick>d__109))] public IEnumerator DelayedKick(Player player, string reason) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <DelayedKick>d__109(0) { <>4__this = this, player = player, reason = reason }; } public static void BroadcastServerMessage(string message) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) if (NetworkServer.active) { string text = ((message.Length > 120) ? (message.Substring(0, 120) + "...") : message); text = text.Replace("<", "").Replace(">", ""); ServerMessage val = default(ServerMessage); val.servMsg = "[HAC] " + text; ServerMessage val2 = val; NetworkServer.SendToAll<ServerMessage>(val2, 0, false); } } private static void PunishVerificationFailure(ulong steamId, string reason) { if (PendingVerification.TryGetValue(steamId, out Coroutine value)) { if ((Object)(object)Instance != (Object)null && value != 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) { string text = playerBySteamID._nickname ?? "Unknown"; Log.LogWarning((object)("[HAC] Kicking " + text + ". Reason: " + reason)); BroadcastServerMessage(text + " was kicked: " + reason); if ((Object)(object)HostConsole._current != (Object)null) { HostConsole._current.Init_ServerMessage("[HAC]: Kicked " + text + ". " + reason); } ((MonoBehaviour)Instance).StartCoroutine(Instance.DelayedKick(playerBySteamID, reason)); } } public void FetchRemoteDatabase() { if (EnableRemoteDatabase.Value && !string.IsNullOrWhiteSpace(RemoteDatabaseURL.Value)) { ((MonoBehaviour)this).StartCoroutine(FetchRemoteDatabaseCoroutine()); } } [IteratorStateMachine(typeof(<FetchRemoteDatabaseCoroutine>d__113))] private IEnumerator FetchRemoteDatabaseCoroutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <FetchRemoteDatabaseCoroutine>d__113(0) { <>4__this = this }; } private void InitEasySettingsSafe() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown Settings.OnInitialized.AddListener(new UnityAction(AddSettings)); Settings.OnApplySettings.AddListener((UnityAction)delegate { ((BaseUnityPlugin)this).Config.Reload(); ((BaseUnityPlugin)this).Config.Save(); ParseTrustedSteamIDs(); ParseBannedSteamIDs(); ParseRequiredMods(); ParseBlacklistedMods(); ParseWhitelistedMods(); if (EnableRemoteDatabase.Value) { FetchRemoteDatabase(); } if (EnableThunderstoreWhitelist.Value) { StartThunderstoreIntegration(); } Log.LogInfo((object)"[HAC] Settings applied and reloaded successfully."); }); } private void AddSettings() { SettingsTab orAddCustomTab = Settings.GetOrAddCustomTab("HardAntiCheat"); orAddCustomTab.AddHeader("General"); orAddCustomTab.AddToggle(EnableAntiCheat); orAddCustomTab.AddToggle(DisableForHost); orAddCustomTab.AddTextField(TrustedSteamIDs, "Text..."); orAddCustomTab.AddTextField(BannedSteamIDs, "Text..."); orAddCustomTab.AddSlider(VerificationTimeout, false); orAddCustomTab.AddHeader("Mod Lists"); orAddCustomTab.AddToggle(EnableRequiredMods); orAddCustomTab.AddTextField(RequiredModGUIDs, "Text..."); orAddCustomTab.AddToggle(EnableModBlacklist); orAddCustomTab.AddTextField(BlacklistedModGUIDs, "Text..."); orAddCustomTab.AddToggle(EnableModWhitelist); orAddCustomTab.AddTextField(WhitelistedModGUIDs, "Text..."); orAddCustomTab.AddHeader("Thunderstore Integration"); orAddCustomTab.AddToggle(EnableThunderstoreWhitelist); orAddCustomTab.AddTextField(ThunderstoreCommunity, "Text..."); orAddCustomTab.AddToggle(BlockDeprecatedMods); orAddCustomTab.AddToggle(AutoWhitelistNewMods); orAddCustomTab.AddToggle(AutoBlacklistUnknownMods); orAddCustomTab.AddAdvancedSlider(ThunderstoreRefreshInterval, false); orAddCustomTab.AddAdvancedSlider(UnknownModGracePeriod, false); orAddCustomTab.AddHeader("Remote Database"); orAddCustomTab.AddToggle(EnableRemoteDatabase); orAddCustomTab.AddTextField(RemoteDatabaseURL, "Text..."); orAddCustomTab.AddHeader("Movement Detection"); orAddCustomTab.AddToggle(EnableMovementChecks); orAddCustomTab.AddSlider(MaxEffectiveSpeed, false); orAddCustomTab.AddSlider(TeleportDistanceThreshold, false); orAddCustomTab.AddToggle(EnableAirborneChecks); orAddCustomTab.AddToggle(EnableSpeedChecks); orAddCustomTab.AddAdvancedSlider(JumpThreshold); orAddCustomTab.AddHeader("Combat & Stats"); orAddCustomTab.AddToggle(EnableExperienceChecks); orAddCustomTab.AddToggle(EnableCooldownChecks); orAddCustomTab.AddToggle(EnableReviveChecks); orAddCustomTab.AddToggle(EnableSpamChecks); orAddCustomTab.AddSlider(MinBlockInterval, false); orAddCustomTab.AddHeader("Punishment"); orAddCustomTab.AddToggle(EnablePunishmentSystem); orAddCustomTab.AddAdvancedSlider(WarningsUntilAction); string[] actions = new string[2] { "Kick", "Ban" }; int num = ((ActionType.Value == "Ban") ? 1 : 0); AtlyssDropdown val2 = orAddCustomTab.AddDropdown("Action Type", actions, num); val2.OnValueChanged.AddListener((UnityAction<int>)delegate(int val) { ActionType.Value = actions[val]; }); orAddCustomTab.AddHeader("Logging"); orAddCustomTab.AddToggle(EnableDetailedLogs); } 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.ToLower()); } } } Log.LogInfo((object)$"[HAC] Blacklist updated. {ServerBlacklistedGUIDs.Count} mods banned."); } private static void ParseWhitelistedMods() { ServerWhitelistedGUIDs.Clear(); string value = WhitelistedModGUIDs.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)) { ServerWhitelistedGUIDs.Add(text2.ToLower()); } } } Log.LogInfo((object)$"[HAC] Whitelist updated. {ServerWhitelistedGUIDs.Count} mods permitted."); } private static void ParseRequiredMods() { ServerRequiredGUIDs.Clear(); string value = RequiredModGUIDs.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)) { ServerRequiredGUIDs.Add(text2.ToLower()); } } } Log.LogInfo((object)$"[HAC] Required mods updated. {ServerRequiredGUIDs.Count} mods required."); } 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); } } } private static void ParseBannedSteamIDs() { ServerBannedUsers.Clear(); string value = BannedSteamIDs.Value; if (!string.IsNullOrWhiteSpace(value)) { string[] array = value.Split(','); string[] array2 = array; foreach (string text in array2) { if (ulong.TryParse(text.Trim(), out var result)) { ServerBannedUsers.Add(result); } } } Log.LogInfo((object)$"[HAC] Banned users updated. {ServerBannedUsers.Count} users banned."); } 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; } public static bool IsPlayerBanned(ulong steamId) { return ServerBannedUsers.Contains(steamId); } 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) { File.Move(InfractionLogPath, Path.Combine(Path.GetDirectoryName(InfractionLogPath), $"{Path.GetFileNameWithoutExtension(InfractionLogPath)}_ARCHIVED_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.txt")); } } } 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."; BroadcastServerMessage($"{text} was {text3}ed for {num} infractions"); Log.LogWarning((object)text4); string capturedPunishment = text4; Task.Run(delegate { try { File.AppendAllText(InfractionLogPath, $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] [PUNISHMENT] " + capturedPunishment + Environment.NewLine); } catch { } }); if ((Object)(object)HostConsole._current != (Object)null) { HostConsole._current.Init_ServerMessage("[HAC]: " + text4); } if (text3 == "kick") { ((MonoBehaviour)Instance).StartCoroutine(Instance.DelayedKick(component, text4)); } 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) { CodeTalkerNetwork.SendNetworkPacket(component, (BinaryPacketBase)(object)new HAC_KickMessage { Reason = text4 }, (CompressionType)0, CompressionLevel.Fastest); HostConsole._current._selectedPeerEntry = val; HostConsole._current.Ban_Peer(); } else { ((MonoBehaviour)Instance).StartCoroutine(Instance.DelayedKick(component, text4)); Log.LogError((object)$"Could not find PeerListEntry for player {text} (netId: {netId}) to BAN, kicked instead."); } } ServerPlayerInfractionCount.Remove(netId); } else { if (!EnableDetailedLogs.Value) { return; } 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 logMessage = stringBuilder.ToString(); Log.LogWarning((object)logMessage); Task.Run(delegate { try { File.AppendAllText(InfractionLogPath, logMessage + Environment.NewLine); } catch { } }); } } public static void ClearAllPlayerData(uint netId, ulong steamId) { ServerRemainingCooldowns.Remove(netId); ServerPlayerPositions.Remove(netId); ServerPlayerStats.Remove(netId); XpGainHistory.Remove(netId); ServerRunningXpTotal.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 && value != 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_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) uint netId = ((NetworkBehaviour)__instance).netId; Player component = ((Component)__instance).GetComponent<Player>(); ulong result2; if (NetworkServer.active) { 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 ((Object)(object)component != (Object)null && !((NetworkBehaviour)component).isLocalPlayer && ulong.TryParse(component._steamID, out var result)) { if (Main.IsPlayerBanned(result)) { Main.Log.LogInfo((object)$"Player {component._nickname} ({result}) is on the banned list. Kicking immediately."); ((MonoBehaviour)Main.Instance).StartCoroutine(Main.Instance.DelayedKick(component, "You are banned from this server.")); } else if (Main.IsPlayerExempt(component)) { Main.Log.LogInfo((object)("Player " + component._nickname + " is exempt. Skipping verification.")); Main.VerifiedSteamIDs.Add(result); } else if (!Main.PendingVerification.ContainsKey(result) && !Main.VerifiedSteamIDs.Contains(result) && (Main.EnableModBlacklist.Value || Main.EnableModWhitelist.Value || Main.EnableRequiredMods.Value || Main.EnableThunderstoreWhitelist.Value)) { ((MonoBehaviour)Main.Instance).StartCoroutine(Main.Instance.SendRequestWithDelay(component, result)); } } } else if ((Main.EnableModBlacklist.Value || Main.EnableModWhitelist.Value || Main.EnableRequiredMods.Value || Main.EnableThunderstoreWhitelist.Value) && (Object)(object)component != (Object)null && component._isHostPlayer && !((NetworkBehaviour)component).isLocalPlayer && ulong.TryParse(component._steamID, out result2)) { Main.Log.LogInfo((object)$"[HAC] Requesting Host ({result2}) Mod List... "); HAC_ModListRequest hAC_ModListRequest = new HAC_ModListRequest { TargetSteamID = result2 }; CodeTalkerNetwork.SendNetworkPacket(component, (BinaryPacketBase)(object)hAC_ModListRequest, (CompressionType)0, CompressionLevel.Fastest); } } } [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 MAX_FLIGHT_HEIGHT = 4240f; public static void Postfix(PlayerMove __instance) { //IL_02ba: Unknown result type (might be due to invalid IL or missing references) //IL_02bf: Unknown result type (might be due to invalid IL or missing references) //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_02fc: Unknown result type (might be due to invalid IL or missing references) //IL_03c0: Unknown result type (might be due to invalid IL or missing references) //IL_03c1: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: 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_01f0: 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_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0412: 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_0422: Unknown result type (might be due to invalid IL or missing references) //IL_0469: Unknown result type (might be due to invalid IL or missing references) //IL_046a: Unknown result type (might be due to invalid IL or missing references) //IL_0484: Unknown result type (might be due to invalid IL or missing references) //IL_04b1: Unknown result type (might be due to invalid IL or missing references) //IL_03a3: Unknown result type (might be due to invalid IL or missing references) //IL_0557: 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._movSpeed = value2; 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 && component2.Network_currentStamina >= component3._statStruct._maxStamina - 1 && __instance.RayGroundCheck() && 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 && 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)"); Main.LogInfraction((NetworkBehaviour)(object)__instance, cheatType, $"Moved {num2:F1} units in {num:F2}s (Expected max: {num3:F1}). Reverting position."); ((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 && (!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; } if (value6.AirTime > 10f) { ((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 || 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 || 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 || Main.IsPlayerExempt(((Component)__instance).GetComponent<Player>())) { 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(