* Add stealthmin command.
* Update Content.Server/Administration/Commands/AdminWhoCommand.cs
As suggested by CE.
Co-authored-by: Chief-Engineer <119664036+Chief-Engineer@users.noreply.github.com>
* Add admin notifications for admins toggling stealthmin.
* Localize stealthmin command
---------
Co-authored-by: Chief-Engineer <119664036+Chief-Engineer@users.noreply.github.com>
var adminMgr = IoCManager.Resolve<IAdminManager>();
var afk = IoCManager.Resolve<IAfkManager>();
+ var seeStealth = true;
+
+ // If null it (hopefully) means it is being called from the console.
+ if (shell.Player != null)
+ {
+ var playerData = adminMgr.GetAdminData(shell.Player);
+
+ seeStealth = playerData != null && playerData.CanStealth();
+ }
+
var sb = new StringBuilder();
var first = true;
foreach (var admin in adminMgr.ActiveAdmins)
var adminData = adminMgr.GetAdminData(admin)!;
DebugTools.AssertNotNull(adminData);
+ if (adminData.Stealth && !seeStealth)
+ continue;
+
sb.Append(admin.Name);
if (adminData.Title is { } title)
sb.Append($": [{title}]");
+ if (adminData.Stealth)
+ sb.Append(" (S)");
+
if (shell.Player is { } player && adminMgr.HasAdminFlag(player, AdminFlags.Admin))
{
if (afk.IsAfk(admin))
--- /dev/null
+using Content.Server.Administration.Managers;
+using Content.Shared.Administration;
+using JetBrains.Annotations;
+using Robust.Shared.Console;
+using Robust.Shared.Utility;
+
+namespace Content.Server.Administration.Commands;
+
+[UsedImplicitly]
+[AdminCommand(AdminFlags.Stealth)]
+public sealed class StealthminCommand : LocalizedCommands
+{
+ public override string Command => "stealthmin";
+
+ public override void Execute(IConsoleShell shell, string argStr, string[] args)
+ {
+ var player = shell.Player;
+ if (player == null)
+ {
+ shell.WriteLine(Loc.GetString("cmd-stealthmin-no-console"));
+ return;
+ }
+
+ var mgr = IoCManager.Resolve<IAdminManager>();
+
+ var adminData = mgr.GetAdminData(player);
+
+ DebugTools.AssertNotNull(adminData);
+
+ if (!adminData!.Stealth)
+ {
+ mgr.Stealth(player);
+ }
+ else
+ {
+ mgr.UnStealth(player);
+ }
+ }
+}
UpdateAdminStatus(session);
}
+ public void Stealth(ICommonSession session)
+ {
+ if (!_admins.TryGetValue(session, out var reg))
+ {
+ throw new ArgumentException($"Player {session} is not an admin");
+ }
+
+ if (reg.Data.Stealth)
+ return;
+
+ var playerData = session.ContentData()!;
+ playerData.Stealthed = true;
+ reg.Data.Stealth = true;
+
+ _chat.DispatchServerMessage(session, Loc.GetString("admin-manager-stealthed-message"));
+ _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-self-de-admin-message", ("exAdminName", session.Name)), AdminFlags.Stealth);
+ _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-self-enable-stealth", ("stealthAdminName", session.Name)), flagWhitelist: AdminFlags.Stealth);
+ }
+
+ public void UnStealth(ICommonSession session)
+ {
+ if (!_admins.TryGetValue(session, out var reg))
+ {
+ throw new ArgumentException($"Player {session} is not an admin");
+ }
+
+ if (!reg.Data.Stealth)
+ return;
+
+ var playerData = session.ContentData()!;
+ playerData.Stealthed = false;
+ reg.Data.Stealth = false;
+
+ _chat.DispatchServerMessage(session, Loc.GetString("admin-manager-unstealthed-message"));
+ _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-self-re-admin-message", ("newAdminName", session.Name)), flagBlacklist: AdminFlags.Stealth);
+ _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-self-disable-stealth", ("exStealthAdminName", session.Name)), flagWhitelist: AdminFlags.Stealth);
+ }
+
public void ReAdmin(ICommonSession session)
{
if (!_admins.TryGetValue(session, out var reg))
plyData.ExplicitlyDeadminned = false;
reg.Data.Active = true;
- _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-self-re-admin-message", ("newAdminName", session.Name)));
+ if (reg.Data.Stealth)
+ {
+ _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-self-re-admin-message", ("newAdminName", session.Name)));
+ }
+ else
+ {
+ _chat.DispatchServerMessage(session, Loc.GetString("admin-manager-stealthed-message"));
+ _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-self-re-admin-message",
+ ("newAdminName", session.Name)), flagWhitelist: AdminFlags.Stealth);
+ }
SendPermsChangedEvent(session);
UpdateAdminStatus(session);
_chat.DispatchServerMessage(player, Loc.GetString("admin-manager-admin-permissions-updated-message"));
}
+
+ if (player.ContentData()!.Stealthed)
+ {
+ aData.Stealth = true;
+ }
}
SendPermsChangedEvent(player);
}
else if (e.NewStatus == SessionStatus.Disconnected)
{
- if (_admins.Remove(e.Session) && _cfg.GetCVar(CCVars.AdminAnnounceLogout))
+ if (_admins.Remove(e.Session, out var reg ) && _cfg.GetCVar(CCVars.AdminAnnounceLogout))
{
- _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-admin-logout-message", ("name", e.Session.Name)));
+ if (reg.Data.Stealth)
+ {
+ _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-admin-logout-message",
+ ("name", e.Session.Name)), flagWhitelist: AdminFlags.Stealth);
+
+ }
+ else
+ {
+ _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-admin-logout-message",
+ ("name", e.Session.Name)));
+ }
}
}
}
_admins.Add(session, reg);
+ if (session.ContentData()!.Stealthed)
+ reg.Data.Stealth = true;
+
if (!session.ContentData()!.ExplicitlyDeadminned)
{
reg.Data.Active = true;
if (_cfg.GetCVar(CCVars.AdminAnnounceLogin))
{
- _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-admin-login-message", ("name", session.Name)));
+ if (reg.Data.Stealth)
+ {
+
+ _chat.DispatchServerMessage(session, Loc.GetString("admin-manager-stealthed-message"));
+ _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-admin-login-message",
+ ("name", session.Name)), flagWhitelist: AdminFlags.Stealth);
+ }
+ else
+ {
+ _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-admin-login-message",
+ ("name", session.Name)));
+ }
}
SendPermsChangedEvent(session);
/// </summary>
void ReAdmin(ICommonSession session);
+ /// <summary>
+ /// Make admin hidden from adminwho.
+ /// </summary>
+ void Stealth(ICommonSession session);
+
+ /// <summary>
+ /// Unhide admin from adminwho.
+ /// </summary>
+ void UnStealth(ICommonSession session);
+
/// <summary>
/// Re-loads the permissions of an player in case their admin data changed DB-side.
/// </summary>
_adminLogger.Add(LogType.Chat, LogImpact.Low, $"Server message to {player:Player}: {message}");
}
- public void SendAdminAnnouncement(string message)
+ public void SendAdminAnnouncement(string message, AdminFlags? flagBlacklist, AdminFlags? flagWhitelist)
{
- var clients = _adminManager.ActiveAdmins.Select(p => p.Channel);
+ var clients = _adminManager.ActiveAdmins.Where(p =>
+ {
+ var adminData = _adminManager.GetAdminData(p);
+
+ DebugTools.AssertNotNull(adminData);
+
+ if (adminData == null)
+ return false;
+
+ if (flagBlacklist != null && adminData.HasFlag(flagBlacklist.Value))
+ return false;
+
+ return flagWhitelist == null || adminData.HasFlag(flagWhitelist.Value);
+
+ }).Select(p => p.Channel);
var wrappedMessage = Loc.GetString("chat-manager-send-admin-announcement-wrap-message",
("adminChannelName", Loc.GetString("chat-manager-admin-channel-name")), ("message", FormattedMessage.EscapeText(message)));
using System.Diagnostics.CodeAnalysis;
+using Content.Shared.Administration;
using Content.Shared.Chat;
using Robust.Shared.Network;
using Robust.Shared.Player;
void TrySendOOCMessage(ICommonSession player, string message, OOCChatType type);
void SendHookOOC(string sender, string message);
- void SendAdminAnnouncement(string message);
+ void SendAdminAnnouncement(string message, AdminFlags? flagBlacklist = null, AdminFlags? flagWhitelist = null);
void SendAdminAlert(string message);
void SendAdminAlert(EntityUid player, string message);
/// </summary>
public bool Active;
+ /// <summary>
+ /// Whether the admin is in stealth mode and won't appear in adminwho to admins without the Stealth flag.
+ /// </summary>
+ public bool Stealth;
+
/// <summary>
/// The admin's title.
/// </summary>
return HasFlag(AdminFlags.Admin);
}
+ /// <summary>
+ /// Check if this admin can be hidden and see other hidden admins.
+ /// </summary>
+ public bool CanStealth()
+ {
+ return HasFlag(AdminFlags.Stealth);
+ }
+
public bool CanAdminReloadPrototypes()
{
return HasFlag(AdminFlags.Host);
/// </summary>
MassBan = 1 << 15,
+ /// <summary>
+ /// Allows you to remain hidden from adminwho except to other admins with this flag.
+ /// </summary>
+ Stealth = 1 << 16,
+
/// <summary>
/// Dangerous host permissions like scsi.
/// </summary>
-using Content.Shared.GameTicking;
+using Content.Shared.Administration;
+using Content.Shared.GameTicking;
using Content.Shared.Mind;
using Robust.Shared.Network;
/// </summary>
public bool ExplicitlyDeadminned { get; set; }
+ /// <summary>
+ /// If true, the admin will not show up in adminwho except to admins with the <see cref="AdminFlags.Stealth"/> flag.
+ /// </summary>
+ public bool Stealthed { get; set; }
+
public ContentPlayerData(NetUserId userId, string name)
{
UserId = userId;
Name = name;
}
-}
\ No newline at end of file
+}
--- /dev/null
+cmd-stealthmin-desc = Toggle whether others can see you in adminwho.
+cmd-stealthmin-help = Usage: stealthmin\nUse stealthmin to toggle whether you appear in the output of the adminwho command.
+cmd-stealthmin-no-console = You cannot use this command from the server console.
admin-manager-admin-permissions-updated-message = Your admin permission have been updated.
admin-manager-admin-logout-message = Admin logout: {$name}
admin-manager-admin-login-message = Admin login: {$name}
-admin-manager-admin-data-host-title = Host
\ No newline at end of file
+admin-manager-admin-data-host-title = Host
+admin-manager-stealthed-message = You are now a hidden admin.
+admin-manager-unstealthed-message = You are no longer hidden.
+admin-manager-self-enable-stealth = {$stealthAdminName} is now hidden.
+admin-manager-self-disable-stealth = {$exStealthAdminName} is no longer hidden.