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

FREE PowerfulWhitelist : 1.0.1 1.0.1

Нет прав для скачивания
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using Facepunch;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using UnityEngine;
using DatabaseConnection = Oxide.Core.Database.Connection;
using Sql = Oxide.Core.Database.Sql;

namespace Oxide.Plugins
{
    [Info("PowerfulWhitelist", "codeboy", "1.0.1")]
    [Description("Whitelist for PowerfulAdmin | embedded panel UI, standalone commands")]
    internal class PowerfulWhitelist : RustPlugin
    {
        #region Classes

        private static class Permissions
        {
            public const string View = "powerfulwhitelist.view";
            public const string Manage = "powerfulwhitelist.manage";
            public const string Bypass = "powerfulwhitelist.bypass";
            public static readonly string[] All = { View, Manage, Bypass };
        }

        private enum StorageBackend
        {
            Json,
            Sqlite,
            MySql
        }

        private enum StorageState
        {
            None,
            Connecting,
            Connected,
            Switching,
            Failed,
            SwitchFailed
        }

        private class WhitelistEntry
        {
            [JsonProperty("steamid")] public ulong SteamId;
            [JsonProperty("name")] public string Name = "";
            [JsonProperty("by")] public string By = "";
            [JsonProperty("by_steamid")] public ulong BySteamId;
            [JsonProperty("created")] public long Created;
        }

        private class ViewerState
        {
            public Dictionary<string, object> Context;
            public Dictionary<string, string> Palette;
            public int Page;
            public string Search = "";
            public ulong RemoveConfirm;
            public bool DialogOpen;
            public string DraftSteamId = "";
            public string DraftName = "";
            public bool PickerOpen;
            public string PickerSearch = "";
            public int PickerPage;
            public string StorageSelection = "";
            public bool StorageConfirm;
            public StorageState StorageStatus = StorageState.None;
        }

        private class PickCandidate
        {
            public ulong SteamId;
            public string Name = "";
            public bool Online;
        }

        private class MySqlConfig
        {
            [JsonProperty(Order = 1)] public string Host = "127.0.0.1";
            [JsonProperty(Order = 2)] public int Port = 3306;
            [JsonProperty(Order = 3)] public string Database = "powerfulwhitelist";
            [JsonProperty(Order = 4)] public string User = "root";
            [JsonProperty(Order = 5)] public string Password = "";
        }

        private class ConfigData
        {
            [JsonProperty(Order = 1)] public bool Enabled;
            [JsonProperty(Order = 2)] public bool AllowAdmins = true;
            [JsonProperty(Order = 3)] public bool KickOnEnable = true;
            [JsonProperty(Order = 4)] public string ServerName = "";
            [JsonProperty(Order = 5)] public string InfoUrl = "";

            [JsonProperty(Order = 6)] [JsonConverter(typeof(StringEnumConverter))]
            public StorageBackend Storage = StorageBackend.Json;

            [JsonProperty(Order = 7)] public int SyncInterval = 60;

            [JsonProperty(Order = 8)] public MySqlConfig MySql = new();

            [JsonProperty(Order = 100)] public VersionNumber Version;
        }

        #endregion

        #region Fields

        [PluginReference] private Plugin PowerfulAdmin;

        private ConfigData _config;

        private readonly Dictionary<ulong, WhitelistEntry> _whitelist = new();

        private readonly Dictionary<ulong, WhitelistEntry> _pendingAdd = new();

        private readonly HashSet<ulong> _pendingRemove = new();

        private readonly Dictionary<ulong, ViewerState> _viewers = new();

        private bool _sectionRegistered;

        private Database _database;

        private bool _dbReady;

        private bool _dbEnabled;

        private bool _storageBusy;

        private Timer _refreshTimer;

        private Timer _retryTimer;

        private const float ReconnectInterval = 30f;

        private const int PerPage = 6;

        private const int PickerPerPage = 12;

        private const string RootLayer = "ui.PowerfulWhitelist";

        private const string SectionId = "whitelist";

        private const string SectionIcon = "assets/icons/check.png";

        #endregion

        #region Hooks

        private void OnServerInitialized()
        {
            foreach (var permissionName in Permissions.All)
                permission.RegisterPermission(permissionName, this);

            RegisterSection();
            StartStorage();
        }

        private void Unload()
        {
            PowerfulAdmin?.Call("API_RemoveSection", SectionId);
            foreach (var player in BasePlayer.activePlayerList)
                if (player != null)
                    CuiHelper.DestroyUi(player, RootLayer);
            _refreshTimer?.Destroy();
            _retryTimer?.Destroy();
            if (_config.Storage == StorageBackend.Json)
                SaveData();
            else
                _database?.Close();
        }

        private void OnPluginLoaded(Plugin plugin)
        {
            if (plugin == null || plugin.Name != "PowerfulAdmin")
                return;
            PowerfulAdmin = plugin;
            _sectionRegistered = false;
            RegisterSection();
        }

        private void OnPluginUnloaded(Plugin plugin)
        {
            if (plugin == null || plugin.Name != "PowerfulAdmin")
                return;
            PowerfulAdmin = null;
            _sectionRegistered = false;
        }

        private object CanClientLogin(Network.Connection connection)
        {
            if (!Enforcing)
                return null;
            if (IsAllowed(connection.userid))
                return null;
            Log($"rejected non-whitelisted {connection.username} ({connection.userid}) on login");
            return BuildRejectText(connection.userid.ToString());
        }

        private void OnPlayerConnected(BasePlayer player)
        {
            if (player == null)
                return;
            RefreshName(player);
            if (!Enforcing)
                return;
            if (IsAllowed(player.userID))
                return;
            player.Kick(BuildRejectText(player.UserIDString));
        }

        private void RefreshName(BasePlayer player)
        {
            if (player == null || !_whitelist.TryGetValue(player.userID, out var entry))
                return;

            var name = player.displayName;
            if (string.IsNullOrEmpty(name) || name == entry.Name)
                return;

            entry.Name = name;
            PersistAdd(entry);
            RefreshViewers();
        }

        private void OnPlayerDisconnected(BasePlayer player, string reason)
        {
            if (player == null)
                return;
            _viewers.Remove(player.userID);
        }

        #endregion

        #region Section registration

        private void RegisterSection()
        {
            PowerfulAdmin ??= plugins.Find("PowerfulAdmin");
            if (PowerfulAdmin == null || _sectionRegistered)
                return;
            var definition = new Dictionary<string, object>
            {
                ["id"] = SectionId,
                ["title"] = (Func<BasePlayer, string>)(viewer =>
                    GetLocalizedMessage(TranslateKey.UiTitle, viewer)),
                ["icon"] = SectionIcon,
                ["category"] = "nav.cat.tools",
                ["permission"] = Permissions.View,
                ["settingsHeight"] = (Func<BasePlayer, int>)SettingsHeight,
                ["open"] = (Action<BasePlayer>)UI_OpenSection,
                ["cardRows"] = (Func<string, List<string[]>>)(steamId =>
                    ulong.TryParse(steamId, out var parsed) ? UI_BuildCardRows(parsed) : null),
                ["settings"] = (Action<BasePlayer, CuiElementContainer, string, int>)UI_DrawSettings
            };
            _sectionRegistered = PowerfulAdmin.Call("API_AddSection", definition) is bool added && added;
        }

        private void UI_OpenSection(BasePlayer player)
        {
            if (player == null)
                return;
            var context = PowerfulAdmin?.Call("API_SectionContext", player) as Dictionary<string, object>;
            var viewer = Viewer(player.userID);
            viewer.Context = context;
            viewer.Palette = context != null && context.TryGetValue("palette", out var palette)
                ? palette as Dictionary<string, string>
                : null;
            viewer.RemoveConfirm = 0;
            viewer.DialogOpen = false;
            viewer.PickerOpen = false;
            UI_Refresh(player);
        }

        #endregion

        #region Methods

        private static long Now() => DateTimeOffset.Now.ToUnixTimeSeconds();

        private bool IsAllowed(ulong steamId)
        {
            if (UsesDatabase && !_dbReady)
                return true;
            if (_whitelist.ContainsKey(steamId))
                return true;
            var idString = steamId.ToString();
            if (permission.UserHasPermission(idString, Permissions.Bypass))
                return true;
            if (_config.AllowAdmins && IsServerAdmin(steamId))
                return true;
            return false;
        }

        private static bool IsServerAdmin(ulong steamId) =>
            ServerUsers.Is(steamId, ServerUsers.UserGroup.Owner) ||
            ServerUsers.Is(steamId, ServerUsers.UserGroup.Moderator);

        private bool AddEntry(ulong steamId, string name, string by, ulong bySteamId = 0)
        {
            if (steamId == 0 || _whitelist.ContainsKey(steamId))
                return false;

            _whitelist[steamId] = new WhitelistEntry
            {
                SteamId = steamId,
                Name = string.IsNullOrEmpty(name) ? steamId.ToString() : name,
                By = string.IsNullOrEmpty(by) ? "Server" : by,
                BySteamId = bySteamId,
                Created = Now()
            };
            PersistAdd(_whitelist[steamId]);
            Log($"{by} added {name} ({steamId}) to the whitelist");
            Interface.CallHook("OnPowerfulWhitelistAdded", steamId, name, by);
            return true;
        }

        private bool RemoveEntry(ulong steamId, string by)
        {
            if (!_whitelist.Remove(steamId))
                return false;

            PersistRemove(steamId);
            Log($"{by} removed {steamId} from the whitelist");
            Interface.CallHook("OnPowerfulWhitelistRemoved", steamId, by);
            if (Enforcing)
            {
                var online = BasePlayer.FindByID(steamId);
                if (online != null && online.IsConnected && !IsAllowed(steamId))
                    online.Kick(BuildRejectText(online.UserIDString));
            }

            return true;
        }

        private int EnforceKick(BasePlayer except)
        {
            if (!Enforcing)
                return 0;

            var targets = Pool.Get<List<BasePlayer>>();
            foreach (var player in BasePlayer.activePlayerList)
                if (player != null && player != except && !IsAllowed(player.userID))
                    targets.Add(player);

            var count = targets.Count;
            foreach (var player in targets)
                player.Kick(BuildRejectText(player.UserIDString));
            Pool.FreeUnmanaged(ref targets);
            return count;
        }

        private string BuildRejectText(string userId)
        {
            var text = lang.GetMessage(TranslateKey.Reject, this, userId);
            if (!string.IsNullOrEmpty(_config.ServerName))
                text = _config.ServerName + "\n\n" + text;
            if (!string.IsNullOrEmpty(_config.InfoUrl))
                text += "\n" + string.Format(lang.GetMessage(TranslateKey.RejectInfo, this, userId), _config.InfoUrl);
            return text;
        }

        private static bool ResolveTarget(string token, out ulong steamId, out string name)
        {
            steamId = 0;
            name = "";
            if (string.IsNullOrWhiteSpace(token))
                return false;

            token = token.Trim();
            if (ulong.TryParse(token, out var parsed))
            {
                steamId = parsed;
                name = BasePlayer.FindAwakeOrSleepingByID(parsed)?.displayName ?? token;
                return true;
            }

            var match = BasePlayer.FindAwakeOrSleeping(token);
            if (match == null)
                return false;

            steamId = match.userID;
            name = match.displayName;
            return true;
        }

        private List<WhitelistEntry> FilterEntries(string search, out int total)
        {
            IEnumerable<WhitelistEntry> query = _whitelist.Values;
            if (!string.IsNullOrEmpty(search))
            {
                var needle = search.Trim();
                query = query.Where(entry =>
                    (!string.IsNullOrEmpty(entry.Name) &&
                     entry.Name.IndexOf(needle, StringComparison.OrdinalIgnoreCase) >= 0) ||
                    entry.SteamId.ToString().Contains(needle));
            }

            var list = query.OrderByDescending(entry => entry.Created).ToList();
            total = list.Count;
            return list;
        }

        private static string FormatDate(long unix)
        {
            if (unix <= 0)
                return "-";
            return DateTimeOffset.FromUnixTimeSeconds(unix).LocalDateTime.ToString("dd.MM.yyyy");
        }

        private string GetLocalizedMessage(string key, BasePlayer player) =>
            lang.GetMessage(key, this, player?.UserIDString);

        private void Notify(BasePlayer player, string message)
        {
            if (string.IsNullOrEmpty(message))
                return;
            if (player == null)
            {
                Puts(message);
                return;
            }

            player.ChatMessage(
                $"<color=#{AccentHex(player)}>{GetLocalizedMessage(TranslateKey.Prefix, player)}</color> " +
                $"<color=#9b9ba3>›</color> <color=#d7d9e0>{message}</color>");
        }

        private string AccentHex(BasePlayer player)
        {
            var accent = "0.357 0.776 0.902 1";
            if (player != null && _viewers.TryGetValue(player.userID, out var viewer) && viewer.Palette != null &&
                viewer.Palette.TryGetValue("accent", out var value) && !string.IsNullOrEmpty(value))
                accent = value;
            return RgbaToHex(accent);
        }

        private static string RgbaToHex(string rgba)
        {
            var parts = rgba.Split(' ');
            if (parts.Length < 3)
                return "5ac6e6";
            var culture = System.Globalization.CultureInfo.InvariantCulture;
            float.TryParse(parts[0], System.Globalization.NumberStyles.Float, culture, out var r);
            float.TryParse(parts[1], System.Globalization.NumberStyles.Float, culture, out var g);
            float.TryParse(parts[2], System.Globalization.NumberStyles.Float, culture, out var b);
            return
                $"{(int)(Mathf.Clamp01(r) * 255):X2}{(int)(Mathf.Clamp01(g) * 255):X2}{(int)(Mathf.Clamp01(b) * 255):X2}";
        }

        private void Log(string message)
        {
            Puts(message);
            PowerfulAdmin?.Call("API_Log", "[PowerfulWhitelist] " + message, "Cmd");
        }

        private bool HasPermission(BasePlayer player, string permissionName) =>
            player != null && permission.UserHasPermission(player.UserIDString, permissionName);

        private static string[] ConsoleArguments(ConsoleSystem.Arg arg)
        {
            if (arg == null || !arg.HasArgs())
                return Array.Empty<string>();
            var arguments = new string[arg.Args.Length];
            for (var index = 0; index < arguments.Length; index++)
                arguments[index] = arg.GetString(index);
            return arguments;
        }

        private bool IsConsoleAllowed(ConsoleSystem.Arg arg, string permissionName)
        {
            var player = arg?.Player();
            if (player == null)
                return true;
            return HasPermission(player, permissionName);
        }

        private void ReplyTo(ConsoleSystem.Arg arg, string message)
        {
            if (arg?.Player() != null)
                Notify(arg.Player(), message);
            else
                Puts(message);
        }

        private string StatusWord(BasePlayer player) =>
            Enforcing
                ? GetLocalizedMessage(TranslateKey.StateOn, player)
                : GetLocalizedMessage(TranslateKey.StateOff, player);

        #endregion

        #region Commands

        [ChatCommand("whitelist")]
        private void CommandChatWhitelist(BasePlayer player, string command, string[] arguments)
        {
            HandleChat(player, arguments);
        }

        [ChatCommand("wl")]
        private void CommandChatWhitelistAlias(BasePlayer player, string command, string[] arguments)
        {
            HandleChat(player, arguments);
        }

        private void HandleChat(BasePlayer player, string[] arguments)
        {
            if (!HasPermission(player, Permissions.View) && !HasPermission(player, Permissions.Manage))
            {
                Notify(player, GetLocalizedMessage(TranslateKey.NoPermission, player));
                return;
            }

            if (arguments == null || arguments.Length == 0 ||
                arguments[0].Equals("help", StringComparison.OrdinalIgnoreCase))
            {
                Notify(player, GetLocalizedMessage(TranslateKey.Usage, player));
                Notify(player, string.Format(GetLocalizedMessage(TranslateKey.Status, player), StatusWord(player),
                    _whitelist.Count));
                return;
            }

            var sub = arguments[0].ToLowerInvariant();
            var rest = arguments.Skip(1).ToArray();
            if (sub == "add")
                DoAdd(player, rest, message => Notify(player, message));
            else if (sub == "remove" || sub == "del")
                DoRemove(player, rest, message => Notify(player, message));
            else if (sub == "list")
                DoList(player, rest, message => Notify(player, message));
            else if (sub == "on" || sub == "enable")
                DoEnable(player, true, message => Notify(player, message));
            else if (sub == "off" || sub == "disable")
                DoEnable(player, false, message => Notify(player, message));
            else if (sub == "enforce" || sub == "kick")
                DoEnforce(player, message => Notify(player, message));
            else if (sub == "status")
                Notify(player, string.Format(GetLocalizedMessage(TranslateKey.Status, player), StatusWord(player),
                    _whitelist.Count));
            else
                Notify(player, GetLocalizedMessage(TranslateKey.Usage, player));
        }

        [ConsoleCommand("pwl")]
        private void CommandConsole(ConsoleSystem.Arg arg)
        {
            var player = arg?.Player();
            var arguments = ConsoleArguments(arg);
            var sub = arguments.Length > 0 ? arguments[0].ToLowerInvariant() : "help";
            var rest = arguments.Skip(1).ToArray();
            if (sub == "add")
            {
                if (IsConsoleAllowed(arg, Permissions.Manage))
                    DoAdd(player, rest, message => ReplyTo(arg, message));
            }
            else if (sub == "remove" || sub == "del")
            {
                if (IsConsoleAllowed(arg, Permissions.Manage))
                    DoRemove(player, rest, message => ReplyTo(arg, message));
            }
            else if (sub == "list")
            {
                if (IsConsoleAllowed(arg, Permissions.View))
                    DoList(player, rest, message => ReplyTo(arg, message));
            }
            else if (sub == "on" || sub == "enable")
            {
                if (IsConsoleAllowed(arg, Permissions.Manage))
                    DoEnable(player, true, message => ReplyTo(arg, message));
            }
            else if (sub == "off" || sub == "disable")
            {
                if (IsConsoleAllowed(arg, Permissions.Manage))
                    DoEnable(player, false, message => ReplyTo(arg, message));
            }
            else if (sub == "enforce" || sub == "kick")
            {
                if (IsConsoleAllowed(arg, Permissions.Manage))
                    DoEnforce(player, message => ReplyTo(arg, message));
            }
            else if (sub == "status")
            {
                if (IsConsoleAllowed(arg, Permissions.View))
                    ReplyTo(arg, string.Format(GetLocalizedMessage(TranslateKey.Status, player), StatusWord(player),
                        _whitelist.Count));
            }
            else if (IsConsoleAllowed(arg, Permissions.View))
                ReplyTo(arg, GetLocalizedMessage(TranslateKey.Usage, player));
        }

        private void DoAdd(BasePlayer admin, string[] arguments, Action<string> reply)
        {
            if (arguments == null || arguments.Length == 0)
            {
                reply(GetLocalizedMessage(TranslateKey.Usage, admin));
                return;
            }

            if (!ResolveTarget(arguments[0], out var steamId, out var name))
            {
                reply(string.Format(GetLocalizedMessage(TranslateKey.NotFound, admin), arguments[0]));
                return;
            }

            if (!AddEntry(steamId, name, admin?.displayName ?? "Server", admin?.userID ?? 0))
            {
                reply(string.Format(GetLocalizedMessage(TranslateKey.AlreadyListed, admin), name));
                return;
            }

            reply(string.Format(GetLocalizedMessage(TranslateKey.Added, admin), name));
        }

        private void DoRemove(BasePlayer admin, string[] arguments, Action<string> reply)
        {
            if (arguments == null || arguments.Length == 0)
            {
                reply(GetLocalizedMessage(TranslateKey.Usage, admin));
                return;
            }

            if (!ResolveTarget(arguments[0], out var steamId, out var name))
            {
                reply(string.Format(GetLocalizedMessage(TranslateKey.NotFound, admin), arguments[0]));
                return;
            }

            if (!RemoveEntry(steamId, admin?.displayName ?? "Server"))
            {
                reply(string.Format(GetLocalizedMessage(TranslateKey.NotListed, admin), name));
                return;
            }

            reply(string.Format(GetLocalizedMessage(TranslateKey.Removed, admin), name));
        }

        private void DoList(BasePlayer admin, string[] arguments, Action<string> reply)
        {
            var entries = FilterEntries("", out var total);
            if (total == 0)
            {
                reply(GetLocalizedMessage(TranslateKey.ListEmpty, admin));
                return;
            }

            var perPage = 20;
            var pages = (total + perPage - 1) / perPage;
            var page = arguments != null && arguments.Length > 0 && int.TryParse(arguments[0], out var parsed)
                ? Mathf.Clamp(parsed, 1, pages)
                : 1;
            var lines = entries.Skip((page - 1) * perPage).Take(perPage)
                .Select(entry => $"{entry.SteamId} · {entry.Name} · {entry.By} · {FormatDate(entry.Created)}");
            reply(string.Format(GetLocalizedMessage(TranslateKey.ListHeader, admin), page, pages, total) + "\n" +
                  string.Join("\n", lines));
        }

        private void DoEnable(BasePlayer admin, bool enable, Action<string> reply)
        {
            if (_config.Enabled == enable)
            {
                reply(GetLocalizedMessage(enable ? TranslateKey.EnabledOn : TranslateKey.EnabledOff, admin));
                return;
            }

            var wasEnforcing = Enforcing;
            _config.Enabled = enable;
            SaveConfig();
            Log($"{(admin?.displayName ?? "Server")} turned this-server whitelist {(enable ? "on" : "off")}");
            reply(GetLocalizedMessage(enable ? TranslateKey.EnabledOn : TranslateKey.EnabledOff, admin));
            if (Enforcing && !wasEnforcing && _config.KickOnEnable)
            {
                var kicked = EnforceKick(admin);
                if (kicked > 0)
                    reply(string.Format(GetLocalizedMessage(TranslateKey.Enforced, admin), kicked));
            }
        }

        private void DoEnforce(BasePlayer admin, Action<string> reply)
        {
            if (!Enforcing)
            {
                reply(GetLocalizedMessage(TranslateKey.EnabledOff, admin));
                return;
            }

            var kicked = EnforceKick(admin);
            reply(kicked > 0
                ? string.Format(GetLocalizedMessage(TranslateKey.Enforced, admin), kicked)
                : GetLocalizedMessage(TranslateKey.NothingToKick, admin));
        }

        #endregion

        #region UI commands

        private bool UI_Guard(ConsoleSystem.Arg arg, out BasePlayer player, out ViewerState viewer,
            string permissionName)
        {
            player = arg?.Player();
            viewer = null;
            if (player == null)
                return false;
            if (!_viewers.TryGetValue(player.userID, out viewer) || viewer.Context == null)
                return false;
            return HasPermission(player, permissionName);
        }

        [ConsoleCommand("pwl.ui.refresh")]
        private void CommandUiRefresh(ConsoleSystem.Arg arg)
        {
            if (!UI_Guard(arg, out var player, out _, Permissions.View))
                return;
            UI_Refresh(player);
        }

        [ConsoleCommand("pwl.ui.search")]
        private void CommandUiSearch(ConsoleSystem.Arg arg)
        {
            if (!UI_Guard(arg, out var player, out var viewer, Permissions.View))
                return;
            var value = arg.HasArgs() ? string.Join(" ", ConsoleArguments(arg)).Trim() : "";
            if (value == GetLocalizedMessage(TranslateKey.UiSearch, player).Trim())
                value = "";
            viewer.Search = value;
            viewer.Page = 0;
            viewer.RemoveConfirm = 0;
            UI_Refresh(player);
        }

        [ConsoleCommand("pwl.ui.page")]
        private void CommandUiPage(ConsoleSystem.Arg arg)
        {
            if (!UI_Guard(arg, out var player, out var viewer, Permissions.View))
                return;
            viewer.Page = arg.GetInt(0, 0);
            viewer.RemoveConfirm = 0;
            UI_Refresh(player);
        }

        [ConsoleCommand("pwl.ui.toggle")]
        private void CommandUiToggle(ConsoleSystem.Arg arg)
        {
            if (!UI_Guard(arg, out var player, out _, Permissions.Manage))
                return;
            DoEnable(player, !_config.Enabled, message => Notify(player, message));
            PowerfulAdmin?.Call("API_RefreshSettings", player);
            UI_Refresh(player);
        }

        [ConsoleCommand("pwl.ui.dbtoggle")]
        private void CommandUiDbToggle(ConsoleSystem.Arg arg)
        {
            if (!UI_Guard(arg, out var player, out _, Permissions.Manage))
                return;
            if (!UsesDatabase || _database?.Connection == null)
            {
                Notify(player, GetLocalizedMessage(TranslateKey.DbToggleUnavailable, player));
                UI_Refresh(player);
                return;
            }

            var wasEnforcing = Enforcing;
            _dbEnabled = !_dbEnabled;
            WriteDbEnabled();
            Log($"{player.displayName} turned database whitelist {(_dbEnabled ? "on" : "off")}");
            Notify(player, GetLocalizedMessage(_dbEnabled ? TranslateKey.DbEnabledOn : TranslateKey.DbEnabledOff, player));
            if (Enforcing && !wasEnforcing && _config.KickOnEnable)
            {
                var kicked = EnforceKick(player);
                if (kicked > 0)
                    Notify(player, string.Format(GetLocalizedMessage(TranslateKey.Enforced, player), kicked));
            }

            UI_Refresh(player);
        }

        [ConsoleCommand("pwl.ui.enforce")]
        private void CommandUiEnforce(ConsoleSystem.Arg arg)
        {
            if (!UI_Guard(arg, out var player, out _, Permissions.Manage))
                return;
            DoEnforce(player, message => Notify(player, message));
            UI_Refresh(player);
        }

        [ConsoleCommand("pwl.ui.remove")]
        private void CommandUiRemove(ConsoleSystem.Arg arg)
        {
            if (!UI_Guard(arg, out var player, out var viewer, Permissions.Manage))
                return;
            viewer.RemoveConfirm = ulong.TryParse(arg.GetString(0), out var steamId) ? steamId : 0;
            UI_Refresh(player);
        }

        [ConsoleCommand("pwl.ui.removeno")]
        private void CommandUiRemoveNo(ConsoleSystem.Arg arg)
        {
            if (!UI_Guard(arg, out var player, out var viewer, Permissions.Manage))
                return;
            viewer.RemoveConfirm = 0;
            UI_Refresh(player);
        }

        [ConsoleCommand("pwl.ui.removeyes")]
        private void CommandUiRemoveYes(ConsoleSystem.Arg arg)
        {
            if (!UI_Guard(arg, out var player, out var viewer, Permissions.Manage))
                return;
            viewer.RemoveConfirm = 0;
            if (ulong.TryParse(arg.GetString(0), out var steamId))
            {
                RemoveEntry(steamId, player.displayName);
                PowerfulAdmin?.Call("API_RefreshPlayerCard", steamId.ToString());
            }

            UI_Refresh(player);
        }

        [ConsoleCommand("pwl.ui.addopen")]
        private void CommandUiAddOpen(ConsoleSystem.Arg arg)
        {
            if (!UI_Guard(arg, out var player, out var viewer, Permissions.Manage))
                return;
            viewer.DialogOpen = true;
            viewer.DraftSteamId = "";
            viewer.DraftName = "";
            UI_Refresh(player);
        }

        [ConsoleCommand("pwl.ui.addclose")]
        private void CommandUiAddClose(ConsoleSystem.Arg arg)
        {
            if (!UI_Guard(arg, out var player, out var viewer, Permissions.Manage))
                return;
            viewer.DialogOpen = false;
            viewer.PickerOpen = false;
            UI_Refresh(player);
        }

        [ConsoleCommand("pwl.ui.draft")]
        private void CommandUiDraft(ConsoleSystem.Arg arg)
        {
            if (!UI_Guard(arg, out var player, out var viewer, Permissions.Manage))
                return;
            var field = arg.GetString(0);
            var value = arg.HasArgs(2) ? string.Join(" ", ConsoleArguments(arg).Skip(1)).Trim() : "";
            if (field == "sid")
            {
                viewer.DraftSteamId = value;
                viewer.DraftName = "";
            }

            UI_Refresh(player);
        }

        [ConsoleCommand("pwl.ui.addconfirm")]
        private void CommandUiAddConfirm(ConsoleSystem.Arg arg)
        {
            if (!UI_Guard(arg, out var player, out var viewer, Permissions.Manage))
                return;
            if (!ulong.TryParse(viewer.DraftSteamId.Trim(), out var steamId) || !steamId.IsSteamId())
            {
                Notify(player, GetLocalizedMessage(TranslateKey.BadSteamid, player));
                return;
            }

            var name = string.IsNullOrEmpty(viewer.DraftName)
                ? BasePlayer.FindAwakeOrSleepingByID(steamId)?.displayName ?? viewer.DraftSteamId
                : viewer.DraftName;
            if (!AddEntry(steamId, name, player.displayName, player.userID))
            {
                Notify(player, string.Format(GetLocalizedMessage(TranslateKey.AlreadyListed, player), name));
                return;
            }

            PowerfulAdmin?.Call("API_RefreshPlayerCard", steamId.ToString());
            viewer.DialogOpen = false;
            viewer.PickerOpen = false;
            viewer.Page = 0;
            UI_Refresh(player);
        }

        [ConsoleCommand("pwl.ui.pickopen")]
        private void CommandUiPickOpen(ConsoleSystem.Arg arg)
        {
            if (!UI_Guard(arg, out var player, out var viewer, Permissions.Manage))
                return;
            viewer.PickerOpen = true;
            viewer.PickerSearch = "";
            viewer.PickerPage = 0;
            UI_Refresh(player);
        }

        [ConsoleCommand("pwl.ui.pickclose")]
        private void CommandUiPickClose(ConsoleSystem.Arg arg)
        {
            if (!UI_Guard(arg, out var player, out var viewer, Permissions.Manage))
                return;
            viewer.PickerOpen = false;
            CuiHelper.DestroyUi(player, RootLayer + ".picker");
        }

        [ConsoleCommand("pwl.ui.pickersearch")]
        private void CommandUiPickerSearch(ConsoleSystem.Arg arg)
        {
            if (!UI_Guard(arg, out var player, out var viewer, Permissions.Manage))
                return;
            var value = arg.HasArgs() ? string.Join(" ", ConsoleArguments(arg)).Trim() : "";
            if (value == GetLocalizedMessage(TranslateKey.UiSearch, player).Trim())
                value = "";
            viewer.PickerSearch = value;
            viewer.PickerPage = 0;
            if (viewer.PickerOpen)
                UI_DrawPlayerPicker(player, viewer);
        }

        [ConsoleCommand("pwl.ui.pickerpage")]
        private void CommandUiPickerPage(ConsoleSystem.Arg arg)
        {
            if (!UI_Guard(arg, out var player, out var viewer, Permissions.Manage))
                return;
            viewer.PickerPage = arg.GetInt(0, 0);
            if (viewer.PickerOpen)
                UI_DrawPlayerPicker(player, viewer);
        }

        [ConsoleCommand("pwl.ui.pick")]
        private void CommandUiPick(ConsoleSystem.Arg arg)
        {
            if (!UI_Guard(arg, out var player, out var viewer, Permissions.Manage))
                return;
            if (ulong.TryParse(arg.GetString(0), out var steamId))
            {
                viewer.DraftSteamId = steamId.ToString();
                viewer.DraftName = arg.HasArgs(2) ? string.Join(" ", ConsoleArguments(arg).Skip(1)).Trim() : "";
            }

            viewer.PickerOpen = false;
            viewer.DialogOpen = true;
            UI_Refresh(player);
        }

        #endregion

        #region Config commands

        private bool CanEditSettings(BasePlayer player) =>
            player != null && permission.UserHasPermission(player.UserIDString, "powerfuladmin.settings");

        [ConsoleCommand("pwl.cfg.toggle")]
        private void CommandConfigToggle(ConsoleSystem.Arg arg)
        {
            var player = arg?.Player();
            if (player == null || !CanEditSettings(player))
                return;
            var key = arg.GetString(0);
            if (key == "allowadmins")
                _config.AllowAdmins = !_config.AllowAdmins;
            else if (key == "kickonenable")
                _config.KickOnEnable = !_config.KickOnEnable;
            else
                return;
            SaveConfig();
            PowerfulAdmin?.Call("API_RefreshSettings", player);
        }

        [ConsoleCommand("pwl.cfg.input")]
        private void CommandConfigInput(ConsoleSystem.Arg arg)
        {
            var player = arg?.Player();
            if (player == null || !CanEditSettings(player))
                return;
            var key = arg.GetString(0);
            var value = arg.HasArgs(2) ? string.Join(" ", ConsoleArguments(arg).Skip(1)).Trim() : "";
            if (key == "servername")
                _config.ServerName = value;
            else if (key == "infourl")
                _config.InfoUrl = value;
            else
                return;
            SaveConfig();
            PowerfulAdmin?.Call("API_RefreshSettings", player);
        }

        [ConsoleCommand("pwl.cfg.storagesel")]
        private void CommandConfigStorageSelect(ConsoleSystem.Arg arg)
        {
            var player = arg?.Player();
            if (player == null || !CanEditSettings(player) || _storageBusy)
                return;
            var selection = arg.GetString(0).ToLowerInvariant();
            if (selection != "json" && selection != "sqlite" && selection != "mysql")
                return;
            var viewer = Viewer(player.userID);
            viewer.StorageSelection = selection;
            viewer.StorageConfirm = false;
            viewer.StorageStatus = StorageState.None;
            PowerfulAdmin?.Call("API_RefreshSettings", player);
        }

        [ConsoleCommand("pwl.cfg.dbfield")]
        private void CommandConfigDbField(ConsoleSystem.Arg arg)
        {
            var player = arg?.Player();
            if (player == null || !CanEditSettings(player))
                return;
            var field = arg.GetString(0);
            var value = arg.HasArgs(2) ? string.Join(" ", ConsoleArguments(arg).Skip(1)).Trim() : "";
            if (field == "host")
                _config.MySql.Host = value;
            else if (field == "port" && int.TryParse(value, out var port))
                _config.MySql.Port = port;
            else if (field == "database")
                _config.MySql.Database = value;
            else if (field == "user")
                _config.MySql.User = value;
            else if (field == "password")
                _config.MySql.Password = value;
            else if (field != "port")
                return;
            SaveConfig();
            Viewer(player.userID).StorageStatus = StorageState.None;
            PowerfulAdmin?.Call("API_RefreshSettings", player);
        }

        [ConsoleCommand("pwl.cfg.dbtest")]
        private void CommandConfigDbTest(ConsoleSystem.Arg arg)
        {
            var player = arg?.Player();
            if (player == null || !CanEditSettings(player) || _storageBusy)
                return;
            var viewer = Viewer(player.userID);
            viewer.StorageStatus = StorageState.Connecting;
            PowerfulAdmin?.Call("API_RefreshSettings", player);
            var test = new Database(StorageBackend.MySql, this, $"{Name}.db", _config.MySql,
                warning => PrintWarning(warning));
            if (!test.Open())
            {
                viewer.StorageStatus = StorageState.Failed;
                PowerfulAdmin?.Call("API_RefreshSettings", player);
                return;
            }

            test.Query(Sql.Builder.Append("SELECT 1 AS ok"), rows =>
            {
                test.Close();
                viewer.StorageStatus = rows != null && rows.Count > 0 ? StorageState.Connected : StorageState.Failed;
                PowerfulAdmin?.Call("API_RefreshSettings", player);
            });
        }

        [ConsoleCommand("pwl.cfg.storageapply")]
        private void CommandConfigStorageApply(ConsoleSystem.Arg arg)
        {
            var player = arg?.Player();
            if (player == null || !CanEditSettings(player) || _storageBusy)
                return;
            var viewer = Viewer(player.userID);
            var selected = SelectedBackend(viewer);
            if (selected == StorageId(_config.Storage))
            {
                viewer.StorageConfirm = false;
                PowerfulAdmin?.Call("API_RefreshSettings", player);
                return;
            }

            if (!arg.HasArgs())
            {
                viewer.StorageConfirm = true;
                PowerfulAdmin?.Call("API_RefreshSettings", player);
                return;
            }

            viewer.StorageConfirm = false;
            if (!arg.GetBool(0))
            {
                PowerfulAdmin?.Call("API_RefreshSettings", player);
                return;
            }

            _storageBusy = true;
            viewer.StorageStatus = StorageState.Switching;
            PowerfulAdmin?.Call("API_RefreshSettings", player);
            SwitchStorage(player, viewer, ParseBackend(selected));
        }

        private static StorageBackend ParseBackend(string id) =>
            id == "mysql" ? StorageBackend.MySql :
            id == "sqlite" ? StorageBackend.Sqlite : StorageBackend.Json;

        #endregion

        #region UI

        private static string ThemeColor(ViewerState viewer, string key, string fallback) =>
            viewer.Palette != null && viewer.Palette.TryGetValue(key, out var value) && !string.IsNullOrEmpty(value)
                ? value
                : fallback;

        private static int GetContextInt(ViewerState viewer, string key, int fallback) =>
            viewer.Context != null && viewer.Context.TryGetValue(key, out var value) && value != null &&
            int.TryParse(value.ToString(), out var parsed)
                ? parsed
                : fallback;

        private static string GetContextString(ViewerState viewer, string key, string fallback) =>
            viewer.Context != null && viewer.Context.TryGetValue(key, out var value) && value != null
                ? value.ToString()
                : fallback;

        private ViewerState Viewer(ulong id)
        {
            if (!_viewers.TryGetValue(id, out var viewer))
            {
                viewer = new ViewerState();
                _viewers[id] = viewer;
            }

            return viewer;
        }

        private void UI_Refresh(BasePlayer player)
        {
            if (player == null || !player.IsConnected)
                return;
            var viewer = Viewer(player.userID);
            if (viewer.Context == null)
                return;
            var entries = FilterEntries(viewer.Search, out var total);
            UI_DrawList(player, viewer, entries, total);
        }

        private void UI_DrawList(BasePlayer player, ViewerState viewer, List<WhitelistEntry> entries, int total)
        {
            var parent = GetContextString(viewer, "parent", "Overlay");
            var bodyWidth = GetContextInt(viewer, "bodyW", 744);
            var pad = GetContextInt(viewer, "pad", 18);
            var fontBold = ThemeColor(viewer, "fontBold", "robotocondensed-bold.ttf");
            var fontRegular = ThemeColor(viewer, "fontRegular", "robotocondensed-regular.ttf");
            var fontMono = ThemeColor(viewer, "fontMono", "droidsansmono.ttf");
            var accent = ThemeColor(viewer, "accent", "0.357 0.776 0.902 1");
            var accentText = ThemeColor(viewer, "accentText", "0.039 0.059 0.090 1");
            var surface = ThemeColor(viewer, "surface", "0.086 0.125 0.180 1");
            var elevated = ThemeColor(viewer, "elev", "0.118 0.169 0.239 1");
            var border = ThemeColor(viewer, "border", "0.165 0.227 0.322 1");
            var pageColor = ThemeColor(viewer, "page", "0.039 0.059 0.090 1");
            var text = ThemeColor(viewer, "text", "0.902 0.933 0.973 1");
            var text2 = ThemeColor(viewer, "text2", "0.561 0.627 0.722 1");
            var text3 = ThemeColor(viewer, "text3", "0.392 0.451 0.541 1");
            var danger = ThemeColor(viewer, "danger", "0.949 0.376 0.384 1");
            var success = ThemeColor(viewer, "success", "0.388 0.800 0.518 1");
            var successSoft = ThemeColor(viewer, "successSoft", "0.388 0.800 0.518 0.15");
            var warn = ThemeColor(viewer, "warn", "0.949 0.647 0.345 1");
            var clear = ThemeColor(viewer, "clear", "0 0 0 0");
            var canManage = HasPermission(player, Permissions.Manage);
            var userId = player.UserIDString;

            var pages = Math.Max(1, (total + PerPage - 1) / PerPage);
            if (viewer.Page >= pages)
                viewer.Page = pages - 1;
            if (viewer.Page < 0)
                viewer.Page = 0;

            var container = new CuiElementContainer();
            container.Add(new CuiElement
            {
                Parent = parent, Name = RootLayer, DestroyUi = RootLayer,
                Components =
                {
                    new CuiImageComponent { Color = clear },
                    new CuiRectTransformComponent { AnchorMin = "0 0", AnchorMax = "1 1" }
                }
            });

            container.Add(new CuiLabel
            {
                Text =
                {
                    Text = string.Format(lang.GetMessage(TranslateKey.UiCount, this, userId), total),
                    FontSize = 10, Font = fontRegular, Align = TextAnchor.UpperLeft, Color = text2
                },
                RectTransform =
                    { AnchorMin = "0 1", AnchorMax = "1 1", OffsetMin = $"{pad} -53", OffsetMax = $"{-pad} -37" }
            }, RootLayer);

            var searchWidth = 200;
            var searchX = bodyWidth - pad - searchWidth;
            if (canManage)
                searchX -= 96;
            container.Add(new CuiElement
            {
                Parent = RootLayer, Name = RootLayer + ".search",
                Components =
                {
                    new CuiImageComponent { Color = pageColor },
                    new CuiOutlineComponent { Color = border, Distance = "1 1" },
                    new CuiRectTransformComponent
                    {
                        AnchorMin = "0 1", AnchorMax = "0 1", OffsetMin = $"{searchX} -42",
                        OffsetMax = $"{searchX + searchWidth} -14"
                    }
                }
            });
            var searchEmpty = string.IsNullOrEmpty(viewer.Search);
            container.Add(new CuiElement
            {
                Parent = RootLayer + ".search",
                Components =
                {
                    new CuiInputFieldComponent
                    {
                        Text = searchEmpty ? lang.GetMessage(TranslateKey.UiSearch, this, userId) : viewer.Search,
                        FontSize = 11, Font = fontRegular, Align = TextAnchor.MiddleLeft,
                        Color = searchEmpty ? text3 : text, CharsLimit = 32, NeedsKeyboard = true,
                        Command = "pwl.ui.search "
                    },
                    new CuiRectTransformComponent
            
// ... [Code preview truncated due to length. Full source in attached file] ...

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