PlayerListControl.xaml.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. using System.Linq;
  2. using Content.Client.Administration.Systems;
  3. using Content.Client.UserInterface.Controls;
  4. using Content.Client.Verbs.UI;
  5. using Content.Shared.Administration;
  6. using Robust.Client.AutoGenerated;
  7. using Robust.Client.GameObjects;
  8. using Robust.Client.Graphics;
  9. using Robust.Client.UserInterface;
  10. using Robust.Client.UserInterface.Controls;
  11. using Robust.Client.UserInterface.XAML;
  12. using Robust.Shared.Input;
  13. using Robust.Shared.Utility;
  14. namespace Content.Client.Administration.UI.CustomControls;
  15. [GenerateTypedNameReferences]
  16. public sealed partial class PlayerListControl : BoxContainer
  17. {
  18. private readonly AdminSystem _adminSystem;
  19. private readonly IEntityManager _entManager;
  20. private readonly IUserInterfaceManager _uiManager;
  21. private PlayerInfo? _selectedPlayer;
  22. private List<PlayerInfo> _playerList = new();
  23. private List<PlayerInfo> _sortedPlayerList = new();
  24. public Comparison<PlayerInfo>? Comparison;
  25. public Func<PlayerInfo, string, string>? OverrideText;
  26. public PlayerListControl()
  27. {
  28. _entManager = IoCManager.Resolve<IEntityManager>();
  29. _uiManager = IoCManager.Resolve<IUserInterfaceManager>();
  30. _adminSystem = _entManager.System<AdminSystem>();
  31. RobustXamlLoader.Load(this);
  32. // Fill the Option data
  33. PlayerListContainer.ItemPressed += PlayerListItemPressed;
  34. PlayerListContainer.ItemKeyBindDown += PlayerListItemKeyBindDown;
  35. PlayerListContainer.GenerateItem += GenerateButton;
  36. PlayerListContainer.NoItemSelected += PlayerListNoItemSelected;
  37. PopulateList(_adminSystem.PlayerList);
  38. FilterLineEdit.OnTextChanged += _ => FilterList();
  39. _adminSystem.PlayerListChanged += PopulateList;
  40. BackgroundPanel.PanelOverride = new StyleBoxFlat { BackgroundColor = new Color(32, 32, 40) };
  41. }
  42. public IReadOnlyList<PlayerInfo> PlayerInfo => _playerList;
  43. public event Action<PlayerInfo?>? OnSelectionChanged;
  44. private void PlayerListNoItemSelected()
  45. {
  46. _selectedPlayer = null;
  47. OnSelectionChanged?.Invoke(null);
  48. }
  49. private void PlayerListItemPressed(BaseButton.ButtonEventArgs? args, ListData? data)
  50. {
  51. if (args == null || data is not PlayerListData { Info: var selectedPlayer })
  52. return;
  53. if (selectedPlayer == _selectedPlayer)
  54. return;
  55. if (args.Event.Function != EngineKeyFunctions.UIClick)
  56. return;
  57. OnSelectionChanged?.Invoke(selectedPlayer);
  58. _selectedPlayer = selectedPlayer;
  59. // update label text. Only required if there is some override (e.g. unread bwoink count).
  60. if (OverrideText != null && args.Button.Children.FirstOrDefault()?.Children?.FirstOrDefault() is Label label)
  61. label.Text = GetText(selectedPlayer);
  62. }
  63. private void PlayerListItemKeyBindDown(GUIBoundKeyEventArgs? args, ListData? data)
  64. {
  65. if (args == null || data is not PlayerListData { Info: var selectedPlayer })
  66. return;
  67. if (args.Function != EngineKeyFunctions.UIRightClick || selectedPlayer.NetEntity == null)
  68. return;
  69. _uiManager.GetUIController<VerbMenuUIController>().OpenVerbMenu(selectedPlayer.NetEntity.Value, true);
  70. args.Handle();
  71. }
  72. public void StopFiltering()
  73. {
  74. FilterLineEdit.Text = string.Empty;
  75. }
  76. private void FilterList()
  77. {
  78. _sortedPlayerList.Clear();
  79. foreach (var info in _playerList)
  80. {
  81. var displayName = $"{info.CharacterName} ({info.Username})";
  82. if (info.IdentityName != info.CharacterName)
  83. displayName += $" [{info.IdentityName}]";
  84. if (!string.IsNullOrEmpty(FilterLineEdit.Text)
  85. && !displayName.ToLowerInvariant().Contains(FilterLineEdit.Text.Trim().ToLowerInvariant()))
  86. continue;
  87. _sortedPlayerList.Add(info);
  88. }
  89. if (Comparison != null)
  90. _sortedPlayerList.Sort((a, b) => Comparison(a, b));
  91. PlayerListContainer.PopulateList(_sortedPlayerList.Select(info => new PlayerListData(info)).ToList());
  92. if (_selectedPlayer != null)
  93. PlayerListContainer.Select(new PlayerListData(_selectedPlayer));
  94. }
  95. public void PopulateList(IReadOnlyList<PlayerInfo>? players = null)
  96. {
  97. // Maintain existing pin statuses
  98. var pinnedPlayers = _playerList.Where(p => p.IsPinned).ToDictionary(p => p.SessionId);
  99. players ??= _adminSystem.PlayerList;
  100. _playerList = players.ToList();
  101. // Restore pin statuses
  102. foreach (var player in _playerList)
  103. {
  104. if (pinnedPlayers.TryGetValue(player.SessionId, out var pinnedPlayer))
  105. {
  106. player.IsPinned = pinnedPlayer.IsPinned;
  107. }
  108. }
  109. if (_selectedPlayer != null && !_playerList.Contains(_selectedPlayer))
  110. _selectedPlayer = null;
  111. FilterList();
  112. }
  113. private string GetText(PlayerInfo info)
  114. {
  115. var text = $"{info.CharacterName} ({info.Username})";
  116. if (OverrideText != null)
  117. text = OverrideText.Invoke(info, text);
  118. return text;
  119. }
  120. private void GenerateButton(ListData data, ListContainerButton button)
  121. {
  122. if (data is not PlayerListData { Info: var info })
  123. return;
  124. var entry = new PlayerListEntry();
  125. entry.Setup(info, OverrideText);
  126. entry.OnPinStatusChanged += _ =>
  127. {
  128. FilterList();
  129. };
  130. button.AddChild(entry);
  131. button.AddStyleClass(ListContainer.StyleClassListContainerButton);
  132. }
  133. }
  134. public record PlayerListData(PlayerInfo Info) : ListData;