diff --git a/Robust.Client/Player/IPlayerManager.cs b/Robust.Client/Player/IPlayerManager.cs index 0edc3fb6f..eb046af69 100644 --- a/Robust.Client/Player/IPlayerManager.cs +++ b/Robust.Client/Player/IPlayerManager.cs @@ -1,13 +1,13 @@ -using System; +using System; using System.Collections.Generic; using Robust.Shared.GameStates; using Robust.Shared.Network; namespace Robust.Client.Player { - public interface IPlayerManager + public interface IPlayerManager : Shared.Players.ISharedPlayerManager { - IEnumerable Sessions { get; } + new IEnumerable Sessions { get; } IReadOnlyDictionary SessionsDict { get; } LocalPlayer? LocalPlayer { get; } @@ -17,8 +17,6 @@ namespace Robust.Client.Player /// event Action? LocalPlayerChanged; - int PlayerCount { get; } - int MaxPlayers { get; } event EventHandler PlayerListUpdated; void Initialize(); diff --git a/Robust.Client/Player/IPlayerSession.cs b/Robust.Client/Player/IPlayerSession.cs index 26476be3e..c0c94b642 100644 --- a/Robust.Client/Player/IPlayerSession.cs +++ b/Robust.Client/Player/IPlayerSession.cs @@ -1,20 +1,11 @@ -using Robust.Shared.Players; +using System; +using Robust.Shared.Players; namespace Robust.Client.Player { /// - /// Client side session of a player. + /// Client side session of a player. /// - public interface IPlayerSession : ICommonSession - { - /// - /// Current name of this player. - /// - new string Name { get; set; } - - /// - /// Current connection latency of this session from the server to their client. - /// - short Ping { get; set; } - } + [Obsolete("Use the base " + nameof(ICommonSession))] + public interface IPlayerSession : ICommonSession { } } diff --git a/Robust.Client/Player/PlayerManager.cs b/Robust.Client/Player/PlayerManager.cs index 0d899d231..5f6eec5cc 100644 --- a/Robust.Client/Player/PlayerManager.cs +++ b/Robust.Client/Player/PlayerManager.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Robust.Shared.Configuration; @@ -8,6 +8,7 @@ using Robust.Shared.GameStates; using Robust.Shared.IoC; using Robust.Shared.Network; using Robust.Shared.Network.Messages; +using Robust.Shared.Players; using Robust.Shared.Utility; using Robust.Shared.ViewVariables; @@ -30,6 +31,21 @@ namespace Robust.Client.Player /// private readonly Dictionary _sessions = new(); + /// + public IEnumerable NetworkedSessions + { + get + { + if (LocalPlayer is not null) + return new[] {LocalPlayer.Session}; + + return Enumerable.Empty(); + } + } + + /// + IEnumerable ISharedPlayerManager.Sessions => _sessions.Values; + /// public int PlayerCount => _sessions.Values.Count; @@ -52,9 +68,9 @@ namespace Robust.Client.Player private LocalPlayer? _localPlayer; public event Action? LocalPlayerChanged; - /// - [ViewVariables] public IEnumerable Sessions => _sessions.Values; + [ViewVariables] + IEnumerable IPlayerManager.Sessions => _sessions.Values; /// public IReadOnlyDictionary SessionsDict => _sessions; diff --git a/Robust.Client/Player/PlayerSession.cs b/Robust.Client/Player/PlayerSession.cs index 3ecd73e04..a2b9c4c38 100644 --- a/Robust.Client/Player/PlayerSession.cs +++ b/Robust.Client/Player/PlayerSession.cs @@ -1,25 +1,50 @@ -using Robust.Shared.Enums; +using Robust.Shared.Enums; using Robust.Shared.GameObjects; using Robust.Shared.Network; +using Robust.Shared.Players; namespace Robust.Client.Player { - internal sealed class PlayerSession : IPlayerSession { /// - public SessionStatus Status { get; set; } = SessionStatus.Connecting; + internal SessionStatus Status { get; set; } = SessionStatus.Connecting; + /// + SessionStatus ICommonSession.Status + { + get => this.Status; + set => this.Status = value; + } + + /// public IEntity? AttachedEntity { get; set; } + /// + public EntityUid? AttachedEntityUid => AttachedEntity?.Uid; + /// public NetUserId UserId { get; } /// - public string Name { get; set; } = ""; + internal string Name { get; set; } = ""; + + /// + string ICommonSession.Name + { + get => this.Name; + set => this.Name = value; + } /// - public short Ping { get; set; } + internal short Ping { get; set; } + + /// + short ICommonSession.Ping + { + get => this.Ping; + set => this.Ping = value; + } /// /// Creates an instance of a PlayerSession. diff --git a/Robust.Server/Console/ServerConsoleHost.cs b/Robust.Server/Console/ServerConsoleHost.cs index 0efc87d7e..35ffb8361 100644 --- a/Robust.Server/Console/ServerConsoleHost.cs +++ b/Robust.Server/Console/ServerConsoleHost.cs @@ -159,7 +159,7 @@ namespace Robust.Server.Console _systemConsole.Print(text + "\n"); } - private static string FormatPlayerString(IBaseSession? session) + private static string FormatPlayerString(ICommonSession? session) { return session != null ? $"{session.Name}" : "[HOST]"; } diff --git a/Robust.Server/Player/IPlayerManager.cs b/Robust.Server/Player/IPlayerManager.cs index 03845b9f2..209068537 100644 --- a/Robust.Server/Player/IPlayerManager.cs +++ b/Robust.Server/Player/IPlayerManager.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using Robust.Shared.Enums; @@ -13,21 +13,10 @@ namespace Robust.Server.Player /// /// Manages each players session when connected to the server. /// - public interface IPlayerManager + public interface IPlayerManager : Shared.Players.ISharedPlayerManager { - /// - /// Number of players currently connected to this server. - /// Fetching this is thread safe. - /// - int PlayerCount { get; } - BoundKeyMap KeyMap { get; } - /// - /// Maximum number of players that can connect to this server at one time. - /// - int MaxPlayers { get; } - /// /// Raised when the of a is changed. /// diff --git a/Robust.Server/Player/IPlayerSession.cs b/Robust.Server/Player/IPlayerSession.cs index 2080e29c9..8268f4ef5 100644 --- a/Robust.Server/Player/IPlayerSession.cs +++ b/Robust.Server/Player/IPlayerSession.cs @@ -1,4 +1,4 @@ -using System; +using System; using Robust.Shared.GameObjects; using Robust.Shared.Network; using Robust.Shared.Players; @@ -7,7 +7,6 @@ namespace Robust.Server.Player { public interface IPlayerSession : ICommonSession { - EntityUid? AttachedEntityUid { get; } INetChannel ConnectedClient { get; } DateTime ConnectedTime { get; } diff --git a/Robust.Server/Player/PlayerManager.cs b/Robust.Server/Player/PlayerManager.cs index 8940f4d06..171f551fd 100644 --- a/Robust.Server/Player/PlayerManager.cs +++ b/Robust.Server/Player/PlayerManager.cs @@ -14,6 +14,7 @@ using Robust.Shared.IoC; using Robust.Shared.Map; using Robust.Shared.Network; using Robust.Shared.Network.Messages; +using Robust.Shared.Players; using Robust.Shared.Reflection; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -53,6 +54,11 @@ namespace Robust.Server.Player [ViewVariables] private readonly Dictionary _userIdMap = new(); + /// + public IEnumerable NetworkedSessions => _sessions.Values; + + /// + public IEnumerable Sessions => _sessions.Values; /// [ViewVariables] diff --git a/Robust.Server/Player/PlayerSession.cs b/Robust.Server/Player/PlayerSession.cs index d0418a6cf..1ee929457 100644 --- a/Robust.Server/Player/PlayerSession.cs +++ b/Robust.Server/Player/PlayerSession.cs @@ -1,9 +1,10 @@ -using Robust.Shared.GameStates; +using Robust.Shared.GameStates; using Robust.Server.GameObjects; using System; using Robust.Shared.Enums; using Robust.Shared.GameObjects; using Robust.Shared.Network; +using Robust.Shared.Players; using Robust.Shared.ViewVariables; namespace Robust.Server.Player @@ -42,11 +43,32 @@ namespace Robust.Server.Player private SessionStatus _status = SessionStatus.Connecting; /// - public string Name { get; } + + [ViewVariables] + internal string Name { get; set; } /// + string ICommonSession.Name + { + get => this.Name; + set => this.Name = value; + } + [ViewVariables] - public SessionStatus Status + internal short Ping + { + get => ConnectedClient.Ping; + set => throw new NotSupportedException(); + } + + short ICommonSession.Ping + { + get => this.Ping; + set => this.Ping = value; + } + + [ViewVariables] + internal SessionStatus Status { get => _status; set @@ -62,6 +84,13 @@ namespace Robust.Server.Player } } + /// + SessionStatus ICommonSession.Status + { + get => this.Status; + set => this.Status = value; + } + /// public DateTime ConnectedTime { get; private set; } diff --git a/Robust.Shared/Player/Filter.cs b/Robust.Shared/Player/Filter.cs new file mode 100644 index 000000000..8dcb53754 --- /dev/null +++ b/Robust.Shared/Player/Filter.cs @@ -0,0 +1,190 @@ +using System; +using System.Collections.Generic; +using JetBrains.Annotations; +using Robust.Shared.IoC; +using Robust.Shared.Maths; +using Robust.Shared.Players; +using Robust.Shared.Utility; + +namespace Robust.Shared.Player +{ + /// + /// A filter for recipients of a networked method call. + /// + public interface IFilter + { + /// + /// Should this networked call be properly predicted? + /// True: Check things like IsFirstTimePredicted(). + /// False: JUST DO IT. + /// + bool CheckPrediction { get; } + + /// + /// Should this network call be sent as reliable? + /// + bool SendReliable { get; } + + /// + /// Networked sessions that should receive the event. + /// + IList Recipients { get; } + } + + /// + /// Contains a set of recipients for a networked method call. + /// + [PublicAPI] + public class Filter : IFilter + { + private bool _prediction; + private List _recipients = new(); + private bool _reliable; + + private Filter() { } + + bool IFilter.CheckPrediction => _prediction; + bool IFilter.SendReliable => _reliable; + IList IFilter.Recipients => _recipients; + + /// + /// Adds a single player to the filter. + /// + public Filter AddPlayer(ICommonSession player) + { + _recipients.Add(player); + return this; + } + + /// + /// Adds all players inside an entity's PVS. + /// + protected Filter AddPlayersByPvs(Vector2 origin) + { + // Calculate this from the PVS system that does not exist. + throw new NotImplementedException(); + + return this; + } + + public Filter AddPlayers(IEnumerable players) + { + foreach (var player in players) + { + AddPlayer(player); + } + + return this; + } + + /// + /// Adds all players to the filter. + /// + public Filter AddAllPlayers() + { + _recipients.Clear(); + + var playerMan = IoCManager.Resolve(); + _recipients.AddRange(playerMan.NetworkedSessions); + return this; + } + + /// + /// Removes a single player from the filter. + /// + public Filter RemovePlayer(ICommonSession player) + { + _recipients.Remove(player); + return this; + } + + public Filter RemoveWhere(Predicate predicate) + { + for (int i = 0; i < _recipients.Count; i++) + { + var player = _recipients[i]; + + if (predicate(player)) + { + _recipients.RemoveSwap(i); + i--; + } + } + + return this; + } + + public Filter AddWhere(Predicate predicate) + { + var playerMan = IoCManager.Resolve(); + foreach (var player in playerMan.NetworkedSessions) + { + if (predicate(player)) + { + AddPlayer(player); + } + } + + return this; + } + + /// + /// This filter will properly be handled by prediction. + /// + public Filter HandlePrediction() + { + _prediction = true; + return this; + } + + /// + /// Should it be guaranteed that recipients receive the message? + /// + public Filter SendReliably() + { + _reliable = true; + return this; + } + + /// + /// A new filter that is empty. + /// + /// + public static Filter Empty() + { + return new(); + } + + /// + /// A new filter with a single player in it. + /// + public static Filter SinglePlayer(ICommonSession player) + { + return Empty().AddPlayer(player); + } + + /// + /// A new filter with all players in it. + /// + public static Filter Broadcast() + { + return Empty().AddAllPlayers(); + } + + /// + /// A filter with every player who's PVS overlaps this point. + /// + public static Filter Pvs(Vector2 origin) + { + return Empty().AddPlayersByPvs(origin); + } + + /// + /// A filter with only the local player. + /// + public static Filter Local() + { + return Empty(); + } + } +} diff --git a/Robust.Shared/Players/IBaseSession.cs b/Robust.Shared/Players/IBaseSession.cs deleted file mode 100644 index ed29e076a..000000000 --- a/Robust.Shared/Players/IBaseSession.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Robust.Shared.Network; - -namespace Robust.Shared.Players -{ - /// - /// Basic info about a player session. - /// - public interface IBaseSession - { - /// - /// The UID of this session. - /// - NetUserId UserId { get; } - - /// - /// Current name of this player. - /// - string Name { get; } - } -} diff --git a/Robust.Shared/Players/ICommonSession.cs b/Robust.Shared/Players/ICommonSession.cs index 8798b68b9..f373cc615 100644 --- a/Robust.Shared/Players/ICommonSession.cs +++ b/Robust.Shared/Players/ICommonSession.cs @@ -1,18 +1,42 @@ -using Robust.Shared.Enums; +using Robust.Shared.Enums; using Robust.Shared.GameObjects; +using Robust.Shared.Network; namespace Robust.Shared.Players { /// - /// Common info between client and server sessions. + /// Common info between client and server sessions. /// - public interface ICommonSession : IBaseSession + public interface ICommonSession { /// - /// Status of the session. + /// Status of the session. /// - SessionStatus Status { get; set; } + SessionStatus Status { get; internal set; } + /// + /// Entity that this session is represented by in the world, if any. + /// IEntity? AttachedEntity { get; } + + /// + /// Entity UID that this session is represented by in the world, if any. + /// + EntityUid? AttachedEntityUid { get; } + + /// + /// The UID of this session. + /// + NetUserId UserId { get; } + + /// + /// Current name of this player. + /// + string Name { get; internal set; } + + /// + /// Current connection latency of this session from the server to their client. + /// + short Ping { get; internal set; } } } diff --git a/Robust.Shared/Players/ISharedPlayerManager.cs b/Robust.Shared/Players/ISharedPlayerManager.cs new file mode 100644 index 000000000..967819e30 --- /dev/null +++ b/Robust.Shared/Players/ISharedPlayerManager.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using Robust.Shared.Network; + +namespace Robust.Shared.Players +{ + public interface ISharedPlayerManager + { + /// + /// Player sessions with a remote endpoint. + /// + IEnumerable NetworkedSessions { get; } + + IEnumerable Sessions { get; } + + /// + /// Number of players currently connected to this server. + /// + int PlayerCount { get; } + + /// + /// Maximum number of players that can connect to this server at one time. + /// + int MaxPlayers { get; } + } +}