C#:
using System.Collections.Generic;
using System.Globalization;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using UnityEngine;
using System.Linq;
namespace Oxide.Plugins {
[Info("FriendsUI", "k1lly0u/Kira", "0.1.4")]
[Description("A user interface for managing friends via FriendsAPI")]
class FriendsUI : RustPlugin {
#region Fields
[PluginReference]
private Plugin Friends;
private const string FriendUI = "FriendsUI";
private const string FriendBG = "FriendsUIBG";
private int maxFriends;
private SortedList<string, string> playerList = new SortedList<string, string>();
private Dictionary<ulong, string[]> temporaryLists = new Dictionary<ulong, string[]>();
private List<ulong> openMenu = new List<ulong>();
#endregion
#region Oxide Hooks
private void OnServerInitialized() {
lang.RegisterMessages(Messages, this);
LoadVariables();
if (!Friends) {
PrintError("Unable to find a valid Friends plugin! Unable to continue");
Interface.Oxide.UnloadPlugin("FriendsUI");
return;
}
maxFriends = (int)Friends?.Call("GetMaxFriends");
cmd.AddChatCommand(configData.MenuActivation.CommandToOpen, this, cmdFriendUI);
foreach (var player in BasePlayer.activePlayerList) OnPlayerInit(player);
}
private void OnPlayerInit(BasePlayer player) {
var name = TrimToSize(RemoveTag(player.displayName), 15);
if (!playerList.ContainsKey(player.UserIDString)) playerList.Add(player.UserIDString, name);
else playerList[player.UserIDString] = name;
if (!string.IsNullOrEmpty(configData.MenuActivation.KeyToBind)) player.Command("bind " + configData.MenuActivation.KeyToBind + " FriendsUIToggle");
}
private void OnPlayerDisconnected(BasePlayer player) {
openMenu.Remove(player.userID);
if (temporaryLists.ContainsKey(player.userID)) temporaryLists.Remove(player.userID);
CuiHelper.DestroyUi(player, FriendBG);
CuiHelper.DestroyUi(player, FriendUI);
}
private void Unload() {
foreach (var player in BasePlayer.activePlayerList) {
if (temporaryLists.ContainsKey(player.userID)) temporaryLists.Remove(player.userID);
CuiHelper.DestroyUi(player, FriendBG);
CuiHelper.DestroyUi(player, FriendUI);
}
openMenu.Clear();
}
#endregion
#region Functions
private string RemoveTag(string str) {
if (str.StartsWith("[") && str.Contains("]") && str.Length > str.IndexOf("]")) str = str.Substring(str.IndexOf("]") + 1).Trim();
if (str.StartsWith("[") && str.Contains("]") && str.Length > str.IndexOf("]")) RemoveTag(str);
return str;
}
private string TrimToSize(string str, int size) => str.Length <= size ? str : str.Substring(0, size);
#endregion
#region Helpers
private bool AddFriend(string playerId, string friendId) {
if (playerId == friendId) return false;
return (bool)Friends.Call("AddFriend", playerId, friendId);
}
private bool RemoveFriend(string playerId, string friendId) => (bool)Friends.Call("RemoveFriend", playerId, friendId);
private bool AreFriends(string playerId, string friendId) => (bool)Friends.Call("AreFriends", playerId, friendId);
private string[] GetFriendsList(string playerId) => Friends.Call("GetFriends", playerId) as string[];
#endregion
#region UI
class UI {
static public CuiElementContainer CreateElementContainer(string panelName, string color, string aMin, string aMax, bool cursor = false, string parent = "Hud") {
var NewElement = new CuiElementContainer() {
{
new CuiPanel {
Image = {
Color = color
}
, RectTransform = {
AnchorMin = aMin, AnchorMax = aMax
}
, CursorEnabled = cursor
}
, new CuiElement().Parent = parent, panelName
}
}
;
return NewElement;
}
static public void CreatePanel(ref CuiElementContainer container, string panel, string color, string aMin, string aMax, bool cursor = false) {
container.Add(new CuiPanel {
Image = {
Color = color
}
, RectTransform = {
AnchorMin = aMin, AnchorMax = aMax
}
, CursorEnabled = cursor
}
, panel, CuiHelper.GetGuid());
}
static public void CreateLabel(ref CuiElementContainer container, string panel, string color, string text, int size, string aMin, string aMax, TextAnchor align = TextAnchor.MiddleCenter) {
container.Add(new CuiLabel {
Text = {
Color = color, FontSize = size, Align = align, FadeIn = 0, Text = text
}
, RectTransform = {
AnchorMin = aMin, AnchorMax = aMax
}
}
, panel, CuiHelper.GetGuid());
}
static public void CreateButton(ref CuiElementContainer container, string panel, string color, string text, int size, string aMin, string aMax, string command, TextAnchor align = TextAnchor.MiddleCenter) {
container.Add(new CuiButton {
Button = {
Color = color, Command = command, FadeIn = 0
}
, RectTransform = {
AnchorMin = aMin, AnchorMax = aMax
}
, Text = {
Text = text, FontSize = size, Align = align
}
}
, panel, CuiHelper.GetGuid());
}
static public string Color(string hexColor, float alpha) {
if (hexColor.StartsWith("#")) hexColor = hexColor.TrimStart('#');
int red = int.Parse(hexColor.Substring(0, 2), NumberStyles.AllowHexSpecifier);
int green = int.Parse(hexColor.Substring(2, 2), NumberStyles.AllowHexSpecifier);
int blue = int.Parse(hexColor.Substring(4, 2), NumberStyles.AllowHexSpecifier);
return $"{(double)red / 255} {(double)green / 255} {(double)blue / 255} {alpha}";
}
}
#endregion
#region UI Creation
class PlayerInfo {
public string playerId, playerName;
}
private void LoadFriendMenu(BasePlayer player, int page = 0) {
var container = UI.CreateElementContainer(FriendBG, "0 0 0 0", "0.15 0.15", "0.85 0.85", true);
openMenu.Add(player.userID);
CuiHelper.AddUi(player, container);
FriendsMenu(player, page);
}
private void FriendsMenu(BasePlayer player, int page = 0) {
if (!temporaryLists.ContainsKey(player.userID)) temporaryLists.Add(player.userID, GetFriendsList(player.UserIDString));
var friendList = temporaryLists[player.userID];
var container = UI.CreateElementContainer(FriendUI, UI.Color(configData.UIColors.Background.HexColor, configData.UIColors.Background.Opacity), $"{configData.UISize.X_Position} {configData.UISize.Y_Position}", $"{configData.UISize.X_Position + configData.UISize.X_Dimension} {configData.UISize.Y_Position + configData.UISize.Y_Dimension}");
UI.CreateButton(ref container, FriendUI, UI.Color(configData.UIColors.CloseButton.HexColor, configData.UIColors.CloseButton.Opacity), "X", 18, "0.92 0.945", "0.998 0.995", "FriendsUI close");
UI.CreateLabel(ref container, FriendUI, "", msg("title", player.UserIDString), 18, "0.02 0.94", "0.5 1", TextAnchor.MiddleLeft);
UI.CreatePanel(ref container, FriendUI, UI.Color(configData.UIColors.Background.HexColor, configData.UIColors.Background.Opacity), "0.0001 0.0001", "0.9999 0.94");
UI.CreatePanel(ref container, FriendUI, UI.Color(configData.UIColors.TitlePanel.HexColor, configData.UIColors.TitlePanel.Opacity), "0.01 0.875", "0.4 0.93");
UI.CreatePanel(ref container, FriendUI, UI.Color(configData.UIColors.TextPanel.HexColor, configData.UIColors.TextPanel.Opacity), "0.41 0.875", "0.59 0.93");
UI.CreateLabel(ref container, FriendUI, "", msg("friendList", player.UserIDString), 16, "0.02 0.875", "0.39 0.93", TextAnchor.MiddleLeft);
UI.CreateLabel(ref container, FriendUI, "", $"({friendList.Length}/{maxFriends})", 16, "0.02 0.875", "0.39 0.93", TextAnchor.MiddleRight);
UI.CreateButton(ref container, FriendUI, UI.Color(configData.UIColors.ButtonColor.HexColor, configData.UIColors.ButtonColor.Opacity), msg("addFriend", player.UserIDString), 16, "0.6 0.875", "0.99 0.93", "FriendsUI friendselect 0");
UI.CreateLabel(ref container, FriendUI, "", msg("mutualInfo", player.UserIDString), 10, "0.02 0.83", "0.98 0.875", TextAnchor.MiddleLeft);
for (int i = (12 * page);
i < friendList.Length;
i++) {
if (i >= (12 * page) + 12) break;
string friendId = friendList[i];
bool isMutual = AreFriends(player.UserIDString, friendId);
AddFriendEntry(ref container, player.UserIDString, friendId, isMutual, i - (12 * page), page);
}
bool hasPages = false;
int maxCount = friendList.Length;
if (maxCount > 10) {
hasPages = true;
var maxpages = (maxCount - 1) / 10 + 1;
if (page < maxpages - 1) UI.CreateButton(ref container, FriendUI, UI.Color(configData.UIColors.ButtonColor.HexColor, configData.UIColors.ButtonColor.Opacity), ">>>", 14, "0.205 0.01", "0.38 0.05", $"FriendsUI mainmenu {page + 1}");
if (page > 0) UI.CreateButton(ref container, FriendUI, UI.Color(configData.UIColors.ButtonColor.HexColor, configData.UIColors.ButtonColor.Opacity), "<<<", 14, "0.02 0.01", "0.195 0.05", $"FriendsUI mainmenu {page - 1}");
}
UI.CreatePanel(ref container, FriendUI, UI.Color(configData.UIColors.TitlePanel.HexColor, configData.UIColors.TitlePanel.Opacity), $"{(hasPages ? 0.39f : 0.01f)} 0.01", "0.99 0.05");
UI.CreateLabel(ref container, FriendUI, "", msg("info", player.UserIDString).Replace("{uiversion}", Version.ToString()), 12, $"{(hasPages ? 0.39f : 0.02f)} 0.01", "0.98 0.05", TextAnchor.MiddleCenter);
CuiHelper.DestroyUi(player, FriendUI);
CuiHelper.AddUi(player, container);
}
private void AddFriendEntry(ref CuiElementContainer container, string playerId, string memberId, bool isMutual, int number, int page) {
var targetPlayer = covalence.Players.FindPlayerById(memberId);
float yPos = 0.78f - (0.06f * number);
UI.CreatePanel(ref container, FriendUI, UI.Color(configData.UIColors.TextPanel.HexColor, configData.UIColors.TextPanel.Opacity), $"0.02 {yPos}", $"0.38 {yPos + 0.05f}");
UI.CreateLabel(ref container, FriendUI, "", $"{(isMutual ? "<color=#00E500>" : "<color=#ce422b>")}•</color> {targetPlayer?.Name ?? memberId}", 14, $"0.03 {yPos}", $"0.37 {yPos + 0.05f}", TextAnchor.MiddleLeft);
for (int i = 0; i < configData.Commands.Count; i++) {
float xPos = 0.39f + (0.11f * i);
var command = configData.Commands[i];
UI.CreateButton(ref container, FriendUI, UI.Color(configData.UIColors.ButtonColor.HexColor, configData.UIColors.ButtonColor.Opacity), command.Name, 14, $"{xPos} {yPos}", $"{xPos + 0.1f} {yPos + 0.05f}", $"FriendsUI command {i} {memberId} {targetPlayer?.Name.Replace(" ", "$$%%^^") ?? memberId}");
}
UI.CreateButton(ref container, FriendUI, UI.Color(configData.UIColors.ButtonColor.HexColor, configData.UIColors.ButtonColor.Opacity), msg("remove", playerId), 14, $"0.88 {yPos}", $"0.99 {yPos + 0.05f}", $"FriendsUI remove {page} {memberId}");
}
private void FriendSelection(BasePlayer player, int page) {
var container = UI.CreateElementContainer(FriendUI, UI.Color(configData.UIColors.Background.HexColor, configData.UIColors.Background.Opacity), $"{configData.UISize.X_Position} {configData.UISize.Y_Position}", $"{configData.UISize.X_Position + configData.UISize.X_Dimension} {configData.UISize.Y_Position + configData.UISize.Y_Dimension}");
UI.CreateButton(ref container, FriendUI, UI.Color(configData.UIColors.CloseButton.HexColor, configData.UIColors.CloseButton.Opacity), "X", 18, "0.92 0.945", "0.998 0.995", "FriendsUI close");
UI.CreateLabel(ref container, FriendUI, "", msg("title", player.UserIDString), 18, "0.02 0.94", "0.5 1", TextAnchor.MiddleLeft);
UI.CreatePanel(ref container, FriendUI, UI.Color(configData.UIColors.Background.HexColor, configData.UIColors.Background.Opacity), "0.0001 0.0001", "0.9999 0.94");
UI.CreatePanel(ref container, FriendUI, UI.Color(configData.UIColors.TitlePanel.HexColor, configData.UIColors.TitlePanel.Opacity), "0.01 0.875", "0.854 0.93");
UI.CreateLabel(ref container, FriendUI, "", msg("friendSelect", player.UserIDString), 16, "0.02 0.875", "0.844 0.93", TextAnchor.MiddleLeft);
UI.CreateButton(ref container, FriendUI, UI.Color(configData.UIColors.ButtonColor.HexColor, configData.UIColors.ButtonColor.Opacity), msg("back", player.UserIDString), 15, "0.864 0.875", "0.99 0.93", "FriendsUI mainmenu 0");
int count = playerList.Count();
for (int i = (60 * page);
i < count;
i++) {
if (i >= (60 * page) + 60) break;
var targetId = playerList.Keys[i];
AddFriendButton(ref container, playerList[targetId], targetId, i - (60 * page));
}
bool hasPages = false;
int maxCount = playerList.Count;
if (maxCount > 60) {
hasPages = true;
var maxpages = (maxCount - 1) / 60 + 1;
if (page < maxpages - 1) UI.CreateButton(ref container, FriendUI, UI.Color(configData.UIColors.ButtonColor.HexColor, configData.UIColors.ButtonColor.Opacity), ">>>", 14, "0.205 0.01", "0.38 0.05", $"FriendsUI friendselect {page + 1}");
if (page > 0) UI.CreateButton(ref container, FriendUI, UI.Color(configData.UIColors.ButtonColor.HexColor, configData.UIColors.ButtonColor.Opacity), "<<<", 14, "0.02 0.01", "0.195 0.05", $"FriendsUI friendselect {page - 1}");
}
UI.CreatePanel(ref container, FriendUI, UI.Color(configData.UIColors.TitlePanel.HexColor, configData.UIColors.TitlePanel.Opacity), $"{(hasPages ? 0.39f : 0.01f)} 0.01", "0.99 0.05");
UI.CreateLabel(ref container, FriendUI, "", msg("info", player.UserIDString).Replace("{uiversion}", Version.ToString()), 12, $"{(hasPages ? 0.39f : 0.02f)} 0.01", "0.98 0.05", TextAnchor.MiddleCenter);
CuiHelper.DestroyUi(player, FriendUI);
CuiHelper.AddUi(player, container);
}
private void AddFriendButton(ref CuiElementContainer container, string name, string playerId, int number) {
float[] position = CalculateEntryPos(number);
UI.CreateButton(ref container, FriendUI, UI.Color(configData.UIColors.ButtonColor.HexColor, configData.UIColors.ButtonColor.Opacity), name, 14, $"{position[0]} {position[1]}", $"{position[2]} {position[3]}", $"FriendsUI addfriend 0 {playerId}");
}
private float[] CalculateEntryPos(int number) {
Vector2 position = new Vector2(0.01f, 0.805f);
Vector2 dimensions = new Vector2(0.188f, 0.055f);
float offsetY = 0;
float offsetX = 0;
if (number >= 0 && number < 5) {
offsetX = (0.01f + dimensions.x) * number;
}
if (number > 4 && number < 10) {
offsetX = (0.01f + dimensions.x) * (number - 5);
offsetY = (-0.01f - dimensions.y) * 1;
}
if (number > 9 && number < 15) {
offsetX = (0.01f + dimensions.x) * (number - 10);
offsetY = (-0.01f - dimensions.y) * 2;
}
if (number > 14 && number < 20) {
offsetX = (0.01f + dimensions.x) * (number - 15);
offsetY = (-0.01f - dimensions.y) * 3;
}
if (number > 19 && number < 25) {
offsetX = (0.01f + dimensions.x) * (number - 20);
offsetY = (-0.01f - dimensions.y) * 4;
}
if (number > 24 && number < 30) {
offsetX = (0.01f + dimensions.x) * (number - 25);
offsetY = (-0.01f - dimensions.y) * 5;
}
if (number > 29 && number < 35) {
offsetX = (0.01f + dimensions.x) * (number - 30);
offsetY = (-0.01f - dimensions.y) * 6;
}
if (number > 34 && number < 40) {
offsetX = (0.01f + dimensions.x) * (number - 35);
offsetY = (-0.01f - dimensions.y) * 7;
}
if (number > 39 && number < 45) {
offsetX = (0.01f + dimensions.x) * (number - 40);
offsetY = (-0.01f - dimensions.y) * 8;
}
if (number > 44 && number < 50) {
offsetX = (0.01f + dimensions.x) * (number - 45);
offsetY = (-0.01f - dimensions.y) * 9;
}
if (number > 49 && number < 55) {
offsetX = (0.01f + dimensions.x) * (number - 50);
offsetY = (-0.01f - dimensions.y) * 10;
}
if (number > 54 && number < 60) {
offsetX = (0.01f + dimensions.x) * (number - 55);
offsetY = (-0.01f - dimensions.y) * 11;
}
Vector2 offset = new Vector2(offsetX, offsetY);
Vector2 posMin = position + offset;
Vector2 posMax = posMin + dimensions;
return new float[] {
posMin.x, posMin.y, posMax.x, posMax.y
}
;
}
#endregion
#region UI Commands
[ConsoleCommand("FriendsUIToggle")]
private void ccmdFriendsUIToggle(ConsoleSystem.Arg arg) {
var player = arg.Connection.player as BasePlayer;
if (player == null) return;
if (!openMenu.Contains(player.userID)) {
LoadFriendMenu(player);
}
else {
openMenu.Remove(player.userID);
if (temporaryLists.ContainsKey(player.userID)) temporaryLists.Remove(player.userID);
CuiHelper.DestroyUi(player, FriendBG);
CuiHelper.DestroyUi(player, FriendUI);
}
}
[ConsoleCommand("FriendsUI")]
private void ccmdFriendsUI(ConsoleSystem.Arg arg) {
var player = arg.Connection.player as BasePlayer;
if (player == null) return;
string command = arg.GetString(0);
if (command == "close") {
openMenu.Remove(player.userID);
if (temporaryLists.ContainsKey(player.userID)) temporaryLists.Remove(player.userID);
CuiHelper.DestroyUi(player, FriendBG);
CuiHelper.DestroyUi(player, FriendUI);
return;
}
int page = arg.GetInt(1);
string targetId = "";
if (arg.Args.Length > 2) targetId = arg.GetString(2);
switch (arg.Args[0]) {
case "mainmenu" : FriendsMenu(player, page);
return;
case "remove" : if (RemoveFriend(player.UserIDString, targetId)) temporaryLists[player.userID] = GetFriendsList(player.UserIDString);
FriendsMenu(player, page);
return;
case "command" : string targetName = arg.GetString(3).Replace("$$%%^^", " ");
var cmd = configData.Commands[page];
rust.RunClientCommand(player, $"chat.say", new string[] {
$"{cmd.Command} \"{cmd.Arg.Replace(" {
playerName
}
", targetName).Replace(" {
playerId
}
", targetId)}\""
}
);
return;
case "addfriend" : if (AddFriend(player.UserIDString, targetId)) temporaryLists[player.userID] = GetFriendsList(player.UserIDString);
FriendsMenu(player, page);
return;
case "friendselect" : FriendSelection(player, page);
return;
default : break;
}
}
#endregion
#region Commands
private void cmdFriendUI(BasePlayer player, string command, string[] args) => LoadFriendMenu(player);
#endregion
#region Config
private ConfigData configData;
class UIColor {
public string HexColor {
get;
set;
}
public float Opacity {
get;
set;
}
}
class UIColors {
public UIColor Background {
get;
set;
}
public UIColor TitlePanel {
get;
set;
}
public UIColor TextPanel {
get;
set;
}
public UIColor CloseButton {
get;
set;
}
public UIColor ButtonColor {
get;
set;
}
}
class UISize {
public float X_Position {
get;
set;
}
public float X_Dimension {
get;
set;
}
public float Y_Position {
get;
set;
}
public float Y_Dimension {
get;
set;
}
}
class CommandButton {
public string Name {
get;
set;
}
public string Command {
get;
set;
}
public string Arg {
get;
set;
}
}
class MenuActivation {
public string KeyToBind {
get;
set;
}
public string CommandToOpen {
get;
set;
}
}
class ConfigData {
public List<CommandButton> Commands {
get;
set;
}
public UIColors UIColors {
get;
set;
}
public UISize UISize {
get;
set;
}
public MenuActivation MenuActivation {
get;
set;
}
}
private void LoadVariables() {
LoadConfigVariables();
SaveConfig();
}
protected override void LoadDefaultConfig() {
var config = new ConfigData {
Commands = new List<CommandButton> {
new CommandButton {
Name = "TPR", Command = "/tpr", Arg = "{playerName}"
}
, new CommandButton {
Name = "TRADE", Command = "/trade", Arg = "{playerName}"
}
}
, MenuActivation = new MenuActivation {
CommandToOpen = "fmenu", KeyToBind = ""
}
, UIColors = new UIColors {
Background = new UIColor {
HexColor = "#00001F", Opacity = 0.7f
}
, ButtonColor = new UIColor {
HexColor = "#00006A", Opacity = 0.7f
}
, TextPanel = new UIColor {
HexColor = "#00006A", Opacity = 0.7f
}
, TitlePanel = new UIColor {
HexColor = "#0000B2", Opacity = 0.7f
}
, CloseButton = new UIColor {
HexColor = "#ce422b", Opacity = 0.7f
}
}
, UISize = new UISize {
X_Position = 0.31f, X_Dimension = 0.4f, Y_Position = 0.2f, Y_Dimension = 0.7f
}
}
;
SaveConfig(config);
}
private void LoadConfigVariables() => configData = Config.ReadObject<ConfigData>();
void SaveConfig(ConfigData config) => Config.WriteObject(config, true);
#endregion
#region Messages
string msg(string key, string playerId = null) => lang.GetMessage(key, this, playerId);
Dictionary<string, string> Messages = new Dictionary<string, string>() {
{
"title", "Friend Administration"
}
, {
"friendList", "Friends List"
}
, {
"on", "ON"
}
, {
"back", "Back"
}
, {
"off", "OFF"
}
, {
"remove", "Remove"
}
, {
"addFriend", "Add Friend"
}
, {
"friendSelect", "Select a player to add to your friends list"
}
, {
"mutualInfo", "<color=#00E500><size=12>•</size></color> Mutual Friendship | <color=#ce422b><size=12>•</size></color> Non-Mutual Friendship"
}
, {
"info", "GUI for Friends - v.{uiversion} :: www.chaoscode.io"
}
}
;
#endregion
}
}