// Requires: Guardian using Newtonsoft.Json; using Oxide.Core.Plugins; using System; using System.Collections.Generic; using UnityEngine; namespace Oxide.Plugins { [Info("Guardian ADR", "Rockioux", "1.0.2")] [Description("Starts demo recordings on Guardian Violations.")] class GuardianADR : CovalencePlugin { #region Config Classes private class GuardianADRConfig { [JsonProperty(PropertyName = "Gravity Violation Demo Config")] public HookConfig GravityHookConfig { get; set; } = new HookConfig(true); [JsonProperty(PropertyName = "Melee Rate Violation Demo Config")] public HookConfig MeleeRateConfig { get; set; } = new HookConfig(true); [JsonProperty(PropertyName = "NoClip Violation Demo Config")] public HookConfig NoClipConfig { get; set; } = new HookConfig(false); [JsonProperty(PropertyName = "InsideTerrain Violation Demo Config")] public HookConfig InsideTerrainConfig { get; set; } = new HookConfig(false); } private class HookConfig { [JsonProperty(PropertyName = "Enable Demo Recordings for this hook")] public bool HookEnabled { get; set; } [JsonProperty(PropertyName = "Demo Duration in minutes")] public int DemoDuration { get; set; } = 2; [JsonProperty(PropertyName = "Discord Webhook")] public string DiscordWebhook { get; set; } = ""; public HookConfig() { } public HookConfig(bool enabled) { HookEnabled = enabled; } } #endregion // Config Classes #region Fields [PluginReference] private Plugin AutoDemoRecord; private GuardianADRConfig _config; #endregion // Fields #region Covalence Plugin Implemented Members private void Init() { if(!_config.GravityHookConfig.HookEnabled) { Unsubscribe(nameof(OnGuardianAntiCheatGravity)); } if (!_config.MeleeRateConfig.HookEnabled) { Unsubscribe(nameof(OnGuardianAntiCheatMeleeRate)); } if(!_config.NoClipConfig.HookEnabled && !_config.InsideTerrainConfig.HookEnabled) { Unsubscribe(nameof(OnGuardianServer)); } } protected override void LoadConfig() { base.LoadConfig(); _config = Config.ReadObject(); SaveConfig(); } protected override void SaveConfig() => Config.WriteObject(_config); protected override void LoadDefaultConfig() { _config = new GuardianADRConfig(); } #endregion // Covalence Plugin Implemented Members #region Guardian Hooks private void OnGuardianAntiCheatGravity(string playerID, Dictionary details) { try { BasePlayer player; if (!GetBasePlayer(playerID, out player)) { return; } // Check if already recording if (player.Connection.IsRecording) { return; } Vector3 pos = player.transform.position; string message = $"{player.displayName} ({playerID}) is defying gravity!\n\nElevation: {details["elevation"]}\nMovement speed: {details["movement_speed"]}\nViolation: {details["violation_id"]}\nPosition: teleportpos {pos.x}, {pos.y}, {pos.z}"; AutoDemoRecord?.Call("API_StartRecording4", player, message, _config.GravityHookConfig.DemoDuration, _config.GravityHookConfig.DiscordWebhook); } catch(Exception ex) { LogError(ex.ToString()); } } private void OnGuardianAntiCheatMeleeRate(string playerID, Dictionary details) { try { BasePlayer player; if (!GetBasePlayer(playerID, out player)) { return; } // Check if already recording if (player.Connection.IsRecording) { return; } string message = $"{player.displayName} ({playerID}) is meleeing too fast!\n\nWeapon Type: {details["weapon_type"]}\nMovement speed: {details["movement_speed"]}\nRate Percentage: {details["rate_percent"]}%\nViolation: {details["violation_id"]}"; AutoDemoRecord?.Call("API_StartRecording4", player, message, _config.MeleeRateConfig.DemoDuration, _config.MeleeRateConfig.DiscordWebhook); } catch(Exception ex) { LogError(ex.ToString()); } } private void OnGuardianServer(string playerID, Dictionary details) { try { AntiHackType antihackType = (AntiHackType)Enum.Parse(typeof(AntiHackType), details["antihack_type"]); if ((antihackType != AntiHackType.NoClip || !_config.NoClipConfig.HookEnabled) && (antihackType != AntiHackType.InsideTerrain || !_config.InsideTerrainConfig.HookEnabled)) { return; } BasePlayer player; if (!GetBasePlayer(playerID, out player)) { return; } // Check if already recording if (player.Connection.IsRecording) { return; } Vector3 pos = player.transform.position; HookConfig config = antihackType == AntiHackType.NoClip ? _config.NoClipConfig : _config.InsideTerrainConfig; string actionStr = antihackType == AntiHackType.NoClip ? "no clipping" : "inside terrain"; string message = $"{player.displayName} ({playerID}) is {actionStr}!\n\nViolation: {details["violation_id"]}\nPosition: teleportpos {pos.x}, {pos.y}, {pos.z}"; AutoDemoRecord?.Call("API_StartRecording4", player, message, config.DemoDuration, config.DiscordWebhook); } catch(Exception ex) { LogError(ex.ToString()); } } #endregion // Guardian Hooks #region Helper Methods private bool GetBasePlayer(string playerID, out BasePlayer player) { player = null; ulong steamID; if (!ulong.TryParse(playerID, out steamID)) { LogError($"Unexpected error. Could not parse player steam id {playerID}."); return false; } player = BasePlayer.FindByID(steamID); if (player == null) { LogError($"Unexpected error. Player with steam id {playerID} was not found."); return false; } return true; } #endregion // Helper Methods } }