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

FREE RSVote : 2.0.2 2.0.2

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

namespace Oxide.Plugins
{
    [Info("RustServer.gg Vote", "TimQQ@Codefling", "2.0.2")]
    [Description("Voting reward plugin for RustServers.gg with language support and Discord integration")]
    public class RSVote: RustPlugin
    {
        #region Vars

        private Dictionary<ulong, Dictionary<string, DateTime>> cooldown = new Dictionary<ulong, Dictionary<string, DateTime>>();
        private Dictionary<ulong, Dictionary<string, int>> voteStreaks = new Dictionary<ulong, Dictionary<string, int>>();
        private Dictionary<ulong, Dictionary<string, DateTime>> lastVoteTime = new Dictionary<ulong, Dictionary<string, DateTime>>();
        private Dictionary<ulong, Dictionary<string, int>> totalVotes = new Dictionary<ulong, Dictionary<string, int>>();
        private Dictionary<ulong, Dictionary<string, DateTime>> firstVote = new Dictionary<ulong, Dictionary<string, DateTime>>();
        private const string DiscordWebhookUrl = "https://discord.com/api/webhooks/your-webhook-url";

        #endregion

        #region Language

        private Dictionary<string, string> lang = new Dictionary<string, string>();

        protected override void LoadDefaultMessages()
        {
            lang = new Dictionary<string, string>
            {
                ["CooldownMessage"] = "Please wait {0} seconds before trying again!",
                ["ClaimingReward"] = "Trying to claim reward...",
                ["VotePrompt"] = "Vote at the servers page to claim reward!\n{0}",
                ["AlreadyClaimed"] = "You already claimed your reward(s)",
                ["RewardReceived"] = "You received {0} for voting!",
                ["RewardFailed"] = "Failed to claim reward, please contact the server owner!",
                ["DiscordVoteMessage"] = "**{0}** has voted and received: {1}",
                ["GlobalVoteMessage"] = "<color=#00ff00>{0}</color> has voted and received: {1}!",
                ["DiscordGlobalVoteMessage"] = "🎮 **{0}** has voted and received: {1}!",
                ["StreakMessage"] = "Vote streak: {0} days!",
                ["StreakBonus"] = "You received a streak bonus reward!",
                ["StreakReset"] = "Your vote streak has been reset!",
                ["DiscordStreakMessage"] = "🔥 **{0}** is on a {1} day voting streak!",
                ["GlobalStreakMessage"] = "<color=#ffd700>{0}</color> is on a {1} day voting streak! 🔥",
                ["StatsMessage"] = "Your voting statistics:\nTotal votes: {0}\nCurrent streak: {1}\nFirst vote: {2}",
                ["LeaderboardTitle"] = "🏆 Top Voters 🏆",
                ["LeaderboardEntry"] = "{0}.{1}: {2} votes",
                ["NoVoteHistory"] = "No voting history found.",
                ["StatsCommandUsage"] = "Usage: /votestats [player]",
                ["PlayerNotFound"] = "Player not found.",
                ["NoPermission"] = "You don't have permission to use this command.",
                ["DiscordStatsMessage"] = "📊 **Voting Statistics**\nPlayer: {0}\nTotal votes: {1}\nCurrent streak: {2}"
            };
        }

        private void LoadMessages()
        {
            // Load default messages first
            LoadDefaultMessages();

            // Try to load custom messages from file
            var customMessages = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<string, string>>($"{Name}/lang");
            if (customMessages != null)
            {
                // Update or add custom messages
                foreach (var message in customMessages)
                {
                    if (lang.ContainsKey(message.Key))
                    {
                        lang[message.Key] = message.Value;
                    }
                    else
                    {
                        lang.Add(message.Key, message.Value);
                    }
                }
            }
        }

        private void SaveMessages()
        {
            Interface.Oxide.DataFileSystem.WriteObject($"{Name}/lang", lang);
        }

        private string GetMsg(string key, string userId = null, params object[] args)
        {
            return string.Format(lang.ContainsKey(key) ? lang[key] : key, args);
        }

        #endregion

        #region Oxide Hooks

        private void Init()
        {
            LoadMessages();
            foreach (var command in config.commands)
            {
                cmd.AddChatCommand(command, this, cmdChat);
            }
            
            cmd.AddChatCommand(config.statsCommand, this, cmdStats);
            cmd.AddChatCommand(config.leaderboardCommand, this, cmdLeaderboard);
            
            timer.Every(Core.Random.Range(300, 500), () => { cooldown.Clear(); });
            LoadData();
            
            // Log loaded servers
            foreach (var server in config.servers)
            {
                Puts($"Loaded server '{server.name}' with id '{server.serverId}'");
            }
        }

        private void OnServerSave()
        {
            SaveConfig();
            SaveMessages();
            SaveData();
        }

        #endregion

        #region Commands

        private void cmdChat(BasePlayer player, string command, string[] args)
        {
            if (args.Length == 0)
            {
                // Show available servers
                var serverList = string.Join("\n", config.servers.Select(s => 
                    $"- {s.name} (ID: {s.serverId})"));
                player.ChatMessage($"Available servers:\n{serverList}\n\nUsage: /{command} <server-id>");
                return;
            }

            var serverId = args[0];
            var serverConfig = GetServerConfig(serverId);
            
            if (!cooldown.ContainsKey(player.userID))
            {
                cooldown[player.userID] = new Dictionary<string, DateTime>();
            }

            if (cooldown[player.userID].ContainsKey(serverId))
            {
                var nextUse = cooldown[player.userID][serverId];
                if (nextUse > DateTime.UtcNow)
                {
                    var remainingSeconds = (nextUse - DateTime.UtcNow).TotalSeconds;
                    player.ChatMessage(GetMsg("CooldownMessage", player.UserIDString, remainingSeconds));
                    return;
                }
                cooldown[player.userID][serverId] = DateTime.UtcNow.AddSeconds(config.cooldownSeconds);
            }
            else
            {
                cooldown[player.userID][serverId] = DateTime.UtcNow.AddSeconds(config.cooldownSeconds);
            }

            player.ChatMessage(GetMsg("ClaimingReward", player.UserIDString));
            var url = BuildUrl("status", player.UserIDString, serverId);
            Execute(url, "status", player, serverId);
        }

        private void cmdStats(BasePlayer player, string command, string[] args)
        {
            if (args.Length > 0 && !permission.UserHasPermission(player.UserIDString, "rsvote.admin"))
            {
                player.ChatMessage(GetMsg("NoPermission", player.UserIDString));
                return;
            }

            BasePlayer target = player;
            if (args.Length > 0)
            {
                target = BasePlayer.Find(args[0]);
                if (target == null)
                {
                    player.ChatMessage(GetMsg("PlayerNotFound", player.UserIDString));
                    return;
                }
            }

            if (!totalVotes.ContainsKey(target.userID))
            {
                player.ChatMessage(GetMsg("NoVoteHistory", player.UserIDString));
                return;
            }

            var streak = voteStreaks.ContainsKey(target.userID) ? voteStreaks[target.userID] : new Dictionary<string, int>();
            var firstVoteDate = firstVote.ContainsKey(target.userID) ? firstVote[target.userID] : new Dictionary<string, DateTime>();
            
            player.ChatMessage(GetMsg("StatsMessage", player.UserIDString, 
                totalVotes[target.userID].Count, streak.Count, firstVoteDate.Count));

            // Send Discord notification for each server where the player has voted
            foreach (var server in config.servers)
            {
                if (server.enableDiscordNotifications && totalVotes[target.userID].ContainsKey(server.serverId))
                {
                    SendDiscordNotification(target.displayName, 
                        $"Stats for {server.name} - Total votes: {totalVotes[target.userID][server.serverId]}, " +
                        $"Streak: {GetVoteStreak(target.userID, server.serverId)}",
                        server.serverId);
                }
            }
        }

        private void cmdLeaderboard(BasePlayer player, string command, string[] args)
        {
            var leaderboard = GetLeaderboard();
            if (leaderboard.Count == 0)
            {
                player.ChatMessage(GetMsg("NoVoteHistory", player.UserIDString));
                return;
            }

            player.ChatMessage(GetMsg("LeaderboardTitle", player.UserIDString));
            for (int i = 0; i < Math.Min(leaderboard.Count, config.leaderboardSize); i++)
            {
                var entry = leaderboard[i];
                player.ChatMessage(GetMsg("LeaderboardEntry", player.UserIDString, 
                    i + 1, entry.Key, entry.Value));
            }
        }

        #endregion

        #region Core

        private string BuildUrl(string action, string userId, string serverId)
        {
            var url = ConfigData.baseUrl;
            url += $"action={action}";
            url += $"&key={GetServerConfig(serverId).apiKey}";
            url += $"&server={serverId}";
            url += $"&steamid={userId}";
            return url;
        }

        private ServerConfig GetServerConfig(string serverId)
        {
            return config.servers.FirstOrDefault(s => s.serverId == serverId) ?? config.servers[0];
        }

        private void Execute(string url, string action, BasePlayer player, string serverId)
        {
            webrequest.Enqueue(url, null, (i, s) => { HandleResponse(url, i, s, action, player, serverId); }, this);
        }

        private void HandleResponse(string url, int code, string response, string action, BasePlayer player, string serverId)
        {
            var rInt = 0;
            if (int.TryParse(response, out rInt) == false)
            {
                PrintWarning($"Failed to parse response from '{response}'");
                return;
            }

            if (action == "status")
            {
                switch (rInt)
                {
                    case 0:
                        player.ChatMessage(GetMsg("VotePrompt", player.UserIDString, 
                            $"https://rustservers.gg/server/{serverId}"));
                        break;

                    case 1:
                        GiveRandomReward(player, serverId);
                        break;

                    case 2:
                        player.ChatMessage(GetMsg("AlreadyClaimed", player.UserIDString));
                        break;
                }
            }

            if (action == "claim")
            {
                switch (rInt)
                {
                    case 0:
                    case 1:
                    case 2:
                        // Ignore
                        break;
                }
            }
        }

        private void GiveRandomReward(BasePlayer player, string serverId)
        {
            var userId = player.UserIDString;
            var serverConfig = GetServerConfig(serverId);
            var streak = GetVoteStreak(player.userID, serverId);
            var totalVoteCount = GetTotalVotes(player.userID, serverId);

            // Find eligible reward categories
            var eligibleCategories = serverConfig.rewardCategories.Where(cat => 
                    (cat.requiredStreak <= 0 || streak >= cat.requiredStreak) &&
                    (cat.requiredVotes <= 0 || totalVoteCount >= cat.requiredVotes)).ToList();

            if (eligibleCategories.Count == 0)
            {
                // Fallback to default category
                eligibleCategories = serverConfig.rewardCategories.Where(cat => string.IsNullOrEmpty(cat.name) || cat.name == "Default").ToList();
            }

            if (eligibleCategories.Count == 0)
            {
                PrintWarning($"No eligible reward categories found for player '{userId}' on server '{serverId}'");
                player.ChatMessage(GetMsg("RewardFailed", userId));
                return;
            }

            // Select a random category from eligible ones
            var selectedCategory = eligibleCategories.GetRandom();
            var reward = selectedCategory.rewards.GetRandom();

            var result = reward.GiveTo(userId);
            if (result == false)
            {
                PrintWarning($"Failed to give reward to '{userId}' ({reward.Info()})");
                player.ChatMessage(GetMsg("RewardFailed", userId));
                return;
            }

            // Handle vote streak
            UpdateVoteStreak(player, serverId);

            // Update vote statistics
            UpdateVoteStats(player, serverId);

            Puts($"Player {userId} received reward for voting on server {serverId} (Category: {selectedCategory.name})");
            player.ChatMessage(GetMsg("RewardReceived", userId, reward.Info()));
            
            // Send Discord notification if enabled
            if (serverConfig.enableDiscordNotifications)
            {
                SendDiscordNotification(player.displayName, 
                    $"{reward.Info()} (Category: {selectedCategory.name})",
                    serverId);
            }

            // Send global message if enabled
            if (serverConfig.enableGlobalMessages)
            {
                SendGlobalMessage(player.displayName, 
                    $"{reward.Info()} (Category: {selectedCategory.name})",
                    serverId);
            }

            var claimUrl = BuildUrl("claim", userId, serverId);
            Execute(claimUrl, "claim", player, serverId);
        }

        private int GetVoteStreak(ulong userId, string serverId)
        {
            if (!voteStreaks.ContainsKey(userId))
                voteStreaks[userId] = new Dictionary<string, int>();
            return voteStreaks[userId].ContainsKey(serverId) ? voteStreaks[userId][serverId] : 0;
        }

        private int GetTotalVotes(ulong userId, string serverId)
        {
            if (!totalVotes.ContainsKey(userId))
                totalVotes[userId] = new Dictionary<string, int>();
            return totalVotes[userId].ContainsKey(serverId) ? totalVotes[userId][serverId] : 0;
        }

        private void UpdateVoteStreak(BasePlayer player, string serverId)
        {
            var now = DateTime.UtcNow;
            var userId = player.userID;
            var serverConfig = GetServerConfig(serverId);

            if (!lastVoteTime.ContainsKey(userId))
                lastVoteTime[userId] = new Dictionary<string, DateTime>();
            if (!voteStreaks.ContainsKey(userId))
                voteStreaks[userId] = new Dictionary<string, int>();

            if (!lastVoteTime[userId].ContainsKey(serverId))
            {
                // First vote
                voteStreaks[userId][serverId] = 1;
                lastVoteTime[userId][serverId] = now;
                player.ChatMessage(GetMsg("StreakMessage", player.UserIDString, 1));
                return;
            }

            var lastVote = lastVoteTime[userId][serverId];
            var timeSinceLastVote = now - lastVote;

            if (timeSinceLastVote.TotalHours <= 24)
            {
                // Within 24 hours, increment streak
                voteStreaks[userId][serverId]++;
                player.ChatMessage(GetMsg("StreakMessage", player.UserIDString, voteStreaks[userId][serverId]));
                
                // Give streak bonus if enabled
                if (serverConfig.enableStreakBonus && voteStreaks[userId][serverId] % serverConfig.streakBonusInterval == 0)
                {
                    GiveStreakBonus(player, serverId);
                }
            }
            else if (timeSinceLastVote.TotalHours <= 48)
            {
                // Within 48 hours, maintain streak
                player.ChatMessage(GetMsg("StreakMessage", player.UserIDString, voteStreaks[userId][serverId]));
            }
            else
            {
                // Streak broken
                player.ChatMessage(GetMsg("StreakReset", player.UserIDString));
                voteStreaks[userId][serverId] = 1;
            }

            lastVoteTime[userId][serverId] = now;

            // Send streak messages if enabled
            if (serverConfig.enableGlobalMessages)
            {
                Server.Broadcast(GetMsg("GlobalStreakMessage", null, player.displayName, voteStreaks[userId][serverId]));
            }

            if (serverConfig.enableDiscordNotifications)
            {
                SendDiscordNotification(player.displayName, $"Streak: {voteStreaks[userId][serverId]} days", serverId);
            }
        }

        private void GiveStreakBonus(BasePlayer player, string serverId)
        {
            var serverConfig = GetServerConfig(serverId);
            var bonusReward = serverConfig.streakBonusReward;
            if (bonusReward != null)
            {
                bonusReward.GiveTo(player.UserIDString);
                player.ChatMessage(GetMsg("StreakBonus", player.UserIDString));
            }
        }

        private void SendGlobalMessage(string playerName, string reward, string serverId = null)
        {
            var serverConfig = !string.IsNullOrEmpty(serverId)
                ? GetServerConfig(serverId)
                : config.servers.FirstOrDefault();

            if (serverConfig == null || !serverConfig.enableGlobalMessages) return;

            var message = GetMsg("GlobalVoteMessage", null, playerName, reward);
            Server.Broadcast(message);
        }

        private void SendDiscordNotification(string playerName, string reward, string serverId = null)
        {
            // If serverId is provided, use that server's config, otherwise use the first server's config
            var serverConfig = !string.IsNullOrEmpty(serverId) 
                ? GetServerConfig(serverId) 
                : config.servers.FirstOrDefault();

            if (serverConfig == null || !serverConfig.enableDiscordNotifications) return;

            var message = serverConfig.enableGlobalMessages 
                ? GetMsg("DiscordGlobalVoteMessage", null, playerName, reward)
                : GetMsg("DiscordVoteMessage", null, playerName, reward);

            // Use Discord Messages plugin instead of webhook
            plugins.Find("DiscordMessages")?.Call("SendMessage", message);
        }

        private void UpdateVoteStats(BasePlayer player, string serverId)
        {
            var userId = player.userID;
            
            if (!totalVotes.ContainsKey(userId))
                totalVotes[userId] = new Dictionary<string, int>();
            if (!firstVote.ContainsKey(userId))
                firstVote[userId] = new Dictionary<string, DateTime>();
            
            if (!totalVotes[userId].ContainsKey(serverId))
            {
                totalVotes[userId][serverId] = 0;
                firstVote[userId][serverId] = DateTime.UtcNow;
            }
            
            totalVotes[userId][serverId]++;
        }

        private List<KeyValuePair<string, int>> GetLeaderboard()
        {
            var leaderboard = new List<KeyValuePair<string, int>>();
            foreach (var kvp in totalVotes)
            {
                var player = BasePlayer.FindByID(kvp.Key);
                if (player != null)
                {
                    leaderboard.Add(new KeyValuePair<string, int>(player.displayName, kvp.Value.Count));
                }
            }
            return leaderboard.OrderByDescending(x => x.Value).ToList();
        }

        #endregion

        #region Config

        private class ServerConfig
        {
            [JsonProperty("Server Name")] 
            public string name = "Default Server";

            [JsonProperty("Server Id")] 
            public string serverId = string.Empty;

            [JsonProperty("API Key")] 
            public string apiKey = string.Empty;

            [JsonProperty("Enable Discord Notifications")] 
            public bool enableDiscordNotifications = false;

            [JsonProperty("Enable Global Messages")] 
            public bool enableGlobalMessages = true;

            [JsonProperty("Global Message Color")] 
            public string globalMessageColor = "#00ff00";

            [JsonProperty("Vote Reward Categories")] 
            public List<VoteRewardCategory> rewardCategories = new List<VoteRewardCategory>();

            [JsonProperty("Enable Streak Bonus")] 
            public bool enableStreakBonus = true;

            [JsonProperty("Streak Bonus Interval (days)")] 
            public int streakBonusInterval = 7;

            [JsonProperty("Streak Bonus Reward")] 
            public RewardItem streakBonusReward = new RewardItem
            {
                shortname = "scrap",
                amountMin = 100,
                amountMax = 200,
                description = "Scrap",
                skinId = 0
            };
        }

        private class ConfigData
        {
            [JsonProperty("Servers")] 
            public List<ServerConfig> servers = new List<ServerConfig>
            {
                new ServerConfig()
            };

            [JsonProperty("Cooldown Seconds")] 
            public int cooldownSeconds = 5;

            [JsonProperty("Chat Commands")] 
            public string[] commands =
            {
                "claim",
                "vote",
                "votes",
            };

            [JsonProperty("Stats Command")] 
            public string statsCommand = "votestats";

            [JsonProperty("Leaderboard Command")] 
            public string leaderboardCommand = "voteleaderboard";

            [JsonProperty("Leaderboard Size")] 
            public int leaderboardSize = 10;

            [JsonIgnore] 
            public const string baseUrl = "https://rustservers.gg/vote-api.php?";
        }

        private static ConfigData config = new ConfigData();

        protected override void LoadConfig()
        {
            base.LoadConfig();

            try
            {
                config = Config.ReadObject<ConfigData>();
                if (config == null)
                {
                    LoadDefaultConfig();
                }
            }
            catch
            {
                for (var i = 0; i < 3; i++)
                {
                    PrintError("Configuration file is corrupt! Check your config file at https://jsonlint.com/");
                }

                LoadDefaultConfig();
                return;
            }

            SaveConfig();
        }

        protected override void LoadDefaultConfig()
        {
            config = new ConfigData();
        }

        protected override void SaveConfig()
        {
            Config.WriteObject(config);
        }

        #endregion

        #region Rewards

        private interface IReward
        {
            bool GiveTo(string userId);

            string Info();
        }

        private class RewardItem : IReward
        {
            [JsonProperty("Item Shortname")] public string shortname;
            [JsonProperty("Description")] public string description;

            [JsonProperty("Item Amount Min")] public int amountMin;

            [JsonProperty("Item Amount Max")] public int amountMax;

            [JsonProperty("Item Skin id")] public ulong skinId;

            public Item GetItem()
            {
                var def = ItemManager.FindItemDefinition(shortname);
                if (def == null)
                {
                    return null;
                }

                var amount = amountMax > amountMin
                    ? Core.Random.Range(amountMin, amountMax)
                    : Core.Random.Range(amountMax, amountMin);

                var item = ItemManager.Create(def, amount);
                if (item == null)
                {
                    return null;
                }

                item.skin = skinId;
                return item;
            }

            public bool GiveTo(string userId)
            {
                var player = BasePlayer.Find(userId);
                if (player == null)
                {
                    return false;
                }

                var item = GetItem();
                if (item == null)
                {
                    return false;
                }

                player.GiveItem(item);
                return true;
            }

            public string Info()
            {
                return $"Item: {description}";
            }
        }

        private class VoteRewardCategory
        {
            [JsonProperty("Name")] 
            public string name;

            [JsonProperty("Description")] 
            public string description;

            [JsonProperty("Required Streak")] 
            public int requiredStreak;

            [JsonProperty("Required Total Votes")] 
            public int requiredVotes;

            [JsonProperty("Rewards")] 
            public List<RewardItem> rewards = new List<RewardItem>();
        }

        #endregion

        #region Data Management

        private void SaveData()
        {
            try
            {
                Interface.Oxide.DataFileSystem.WriteObject($"{Name}/vote_stats", new
                {
                    totalVotes,
                    firstVote,
                    voteStreaks,
                    lastVoteTime
                });
            }
            catch (Exception ex)
            {
                PrintError($"Failed to save data: {ex.Message}");
            }
        }

        private void LoadData()
        {
            try
            {
                var data = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<string, object>>($"{Name}/vote_stats");
                if (data != null)
                {
                    // Initialize dictionaries with default values
                    totalVotes = new Dictionary<ulong, Dictionary<string, int>>();
                    firstVote = new Dictionary<ulong, Dictionary<string, DateTime>>();
                    voteStreaks = new Dictionary<ulong, Dictionary<string, int>>();
                    lastVoteTime = new Dictionary<ulong, Dictionary<string, DateTime>>();

                    // Try to load data if it exists
                    if (data.ContainsKey("totalVotes"))
                        totalVotes = data["totalVotes"] as Dictionary<ulong, Dictionary<string, int>> ?? totalVotes;
                    if (data.ContainsKey("firstVote"))
                        firstVote = data["firstVote"] as Dictionary<ulong, Dictionary<string, DateTime>> ?? firstVote;
                    if (data.ContainsKey("voteStreaks"))
                        voteStreaks = data["voteStreaks"] as Dictionary<ulong, Dictionary<string, int>> ?? voteStreaks;
                    if (data.ContainsKey("lastVoteTime"))
                        lastVoteTime = data["lastVoteTime"] as Dictionary<ulong, Dictionary<string, DateTime>> ?? lastVoteTime;
                }
            }
            catch (Exception ex)
            {
                PrintError($"Failed to load data: {ex.Message}");
                // Initialize empty dictionaries on error
                totalVotes = new Dictionary<ulong, Dictionary<string, int>>();
                firstVote = new Dictionary<ulong, Dictionary<string, DateTime>>();
                voteStreaks = new Dictionary<ulong, Dictionary<string, int>>();
                lastVoteTime = new Dictionary<ulong, Dictionary<string, DateTime>>();
            }
        }

        #endregion
    }
}

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