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

FREE VoteBan : 1.1.1 1.1.1

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System;
using System.Collections.Generic;
using System.Linq;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Core.Libraries.Covalence;
using Newtonsoft.Json;
using UnityEngine;
using System.Threading.Tasks;

//  ____  _       _ _       
// / ___|(_) __ _(_) | ___  
// \___ \| |/ _` | | |/ _ \ 
//  ___) | | (_| | | | (_) |
// |____/|_|\__, |_|_|\___/ 
//          |___/             
// ☽✧✵✧✵✧✵✧✵✧✵✧✵✧☾
// ✦    RUST PLUGINS   ✦
// ✦     Sigilo.dev    ✦
// ☽✧✵✧✵✧✵✧✵✧✵✧✵✧☾

namespace Oxide.Plugins
{
    [Info("VoteBan", "Sigilo", "1.1.1")]
    [Description("Player voting system for banning players")]
    class VoteBan : RustPlugin
    {
        #region Configuration

        private Configuration config;

        class Configuration
        {
            [JsonProperty("Required percentage (0-100)")]
            public float RequiredPercentage = 90f;
            
            [JsonProperty("Vote duration (seconds)")]
            public int VoteDuration = 120;
            
            [JsonProperty("Cooldown between votes (minutes)")]
            public int CooldownMinutes = 10;
            
            [JsonProperty("Ban duration (minutes, 0 for permanent)")]
            public int BanDuration = 60;
            
            [JsonProperty("Discord Webhook URL")]
            public string WebhookUrl = "";
            
            [JsonProperty("Log to console")]
            public bool LogToConsole = false;

            [JsonProperty("Minimum players required for voting")]
            public int MinimumPlayers = 9;

            [JsonProperty("Allow voting to ban self")]
            public bool AllowSelfVote = false;

            [JsonProperty("Allow voting to ban admins")]
            public bool AllowAdminVote = false;

            [JsonProperty("Reminder interval (seconds)")]
            public int ReminderInterval = 30;
            
            [JsonProperty("Count only voters (if false, non-voters count as No)")]
            public bool CountOnlyVoters = true;
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                config = Config.ReadObject<Configuration>();
                if (config == null) LoadDefaultConfig();
            }
            catch
            {
                PrintError("Configuration file is corrupt, using defaults");
                LoadDefaultConfig();
            }
        }

        protected override void LoadDefaultConfig() => config = new Configuration();
        protected override void SaveConfig() => Config.WriteObject(config);

        #endregion

        #region Initialization

        private const string permStartVote = "voteban.start";    
        private const string permVote = "voteban.vote";          
        private Dictionary<ulong, DateTime> lastVoteCall = new Dictionary<ulong, DateTime>();
        private VoteSession activeVote;
        private Dictionary<ulong, DateTime> tempBans = new Dictionary<ulong, DateTime>();

        void Init()
        {
            permission.RegisterPermission(permStartVote, this);
            permission.RegisterPermission(permVote, this);
            LoadDefaultMessages();
            LoadBanData();
            timer.Every(60f, CheckTempBans);
        }

        void Unload()
        {
            SaveBanData();
        }
        
        protected override void LoadDefaultMessages()
        {
            var messages = new Dictionary<string, string>
            {
                ["VoteStarted"] = "A vote has started to ban <color=#B87333>{0}</color> for <color=#9CAF88>{1}</color>!",
                ["VoteDuration"] = "Vote will last <color=#9CAF88>{0}</color> seconds",
                ["VoteInstructions"] = "Type <color=#E6BE8A>/y</color> to ban or <color=#E6BE8A>/n</color> to cancel",
                ["VoteSuccess"] = "Vote passed (<color=#9CAF88>{0}/{1}</color> votes): <color=#B87333>{2}</color> has been banned for <color=#9CAF88>{3}</color>",
                ["VoteFailed"] = "Vote failed (<color=#9CAF88>{0}/{1}</color> votes): <color=#B87333>{2}</color> will not be banned",
                ["Cooldown"] = "Wait <color=#9CAF88>{0}</color> minutes before starting another vote",
                ["NoPermission"] = "You don't have permission to start a vote",
                ["InvalidTarget"] = "Player '<color=#B87333>{0}</color>' not found",
                ["VoteInProgress"] = "A vote is already in progress",
                ["InvalidCommandBan"] = "Usage: <color=#E6BE8A>/voteban</color> <color=#B87333><player></color>",
                ["MinimumPlayers"] = "Need at least <color=#9CAF88>{0}</color> players online to start a vote",
                ["CannotVoteAdmin"] = "Cannot vote to ban <color=#B87333>admin</color>",
                ["CannotVoteSelf"] = "Cannot vote to ban <color=#B87333>yourself</color>",
                ["AlreadyBanned"] = "<color=#B87333>{0}</color> is already banned",
                ["BanSuccessOnline"] = "<color=#708090>You have been banned via vote</color>",
                ["NoVotePermission"] = "You don't have permission to vote",
                ["VoteReminder"] = "Vote to ban <color=#B87333>{0}</color> - {1}s left",
                ["AlreadyVoted"] = "You have already voted"
            };

            lang.RegisterMessages(messages, this, "en");
            lang.RegisterMessages(messages, this);
        }

        #endregion

        #region Voting System

        class VoteSession
        {
            public string TargetName;
            public ulong TargetId;
            public Dictionary<ulong, bool> Votes = new Dictionary<ulong, bool>();
            public Timer VoteTimer;
            public Timer ReminderTimer;
            public int RemainingTime;
        }

        [ChatCommand("voteban")]
        void CmdVoteBan(BasePlayer player, string command, string[] args)
        {
            StartVote(player, args);
        }

        void StartVote(BasePlayer initiator, string[] args)
        {
            if (!permission.UserHasPermission(initiator.UserIDString, permStartVote))
            {
                SendReply(initiator, Lang("NoPermission", initiator.UserIDString));
                return;
            }

            if (BasePlayer.activePlayerList.Count < config.MinimumPlayers)
            {
                SendReply(initiator, Lang("MinimumPlayers", initiator.UserIDString, config.MinimumPlayers));
                return;
            }

            if (activeVote != null)
            {
                SendReply(initiator, Lang("VoteInProgress", initiator.UserIDString));
                return;
            }

            if (args.Length == 0)
            {
                SendReply(initiator, Lang("InvalidCommandBan", initiator.UserIDString));
                return;
            }

            if (lastVoteCall.TryGetValue(initiator.userID, out DateTime lastCall) && 
                (DateTime.Now - lastCall).TotalMinutes < config.CooldownMinutes)
            {
                var remainingTime = config.CooldownMinutes - (DateTime.Now - lastCall).TotalMinutes;
                SendReply(initiator, Lang("Cooldown", initiator.UserIDString, Math.Round(remainingTime, 2)));
                return;
            }

            var target = FindPlayer(args[0]);
            if (target == null)
            {
                SendReply(initiator, Lang("InvalidTarget", initiator.UserIDString, args[0]));
                return;
            }

            if (tempBans.ContainsKey(target.userID))
            {
                SendReply(initiator, Lang("AlreadyBanned", initiator.UserIDString, target.displayName));
                return;
            }

            if (!config.AllowSelfVote && target.userID == initiator.userID)
            {
                SendReply(initiator, Lang("CannotVoteSelf", initiator.UserIDString));
                return;
            }

            if (!config.AllowAdminVote && target.IsAdmin)
            {
                SendReply(initiator, Lang("CannotVoteAdmin", initiator.UserIDString));
                return;
            }

            activeVote = new VoteSession
            {
                TargetName = target.displayName,
                TargetId = target.userID,
                RemainingTime = config.VoteDuration,
                VoteTimer = timer.Once(config.VoteDuration, EndVote)
            };

            lastVoteCall[initiator.userID] = DateTime.Now;

            string banDurationText = config.BanDuration > 0 ? $"{config.BanDuration} minutes" : "permanently";
            BroadcastChat(Lang("VoteStarted", null, target.displayName, banDurationText));
            BroadcastChat(Lang("VoteDuration", null, config.VoteDuration));
            BroadcastChat(Lang("VoteInstructions"));

            if (config.ReminderInterval > 0 && config.ReminderInterval < config.VoteDuration)
            {
                activeVote.RemainingTime = config.VoteDuration;
                activeVote.ReminderTimer = timer.Every(config.ReminderInterval, () =>
                {
                    activeVote.RemainingTime -= config.ReminderInterval;
                    
                    if (activeVote.RemainingTime <= 5) return;
                    
                    BroadcastChat(Lang("VoteReminder", null, activeVote.TargetName, activeVote.RemainingTime));
                    BroadcastChat(Lang("VoteInstructions"));
                });
            }
        }

        [ChatCommand("y")]
        void VoteYes(BasePlayer player, string command, string[] args)
        {
            RegisterVote(player, true);
        }

        [ChatCommand("n")]
        void VoteNo(BasePlayer player, string command, string[] args)
        {
            RegisterVote(player, false);
        }

        void RegisterVote(BasePlayer voter, bool vote)
        {
            if (activeVote == null)
            {
                SendReply(voter, Lang("VoteInProgress", voter.UserIDString));
                return;
            }
            
            if (!permission.UserHasPermission(voter.UserIDString, permVote))
            {
                SendReply(voter, Lang("NoVotePermission", voter.UserIDString));
                return;
            }
            
            if (activeVote.Votes.ContainsKey(voter.userID))
            {
                SendReply(voter, Lang("AlreadyVoted", voter.UserIDString));
                return;
            }
            
            activeVote.Votes[voter.userID] = vote;
            SendReply(voter, $"You voted {(vote ? "<color=#E6BE8A>YES</color>" : "<color=#708090>NO</color>")}");
        }

        void EndVote()
        {
            if (activeVote == null) return;

            if (activeVote.ReminderTimer != null)
            {
                activeVote.ReminderTimer.Destroy();
            }

            int participants;
            float votePercentage;
            var yesVotes = activeVote.Votes.Count(v => v.Value);
            var totalVotes = activeVote.Votes.Count;
            
            if (config.CountOnlyVoters)
            {
                participants = totalVotes > 0 ? totalVotes : 1;
                votePercentage = (yesVotes * 100.0f) / participants;
            }
            else
            {
                participants = BasePlayer.activePlayerList.Count;
                votePercentage = (yesVotes * 100.0f) / participants;
            }
            
            var requiredVotes = (int)Math.Ceiling(participants * (config.RequiredPercentage / 100));

            try
            {
                if (yesVotes >= requiredVotes)
                {
                    ExecuteBan(activeVote, yesVotes, participants, votePercentage);
                    string banDurationText = config.BanDuration > 0 ? $"{config.BanDuration} minutes" : "permanently";
                    BroadcastChat(Lang("VoteSuccess", null, yesVotes, participants, activeVote.TargetName, banDurationText));
                }
                else
                {
                    BroadcastChat(Lang("VoteFailed", null, yesVotes, participants, activeVote.TargetName));
                }
            }
            catch (Exception ex)
            {
                PrintError($"Error in EndVote: {ex.Message}");
            }
            finally
            {
                activeVote = null;
            }
        }

        void ExecuteBan(VoteSession vote, int yesVotes, int participants, float votePercentage)
        {
            try
            {
                IPlayer targetIPlayer = covalence.Players.FindPlayer(vote.TargetId.ToString());
                string reason = config.BanDuration > 0 
                    ? $"Banned by vote for {config.BanDuration} minutes" 
                    : "Permanently banned by vote";

                if (targetIPlayer != null)
                {
                    if (config.BanDuration > 0)
                    {
                        tempBans[vote.TargetId] = DateTime.Now.AddMinutes(config.BanDuration);
                        ConsoleSystem.Run(ConsoleSystem.Option.Server, $"banid {vote.TargetId} {config.BanDuration * 60} \"{reason}\"");
                    }
                    else
                    {
                        ConsoleSystem.Run(ConsoleSystem.Option.Server, $"banid {vote.TargetId} \"{reason}\"");
                    }

                    var basePlayer = BasePlayer.FindByID(vote.TargetId);
                    if (basePlayer != null)
                    {
                        basePlayer.Kick(reason);
                    }
                }
                else
                {
                    if (config.BanDuration > 0)
                    {
                        tempBans[vote.TargetId] = DateTime.Now.AddMinutes(config.BanDuration);
                        ConsoleSystem.Run(ConsoleSystem.Option.Server, $"banid {vote.TargetId} {config.BanDuration * 60} \"{reason}\"");
                    }
                    else
                    {
                        ConsoleSystem.Run(ConsoleSystem.Option.Server, $"banid {vote.TargetId} \"{reason}\"");
                    }
                }
                SaveBanData();

                SendDiscordEmbed("Vote Ban Success",
                    $"Player **{vote.TargetName}** has been banned via vote.",
                    3066993,
                    new List<Dictionary<string, object>>
                    {
                        new Dictionary<string, object> { { "name", "Player Name" }, { "value", vote.TargetName }, { "inline", true } },
                        new Dictionary<string, object> { { "name", "Player ID" }, { "value", vote.TargetId.ToString() }, { "inline", true } },
                        new Dictionary<string, object> { { "name", "Ban Duration" }, { "value", config.BanDuration > 0 ? $"{config.BanDuration} minutes" : "Permanent" }, { "inline", true } },
                        new Dictionary<string, object> { { "name", "Vote Result" }, { "value", $"{vote.Votes.Count(v => v.Value)}/{participants} ({Math.Round(votePercentage, 1)}%)" }, { "inline", true } },
                        new Dictionary<string, object> { { "name", "Count Mode" }, { "value", config.CountOnlyVoters ? "Only Voters" : "All Players" }, { "inline", true } }
                    }
                );
            }
            catch (Exception ex)
            {
                PrintError($"Error in ExecuteBan: {ex.Message}");
            }
        }

        #endregion

        #region Helper Methods

        BasePlayer FindPlayer(string search)
        {
            return BasePlayer.activePlayerList.FirstOrDefault(p => p.displayName.Contains(search, StringComparison.OrdinalIgnoreCase) 
                                   || p.UserIDString == search);
        }

        string Lang(string key, string userId = null, params object[] args)
        {
            try 
            {
                var message = lang.GetMessage(key, this, userId);
                return args == null || args.Length == 0 ? message : string.Format(message, args);
            }
            catch (Exception ex)
            {
                PrintError($"Lang format error for key '{key}': {ex.Message}");
                return key;
            }
        }

        void BroadcastChat(string message)
        {
            foreach (var player in BasePlayer.activePlayerList)
                SendReply(player, message);
            
            if (config.LogToConsole)
                Puts(message);
        }

        async Task SendDiscordEmbed(string title, string description, int color, List<Dictionary<string, object>> fields)
        {
            if (string.IsNullOrEmpty(config.WebhookUrl)) return;

            var embed = new Dictionary<string, object>
            {
                {"title", title},
                {"description", description},
                {"color", color},
                {"timestamp", DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ")}
            };

            if (fields != null && fields.Count > 0)
            {
                embed["fields"] = fields;
            }

            var payloadObj = new Dictionary<string, object>
            {
                {"username", "Vote Ban System"},
                {"embeds", new object[] { embed } }
            };

            var payload = JsonConvert.SerializeObject(payloadObj);

            try
            {
                webrequest.EnqueuePost(
                    config.WebhookUrl.TrimEnd('/'),
                    payload,
                    (code, response) =>
                    {
                        if (code != 204 && code != 200)
                            PrintError($"Discord webhook error: {code} - {response}");
                    },
                    this,
                    new Dictionary<string, string>
                    {
                        ["Content-Type"] = "application/json"
                    }
                );
            }
            catch (Exception ex)
            {
                PrintError($"Discord embed log failed: {ex.Message}");
            }
        }

        void LoadBanData()
        {
            tempBans = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<ulong, DateTime>>(Name) ?? new Dictionary<ulong, DateTime>();
        }

        void SaveBanData()
        {
            Interface.Oxide.DataFileSystem.WriteObject(Name, tempBans);
        }

        #endregion

        void CheckTempBans()
        {
            var now = DateTime.Now;
            foreach (var entry in tempBans.Where(entry => entry.Value <= now).ToList())
            {
                try
                {
                    ConsoleSystem.Run(ConsoleSystem.Option.Server, $"unban {entry.Key}");
                    var targetName = covalence.Players.FindPlayerById(entry.Key.ToString())?.Name ?? "Unknown";
                    
                    SendDiscordEmbed("Temporary Ban Expired",
                        $"Player **{targetName}** has been unbanned.",
                        3447003,
                        new List<Dictionary<string, object>>
                        {
                            new Dictionary<string, object> { { "name", "Player Name" }, { "value", targetName }, { "inline", true } },
                            new Dictionary<string, object> { { "name", "Player ID" }, { "value", entry.Key.ToString() }, { "inline", true } }
                        }
                    );
                }
                catch (Exception ex)
                {
                    PrintError($"Error unbanning player with ID {entry.Key}: {ex.Message}");
                }
                tempBans.Remove(entry.Key);
            }
            SaveBanData();
        }
    }
}

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