Implement a playerpanel (#30238)
* Basic structure for the player panel ui * Ensure basic functionality Player panel now receives and displays basic info * Make whitelistcommands accept user ids * Make PlayerPanel use GUIDs where possible * Add functionality to most playerpanel buttons * Implement remaining playerpanel features * Localize everything * Finish up * Put command arguments in quotes I am not sure if it's even possible to have something like a space in them considering they are guids and usernames but sure why not * Make playerpanel a verb * Add Logs button to player panel * Change Notesbutton text and make whitelistbutton a confirmtion button * Add freeze button that does not mute the player * Add sharedconnections counter to playerpanel * Make the playetime format clearer * Allow for copying of the a player's username * Do minor cleanup * Rearrange buttons * Fix unfreeze button not updating * Fix wrong localisation text * "Fix" the same role ban counting multiple times The way rolebans are stored is horrible. As such if you ban someone from a departmenrt or something role bans are individually placed for every role. The only way I found to distinguish them is the bantime. This is horrible but I do not want to rewrite how all the bans are stored right now. * Add Delete and Rejuvenate buttons to player panel By popular demand * Marginally improve ui * Add logs * review update * Fix verb * Fix double notes --------- Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
<ui:FancyWindow
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
xmlns:ui="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
Title="{Loc ban-panel-title}" MinSize="300 300">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Name="PlayerName"/>
|
||||
<Button Name="UsernameCopyButton" Text="{Loc player-panel-copy-username}"/>
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Name="Whitelisted"/>
|
||||
<controls:ConfirmButton Name="WhitelistToggle" Text="{Loc 'player-panel-false'}" Visible="False"></controls:ConfirmButton>
|
||||
</BoxContainer>
|
||||
<Label Name="Playtime"/>
|
||||
<Label Name="Notes"/>
|
||||
<Label Name="Bans"/>
|
||||
<Label Name="RoleBans"/>
|
||||
<Label Name="SharedConnections"/>
|
||||
|
||||
<BoxContainer Align="Center">
|
||||
<GridContainer Rows="5">
|
||||
<Button Name="NotesButton" Text="{Loc player-panel-show-notes}" SetWidth="136" Disabled="True"/>
|
||||
<Button Name="AhelpButton" Text="{Loc player-panel-help}" Disabled="True"/>
|
||||
<Button Name="FreezeButton" Text = "{Loc player-panel-freeze}" Disabled="True"/>
|
||||
<controls:ConfirmButton Name="KickButton" Text="{Loc player-panel-kick}" Disabled="True"/>
|
||||
<controls:ConfirmButton Name="DeleteButton" Text="{Loc player-panel-delete}" Disabled="True"/>
|
||||
<Button Name="ShowBansButton" Text="{Loc player-panel-show-bans}" SetWidth="136" Disabled="True"/>
|
||||
<Button Name="LogsButton" Text="{Loc player-panel-logs}" Disabled="True"/>
|
||||
<Button Name="FreezeAndMuteToggleButton" Text="{Loc player-panel-freeze-and-mute}" Disabled="True"/>
|
||||
<Button Name="BanButton" Text="{Loc player-panel-ban}" Disabled="True"/>
|
||||
<controls:ConfirmButton Name="RejuvenateButton" Text="{Loc player-panel-rejuvenate}" Disabled="True"/>
|
||||
</GridContainer>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</ui:FancyWindow>
|
||||
132
Content.Client/Administration/UI/PlayerPanel/PlayerPanel.xaml.cs
Normal file
132
Content.Client/Administration/UI/PlayerPanel/PlayerPanel.xaml.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
using Content.Client.Administration.Managers;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.Administration.UI.PlayerPanel;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class PlayerPanel : FancyWindow
|
||||
{
|
||||
private readonly IClientAdminManager _adminManager;
|
||||
|
||||
public event Action<string>? OnUsernameCopy;
|
||||
public event Action<NetUserId?>? OnOpenNotes;
|
||||
public event Action<NetUserId?>? OnOpenBans;
|
||||
public event Action<NetUserId?>? OnAhelp;
|
||||
public event Action<string?>? OnKick;
|
||||
public event Action<NetUserId?>? OnOpenBanPanel;
|
||||
public event Action<NetUserId?, bool>? OnWhitelistToggle;
|
||||
public event Action? OnFreezeAndMuteToggle;
|
||||
public event Action? OnFreeze;
|
||||
public event Action? OnLogs;
|
||||
public event Action? OnDelete;
|
||||
public event Action? OnRejuvenate;
|
||||
|
||||
public NetUserId? TargetPlayer;
|
||||
public string? TargetUsername;
|
||||
private bool _isWhitelisted;
|
||||
|
||||
public PlayerPanel(IClientAdminManager adminManager)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
_adminManager = adminManager;
|
||||
|
||||
UsernameCopyButton.OnPressed += _ => OnUsernameCopy?.Invoke(PlayerName.Text ?? "");
|
||||
BanButton.OnPressed += _ => OnOpenBanPanel?.Invoke(TargetPlayer);
|
||||
KickButton.OnPressed += _ => OnKick?.Invoke(TargetUsername);
|
||||
NotesButton.OnPressed += _ => OnOpenNotes?.Invoke(TargetPlayer);
|
||||
ShowBansButton.OnPressed += _ => OnOpenBans?.Invoke(TargetPlayer);
|
||||
AhelpButton.OnPressed += _ => OnAhelp?.Invoke(TargetPlayer);
|
||||
WhitelistToggle.OnPressed += _ =>
|
||||
{
|
||||
OnWhitelistToggle?.Invoke(TargetPlayer, _isWhitelisted);
|
||||
SetWhitelisted(!_isWhitelisted);
|
||||
};
|
||||
FreezeButton.OnPressed += _ => OnFreeze?.Invoke();
|
||||
FreezeAndMuteToggleButton.OnPressed += _ => OnFreezeAndMuteToggle?.Invoke();
|
||||
LogsButton.OnPressed += _ => OnLogs?.Invoke();
|
||||
DeleteButton.OnPressed += _ => OnDelete?.Invoke();
|
||||
RejuvenateButton.OnPressed += _ => OnRejuvenate?.Invoke();
|
||||
}
|
||||
|
||||
public void SetUsername(string player)
|
||||
{
|
||||
Title = Loc.GetString("player-panel-title", ("player", player));
|
||||
PlayerName.Text = Loc.GetString("player-panel-username", ("player", player));
|
||||
}
|
||||
|
||||
public void SetWhitelisted(bool? whitelisted)
|
||||
{
|
||||
if (whitelisted == null)
|
||||
{
|
||||
Whitelisted.Text = null;
|
||||
WhitelistToggle.Visible = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Whitelisted.Text = Loc.GetString("player-panel-whitelisted");
|
||||
WhitelistToggle.Text = whitelisted.Value.ToString();
|
||||
WhitelistToggle.Visible = true;
|
||||
_isWhitelisted = whitelisted.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetBans(int? totalBans, int? totalRoleBans)
|
||||
{
|
||||
// If one value exists then so should the other.
|
||||
DebugTools.Assert(totalBans.HasValue && totalRoleBans.HasValue || totalBans == null && totalRoleBans == null);
|
||||
|
||||
Bans.Text = totalBans != null ? Loc.GetString("player-panel-bans", ("totalBans", totalBans)) : null;
|
||||
|
||||
RoleBans.Text = totalRoleBans != null ? Loc.GetString("player-panel-rolebans", ("totalRoleBans", totalRoleBans)) : null;
|
||||
}
|
||||
|
||||
public void SetNotes(int? totalNotes)
|
||||
{
|
||||
Notes.Text = totalNotes != null ? Loc.GetString("player-panel-notes", ("totalNotes", totalNotes)) : null;
|
||||
}
|
||||
|
||||
public void SetSharedConnections(int sharedConnections)
|
||||
{
|
||||
SharedConnections.Text = Loc.GetString("player-panel-shared-connections", ("sharedConnections", sharedConnections));
|
||||
}
|
||||
|
||||
public void SetPlaytime(TimeSpan playtime)
|
||||
{
|
||||
Playtime.Text = Loc.GetString("player-panel-playtime",
|
||||
("days", playtime.Days),
|
||||
("hours", playtime.Hours % 24),
|
||||
("minutes", playtime.Minutes % (24 * 60)));
|
||||
}
|
||||
|
||||
public void SetFrozen(bool canFreeze, bool frozen)
|
||||
{
|
||||
FreezeAndMuteToggleButton.Disabled = !canFreeze;
|
||||
FreezeButton.Disabled = !canFreeze || frozen;
|
||||
|
||||
FreezeAndMuteToggleButton.Text = Loc.GetString(!frozen ? "player-panel-freeze-and-mute" : "player-panel-unfreeze");
|
||||
}
|
||||
|
||||
public void SetAhelp(bool canAhelp)
|
||||
{
|
||||
AhelpButton.Disabled = !canAhelp;
|
||||
}
|
||||
|
||||
public void SetButtons()
|
||||
{
|
||||
BanButton.Disabled = !_adminManager.CanCommand("banpanel");
|
||||
KickButton.Disabled = !_adminManager.CanCommand("kick");
|
||||
NotesButton.Disabled = !_adminManager.CanCommand("adminnotes");
|
||||
ShowBansButton.Disabled = !_adminManager.CanCommand("banlist");
|
||||
WhitelistToggle.Disabled =
|
||||
!(_adminManager.CanCommand("addwhitelist") && _adminManager.CanCommand("removewhitelist"));
|
||||
LogsButton.Disabled = !_adminManager.CanCommand("adminlogs");
|
||||
RejuvenateButton.Disabled = !_adminManager.HasFlag(AdminFlags.Debug);
|
||||
DeleteButton.Disabled = !_adminManager.HasFlag(AdminFlags.Debug);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
using Content.Client.Administration.Managers;
|
||||
using Content.Client.Eui;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.Eui;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.Console;
|
||||
using Robust.Client.UserInterface;
|
||||
|
||||
namespace Content.Client.Administration.UI.PlayerPanel;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class PlayerPanelEui : BaseEui
|
||||
{
|
||||
[Dependency] private readonly IClientConsoleHost _console = default!;
|
||||
[Dependency] private readonly IClientAdminManager _admin = default!;
|
||||
[Dependency] private readonly IClipboardManager _clipboard = default!;
|
||||
|
||||
private PlayerPanel PlayerPanel { get; }
|
||||
|
||||
public PlayerPanelEui()
|
||||
{
|
||||
PlayerPanel = new PlayerPanel(_admin);
|
||||
|
||||
PlayerPanel.OnUsernameCopy += username => _clipboard.SetText(username);
|
||||
PlayerPanel.OnOpenNotes += id => _console.ExecuteCommand($"adminnotes \"{id}\"");
|
||||
// Kick command does not support GUIDs
|
||||
PlayerPanel.OnKick += username => _console.ExecuteCommand($"kick \"{username}\"");
|
||||
PlayerPanel.OnOpenBanPanel += id => _console.ExecuteCommand($"banpanel \"{id}\"");
|
||||
PlayerPanel.OnOpenBans += id => _console.ExecuteCommand($"banlist \"{id}\"");
|
||||
PlayerPanel.OnAhelp += id => _console.ExecuteCommand($"openahelp \"{id}\"");
|
||||
PlayerPanel.OnWhitelistToggle += (id, whitelisted) =>
|
||||
{
|
||||
_console.ExecuteCommand(whitelisted ? $"whitelistremove \"{id}\"" : $"whitelistadd \"{id}\"");
|
||||
};
|
||||
|
||||
PlayerPanel.OnFreezeAndMuteToggle += () => SendMessage(new PlayerPanelFreezeMessage(true));
|
||||
PlayerPanel.OnFreeze += () => SendMessage(new PlayerPanelFreezeMessage());
|
||||
PlayerPanel.OnLogs += () => SendMessage(new PlayerPanelLogsMessage());
|
||||
PlayerPanel.OnRejuvenate += () => SendMessage(new PlayerPanelRejuvenationMessage());
|
||||
PlayerPanel.OnDelete+= () => SendMessage(new PlayerPanelDeleteMessage());
|
||||
|
||||
PlayerPanel.OnClose += () => SendMessage(new CloseEuiMessage());
|
||||
}
|
||||
|
||||
public override void Opened()
|
||||
{
|
||||
PlayerPanel.OpenCentered();
|
||||
}
|
||||
|
||||
public override void Closed()
|
||||
{
|
||||
PlayerPanel.Close();
|
||||
}
|
||||
|
||||
public override void HandleState(EuiStateBase state)
|
||||
{
|
||||
if (state is not PlayerPanelEuiState s)
|
||||
return;
|
||||
|
||||
PlayerPanel.TargetPlayer = s.Guid;
|
||||
PlayerPanel.TargetUsername = s.Username;
|
||||
PlayerPanel.SetUsername(s.Username);
|
||||
PlayerPanel.SetPlaytime(s.Playtime);
|
||||
PlayerPanel.SetBans(s.TotalBans, s.TotalRoleBans);
|
||||
PlayerPanel.SetNotes(s.TotalNotes);
|
||||
PlayerPanel.SetWhitelisted(s.Whitelisted);
|
||||
PlayerPanel.SetSharedConnections(s.SharedConnections);
|
||||
PlayerPanel.SetFrozen(s.CanFreeze, s.Frozen);
|
||||
PlayerPanel.SetAhelp(s.CanAhelp);
|
||||
PlayerPanel.SetButtons();
|
||||
}
|
||||
}
|
||||
56
Content.Server/Administration/Commands/PlayerPanelCommand.cs
Normal file
56
Content.Server/Administration/Commands/PlayerPanelCommand.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System.Linq;
|
||||
using Content.Server.EUI;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
namespace Content.Server.Administration.Commands;
|
||||
|
||||
[AdminCommand(AdminFlags.Admin)]
|
||||
public sealed class PlayerPanelCommand : LocalizedCommands
|
||||
{
|
||||
[Dependency] private readonly IPlayerLocator _locator = default!;
|
||||
[Dependency] private readonly EuiManager _euis = default!;
|
||||
[Dependency] private readonly IPlayerManager _players = default!;
|
||||
|
||||
public override string Command => "playerpanel";
|
||||
|
||||
public override async void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (shell.Player is not { } admin)
|
||||
{
|
||||
shell.WriteError(Loc.GetString("cmd-playerpanel-server"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Length != 1)
|
||||
{
|
||||
shell.WriteError(Loc.GetString("cmd-playerpanel-invalid-arguments"));
|
||||
return;
|
||||
}
|
||||
|
||||
var queriedPlayer = await _locator.LookupIdByNameOrIdAsync(args[0]);
|
||||
|
||||
if (queriedPlayer == null)
|
||||
{
|
||||
shell.WriteError(Loc.GetString("cmd-playerpanel-invalid-player"));
|
||||
return;
|
||||
}
|
||||
|
||||
var ui = new PlayerPanelEui(queriedPlayer);
|
||||
_euis.OpenEui(ui, admin);
|
||||
ui.SetPlayerState();
|
||||
}
|
||||
|
||||
public override CompletionResult GetCompletion(IConsoleShell shell, string[] args)
|
||||
{
|
||||
if (args.Length == 1)
|
||||
{
|
||||
var options = _players.Sessions.OrderBy(c => c.Name).Select(c => c.Name).ToArray();
|
||||
|
||||
return CompletionResult.FromHintOptions(options, LocalizationManager.GetString("cmd-playerpanel-completion"));
|
||||
}
|
||||
|
||||
return CompletionResult.Empty;
|
||||
}
|
||||
}
|
||||
210
Content.Server/Administration/PlayerPanelEui.cs
Normal file
210
Content.Server/Administration/PlayerPanelEui.cs
Normal file
@@ -0,0 +1,210 @@
|
||||
using System.Linq;
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Administration.Managers;
|
||||
using Content.Server.Administration.Notes;
|
||||
using Content.Server.Administration.Systems;
|
||||
using Content.Server.Database;
|
||||
using Content.Server.EUI;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Eui;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Server.Administration;
|
||||
|
||||
public sealed class PlayerPanelEui : BaseEui
|
||||
{
|
||||
[Dependency] private readonly IAdminManager _admins = default!;
|
||||
[Dependency] private readonly IServerDbManager _db = default!;
|
||||
[Dependency] private readonly IAdminNotesManager _notesMan = default!;
|
||||
[Dependency] private readonly IEntityManager _entity = default!;
|
||||
[Dependency] private readonly IPlayerManager _player = default!;
|
||||
[Dependency] private readonly EuiManager _eui = default!;
|
||||
[Dependency] private readonly IAdminLogManager _adminLog = default!;
|
||||
|
||||
private readonly LocatedPlayerData _targetPlayer;
|
||||
private int? _notes;
|
||||
private int? _bans;
|
||||
private int? _roleBans;
|
||||
private int _sharedConnections;
|
||||
private bool? _whitelisted;
|
||||
private TimeSpan _playtime;
|
||||
private bool _frozen;
|
||||
private bool _canFreeze;
|
||||
private bool _canAhelp;
|
||||
|
||||
public PlayerPanelEui(LocatedPlayerData player)
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
_targetPlayer = player;
|
||||
}
|
||||
|
||||
public override void Opened()
|
||||
{
|
||||
base.Opened();
|
||||
_admins.OnPermsChanged += OnPermsChanged;
|
||||
}
|
||||
|
||||
public override void Closed()
|
||||
{
|
||||
base.Closed();
|
||||
_admins.OnPermsChanged -= OnPermsChanged;
|
||||
}
|
||||
|
||||
public override EuiStateBase GetNewState()
|
||||
{
|
||||
return new PlayerPanelEuiState(_targetPlayer.UserId,
|
||||
_targetPlayer.Username,
|
||||
_playtime,
|
||||
_notes,
|
||||
_bans,
|
||||
_roleBans,
|
||||
_sharedConnections,
|
||||
_whitelisted,
|
||||
_canFreeze,
|
||||
_frozen,
|
||||
_canAhelp);
|
||||
}
|
||||
|
||||
private void OnPermsChanged(AdminPermsChangedEventArgs args)
|
||||
{
|
||||
if (args.Player != Player)
|
||||
return;
|
||||
|
||||
SetPlayerState();
|
||||
}
|
||||
|
||||
public override void HandleMessage(EuiMessageBase msg)
|
||||
{
|
||||
base.HandleMessage(msg);
|
||||
|
||||
ICommonSession? session;
|
||||
|
||||
switch (msg)
|
||||
{
|
||||
case PlayerPanelFreezeMessage freezeMsg:
|
||||
if (!_admins.IsAdmin(Player) ||
|
||||
!_entity.TrySystem<AdminFrozenSystem>(out var frozenSystem) ||
|
||||
!_player.TryGetSessionById(_targetPlayer.UserId, out session) ||
|
||||
session.AttachedEntity == null)
|
||||
return;
|
||||
|
||||
if (_entity.HasComponent<AdminFrozenComponent>(session.AttachedEntity))
|
||||
{
|
||||
_adminLog.Add(LogType.Action,$"{Player:actor} unfroze {_entity.ToPrettyString(session.AttachedEntity):subject}");
|
||||
_entity.RemoveComponent<AdminFrozenComponent>(session.AttachedEntity.Value);
|
||||
SetPlayerState();
|
||||
return;
|
||||
}
|
||||
|
||||
if (freezeMsg.Mute)
|
||||
{
|
||||
_adminLog.Add(LogType.Action,$"{Player:actor} froze and muted {_entity.ToPrettyString(session.AttachedEntity):subject}");
|
||||
frozenSystem.FreezeAndMute(session.AttachedEntity.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
_adminLog.Add(LogType.Action,$"{Player:actor} froze {_entity.ToPrettyString(session.AttachedEntity):subject}");
|
||||
_entity.EnsureComponent<AdminFrozenComponent>(session.AttachedEntity.Value);
|
||||
}
|
||||
SetPlayerState();
|
||||
break;
|
||||
|
||||
case PlayerPanelLogsMessage:
|
||||
if (!_admins.HasAdminFlag(Player, AdminFlags.Logs))
|
||||
return;
|
||||
|
||||
_adminLog.Add(LogType.Action, $"{Player:actor} opened logs on {_targetPlayer.Username:subject}");
|
||||
var ui = new AdminLogsEui();
|
||||
_eui.OpenEui(ui, Player);
|
||||
ui.SetLogFilter(search: _targetPlayer.Username);
|
||||
break;
|
||||
case PlayerPanelDeleteMessage:
|
||||
case PlayerPanelRejuvenationMessage:
|
||||
if (!_admins.HasAdminFlag(Player, AdminFlags.Debug) ||
|
||||
!_player.TryGetSessionById(_targetPlayer.UserId, out session) ||
|
||||
session.AttachedEntity == null)
|
||||
return;
|
||||
|
||||
if (msg is PlayerPanelRejuvenationMessage)
|
||||
{
|
||||
_adminLog.Add(LogType.Action,$"{Player:actor} rejuvenated {_entity.ToPrettyString(session.AttachedEntity):subject}");
|
||||
if (!_entity.TrySystem<RejuvenateSystem>(out var rejuvenate))
|
||||
return;
|
||||
|
||||
rejuvenate.PerformRejuvenate(session.AttachedEntity.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
_adminLog.Add(LogType.Action,$"{Player:actor} deleted {_entity.ToPrettyString(session.AttachedEntity):subject}");
|
||||
_entity.DeleteEntity(session.AttachedEntity);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public async void SetPlayerState()
|
||||
{
|
||||
if (!_admins.IsAdmin(Player))
|
||||
{
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
_playtime = (await _db.GetPlayTimes(_targetPlayer.UserId))
|
||||
.Where(p => p.Tracker == "Overall")
|
||||
.Select(p => p.TimeSpent)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (_notesMan.CanView(Player))
|
||||
{
|
||||
_notes = (await _notesMan.GetAllAdminRemarks(_targetPlayer.UserId)).Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
_notes = null;
|
||||
}
|
||||
|
||||
_sharedConnections = _player.Sessions.Count(s => s.Channel.RemoteEndPoint.Address.Equals(_targetPlayer.LastAddress) && s.UserId != _targetPlayer.UserId);
|
||||
|
||||
// Apparently the Bans flag is also used for whitelists
|
||||
if (_admins.HasAdminFlag(Player, AdminFlags.Ban))
|
||||
{
|
||||
_whitelisted = await _db.GetWhitelistStatusAsync(_targetPlayer.UserId);
|
||||
// This won't get associated ip or hwid bans but they were not placed on this account anyways
|
||||
_bans = (await _db.GetServerBansAsync(null, _targetPlayer.UserId, null)).Count;
|
||||
// Unfortunately role bans for departments and stuff are issued individually. This means that a single role ban can have many individual role bans internally
|
||||
// The only way to distinguish whether a role ban is the same is to compare the ban time.
|
||||
// This is horrible and I would love to just erase the database and start from scratch instead but that's what I can do for now.
|
||||
_roleBans = (await _db.GetServerRoleBansAsync(null, _targetPlayer.UserId, null)).DistinctBy(rb => rb.BanTime).Count();
|
||||
}
|
||||
else
|
||||
{
|
||||
_whitelisted = null;
|
||||
_bans = null;
|
||||
_roleBans = null;
|
||||
}
|
||||
|
||||
if (_player.TryGetSessionById(_targetPlayer.UserId, out var session))
|
||||
{
|
||||
_canFreeze = session.AttachedEntity != null;
|
||||
_frozen = _entity.HasComponent<AdminFrozenComponent>(session.AttachedEntity);
|
||||
}
|
||||
else
|
||||
{
|
||||
_canFreeze = false;
|
||||
}
|
||||
|
||||
if (_admins.HasAdminFlag(Player, AdminFlags.Adminhelp))
|
||||
{
|
||||
_canAhelp = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_canAhelp = false;
|
||||
}
|
||||
|
||||
StateDirty();
|
||||
}
|
||||
}
|
||||
@@ -208,6 +208,15 @@ namespace Content.Server.Administration.Systems
|
||||
ConfirmationPopup = true,
|
||||
Impact = LogImpact.High,
|
||||
});
|
||||
|
||||
// PlayerPanel
|
||||
args.Verbs.Add(new Verb
|
||||
{
|
||||
Text = Loc.GetString("admin-player-actions-player-panel"),
|
||||
Category = VerbCategory.Admin,
|
||||
Act = () => _console.ExecuteCommand(player, $"playerpanel \"{targetActor.PlayerSession.UserId}\""),
|
||||
Impact = LogImpact.Low
|
||||
});
|
||||
}
|
||||
|
||||
// Freeze
|
||||
|
||||
@@ -27,7 +27,7 @@ public sealed class AddWhitelistCommand : LocalizedCommands
|
||||
var loc = IoCManager.Resolve<IPlayerLocator>();
|
||||
|
||||
var name = string.Join(' ', args).Trim();
|
||||
var data = await loc.LookupIdByNameAsync(name);
|
||||
var data = await loc.LookupIdByNameOrIdAsync(name);
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
@@ -76,7 +76,7 @@ public sealed class RemoveWhitelistCommand : LocalizedCommands
|
||||
var loc = IoCManager.Resolve<IPlayerLocator>();
|
||||
|
||||
var name = string.Join(' ', args).Trim();
|
||||
var data = await loc.LookupIdByNameAsync(name);
|
||||
var data = await loc.LookupIdByNameOrIdAsync(name);
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
|
||||
54
Content.Shared/Administration/PlayerPanelEuiState.cs
Normal file
54
Content.Shared/Administration/PlayerPanelEuiState.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using Content.Shared.Eui;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Serialization;
|
||||
using YamlDotNet.Serialization.Callbacks;
|
||||
|
||||
namespace Content.Shared.Administration;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class PlayerPanelEuiState(NetUserId guid,
|
||||
string username,
|
||||
TimeSpan playtime,
|
||||
int? totalNotes,
|
||||
int? totalBans,
|
||||
int? totalRoleBans,
|
||||
int sharedConnections,
|
||||
bool? whitelisted,
|
||||
bool canFreeze,
|
||||
bool frozen,
|
||||
bool canAhelp)
|
||||
: EuiStateBase
|
||||
{
|
||||
public readonly NetUserId Guid = guid;
|
||||
public readonly string Username = username;
|
||||
public readonly TimeSpan Playtime = playtime;
|
||||
public readonly int? TotalNotes = totalNotes;
|
||||
public readonly int? TotalBans = totalBans;
|
||||
public readonly int? TotalRoleBans = totalRoleBans;
|
||||
public readonly int SharedConnections = sharedConnections;
|
||||
public readonly bool? Whitelisted = whitelisted;
|
||||
public readonly bool CanFreeze = canFreeze;
|
||||
public readonly bool Frozen = frozen;
|
||||
public readonly bool CanAhelp = canAhelp;
|
||||
}
|
||||
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class PlayerPanelFreezeMessage : EuiMessageBase
|
||||
{
|
||||
public readonly bool Mute;
|
||||
|
||||
public PlayerPanelFreezeMessage(bool mute = false)
|
||||
{
|
||||
Mute = mute;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class PlayerPanelLogsMessage : EuiMessageBase;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class PlayerPanelDeleteMessage : EuiMessageBase;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class PlayerPanelRejuvenationMessage: EuiMessageBase;
|
||||
@@ -7,6 +7,7 @@ admin-player-actions-ahelp = AHelp
|
||||
admin-player-actions-respawn = Respawn
|
||||
admin-player-actions-spawn = Spawn here
|
||||
admin-player-spawn-failed = Failed to find valid coordinates
|
||||
admin-player-actions-player-panel = Open Player Panel
|
||||
|
||||
admin-player-actions-clone = Clone
|
||||
admin-player-actions-follow = Follow
|
||||
|
||||
22
Resources/Locale/en-US/administration/ui/player-panel.ftl
Normal file
22
Resources/Locale/en-US/administration/ui/player-panel.ftl
Normal file
@@ -0,0 +1,22 @@
|
||||
player-panel-title = information for {$player}
|
||||
player-panel-username = Username: {$player}
|
||||
player-panel-whitelisted = Whitelisted:
|
||||
player-panel-bans = Total Bans: {$totalBans}
|
||||
player-panel-rolebans = Total Role Bans: {$totalRoleBans}
|
||||
player-panel-notes = Total Notes: {$totalNotes}
|
||||
player-panel-playtime = Total Playtime: {$days}d:{$hours}h:{$minutes}m
|
||||
player-panel-shared-connections = Shared Connections: {$sharedConnections}
|
||||
|
||||
player-panel-copy-username = Copy
|
||||
player-panel-show-notes = Notes
|
||||
player-panel-show-bans = Show Bans
|
||||
player-panel-help = Ahelp
|
||||
player-panel-freeze-and-mute = Freeze & Mute
|
||||
player-panel-freeze = Freeze
|
||||
player-panel-unfreeze = Unfreeze
|
||||
player-panel-kick = Kick
|
||||
player-panel-ban = Ban
|
||||
player-panel-logs = Logs
|
||||
player-panel-delete = Delete
|
||||
player-panel-rejuvenate = Rejuvenate
|
||||
player-panel-false = False
|
||||
@@ -11,14 +11,14 @@ whitelist-playercount-invalid = {$min ->
|
||||
whitelist-not-whitelisted-rp = You are not whitelisted. To become whitelisted, visit our Discord (which can be found at https://spacestation14.io) and check the #rp-whitelist channel.
|
||||
|
||||
cmd-whitelistadd-desc = Adds the player with the given username to the server whitelist.
|
||||
cmd-whitelistadd-help = Usage: whitelistadd <username>
|
||||
cmd-whitelistadd-help = Usage: whitelistadd <username or User ID>
|
||||
cmd-whitelistadd-existing = {$username} is already on the whitelist!
|
||||
cmd-whitelistadd-added = {$username} added to the whitelist
|
||||
cmd-whitelistadd-not-found = Unable to find '{$username}'
|
||||
cmd-whitelistadd-arg-player = [player]
|
||||
|
||||
cmd-whitelistremove-desc = Removes the player with the given username from the server whitelist.
|
||||
cmd-whitelistremove-help = Usage: whitelistremove <username>
|
||||
cmd-whitelistremove-help = Usage: whitelistremove <username or User ID>
|
||||
cmd-whitelistremove-existing = {$username} is not on the whitelist!
|
||||
cmd-whitelistremove-removed = {$username} removed from the whitelist
|
||||
cmd-whitelistremove-not-found = Unable to find '{$username}'
|
||||
|
||||
7
Resources/Locale/en-US/info/playerpanel.ftl
Normal file
7
Resources/Locale/en-US/info/playerpanel.ftl
Normal file
@@ -0,0 +1,7 @@
|
||||
cmd-playerpanel-desc = Displays general information and actions for a player
|
||||
cmd-playerpanel-help = Usage: playerpanel <name or user ID>
|
||||
|
||||
cmd-playerpanel-server = This command cannot be run from the server
|
||||
cmd-playerpanel-invalid-arguments = Invalid amount of arguments
|
||||
cmd-playerpanel-invalid-player = Player not found
|
||||
cmd-playerpanel-completion = <PlayerIndex>
|
||||
Reference in New Issue
Block a user