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

FREE PluginLister : 1.5.2 1.5.2

Нет прав для скачивания
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Libraries;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;

namespace Oxide.Plugins
{
    [Info("PluginLister", "Milestorme", "1.5.2")]
    [Description("Lists installed plugins in-game and sends a polished summary to a Discord webhook.")]
    public class PluginLister : CovalencePlugin
    {
        private PluginConfig config;
        private const string CurrentConfigVersion = "1.5";
        private const string AdminPermission = "pluginlister.admin";

        private readonly Dictionary<string, DateTime> cooldowns = new Dictionary<string, DateTime>();

        private class PluginConfig
        {
            [JsonProperty("Enable Plugin")]
            public bool EnablePlugin { get; set; } = true;

            [JsonProperty("Enable Discord Webhook")]
            public bool EnableDiscordWebhook { get; set; } = true;

            [JsonProperty("Webhook URL")]
            public string WebhookUrl { get; set; } = "YOUR_DISCORD_WEBHOOK_URL_HERE";

            [JsonProperty("Command Cooldown Seconds")]
            public int CommandCooldownSeconds { get; set; } = 30;

            [JsonProperty("Sort Plugins Alphabetically")]
            public bool SortPluginsAlphabetically { get; set; } = true;

            [JsonProperty("Discord: Webhook Username")]
            public string WebhookUsername { get; set; } = "RustStorm";

            [JsonProperty("Discord: Avatar URL")]
            public string WebhookAvatarUrl { get; set; } = string.Empty;

            [JsonProperty("Discord: Embed Title")]
            public string EmbedTitle { get; set; } = "🌩 RustStorm Plugin Audit";

            [JsonProperty("Discord: Embed Color")]
            public int EmbedColor { get; set; } = 5814783;

            [JsonProperty("Discord: Footer Text")]
            public string FooterText { get; set; } = "RustStorm • Plugin Inventory";

            [JsonProperty("Discord: Embed Description")]
            public string EmbedDescription { get; set; } = "Live plugin inventory snapshot from your RustStorm server.";

            [JsonProperty("Discord: Thumbnail URL")]
            public string ThumbnailUrl { get; set; } = string.Empty;

            [JsonProperty("Discord: Banner Image URL")]
            public string BannerImageUrl { get; set; } = string.Empty;

            [JsonProperty("Discord: Mention Everyone")]
            public bool MentionEveryone { get; set; } = false;

            [JsonProperty("Discord: Max Plugins Per Embed")]
            public int MaxPluginsPerEmbed { get; set; } = 20;

            [JsonProperty("Discord: Include Text Fallback")]
            public bool IncludeTextFallback { get; set; } = true;

            [JsonProperty("Plugin Blacklist")]
            public List<string> PluginBlacklist { get; set; } = new List<string>
            {
                "Unity",
                "Rust",
                "PlayerAdministration",
                "PermissionsManager",
                "Copy Paste",
                "AdminMenu",
                "Admin Panel"
            };

            [JsonProperty("Config Version")]
            public string ConfigVersion { get; set; } = CurrentConfigVersion;
        }

        private class PluginInfo
        {
            public int Number { get; set; }
            public string Name { get; set; }
            public string Version { get; set; }
        }

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

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                config = Config.ReadObject<PluginConfig>();
                if (config == null)
                    throw new Exception("Configuration file is null");

                Puts("Config loaded successfully.");
                Puts("Config Version: " + config.ConfigVersion);

                if (config.ConfigVersion != CurrentConfigVersion)
                {
                    Puts("Updating configuration to match the latest version.");
                    UpdateConfig();
                }
            }
            catch (Exception ex)
            {
                Puts("Configuration file is corrupted or missing, creating a new one. " + ex.Message);
                LoadDefaultConfig();
            }
        }

        protected override void SaveConfig() => Config.WriteObject(config, true);

        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                ["NoPermission"] = "You do not have permission to use this command.",
                ["PluginDisabled"] = "This plugin is currently disabled.",
                ["NoPlugins"] = "No plugins are currently installed.",
                ["CooldownMessage"] = "You must wait {0} seconds before using this command again.",
                ["PluginsListed"] = "Installed Plugins ({0}):\n{1}",
                ["DiscordSent"] = "Plugin list sent to Discord."
            }, this);
        }

        private void UpdateConfig()
        {
            if (string.IsNullOrWhiteSpace(config.WebhookUrl))
                config.WebhookUrl = "YOUR_DISCORD_WEBHOOK_URL_HERE";

            if (config.CommandCooldownSeconds <= 0)
                config.CommandCooldownSeconds = 30;

            if (config.MaxPluginsPerEmbed <= 0)
                config.MaxPluginsPerEmbed = 20;

            if (config.MaxPluginsPerEmbed > 50)
                config.MaxPluginsPerEmbed = 50;

            if (string.IsNullOrWhiteSpace(config.WebhookUsername))
                config.WebhookUsername = "RustStorm";

            if (string.IsNullOrWhiteSpace(config.EmbedTitle))
                config.EmbedTitle = "🌩 RustStorm Plugin Audit";

            if (string.IsNullOrWhiteSpace(config.EmbedDescription))
                config.EmbedDescription = "Live plugin inventory snapshot from your RustStorm server.";

            if (string.IsNullOrWhiteSpace(config.FooterText))
                config.FooterText = "RustStorm • Plugin Inventory";

            if (config.PluginBlacklist == null)
            {
                config.PluginBlacklist = new List<string>
                {
                    "Unity",
                    "Rust",
                    "PlayerAdministration",
                    "PermissionsManager",
                    "CopyPaste",
                    "AdminMenu",
                    "AdminPanel"
                };
            }

            config.ConfigVersion = CurrentConfigVersion;
            SaveConfig();
        }

        private void Init()
        {
            permission.RegisterPermission(AdminPermission, this);
        }

        private void ConditionalPrint(string message) => Puts(message);

        private string Lang(string key, string playerId = null, params object[] args)
        {
            var message = lang.GetMessage(key, this, playerId);
            return args == null || args.Length == 0 ? message : string.Format(message, args);
        }

        private List<Plugin> GetFilteredPlugins()
        {
            var blacklist = new HashSet<string>(
                config.PluginBlacklist ?? new List<string>(),
                StringComparer.OrdinalIgnoreCase);

            var plugins = Interface.Oxide.RootPluginManager.GetPlugins()
                .Where(p => p != null && !blacklist.Contains(p.Title))
                .ToList();

            if (config.SortPluginsAlphabetically)
                plugins = plugins.OrderBy(p => p.Title, StringComparer.OrdinalIgnoreCase).ToList();

            return plugins;
        }

        [Command("listplugins")]
        [Permission(AdminPermission)]
        private void ListPluginsCommand(IPlayer player, string command, string[] args)
        {
            if (!config.EnablePlugin)
            {
                player.Reply(Lang("PluginDisabled", player.Id));
                return;
            }

            if (cooldowns.ContainsKey(player.Id) && cooldowns[player.Id] > DateTime.Now)
            {
                var remaining = (cooldowns[player.Id] - DateTime.Now).TotalSeconds;
                player.Reply(Lang("CooldownMessage", player.Id, Math.Ceiling(remaining)));
                return;
            }

            cooldowns[player.Id] = DateTime.Now.AddSeconds(config.CommandCooldownSeconds);

            var plugins = GetFilteredPlugins();
            if (!plugins.Any())
            {
                player.Reply(Lang("NoPlugins", player.Id));
                return;
            }

            var pluginNames = plugins.Select((p, i) => $"{i + 1}. {p.Title} v{p.Version}").ToList();
            player.Reply(Lang("PluginsListed", player.Id, pluginNames.Count, string.Join("\n", pluginNames)));

            if (config.EnableDiscordWebhook)
            {
                SendToDiscord(player, plugins);
                player.Reply(Lang("DiscordSent", player.Id));
            }
        }

        private void SendToDiscord(IPlayer requester, List<Plugin> plugins)
        {
            if (string.IsNullOrWhiteSpace(config.WebhookUrl) || config.WebhookUrl == "YOUR_DISCORD_WEBHOOK_URL_HERE")
            {
                ConditionalPrint("Webhook URL is not configured or is using the default placeholder.");
                return;
            }

            var pluginDetails = plugins.Select((p, i) => new PluginInfo
            {
                Number = i + 1,
                Name = p.Title,
                Version = p.Version != null ? p.Version.ToString() : "Unknown"
            }).ToList();

            var embeds = BuildDiscordEmbeds(requester, pluginDetails);
            var requests = BuildWebhookPayloads(embeds, plugins.Count);

            ConditionalPrint($"Preparing {requests.Count} Discord webhook request(s) for {plugins.Count} plugin(s).");
            SendDiscordPayloadsSequentially(requests, 0);
        }

        private List<Dictionary<string, object>> BuildWebhookPayloads(List<Dictionary<string, object>> embeds, int pluginCount)
        {
            const int maxEmbedsPerRequest = 10;
            var payloads = new List<Dictionary<string, object>>();

            for (var i = 0; i < embeds.Count; i += maxEmbedsPerRequest)
            {
                var payload = new Dictionary<string, object>
                {
                    ["username"] = config.WebhookUsername,
                    ["embeds"] = embeds.Skip(i).Take(maxEmbedsPerRequest).ToList()
                };

                if (config.IncludeTextFallback)
                {
                    payload["content"] = config.MentionEveryone
                        ? $"@everyone RustStorm plugin audit generated ({pluginCount} plugins)."
                        : $"RustStorm plugin audit generated ({pluginCount} plugins).";
                }
                else if (config.MentionEveryone)
                {
                    payload["content"] = "@everyone";
                }

                if (!string.IsNullOrWhiteSpace(config.WebhookAvatarUrl))
                    payload["avatar_url"] = config.WebhookAvatarUrl;

                payloads.Add(payload);
            }

            return payloads;
        }

        private List<Dictionary<string, object>> BuildDiscordEmbeds(IPlayer requester, List<PluginInfo> plugins)
        {
            var embeds = new List<Dictionary<string, object>>();
            var chunkSize = Math.Max(1, Math.Min(config.MaxPluginsPerEmbed, 50));
            var totalPages = (int)Math.Ceiling(plugins.Count / (double)chunkSize);

            for (var page = 0; page < totalPages; page++)
            {
                var chunk = plugins.Skip(page * chunkSize).Take(chunkSize).ToList();
                var descriptionLines = chunk.Select(p => $"`{p.Number,2}.` **{EscapeDiscord(p.Name)}** `v{EscapeDiscord(p.Version)}`").ToList();
                var description = string.Join("\n", descriptionLines);

                if (!string.IsNullOrWhiteSpace(config.EmbedDescription))
                    description = config.EmbedDescription + "\n\n" + description;

                if (description.Length > 4096)
                    description = description.Substring(0, 4090) + "...";

                var fields = new List<object>();
                if (page == 0)
                {
                    fields.Add(new
                    {
                        name = "Server Snapshot",
                        value = $"**Total Plugins:** {plugins.Count}\n**Requested By:** {EscapeDiscord(requester?.Name ?? "Console")}\n**Requested At:** <t:{DateTimeOffset.UtcNow.ToUnixTimeSeconds()}:F>",
                        inline = false
                    });
                }

                var embed = new Dictionary<string, object>
                {
                    ["title"] = totalPages > 1 ? $"{config.EmbedTitle} — Page {page + 1}/{totalPages}" : config.EmbedTitle,
                    ["description"] = description,
                    ["color"] = config.EmbedColor,
                    ["fields"] = fields,
                    ["footer"] = new { text = config.FooterText },
                    ["timestamp"] = DateTime.UtcNow.ToString("o")
                };

                if (!string.IsNullOrWhiteSpace(config.ThumbnailUrl))
                    embed["thumbnail"] = new { url = config.ThumbnailUrl };

                if (!string.IsNullOrWhiteSpace(config.BannerImageUrl))
                    embed["image"] = new { url = config.BannerImageUrl };

                embeds.Add(embed);
            }

            return embeds;
        }

        private void SendDiscordPayloadsSequentially(List<Dictionary<string, object>> payloads, int index)
        {
            if (payloads == null || index >= payloads.Count)
                return;

            var payloadJson = JsonConvert.SerializeObject(payloads[index]);
            SendDiscordPayload(payloadJson, () => SendDiscordPayloadsSequentially(payloads, index + 1));
        }

        private void SendDiscordPayload(string payload, Action onSuccess = null, int retryCount = 0)
        {
            var headers = new Dictionary<string, string>
            {
                { "Content-Type", "application/json" }
            };

            var url = config.WebhookUrl;
            if (!url.Contains("wait=true"))
                url += (url.Contains("?") ? "&" : "?") + "wait=true";

            webrequest.Enqueue(
                url,
                payload,
                (code, response) =>
                {
                    if (code != 200 && code != 204)
                    {
                        ConditionalPrint($"Failed to send data to Discord. Response code: {code}. Response: {response}");

                        if (retryCount < 3)
                            timer.Once(5f, () => SendDiscordPayload(payload, onSuccess, retryCount + 1));
                        return;
                    }

                    ConditionalPrint($"Successfully sent data to Discord. Response code: {code}.");
                    if (!string.IsNullOrWhiteSpace(response))
                        ConditionalPrint($"Discord response: {response}");

                    onSuccess?.Invoke();
                },
                this,
                RequestMethod.POST,
                headers
            );
        }

        private string EscapeDiscord(string value)
        {
            if (string.IsNullOrEmpty(value))
                return string.Empty;

            return value
                .Replace("\\", "\\\\")
                .Replace("*", "\\*")
                .Replace("_", "\\_")
                .Replace("`", "\\`")
                .Replace("~", "\\~")
                .Replace("|", "\\|");
        }
    }
}

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