C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Enumerable = System.Linq.Enumerable;
// #define TESTING
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using Facepunch;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Oxide.Core;
using Oxide.Core.Configuration;
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.UI;
using Random = UnityEngine.Random;
#if CARBON
using Carbon.Base;
using Carbon.Modules;
#endif
namespace Oxide.Plugins {
/*ПЛАГИН БЫЛ ПОФИКШЕН С ПОМОЩЬЮ ПРОГРАММЫ СКАЧАНОЙ С https://discord.gg/dNGbxafuJn */
[Info("ServerPanel", "https://discord.gg/dNGbxafuJn", "1.0.3")]
public class ServerPanel : RustPlugin {
#region Fields
[PluginReference]
private Plugin ImageLibrary = null, NoEscape = null, Notify = null, UINotify = null, KillRecords = null, Statistics = null;
private static ServerPanel Instance;
#if CARBON
private ImageDatabaseModule imageDatabase;
#endif
private bool _enabledImageLibrary;
private Dictionary<int, int> _categoriesByID = new();
private Dictionary<string, int> _categoriesByCommand = new();
private Dictionary<string, Func<BasePlayer, string>> _headerUpdateFields = new();
private const string Perm_Edit = "serverpanel.edit", CmdMainConsole = "UI_ServerPanel", Layer = "UI.Server.Panel", LayerHeader = "UI.Server.Panel.Header", LayerContent = "UI.Server.Panel.Content", 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", EditingLayerModalAnchorSelector = "UI.Server.Panel.Editor.Modal.Anchor.Selector", EditingLayerModalColorSelector = "UI.Server.Panel.Editor.Modal.Color.Selector", EditingLayerModalTextEditor = "UI.Server.Panel.Editor.Modal.Text.Editor";
private Dictionary<(float AnchorMinX, float AnchorMinY, float AnchorMaxX, float AnchorMaxY), string> rectToImage = new() {
[(0, 1, 0, 1)]
= "https://github.com/TheMevent/PluginsStorage/blob/main/Images/Anchors/top-left.png?raw=true", [(0.5f, 1, 0.5f, 1)] = "https://github.com/TheMevent/PluginsStorage/blob/main/Images/Anchors/top-center.png?raw=true", [(1, 1, 1, 1)] = "https://github.com/TheMevent/PluginsStorage/blob/main/Images/Anchors/top-right.png?raw=true", [(0, 0.5f, 0, 0.5f)] = "https://github.com/TheMevent/PluginsStorage/blob/main/Images/Anchors/middle-left.png?raw=true", [(0.5f, 0.5f, 0.5f, 0.5f)] = "https://github.com/TheMevent/PluginsStorage/blob/main/Images/Anchors/middle-center.png?raw=true", [(1, 0.5f, 1, 0.5f)] = "https://github.com/TheMevent/PluginsStorage/blob/main/Images/Anchors/middle-right.png?raw=true", [(0, 0, 0, 0)] = "https://github.com/TheMevent/PluginsStorage/blob/main/Images/Anchors/bottom-left.png?raw=true", [(0.5f, 0, 0.5f, 0)] = "https://github.com/TheMevent/PluginsStorage/blob/main/Images/Anchors/bottom-center.png?raw=true", [(1, 0, 1, 0)] = "https://github.com/TheMevent/PluginsStorage/blob/main/Images/Anchors/bottom-right.png?raw=true", [(0, 1, 1, 1)] = "https://github.com/TheMevent/PluginsStorage/blob/main/Images/Anchors/top-stretch.png?raw=true", [(0, 0, 0, 1)] = "https://github.com/TheMevent/PluginsStorage/blob/main/Images/Anchors/stretch-left.png?raw=true", [(0.5f, 0, 0.5f, 1)] = "https://github.com/TheMevent/PluginsStorage/blob/main/Images/Anchors/stretch-center.png?raw=true", [(1, 0, 1, 1)] = "https://github.com/TheMevent/PluginsStorage/blob/main/Images/Anchors/stretch-right.png?raw=true", [(0, 0, 1, 1)] = "https://github.com/TheMevent/PluginsStorage/blob/main/Images/Anchors/stretch-stretch.png?raw=true",
}
;
#endregion
#region Config
private static Configuration _config;
private class Configuration {
#region Fields
[JsonProperty(PropertyName = "Work with Notify?")]
public bool UseNotify = true;
[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
}
;
#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 ItemCount(Enumerable.ToArray(Enumerable.Concat(player.inventory.containerMain?.itemList ?? Enumerable.Empty<Item>(), Enumerable.Concat(player.inventory.containerBelt?.itemList ?? Enumerable.Empty<Item>(), player.inventory.containerWear?.itemList ?? Enumerable.Empty<Item>()))), 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 = Enumerable.Concat(player.inventory.containerMain?.itemList ?? Enumerable.Empty<Item>(), Enumerable.Concat(player.inventory.containerBelt?.itemList ?? Enumerable.Empty<Item>(), player.inventory.containerWear?.itemList ?? Enumerable.Empty<Item>()));
var am = (int) amount;
if (ItemCount(Enumerable.ToArray(playerItems), ShortName, Skin) < am) return false;
Take(playerItems, ShortName, Skin, am);
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 ItemCount(Item[] items, string shortname, ulong skin) {
return Array.FindAll(items, item => item.info.shortname == shortname && !item.isBroken && (skin == 0 || item.skin == skin)).Sum(item => item.amount);
}
private static void Take(IEnumerable<Item> itemList, string shortname, ulong skinId, int amountToTake) {
if (amountToTake == 0) return;
var takenAmount = 0;
var itemsToTake = Pool.GetList<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.FreeList(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
}
protected override void LoadConfig() {
base.LoadConfig();
try {
_config = Config.ReadObject<Configuration>();
if (_config == null) throw new Exception();
SaveConfig();
}
catch {
PrintError("Your configuration file contains an error.Using default configuration values.");
LoadDefaultConfig();
}
}
protected override void SaveConfig() {
Config.WriteObject(_config);
}
protected override void LoadDefaultConfig() {
_config = new Configuration();
}
#endregion Config
#region Data
#region Data.General
public void SaveData() {
SaveCategoriesData();
SaveTemplateData();
SaveLocalizationData();
SaveHeaderFieldsData();
}
private void LoadData() {
LoadCategoriesData();
LoadTemplateData();
LoadLocalizationData();
LoadHeaderFieldsData();
}
private void LoadDataFromFile<T>(ref T data, string filePath) {
try {
data = Interface.Oxide.DataFileSystem.ReadObject<T>(filePath);
}
catch (Exception e) {
PrintError(e.ToString());
}
data ??= Activator.CreateInstance<T>();
}
private void SaveDataToFile<T>(T data, string filePath) {
Interface.Oxide.DataFileSystem.WriteObject(filePath, data);
}
#endregion Data.General
#region Data.Categories
private static CategoriesData _categoriesData;
private class CategoriesData {
[JsonProperty(PropertyName = "Categories", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<MenuCategory> Categories = new();
}
private void LoadCategoriesData() => LoadDataFromFile(ref _categoriesData, $"{Name}/Categories");
private void SaveCategoriesData() => SaveDataToFile(_categoriesData, $"{Name}/Categories");
#endregion Data.Categories
#region Data.Template
private static TemplateData _templateData;
private void SaveTemplateData() => SaveDataToFile(_templateData, $"{Name}/Template");
private void LoadTemplateData() => LoadDataFromFile(ref _templateData, $"{Name}/Template");
private class TemplateData {
#region Fields
[JsonProperty(PropertyName = "Use an expert mod?")]
public bool UseExpertMod = false;
[JsonProperty(PropertyName = "UI Settings")]
public UISettings UI = default;
#endregion
#region Public Methods
public void ShowEditPageButtonsUI(BasePlayer player, CuiElementContainer container, string parent, string cmdAddPage = "", string cmdRemovePage = "") {
#region Add Page
container.Add(new CuiButton {
Button = {
Color = "0 0.372549 0.7176471 1", Command = cmdAddPage
}
, Text = {
Text = "+ NEW PAGE", Font = "robotocondensed-regular.ttf", FontSize = 14, Align = TextAnchor.MiddleCenter, Color = "0.8862745 0.8588235 0.827451 1"
}
, RectTransform = {
AnchorMin = "0 0", AnchorMax = "0 0", OffsetMin = "22 10", OffsetMax = "148 40"
}
}
, parent);
#endregion
#region Remove Page
container.Add(new CuiButton {
Button = {
Color = "0.8117647 0.2627451 0.1764706 1", Command = cmdRemovePage
}
, Text = {
Text = "DELETE PAGE", Font = "robotocondensed-regular.ttf", FontSize = 14, Align = TextAnchor.MiddleCenter, Color = "0.8862745 0.8588235 0.827451 1"
}
, RectTransform = {
AnchorMin = "0 0", AnchorMax = "0 0", OffsetMin = "158 10", OffsetMax = "284 40"
}
}
, parent);
#endregion
}
public void ShowContentUI(BasePlayer player, CuiElementContainer container, string cmdPage = "", Action<string> callback = null) {
if (!TryGetOpenedMenu(player.userID, out var openedMenu)) return;
var menuCategory = Instance.GetCategoryById(openedMenu.SelectedCategory);
var page = openedMenu.PageIndex;
var maxPages = menuCategory.Pages.Count;
UI.Content.Background.Get(ref container, player, Layer, LayerContent, destroy : LayerContent);
var categoryPage = menuCategory?.Pages[page];
if (categoryPage != null) {
switch (categoryPage.Type) {
case CategoryPage.PageType.Plugin : {
var elements = categoryPage.Plugin?.Call<CuiElementContainer>(categoryPage.PluginHook, player);
if (elements != null) {
container.AddRange(elements);
}
break;
}
case CategoryPage.PageType.UI : {
categoryPage.Elements?.ForEach(element => element?.Get(ref container, player, LayerContent, element.Name));
if (menuCategory.ShowPages) UI.Content.Pagination.ShowPagination(player, container, LayerContent, page, maxPages, LayerContent + ".Navigation", cmdPage);
if (CanPlayerEdit(player)) {
UI.Content.EditButton.ShowEditButtonUI(player, container, LayerContent, cmdEdit : $"{CmdMainConsole} edit_page start {menuCategory.ID} {page}");
ShowEditPageButtonsUI(player, container, LayerContent, cmdAddPage : $"{CmdMainConsole} edit_page add {menuCategory.ID} {page}", cmdRemovePage : $"{CmdMainConsole} edit_page remove {menuCategory.ID} {page}");
}
break;
}
}
}
callback?.Invoke(LayerContent);
}
public void ShowCloseButtonUI(BasePlayer player, CuiElementContainer container, string parent, string closeLayer = "", string command = "") {
UI.CloseButton.ShowButtonUI(player, container, parent, parent + ".CloseButton", closeLayer : closeLayer, command : command);
}
public void ShowBackgroundUI(BasePlayer player, CuiElementContainer container, string cmdOnClick = "") {
UI.Background.Background.Get(ref container, player, UI.Background.ParentLayer, Layer, destroy : Layer);
if (UI.Background.CloseAfterClick) {
container.Add(new CuiElement() {
Parent = Layer, Components = {
new CuiButtonComponent() {
Color = "0 0 0 0", Close = Layer, Command = cmdOnClick
}
, new CuiRectTransformComponent()
}
}
);
}
}
public void ShowHeaderUI(BasePlayer player, CuiElementContainer container) {
UI.Header.Background.Get(ref container, player, Layer, LayerHeader, destroy : LayerHeader);
foreach (var headerField in _headerFieldsData.Fields) headerField.Get(ref container, player, LayerHeader, headerField.Name, destroy : headerField.Name, textFormatter : text => Instance.FormatUpdateField(player, text));
}
public void UpdateGlobalHeaderUI(BasePlayer player, CuiElementContainer container) {
foreach (var headerField in _headerFieldsData.Fields) headerField.Get(ref container, player, LayerHeader, headerField.Name, textFormatter : text => Instance.FormatUpdateField(player, text), needUpdate : true);
}
public void UpdateHeaderUI(BasePlayer player, CuiElementContainer container) {
foreach (var headerField in _headerFieldsData.elementsToUpdate) headerField.Get(ref container, player, LayerHeader, headerField.Name, destroy : headerField.Name, textFormatter : text => Instance.FormatUpdateField(player, text));
}
public void ShowUpdateHeaderUI(BasePlayer player) {
UpdateUI(player, container => {
UpdateHeaderUI(player, container);
}
);
}
public void ShowCategories(BasePlayer player, CuiElementContainer container) {
UI.Categories.Background.Get(ref container, player, Layer, LayerCategories, destroy : LayerCategories);
container.Add(new CuiElement() {
Name = Layer + ".Scroll.Panel", DestroyUi = Layer + ".Scroll.Panel", Parent = LayerCategories, Components = {
new CuiImageComponent() {
Color = "0 0 0 0"
}
, UI.Categories.CategoriesScroll.GetRectTransform()
}
}
);
ShowCategoriesScrollUI(player, container);
}
public void ShowCategoriesScrollUI(BasePlayer player, CuiElementContainer container, bool needUpdate = false) {
var targetCategoriesCount = _categoriesData.Categories.Count;
if (CanPlayerEdit(player)) targetCategoriesCount += 2;
var totalWidth = targetCategoriesCount * UI.Categories.CategoryWidth + (targetCategoriesCount - 1) * UI.Categories.CategoriesMargin;
if (UI.Categories.UseScrolling) {
container.Add(new CuiElement {
Name = Layer + ".Scroll.View", DestroyUi = Layer + ".Scroll.View", Parent = Layer + ".Scroll.Panel", Update = needUpdate, Components = {
UI.Categories.CategoriesScroll.GetScrollView(CalculateContentRectTransform(totalWidth)),
}
}
);
}
else {
container.Add(new CuiElement {
Name = Layer + ".Scroll.View", DestroyUi = Layer + ".Scroll.View", Parent = Layer + ".Scroll.Panel", Update = needUpdate, Components = {
new CuiImageComponent() {
Color = "0 0 0 0"
}
, new CuiRectTransformComponent()
}
}
);
}
ShowCategoriesLoopUI(player, container);
}
public void ShowCategoriesLoopUI(BasePlayer player, CuiElementContainer container) {
if (!TryGetOpenedMenu(player.userID, out var openedMenu)) return;
var selectedCategory = openedMenu.SelectedCategory;
var mainOffset = UI.Categories.CategoriesIndent;
foreach (var menuCategory in _categoriesData.Categories) {
var menuCategoryTitle = menuCategory.Title;
var isSelected = selectedCategory == menuCategory.ID;
var categoryButton = Layer + ".Scroll.View" + $".Category.{menuCategory.ID}";
container.Add(new CuiElement() {
Name = categoryButton, DestroyUi = categoryButton, Parent = Layer + ".Scroll.View", Components = {
GetCategoriesButtonComponent(isSelected, menuCategory), CalculateCategoriesPosition(mainOffset, UI.Categories.CategoryWidth, UI.Categories.CategoryHeight)
}
}
);
UI.Categories.CategoryTitle.Get(player, container, categoryButton, text : menuCategoryTitle, isSelected : isSelected);
if (UI.Categories.ShowSelectedElement && isSelected) UI.Categories.SelectedElement.Get(ref container, player, categoryButton);
if (UI.Categories.CategoryTitle.UseIcon && !string.IsNullOrEmpty(menuCategory.Icon)) UI.Categories.CategoryTitle.Icon.Get(ref container, player, categoryButton, textFormatter : menuIcon => menuCategory.Icon);
if (UI.Categories.CategoryTitle.UseOutline) (isSelected ? UI.Categories.CategoryTitle.SelectedOutline : UI.Categories.CategoryTitle.Outline).ShowOutlineUI(player, container, categoryButton);
if (openedMenu.isEditMode) UI.Categories.CategoryEditPanel.GetCategoriesEditPanel(player, ref container, categoryButton, categoryButton + ".Panel.Settings", $"{CmdMainConsole} edit_menu category up {menuCategory.ID}", $"{CmdMainConsole} edit_menu category down {menuCategory.ID}", $"{CmdMainConsole} edit_category start {menuCategory.ID}");
CategoriesLoopPosition(ref mainOffset);
}
if (CanPlayerEdit(player)) {
container.Add(new CuiElement() {
Name = Layer + ".Scroll.View.Category.Create", DestroyUi = Layer + ".Scroll.View.Category.Create", Parent = Layer + ".Scroll.View", Components = {
new CuiImageComponent() {
Color = "0 0 0 0"
}
, CalculateCategoriesPosition(mainOffset, UI.Categories.CategoryWidth, UI.Categories.CategoryHeight)
}
}
);
UI.Categories.AdminCategory.AdminCheckbox.GetCheckbox(player, container, Layer + ".Scroll.View.Category.Create", Layer + ".Scroll.View.Category.Create.CheckBox.AdminMode", $"{CmdMainConsole} edit_menu change_mode", openedMenu.isEditMode);
UI.Categories.AdminCategory.ButtonAddCategory.Get(ref container, player, Layer + ".Scroll.View.Category.Create", cmdFormatter : text => $"{CmdMainConsole} edit_category create");
CategoriesLoopPosition(ref mainOffset);
container.Add(new CuiElement() {
Name = Layer + ".Scroll.View.Category.Admin.Settings", DestroyUi = Layer + ".Scroll.View.Category.Admin.Settings", Parent = Layer + ".Scroll.View", Components = {
new CuiButtonComponent() {
Command = $"{CmdMainConsole} edit_header_fields start", Color = "0 0 0 0"
}
, CalculateCategoriesPosition(mainOffset, UI.Categories.CategoryWidth, UI.Categories.CategoryHeight)
}
}
);
UI.Categories.AdminCategory.ButtonAdminSettings.Get(ref container, player, Layer + ".Scroll.View.Category.Admin.Settings", cmdFormatter : text => $"{CmdMainConsole} edit_header_fields start");
}
}
private void CategoriesLoopPosition(ref float mainOffset) {
if (UI.Categories.CategoriesScroll.ScrollType == ScrollType.Horizontal) mainOffset += UI.Categories.CategoriesMargin + UI.Categories.CategoryWidth;
else mainOffset = mainOffset - UI.Categories.CategoriesMargin - UI.Categories.CategoryHeight;
}
private CuiButtonComponent GetCategoriesButtonComponent(bool isSelected, MenuCategory menuCategory) {
var btnComponent = new CuiButtonComponent {
Color = isSelected ? UI.Categories.CategoryTitle.SelectedBackgroundColor.Get() : UI.Categories.CategoryTitle.BackgroundColor.Get(), Command = $"{CmdMainConsole} menu category {menuCategory.ID}",
}
;
if (!string.IsNullOrEmpty(UI.Categories.CategoryTitle.BackgroundSprite)) btnComponent.Sprite = UI.Categories.CategoryTitle.BackgroundSprite;
if (!string.IsNullOrEmpty(UI.Categories.CategoryTitle.BackgroundMaterial)) btnComponent.Material = UI.Categories.CategoryTitle.BackgroundMaterial;
return btnComponent;
}
private CuiRectTransform CalculateContentRectTransform(float totalWidth) {
CuiRectTransform contentRect;
if (UI.Categories.CategoriesScroll.ScrollType == ScrollType.Horizontal) {
contentRect = new CuiRectTransform() {
AnchorMin = "0 0", AnchorMax = "0 1", OffsetMin = "0 0", OffsetMax = $"{totalWidth} 0"
}
;
}
else {
contentRect = new CuiRectTransform() {
AnchorMin = "0 1", AnchorMax = "1 1", OffsetMin = $"0 -{totalWidth}", OffsetMax = "0 0"
}
;
}
return contentRect;
}
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;
}
#endregion
}
#endregion Data.Template
#region Data.Localization
private static LocalizationData _localizationData;
private void SaveLocalizationData() => SaveDataToFile(_localizationData, $"{Name}/Localization");
private void LoadLocalizationData() => LoadDataFromFile(ref _localizationData, $"{Name}/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, $"{Name}/HeaderFields");
private void LoadHeaderFieldsData() {
LoadDataFromFile(ref _headerFieldsData, $"{Name}/HeaderFields");
LoadHeaderFieldsDataCache();
}
private void LoadHeaderFieldsDataCache() {
_headerFieldsData?.Load();
}
private class HeaderFieldsData {
#region Fields
[JsonProperty(PropertyName = "Fields", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<HeaderFieldUI> Fields = new();
#endregion
#region Cache
[JsonIgnore]
public bool needToUpdate;
[JsonIgnore]
public List<HeaderFieldUI> elementsToUpdate;
public void Load() {
elementsToUpdate?.Clear();
elementsToUpdate = Fields.FindAll(x => x.NeedToUpdate);
if (elementsToUpdate.Count > 0) needToUpdate = true;
}
#endregion
}
public class HeaderFieldUI : UiElement {
#region Fields
[JsonProperty(PropertyName = "Need to update?")]
public bool NeedToUpdate;
#endregion
#region Constructors
public HeaderFieldUI() {
}
public HeaderFieldUI(UiElement other) : base(other) {
NeedToUpdate = false;
}
public HeaderFieldUI(UiElement other, bool needToUpdate) : base(other) {
NeedToUpdate = needToUpdate;
}
#endregion
}
#endregion Data.Localization
#region Classes
#region Categories
public class MenuCategory {
#region Fields
[JsonProperty(PropertyName = "ID")]
public int ID;
[JsonProperty(PropertyName = "Enabled")]
public bool Enabled;
[JsonProperty(PropertyName = "Permission")]
public string Permission = string.Empty;
[JsonProperty(PropertyName = "Title")]
public string Title = string.Empty;
[JsonProperty(PropertyName = "Chat Button")]
public bool ChatBtn;
[JsonProperty(PropertyName = "Show Pages?")]
public bool ShowPages;
[JsonProperty(PropertyName = "Commands", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public string[] Commands;
[JsonProperty(PropertyName = "Icon")]
public string Icon = string.Empty;
[JsonProperty(PropertyName = "Pages", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<CategoryPage> Pages = new();
#endregion
#region Public Methods
public void MoveUp() {
var index = _categoriesData.Categories.IndexOf(this);
if (index > 0 && index < _categoriesData.Categories.Count) {
(_categoriesData.Categories[index], _categoriesData.Categories[index - 1]) = (_categoriesData.Categories[index - 1], _categoriesData.Categories[index]);
// Swap
}
}
public void MoveDown() {
var index = _categoriesData.Categories.IndexOf(this);
if (index >= 0 && index < _categoriesData.Categories.Count - 1) (_categoriesData.Categories[index], _categoriesData.Categories[index + 1]) = (_categoriesData.Categories[index + 1], _categoriesData.Categories[index]);
// Swap
}
#endregion
}
public class MenuCategoryBuilder {
private bool _enabled;
private string _permission = string.Empty;
private string _title = string.Empty;
private bool _chatButton;
private bool _showPages = true;
private List<string> _commands = new();
private List<CategoryPage> _pages;
public MenuCategory Build() {
var menuCategory = new MenuCategory {
ID = Instance.GetUniqueCategoryID(), Enabled = _enabled, Permission = _permission, Title = _title, ChatBtn = _chatButton, ShowPages = _showPages, Commands = _commands?.ToArray(), Pages = _pages
}
;
return menuCategory;
}
public MenuCategoryBuilder WithEnabled(bool enabled) {
_enabled = enabled;
return this;
}
public MenuCategoryBuilder WithTitle(string title) {
_title = title;
return this;
}
public MenuCategoryBuilder WithPermission(string permission) {
_permission = permission;
return this;
}
public MenuCategoryBuilder WithChatButton(bool chatButton) {
_chatButton = chatButton;
return this;
}
public MenuCategoryBuilder WithShowPages(bool showPages) {
_showPages = showPages;
return this;
}
public MenuCategoryBuilder WithCommand(string command) {
_commands.Add(command);
return this;
}
public MenuCategoryBuilder WithPages(List<CategoryPage> pages) {
_pages = pages;
return this;
}
}
public class CategoryPage {
#region Fields
[JsonProperty(PropertyName = "Title")]
public string Title;
[JsonProperty(PropertyName = "Command")]
public string Command;
[JsonProperty(PropertyName = "Type (Plugin/UI)")]
[JsonConverter(typeof(StringEnumConverter))]
public PageType Type;
[JsonProperty(PropertyName = "Plugin Name")]
public string PluginName;
[JsonProperty(PropertyName = "Plugin Hook")]
public string PluginHook;
[JsonProperty(PropertyName = "UI Elements", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<UiElement> Elements = new();
#endregion
#region Cache
[JsonIgnore]
public Plugin Plugin => Instance?.plugins.Find(PluginName);
#endregion
#region Classes
public enum PageType {
Plugin, UI
}
#endregion
}
#endregion Categories
#region UI
public class UISettings {
#region Fields
[JsonProperty(PropertyName = "ID (DONT CHANGE)")]
public string ID;
[JsonProperty(PropertyName = "Background")]
public BackgroundUI Background = new();
[JsonProperty(PropertyName = "Content")]
public ContentUI Content = new();
[JsonProperty(PropertyName = "Header")]
public HeaderUI Header = new();
[JsonProperty(PropertyName = "Categories")]
public CategoriesUI Categories = new();
[JsonProperty(PropertyName = "Close Button")]
public CloseButtonUI CloseButton = new();
#endregion
#region Classes
public class OutlineUI {
#region Fields
[JsonProperty(PropertyName = "Color")]
public IColor Color = IColor.CreateTransparent();
[JsonProperty(PropertyName = "Size")]
public float Size = 0f;
[JsonProperty(PropertyName = "Sprite")]
public string Sprite = string.Empty;
[JsonProperty(PropertyName = "Material")]
public string Material = string.Empty;
#endregion
#region Public Methods
public void ShowOutlineUI(BasePlayer player, CuiElementContainer container, string outlineParent, string name = "") {
if (string.IsNullOrEmpty(name)) name = CuiHelper.GetGuid();
var imageComponent = new CuiImageComponent {
Color = Color.Get()
}
;
if (!string.IsNullOrWhiteSpace(Sprite)) imageComponent.Sprite = Sprite;
if (!string.IsNullOrWhiteSpace(Material)) imageComponent.Material = Material;
container.Add(new CuiElement() {
Parent = outlineParent, Name = name + ".1", DestroyUi = name + ".1", Components = {
imageComponent, new CuiRectTransformComponent {
AnchorMin = "0 1", AnchorMax = "1 1", OffsetMin = $"0 -{Size}", OffsetMax = "0 0"
}
}
}
);
container.Add(new CuiElement() {
Parent = outlineParent, Name = name + ".2", DestroyUi = name + ".2", Components = {
imageComponent, new CuiRectTransformComponent {
AnchorMin = "0 0", AnchorMax = "1 0", OffsetMin = "0 0", OffsetMax = $"0 {Size}"
}
}
}
);
container.Add(new CuiElement() {
Parent = outlineParent, Name = name + ".3", DestroyUi = name + ".3", Components = {
imageComponent, new CuiRectTransformComponent {
AnchorMin = "0 0", AnchorMax = "0 1", OffsetMin = $"0 {Size}", OffsetMax = $"{Size} -{Size}"
}
}
}
);
container.Add(new CuiElement() {
Parent = outlineParent, Name = name + ".4", DestroyUi = name + ".4", Components = {
imageComponent, new CuiRectTransformComponent {
AnchorMin = "1 0", AnchorMax = "1 1", OffsetMin = $"-{Size} {Size}", OffsetMax = $"0 -{Size}"
}
}
}
);
}
#endregion
}
public class CloseButtonUI {
#region Fields
[JsonProperty(PropertyName = "Background")]
public UiElement Background = new();
[JsonProperty(PropertyName = "Title")]
public UiElement Title = new();
#endregion
#region Public Methods
public void ShowButtonUI(BasePlayer player, CuiElementContainer container, string parent, string name = "", string closeLayer = "", string command = "") {
if (string.IsNullOrEmpty(name)) name = CuiHelper.GetGuid();
Background.Get(ref container, player, parent, name, name);
Title.Get(ref container, player, name, name + ".Title");
container.Add(new CuiElement() {
Parent = name, Components = {
new CuiButtonComponent() {
Color = "0 0 0 0", Command = command, Close = closeLayer
}
}
}
);
}
#endregion
}
public class EditButtonUI {
#region Fields
[JsonProperty(PropertyName = "Background")]
public UiElement Background = new();
[JsonProperty(PropertyName = "Title")]
public UiElement Title = new();
[JsonProperty(PropertyName = "Description Background")]
public UiElement DescriptionBackground = new();
[JsonProperty(PropertyName = "Description Title")]
public UiElement DescriptionTitle = new();
#endregion
#region Public Methods
public void ShowEditButtonUI(BasePlayer player, CuiElementContainer container, string parent, string name = "", string closeLayer = "", string cmdEdit = "") {
if (string.IsNullOrEmpty(name)) name = CuiHelper.GetGuid();
Background.Get(ref container, player, parent, name);
Title.Get(ref container, player, name);
DescriptionBackground.Get(ref container, player, name,
// ... [Code preview truncated due to length. Full source in attached file] ...