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

FREE SteamGroups : 0.4.1 0.4.1

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

// TODO: Add queue for old member removal
// TODO: Add log rotation support for cleanup
// TODO: Cache members in data file and compare when updating

namespace Oxide.Plugins
{
    [Info("Steam Groups", "Wulf/lukespragg", "0.4.1")]
    [Description("Automatically adds members of Steam group(s) to a permissions group")]
    public class SteamGroups : CovalencePlugin
    {
        #region Configuration

        private Configuration config;

        public class Configuration
        {
            [JsonProperty(PropertyName = "Group Setup")]
            public List<GroupInfo> GroupSetup { get; set; } = new List<GroupInfo>();

            [JsonProperty(PropertyName = "Update Interval in seconds")]
            public int UpdateInterval { get; set; } = 300;

            [JsonProperty(PropertyName = "Log member changes to console")]
            public bool LogToConsole { get; set; } = true;

            [JsonProperty(PropertyName = "Log member changes to file")]
            public bool LogToFile { get; set; } = true;
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                config = Config.ReadObject<Configuration>();
                if (config == null)
                {
                    LoadDefaultConfig();
                }
            }
            catch
            {
                LoadDefaultConfig();
            }
            SaveConfig();
        }

        protected override void LoadDefaultConfig()
        {
            string configPath = $"{Interface.Oxide.ConfigDirectory}{Path.DirectorySeparatorChar}{Name}.json";
            LogWarning($"Could not load a valid configuration file, creating a new configuration file at {configPath}");
            config = new Configuration();
        }

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

        #endregion Configuration

        #region Localization

        private new void LoadDefaultMessages()
        {
            // English
            lang.RegisterMessages(new Dictionary<string, string>
            {
                ["CommandGroup"] = "steamgroup",
                ["CommandMembers"] = "steammembers",
                ["CommandUsageGroup"] = "Usage: {0} <add/remove> <steam group> [oxide group]",
                ["CheckingGroups"] = "Checking for new Steam group members...",
                ["GroupAdded"] = "Steam group '{0}' will be added to Oxide group '{1}'",
                ["GroupExists"] = "Steam group '{0}' and Oxide group '{1}' setup already exists",
                ["GroupRemoved"] = "Steam group '{0}' has been removed and will not longer be checked"
            }, this);
        }

        #endregion Localization

        #region Initialization

        private readonly Dictionary<string, string> steamGroups = new Dictionary<string, string>();
        private readonly Dictionary<string, string> groups = new Dictionary<string, string>();
        private readonly HashSet<string> members = new HashSet<string>();
        private readonly Queue<Member> membersQueue = new Queue<Member>();
        private readonly Regex idRegex = new Regex(@"<steamID64>(?<id>.+)</steamID64>");
        private readonly Regex pageRegex = new Regex(@"<currentPage>(?<page>.+)</currentPage>");
        private readonly Regex pagesRegex = new Regex(@"<totalPages>(?<pages>.+)</totalPages>");

        private const string permAdmin = "steamgroups.admin";

        private bool backoffPoll = false;

        public class GroupInfo
        {
            public readonly string Oxide;
            public readonly string Steam;

            public GroupInfo(string oxide, string steam)
            {
                Oxide = oxide.ToLower();
                Steam = steam.ToLower();
            }
        }

        private class Member
        {
            public readonly string Id;
            public readonly string Group;

            public Member(string id, string group)
            {
                Id = id;
                Group = group;
            }
        }

        private void OnServerInitialized()
        {
            foreach (GroupInfo group in config.GroupSetup)
            {
                if (!permission.GroupExists(group.Oxide))
                {
                    permission.CreateGroup(group.Oxide, group.Oxide, 0);
                }

                AddSteamGroup(group.Steam, group.Oxide);
            }

            permission.RegisterPermission(permAdmin, this);

            AddLocalizedCommand("CommandGroup", "GroupCommand");
            AddLocalizedCommand("CommandMembers", "MembersCommand");

            // Start the timed group checking (only once, will be enabled entire plugin lifecycle)
            StartTimedChecking();

            // Trigger check of Steam members immediately
            QueueWorkerThread(worker => CheckSteamGroups());

            // Start member dequeue/cleanup loop
            RunQueueAndCleanup();
        }

        #endregion Initialization

        #region Group Handling

        private void AddSteamGroup(string steamGroup, string oxideGroup)
        {
            ulong result;
            const string urlFormat = "http://steamcommunity.com/{0}/{1}/memberslistxml/?xml=1";
            string url = string.Format(urlFormat, ulong.TryParse(steamGroup, out result) ? "gid" : "groups", steamGroup);

            string groupValue;
            if (!(groups.TryGetValue(steamGroup, out groupValue) && groupValue == oxideGroup))
            {
                groups.Add(steamGroup, oxideGroup);
            }

            if (!steamGroups.ContainsKey(steamGroup))
            {
                steamGroups.Add(steamGroup, url);
            }
        }

        private void ProcessQueuedMembers()
        {
            QueueWorkerThread(worker =>
            {
                try
                {
                    Member member = membersQueue.Dequeue();

                    // Check if player is already in appropriate Oxide group, else add
                    if (!permission.UserHasGroup(member.Id, groups[member.Group]))
                    {
                        permission.AddUserGroup(member.Id, groups[member.Group]);
                        Log($"{member.Id} from {member.Group} added to '{groups[member.Group]}' group", "additions");
                    }
                }
                catch (Exception e)
                {
                    Puts($"An error occurred while processing queue: {e}");
                }
            });
        }

        private void RunQueueAndCleanup()
        {
            timer.Every(1f, () =>
            {
                if (membersQueue.Count != 0)
                {
                    ProcessQueuedMembers();
                }
                else
                {
                    //RemoveOldMembers();
                }
            });
        }

        #endregion Group Handling

        #region Group Cleanup

        private void RemoveOldMembers()
        {
            foreach (KeyValuePair<string, string> group in groups)
            {
                foreach (string user in permission.GetUsersInGroup(group.Value))
                {
                    string id = Regex.Replace(user, "[^0-9]", "");
                    if (!members.Contains(id))
                    {
                        permission.RemoveUserGroup(id, group.Value);
                        Log($"{id} from '{group.Value}' group", "removals");
                    }
                }
            }
        }

        #endregion Group Cleanup

        #region Member Checking

        private void StartTimedChecking()
        {
            timer.Every(config.UpdateInterval, () =>
            {
                // While backoff is enabled, we do not want to check members
                if (backoffPoll)
                {
                    Puts("Currently in backoff state, will not poll Steam group(s) for members");
                    return;
                }

                try
                {
                    QueueWorkerThread(worker => CheckSteamGroups());
                }
                catch (Exception e)
                {
                    Puts($"Exception occurred: {e}");
                }
            });
        }

        private void CheckSteamGroups()
        {
            try
            {
                Puts("Polling Steam group(s) to get member list");

                foreach (KeyValuePair<string, string> group in steamGroups)
                {
                    const int page = 1;

                    // One group at the time, no additional threading, we don't want to flood the API
                    Puts($"Checking Steam group {group.Key}, starting from page {page}");
                    QueueWebRequest(group.Key, group.Value, page);
                }
            }
            catch (Exception e)
            {
                Puts($"Exception occurred: {e}");
            }
        }

        private void QueueWebRequest(string groupName, string baseUrl, int page)
        {
            try
            {
                // Queue web request to get member list for Steam group
                webrequest.Enqueue($"{baseUrl}&p={page}", null, (code, response) =>
                {
                    WebRequestCallback(code, response, baseUrl, groupName);
                }, this, RequestMethod.GET, null, 10000f);
            }
            catch (Exception e)
            {
                Puts($"Exception occurred: {e}");
            }
        }

        private void WebRequestCallback(int code, string response, string baseUrl, string groupName)
        {
            if (code == 403 || code == 429)
            {
                Puts($"Steam is currently not allowing connections from your server! code={code}.Aborting this call");
                ToggleBackoff();
                return;
            }

            if (code != 200 || response == null)
            {
                Puts($"Checking for Steam group members failed! code={code}.Aborting this call");
                ToggleBackoff();
                return;
            }

            MatchCollection ids = idRegex.Matches(response);
            Log($"Found {ids.Count} member(s) in {groupName} to check");

            int newMembers = 0;
            foreach (Match match in ids)
            {
                string id = match.Groups["id"].Value;
                if (!members.Contains(id))
                {
                    newMembers++;
                    members.Add(id);
                    membersQueue.Enqueue(new Member(id, groupName));
                }
            }
            Puts($"Added {newMembers} member(s) in {groupName} to queue");

            int currentPage;
            int totalPages;
            int.TryParse(pageRegex.Match(response).Groups[1].Value, out currentPage);
            int.TryParse(pagesRegex.Match(response).Groups[1].Value, out totalPages);

            if (currentPage != 0 && totalPages != 0 && currentPage < totalPages)
            {
                QueueWorkerThread(worker => QueueWebRequest(groupName, baseUrl, currentPage + 1));
            }
        }

        private void ToggleBackoff()
        {
            if (!backoffPoll)
            {
                backoffPoll = true;
                timer.Once(600f, () => QueueWorkerThread(worker => ToggleBackoff()));
                Puts("Backoff polling state enabled");
            }
            else
            {
                backoffPoll = false;
                Puts("Backoff polling state disabled");
            }
        }

        #endregion Member Checking

        #region Commands

        private void GroupCommand(IPlayer player, string command, string[] args)
        {
            if (player.HasPermission(permAdmin))
            {
                if (args.Length < 2)
                {
                    Message(player, "CommandUsageGroup", command);
                    return;
                }

                string steamGroup = args[1].ToLower();
                string oxideGroup = args.Length >= 3 ? args[2].ToLower() : Interface.Oxide.Config.Options.DefaultGroups.Players.ToLower();

                switch (args[0].ToLower())
                {
                    case "+":
                    case "add":
                        {
                            if (!config.GroupSetup.Any(g => g.Steam == steamGroup && g.Oxide == oxideGroup))
                            {
                                config.GroupSetup.Add(new GroupInfo(oxideGroup, args[1]));
                                Message(player, "GroupAdded", args[1], oxideGroup);
                            }
                            else
                            {
                                Message(player, "GroupExists", args[1], oxideGroup);
                                return;
                            }

                            break;
                        }

                    case "-":
                    case "del":
                    case "delete":
                    case "remove":
                        {
                            config.GroupSetup.RemoveAll(g => g.Oxide == args[1] || g.Steam == args[1]);
                            Message(player, "GroupRemoved", args[1]);
                            break;
                        }

                    default:
                        {
                            Message(player, "CommandUsageGroup", command);
                            return;
                        }
                }
                SaveConfig();
            }
        }

        private void MembersCommand(IPlayer player, string command, string[] args)
        {
            if (player.HasPermission(permAdmin))
            {
                // Trigger check of Steam members immediately
                QueueWorkerThread(worker => CheckSteamGroups());

                Message(player, "CheckingGroups");
            }
        }

        #endregion Commands

        #region Helpers

        private string Lang(string key, string id = null, params object[] args)
        {
            return string.Format(lang.GetMessage(key, this, id), args);
        }

        private void AddLocalizedCommand(string key, string command)
        {
            foreach (string language in lang.GetLanguages(this))
            {
                Dictionary<string, string> messages = lang.GetMessages(language, this);
                foreach (KeyValuePair<string, string> message in messages.Where(m => m.Key.Equals(key)))
                {
                    if (!string.IsNullOrEmpty(message.Value))
                    {
                        AddCovalenceCommand(message.Value, command);
                    }
                }
            }
        }

        private void Log(string text, string filename)
        {
            if (config.LogToConsole)
            {
                Puts(text);
            }

            if (config.LogToFile)
            {
                LogToFile(filename, $"[{DateTime.Now}] {text}", this);
            }
        }

        private void Message(IPlayer player, string key, params object[] args)
        {
            player.Reply(Lang(key, player.Id, args));
        }

        #endregion Helpers
    }
}

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