Skip to content

Commit

Permalink
Merge branch 'master' into quirks
Browse files Browse the repository at this point in the history
  • Loading branch information
FaDeOkno authored Aug 8, 2024
2 parents bc4caba + c297112 commit a2a171a
Show file tree
Hide file tree
Showing 1,337 changed files with 96,708 additions and 87,225 deletions.
6 changes: 5 additions & 1 deletion .github/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,13 @@
- changed-files:
- any-glob-to-any-file: '**/*.xaml*'

"Changes: Shaders":
- changed-files:
- any-glob-to-any-file: '**/*.swsl'

"Changes: Localization":
- changed-files:
- any-glob-to-any-file: 'Resources/Locale/**/*.ftl'
- any-glob-to-any-file: '**/*.ftl'

"No C#":
- changed-files:
Expand Down
41 changes: 37 additions & 4 deletions Content.Client/Administration/UI/Bwoink/BwoinkControl.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ public BwoinkControl()
var ach = AHelpHelper.EnsurePanel(a.SessionId);
var bch = AHelpHelper.EnsurePanel(b.SessionId);

// Pinned players first
if (a.IsPinned != b.IsPinned)
return a.IsPinned ? -1 : 1;

// First, sort by unread. Any chat with unread messages appears first. We just sort based on unread
// status, not number of unread messages, so that more recent unread messages take priority.
var aUnread = ach.Unread > 0;
Expand All @@ -99,15 +103,31 @@ public BwoinkControl()
if (a.Connected != b.Connected)
return a.Connected ? -1 : 1;

// Next, group by whether or not the players have participated in this round.
// The ahelp window shows all players that have connected since server restart, this groups them all towards the bottom.
if (a.ActiveThisRound != b.ActiveThisRound)
return a.ActiveThisRound ? -1 : 1;
// Sort connected players by New Player status, then by Antag status
if (a.Connected && b.Connected)
{
var aNewPlayer = a.OverallPlaytime <= TimeSpan.FromMinutes(_cfg.GetCVar(CCVars.NewPlayerThreshold));
var bNewPlayer = b.OverallPlaytime <= TimeSpan.FromMinutes(_cfg.GetCVar(CCVars.NewPlayerThreshold));

if (aNewPlayer != bNewPlayer)
return aNewPlayer ? -1 : 1;

if (a.Antag != b.Antag)
return a.Antag ? -1 : 1;
}

// Sort disconnected players by participation in the round
if (!a.Connected && !b.Connected)
{
if (a.ActiveThisRound != b.ActiveThisRound)
return a.ActiveThisRound ? -1 : 1;
}

// Finally, sort by the most recent message.
return bch.LastMessage.CompareTo(ach.LastMessage);
};


Bans.OnPressed += _ =>
{
if (_currentPlayer is not null)
Expand Down Expand Up @@ -253,7 +273,20 @@ private void SwitchToChannel(NetUserId? ch)

public void PopulateList()
{
// Maintain existing pin statuses
var pinnedPlayers = ChannelSelector.PlayerInfo.Where(p => p.IsPinned).ToDictionary(p => p.SessionId);

ChannelSelector.PopulateList();

// Restore pin statuses
foreach (var player in ChannelSelector.PlayerInfo)
{
if (pinnedPlayers.TryGetValue(player.SessionId, out var pinnedPlayer))
{
player.IsPinned = pinnedPlayer.IsPinned;
}
}

UpdateButtons();
}
}
Expand Down
6 changes: 5 additions & 1 deletion Content.Client/Administration/UI/Bwoink/BwoinkWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ public BwoinkWindow()
}
};

OnOpen += () => Bwoink.PopulateList();
OnOpen += () =>
{
Bwoink.ChannelSelector.StopFiltering();
Bwoink.PopulateList();
};
}
}
}
236 changes: 124 additions & 112 deletions Content.Client/Administration/UI/CustomControls/PlayerListControl.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,154 +4,166 @@
using Content.Client.Verbs.UI;
using Content.Shared.Administration;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Input;
using Robust.Shared.Utility;

namespace Content.Client.Administration.UI.CustomControls
namespace Content.Client.Administration.UI.CustomControls;

[GenerateTypedNameReferences]
public sealed partial class PlayerListControl : BoxContainer
{
[GenerateTypedNameReferences]
public sealed partial class PlayerListControl : BoxContainer
{
private readonly AdminSystem _adminSystem;
private readonly AdminSystem _adminSystem;

private List<PlayerInfo> _playerList = new();
private readonly List<PlayerInfo> _sortedPlayerList = new();
private readonly IEntityManager _entManager;
private readonly IUserInterfaceManager _uiManager;

public event Action<PlayerInfo?>? OnSelectionChanged;
public IReadOnlyList<PlayerInfo> PlayerInfo => _playerList;
private PlayerInfo? _selectedPlayer;

public Func<PlayerInfo, string, string>? OverrideText;
public Comparison<PlayerInfo>? Comparison;
private List<PlayerInfo> _playerList = new();
private List<PlayerInfo> _sortedPlayerList = new();

private IEntityManager _entManager;
private IUserInterfaceManager _uiManager;
public Comparison<PlayerInfo>? Comparison;
public Func<PlayerInfo, string, string>? OverrideText;

private PlayerInfo? _selectedPlayer;
public PlayerListControl()
{
_entManager = IoCManager.Resolve<IEntityManager>();
_uiManager = IoCManager.Resolve<IUserInterfaceManager>();
_adminSystem = _entManager.System<AdminSystem>();
RobustXamlLoader.Load(this);
// Fill the Option data
PlayerListContainer.ItemPressed += PlayerListItemPressed;
PlayerListContainer.ItemKeyBindDown += PlayerListItemKeyBindDown;
PlayerListContainer.GenerateItem += GenerateButton;
PlayerListContainer.NoItemSelected += PlayerListNoItemSelected;
PopulateList(_adminSystem.PlayerList);
FilterLineEdit.OnTextChanged += _ => FilterList();
_adminSystem.PlayerListChanged += PopulateList;
BackgroundPanel.PanelOverride = new StyleBoxFlat { BackgroundColor = new Color(32, 32, 40) };
}

public PlayerListControl()
{
_entManager = IoCManager.Resolve<IEntityManager>();
_uiManager = IoCManager.Resolve<IUserInterfaceManager>();
_adminSystem = _entManager.System<AdminSystem>();
RobustXamlLoader.Load(this);
// Fill the Option data
PlayerListContainer.ItemPressed += PlayerListItemPressed;
PlayerListContainer.ItemKeyBindDown += PlayerListItemKeyBindDown;
PlayerListContainer.GenerateItem += GenerateButton;
PlayerListContainer.NoItemSelected += PlayerListNoItemSelected;
PopulateList(_adminSystem.PlayerList);
FilterLineEdit.OnTextChanged += _ => FilterList();
_adminSystem.PlayerListChanged += PopulateList;
BackgroundPanel.PanelOverride = new StyleBoxFlat {BackgroundColor = new Color(32, 32, 40)};
}
public IReadOnlyList<PlayerInfo> PlayerInfo => _playerList;

private void PlayerListNoItemSelected()
{
_selectedPlayer = null;
OnSelectionChanged?.Invoke(null);
}
public event Action<PlayerInfo?>? OnSelectionChanged;

private void PlayerListItemPressed(BaseButton.ButtonEventArgs? args, ListData? data)
{
if (args == null || data is not PlayerListData {Info: var selectedPlayer})
return;
private void PlayerListNoItemSelected()
{
_selectedPlayer = null;
OnSelectionChanged?.Invoke(null);
}

if (selectedPlayer == _selectedPlayer)
return;
private void PlayerListItemPressed(BaseButton.ButtonEventArgs? args, ListData? data)
{
if (args == null || data is not PlayerListData { Info: var selectedPlayer })
return;

if (args.Event.Function != EngineKeyFunctions.UIClick)
return;
if (selectedPlayer == _selectedPlayer)
return;

OnSelectionChanged?.Invoke(selectedPlayer);
_selectedPlayer = selectedPlayer;
if (args.Event.Function != EngineKeyFunctions.UIClick)
return;

// update label text. Only required if there is some override (e.g. unread bwoink count).
if (OverrideText != null && args.Button.Children.FirstOrDefault()?.Children?.FirstOrDefault() is Label label)
label.Text = GetText(selectedPlayer);
}
OnSelectionChanged?.Invoke(selectedPlayer);
_selectedPlayer = selectedPlayer;

private void PlayerListItemKeyBindDown(GUIBoundKeyEventArgs? args, ListData? data)
{
if (args == null || data is not PlayerListData { Info: var selectedPlayer })
return;
// update label text. Only required if there is some override (e.g. unread bwoink count).
if (OverrideText != null && args.Button.Children.FirstOrDefault()?.Children?.FirstOrDefault() is Label label)
label.Text = GetText(selectedPlayer);
}

if (args.Function != EngineKeyFunctions.UIRightClick || selectedPlayer.NetEntity == null)
return;
private void PlayerListItemKeyBindDown(GUIBoundKeyEventArgs? args, ListData? data)
{
if (args == null || data is not PlayerListData { Info: var selectedPlayer })
return;

_uiManager.GetUIController<VerbMenuUIController>().OpenVerbMenu(selectedPlayer.NetEntity.Value, true);
args.Handle();
}
if (args.Function != EngineKeyFunctions.UIRightClick || selectedPlayer.NetEntity == null)
return;

_uiManager.GetUIController<VerbMenuUIController>().OpenVerbMenu(selectedPlayer.NetEntity.Value, true);
args.Handle();
}

public void StopFiltering()
{
FilterLineEdit.Text = string.Empty;
}

public void StopFiltering()
private void FilterList()
{
_sortedPlayerList.Clear();
foreach (var info in _playerList)
{
FilterLineEdit.Text = string.Empty;
var displayName = $"{info.CharacterName} ({info.Username})";
if (info.IdentityName != info.CharacterName)
displayName += $" [{info.IdentityName}]";
if (!string.IsNullOrEmpty(FilterLineEdit.Text)
&& !displayName.ToLowerInvariant().Contains(FilterLineEdit.Text.Trim().ToLowerInvariant()))
continue;
_sortedPlayerList.Add(info);
}

private void FilterList()
{
_sortedPlayerList.Clear();
foreach (var info in _playerList)
{
var displayName = $"{info.CharacterName} ({info.Username})";
if (info.IdentityName != info.CharacterName)
displayName += $" [{info.IdentityName}]";
if (!string.IsNullOrEmpty(FilterLineEdit.Text)
&& !displayName.ToLowerInvariant().Contains(FilterLineEdit.Text.Trim().ToLowerInvariant()))
continue;
_sortedPlayerList.Add(info);
}
if (Comparison != null)
_sortedPlayerList.Sort((a, b) => Comparison(a, b));

if (Comparison != null)
_sortedPlayerList.Sort((a, b) => Comparison(a, b));
PlayerListContainer.PopulateList(_sortedPlayerList.Select(info => new PlayerListData(info)).ToList());
if (_selectedPlayer != null)
PlayerListContainer.Select(new PlayerListData(_selectedPlayer));
}

PlayerListContainer.PopulateList(_sortedPlayerList.Select(info => new PlayerListData(info)).ToList());
if (_selectedPlayer != null)
PlayerListContainer.Select(new PlayerListData(_selectedPlayer));
}

public void PopulateList(IReadOnlyList<PlayerInfo>? players = null)
{
players ??= _adminSystem.PlayerList;
public void PopulateList(IReadOnlyList<PlayerInfo>? players = null)
{
// Maintain existing pin statuses
var pinnedPlayers = _playerList.Where(p => p.IsPinned).ToDictionary(p => p.SessionId);

_playerList = players.ToList();
if (_selectedPlayer != null && !_playerList.Contains(_selectedPlayer))
_selectedPlayer = null;
players ??= _adminSystem.PlayerList;

FilterList();
}
_playerList = players.ToList();

private string GetText(PlayerInfo info)
// Restore pin statuses
foreach (var player in _playerList)
{
var text = $"{info.CharacterName} ({info.Username})";
if (OverrideText != null)
text = OverrideText.Invoke(info, text);
return text;
if (pinnedPlayers.TryGetValue(player.SessionId, out var pinnedPlayer))
{
player.IsPinned = pinnedPlayer.IsPinned;
}
}

private void GenerateButton(ListData data, ListContainerButton button)
{
if (data is not PlayerListData { Info: var info })
return;
if (_selectedPlayer != null && !_playerList.Contains(_selectedPlayer))
_selectedPlayer = null;

button.AddChild(new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
Children =
{
new Label
{
ClipText = true,
Text = GetText(info)
}
}
});

button.AddStyleClass(ListContainer.StyleClassListContainerButton);
}
FilterList();
}


private string GetText(PlayerInfo info)
{
var text = $"{info.CharacterName} ({info.Username})";
if (OverrideText != null)
text = OverrideText.Invoke(info, text);
return text;
}

public record PlayerListData(PlayerInfo Info) : ListData;
private void GenerateButton(ListData data, ListContainerButton button)
{
if (data is not PlayerListData { Info: var info })
return;

var entry = new PlayerListEntry();
entry.Setup(info, OverrideText);
entry.OnPinStatusChanged += _ =>
{
FilterList();
};

button.AddChild(entry);
button.AddStyleClass(ListContainer.StyleClassListContainerButton);
}
}

public record PlayerListData(PlayerInfo Info) : ListData;
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<BoxContainer xmlns="https://spacestation14.io"
Orientation="Horizontal" HorizontalExpand="true">
<Label Name="PlayerEntryLabel" Text="" ClipText="True" HorizontalExpand="True" />
<TextureButton Name="PlayerEntryPinButton"
HorizontalAlignment="Right" />
</BoxContainer>
Loading

0 comments on commit a2a171a

Please sign in to comment.