From 3f3f54576072914399570bc389a2916d4de7867f Mon Sep 17 00:00:00 2001 From: AeonLucid Date: Fri, 25 Sep 2020 22:02:03 +0200 Subject: [PATCH] Refactor code --- .../Extensions/ConnectionExtensions.cs | 16 -- src/Impostor.Server/Net/Client.cs | 29 ++- src/Impostor.Server/Net/ClientPlayer.cs | 16 -- src/Impostor.Server/Net/GameStates.cs | 10 - .../Net/{ => Manager}/ClientManager.cs | 2 +- .../Net/{ => Manager}/GameManager.cs | 5 +- src/Impostor.Server/Net/Matchmaker.cs | 10 +- .../Net/Messages/Message00HostGame.cs | 60 ++++++ .../Net/Messages/Message01JoinGame.cs | 46 +++++ .../Net/Messages/Message04RemovePlayer.cs | 25 +++ .../Net/Messages/Message07JoinedGame.cs | 28 +++ .../Net/Messages/Message10AlterGame.cs | 19 ++ .../Net/Messages/Message11KickPlayer.cs | 21 +++ .../Net/Messages/Message12WaitForHost.cs | 20 ++ .../Net/Messages/MessageFlags.cs | 22 +++ .../Net/Response/Message1DisconnectReason.cs | 30 --- .../Net/Response/MessageBase.cs | 32 ---- .../Net/Response/MessageFlag.cs | 7 - src/Impostor.Server/Net/State/ClientPlayer.cs | 27 +++ .../Net/{Game.cs => State/Game.Incoming.cs} | 173 +----------------- .../Net/State/Game.Outgoing.cs | 40 ++++ src/Impostor.Server/Net/State/Game.cs | 95 ++++++++++ .../Innersloth/Data/GameStates.cs | 8 +- 23 files changed, 438 insertions(+), 303 deletions(-) delete mode 100644 src/Impostor.Server/Extensions/ConnectionExtensions.cs delete mode 100644 src/Impostor.Server/Net/ClientPlayer.cs delete mode 100644 src/Impostor.Server/Net/GameStates.cs rename src/Impostor.Server/Net/{ => Manager}/ClientManager.cs (97%) rename src/Impostor.Server/Net/{ => Manager}/GameManager.cs (91%) create mode 100644 src/Impostor.Server/Net/Messages/Message00HostGame.cs create mode 100644 src/Impostor.Server/Net/Messages/Message01JoinGame.cs create mode 100644 src/Impostor.Server/Net/Messages/Message04RemovePlayer.cs create mode 100644 src/Impostor.Server/Net/Messages/Message07JoinedGame.cs create mode 100644 src/Impostor.Server/Net/Messages/Message10AlterGame.cs create mode 100644 src/Impostor.Server/Net/Messages/Message11KickPlayer.cs create mode 100644 src/Impostor.Server/Net/Messages/Message12WaitForHost.cs create mode 100644 src/Impostor.Server/Net/Messages/MessageFlags.cs delete mode 100644 src/Impostor.Server/Net/Response/Message1DisconnectReason.cs delete mode 100644 src/Impostor.Server/Net/Response/MessageBase.cs delete mode 100644 src/Impostor.Server/Net/Response/MessageFlag.cs create mode 100644 src/Impostor.Server/Net/State/ClientPlayer.cs rename src/Impostor.Server/Net/{Game.cs => State/Game.Incoming.cs} (53%) create mode 100644 src/Impostor.Server/Net/State/Game.Outgoing.cs create mode 100644 src/Impostor.Server/Net/State/Game.cs diff --git a/src/Impostor.Server/Extensions/ConnectionExtensions.cs b/src/Impostor.Server/Extensions/ConnectionExtensions.cs deleted file mode 100644 index 21ef19e..0000000 --- a/src/Impostor.Server/Extensions/ConnectionExtensions.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Hazel; -using Impostor.Server.Net.Response; - -namespace Impostor.Server.Extensions -{ - internal static class ConnectionExtensions - { - public static void Send(this Connection connection, MessageBase message) - { - using (message) - { - connection.Send(message.Write()); - } - } - } -} \ No newline at end of file diff --git a/src/Impostor.Server/Net/Client.cs b/src/Impostor.Server/Net/Client.cs index b3a041e..72e3558 100644 --- a/src/Impostor.Server/Net/Client.cs +++ b/src/Impostor.Server/Net/Client.cs @@ -1,9 +1,9 @@ using System; using Hazel; using Impostor.Server.Data; -using Impostor.Server.Extensions; -using Impostor.Server.Net.Response; -using Impostor.Shared.Innersloth; +using Impostor.Server.Net.Manager; +using Impostor.Server.Net.Messages; +using Impostor.Server.Net.State; using Impostor.Shared.Innersloth.Data; using Serilog; using ILogger = Serilog.ILogger; @@ -85,7 +85,7 @@ namespace Impostor.Server.Net catch (Exception ex) { Logger.Error(ex, "Exception caught in client data handler."); - Connection.Send(new Message1DisconnectReason(DisconnectReason.Custom, DisconnectMessages.Error)); + Player.SendDisconnectReason(DisconnectReason.Custom, DisconnectMessages.Error); } } @@ -100,23 +100,20 @@ namespace Impostor.Server.Net case RequestFlag.HostGame: { // Read game settings. - var gameInfoBytes = message.ReadBytesAndSize(); - var gameInfo = GameOptionsData.Deserialize(gameInfoBytes); + var gameInfo = Message00HostGame.Deserialize(message); // Create game. var game = _gameManager.Create(this, gameInfo); if (game == null) { - Connection.Send(new Message1DisconnectReason(DisconnectReason.ServerFull)); + Player.SendDisconnectReason(DisconnectReason.ServerFull); return; } // Code in the packet below will be used in JoinGame. using (var writer = MessageWriter.Get(SendOption.Reliable)) { - writer.StartMessage(0); - writer.Write(game.Code); - writer.EndMessage(); + Message00HostGame.Serialize(writer, game.Code); Connection.Send(writer); } @@ -130,7 +127,7 @@ namespace Impostor.Server.Net var game = _gameManager.Find(gameCode); if (game == null) { - Connection.Send(new Message1DisconnectReason(DisconnectReason.GameMissing)); + Player.SendDisconnectReason(DisconnectReason.GameMissing); return; } @@ -240,17 +237,19 @@ namespace Impostor.Server.Net Logger.Warning("Server received unknown flag {0}.", flag); break; } - + +#if DEBUG if (flag != RequestFlag.GameData && flag != RequestFlag.GameDataTo && flag != RequestFlag.EndGame && message.Position < message.Length) { - Logger.Warning("Server did not consume all bytes from {0} ({1} < {2}).", - flag, - message.Position, + Logger.Warning("Server did not consume all bytes from {0} ({1} < {2}).", + flag, + message.Position, message.Length); } +#endif } private void OnDisconnected(object sender, DisconnectedEventArgs e) diff --git a/src/Impostor.Server/Net/ClientPlayer.cs b/src/Impostor.Server/Net/ClientPlayer.cs deleted file mode 100644 index a0b7866..0000000 --- a/src/Impostor.Server/Net/ClientPlayer.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Impostor.Shared.Innersloth.Data; - -namespace Impostor.Server.Net -{ - public class ClientPlayer - { - public ClientPlayer(Client client) - { - Client = client; - } - - public Client Client { get; } - public Game Game { get; set; } - public LimboStates LimboState { get; set; } - } -} \ No newline at end of file diff --git a/src/Impostor.Server/Net/GameStates.cs b/src/Impostor.Server/Net/GameStates.cs deleted file mode 100644 index f24ecc5..0000000 --- a/src/Impostor.Server/Net/GameStates.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Impostor.Server.Net -{ - public enum GameStates : byte - { - NotStarted = 0, - Started = 1, - Ended = 2, - Destroyed = 3 - } -} \ No newline at end of file diff --git a/src/Impostor.Server/Net/ClientManager.cs b/src/Impostor.Server/Net/Manager/ClientManager.cs similarity index 97% rename from src/Impostor.Server/Net/ClientManager.cs rename to src/Impostor.Server/Net/Manager/ClientManager.cs index 2a43d14..b4f7684 100644 --- a/src/Impostor.Server/Net/ClientManager.cs +++ b/src/Impostor.Server/Net/Manager/ClientManager.cs @@ -2,7 +2,7 @@ using Impostor.Server.Exceptions; using Serilog; -namespace Impostor.Server.Net +namespace Impostor.Server.Net.Manager { public class ClientManager { diff --git a/src/Impostor.Server/Net/GameManager.cs b/src/Impostor.Server/Net/Manager/GameManager.cs similarity index 91% rename from src/Impostor.Server/Net/GameManager.cs rename to src/Impostor.Server/Net/Manager/GameManager.cs index 664f640..0b2b251 100644 --- a/src/Impostor.Server/Net/GameManager.cs +++ b/src/Impostor.Server/Net/Manager/GameManager.cs @@ -1,8 +1,9 @@ using System.Collections.Concurrent; +using Impostor.Server.Net.State; using Impostor.Shared.Innersloth; using Serilog; -namespace Impostor.Server.Net +namespace Impostor.Server.Net.Manager { public class GameManager { @@ -22,7 +23,7 @@ namespace Impostor.Server.Net if (_games.TryAdd(gameCode, game)) { - Logger.Debug("Created game with code {0} ({1}).", GameCode.IntToGameName(gameCode), gameCode); + Logger.Debug("Created game with code {0} ({1}).", game.CodeStr, gameCode); return game; } diff --git a/src/Impostor.Server/Net/Matchmaker.cs b/src/Impostor.Server/Net/Matchmaker.cs index 8acc9d6..5a1bec7 100644 --- a/src/Impostor.Server/Net/Matchmaker.cs +++ b/src/Impostor.Server/Net/Matchmaker.cs @@ -1,8 +1,8 @@ using System.Net; using Hazel; using Hazel.Udp; -using Impostor.Server.Extensions; -using Impostor.Server.Net.Response; +using Impostor.Server.Net.Manager; +using Impostor.Server.Net.Messages; using Impostor.Shared.Innersloth.Data; using Serilog; using ILogger = Serilog.ILogger; @@ -39,7 +39,11 @@ namespace Impostor.Server.Net if (clientVersion != 50516550) { - e.Connection.Send(new Message1DisconnectReason(DisconnectReason.IncorrectVersion)); + using (var packet = MessageWriter.Get(SendOption.Reliable)) + { + Message01JoinGame.SerializeError(packet, false, DisconnectReason.IncorrectVersion); + e.Connection.Send(packet); + } return; } diff --git a/src/Impostor.Server/Net/Messages/Message00HostGame.cs b/src/Impostor.Server/Net/Messages/Message00HostGame.cs new file mode 100644 index 0000000..392bc38 --- /dev/null +++ b/src/Impostor.Server/Net/Messages/Message00HostGame.cs @@ -0,0 +1,60 @@ +using System.IO; +using Hazel; +using Impostor.Shared.Innersloth; +using Impostor.Shared.Innersloth.Data; + +namespace Impostor.Server.Net.Messages +{ + internal static class Message00HostGame + { + public static void Serialize(MessageWriter writer, int gameCode) + { + writer.StartMessage(MessageFlags.HostGame); + writer.Write(gameCode); + writer.EndMessage(); + } + + public static GameOptionsData Deserialize(MessageReader reader) + { + var bytes = reader.ReadBytesAndSize(); + + using (var stream = new MemoryStream(bytes)) + using (var binary = new BinaryReader(stream)) + { + var result = new GameOptionsData + { + Version = binary.ReadByte(), + MaxPlayers = binary.ReadByte(), + Keywords = (GameKeywords) binary.ReadUInt32(), + MapId = binary.ReadByte(), + PlayerSpeedMod = binary.ReadSingle(), + CrewLightMod = binary.ReadSingle(), + ImpostorLightMod = binary.ReadSingle(), + KillCooldown = binary.ReadSingle(), + NumCommonTasks = binary.ReadByte(), + NumLongTasks = binary.ReadByte(), + NumShortTasks = binary.ReadByte(), + NumEmergencyMeetings = binary.ReadInt32(), + NumImpostors = binary.ReadByte(), + KillDistance = binary.ReadByte(), + DiscussionTime = binary.ReadInt32(), + VotingTime = binary.ReadInt32(), + IsDefaults = binary.ReadBoolean() + }; + + if (result.Version > 1) + { + result.EmergencyCooldown = binary.ReadByte(); + } + + if (result.Version > 2) + { + result.ConfirmImpostor = binary.ReadBoolean(); + result.VisualTasks = binary.ReadBoolean(); + } + + return result; + } + } + } +} \ No newline at end of file diff --git a/src/Impostor.Server/Net/Messages/Message01JoinGame.cs b/src/Impostor.Server/Net/Messages/Message01JoinGame.cs new file mode 100644 index 0000000..badee4f --- /dev/null +++ b/src/Impostor.Server/Net/Messages/Message01JoinGame.cs @@ -0,0 +1,46 @@ +using System; +using Hazel; +using Impostor.Shared.Innersloth.Data; + +namespace Impostor.Server.Net.Messages +{ + internal static class Message01JoinGame + { + public static void SerializeJoin(MessageWriter writer, bool clear, int gameCode, int playerId, int hostId) + { + if (clear) + { + writer.Clear(SendOption.Reliable); + } + + writer.StartMessage(MessageFlags.JoinGame); + writer.Write(gameCode); + writer.Write(playerId); + writer.Write(hostId); + writer.EndMessage(); + } + + public static void SerializeError(MessageWriter writer, bool clear, DisconnectReason reason, string message = null) + { + if (clear) + { + writer.Clear(SendOption.Reliable); + } + + writer.StartMessage(MessageFlags.JoinGame); + writer.Write((int) reason); + + if (reason == DisconnectReason.Custom) + { + if (message == null) + { + throw new ArgumentNullException(nameof(message)); + } + + writer.Write(message); + } + + writer.EndMessage(); + } + } +} \ No newline at end of file diff --git a/src/Impostor.Server/Net/Messages/Message04RemovePlayer.cs b/src/Impostor.Server/Net/Messages/Message04RemovePlayer.cs new file mode 100644 index 0000000..b572c21 --- /dev/null +++ b/src/Impostor.Server/Net/Messages/Message04RemovePlayer.cs @@ -0,0 +1,25 @@ +using Hazel; +using Impostor.Shared.Innersloth.Data; + +namespace Impostor.Server.Net.Messages +{ + internal static class Message04RemovePlayer + { + public static void Serialize(MessageWriter writer, bool clear, int gameCode, int playerId, int hostId, DisconnectReason reason) + { + // Only a subset of DisconnectReason shows an unique message. + // ExitGame, Banned and Kicked. + if (clear) + { + writer.Clear(SendOption.Reliable); + } + + writer.StartMessage(MessageFlags.RemovePlayer); + writer.Write(gameCode); + writer.Write(playerId); + writer.Write(hostId); + writer.Write((byte) reason); + writer.EndMessage(); + } + } +} \ No newline at end of file diff --git a/src/Impostor.Server/Net/Messages/Message07JoinedGame.cs b/src/Impostor.Server/Net/Messages/Message07JoinedGame.cs new file mode 100644 index 0000000..9fa08e7 --- /dev/null +++ b/src/Impostor.Server/Net/Messages/Message07JoinedGame.cs @@ -0,0 +1,28 @@ +using Hazel; + +namespace Impostor.Server.Net.Messages +{ + internal static class Message07JoinedGame + { + public static void Serialize(MessageWriter writer, bool clear, int gameCode, int playerId, int hostId, int[] otherPlayerIds) + { + if (clear) + { + writer.Clear(SendOption.Reliable); + } + + writer.StartMessage(MessageFlags.JoinedGame); + writer.Write(gameCode); + writer.Write(playerId); + writer.Write(hostId); + writer.WritePacked(otherPlayerIds.Length); + + foreach (var id in otherPlayerIds) + { + writer.WritePacked(id); + } + + writer.EndMessage(); + } + } +} \ No newline at end of file diff --git a/src/Impostor.Server/Net/Messages/Message10AlterGame.cs b/src/Impostor.Server/Net/Messages/Message10AlterGame.cs new file mode 100644 index 0000000..3b77548 --- /dev/null +++ b/src/Impostor.Server/Net/Messages/Message10AlterGame.cs @@ -0,0 +1,19 @@ +using Hazel; + +namespace Impostor.Server.Net.Messages +{ + internal static class Message10AlterGame + { + public static void Serialize(MessageWriter writer, bool clear, int gameCode) + { + if (clear) + { + writer.Clear(SendOption.Reliable); + } + + writer.StartMessage(MessageFlags.HostGame); + writer.Write(gameCode); + writer.EndMessage(); + } + } +} \ No newline at end of file diff --git a/src/Impostor.Server/Net/Messages/Message11KickPlayer.cs b/src/Impostor.Server/Net/Messages/Message11KickPlayer.cs new file mode 100644 index 0000000..dde4726 --- /dev/null +++ b/src/Impostor.Server/Net/Messages/Message11KickPlayer.cs @@ -0,0 +1,21 @@ +using Hazel; + +namespace Impostor.Server.Net.Messages +{ + internal static class Message11KickPlayer + { + public static void Serialize(MessageWriter writer, bool clear, int gameCode, int playerId, bool isBan) + { + if (clear) + { + writer.Clear(SendOption.Reliable); + } + + writer.StartMessage(MessageFlags.KickPlayer); + writer.Write(gameCode); + writer.WritePacked(playerId); + writer.Write(isBan); + writer.EndMessage(); + } + } +} \ No newline at end of file diff --git a/src/Impostor.Server/Net/Messages/Message12WaitForHost.cs b/src/Impostor.Server/Net/Messages/Message12WaitForHost.cs new file mode 100644 index 0000000..e09f4b4 --- /dev/null +++ b/src/Impostor.Server/Net/Messages/Message12WaitForHost.cs @@ -0,0 +1,20 @@ +using Hazel; + +namespace Impostor.Server.Net.Messages +{ + internal static class Message12WaitForHost + { + public static void Serialize(MessageWriter writer, bool clear, int gameCode, int playerId) + { + if (clear) + { + writer.Clear(SendOption.Reliable); + } + + writer.StartMessage(MessageFlags.WaitForHost); + writer.Write(gameCode); + writer.Write(playerId); + writer.EndMessage(); + } + } +} \ No newline at end of file diff --git a/src/Impostor.Server/Net/Messages/MessageFlags.cs b/src/Impostor.Server/Net/Messages/MessageFlags.cs new file mode 100644 index 0000000..595c02e --- /dev/null +++ b/src/Impostor.Server/Net/Messages/MessageFlags.cs @@ -0,0 +1,22 @@ +namespace Impostor.Server.Net.Messages +{ + internal static class MessageFlags + { + public const byte HostGame = 0; + public const byte JoinGame = 1; + public const byte StartGame = 2; + public const byte RemoveGame = 3; + public const byte RemovePlayer = 4; + public const byte GameData = 5; + public const byte GameDataTo = 6; + public const byte JoinedGame = 7; + public const byte EndGame = 8; + public const byte AlterGame = 10; + public const byte KickPlayer = 11; + public const byte WaitForHost = 12; + public const byte Redirect = 13; + public const byte ReselectServer = 14; + public const byte GetGameList = 9; + public const byte GetGameListV2 = 16; + } +} \ No newline at end of file diff --git a/src/Impostor.Server/Net/Response/Message1DisconnectReason.cs b/src/Impostor.Server/Net/Response/Message1DisconnectReason.cs deleted file mode 100644 index 0ab5be4..0000000 --- a/src/Impostor.Server/Net/Response/Message1DisconnectReason.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Hazel; -using Impostor.Shared.Innersloth.Data; - -namespace Impostor.Server.Net.Response -{ - public class Message1DisconnectReason : MessageBase - { - private readonly DisconnectReason _reason; - private readonly string _message; - - // Notes: - // - Specifying no reason does something with ban minutes left. - // - (?) You were disconnected because Among Us was suspended by another app. - public Message1DisconnectReason(DisconnectReason reason, string message = null) : base(SendOption.Reliable, MessageFlag.DisconnectReason) - { - _reason = reason; - _message = message; - } - - protected override void WriteMessage(MessageWriter writer) - { - writer.Write((int) _reason); - - if (_reason == DisconnectReason.Custom) - { - writer.Write(_message); - } - } - } -} \ No newline at end of file diff --git a/src/Impostor.Server/Net/Response/MessageBase.cs b/src/Impostor.Server/Net/Response/MessageBase.cs deleted file mode 100644 index d9fceab..0000000 --- a/src/Impostor.Server/Net/Response/MessageBase.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using Hazel; - -namespace Impostor.Server.Net.Response -{ - public abstract class MessageBase : IDisposable - { - private readonly MessageWriter _writer; - private readonly MessageFlag _flag; - - protected MessageBase(SendOption option, MessageFlag flag) - { - _writer = MessageWriter.Get(option); - _flag = flag; - } - - public MessageWriter Write() - { - _writer.StartMessage((byte) _flag); - WriteMessage(_writer); - _writer.EndMessage(); - return _writer; - } - - protected abstract void WriteMessage(MessageWriter writer); - - public void Dispose() - { - _writer.Dispose(); - } - } -} \ No newline at end of file diff --git a/src/Impostor.Server/Net/Response/MessageFlag.cs b/src/Impostor.Server/Net/Response/MessageFlag.cs deleted file mode 100644 index a29135d..0000000 --- a/src/Impostor.Server/Net/Response/MessageFlag.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Impostor.Server.Net.Response -{ - public enum MessageFlag : byte - { - DisconnectReason = 1 - } -} \ No newline at end of file diff --git a/src/Impostor.Server/Net/State/ClientPlayer.cs b/src/Impostor.Server/Net/State/ClientPlayer.cs new file mode 100644 index 0000000..242d6b9 --- /dev/null +++ b/src/Impostor.Server/Net/State/ClientPlayer.cs @@ -0,0 +1,27 @@ +using Hazel; +using Impostor.Server.Net.Messages; +using Impostor.Shared.Innersloth.Data; + +namespace Impostor.Server.Net.State +{ + public class ClientPlayer + { + public ClientPlayer(Client client) + { + Client = client; + } + + public Client Client { get; } + public Game Game { get; set; } + public LimboStates LimboState { get; set; } + + public void SendDisconnectReason(DisconnectReason reason, string message = null) + { + using (var packet = MessageWriter.Get(SendOption.Reliable)) + { + Message01JoinGame.SerializeError(packet, false, reason, message); + Client.Connection.Send(packet); + } + } + } +} \ No newline at end of file diff --git a/src/Impostor.Server/Net/Game.cs b/src/Impostor.Server/Net/State/Game.Incoming.cs similarity index 53% rename from src/Impostor.Server/Net/Game.cs rename to src/Impostor.Server/Net/State/Game.Incoming.cs index be982d7..1e7155f 100644 --- a/src/Impostor.Server/Net/Game.cs +++ b/src/Impostor.Server/Net/State/Game.Incoming.cs @@ -1,80 +1,14 @@ using System; -using System.Collections.Concurrent; -using System.Collections.Generic; using System.Linq; -using System.Net; using Hazel; using Impostor.Server.Data; using Impostor.Server.Exceptions; -using Impostor.Server.Extensions; -using Impostor.Server.Net.Response; -using Impostor.Shared.Innersloth; using Impostor.Shared.Innersloth.Data; -using Serilog; -using ILogger = Serilog.ILogger; -namespace Impostor.Server.Net +namespace Impostor.Server.Net.State { - public class Game + public partial class Game { - private static readonly ILogger Logger = Log.ForContext(); - - private readonly GameManager _gameManager; - private readonly ConcurrentDictionary _players; - private readonly HashSet _bannedIps; - - public Game(GameManager gameManager, int code, GameOptionsData options) - { - _gameManager = gameManager; - _players = new ConcurrentDictionary(); - _bannedIps = new HashSet(); - - Code = code; - CodeStr = GameCode.IntToGameName(code); - HostId = -1; - GameState = GameStates.NotStarted; - Options = options; - } - - public int Code { get; } - public string CodeStr { get; } - public bool IsPublic { get; private set; } - public int HostId { get; private set; } - public GameStates GameState { get; private set; } - public GameOptionsData Options { get; } - - public void SendToAllExcept(MessageWriter message, ClientPlayer sender) - { - foreach (var (_, player) in _players.Where(x => x.Value != sender)) - { - if (player.Client.Connection.State != ConnectionState.Connected) - { - Logger.Warning("[{0}] Tried to sent data to a disconnected player ({1}).", sender?.Client.Id, player.Client.Id); - continue; - } - - player.Client.Send(message); - } - } - - public void SendTo(MessageWriter message, int playerId) - { - if (_players.TryGetValue(playerId, out var player)) - { - if (player.Client.Connection.State != ConnectionState.Connected) - { - Logger.Warning("[{0}] Sending data to {1} failed, player is not connected.", CodeStr, player.Client.Id); - return; - } - - player.Client.Send(message); - } - else - { - Logger.Warning("[{0}] Sending data to {1} failed, player does not exist.", CodeStr, playerId); - } - } - public void HandleStartGame(MessageReader message) { GameState = GameStates.Started; @@ -90,7 +24,7 @@ namespace Impostor.Server.Net { if (_bannedIps.Contains(sender.Client.Connection.EndPoint.Address)) { - sender.Client.Connection.Send(new Message1DisconnectReason(DisconnectReason.Banned)); + sender.SendDisconnectReason(DisconnectReason.Banned); return; } @@ -103,10 +37,10 @@ namespace Impostor.Server.Net HandleJoinGameNext(sender); break; case GameStates.Started: - sender.Client.Connection.Send(new Message1DisconnectReason(DisconnectReason.GameStarted)); + sender.SendDisconnectReason(DisconnectReason.GameStarted); return; case GameStates.Destroyed: - sender.Client.Connection.Send(new Message1DisconnectReason(DisconnectReason.Custom, DisconnectMessages.Destroyed)); + sender.SendDisconnectReason(DisconnectReason.Custom, DisconnectMessages.Destroyed); return; default: throw new ArgumentOutOfRangeException(); @@ -264,7 +198,7 @@ namespace Impostor.Server.Net if (_players.Count >= 9) { - sender.Client.Connection.Send(new Message1DisconnectReason(DisconnectReason.GameFull)); + sender.SendDisconnectReason(DisconnectReason.GameFull); return; } @@ -288,100 +222,5 @@ namespace Impostor.Server.Net BroadcastJoinMessage(packet, true, sender); } } - - private void WriteRemovePlayerMessage(MessageWriter message, bool clear, int playerId, DisconnectReason reason) - { - // Only a subset of DisconnectReason shows an unique message. - // ExitGame, Banned and Kicked. - if (clear) - { - message.Clear(SendOption.Reliable); - } - - message.StartMessage((byte) RequestFlag.RemovePlayer); - message.Write(Code); - message.Write(playerId); - message.Write(HostId); - message.Write((byte) reason); - message.EndMessage(); - } - - private void WriteJoinedGameMessage(MessageWriter message, bool clear, ClientPlayer player) - { - if (clear) - { - message.Clear(SendOption.Reliable); - } - - message.StartMessage((byte) RequestFlag.JoinedGame); - message.Write(Code); - message.Write(player.Client.Id); - message.Write(HostId); - message.WritePacked(_players.Count - 1); - - foreach (var (_, p) in _players.Where(x => x.Value != player)) - { - message.WritePacked(p.Client.Id); - } - - message.EndMessage(); - } - - private void WriteAlterGameMessage(MessageWriter message, bool clear) - { - if (clear) - { - message.Clear(SendOption.Reliable); - } - - message.StartMessage((byte) RequestFlag.AlterGame); - message.Write(Code); - message.Write((byte) AlterGameTags.ChangePrivacy); - message.Write(IsPublic); - message.EndMessage(); - } - - private void WriteKickPlayerMessage(MessageWriter message, bool clear, int playerId, bool isBan) - { - if (clear) - { - message.Clear(SendOption.Reliable); - } - - message.StartMessage((byte) RequestFlag.KickPlayer); - message.Write(Code); - message.WritePacked(playerId); - message.Write(isBan); - message.EndMessage(); - } - - private void WriteWaitForHostMessage(MessageWriter message, bool clear, ClientPlayer player) - { - if (clear) - { - message.Clear(SendOption.Reliable); - } - - message.StartMessage((byte) RequestFlag.WaitForHost); - message.Write(Code); - message.Write(player.Client.Id); - message.EndMessage(); - } - - private void BroadcastJoinMessage(MessageWriter message, bool clear, ClientPlayer player) - { - if (clear) - { - message.Clear(SendOption.Reliable); - } - - message.StartMessage((byte) RequestFlag.JoinGame); - message.Write(Code); - message.Write(player.Client.Id); - message.Write(HostId); - message.EndMessage(); - - SendToAllExcept(message, player); - } } } \ No newline at end of file diff --git a/src/Impostor.Server/Net/State/Game.Outgoing.cs b/src/Impostor.Server/Net/State/Game.Outgoing.cs new file mode 100644 index 0000000..c03b3b4 --- /dev/null +++ b/src/Impostor.Server/Net/State/Game.Outgoing.cs @@ -0,0 +1,40 @@ +using System.Linq; +using Hazel; +using Impostor.Server.Net.Messages; +using Impostor.Shared.Innersloth.Data; + +namespace Impostor.Server.Net.State +{ + public partial class Game + { + private void WriteRemovePlayerMessage(MessageWriter message, bool clear, int playerId, DisconnectReason reason) + { + Message04RemovePlayer.Serialize(message, clear, Code, playerId, HostId, reason); + } + + private void WriteJoinedGameMessage(MessageWriter message, bool clear, ClientPlayer player) + { + var playerIds = _players + .Where(x => x.Value != player) + .Select(x => x.Key) + .ToArray(); + + Message07JoinedGame.Serialize(message, clear, Code, player.Client.Id, HostId, playerIds); + } + + private void WriteAlterGameMessage(MessageWriter message, bool clear) + { + Message10AlterGame.Serialize(message, clear, Code); + } + + private void WriteKickPlayerMessage(MessageWriter message, bool clear, int playerId, bool isBan) + { + Message11KickPlayer.Serialize(message, clear, Code, playerId, isBan); + } + + private void WriteWaitForHostMessage(MessageWriter message, bool clear, ClientPlayer player) + { + Message12WaitForHost.Serialize(message, clear, Code, player.Client.Id); + } + } +} \ No newline at end of file diff --git a/src/Impostor.Server/Net/State/Game.cs b/src/Impostor.Server/Net/State/Game.cs new file mode 100644 index 0000000..fe043a1 --- /dev/null +++ b/src/Impostor.Server/Net/State/Game.cs @@ -0,0 +1,95 @@ +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using Hazel; +using Impostor.Server.Net.Manager; +using Impostor.Server.Net.Messages; +using Impostor.Shared.Innersloth; +using Impostor.Shared.Innersloth.Data; +using Serilog; +using ILogger = Serilog.ILogger; + +namespace Impostor.Server.Net.State +{ + public partial class Game + { + private static readonly ILogger Logger = Log.ForContext(); + + private readonly GameManager _gameManager; + private readonly ConcurrentDictionary _players; + private readonly HashSet _bannedIps; + + public Game(GameManager gameManager, int code, GameOptionsData options) + { + _gameManager = gameManager; + _players = new ConcurrentDictionary(); + _bannedIps = new HashSet(); + + Code = code; + CodeStr = GameCode.IntToGameName(code); + HostId = -1; + GameState = GameStates.NotStarted; + Options = options; + } + + public int Code { get; } + public string CodeStr { get; } + public bool IsPublic { get; private set; } + public int HostId { get; private set; } + public GameStates GameState { get; private set; } + public GameOptionsData Options { get; } + + /// + /// Send a message to all players except one. + /// + /// The message to send. + /// + /// The player to exclude from sending the message. + /// Set to null to send a message to everyone. + /// + public void SendToAllExcept(MessageWriter message, ClientPlayer sender) + { + foreach (var (_, player) in _players.Where(x => x.Value != sender)) + { + if (player.Client.Connection.State != ConnectionState.Connected) + { + Logger.Warning("[{0}] Tried to sent data to a disconnected player ({1}).", sender?.Client.Id, player.Client.Id); + continue; + } + + player.Client.Send(message); + } + } + + /// + /// Send a message to a specific player. + /// + /// The message to send. + /// + public void SendTo(MessageWriter message, int playerId) + { + if (_players.TryGetValue(playerId, out var player)) + { + if (player.Client.Connection.State != ConnectionState.Connected) + { + Logger.Warning("[{0}] Sending data to {1} failed, player is not connected.", CodeStr, player.Client.Id); + return; + } + + player.Client.Send(message); + } + else + { + Logger.Warning("[{0}] Sending data to {1} failed, player does not exist.", CodeStr, playerId); + } + } + + private void BroadcastJoinMessage(MessageWriter message, bool clear, ClientPlayer player) + { + Message01JoinGame.SerializeJoin(message, clear, Code, player.Client.Id, HostId); + + SendToAllExcept(message, player); + } + } +} \ No newline at end of file diff --git a/src/Impostor.Shared/Innersloth/Data/GameStates.cs b/src/Impostor.Shared/Innersloth/Data/GameStates.cs index ec2a2f2..7f165e9 100644 --- a/src/Impostor.Shared/Innersloth/Data/GameStates.cs +++ b/src/Impostor.Shared/Innersloth/Data/GameStates.cs @@ -2,9 +2,9 @@ { public enum GameStates : byte { - NotStarted, - Started, - Ended, - Destroyed + NotStarted = 0, + Started = 1, + Ended = 2, + Destroyed = 3 } } \ No newline at end of file -- 2.39.5