Perms UI 1.3.3 - compatibility fix for current Rust
Perms UI by Camoec stopped compiling after a recent Rust update with this error:'StringView' does not contain a definition for 'ToLower' (line 227)
Rust changed console command arguments (arg.Args) from string to StringView. Below is a small patch to the original 1.3. All credit for the plugin stays with Camoec.
Changes
- Fixed the compile error: the console command now reads its arguments with
arg.GetString(index, "")and checks the argument count witharg.HasArgs(n)instead of usingarg.Argsdirectly. - Fixed a NullReferenceException when the player whose permissions you are editing goes offline while the UI is open. Sleeping players are found too, and an unknown player shows as "Unknown".
- The null check on the console argument now runs before the argument is used.
- Invalid or missing button arguments are ignored safely (
TryParseinstead ofParse), so a bad command no longer throws errors in console. - Fixed the page count. It divided by 10 while each page shows 11 permissions, so the header could show the wrong total and the last page could be unreachable.
- The
>(next page) button sentPERMSin uppercase. It now sendspermslike the other buttons. - Version bumped to 1.3.3. The author is still Camoec.
Unchanged
Commands (/perms user <name|steamid>, /perms group <group>), the permission (permsui.use), the UI layout and the language messages are all the same as 1.3.
FILE: Perms UI v1.3.3 by Camoec Updated by Black Lagoon Gaming
Note
Anyone with permsui.use can grant themselves any plugin permission, so only give it to trusted admins, for example: oxide.grant group admin permsui.use
// Perms UI by Camoec. 1.3.3: minimal compatibility patch for current Rust (Black Lagoon Gaming - Robin de Bie, 2026).
using UnityEngine;
using System.Collections.Generic;
using Oxide.Game.Rust.Cui;
namespace Oxide.Plugins
{
[Info("Perms UI", "Camoec", "1.3.3")]
[Description("GUI for managing plugin permissions in-game")]
public class PermsUI : RustPlugin
{
private const string UsePerm = "PermsUI.use";
private void Init()
{
permission.RegisterPermission(UsePerm, this);
}
private void MainUI(BasePlayer player, string userID, bool user, int page)
{
string Layer = "UI";
if (player == null)
return;
BasePlayer target = user ? BasePlayer.FindAwakeOrSleeping(userID) : null;
var container = new CuiElementContainer();
List<string> perms = new List<string>();
foreach (var perm in permission.GetPermissions())
if (!perm.StartsWith("oxide"))
perms.Add(perm);
int pageLen = 11;
CuiHelper.DestroyUi(player, Layer);
container.Add(new CuiPanel
{
RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1"},
Image =
{
Color = "0 0 0 0.5"
},
CursorEnabled = true
}, "Overlay", Layer);
container.Add(new CuiButton
{
RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" },
Text = { Text = "" },
Button =
{
Color = "0 0 0 0",
Close = Layer
}
}, Layer);
container.Add(new CuiPanel
{
RectTransform =
{
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5",
OffsetMin = "-310 -250",
OffsetMax = "310 250"
},
Image =
{
Color = "0.1 0.1 0.1 0.99"
}
}, Layer, Layer + ".Main");
container.Add(new CuiPanel
{
RectTransform =
{
AnchorMin = "0 1", AnchorMax = "1 1",
OffsetMin = "0 -50",
OffsetMax = "0 0"
},
Image =
{
Color = "0.09 0.09 0.09 1"
}
}, Layer + ".Main", Layer + ".Header");
container.Add(new CuiLabel
{
RectTransform =
{
AnchorMin = "0 0", AnchorMax = "1 1",
OffsetMin = "30 0",
OffsetMax = "0 0"
},
Text =
{
Text = string.Format(Lang("Info", player.UserIDString), page+1, (int)((perms.Count - 1) / pageLen)+1, (user ? (target != null ? target.displayName : "Unknown") + " [" + userID + "]" : userID)),
Align = TextAnchor.MiddleLeft,
Font = "RobotoCondensed-Bold.ttf",
FontSize = 14,
Color = "1 1 1 1"
}
}, Layer + ".Header");
var _y = -60f;
float _x = -10;
float width = 30;
float margin = 2;
container.Add(new CuiButton
{
RectTransform =
{
AnchorMin = "1 1", AnchorMax = "1 1",
OffsetMin = $"{_x - width} -37.5",
OffsetMax = $"{_x} -12.5"
},
Text =
{
Text = ">",
Align = TextAnchor.MiddleCenter,
FontSize = 12,
Color = "1 1 1 1"
},
Button =
{
Color = "0.6 0.01 0.16 1",
Command = $"perms page {player.UserIDString} {userID} {user} {(page < ((perms.Count - 1) / pageLen) ? page+1 : page)}"
}
}, Layer + ".Header");
_x = _x - margin - width;
container.Add(new CuiButton
{
RectTransform =
{
AnchorMin = "1 1", AnchorMax = "1 1",
OffsetMin = $"{_x - width} -37.5",
OffsetMax = $"{_x} -12.5"
},
Text =
{
Text = "<",
Align = TextAnchor.MiddleCenter,
FontSize = 12,
Color = "1 1 1 1"
},
Button =
{
Color = "0.6 0.01 0.16 1",
Command = $"perms page {player.UserIDString} {userID} {user} {(page > 0 ? page-1 : 0)}"
}
}, Layer + ".Header");
for (int i = page * pageLen ; i < perms.Count; i++)
{
if (i > page * pageLen + pageLen - 1)
break;
var perm = perms[i];
container.Add(new CuiPanel
{
RectTransform =
{
AnchorMin = "0.5 1", AnchorMax = "0.5 1",
OffsetMin = $"-300 {_y - 30}",
OffsetMax = $"300 {_y}"
},
Image =
{
Color = "0.09 0.09 0.09 1"
}
}, Layer + ".Main", Layer + $".Perm.{_y}");
container.Add(new CuiLabel
{
RectTransform =
{
AnchorMin = "0 0", AnchorMax = "1 1",
OffsetMin = "10 0", OffsetMax = "0 0"
},
Text =
{
Text = $"{perm}",
Align = TextAnchor.MiddleLeft,
FontSize = 14,
Color = "1 1 1 1"
}
}, Layer + $".Perm.{_y}");
string cmd = $"{(user ? permission.UserHasPermission(userID, perm) ? "Revoke" : "Grant" : permission.GroupHasPermission(userID, perm) ? "Revoke" : "Grant")}";
container.Add(new CuiButton
{
RectTransform =
{
AnchorMin = "1 0.5", AnchorMax = "1 0.5",
OffsetMin = "-120 -15", OffsetMax = "-0 15"
},
Text =
{
Text = cmd,
Align = TextAnchor.MiddleCenter,
FontSize = 14,
Color = "1 1 1 1"
},
Button =
{
Color = cmd == "Revoke" ? "0.6 0.01 0.16 1" : "0.1 0.6 0.1 1",
Command = $"perms {(user ? "USER" : "GROUP")} {cmd} {perm} {userID} {player.userID} {page}"
}
}, Layer + $".Perm.{_y}");
_y = _y - 30 - 10;
}
CuiHelper.AddUi(player, container);
}
[ConsoleCommand("perms")]
private void GivePerm(ConsoleSystem.Arg arg)
{
if (arg == null)
return;
if (!arg.IsRcon && (arg.Player() != null && !permission.UserHasPermission(arg.Player().UserIDString, UsePerm)))
return;
if (!arg.HasArgs(5))
return;
// Current Rust: arg.Args is StringView[], so read arguments with GetString.
string id = arg.GetString(0, "").ToLower();
string cmd = arg.GetString(1, "").ToLower();
if(id == "page")
{
ulong pageCaller;
bool pageUser;
int pageNum;
if (!ulong.TryParse(cmd, out pageCaller) || !bool.TryParse(arg.GetString(3, ""), out pageUser) || !int.TryParse(arg.GetString(4, ""), out pageNum))
return;
MainUI(BasePlayer.FindByID(pageCaller), arg.GetString(2, ""), pageUser, pageNum);
return;
}
if (!arg.HasArgs(6))
return;
string perm = arg.GetString(2, "");
string userid = arg.GetString(3, "");
ulong caller;
int page;
if (!ulong.TryParse(arg.GetString(4, ""), out caller) || !int.TryParse(arg.GetString(5, ""), out page))
return;
if (id == "user")
{
if (cmd == "grant")
{
permission.GrantUserPermission(userid, perm, null);
}
else if (cmd == "revoke")
{
permission.RevokeUserPermission(userid, perm);
}
MainUI(BasePlayer.FindByID(caller), userid, true, page);
}else if(id == "group")
{
if (cmd == "grant")
{
permission.GrantGroupPermission(userid, perm, null);
}
else if (cmd == "revoke")
{
permission.RevokeGroupPermission(userid, perm);
}
MainUI(BasePlayer.FindByID(caller), userid, false, page);
}
}
[ChatCommand("perms")]
private void permsCommand (BasePlayer player, string command, string[] args)
{
if (!permission.UserHasPermission(player.UserIDString, UsePerm))
{
PrintToChat(player, Lang("NoPermission", player.UserIDString));
return;
}
if (args.Length > 1)
{
string cmd = args[0].ToLower();
string id = args[1].ToLower();
if (cmd == "user")
{
BasePlayer target = BasePlayer.Find(id);
if(target == null)
{
PrintToChat(player, Lang("UserNF", player.UserIDString));
return;
}
MainUI(player, target.UserIDString, true, 0);
return;
}
if (cmd == "group")
{
if(!permission.GroupExists(id))
{
PrintToChat(player, Lang("GroupNF", player.UserIDString));
return;
}
MainUI(player, id, false, 0);
return;
}
return;
}
PrintToChat(player, Lang("Syntax", player.UserIDString));
}
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
["NoPermission"] = "You don't have permission to use this",
["Syntax"] = "Use /perms [user|group] [id|name]",
["GroupNF"] = "Group not found",
["UserNF"] = "Player not found",
["Info"] = "[{0}/{1}] Permissions for {2}"
}, this);
}
private string Lang(string key, string userid) => lang.GetMessage(key, this, userid);
}
}