Delta-v/Content.Client/_DV/Curation/UI/Cwoink/CwoinkControl.xaml.cs

245 lines
8.0 KiB
C#

using System.Linq;
using System.Text;
using Content.Client._DV.UserInterfaces.Systems.Cwoink;
using Content.Client.Administration.Managers;
using Content.Client.Administration.UI.CustomControls;
using Content.Shared.Administration;
using Content.Shared.CCVar;
using Robust.Client.AutoGenerated;
using Robust.Client.Console;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Configuration;
using Robust.Shared.Network;
using Robust.Shared.Utility;
namespace Content.Client._DV.Curation.UI.Cwoink;
/// <summary>
/// This window connects to a CwoinkSystem channel. CwoinkSystem manages the rest.
/// </summary>
[GenerateTypedNameReferences]
public sealed partial class CwoinkControl : Control
{
[Dependency] private readonly IClientAdminManager _adminManager = default!;
[Dependency] private readonly IClientConsoleHost _console = default!;
[Dependency] private readonly IUserInterfaceManager _ui = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
public CuratorCHelpUIHandler CHelpHelper = default!;
private PlayerInfo? _currentPlayer;
public CwoinkControl()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
var newPlayerThreshold = 0;
_cfg.OnValueChanged(CCVars.NewPlayerThreshold, (val) => { newPlayerThreshold = val; }, true);
var uiController = _ui.GetUIController<CHelpUIController>();
if (uiController.UIHelper is not CuratorCHelpUIHandler helper)
return;
CHelpHelper = helper;
_adminManager.AdminStatusUpdated += UpdateButtons;
UpdateButtons();
CuratorOnly.OnToggled += args => PlaySound.Disabled = args.Pressed;
ChannelSelector.OnSelectionChanged += sel =>
{
_currentPlayer = sel;
SwitchToChannel(sel?.SessionId);
ChannelSelector.PlayerListContainer.DirtyList();
};
ChannelSelector.OverrideText += (info, text) =>
{
var sb = new StringBuilder();
if (info.Connected)
sb.Append(info.ActiveThisRound ? '⚫' : '◐');
else
sb.Append(info.ActiveThisRound ? '⭘' : '·');
sb.Append(' ');
if (CHelpHelper.TryGetChannel(info.SessionId, out var panel) && panel.Unread > 0)
{
if (panel.Unread < 11)
sb.Append(new Rune('➀' + (panel.Unread - 1)));
else
sb.Append(new Rune(0x2639)); // ☹
sb.Append(' ');
}
// Mark antagonists with symbol
if (info.Antag && info.ActiveThisRound)
sb.Append(new Rune(0x1F5E1)); // 🗡
// Mark new players with symbol
if (IsNewPlayer(info))
sb.Append(new Rune(0x23F2)); // ⏲
sb.Append('"');
sb.Append(text);
sb.Append('"');
return sb.ToString();
};
// <summary>
// Returns true if the player's overall playtime is under the set threshold
// </summary>
bool IsNewPlayer(PlayerInfo info)
{
// Don't show every disconnected player as new, don't show 0-minute players as new if threshold is
if (newPlayerThreshold <= 0 || info.OverallPlaytime is null && !info.Connected)
return false;
return info.OverallPlaytime is null
|| info.OverallPlaytime < TimeSpan.FromMinutes(newPlayerThreshold);
}
ChannelSelector.Comparison = (a, b) =>
{
var ach = CHelpHelper.EnsurePanel(a.SessionId);
var bch = CHelpHelper.EnsurePanel(b.SessionId);
// Pinned players first
if (a.IsPinned != b.IsPinned)
return a.IsPinned ? -1 : 1;
// Then, any chat with unread messages.
var aUnread = ach.Unread > 0;
var bUnread = bch.Unread > 0;
if (aUnread != bUnread)
return aUnread ? -1 : 1;
// Then, any chat with recent messages from the current round
var aRecent = a.ActiveThisRound && ach.LastMessage != DateTime.MinValue;
var bRecent = b.ActiveThisRound && bch.LastMessage != DateTime.MinValue;
if (aRecent != bRecent)
return aRecent ? -1 : 1;
// Sort by connection status. Disconnected players will be last.
if (a.Connected != b.Connected)
return a.Connected ? -1 : 1;
// Sort disconnected players by participation in the round
if (a.ActiveThisRound != b.ActiveThisRound)
return a.ActiveThisRound ? -1 : 1;
// Sort connected players by whether they have joined the round, then by New Player status, then by Antag status
if (a.Connected && b.Connected)
{
var aNewPlayer = IsNewPlayer(a);
var bNewPlayer = IsNewPlayer(b);
// Within both the joined group and lobby group, new players will be grouped and listed first
if (aNewPlayer != bNewPlayer)
return aNewPlayer ? -1 : 1;
// Within all four previous groups, antagonists will be listed first.
if (a.Antag != b.Antag)
return a.Antag ? -1 : 1;
}
// Finally, sort by the most recent message.
return bch.LastMessage.CompareTo(ach.LastMessage);
};
ViewVariables.OnPressed += _ =>
{
if (_currentPlayer is not null)
_console.ExecuteCommand($"vv \"{_currentPlayer.NetEntity}\"");
};
Follow.OnPressed += _ =>
{
if (_currentPlayer is not null)
_console.ExecuteCommand($"follow \"{_currentPlayer.NetEntity}\"");
};
Respawn.OnPressed += _ =>
{
if (_currentPlayer is not null)
_console.ExecuteCommand($"respawn \"{_currentPlayer.Username}\"");
};
PopOut.OnPressed += _ =>
{
uiController.PopOut();
};
}
public void OnCwoink()
{
ChannelSelector.PopulateList();
}
public void SelectChannel(NetUserId channel)
{
if (!Extensions.TryFirstOrDefault(ChannelSelector.PlayerInfo, i => i.SessionId == channel, out var info))
return;
// clear filter if we're trying to select a channel for a player that isn't currently filtered
// i.e. through the message verb.
var data = new PlayerListData(info);
if (!Enumerable.Contains(ChannelSelector.PlayerListContainer.Data, data))
{
ChannelSelector.StopFiltering();
}
ChannelSelector.PopulateList();
ChannelSelector.PlayerListContainer.Select(data);
}
public void UpdateButtons()
{
var disabled = _currentPlayer == null;
ViewVariables.Visible = _adminManager.CanCommand("vv");
ViewVariables.Disabled = !ViewVariables.Visible || disabled;
Respawn.Visible = _adminManager.CanCommand("respawn");
Respawn.Disabled = !Respawn.Visible || disabled;
Follow.Visible = _adminManager.CanCommand("follow");
Follow.Disabled = !Follow.Visible || disabled;
}
private void SwitchToChannel(NetUserId? ch)
{
UpdateButtons();
CHelpHelper.HideAllPanels();
if (ch != null)
{
var panel = CHelpHelper.EnsurePanel(ch.Value);
panel.Visible = true;
}
}
public void PopulateList()
{
// Maintain existing pin statuses
var pinnedPlayers = Enumerable.Where<PlayerInfo>(ChannelSelector.PlayerInfo, 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();
}
}