C#:
// #define TESTING
using System;
using System.Collections;
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 Newtonsoft.Json.Linq;
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 {
[Info("ServerPanel", "Mevent", "1.1.1")]
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<int, Coroutine> _categoriesActiveCoroutines = 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", EditingElementOutline = "UI.Server.Panel.Editor.EditingElement.Outline";
private Dictionary<(float AnchorMinX, float AnchorMinY, float AnchorMaxX, float AnchorMaxY), string> rectToImage = new() {
[(0, 1, 0, 1)]
= "https://gitlab.com/TheMevent/PluginsStorage/raw/main/Images/Anchors/top-left.png", [(0.5f, 1, 0.5f, 1)] = "https://gitlab.com/TheMevent/PluginsStorage/raw/main/Images/Anchors/top-center.png", [(1, 1, 1, 1)] = "https://gitlab.com/TheMevent/PluginsStorage/raw/main/Images/Anchors/top-right.png", [(0, 0.5f, 0, 0.5f)] = "https://gitlab.com/TheMevent/PluginsStorage/raw/main/Images/Anchors/middle-left.png", [(0.5f, 0.5f, 0.5f, 0.5f)] = "https://gitlab.com/TheMevent/PluginsStorage/raw/main/Images/Anchors/middle-center.png", [(1, 0.5f, 1, 0.5f)] = "https://gitlab.com/TheMevent/PluginsStorage/raw/main/Images/Anchors/middle-right.png", [(0, 0, 0, 0)] = "https://gitlab.com/TheMevent/PluginsStorage/raw/main/Images/Anchors/bottom-left.png", [(0.5f, 0, 0.5f, 0)] = "https://gitlab.com/TheMevent/PluginsStorage/raw/main/Images/Anchors/bottom-center.png", [(1, 0, 1, 0)] = "https://gitlab.com/TheMevent/PluginsStorage/raw/main/Images/Anchors/bottom-right.png", [(0, 1, 1, 1)] = "https://gitlab.com/TheMevent/PluginsStorage/raw/main/Images/Anchors/top-stretch.png", [(0, 0, 0, 1)] = "https://gitlab.com/TheMevent/PluginsStorage/raw/main/Images/Anchors/stretch-left.png", [(0.5f, 0, 0.5f, 1)] = "https://gitlab.com/TheMevent/PluginsStorage/raw/main/Images/Anchors/stretch-center.png", [(1, 0, 1, 1)] = "https://gitlab.com/TheMevent/PluginsStorage/raw/main/Images/Anchors/stretch-right.png", [(0, 0, 1, 1)] = "https://gitlab.com/TheMevent/PluginsStorage/raw/main/Images/Anchors/stretch-stretch.png",
}
;
#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 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
}
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();
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>(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, textFormatter : text => Instance.FormatUpdateField(player, text)));
// 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 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 : Instance.Msg(player, menuCategory.Title), 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 = menuCategory.ChatBtn && menuCategory.Commands.Length > 0 ? $"UI_ServerPanel_Send_Command UI_ServerPanel_Close|{menuCategory.Commands[0]}" : $"{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 Data.Players
private static PlayersData _playersData;
private void SavePlayersData() => SaveDataToFile(_playersData, $"{Name}/Players");
private void LoadPlayersData() {
LoadDataFromFile(ref _playersData, $"{Name}/Players");
}
private class PlayersData {
#region Fields
[JsonProperty(PropertyName = "Players", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, PlayerData> Players = new();
#endregion
}
public class PlayerData {
#region Fields
[JsonProperty(PropertyName = "Selected Editor Position")]
public EditorPosition SelectedEditorPosition = EditorPosition.Left;
#endregion
#region Public Methods
public static PlayerData GetOrCreate(string userID) {
if (!_playersData.Players.TryGetValue(userID, out var data)) _playersData.Players.TryAdd(userID, data = new PlayerData());
return data;
}
public CuiRectTransformComponent GetEditorPosition() {
switch (SelectedEditorPosition) {
case EditorPosition.Center : {
return new CuiRectTransformComponent() {
AnchorMin = "0.5 0", AnchorMax = "0.5 1", OffsetMin = "-130 0", OffsetMax = "130 0"
}
;
}
case EditorPosition.Right : {
return new CuiRectTransformComponent() {
AnchorMin = "1 0", AnchorMax = "1 1", OffsetMin = "-260 0", OffsetMax = "0 0"
}
;
}
default : {
return new CuiRectTransformComponent() {
AnchorMin = "0 0", AnchorMax = "0 1", OffsetMin = "0 0", OffsetMax = "260 0"
}
;
}
}
}
#endregion
}
public enum EditorPosition {
Left, Center, Right
}
#endregion Data.Players
#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
}
public void ProcessCategory(string pluginName = null) {
if (Pages is not {
Count : 1
}
) return;
var page = Pages[0];
if (page == null || page.Type != CategoryPage.PageType.Plugin || page.PluginName != pluginName) return;
var plugin = page.Plugin;
if (plugin == null) return;
if (plugin.IsLoaded) plugin.Call("OnReceiveCategoryInfo", ID);
else {
var coroutine = ServerMgr.Instance.StartCoroutine(Instance.CheckPluginLoaded(plugin, ID, 5));
Instance._categoriesActiveCoroutines[ID] = coroutine;
}
}
#endregion
#region Constructors
public static MenuCategory GetDefault() {
return new MenuCategory {
ID = Instance.GetUniqueCategoryID(), Enabled = true, Permission = string.Empty, Title = "New Category", ChatBtn = false, ShowPages = false, Commands = new[] {
"test_command_123"
}
, Icon = string.Empty, Pages = new List<CategoryPage> {
new() {
Title = string.Empty, Command = string.Empty, Type = CategoryPage.PageType.UI, PluginName = string.Empty, PluginHook = string.Empty, Elements = new List<UiElement> {
UiElement.CreatePanel(InterfacePosition.CreatePosition(0.5f, 0.5f, 0.5f, 0.5f, -50, -50, 50, 50), IColor.CreateWhite())
}
}
}
}
;
}
public JObject ToJson() {
var obj = new JObject() {
["ID"]
= ID, ["Enabled"] = Enabled, ["Permission"] = Permission, ["Title"] = Title, ["ChatBtn"] = ChatBtn, ["ShowPages"] = ShowPages, ["Commands"] = JArray.FromObject(Commands), ["Icon"] = Icon, ["Pages"] = JArray.FromObject(Pages.Select(p => p.ToJson()).ToArray()),
}
;
return obj;
}
public static MenuCategory FromJson(JObject obj) {
var menuCategory = GetDefault();
if (obj.TryGetValue("ID", out var id)) menuCategory.ID = Convert.ToInt32(id);
if (obj.TryGetValue("Enabled", out var enabled)) menuCategory.Enabled = Convert.ToBoolean(enabled);
if (obj.TryGetValue("Permission", out var permission)) menuCategory.Permission = Convert.ToString(permission);
if (obj.TryGetValue("Title", out var title)) menuCategory.Title = Convert.ToString(title);
if (obj.TryGetValue("ChatBtn", out var chatBtn)) menuCategory.ChatBtn = Convert.ToBoolean(chatBtn);
if (obj.TryGetValue("ShowPages", out var showPages)) menuCategory.ShowPages = Convert.ToBoolean(showPages);
if (obj.TryGetValue("Icon", out var icon)) menuCategory.Icon = Convert.ToString(icon);
if (obj.TryGetValue("Commands", out var arrCommands)) {
var list = new List<string>();
foreach (var targetCommand in (JArray) arrCommands) {
list.Add(targetCommand?.ToString());
}
if (list.Count > 0) menuCategory.Commands = list.ToArray();
}
if (obj.TryGetValue("Pages", out var arrPages)) {
var list = new List<CategoryPage>();
foreach (var jPage in (JArray) arrPages) {
var targetPage = CategoryPage.FromJson((JObject) jPage);
if (targetPage != null) list.Add(targetPage);
}
if (list.Count > 0) menuCategory.Pages = list;
}
return menuCategory;
}
#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 Ty
// ... [Code preview truncated due to length. Full source in attached file] ...