Ready Indicator in the lobby (#1771)

* Ready Indicator in the lobby

* Use SessionID instead of Name

* Don't show ready state when game is already running

* Make Ready List not selectable

* -Remove disconnected sessions from Ready
-Fix showing ReadyStatus when staying in lobby
This commit is contained in:
Exp
2020-08-18 14:52:59 +02:00
committed by GitHub
parent 6fb2a335b1
commit 5de57d6cd2
6 changed files with 157 additions and 5 deletions

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using Content.Client.Interfaces;
using Content.Client.State;
using Content.Client.UserInterface;
@@ -8,6 +9,7 @@ using Robust.Client.Interfaces.Graphics;
using Robust.Client.Interfaces.State;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC;
using Robust.Shared.Network;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
@@ -27,9 +29,11 @@ namespace Content.Client.GameTicking
[ViewVariables] public string ServerInfoBlob { get; private set; }
[ViewVariables] public DateTime StartTime { get; private set; }
[ViewVariables] public bool Paused { get; private set; }
[ViewVariables] public Dictionary<NetSessionId, bool> Ready { get; private set; }
public event Action InfoBlobUpdated;
public event Action LobbyStatusUpdated;
public event Action LobbyReadyUpdated;
public void Initialize()
{
@@ -40,12 +44,14 @@ namespace Content.Client.GameTicking
_netManager.RegisterNetMessage<MsgTickerLobbyStatus>(nameof(MsgTickerLobbyStatus), LobbyStatus);
_netManager.RegisterNetMessage<MsgTickerLobbyInfo>(nameof(MsgTickerLobbyInfo), LobbyInfo);
_netManager.RegisterNetMessage<MsgTickerLobbyCountdown>(nameof(MsgTickerLobbyCountdown), LobbyCountdown);
_netManager.RegisterNetMessage<MsgTickerLobbyReady>(nameof(MsgTickerLobbyReady), LobbyReady);
_netManager.RegisterNetMessage<MsgRoundEndMessage>(nameof(MsgRoundEndMessage), RoundEnd);
_netManager.RegisterNetMessage<MsgRequestWindowAttention>(nameof(MsgRequestWindowAttention), msg =>
{
IoCManager.Resolve<IClyde>().RequestWindowAttention();
});
Ready = new Dictionary<NetSessionId, bool>();
_initialized = true;
}
@@ -62,6 +68,8 @@ namespace Content.Client.GameTicking
IsGameStarted = message.IsRoundStarted;
AreWeReady = message.YouAreReady;
Paused = message.Paused;
if (IsGameStarted)
Ready.Clear();
LobbyStatusUpdated?.Invoke();
}
@@ -84,9 +92,18 @@ namespace Content.Client.GameTicking
Paused = message.Paused;
}
private void LobbyReady(MsgTickerLobbyReady message)
{
// Merge the Dictionaries
foreach (var p in message.PlayerReady)
{
Ready[p.Key] = p.Value;
}
LobbyReadyUpdated?.Invoke();
}
private void RoundEnd(MsgRoundEndMessage message)
{
//This is not ideal at all, but I don't see an immediately better fit anywhere else.
var roundEnd = new RoundEndSummaryWindow(message.GamemodeTitle, message.RoundDuration, message.AllPlayersEndInfo);

View File

@@ -1,4 +1,6 @@
using Robust.Shared.Network;
using System;
using System.Collections.Generic;
namespace Content.Client.Interfaces
{
@@ -9,9 +11,11 @@ namespace Content.Client.Interfaces
bool AreWeReady { get; }
DateTime StartTime { get; }
bool Paused { get; }
Dictionary<NetSessionId, bool> Ready { get; }
void Initialize();
event Action InfoBlobUpdated;
event Action LobbyStatusUpdated;
event Action LobbyReadyUpdated;
}
}

View File

@@ -99,7 +99,8 @@ namespace Content.Client.State
_playerManager.PlayerListUpdated += PlayerManagerOnPlayerListUpdated;
_clientGameTicker.InfoBlobUpdated += UpdateLobbyUi;
_clientGameTicker.LobbyStatusUpdated += UpdateLobbyUi;
_clientGameTicker.LobbyStatusUpdated += LobbyStatusUpdated;
_clientGameTicker.LobbyReadyUpdated += LobbyReadyUpdated;
}
public override void Shutdown()
@@ -149,7 +150,25 @@ namespace Content.Client.State
_lobby.StartTime.Text = Loc.GetString("Round Starts In: {0}", text);
}
private void PlayerManagerOnPlayerListUpdated(object sender, EventArgs e) => UpdatePlayerList();
private void PlayerManagerOnPlayerListUpdated(object sender, EventArgs e)
{
// Remove disconnected sessions from the Ready Dict
foreach (var p in _clientGameTicker.Ready)
{
if (!_playerManager.SessionsDict.TryGetValue(p.Key, out _))
{
_clientGameTicker.Ready.Remove(p.Key);
}
}
UpdatePlayerList();
}
private void LobbyReadyUpdated() => UpdatePlayerList();
private void LobbyStatusUpdated()
{
UpdatePlayerList();
UpdateLobbyUi();
}
private void UpdateLobbyUi()
{
@@ -178,10 +197,24 @@ namespace Content.Client.State
private void UpdatePlayerList()
{
_lobby.OnlinePlayerItemList.Clear();
_lobby.PlayerReadyList.Clear();
foreach (var session in _playerManager.Sessions.OrderBy(s => s.Name))
{
_lobby.OnlinePlayerItemList.AddItem(session.Name);
var readyState = "";
// Don't show ready state if we're ingame
if (!_clientGameTicker.IsGameStarted)
{
var ready = false;
if (session.SessionId == _playerManager.LocalPlayer.SessionId)
ready = _clientGameTicker.AreWeReady;
else
_clientGameTicker.Ready.TryGetValue(session.SessionId, out ready);
readyState = ready ? Loc.GetString("Ready") : Loc.GetString("Not Ready");
}
_lobby.PlayerReadyList.AddItem(readyState, null, false);
}
}
@@ -193,6 +226,7 @@ namespace Content.Client.State
}
_console.ProcessCommand($"toggleready {newReady}");
UpdatePlayerList();
}
}
}

View File

@@ -1,4 +1,4 @@
using Content.Client.Chat;
using Content.Client.Chat;
using Content.Client.Interfaces;
using Content.Client.UserInterface.Stylesheets;
using Content.Client.Utility;
@@ -22,6 +22,7 @@ namespace Content.Client.UserInterface
public Button LeaveButton { get; }
public ChatBox Chat { get; }
public ItemList OnlinePlayerItemList { get; }
public ItemList PlayerReadyList { get; }
public ServerInfo ServerInfo { get; }
public LobbyCharacterPreviewPanel CharacterPreview { get; }
@@ -219,7 +220,25 @@ namespace Content.Client.UserInterface
MarginBottomOverride = 3,
Children =
{
(OnlinePlayerItemList = new ItemList())
new HBoxContainer
{
SizeFlagsHorizontal = SizeFlags.FillExpand,
CustomMinimumSize = (50,50),
Children =
{
(OnlinePlayerItemList = new ItemList
{
SizeFlagsVertical = SizeFlags.FillExpand,
SizeFlagsHorizontal = SizeFlags.FillExpand,
}),
(PlayerReadyList = new ItemList
{
SizeFlagsVertical = SizeFlags.FillExpand,
SizeFlagsHorizontal = SizeFlags.FillExpand,
SizeFlagsStretchRatio = 0.2f
}),
}
}
}
},
new NanoHeading

View File

@@ -49,6 +49,7 @@ using Robust.Shared.Localization;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Network;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Timing;
@@ -138,6 +139,7 @@ namespace Content.Server.GameTicking
_netManager.RegisterNetMessage<MsgTickerLobbyStatus>(nameof(MsgTickerLobbyStatus));
_netManager.RegisterNetMessage<MsgTickerLobbyInfo>(nameof(MsgTickerLobbyInfo));
_netManager.RegisterNetMessage<MsgTickerLobbyCountdown>(nameof(MsgTickerLobbyCountdown));
_netManager.RegisterNetMessage<MsgTickerLobbyReady>(nameof(MsgTickerLobbyReady));
_netManager.RegisterNetMessage<MsgRoundEndMessage>(nameof(MsgRoundEndMessage));
_netManager.RegisterNetMessage<MsgRequestWindowAttention>(nameof(MsgRequestWindowAttention));
@@ -381,6 +383,7 @@ namespace Content.Server.GameTicking
_playersInLobby[player] = ready;
_netManager.ServerSendMessage(_getStatusMsg(player), player.ConnectedClient);
_netManager.ServerSendToAll(GetReadySingle(player, ready));
}
public T AddGameRule<T>() where T : GameRule, new()
@@ -871,6 +874,7 @@ namespace Content.Server.GameTicking
_netManager.ServerSendMessage(_netManager.CreateNetMessage<MsgTickerJoinLobby>(), session.ConnectedClient);
_netManager.ServerSendMessage(_getStatusMsg(session), session.ConnectedClient);
_netManager.ServerSendMessage(GetInfoMsg(), session.ConnectedClient);
_netManager.ServerSendMessage(GetReadyStatus(), session.ConnectedClient);
}
private void _playerJoinGame(IPlayerSession session)
@@ -882,6 +886,26 @@ namespace Content.Server.GameTicking
_netManager.ServerSendMessage(_netManager.CreateNetMessage<MsgTickerJoinGame>(), session.ConnectedClient);
}
private MsgTickerLobbyReady GetReadyStatus()
{
var msg = _netManager.CreateNetMessage<MsgTickerLobbyReady>();
msg.PlayerReady = new Dictionary<NetSessionId, bool>();
foreach (var player in _playersInLobby.Keys)
{
_playersInLobby.TryGetValue(player, out var ready);
msg.PlayerReady.Add(player.SessionId, ready);
}
return msg;
}
private MsgTickerLobbyReady GetReadySingle(IPlayerSession player, bool ready)
{
var msg = _netManager.CreateNetMessage<MsgTickerLobbyReady>();
msg.PlayerReady = new Dictionary<NetSessionId, bool>();
msg.PlayerReady.Add(player.SessionId, ready);
return msg;
}
private MsgTickerLobbyStatus _getStatusMsg(IPlayerSession session)
{
_playersInLobby.TryGetValue(session, out var ready);

View File

@@ -1,7 +1,10 @@
using System;
using System.Collections.Generic;
using System.IO;
using Lidgren.Network;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.Interfaces.Serialization;
using Robust.Shared.IoC;
using Robust.Shared.Network;
namespace Content.Shared
@@ -152,6 +155,57 @@ namespace Content.Shared
}
}
protected class MsgTickerLobbyReady : NetMessage
{
#region REQUIRED
public const MsgGroups GROUP = MsgGroups.Command;
public const string NAME = nameof(MsgTickerLobbyReady);
public MsgTickerLobbyReady(INetChannel channel) : base(NAME, GROUP) { }
#endregion
/// <summary>
/// The Players Ready (SessionID:ready)
/// </summary>
public Dictionary<NetSessionId, bool> PlayerReady { get; set; }
public override void ReadFromBuffer(NetIncomingMessage buffer)
{
PlayerReady = new Dictionary<NetSessionId, bool>();
var length = buffer.ReadInt32();
for (int i = 0; i < length; i++)
{
var serializer = IoCManager.Resolve<IRobustSerializer>();
var byteLength = buffer.ReadVariableInt32();
NetSessionId sessionID;
using (var stream = buffer.ReadAsStream(byteLength))
{
serializer.DeserializeDirect(stream, out sessionID);
}
var ready = buffer.ReadBoolean();
PlayerReady.Add(sessionID, ready);
}
}
public override void WriteToBuffer(NetOutgoingMessage buffer)
{
var serializer = IoCManager.Resolve<IRobustSerializer>();
buffer.Write(PlayerReady.Count);
foreach (var p in PlayerReady)
{
using (var stream = new MemoryStream())
{
serializer.SerializeDirect(stream, p.Key);
buffer.WriteVariableInt32((int) stream.Length);
stream.TryGetBuffer(out var segment);
buffer.Write(segment);
}
buffer.Write(p.Value);
}
}
}
public struct RoundEndPlayerInfo
{