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

FREE ServerPanel : 2.0.9 2.0.9

Нет прав для скачивания
C#:
// #define TESTING

using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using Facepunch;
using Facepunch.Extend;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Libraries;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using Oxide.Plugins.ServerPanelExtensionMethods;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
using Global = Rust.Global;
using Random = UnityEngine.Random;
using Time = UnityEngine.Time;

#if CARBON
using Carbon.Base;
using Carbon.Modules;
#endif

namespace Oxide.Plugins
{
    [Info("ServerPanel", "Mevent", "2.0.9")]
    public class ServerPanel : RustPlugin
    {
        #region Fields

        [PluginReference] private Plugin
            ImageLibrary = null,
            NoEscape = null,
            Notify = null,
            UINotify = null,
            KillRecords = null,
            Statistics = null,
            UltimateLeaderboard = null,
            ServerPanelPopUps = null,
            ServerPanelMigrations = null;

        private static ServerPanel Instance;

#if CARBON
		private ImageDatabaseModule imageDatabase;
#endif

        private bool _enabledImageLibrary;

        private readonly Dictionary<ulong, float> _lastCommandTime = new();

        private Dictionary<int, int> _categoriesByID = new();

        private Dictionary<string, (int, int)> _categoriesByCommand = new();

        private Dictionary<int, Coroutine> _categoriesActiveCoroutines = new();

        private Dictionary<string, Func<BasePlayer, string>> _headerUpdateFields;

        private Dictionary<string, List<string>> _headerUpdateFieldsByPlugin = new();

        private const string
            Perm_Edit = "serverpanel.edit",
            CmdMainConsole = "UI_ServerPanel",
            CmdExample = "test_command_123",
            Layer = "UI.Server.Panel",
            ElementsLayer = "UI.Server.Panel.Elements",
            LayerHeader = "UI.Server.Panel.Header",
            LayerContent = "UI.Server.Panel.Content",
            LayerContentElements = "UI.Server.Panel.Content.Elements",
            LayerContentElementsStatic = "UI.Server.Panel.Content.Elements.Static",
            LayerCategories = "UI.Server.Panel.Categories",
            EditingLayerPageEditor = "UI.Server.Panel.Editor.Page",
            EditingLayerElementEditor = "UI.Server.Panel.Editor.Element",
            EditingLayerModal = "UI.Server.Panel.Editor.Modal",
            EditingLayerModalArrayView = EditingLayerModal + ".Content.View",
            EditingLayerModalColorSelector = "UI.Server.Panel.Editor.Modal.Color.Selector",
            EditingLayerModalTextEditor = "UI.Server.Panel.Editor.Modal.Text.Editor",
            EditingLayerModalPreClose = "UI.Server.Panel.Editor.Modal.PreClose",
            EditingElementOutline = "UI.Server.Panel.Editor.EditingElement.Outline";

        private HashSet<string> _registredCommands = new();

        private bool _migrationRequired;
        private string _migrationName;
        private bool _dataLoaded;
        private bool _migrationInProgress;
        private bool _waitingForMigrationsPlugin;

        #endregion

        #region Config

        private static Configuration _config;

        private class Configuration
        {
            #region Fields

            [JsonProperty(PropertyName = "Work with Notify?")]
            public bool UseNotify = true;

            [JsonProperty(PropertyName = "Enable Offline Image Mode")]
            public bool EnableOfflineImageMode = false;

            [JsonProperty(PropertyName = "Cooldown between actions (in seconds)")]
            public float CooldownBetweenActions = 0.2f;

            [JsonProperty(PropertyName = "Economy Header Fields",
                ObjectCreationHandling = ObjectCreationHandling.Replace)]
            public List<EconomyHeadField> EconomyFields = new()
            {
                EconomyHeadField.Create(true, EconomyEntry.CreateEconomics(), "{economy_economics}"),
                EconomyHeadField.Create(true, EconomyEntry.CreateServerRewards(), "{economy_server_rewards}"),
                EconomyHeadField.Create(true, EconomyEntry.CreateBankSystem(), "{economy_bank_system}")
            };

            [JsonProperty(PropertyName = "Block Settings")]
            public BlockSettings Block = new()
            {
                BlockWhenBuildingBlock = false,
                BlockWhenRaidBlock = false,
                BlockWhenCombatBlock = false
            };

            [JsonProperty(PropertyName = "Auto-Open Settings")]
            public AutoOpenSettings AutoOpen = new()
            {
                ShowMenuEveryTime = true
            };

            public VersionNumber Version;

            #endregion Fields

            #region Classes

            public class AutoOpenSettings
            {
                [JsonProperty(PropertyName = "Show menu every time player connects to server?")]
                public bool ShowMenuEveryTime = true;
            }

            public class BlockSettings
            {
                [JsonProperty(PropertyName = "Block the opening during a building block?")]
                public bool BlockWhenBuildingBlock;

                [JsonProperty(PropertyName = "Block the opening during a raid block?")]
                public bool BlockWhenRaidBlock;

                [JsonProperty(PropertyName = "Block the opening during a combat block?")]
                public bool BlockWhenCombatBlock;
            }

            public class EconomyHeadField
            {
                #region Fields

                [JsonProperty(PropertyName = "Enabled")]
                public bool Enabled;

                [JsonProperty(PropertyName = "Economy Settings")]
                public EconomyEntry Economy = new();

                [JsonProperty(PropertyName = "Update key (MUST BE UNIQUE)")]
                public string UpdateKey;

                #endregion

                #region Constructors

                public static EconomyHeadField Create(bool enabled, EconomyEntry economy, string updateKey)
                {
                    return new EconomyHeadField
                    {
                        Enabled = enabled,
                        Economy = economy,
                        UpdateKey = updateKey
                    };
                }

                #endregion
            }

            public enum EconomyType
            {
                Plugin,
                Item
            }

            public class EconomyEntry
            {
                #region Fields

                [JsonProperty(PropertyName = "Type (Plugin/Item)")] [JsonConverter(typeof(StringEnumConverter))]
                public EconomyType Type;

                [JsonProperty(PropertyName = "Plugin name")]
                public string Plug;

                [JsonProperty(PropertyName = "Balance add hook")]
                public string AddHook;

                [JsonProperty(PropertyName = "Balance remove hook")]
                public string RemoveHook;

                [JsonProperty(PropertyName = "Balance show hook")]
                public string BalanceHook;

                [JsonProperty(PropertyName = "ShortName")]
                public string ShortName;

                [JsonProperty(PropertyName = "Display Name (empty - default)")]
                public string DisplayName;

                [JsonProperty(PropertyName = "Skin")] public ulong Skin;

                [JsonProperty(PropertyName = "Lang Key (for Title)")]
                public string TitleLangKey;

                [JsonProperty(PropertyName = "Lang Key (for Balance)")]
                public string BalanceLangKey;

                #endregion Fields

                #region Public Methods

                #region Titles

                public string GetTitle(BasePlayer player)
                {
                    return Instance.Msg(player, TitleLangKey);
                }

                public string GetBalanceTitle(BasePlayer player)
                {
                    return Instance.Msg(player, BalanceLangKey, ShowBalance(player).ToString());
                }

                #endregion Titles

                #region Economy

                public double ShowBalance(BasePlayer player)
                {
                    switch (Type)
                    {
                        case EconomyType.Plugin:
                        {
                            var plugin = Instance?.plugins?.Find(Plug);
                            if (plugin == null)
                                return 0;

                            return Convert.ToDouble(plugin.Call(BalanceHook, player.UserIDString));
                        }
                        case EconomyType.Item:
                        {
                            return PlayerItemsCount(player, ShortName, Skin);
                        }
                        default:
                            return 0;
                    }
                }

                public void AddBalance(BasePlayer player, double amount)
                {
                    switch (Type)
                    {
                        case EconomyType.Plugin:
                        {
                            var plugin = Instance?.plugins.Find(Plug);
                            if (plugin == null) return;

                            switch (Plug)
                            {
                                case "BankSystem":
                                case "ServerRewards":
                                case "IQEconomic":
                                    plugin.Call(AddHook, player.UserIDString, (int) amount);
                                    break;
                                default:
                                    plugin.Call(AddHook, player.UserIDString, amount);
                                    break;
                            }

                            break;
                        }
                        case EconomyType.Item:
                        {
                            var am = (int) amount;

                            var item = ToItem(am);
                            if (item == null) return;

                            player.GiveItem(item);
                            break;
                        }
                    }
                }

                public bool RemoveBalance(BasePlayer player, double amount)
                {
                    switch (Type)
                    {
                        case EconomyType.Plugin:
                        {
                            if (ShowBalance(player) < amount) return false;

                            var plugin = Instance?.plugins.Find(Plug);
                            if (plugin == null) return false;

                            switch (Plug)
                            {
                                case "BankSystem":
                                case "ServerRewards":
                                case "IQEconomic":
                                    plugin.Call(RemoveHook, player.UserIDString, (int) amount);
                                    break;
                                default:
                                    plugin.Call(RemoveHook, player.UserIDString, amount);
                                    break;
                            }

                            return true;
                        }
                        case EconomyType.Item:
                        {
                            var playerItems = Pool.Get<List<Item>>();
                            player.inventory.GetAllItems(playerItems);

                            var am = (int) amount;

                            if (ItemCount(playerItems, ShortName, Skin) < am)
                            {
                                Pool.Free(ref playerItems);
                                return false;
                            }

                            Take(playerItems, ShortName, Skin, am);
                            Pool.Free(ref playerItems);
                            return true;
                        }
                        default:
                            return false;
                    }
                }

                #endregion Economy

                #endregion

                #region Private Methods

                private Item ToItem(int amount)
                {
                    var item = ItemManager.CreateByName(ShortName, amount, Skin);
                    if (item == null)
                    {
                        Debug.LogError($"Error creating item with ShortName: '{ShortName}'");
                        return null;
                    }

                    if (!string.IsNullOrEmpty(DisplayName)) item.name = DisplayName;

                    return item;
                }

                private static int PlayerItemsCount(BasePlayer player, string shortname, ulong skin)
                {
                    var items = Pool.Get<List<Item>>();
                    player.inventory.GetAllItems(items);

                    var result = ItemCount(items, shortname, skin);

                    Pool.Free(ref items);
                    return result;
                }

                private static int ItemCount(List<Item> items, string shortname, ulong skin)
                {
                    return items.FindAll(item =>
                            item.info.shortname == shortname && !item.isBroken && (skin == 0 || item.skin == skin))
                        .Sum(item => item.amount);
                }

                private static void Take(List<Item> itemList, string shortname, ulong skinId, int amountToTake)
                {
                    if (amountToTake == 0) return;

                    var takenAmount = 0;

                    var itemsToTake = Pool.Get<List<Item>>();

                    foreach (var item in itemList)
                    {
                        if (item.info.shortname != shortname ||
                            (skinId != 0 && item.skin != skinId) || item.isBroken) continue;

                        var remainingAmount = amountToTake - takenAmount;
                        if (remainingAmount <= 0) break;

                        if (item.amount > remainingAmount)
                        {
                            item.MarkDirty();
                            item.amount -= remainingAmount;
                            break;
                        }

                        if (item.amount <= remainingAmount)
                        {
                            takenAmount += item.amount;
                            itemsToTake.Add(item);
                        }

                        if (takenAmount == amountToTake)
                            break;
                    }

                    foreach (var itemToTake in itemsToTake)
                        itemToTake.RemoveFromContainer();

                    Pool.FreeUnmanaged(ref itemsToTake);
                }

                #endregion Private Methods

                #region Constructors

                public static EconomyEntry CreateEconomics()
                {
                    return new EconomyEntry
                    {
                        Type = EconomyType.Plugin,
                        Plug = "Economics",
                        TitleLangKey = "Economy.Economics.Title",
                        BalanceLangKey = "Economy.Economics.Balance",
                        AddHook = "Deposit",
                        BalanceHook = "Balance",
                        RemoveHook = "Withdraw",
                        ShortName = string.Empty,
                        DisplayName = string.Empty,
                        Skin = 0
                    };
                }

                public static EconomyEntry CreateServerRewards()
                {
                    return new EconomyEntry
                    {
                        Type = EconomyType.Plugin,
                        Plug = "ServerRewards",
                        TitleLangKey = "Economy.ServerRewards.Title",
                        BalanceLangKey = "Economy.ServerRewards.Balance",
                        AddHook = "AddPoints",
                        BalanceHook = "CheckPoints",
                        RemoveHook = "TakePoints",
                        ShortName = string.Empty,
                        DisplayName = string.Empty,
                        Skin = 0
                    };
                }

                public static EconomyEntry CreateBankSystem()
                {
                    return new EconomyEntry
                    {
                        Type = EconomyType.Plugin,
                        Plug = "BankSystem",
                        TitleLangKey = "Economy.BankSystem.Title",
                        BalanceLangKey = "Economy.BankSystem.Balance",
                        AddHook = "API_BankSystemDeposit",
                        BalanceHook = "API_BankSystemBalance",
                        RemoveHook = "API_BankSystemWithdraw",
                        ShortName = string.Empty,
                        DisplayName = string.Empty,
                        Skin = 0
                    };
                }

                public static EconomyEntry CreateIQEconomic()
                {
                    return new EconomyEntry
                    {
                        Type = EconomyType.Plugin,
                        Plug = "IQEconomic",
                        TitleLangKey = "Economy.IQEconomic.Title",
                        BalanceLangKey = "Economy.IQEconomic.Balance",
                        AddHook = "API_SET_BALANCE",
                        BalanceHook = "API_GET_BALANCE",
                        RemoveHook = "API_REMOVE_BALANCE",
                        ShortName = string.Empty,
                        DisplayName = string.Empty,
                        Skin = 0
                    };
                }

                public static EconomyEntry CreateScrap()
                {
                    return new EconomyEntry
                    {
                        Type = EconomyType.Item,
                        Plug = string.Empty,
                        TitleLangKey = "Economy.Scrap.Title",
                        BalanceLangKey = "Economy.Scrap.Balance",
                        AddHook = string.Empty,
                        BalanceHook = string.Empty,
                        RemoveHook = string.Empty,
                        ShortName = "scrap",
                        DisplayName = string.Empty,
                        Skin = 0
                    };
                }

                #endregion Constructors
            }

            #endregion
        }

        private bool hasConfigFile = true;

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                _config = Config.ReadObject<Configuration>();
                if (_config == null) throw new Exception();

                if (_config.Version < Version)
                    UpdateConfigValues();

                SaveConfig();
            }
            catch (Exception ex)
            {
                PrintError("Your configuration file contains an error. Using default configuration values.");
                LoadDefaultConfig();
                Debug.LogException(ex);
            }
        }

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

        protected override void LoadDefaultConfig()
        {
            hasConfigFile = false;
            _config = new Configuration();
        }

        private void UpdateConfigValues()
        {
            if (hasConfigFile)
            {
                if (_config.Version == default) _migrationRequired = true;

                if (_config.Version == new VersionNumber(2, 0, 0)) _migrationRequired = true;

                if (_config.Version == new VersionNumber(2, 0, 1)) _migrationRequired = true;

                if (_migrationRequired)
                {
                    _migrationName = "all";
                    return;
                }

                PrintWarning("Config update completed!");
            }

            _config.Version = Version;
        }

        #endregion Config

        #region Data

        #region Data.General

        public void SaveData()
        {
            SaveCategoriesData();

            SaveTemplateData();

            SaveLocalizationData();

            SaveHeaderFieldsData();

            SavePlayersData();
        }

        private void LoadData()
        {
            LoadCategoriesData();

            LoadTemplateData();

            LoadLocalizationData();

            LoadHeaderFieldsData();

            LoadPlayersData();
        }

        private void LoadDataFromFile<T>(ref T data, string filePath)
        {
            try
            {
                data = Interface.Oxide.DataFileSystem.ReadObject<T>(Path.Combine(Name, filePath));
            }
            catch (Exception e)
            {
                PrintError(e.ToString());
            }

            data ??= Activator.CreateInstance<T>();
        }

        private void SaveDataToFile<T>(T data, string filePath)
        {
            Interface.Oxide.DataFileSystem.WriteObject(Path.Combine(Name, filePath), data);
        }

        #endregion Data.General

        #region Data.Categories

        private bool _isCategoriesLoaded;

        private static CategoriesData _categoriesData;

        private class CategoriesData
        {
            [JsonProperty(PropertyName = "Categories", ObjectCreationHandling = ObjectCreationHandling.Replace)]
            public List<MenuCategory> Categories = new();
        }

        private void LoadCategoriesData()
        {
            if (_isCategoriesLoaded) return;

            LoadDataFromFile(ref _categoriesData, "Categories");

            _isCategoriesLoaded = true;
        }

        private void SaveCategoriesData()
        {
            SaveDataToFile(_categoriesData, "Categories");
        }

        #endregion Data.Categories

        #region Data.Template

        private static TemplateData _templateData;

        private void SaveTemplateData()
        {
            SaveDataToFile(_templateData, "Template");
        }

        private void LoadTemplateData()
        {
            LoadDataFromFile(ref _templateData, "Template");

            _templateData?.UI?.LoadAllElements();
        }

        private class TemplateData
        {
            #region Fields

            [JsonProperty(PropertyName = "Use an expert mod?")]
            public bool UseExpertMod = false;

            [JsonProperty(PropertyName = "UI Settings")]
            public UISettings UI;

            #endregion

            #region Public Methods

            public void ShowEditPageButtonsUI(BasePlayer player, ref List<string> allElements, string parent,
                string cmdAddPage = "",
                string cmdRemovePage = "",
                string cmdClonePage = "",
                string cmdMovePage = "")
            {
                #region Add Page

                allElements.Add(CuiJsonFactory.CreateButton(
                    parent: parent,
                    anchorMin: "0 0", anchorMax: "0 0", offsetMin: "10 10", offsetMax: "90 35",
                    color: IColor.Create("#4CAF50").Get(),
                    textColor: IColor.Create("#E2DBD4").Get(),
                    command: cmdAddPage,
                    text: "+ NEW PAGE",
                    font: "robotocondensed-bold.ttf",
                    fontSize: 11,
                    align: TextAnchor.MiddleCenter));

                #endregion

                #region Remove Page

                allElements.Add(CuiJsonFactory.CreateButton(
                    parent: parent,
                    anchorMin: "0 0", anchorMax: "0 0", offsetMin: "95 10", offsetMax: "175 35",
                    color: IColor.Create("#CF432D").Get(),
                    textColor: IColor.Create("#E2DBD4").Get(),
                    command: cmdRemovePage,
                    text: "DELETE PAGE",
                    font: "robotocondensed-bold.ttf",
                    fontSize: 11,
                    align: TextAnchor.MiddleCenter));

                #endregion

                #region Clone Page

                allElements.Add(CuiJsonFactory.CreateButton(
                    parent: parent,
                    anchorMin: "0 0", anchorMax: "0 0", offsetMin: "180 10", offsetMax: "260 35",
                    color: IColor.Create("#005FB7").Get(),
                    textColor: IColor.Create("#E2DBD4").Get(),
                    command: cmdClonePage,
                    text: "CLONE PAGE",
                    font: "robotocondensed-bold.ttf",
                    fontSize: 11,
                    align: TextAnchor.MiddleCenter));

                #endregion

                #region Move Page

                if (!string.IsNullOrEmpty(cmdMovePage))
                    allElements.Add(CuiJsonFactory.CreateButton(
                        parent: parent,
                        anchorMin: "0 0", anchorMax: "0 0", offsetMin: "265 10", offsetMax: "345 35",
                        color: IColor.Create("#A88600").Get(),
                        textColor: IColor.Create("#E2DBD4").Get(),
                        command: cmdMovePage,
                        text: "MOVE PAGE",
                        font: "robotocondensed-bold.ttf",
                        fontSize: 11,
                        align: TextAnchor.MiddleCenter));

                #endregion
            }

            public void ShowContentUISerialized(BasePlayer player,
                ref List<string> allElements,
                string cmdPage = "",
                Action<string> callback = null,
                bool needUpdate = false)
            {
                if (!TryGetOpenedMenu(player.userID, out var openedMenu)) return;

                allElements.Add(
                    UI.Content.Background.GetSerialized(player, Layer, LayerContent, LayerContent));
                
                allElements.Add(CuiJsonFactory.CreatePanel(parent: LayerContent, name: LayerContentElementsStatic, destroy: LayerContentElementsStatic, color: "0 0 0 0", anchorMin: "0 0", anchorMax: "1 1", offsetMin: "0 0", offsetMax: "0 0"));
                allElements.Add(CuiJsonFactory.CreatePanel(parent: LayerContent, name: LayerContentElements, destroy: LayerContentElements, color: "0 0 0 0", anchorMin: "0 0", anchorMax: "1 1", offsetMin: "0 0", offsetMax: "0 0"));

                var menuCategory = Instance.GetCategoryById(openedMenu.SelectedCategory);
                var page = openedMenu.PageIndex;
                var maxPages = menuCategory.Pages.Count;

                #region Plugin Page Elements

                var categoryPage = menuCategory?.Pages[page];
                if (categoryPage != null)
                    switch (categoryPage.Type)
                    {
                        case CategoryPage.PageType.Plugin:
                        {
                            var obj = categoryPage.Plugin?.Call(categoryPage.PluginHook, player);
                            if (obj is CuiElementContainer pluginElements && pluginElements.Count > 0)
                                allElements.Add(pluginElements.ToJson().RemoveArrayBrackets());
                            else if (obj is string serializedElements && !string.IsNullOrWhiteSpace(serializedElements))
                                allElements.Add(serializedElements);

                #region Pagination

                if (UI.Content.Pagination.Type == UISettings.PaginationUI.PaginationType.SubCategories)
                {
                    
                #region Pagination

                if (menuCategory.ShowPages || (CanPlayerEdit(player) && openedMenu.CanEditContent()) ||
                    (openedMenu.isEditMode && UI.Content.Pagination.Type ==
                        UISettings.PaginationUI.PaginationType.SubCategories))
                    UI.Content.Pagination.ShowPagination(player, ref allElements, LayerContentElements, page,
                        maxPages,
                        LayerContentElements + ".Navigation", cmdPage, needUpdate);

                #endregion Pagination
                }

                #endregion Pagination

                            break;
                        }

                        case CategoryPage.PageType.UI:
                        {
                            if (categoryPage.Elements != null)
                                foreach (var element in categoryPage.Elements)
                                    allElements.Add(element.GetSerialized(player,
                                        element.RequiresDynamicLayer() ? LayerContentElements : LayerContentElementsStatic,
                                        ElementsLayer + element.Name,
                                        textFormatter: text => Instance.FormatUpdateField(player, text)));

                            if (CanPlayerEdit(player) && openedMenu.CanEditContent())
                                UI.Content.EditButton.ShowEditButtonUI(player, ref allElements, LayerContentElements,
                                    LayerContentElements + ".EditButton",
                                    cmdEdit: $"{CmdMainConsole} edit_page start {menuCategory.ID} {page}");

                #region Pagination

                if (menuCategory.ShowPages || (CanPlayerEdit(player) && openedMenu.CanEditContent()) ||
                    (openedMenu.isEditMode && UI.Content.Pagination.Type ==
                        UISettings.PaginationUI.PaginationType.SubCategories))
                    UI.Content.Pagination.ShowPagination(player, ref allElements, LayerContentElements, page,
                        maxPages,
                        LayerContentElements + ".Navigation", cmdPage, needUpdate);

                #endregion Pagination

                            break;
                        }
                    }

                #endregion Plugin Page Elements

                callback?.Invoke(LayerContentElements);
            }

            public void ShowPaginationIfNeeded(BasePlayer player, ref List<string> allElements)
            {
                if (!TryGetOpenedMenu(player.userID, out var openedMenu)) return;

                var menuCategory = Instance.GetCategoryById(openedMenu.SelectedCategory);
                if (menuCategory == null || !(menuCategory.ShowPages || CanPlayerEdit(player))) return;
                var page = openedMenu.PageIndex;
                var maxPages = menuCategory.Pages.Count;

                UI.Content.Pagination.ShowPagination(player, ref allElements, LayerContentElements, page,
                    maxPages,
                    LayerContentElements + ".Navigation", $"{CmdMainConsole} menu page");
            }

            public void ShowCloseButtonUISerialized(BasePlayer player, ref List<string> allElements,
                string parent,
                string closeLayer = "",
                string command = "")
            {
                UI.CloseButton.ShowButtonUI(player, ref allElements, parent, parent + ".CloseButton", closeLayer,
                    command);
            }

            public void ShowBackgroundUISerialized(BasePlayer player, ref List<string> allElements,
                string cmdOnClick = "")
            {
                allElements.Add(
                    UI.Background.Background.GetSerialized(player, UI.Background.ParentLayer, Layer, Layer));

                if (UI.Background.CloseAfterClick)
                    allElements.Add(CuiJsonFactory.CreateButton(
                        parent: Layer,
                        command: cmdOnClick,
                        close: Layer));
            }

            public void ShowHeaderUISerialized(BasePlayer player, ref List<string> allElements)
            {
                allElements.Add(UI.Header.Background.GetSerialized(player, Layer, LayerHeader, LayerHeader));

                foreach (var headerField in _headerFieldsData.Fields)
                    allElements.Add(headerField.GetSerialized(player, LayerHeader, 
                        ElementsLayer + headerField.Name,
                        ElementsLayer + headerField.Name,
                        textFormatter: text => Instance.FormatUpdateField(player, text)));

                if (CanPlayerEdit(player) && TryGetOpenedMenu(player.userID, out var openedMenu))
                    ShowAdminModeButtonsUISerialized(player, ref allElements, openedMenu);
            }

            public void ShowAdminModeButtonsUISerialized(BasePlayer player, ref List<string> allElements,
                OpenedMenu openedMenu)
            {
                if (openedMenu == null) return;

                API_OnServerPanelDestroyAdminModeButtons(player);

                if (openedMenu.isEditMode)
                    UI.Header.EditPagesButton?.ShowEditButtonUI(player, ref allElements, LayerHeader,
                        LayerHeader + ".EditPagesButton",
                        cmdEdit: $"{CmdMainConsole} edit_category open_pages");

                if (openedMenu.CanEditContent())
                {
                    UI.Header.EditButton?.ShowEditButtonUI(player, ref allElements, LayerHeader,
                        LayerHeader + ".EditButton",
                        cmdEdit: $"{CmdMainConsole} edit_header_fields start");

                    UI.Header.EditPopUpsButton?.ShowEditButtonUI(player, ref allElements, LayerHeader,
                        LayerHeader + ".EditPopUpsButton",
                        cmdEdit: $"{CmdMainConsole} start_edit_popups");
                }
            }

            public void UpdateGlobalHeaderUISerialized(BasePlayer player, ref List<string> allElements)
            {
                foreach (var headerField in _headerFieldsData.Fields)
                    allElements.Add(headerField.GetSerialized(player, LayerHeader,
                        ElementsLayer + headerField.Name,
                        textFormatter: text => Instance.FormatUpdateField(player, text),
                        needUpdate: true));
            }

            public void UpdateHeaderUISerialized(BasePlayer player, ref List<string> allElements)
            {
                foreach (var headerField in _headerFieldsData.elementsToUpdate)
                    allElements.Add(headerField.GetSerialized(player, LayerHeader,
                        ElementsLayer + headerField.Name,
                        ElementsLayer + headerField.Name,
                        textFormatter: text => Instance.FormatUpdateField(player, text)));
            }

            public void ShowUpdateHeaderUI(BasePlayer player)
            {
                UpdateUI(player, (List<string> allElements) => UpdateHeaderUISerialized(player, ref allElements));
            }

            public void ShowCategoriesUISerialized(BasePlayer player, ref List<string> allElements)
            {
                allElements.Add(UI.Categories.Background.GetSerialized(player, Layer, LayerCategories,
                    LayerCategories));

                if (UI.Categories.ShowLine)
                    allElements.Add(UI.Categories.Line?.GetSerialized(player, LayerCategories,
                        LayerCategories + ".Line", LayerCategories + ".Line"));

                ShowCategoriesScrollUISerialized(player, ref allElements);
            }

            public void ShowCategoriesScrollUISerialized(BasePlayer player, ref List<string> allElements,
                bool needUpdate = false)
            {
                var totalWidth = CalculateTotalCategoriesWidth(player);

                if (UI.Categories.UseScrolling)
                    allElements.Add(UI.Categories.CategoriesScroll.GetScrollViewSerialized(Layer + ".Scroll.View",
                        Layer + ".Scroll.View", LayerCategories, totalWidth));
                else
                    allElements.Add(UiElement
                        .CreatePanel(
                            InterfacePosition.CreatePosition(UI.Categories.CategoriesScroll.GetRectTransform()),
                            IColor.CreateTransparent())
                        .GetSerialized(player, LayerCategories, Layer + ".Scroll.View",
                            Layer + ".Scroll.View"));

                ShowCategoriesLoopUISerialized(player, ref allElements);

                if (CanPlayerEdit(player) && TryGetOpenedMenu(player.userID, out var openedMenu))
                    (openedMenu.isEditMode ? UI.Categories.AdminHeaderSelectedButton : UI.Categories.AdminHeaderButton)
                        ?.ShowButtonUI(player, ref allElements, LayerCategories, LayerCategories + ".AdminHeaderButton",
                            command: $"{CmdMainConsole} edit_menu change_mode");
            }

            public void ShowCategoriesLoopUISerialized(BasePlayer player, ref List<string> allElements)
            {
                if (!TryGetOpenedMenu(player.userID, out var openedMenu))
                    return;

                var playerLang = Instance.lang.GetLanguage(player.UserIDString);

                var mainOffset = UI.Categories.CategoriesIndent;

                var availableCategories = GetAvailableCategories(player.userID);
                try
                {
                    for (var i = 0; i < availableCategories.Count; i++)
                    {
                        var menuCategory = availableCategories[i];

                        var isSelected = openedMenu.SelectedCategory == menuCategory.ID;

                        var targetWidth = UI.Categories.CategoryWidth;
                        if (UI.Categories.UseAdaptiveWidth &&
                            (menuCategory.Localizations.TryGetValue(playerLang, out var localizedText) ||
                             menuCategory.Localizations.TryGetValue("en", out localizedText)))
                            targetWidth = localizedText.Width;

                        var btnRect =
                            CalculateCategoriesPosition(mainOffset, targetWidth, UI.Categories.CategoryHeight);

                        var categoryButton = Layer + ".Scroll.View" + $".Category.{menuCategory.ID}";

                        allElements.Add(CuiJsonFactory.CreateButton(anchorMin: btnRect.AnchorMin,
                            anchorMax: btnRect.AnchorMax, offsetMin: btnRect.OffsetMin, offsetMax: btnRect.OffsetMax,
                            parent: Layer + ".Scroll.View", name: categoryButton, destroy: categoryButton,
                            command: menuCategory.ChatBtn && menuCategory.Commands.Length > 0
                                ? $"UI_ServerPanel_Send_Command UI_ServerPanel_Close|{menuCategory.Commands[0]}"
                                : $"{CmdMainConsole} menu category {menuCategory.ID}"));

                        var categoryBackground = isSelected
                            ? UI.Categories.CategoryTitle.SelectedBackground
                            : UI.Categories.CategoryTitle.Background;
                        if (categoryBackground != null)
                            allElements.Add(categoryBackground.GetSerialized(player, categoryButton,
                                categoryButton + ".Background"));

                        UI.Categories.CategoryTitle.Get(player, ref allElements, categoryButton,
                            text: Instance.Msg(player, menuCategory.GetTitle(player.UserIDString)),
                            isSelected: isSelected);

                        if (UI.Categories.ShowSelectedElement && isSelected)
                            allElements.Add(UI.Categories.SelectedElement.GetSerialized(player, categoryButton));

                        if (UI.Categories.CategoryTitle.UseIcon && !string.IsNullOrEmpty(menuCategory.Icon))
                            allElements.Add(UI.Categories.CategoryTitle.Icon.GetSerialized(player, categoryButton,
                                textFormatter: menuIcon => menuCategory.Icon));

                        if (UI.Categories.CategoryTitle.UseOutline)
                            (isSelected
                                    ? UI.Categories.CategoryTitle.SelectedOutline
                                    : UI.Categories.CategoryTitle.Outline)
                                .ShowOutlineUI(player, ref allElements, categoryButton);

                        CategoriesLoopPosition(ref mainOffset, i, availableCategories.Count, targetWidth);
                    }

                    if (CanPlayerEdit(player) && openedMenu.isEditMode)
                    {
                        var margin = 5f;

                        if (UI.Categories.CategoriesScroll.ScrollType == ScrollType.Horizontal)
                            mainOffset += margin;
                        else
                            mainOffset -= margin;

                        var btnRect = CalculateCategoriesPosition(mainOffset, UI.Categories.EditCategoryButton.Width,
                            UI.Categories.CategoryHeight);

                        var editCategoryButton = Layer + ".Scroll.View" + ".EditCategoryButton";

                        allElements.Add(CuiJsonFactory.CreatePanel(anchorMin: btnRect.AnchorMin,
                            anchorMax: btnRect.AnchorMax, offsetMin: btnRect.OffsetMin, offsetMax: btnRect.OffsetMax,
                            parent: Layer + ".Scroll.View", name: editCategoryButton, destroy: editCategoryButton));

                        UI.Categories.EditCategoryButton?.ShowButtonUI(player, ref allElements, editCategoryButton,
                            command: $"{CmdMainConsole} edit_category open");
                    }
                }
                finally
                {
                    Pool.FreeUnmanaged(ref availableCategories);
                }
            }

            private void CategoriesLoopPosition(ref float mainOffset, int index, int totalCount, float targetWidth = 0f)
            {
                if (UI.Categories.CategoriesScroll.ScrollType == ScrollType.Horizontal)
                    mainOffset += targetWidth > 0f ? targetWidth : UI.Categories.CategoryWidth;
                else
                    mainOffset -= UI.Categories.CategoryHeight;

                if (index != totalCount - 1)
                {
                    if (UI.Categories.CategoriesScroll.ScrollType == ScrollType.Horizontal)
                        mainOffset += UI.Categories.CategoriesMargin;
                    else
                        mainOffset -= UI.Categories.CategoriesMargin;
                }
            }

            private CuiRectTransformComponent CalculateCategoriesPosition(float offsetVal, float categoryWidth,
                float categoryHeight)
            {
                CuiRectTransformComponent cuiRect;
                if (UI.Categories.CategoriesScroll.ScrollType == ScrollType.Horizontal)
                    cuiRect = new CuiRectTransformComponent
                    {
                        AnchorMin = "0 1", AnchorMax = "0 1",
                        OffsetMin = $"{offsetVal} -{categoryHeight}",
                        OffsetMax = $"{offsetVal + categoryWidth} 0"
                    };
                else
                    cuiRect = new CuiRectTransformComponent
                    {
                        AnchorMin = "0 1", AnchorMax = "0 1",
                        OffsetMin = $"0 {offsetVal - categoryHeight}",
                        OffsetMax = $"{categoryWidth} {offsetVal}"
                    };

                return cuiRect;
            }

            private float CalculateTotalCategoriesWidth(BasePlayer player)
            {
                var playerLang = Instance.lang?.GetLanguage(player.UserIDString);

                var categories = GetAvailableCategories(player.userID);
                try
                {
                    if (categories == null || categories.Count == 0)
                        return 0f;

                    var totalWidth = 0f;

                    for (var i = 0; i < categories.Count; i++)
                    {
                        var category = categories[i];

                        var categoryWidth = UI.Categories.CategoryWidth;
                        if (UI.Categories.UseAdaptiveWidth &&
                            (category.Localizations.TryGetValue(playerLang, out var localizedText) ||
                             category.Localizations.TryGetValue("en", out localizedText)))
                            categoryWidth = localizedText.Width;

                        totalWidth += categoryWidth;

                        if (i != categories.Count - 1)
                            totalWidth += UI.Categories.CategoriesMargin;
                    }

                    if (CanPlayerEdit(player) && TryGetOpenedMenu(player.userID, out var openedMenu) &&
                        openedMenu.isEditMode) totalWidth += 5f + UI.Categories.EditCategoryButton.Width;

                    return Mathf.Max(totalWidth, UI.Categories.CategoriesScroll.ScrollSize);
                }
                finally
                {
                    Pool.FreeUnmanaged(ref categories);
                }
            }

            #endregion
        }

        #endregion Data.Template

        #region Data.Localization

        private static LocalizationData _localizationData;

        private void SaveLocalizationData()
        {
            SaveDataToFile(_localizationData, "Localization");
        }

        private void LoadLocalizationData()
        {
            LoadDataFromFile(ref _localizationData, "Localization");
        }

        private class LocalizationData
        {
            [JsonProperty(PropertyName = "Localization Settings")]
            public LocalizationSettings Localization = new();
        }

        #endregion Data.Localization

        #region Data.Header

        private static HeaderFieldsData _headerFieldsData;

        private void SaveHeaderFieldsData()
        {
            SaveDataToFile(_headerFieldsData, "HeaderFields");
        }

        private void LoadHeaderFieldsData()
        {
            LoadDataFromFile(ref _headerFieldsData, "HeaderFields");

            LoadHeaderFieldsDataCache();
        }

        private void LoadHeaderFieldsDataCache()
        {
            _headerFields
// ... [Code preview truncated due to length. Full source in attached file] ...

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