C#:
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using System.Collections.Generic;
using UnityEngine;
using System.Collections;
using Oxide.Core;
using System.Linq;
using Newtonsoft.Json;
namespace Oxide.Plugins
{
[Info("MBCommands", "Barry_Allenn", "1.0.0")]
[Description("MBCommands")]
public class MBCommands : RustPlugin
{
[PluginReference] private Plugin ImageLibrary, MBMainMenu;
private ImageUI imageUI = new ImageUI();
private ConfigData configData;
private class ConfigData
{
[JsonProperty("Команды")]
public List<CommandEntry> Commands = new();
}
public class CommandEntry
{
public string Command;
public string LangKey;
}
protected override void LoadConfig()
{
base.LoadConfig();
configData = Config.ReadObject<ConfigData>();
SaveConfig();
}
protected override void SaveConfig()
{
Config.WriteObject(configData, true);
}
protected override void LoadDefaultConfig()
{
configData = new ConfigData
{
Commands = new List<CommandEntry>
{
new CommandEntry { Command = "/vip", LangKey = "Command_1" },
new CommandEntry { Command = "/craft", LangKey = "Command_2" },
new CommandEntry { Command = "/commands", LangKey = "Command_3" },
new CommandEntry { Command = "/wipe", LangKey = "Command_4" },
new CommandEntry { Command = "/info", LangKey = "Command_5" }
}
};
SaveConfig();
}
[ChatCommand("commands")]
private void CmdCommands(BasePlayer player, string command, string[] args)
{
ShowCommandsUI(player);
}
void Init()
{
LoadConfig();
// imageUI = new ImageUI();
// imageUI.DownloadImages();
}
private void OnServerInitialized()
{
imageUI = new ImageUI();
imageUI.DownloadImages();
}
void Unload()
{
foreach (var player in BasePlayer.activePlayerList)
{
CuiHelper.DestroyUi(player, "MBCommands_UI");
}
imageUI?.UnloadImages();
}
[HookMethod("OpenCommandsForPlayer")]
private void ShowCommandsUI(BasePlayer player)
{
CuiHelper.DestroyUi(player, "MBCommands_UI");
var container = new CuiElementContainer();
string root = container.Add(new CuiPanel
{
Image = { Color = "0 0 0 0" },
RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" },
CursorEnabled = true
}, "Overlay", "MBCommands_UI");
string backgroundPanel = container.Add(new CuiPanel
{
Image = { Color = "0 0 0 0.7", Material = "assets/content/ui/uibackgroundblur.mat" },
RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" },
CursorEnabled = true
}, root);
string imageId = imageUI?.GetImage("MBWelcome_Three_Os");
if (!string.IsNullOrEmpty(imageId))
{
container.Add(new CuiElement
{
Name = CuiHelper.GetGuid(),
Parent = root,
Components =
{
new CuiRawImageComponent { Png = imageId },
new CuiRectTransformComponent { AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = "-558 -314", OffsetMax = "558 315" }
}
});
}
// Добавляем кнопку закрытия UI
container.Add(new CuiButton
{
Button = { Color = "0 0 0 0", Close = "MBCommands_UI" },
RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" },
Text = { Text = "", FontSize = 0 }
}, root);
string centerPanel = container.Add(new CuiPanel
{
Image = { Color = "0.1 0.1 0.1 0" },
RectTransform = {
AnchorMin = "0.5 0.5",
AnchorMax = "0.5 0.5",
OffsetMin = "-438 -265", // ширина 800, высота 600
OffsetMax = "440 265"
},
CursorEnabled = true
}, root);
container.Add(new CuiLabel
{
RectTransform = { AnchorMin = "0.341 0.86", AnchorMax = "0.75 0.955" },
Text = { Text = Msg("MB_Commands_Player", player.userID.ToString()), Color = "1 1 1 0.9", Align = TextAnchor.MiddleLeft, FontSize = 30 }
}, centerPanel);
container.Add(new CuiLabel
{
RectTransform = { AnchorMin = "0.341 0.8", AnchorMax = "0.8 0.868" },
Text = { Text = Msg("MB_Commands_Player_2", player.userID.ToString()), Color = "1 1 1 0.9", Align = TextAnchor.MiddleLeft, FontSize = 21, Font = "permanentmarker.ttf" }
}, centerPanel);
container.Add(new CuiLabel
{
Text = { Text = Msg("MB_Close_Commands", player.userID.ToString()), FontSize = 13, Color = "1 1 1 0.4", Align = TextAnchor.MiddleCenter },
RectTransform = { AnchorMin = "0.2 -0.06", AnchorMax = "0.8 -0.02" }
}, centerPanel);
container.Add(new CuiButton
{
Button = {
Command = "mbcommands.back", // кастомная команда
Color = "0.2 0.5 0.8 0"
},
RectTransform = { AnchorMin = "0.865 0.04", AnchorMax = "0.947 0.12" },
Text = {
Text = Msg("MB_Back", player.UserIDString),
FontSize = 15,
Align = TextAnchor.MiddleCenter,
Color = "1 1 1 1"
}
}, centerPanel);
// Прокрутка
float blockHeight = 75f;
float blockMargin = 9f;
float verticalShift = 0f;
int totalCommands = configData.Commands.Count;
int rowCount = Mathf.CeilToInt(totalCommands / 2f);
float totalHeight = rowCount * (blockHeight + blockMargin);
float minVisibleHeight = 300f;
float scrollContentHeight = Mathf.Max(totalHeight, minVisibleHeight);
container.Add(new CuiElement
{
Name = "MBScrollableCommandArea",
Parent = centerPanel,
Components =
{
new CuiScrollViewComponent
{
Vertical = true,
Horizontal = false,
Inertia = true,
Elasticity = 0.2f,
DecelerationRate = 0.2f,
ScrollSensitivity = 30f,
ContentTransform = new CuiRectTransform
{
AnchorMin = "0 1",
AnchorMax = "0.975 1",
OffsetMin = $"0 -{scrollContentHeight}",
OffsetMax = "0 0"
},
VerticalScrollbar = new CuiScrollbar
{
Size = 5f,
AutoHide = false,
HandleColor = "0.3 0.6 0.9 0.7",
TrackColor = "0.1 0.1 0.1 0.6"
}
},
new CuiRectTransformComponent
{
AnchorMin = "0.338 0.19",
AnchorMax = "0.9577 0.75"
},
new CuiNeedsCursorComponent()
}
});
container.Add(new CuiPanel
{
Image = { Color = "0 0 0 0" },
RectTransform = {
AnchorMin = "0 1",
AnchorMax = "1 1",
OffsetMin = $"0 -{scrollContentHeight}",
OffsetMax = "0 0"
}
}, "MBScrollableCommandArea", "MBCommandContent");
int columns = 2;
float columnGap = 0.02f; // 2% зазор між колонками
float columnWidth = (1f - columnGap) / columns;
for (int i = 0; i < totalCommands; i++)
{
int row = i / columns;
int col = i % columns;
float topOffset = -(row * (blockHeight + blockMargin)) - verticalShift;
float bottomOffset = topOffset - blockHeight;
float left = col == 0 ? 0f : columnWidth + columnGap;
float right = left + columnWidth;
var entry = configData.Commands[i];
string cmd = entry.Command;
string desc = Msg(entry.LangKey, player.UserIDString);
string backgroundImg = imageUI.GetImage("CommandBG");
string containerName = $"MBCommandContainer_{i}";
// Контейнер кожної команди
container.Add(new CuiPanel
{
Image = { Color = "0 0 0 0" },
RectTransform = {
AnchorMin = $"{left} 1",
AnchorMax = $"{right} 1",
OffsetMin = $"0 {bottomOffset}",
OffsetMax = $"0 {topOffset}"
}
}, "MBCommandContent", containerName);
// Фонове зображення
if (!string.IsNullOrEmpty(backgroundImg))
{
container.Add(new CuiElement
{
Name = $"MBCommandBG_{i}",
Parent = containerName,
Components =
{
new CuiRawImageComponent
{
Png = backgroundImg,
Sprite = "assets/content/textures/generic/fulltransparent.tga",
Color = "1 1 1 1"
},
new CuiRectTransformComponent
{
AnchorMin = "0 0",
AnchorMax = "1 1"
}
}
});
}
// Назва команди
container.Add(new CuiLabel
{
Text = {
Text = cmd,
FontSize = 14,
Align = TextAnchor.MiddleLeft,
Color = "0.00 1.00 0.00 0.7"
},
RectTransform = {
AnchorMin = "0.05 0.6", AnchorMax = "0.95 0.95"
}
}, containerName);
// Опис команди
container.Add(new CuiLabel
{
Text = {
Text = desc,
FontSize = 9,
Align = TextAnchor.UpperLeft,
Color = "1 1 1 0.5"
},
RectTransform = {
AnchorMin = "0.05 0", AnchorMax = "0.95 0.64"
}
}, containerName);
// // Панель-фон
// container.Add(new CuiPanel
// {
// Image = { Color = "0.67 0.87 0.80 0.3" }, // Темно-сірий прозорий фон
// RectTransform = { AnchorMin = "0.05 0.08", AnchorMax = "0.95 0.6" }
// }, containerName);
}
CuiHelper.AddUi(player, container);
}
[ConsoleCommand("mbcommands.back")]
private void CmdBack(ConsoleSystem.Arg arg)
{
var player = arg.Connection?.player as BasePlayer;
if (player == null) return;
CuiHelper.DestroyUi(player, "MBCommands_UI");
MBMainMenu?.Call("ShowMainMenu", player);
}
// Встроенный класс ImageUI
private class ImageUI
{
private const string PathFolder = "MBSystem/MBCommands/Images/";
private readonly Dictionary<string, ImageData> _images = new()
{
{ "MBWelcome_Three_Os", new ImageData() },
{ "CommandBG", new ImageData() }
};
private enum ImageStatus { NotLoaded, Loaded, Failed }
private class ImageData
{
public ImageStatus Status = ImageStatus.NotLoaded;
public string Id { get; set; }
}
public string GetImage(string name)
{
if (_images.TryGetValue(name, out var image) && image.Status == ImageStatus.Loaded)
return image.Id;
return null;
}
public void DownloadImages()
{
string fullPath = Interface.Oxide.DataDirectory + System.IO.Path.DirectorySeparatorChar + PathFolder;
if (!System.IO.Directory.Exists(fullPath))
{
System.IO.Directory.CreateDirectory(fullPath);
Interface.Oxide.LogInfo($"[MBCommands] Создана папка: {fullPath}");
}
var nextImage = _images.FirstOrDefault(img => img.Value.Status == ImageStatus.NotLoaded);
if (!string.IsNullOrEmpty(nextImage.Key))
ServerMgr.Instance.StartCoroutine(LoadImage(nextImage));
else
Interface.Oxide.LogInfo("[MBCommands] Все изображения загружены!");
}
private IEnumerator LoadImage(KeyValuePair<string, ImageData> image)
{
string filePath = "file://" + Interface.Oxide.DataDirectory + System.IO.Path.DirectorySeparatorChar + PathFolder + image.Key + ".png";
using (var www = UnityEngine.Networking.UnityWebRequestTexture.GetTexture(filePath))
{
yield return www.SendWebRequest();
if (www.result != UnityEngine.Networking.UnityWebRequest.Result.Success)
{
image.Value.Status = ImageStatus.Failed;
Interface.Oxide.LogWarning($"[MBCommands] Ошибка загрузки {image.Key}");
}
else
{
Texture2D texture = UnityEngine.Networking.DownloadHandlerTexture.GetContent(www);
image.Value.Id = FileStorage.server.Store(texture.EncodeToPNG(), FileStorage.Type.png, CommunityEntity.ServerInstance.net.ID).ToString();
image.Value.Status = ImageStatus.Loaded;
UnityEngine.Object.DestroyImmediate(texture);
}
DownloadImages(); // Попытка загрузить следующую
}
}
public void UnloadImages()
{
foreach (var img in _images)
{
if (img.Value.Status == ImageStatus.Loaded && img.Value.Id != null)
FileStorage.server.Remove(uint.Parse(img.Value.Id), FileStorage.Type.png, CommunityEntity.ServerInstance.net.ID);
}
_images.Clear();
}
}
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
["MB_Close_Commands"] = "Click on an empty space to close the menu",
["MB_Commands_Player"] = "CHAT COMMANDS",
["MB_Commands_Player_2"] = "<color=#FFD700>Control the game</color> using commands",
["MB_Back"] = "Back",
["Command_1"] = "Opens a beautiful graphical menu with perks that you can view and purchase using the in-game currency MBCoins.",
["Command_2"] = "Opens a stylish graphical menu where you can craft exclusive items without searching for them in the usual crafting table.",
["Command_3"] = "Opens a sleek graphical menu with all the main server commands, each accompanied by a brief description.",
["Command_4"] = "Opens a stylish graphical menu displaying the server's wipe calendar with a visual interface.",
["Command_5"] = "Opens the server's main menu with all the most important information in one place.The menu automatically updates data like online players, balance, and event statuses—convenient, fast, and visually appealing."
}, this);
lang.RegisterMessages(new Dictionary<string, string>
{
["MB_Close_Commands"] = "Натисніть на порожнє місце, щоб закрити меню",
["MB_Commands_Player"] = "ЧАТ КОМАНДИ",
["MB_Commands_Player_2"] = "<color=#FFD700>Керуй грою</color> за допомогою команд",
["MB_Back"] = "Назад",
["Command_1"] = "Відкриває красиве графічне меню з привілеями, які ви можете переглянути та придбати за внутрішню валюту MBCoins.",
["Command_2"] = "Відкриває стильне графічне меню, де можна скрафтити ексклюзивні предмети, не шукаючи їх у звичайному верстаку.",
["Command_3"] = "Відкриває стильне графічне меню з усіма основними командами сервера, де кожна команда має короткий опис.",
["Command_4"] = "Відкриває стильне графічне меню в якому відображає календар вайпів на сервері з графічним інтерфейсом.",
["Command_5"] = "Відкриває головне меню сервера з усією найважливішою інформацією в одному місці.Меню автоматично оновлює дані про онлайн, баланс і статуси подій — зручно, швидко, красиво."
}, this, "uk");
lang.RegisterMessages(new Dictionary<string, string>
{
["MB_Close_Commands"] = "Нажмите на пустое место, чтобы закрыть меню",
["MB_Commands_Player"] = "ЧАТ КОМАНДЫ",
["MB_Commands_Player_2"] = "<color=#FFD700>Управляй игрой</color> с помощью команд",
["MB_Back"] = "Назад",
["Command_1"] = "Открывает красивое графическое меню с привилегиями, которые можно просмотреть и приобрести за внутриигровую валюту MBCoins.",
["Command_2"] = "Открывает стильное графическое меню, где можно скрафтить эксклюзивные предметы, не ища их в обычном верстаке.",
["Command_3"] = "Открывает стильное графическое меню со всеми основными командами сервера, где каждая команда имеет краткое описание.",
["Command_4"] = "Открывает стильное графическое меню, в котором отображается календарь вайпов на сервере с графическим интерфейсом.",
["Command_5"] = "Открывает главное меню сервера со всей важной информацией в одном месте.Меню автоматически обновляет данные об онлайн-игроках, балансе и статусах событий — удобно, быстро, красиво."
}, this, "ru");
}
private string Msg(string key, string userid = null, params object[] obj)
{
return string.Format(lang.GetMessage(key, this, userid), obj);
}
}
}