C#:
using Newtonsoft.Json;
using Oxide.Core.Plugins;
using Oxide.Core;
using Oxide.Game.Rust.Cui;
using System.Collections.Generic;
using System.Linq;
using System;
using UnityEngine;
namespace Oxide.Plugins {
[Info("RadialMenu", "MTriper", "1.2.2")]
[Description("A customizable quick access panel with all popular and frequently used server commands")]
class RadialMenu : RustPlugin {
#region Fields
[PluginReference]
private Plugin ImageLibrary, NTeleportation, Teleportation, Friends, Clans;
QuickMenuConfig config;
const bool isRus = false;
HashSet<string> activeUsers = new HashSet<string>();
#endregion
#region Config
class QuickMenuConfig {
[JsonProperty(isRus ? "Команда для открытия радиального меню. Если пусто, сервер будет отслеживать нажатие СКМ [повышенная нагрузка]" : "The command to open the radial menu. If empty, the server will monitor the MMB press [increased load]")]
public string command = "";
[JsonProperty(isRus ? "Подсказка о том, как закрыть панель [если используется команда выше]" : "Hint on how to close the panel [if using the command above]")]
public string closeMessage = isRus ? "Введите команду еще раз или нажмите в свободном месте, чтобы закрыть панель" : "Enter the command again or click in an empty space to close the panel";
[JsonProperty(isRus ? "Сообщение игроку в чат если у него нет привилегии" : "Message to player in chat if he does not have a privilege")]
public string needPerm = isRus ? "У вас нет разрешения на использование этой команды!" : "You do not have permission to use this command!";
[JsonProperty(isRus ? "Изображение с 1-им кольцом меню" : "Image with 1 menu ring")]
public string imgLVL1 = "https://i.imgur.com/gMRz5Et.png";
[JsonProperty(isRus ? "Изображение с 2-мя кольцами меню" : "Image with 2 menu rings")]
public string imgLVL2 = "https://i.imgur.com/OHQTGPM.png";
[JsonProperty(isRus ? "Изображение с 3-мя кольцами меню" : "Image with 3 menu rings")]
public string imgLVL3 = "https://i.imgur.com/w87aldf.png";
[JsonProperty(isRus ? "Размер радиального меню" : "Radial menu size")]
public int menuSize = 250;
[JsonProperty(isRus ? "Скорость появления радиального меню" : "Speed of displaying the radial menu")]
public float menuFadeIn = 0.5f;
[JsonProperty(isRus ? "Размер иконки" : "Icon size")]
public int sectionSize = 15;
[JsonProperty(isRus ? "Размер текста" : "Text size")]
public int textSize = 8;
[JsonProperty(isRus ? "Скорость появления иконок" : "Speed of displaying icons")]
public float sectionFadeIn = 0.5f;
[JsonProperty(isRus ? "Расстояние от центра до иконок 1-го уровня" : "Distance from center to 1st level icons")]
public float distanceLVL1 = 0.194f;
[JsonProperty(isRus ? "Расстояние от центра до иконок 2-го уровня" : "Distance from center to 2nd level icons")]
public float distanceLVL2 = 0.32f;
[JsonProperty(isRus ? "Расстояние от центра до иконок 3-го уровня" : "Distance from center to 3rd level icons")]
public float distanceLVL3 = 0.446f;
[JsonProperty(isRus ? "Разделы" : "Sections", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<MenuSectionClass> menuSections = new List<MenuSectionClass> {
new MenuSectionClass {
name = "Teleport", perm = "_homes", img = "https://i.imgur.com/5jmbECE.png", separate = 15, subsections = {
new MenuSectionClass {
name = "Home 1", perm = "home_1_all", img = "https://i.imgur.com/Q4wlQVX.png", separate = -15, subsections = {
new MenuSectionClass {
name = "Teleport", perm = "teleport", img = "https://i.imgur.com/2S9oQB8.png", command = "home {0}", colorInactive = "#57de54"
}
, new MenuSectionClass {
name = "Remove", perm = "remove", img = "https://i.imgur.com/PECEX3I.png", command = "home remove {0}", colorInactive = "#f55757"
}
}
}
, new MenuSectionClass {
name = "Home 2", perm = "home_2_all", img = "https://i.imgur.com/Q4wlQVX.png", separate = -15, subsections = {
new MenuSectionClass {
name = "Teleport", perm = "teleport", img = "https://i.imgur.com/2S9oQB8.png", command = "home {0}", colorInactive = "0.34 0.87 0.33 1"
}
, new MenuSectionClass {
name = "Remove", perm = "remove", img = "https://i.imgur.com/PECEX3I.png", command = "home remove {0}", colorInactive = "0.96 0.34 0.34 1"
}
}
}
, new MenuSectionClass {
name = "Home 3", perm = "home_3_all", img = "https://i.imgur.com/Q4wlQVX.png", separate = -15, subsections = {
new MenuSectionClass {
name = "Teleport", perm = "teleport", img = "https://i.imgur.com/2S9oQB8.png", command = "home {0}", colorInactive = "0.34 0.87 0.33 1"
}
, new MenuSectionClass {
name = "Remove", perm = "remove", img = "https://i.imgur.com/PECEX3I.png", command = "home remove {0}", colorInactive = "0.96 0.34 0.34 1"
}
}
}
, new MenuSectionClass {
name = "Add", perm = "home_add", img = "https://i.imgur.com/h1R6x2F.png", command = "home add {0}"
}
}
}
, new MenuSectionClass {
name = "Friends", perm = "_teammates", img = "https://i.imgur.com/pIw7xwN.png", separate = 15, subsections = {
new MenuSectionClass {
name = "Friend 1", perm = "friend_1_all", img = "https://i.imgur.com/O5qyPlz.png", separate = 20, subsections = {
new MenuSectionClass {
name = "Teleport", perm = "teleport", img = "https://i.imgur.com/2S9oQB8.png", command = "tpr {0}"
}
, new MenuSectionClass {
name = "Trade", perm = "trade", img = "https://i.imgur.com/KXMfoeI.png", command = "trade {0}"
}
}
}
, new MenuSectionClass {
name = "Friend 2", perm = "friend_2_all", img = "https://i.imgur.com/O5qyPlz.png", separate = 20, subsections = {
new MenuSectionClass {
name = "Teleport", perm = "teleport", img = "https://i.imgur.com/2S9oQB8.png", command = "tpr {0}"
}
, new MenuSectionClass {
name = "Trade", perm = "trade", img = "https://i.imgur.com/KXMfoeI.png", command = "trade {0}"
}
}
}
, new MenuSectionClass {
name = "Friend 3", perm = "friend_3_all", img = "https://i.imgur.com/O5qyPlz.png", separate = 20, subsections = {
new MenuSectionClass {
name = "Teleport", perm = "teleport", img = "https://i.imgur.com/2S9oQB8.png", command = "tpr {0}"
}
, new MenuSectionClass {
name = "Trade", perm = "trade", img = "https://i.imgur.com/KXMfoeI.png", command = "trade {0}"
}
}
}
,
}
}
, new MenuSectionClass {
name = "Remove", perm = "remove", img = "https://i.imgur.com/M7K8DV8.png", command = "remove", neededperm = "removertool.normal, removertool.structure, removertool.external", showall = true
}
, new MenuSectionClass {
name = "Recycler", perm = "recycler", img = "https://i.imgur.com/WTm5bKJ.png", command = "rec"
}
, new MenuSectionClass {
name = "Skins", perm = "skins", img = "https://i.imgur.com/qzQwBKI.png", command = "skins", neededperm = "skins.use"
}
, new MenuSectionClass {
name = "Craft", perm = "craft", img = "https://i.imgur.com/m7kyUIK.png", command = "craft", neededperm = "craft.use", showall = true
}
, new MenuSectionClass {
name = "Turrets", perm = "turrets", img = "https://i.imgur.com/MVtdwjA.png", separate = -15, subsections = {
new MenuSectionClass {
name = "Turret on/off", perm = "one", img = "https://i.imgur.com/dpXp5mS.png", command = "turret"
}
, new MenuSectionClass {
name = "Turrets on", perm = "all_on", img = "https://i.imgur.com/74QGojp.png", command = "turret.tc on", colorInactive = "0.34 0.87 0.33 1"
}
, new MenuSectionClass {
name = "Turrets off", perm = "all_off", img = "https://i.imgur.com/74QGojp.png", command = "turret.tc off", colorInactive = "0.96 0.34 0.34 1"
}
, new MenuSectionClass {
name = "SAMs on", perm = "sams_on", img = "https://i.imgur.com/Zb4X3wW.png", command = "sam.tc on", colorInactive = "0.34 0.87 0.33 1"
}
, new MenuSectionClass {
name = "SAMs off", perm = "sams_off", img = "https://i.imgur.com/Zb4X3wW.png", command = "sam.tc off", colorInactive = "0.96 0.34 0.34 1"
}
}
}
, new MenuSectionClass {
name = "Notify", perm = "notify_all", img = "https://i.imgur.com/GQnCUNy.png", separate = -15, subsections = {
new MenuSectionClass {
name = "Teleport", perm = "tp", img = "https://i.imgur.com/2S9oQB8.png", separate = -15, subsections = {
new MenuSectionClass {
name = "Accept", perm = "accept", img = "https://i.imgur.com/CsUosUr.png", command = "tpa", colorInactive = "0.34 0.87 0.33 1"
}
, new MenuSectionClass {
name = "Cancel", perm = "cancel", img = "https://i.imgur.com/ETgjR6K.png", command = "tpc", colorInactive = "0.96 0.34 0.34 1"
}
}
}
, new MenuSectionClass {
name = "Trade", perm = "trade", img = "https://i.imgur.com/KXMfoeI.png", separate = -15, subsections = {
new MenuSectionClass {
name = "Accept", perm = "accept", img = "https://i.imgur.com/CsUosUr.png", command = "trade accept", colorInactive = "0.34 0.87 0.33 1"
}
, new MenuSectionClass {
name = "Cancel", perm = "cancel", img = "https://i.imgur.com/ETgjR6K.png", command = "trade cancel", colorInactive = "0.96 0.34 0.34 1"
}
}
}
}
}
}
;
}
class MenuSectionClass {
[JsonProperty(isRus ? "Название раздела" : "Section name")]
public string name = "";
[JsonProperty(isRus ? "Включить раздел?" : "Enable this section?")]
public bool isEnable = true;
[JsonProperty(isRus ? "Permission раздела [обязательно]" : "Section permission [required]")]
public string perm = "";
[JsonProperty(isRus ? "Иконка раздела" : "Section icon")]
public string img = "";
[JsonProperty(isRus ? "Залить иконку цветом ниже?" : "Fill icon with color below?")]
public bool isFill = true;
[JsonProperty(isRus ? "Цвет, когда раздел неактивен [HEX или Unity RGBA]" : "Inactive section color [HEX or Unity RGBA]")]
public string colorInactive = "#fade54";
[JsonProperty(isRus ? "Цвет, когда раздел активен [HEX или Unity RGBA]" : "Active section color [HEX or Unity RGBA]")]
public string colorActive = "#e3e3e3";
[JsonProperty(isRus ? "Команда от имени игрока [если пусто, то используются подразделы ниже]" : "Command executed on behalf of the player [if empty, the subsections below are used]")]
public string command = "";
[JsonProperty(isRus ? "Тип выполняемой команды [true - чат, false - консоль]" : "Command type [true - chat, false - console]")]
public bool isChat = true;
[JsonProperty(isRus ? "Permissions для команды выше [через запятую. необязательно]. Проверяет есть ли у игрока такие permissions." : "Permissions for above command [comma separated. optional]. Checks if the player has such a permissions.")]
public string neededperm = "";
[JsonProperty(isRus ? "Показывать этот раздел даже тем, у кого нет привилегий?" : "Show this section even to those who don't have privileges?")]
public bool showall = false;
[JsonProperty(isRus ? "Расположение подразделов [n - число]: 0 - авто; n - с начала; -n - от активного элемента." : "Subsections layout [n - number]: 0 - auto; n - from the beginning; -n - from an active element")]
public int separate = 0;
[JsonProperty(isRus ? "Подразделы" : "Subsections", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<MenuSectionClass> subsections = new List<MenuSectionClass>();
}
protected override void LoadDefaultConfig() {
config = new QuickMenuConfig();
SaveConfig();
}
void ReadConfig() {
config = Config.ReadObject<QuickMenuConfig>();
SaveConfig();
}
protected override void SaveConfig() => Config.WriteObject(config, true);
bool CheckConfig() {
if (config.command != "") {
Unsubscribe("OnPlayerInput");
AddCovalenceCommand(config.command, nameof(Command));
}
if (string.IsNullOrEmpty(config.imgLVL1) || string.IsNullOrEmpty(config.imgLVL2) || string.IsNullOrEmpty(config.imgLVL3)) {
PrintError("One of the radial menu images is not set!");
return false;
}
for (int i = config.menuSections.Count - 1; i > -1; i--) {
if (!config.menuSections[i].isEnable) {
config.menuSections.RemoveAt(i);
continue;
}
if (config.menuSections[i].perm == "") {
PrintError($"One of the sections ({config.menuSections[i].name}) has no permission set.");
return false;
}
if (config.menuSections[i].perm == "_homes") {
if ((NTeleportation == null || !NTeleportation.IsLoaded) & (Teleportation == null || !Teleportation.IsLoaded)) {
PrintError("Supported teleport plugin not found!");
//config.menuSections.RemoveAt(i);
//continue;
}
}
if (config.menuSections[i].perm == "_friends") {
if (Friends == null || !Friends.IsLoaded || Friends.Author != "Wulf") {
PrintError("Supported plugin 'Friends' not found!");
//config.menuSections.RemoveAt(i);
//continue;
}
}
if (config.menuSections[i].perm == "_clans") {
if (Clans == null || !Clans.IsLoaded || Clans.Author != "k1lly0u") {
PrintError("Supported plugin 'Clans' not found!");
//config.menuSections.RemoveAt(i);
//continue;
}
}
if (config.menuSections.Where(x => x.perm == config.menuSections[i].perm).Count() > 1) {
PrintError($"Several sections have the same permission - '{config.menuSections[i].perm}'.");
return false;
}
config.menuSections[i].colorInactive = ToUnityRGBA(config.menuSections[i].colorInactive);
config.menuSections[i].colorActive = ToUnityRGBA(config.menuSections[i].colorActive);
permission.RegisterPermission($"{Title.ToLower()}.{config.menuSections[i].perm}", this);
ImageLibrary.Call("AddImage", config.menuSections[i].img, $"{Title}.{config.menuSections[i].perm}");
if (config.menuSections[i].command == "" && config.menuSections[i].subsections.IsNullOrEmpty()) {
PrintWarning($"The '{config.menuSections[i].name}' section is missing a command and subsections.");
}
for (int j = config.menuSections[i].subsections.Count - 1; j > -1; j--) {
if (!config.menuSections[i].subsections[j].isEnable) {
config.menuSections[i].subsections.RemoveAt(j);
continue;
}
if (config.menuSections[i].subsections[j].perm == "") {
PrintError($"One of the subsections ({config.menuSections[i].subsections[j].name}) has no permission set.");
return false;
}
if (config.menuSections[i].subsections.Where(x => x.perm == config.menuSections[i].subsections[j].perm).Count() > 1) {
PrintError($"Several subsections have the same permission - '{config.menuSections[i].subsections[j].perm}'.");
return false;
}
config.menuSections[i].subsections[j].colorInactive = ToUnityRGBA(config.menuSections[i].subsections[j].colorInactive);
config.menuSections[i].subsections[j].colorActive = ToUnityRGBA(config.menuSections[i].subsections[j].colorActive);
if (!config.menuSections[i].perm.Contains("_all")) permission.RegisterPermission($"{Title.ToLower()}.{config.menuSections[i].perm}.{config.menuSections[i].subsections[j].perm}", this);
ImageLibrary.Call("AddImage", config.menuSections[i].subsections[j].img, $"{Title}.{config.menuSections[i].perm}.{config.menuSections[i].subsections[j].perm}");
if (config.menuSections[i].subsections[j].command == "" && config.menuSections[i].subsections[j].subsections.IsNullOrEmpty()) {
PrintWarning($"The '{config.menuSections[i].subsections[j].name}' section is missing a command and subsections.");
}
for (int k = config.menuSections[i].subsections[j].subsections.Count - 1; k > -1; k--) {
if (!config.menuSections[i].subsections[j].subsections[k].isEnable) {
config.menuSections[i].subsections[j].subsections.RemoveAt(k);
continue;
}
if (!config.menuSections[i].subsections[j].subsections[k].subsections.IsNullOrEmpty()) {
PrintError($"Only 2 levels of attachments are allowed - {config.menuSections[i].perm} => {config.menuSections[i].subsections[j].perm} => {config.menuSections[i].subsections[j].subsections[k].perm} ---> {config.menuSections[i].subsections[j].subsections[k].subsections[0].perm}");
return false;
}
if (config.menuSections[i].subsections[j].subsections[k].perm == "") {
PrintError($"One of the subsections ({config.menuSections[i].subsections[j].subsections[k].name}) has no permission set.");
return false;
}
if (config.menuSections[i].subsections[j].subsections.Where(x => x.perm == config.menuSections[i].subsections[j].subsections[k].perm).Count() > 1) {
PrintError($"Several subsections have the same permission - '{config.menuSections[i].subsections[j].subsections[k].perm}'.");
return false;
}
config.menuSections[i].subsections[j].subsections[k].colorInactive = ToUnityRGBA(config.menuSections[i].subsections[j].subsections[k].colorInactive);
config.menuSections[i].subsections[j].subsections[k].colorActive = ToUnityRGBA(config.menuSections[i].subsections[j].subsections[k].colorActive);
if (!config.menuSections[i].perm.Contains("_all") && !config.menuSections[i].subsections[j].perm.Contains("_all")) permission.RegisterPermission($"{Title.ToLower()}.{config.menuSections[i].perm}.{config.menuSections[i].subsections[j].perm}.{config.menuSections[i].subsections[j].subsections[k].perm}", this);
ImageLibrary.Call("AddImage", config.menuSections[i].subsections[j].subsections[k].img, $"{Title}.{config.menuSections[i].perm}.{config.menuSections[i].subsections[j].perm}.{config.menuSections[i].subsections[j].subsections[k].perm}");
if (config.menuSections[i].subsections[j].subsections[k].command == "") {
PrintWarning($"The '{config.menuSections[i].subsections[j].subsections[k].name}' section is missing a command.");
}
}
}
}
return true;
}
#endregion
#region Hooks
private void OnServerInitialized() {
if (!ImageLibrary) {
PrintError("Отсутствует плагин: 'ImageLibrary'");
Interface.Oxide.UnloadPlugin(Title);
return;
}
ReadConfig();
if (!CheckConfig()) {
NextTick(() => {
Interface.Oxide.UnloadPlugin(Title);
}
);
return;
}
ImageLibrary.Call("AddImage", config.imgLVL1, Title + ".LVL1");
ImageLibrary.Call("AddImage", config.imgLVL2, Title + ".LVL2");
ImageLibrary.Call("AddImage", config.imgLVL3, Title + ".LVL3");
foreach (var item in config.menuSections) ImageLibrary.Call("AddImage", item.img, $"{Title}.{item.perm}");
}
void Unload() {
foreach (BasePlayer player in BasePlayer.activePlayerList) CuiHelper.DestroyUi(player, Title + ".MainPanel");
}
void OnPlayerDisconnected(BasePlayer player) => activeUsers.Remove(player.UserIDString);
void OnPlayerInput(BasePlayer player, InputState input) {
if (player == null || !input.WasJustReleased(BUTTON.FIRE_THIRD) || !player.CanInteract() || player.inventory.loot.IsLooting()) return;
if (activeUsers.Contains(player.UserIDString)) {
CuiHelper.DestroyUi(player, Title + ".MainPanel");
activeUsers.Remove(player.UserIDString);
return;
}
else activeUsers.Add(player.UserIDString);
OpenPanel(player);
}
object OnInventoryNetworkUpdate(PlayerInventory inventory, ItemContainer container, ProtoBuf.UpdateItemContainer updateItemContainer, PlayerInventory.Type type, bool broadcast) {
if (container?.playerOwner != null && type != PlayerInventory.Type.Wear) {
try {
CuiHelper.DestroyUi(container.playerOwner, Title + ".MainPanel");
activeUsers.Remove(container.playerOwner.UserIDString);
}
catch {
}
}
return null;
}
#endregion
#region Commands
[ConsoleCommand("distributionCommand")]
void DistributionCommand(ConsoleSystem.Arg args) {
BasePlayer player = args?.Player();
if (player == null) return;
if (args.Args[0] == "close") {
CuiHelper.DestroyUi(player, Title + ".MainPanel");
activeUsers.Remove(player.UserIDString);
return;
}
string[] sections = args.Args[0].Split('.');
int index = Array.FindIndex(sections, x => x.Contains("_all"));
MenuSectionClass neededSection = config.menuSections.Find(x => x.perm == sections[0]);
switch (index) {
case 0 : if (!permission.UserHasPermission(player.UserIDString, $"{Title}.{sections[0]}")) {
SendReply(player, config.needPerm);
OpenPanel(player, sections);
return;
}
break;
case 1 : neededSection = neededSection.subsections.Find(x => x.perm == sections[1]);
if (!permission.UserHasPermission(player.UserIDString, $"{Title}.{sections[0]}.{sections[1]}")) {
SendReply(player, config.needPerm);
OpenPanel(player, sections);
return;
}
break;
default : if (!permission.UserHasPermission(player.UserIDString, $"{Title}.{args.Args[0]}")) {
SendReply(player, config.needPerm);
OpenPanel(player, sections);
return;
}
break;
}
if (!UserHasNeededPerm(player.UserIDString, neededSection.neededperm)) {
SendReply(player, config.needPerm);
OpenPanel(player, sections);
return;
}
if (args.Args.ElementAtOrDefault(1) == "chat") // Пример: _friends.friend_1.teleport chat tpr *name*
{
player.Command($"chat.say \"/{string.Join(" ", args.Args.Skip(2))}\"");
activeUsers.Remove(player.UserIDString);
CuiHelper.DestroyUi(player, Title + ".MainPanel");
return;
}
else if (args.Args.ElementAtOrDefault(1) == "console") {
player.Command(args.Args[2], args.Args.Skip(3));
activeUsers.Remove(player.UserIDString);
CuiHelper.DestroyUi(player, Title + ".MainPanel");
return;
}
if (!neededSection.subsections.IsNullOrEmpty()) {
OpenPanel(player, sections);
//SendReply(player, neededSection.message);
}
}
void Command(Core.Libraries.Covalence.IPlayer iplayer) {
BasePlayer player = iplayer.Object as BasePlayer;
if (player != null && player.CanInteract()) {
if (activeUsers.Contains(player.UserIDString)) {
CuiHelper.DestroyUi(player, Title + ".MainPanel");
activeUsers.Remove(player.UserIDString);
return;
}
else activeUsers.Add(player.UserIDString);
OpenPanel(player);
}
}
#endregion
#region Functions
HashSet<MenuSectionClass> GetValidSections(BasePlayer player, string[] lvls) {
HashSet<MenuSectionClass> sections = new HashSet<MenuSectionClass>();
foreach (var lvl1 in config.menuSections) {
MenuSectionClass section1 = new MenuSectionClass();
if (!lvl1.showall) {
if (permission.UserHasPermission(player.UserIDString, $"{Title}.{lvl1.perm}")) {
if (UserHasNeededPerm(player.UserIDString, lvl1.neededperm)) {
section1.name = lvl1.name;
section1.perm = lvl1.perm;
section1.command = lvl1.command;
section1.isChat = lvl1.isChat;
section1.isFill = lvl1.isFill;
section1.separate = lvl1.separate;
section1.colorActive = lvl1.colorActive;
section1.colorInactive = lvl1.colorInactive;
}
else continue;
}
else continue;
}
else {
section1.name = lvl1.name;
section1.perm = lvl1.perm;
section1.command = lvl1.command;
section1.isChat = lvl1.isChat;
section1.isFill = lvl1.isFill;
section1.separate = lvl1.separate;
section1.colorActive = lvl1.colorActive;
section1.colorInactive = lvl1.colorInactive;
}
if (lvls.IsNullOrEmpty() || lvl1.perm != lvls[0]) {
sections.Add(section1);
continue;
}
foreach (var lvl2 in lvl1.subsections) {
MenuSectionClass section2 = new MenuSectionClass();
if (!lvl2.showall) {
if (lvl1.perm.Contains("_all") || permission.UserHasPermission(player.UserIDString, $"{Title}.{lvl1.perm}.{lvl2.perm}")) {
if (UserHasNeededPerm(player.UserIDString, lvl2.neededperm)) {
section2.name = lvl2.name;
section2.perm = lvl2.perm;
section2.command = lvl2.command;
section2.isChat = lvl2.isChat;
section2.isFill = lvl2.isFill;
section2.separate = lvl2.separate;
section2.colorActive = lvl2.colorActive;
section2.colorInactive = lvl2.colorInactive;
}
else {
sections.Add(section1);
continue;
}
}
else {
sections.Add(section1);
continue;
}
}
else {
section2.name = lvl2.name;
section2.perm = lvl2.perm;
section2.command = lvl2.command;
section2.isChat = lvl2.isChat;
section2.isFill = lvl2.isFill;
section2.separate = lvl2.separate;
section2.colorActive = lvl2.colorActive;
section2.colorInactive = lvl2.colorInactive;
}
if (lvls.IsNullOrEmpty() || lvls.Count() != 2 || lvl2.perm != lvls[1]) {
section1.subsections.Add(section2);
continue;
}
foreach (var lvl3 in lvl2.subsections) {
MenuSectionClass section3 = new MenuSectionClass();
if (!lvl3.showall) {
if (lvl1.perm.Contains("_all") || lvl2.perm.Contains("_all") || permission.UserHasPermission(player.UserIDString, $"{Title}.{lvl1.perm}.{lvl2.perm}.{lvl3.perm}")) {
if (UserHasNeededPerm(player.UserIDString, lvl3.neededperm)) {
section3.name = lvl3.name;
section3.perm = lvl3.perm;
section3.command = lvl3.command;
section3.isChat = lvl3.isChat;
section3.isFill = lvl3.isFill;
section3.colorActive = lvl3.colorActive;
section3.colorInactive = lvl3.colorInactive;
}
else {
section1.subsections.Add(section3);
continue;
}
}
else {
section1.subsections.Add(section2);
continue;
}
}
else {
section3.name = lvl3.name;
section3.perm = lvl3.perm;
section3.command = lvl3.command;
section3.isChat = lvl3.isChat;
section3.isFill = lvl3.isFill;
section3.colorActive = lvl3.colorActive;
section3.colorInactive = lvl3.colorInactive;
}
section2.subsections.Add(section3);
}
if (!section1.subsections.Contains(section2)) section1.subsections.Add(section2);
}
sections.Add(section1);
}
return sections;
}
void AdditionalFunctionality(BasePlayer player, ref HashSet<MenuSectionClass> validSections, string[] lvls) {
if (lvls.IsNullOrEmpty()) return;
switch (lvls[0]) {
case "_homes" : case "_homes_all" : MenuSectionClass homes = validSections.First(x => x.perm.StartsWith("_homes"));
Dictionary<string, Vector3> teleportHomes = new Dictionary<string, Vector3>();
if (NTeleportation != null && NTeleportation.IsLoaded) teleportHomes = NTeleportation?.Call("API_GetHomes", player) as Dictionary<string, Vector3>;
else if (Teleportation != null && Teleportation.IsLoaded && Teleportation.Author == "OxideBro") teleportHomes = Teleportation?.Call("GetHomes", player.userID) as Dictionary<string, Vector3>;
else {
PrintWarning("Supported teleport plugin not found!");
homes.subsections.Clear();
return;
}
HashSet<string> delHomes = new HashSet<string>();
int totalHomesCount = homes.subsections.Where(x => x.perm.Contains("home_")).Count();
int passedHomes = 0;
for (int i = 0; i < homes.subsections.Count; i++) {
if (!homes.subsections[i].perm.Contains("home_")) continue;
if (homes.subsections[i].perm == "home_add") {
string grid = PhoneController.PositionToGridCoord(player.transform.position);
if (!teleportHomes.IsNullOrEmpty() && teleportHomes.ContainsKey(grid)) {
int c = teleportHomes.Keys.Where(x => x.Contains(grid)).Count();
grid += $"_{c + 1}";
}
homes.subsections[i].command = string.Format(homes.subsections[i].command, grid);
continue;
}
if (!teleportHomes.IsNullOrEmpty() && passedHomes < totalHomesCount && passedHomes < teleportHomes.Count) {
homes.subsections[i].name = teleportHomes.ElementAt(passedHomes).Key;
foreach (var item in homes.subsections[i].subsections) {
if (item.command.Contains("{0}")) item.command = string.Format(item.command, homes.subsections[i].name);
}
passedHomes++;
}
else delHomes.Add(homes.subsections[i].perm);
}
foreach (var id in delHomes) homes.subsections.RemoveAll(x => x.perm == id);
break;
case "_clans" : case "_clans_all" : case "_friends" : case "_friends_all" : case "_teammates" : case "_teammates_all" : MenuSectionClass friends = new MenuSectionClass();
List<ulong> friendsList = new List<ulong>();
if (lvls[0].StartsWith("_friends")) {
friends = validSections.First(x => x.perm.StartsWith("_friends"));
if (Friends == null || !Friends.IsLoaded || Friends.Author != "Wulf") {
PrintWarning("Supported plugin 'Friends' not found!");
friends.subsections.Clear();
return;
}
friendsList = Friends?.Call<ulong[]>("GetFriends", player.userID).ToList();
}
else if (lvls[0].StartsWith("_teammates")) {
friends = validSections.First(x => x.perm.StartsWith("_teammates"));
friendsList = player.Team?.members.ToList();
}
else if (lvls[0].StartsWith("_clans")) {
friends = validSections.First(x => x.perm.StartsWith("_clans"));
if (Clans == null || !Clans.IsLoaded || Clans.Author != "k1lly0u") {
PrintWarning("Supported plugin 'Clans' not found!");
friends.subsections.Clear();
return;
}
friendsList = Clans?.Call<List<string>>("GetClanMembers", player.UserIDString).Select(ulong.Parse).ToList();
}
HashSet<string> delFriends = new HashSet<string>();
int totalFriendsCount = friends.subsections.Where(x => x.perm.Contains("friend_")).Count();
int passedFriends = 0;
friendsList?.Remove(player.userID);
for (int i = 0; i < friends.subsections.Count; i++) {
if (!friends.subsections[i].perm.Contains("friend_")) continue;
if (!friendsList.IsNullOrEmpty() && passedFriends < totalFriendsCount && passedFriends < friendsList.Count) {
friends.subsections[i].name = BasePlayer.FindAwakeOrSleeping(friendsList.ElementAt(passedFriends).ToString()).displayName;
foreach (var item in friends.subsections[i].subsections) {
if (item.command.Contains("{0}")) item.command = string.Format(item.command, friends.subsections[i].name);
}
passedFriends++;
}
else delFriends.Add(friends.subsections[i].perm);
}
foreach (var id in delFriends) friends.subsections.RemoveAll(x => x.perm == id);
break;
}
}
bool UserHasNeededPerm(string playerId, string str) {
string[] perms = str.Split(new char[] {
',', ' '
}
, StringSplitOptions.RemoveEmptyEntries);
if (!perms.IsNullOrEmpty()) {
foreach (var item in perms) {
if (!permission.UserHasPermission(playerId, item)) return false;
}
}
return true;
}
string ToUnityRGBA(string hexColor) {
Color color;
if(ColorUtility.TryParseHtmlString(hexColor, out color)) return string.Format("{0:F2} {1:F2} {2:F2} {3:F2}", color.r, color.g, color.b, color.a);
else return hexColor;
}
#endregion
#region Interface
void OpenPanel(BasePlayer player, params string[] lvls) {
HashSet<MenuSectionClass> validSections = GetValidSections(player, lvls);
if (validSections.IsNullOrEmpty()) return;
AdditionalFunctionality(player, ref validSections, lvls);
var container = new CuiElementContainer();
string png, color1, color2;
float menuFadeIn = 0f, section1FadeIn = 0f, section2FadeIn = 0f, section3FadeIn = 0f;
Dictionary<string, double> section1Radians = new Dictionary<string, double>();
if (lvls.IsNullOrEmpty()) {
png = (string) ImageLibrary.Call("GetImage", Title + ".LVL1");
menuFadeIn = config.menuFadeIn;
section1FadeIn = config.sectionFadeIn;
}
else if (lvls.Count() == 1) {
if (validSections.First(x => x.perm == lvls[0]).subsections.IsNullOrEmpty()) png = (string) ImageLibrary.Call("GetImage", Title + ".LVL1");
else {
png = (string) ImageLibrary.Call("GetImage", Title + ".LVL2");
section2FadeIn = config.sectionFadeIn;
}
}
else {
png = (string) ImageLibrary.Call("GetImage", Title + ".LVL3");
section3FadeIn = config.sectionFadeIn;
}
container.Add(new CuiPanel {
RectTransform = {
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = $"-{config.menuSize} -{config.menuSize}", OffsetMax = $"{config.menuSize} {config.menuSize}"
}
, Image = {
Color = "0 0 0 0"
}
, CursorEnabled = true
}
, "Hud", Title + ".MainPanel");
if (config.command != "") {
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "-1 -1", AnchorMax = "2 2"
}
, Button = {
Color = "0 0 0 0", Command = "distributionCommand close"
}
, Text = {
Text = ""
}
}
, Title + ".MainPanel");
container.Add(new CuiLabel {
RectTransform = {
AnchorMin = "0.5 0.46", AnchorMax = "0.5 0.46", OffsetMin = $"-{config.menuSize} -{config.menuSize}", OffsetMax = $"{config.menuSize} {config.menuSize}"
}
, Text = {
Text = config.closeMessage, Color = "1 1 1 0.8", FontSize = 12, Align = TextAnchor.LowerCenter, Font = "robotocondensed-regular.ttf"
}
}
, Title + ".MainPanel");
}
container.Add(new CuiElement {
Name = Title + ".RadialMenu", Parent = Title + ".MainPanel", Components = {
new CuiRectTransformComponent {
AnchorMin = "0 0", AnchorMax = "1 1"
}
, new CuiRawImageComponent {
Png = png, FadeIn = menuFadeIn
}
}
}
);
for (int i = 0; i < validSections.Count; i++) {
double rad = 1.57f - i * 6.28f / validSections.Count;
double x = 0.5f + config.distanceLVL1 * Math.Cos(rad);
double y = 0.5f + config.distanceLVL1 * Math.Sin(rad);
section1Radians.Add(validSections.ElementAt(i).perm, rad);
if (!lvls.IsNullOrEmpty() && lvls[0] == validSections.ElementAt(i).perm && !validSections.ElementAt(i).subsections.IsNullOrEmpty()) color1 = validSections.ElementAt(i).colorActive;
else color1 = validSections.ElementAt(i).colorInactive;
container.Add(new CuiButton {
RectTransform = {
AnchorMin = $"{x} {y}", AnchorMax = $"{x} {y}", OffsetMin = $"-{config.sectionSize} -{config.sectionSize}", OffsetMax = $"{config.sectionSize} {config.sectionSize}"
}
, Button = {
Color = "1 1 1 0", Command = validSections.ElementAt(i).command == "" ? $"distributionCommand {validSections.ElementAt(i).perm}" : string.Format("distributionCommand {0} {1} {2}", validSections.ElementAt(i).perm, validSections.ElementAt(i).isChat ? "chat" : "console", validSections.ElementAt(i).command), FadeIn = section1FadeIn
}
}
, Title + ".MainPanel", Title + ".LVL1." + i);
if (!validSections.ElementAt(i).isFill) {
container.Add(new CuiElement {
Parent = Title + ".LVL1." + i, Components = {
new CuiRectTransformComponent {
AnchorMin = "0.1 0.2", AnchorMax = "0.9 1"
}
, new CuiRawImageComponent {
Png = (string) ImageLibrary.Call("GetImage", $"{Title}.{validSections.ElementAt(i).perm}"), FadeIn = section1FadeIn
}
}
}
);
}
else {
container.Add(new CuiPanel {
RectTransform = {
AnchorMin = "0.1 0.2", AnchorMax = "0.9 1"
}
, Image = {
Png = (string) ImageLibrary.Call("GetImage", $"{Title}.{validSections.ElementAt(i).perm}"), Color = color1, FadeIn = section1FadeIn
}
}
, Title + ".LVL1." + i);
}
container.Add(new CuiLabel {
RectTransform = {
AnchorMin = "-0.1 -0.15", AnchorMax = "1.1 0.15"
}
, Text = {
Text = validSections.ElementAt(i).name, Color = color1, FontSize = config.textSize, FadeIn = section1FadeIn, Align = TextAnchor.MiddleCenter, Font = "robotocondensed-regular.ttf"
}
}
, Title + ".LVL1." + i);
}
MenuSectionClass validSections2 = new MenuSectionClass();
Dictionary<string,
// ... [Code preview truncated due to length. Full source in attached file] ...