mirror of
https://github.com/space-syndicate/space-station-14.git
synced 2026-10-09 18:31:17 +03:00
* Store last player whose mind was in container * Send last player who controlled the entity's session ID along with other quick info * No more spam * Display last player info if there is no active player on entity * Better looking separator * Better looking separator but I didnt forget to ctrl s this time * newline * Address reviews * cleaning * Tiny tweaks --------- Co-authored-by: ScarKy0 <scarky0@onet.eu> Co-authored-by: Connor Huffine <chuffine@gmail.com>
253 lines
8.8 KiB
C#
253 lines
8.8 KiB
C#
using System.Linq;
|
|
using Content.Client.Administration.Systems;
|
|
using Content.Client.Stylesheets;
|
|
using Content.Shared.Administration;
|
|
using Robust.Client.UserInterface;
|
|
using Robust.Client.UserInterface.Controls;
|
|
using Robust.Shared.Console;
|
|
using Robust.Shared.Prototypes;
|
|
using Robust.Shared.RichText;
|
|
using Robust.Shared.Utility;
|
|
|
|
namespace Content.Client.Administration;
|
|
|
|
// Server-validated, AnyCommand is acceptable here.
|
|
[AnyCommand]
|
|
internal sealed partial class AdminQuickInfoCommand : LocalizedEntityCommands
|
|
{
|
|
[Dependency] private AdminQuickInfoSystem _quickInfo = null!;
|
|
|
|
public override string Command => QuickInfoShared.CommandName;
|
|
|
|
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
if (args.Length != 1)
|
|
return;
|
|
|
|
var idsArg = args[0].Split(',');
|
|
var ids = new NetEntity[idsArg.Length];
|
|
for (var i = 0; i < ids.Length; i++)
|
|
{
|
|
if (!NetEntity.TryParse(idsArg[i], out ids[i]))
|
|
return;
|
|
}
|
|
|
|
_quickInfo.OpenPopupFor(ids);
|
|
}
|
|
}
|
|
|
|
internal sealed partial class AdminQuickInfoSystem : EntitySystem
|
|
{
|
|
[Dependency] private AdminSystem _adminSystem = null!;
|
|
|
|
public event Action<QuickInfoShared.SingleEntityInfo>? EntityResponseReceived;
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
|
|
SubscribeNetworkEvent<QuickInfoShared.Response>(HandleInfoResponse);
|
|
}
|
|
|
|
private void HandleInfoResponse(QuickInfoShared.Response ev)
|
|
{
|
|
foreach (var singleEntityInfo in ev.Entities)
|
|
{
|
|
EntityResponseReceived?.Invoke(singleEntityInfo);
|
|
}
|
|
}
|
|
|
|
public void OpenPopupFor(NetEntity[] entities)
|
|
{
|
|
var vBox = new VBox() { SeparationOverride = 6 };;
|
|
var popup = new Popup
|
|
{
|
|
Children =
|
|
{
|
|
new PanelContainer
|
|
{
|
|
StyleClasses = { StyleClass.TooltipPanel },
|
|
Children =
|
|
{
|
|
vBox,
|
|
},
|
|
},
|
|
},
|
|
};
|
|
var first = true;
|
|
foreach (var entity in entities)
|
|
{
|
|
if (!first)
|
|
{
|
|
vBox.AddChild(new PanelContainer
|
|
{
|
|
StyleClasses = { StyleClass.LowDivider },
|
|
HorizontalExpand = true,
|
|
});
|
|
first = false;
|
|
}
|
|
|
|
var playerInfo = _adminSystem.PlayerList.FirstOrDefault(p => p.NetEntity == entity);
|
|
var control = new InfoControl(this, entity, playerInfo);
|
|
popup.OnPopupHide += () => control.Unsubscribe();
|
|
vBox.AddChild(control);
|
|
}
|
|
|
|
popup.OpenAtMouse();
|
|
|
|
RaiseNetworkEvent(new QuickInfoShared.Request { Entities = entities });
|
|
}
|
|
|
|
private sealed class InfoControl : Control
|
|
{
|
|
private readonly AdminQuickInfoSystem _system;
|
|
private readonly NetEntity _entity;
|
|
private readonly bool _activeControl;
|
|
private PlayerInfo? _playerInfo;
|
|
private QuickInfoShared.SingleEntityInfo? _response;
|
|
|
|
private readonly RichTextLabel _contents = new();
|
|
|
|
private ILocalizationManager Loc => _system.Loc;
|
|
private AdminSystem Admin => _system._adminSystem;
|
|
|
|
public InfoControl(AdminQuickInfoSystem system, NetEntity entity, PlayerInfo? playerInfo)
|
|
{
|
|
_system = system;
|
|
_entity = entity;
|
|
_playerInfo = playerInfo;
|
|
_activeControl = (playerInfo != null);
|
|
AddChild(_contents);
|
|
|
|
system.EntityResponseReceived += OnEntityResponseReceived;
|
|
Rebuild();
|
|
}
|
|
|
|
private void OnEntityResponseReceived(QuickInfoShared.SingleEntityInfo ev)
|
|
{
|
|
// Yes I know this is O(n^2)
|
|
// Realistically, n is going to be 30 (default cvar limit) or less. Not a big deal.
|
|
if (ev.Entity != _entity)
|
|
return;
|
|
|
|
_response = ev;
|
|
_playerInfo ??= Admin.PlayerList.FirstOrDefault(p => p.SessionId == ev.LastPlayer);
|
|
Rebuild();
|
|
}
|
|
|
|
public void Unsubscribe()
|
|
{
|
|
// This, too, is O(n^2). I think.
|
|
_system.EntityResponseReceived -= OnEntityResponseReceived;
|
|
}
|
|
|
|
private void Rebuild()
|
|
{
|
|
var sb = new FormattedStringBuilder();
|
|
if (!_activeControl)
|
|
{
|
|
sb.AppendMarkupLine(Loc.GetString("admin-quick-info-inactive"));
|
|
}
|
|
|
|
if (_playerInfo != null)
|
|
{
|
|
sb.AppendMarkupLine(Loc.GetString("admin-quick-info-username",
|
|
("username", _playerInfo.Username),
|
|
("playtime", _playerInfo.PlaytimeString)));
|
|
if (_playerInfo.CharacterName != _playerInfo.IdentityName)
|
|
{
|
|
sb.AppendMarkupLine(Loc.GetString("admin-quick-info-character-identity",
|
|
("character", _playerInfo.CharacterName),
|
|
("identity", _playerInfo.IdentityName)));
|
|
}
|
|
else
|
|
{
|
|
sb.AppendMarkupLine(Loc.GetString("admin-quick-info-character",
|
|
("character", _playerInfo.CharacterName)));
|
|
}
|
|
|
|
sb.AppendMarkupLine(Loc.GetString("admin-quick-info-job", ("job", _playerInfo.StartingJob)));
|
|
|
|
if (_playerInfo.RoleProto is { } roleId && _system.ProtoMan.Resolve(roleId, out var role))
|
|
{
|
|
var roleColor = role.Color.ToHex();
|
|
var symbol = _playerInfo.Antag ? role.Symbol : "";
|
|
|
|
var roleTypeString = Loc.GetString(role.Name);
|
|
var roleSubtypeString = _playerInfo.Subtype is { } subtype ? Loc.GetString(subtype) : null;
|
|
|
|
var roleString = roleSubtypeString != null
|
|
? Loc.GetString("admin-quick-info-role-type-subtype",
|
|
("color", roleColor),
|
|
("symbol", symbol),
|
|
("type", roleTypeString),
|
|
("subtype", roleSubtypeString))
|
|
: Loc.GetString("admin-quick-info-role-type",
|
|
("color", roleColor),
|
|
("symbol", symbol),
|
|
("type", roleTypeString));
|
|
sb.AppendMarkupLine(roleString);
|
|
}
|
|
else
|
|
{
|
|
sb.AppendMarkupLine(Loc.GetString("admin-quick-info-no-role"));
|
|
}
|
|
}
|
|
|
|
if (_response == null)
|
|
{
|
|
sb.AppendMarkupLine(Loc.GetString("admin-quick-info-loading", ("entity", _entity)));
|
|
}
|
|
else
|
|
{
|
|
if (!_response.Exists)
|
|
{
|
|
sb.AppendMarkupLine(Loc.GetString("admin-quick-info-entity-missing", ("entity", _entity)));
|
|
}
|
|
else
|
|
{
|
|
sb.AppendMarkupLine(Loc.GetString("admin-quick-info-entity",
|
|
("entity", _entity),
|
|
("name", _response.Name),
|
|
("prototype", _response.Prototype ?? Loc.GetString("admin-quick-info-no-prototype"))));
|
|
}
|
|
}
|
|
|
|
// Link line at the bottom
|
|
if (_playerInfo != null)
|
|
{
|
|
// Player panel
|
|
sb.MakeCommandLinkTag(
|
|
Loc.GetString("admin-quick-link-playerpanel"),
|
|
CommandParsing.EscapeCommand(
|
|
AdminCommandSyntax.NamePlayerPanel,
|
|
_playerInfo.SessionId.ToString()),
|
|
Loc.GetString("admin-quick-link-playerpanel-tooltip"));
|
|
sb.AppendText(" ");
|
|
|
|
// Send Message
|
|
sb.MakeCommandLinkTag(
|
|
Loc.GetString("admin-quick-link-message"),
|
|
CommandParsing.EscapeCommand(
|
|
AdminCommandSyntax.NameOpenAdminHelp,
|
|
_playerInfo.SessionId.ToString()),
|
|
Loc.GetString("admin-quick-link-message-tooltip"));
|
|
sb.AppendText(" ");
|
|
}
|
|
|
|
if (_response is not { Exists: false })
|
|
{
|
|
// Jump/follow
|
|
sb.MakeCommandLinkTag(
|
|
Loc.GetString("admin-quick-link-follow"),
|
|
CommandParsing.EscapeCommand(
|
|
AdminCommandSyntax.NameFollow,
|
|
_entity.ToString()),
|
|
Loc.GetString("admin-quick-link-follow-tooltip"));
|
|
sb.AppendText(" ");
|
|
}
|
|
|
|
_contents.SetMessage(FormattedMessage.FromMarkupOrThrow(sb.ToString().Trim()), tagsAllowed: null);
|
|
}
|
|
}
|
|
}
|