RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
+ var newPlayerThreshold = 0;
+ _cfg.OnValueChanged(CCVars.NewPlayerThreshold, (val) => { newPlayerThreshold = val; }, true);
+
var uiController = _ui.GetUIController<AHelpUIController>();
if (uiController.UIHelper is not AdminAHelpUIHandler helper)
return;
var sb = new StringBuilder();
if (info.Connected)
- sb.Append('●');
+ sb.Append(info.ActiveThisRound ? '⚫' : '◐');
else
- sb.Append(info.ActiveThisRound ? 'â\97\8b' : '·');
+ sb.Append(info.ActiveThisRound ? 'â\98' : '·');
sb.Append(' ');
if (AHelpHelper.TryGetChannel(info.SessionId, out var panel) && panel.Unread > 0)
sb.Append(' ');
}
+ // Mark antagonists with symbol
if (info.Antag && info.ActiveThisRound)
sb.Append(new Rune(0x1F5E1)); // 🗡
- if (info.OverallPlaytime <= TimeSpan.FromMinutes(_cfg.GetCVar(CCVars.NewPlayerThreshold)))
+ // Mark new players with symbol
+ if (IsNewPlayer(info))
sb.Append(new Rune(0x23F2)); // ⏲
sb.AppendFormat("\"{0}\"", text);
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 = AHelpHelper.EnsurePanel(a.SessionId);
if (a.IsPinned != b.IsPinned)
return a.IsPinned ? -1 : 1;
- // First, sort by unread. Any chat with unread messages appears first.
+ // Then, any chat with unread messages.
var aUnread = ach.Unread > 0;
var bUnread = bch.Unread > 0;
if (aUnread != bUnread)
return aUnread ? -1 : 1;
- // Sort by recent messages during the current round.
+ // 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;
- // Next, sort by connection status. Any disconnected players are grouped towards the end.
+ // Sort by connection status. Disconnected players will be last.
if (a.Connected != b.Connected)
return a.Connected ? -1 : 1;
- // Sort connected players by New Player status, then by Antag status
+ // 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 = a.OverallPlaytime <= TimeSpan.FromMinutes(_cfg.GetCVar(CCVars.NewPlayerThreshold));
- var bNewPlayer = b.OverallPlaytime <= TimeSpan.FromMinutes(_cfg.GetCVar(CCVars.NewPlayerThreshold));
+ var aNewPlayer = IsNewPlayer(a);
+ var bNewPlayer = IsNewPlayer(b);
+
+ // Players who have joined the round will be listed before players in the lobby
+ if (a.ActiveThisRound != b.ActiveThisRound)
+ return a.ActiveThisRound ? -1 : 1;
+ // 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;
}
var entityName = string.Empty;
var identityName = string.Empty;
+ // Visible (identity) name can be different from real name
if (session?.AttachedEntity != null)
{
entityName = EntityManager.GetComponent<MetaDataComponent>(session.AttachedEntity.Value).EntityName;
var antag = false;
+ // Starting role, antagonist status and role type
RoleTypePrototype roleType = new();
var startingRole = string.Empty;
if (_minds.TryGetMind(session, out var mindId, out var mindComp))
startingRole = _jobs.MindTryGetJobName(mindId);
}
+ // Connection status and playtime
var connected = session != null && session.Status is SessionStatus.Connected or SessionStatus.InGame;
- TimeSpan? overallPlaytime = null;
+
+ // Start with the last available playtime data
+ var cachedInfo = GetCachedPlayerInfo(data.UserId);
+ var overallPlaytime = cachedInfo?.OverallPlaytime;
+ // Overwrite with current playtime data, unless it's null (such as if the player just disconnected)
if (session != null &&
_playTime.TryGetTrackerTimes(session, out var playTimes) &&
playTimes.TryGetValue(PlayTimeTrackingShared.TrackerOverall, out var playTime))