From: AeonLucid Date: Mon, 19 Oct 2020 12:39:36 +0000 (+0200) Subject: Refactor messages X-Git-Tag: v1.2.2~96^2~66 X-Git-Url: https://git.deb.at/?a=commitdiff_plain;h=e630863e72952cc46c8aba0fa83fff87ccf92d24;p=rhonda%2Fimpostor.git Refactor messages --- diff --git a/src/Impostor.Api/Games/Extensions/GameExtensions.cs b/src/Impostor.Api/Games/Extensions/GameExtensions.cs new file mode 100644 index 0000000..a736978 --- /dev/null +++ b/src/Impostor.Api/Games/Extensions/GameExtensions.cs @@ -0,0 +1,42 @@ +using System; +using System.Threading.Tasks; +using Impostor.Api.Net; +using Impostor.Api.Net.Messages; + +namespace Impostor.Api.Games +{ + public static class GameExtensions + { + public static ValueTask SendToAllExceptAsync(this IGame game, IMessageWriter writer, LimboStates states, int? id) + { + return id.HasValue + ? game.SendToAllExceptAsync(writer, id.Value, states) + : game.SendToAllAsync(writer, states); + } + + public static ValueTask SendToAllExceptAsync(this IGame game, IMessageWriter writer, LimboStates states, IClient client) + { + if (client == null) + { + throw new ArgumentNullException(nameof(client)); + } + + return game.SendToAllExceptAsync(writer, client.Id, states); + } + + public static ValueTask SendToAsync(this IGame game, IMessageWriter writer, IClient client) + { + if (client == null) + { + throw new ArgumentNullException(nameof(client)); + } + + return game.SendToAsync(writer, client.Id); + } + + public static ValueTask SendToAsync(this IGame game, IMessageWriter writer, IClientPlayer player) + { + return game.SendToAsync(writer, player.Client); + } + } +} \ No newline at end of file diff --git a/src/Impostor.Api/Games/IGame.cs b/src/Impostor.Api/Games/IGame.cs index 6de41f0..17fa2b8 100644 --- a/src/Impostor.Api/Games/IGame.cs +++ b/src/Impostor.Api/Games/IGame.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Net; +using System.Threading.Tasks; using Impostor.Api.Innersloth; using Impostor.Api.Innersloth.Data; using Impostor.Api.Net; @@ -29,6 +30,29 @@ namespace Impostor.Api.Games int HostId { get; } - IGameMessageWriter CreateMessage(MessageType type); + /// + /// Send the message to all players. + /// + /// Message to send. + /// Required limbo state of the player. + /// A representing the asynchronous operation. + ValueTask SendToAllAsync(IMessageWriter writer, LimboStates states = LimboStates.NotLimbo); + + /// + /// Send the message to all players except one. + /// + /// Message to send. + /// The player to exclude from sending the message. + /// Required limbo state of the player. + /// A representing the asynchronous operation. + ValueTask SendToAllExceptAsync(IMessageWriter writer, int senderId, LimboStates states = LimboStates.NotLimbo); + + /// + /// Send a message to a specific player. + /// + /// Message to send. + /// ID of the client. + /// A representing the asynchronous operation. + ValueTask SendToAsync(IMessageWriter writer, int id); } } \ No newline at end of file diff --git a/src/Impostor.Api/Net/Extensions/GameMessageWriterExtensions.cs b/src/Impostor.Api/Net/Extensions/GameMessageWriterExtensions.cs deleted file mode 100644 index 5f90bb5..0000000 --- a/src/Impostor.Api/Net/Extensions/GameMessageWriterExtensions.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Threading.Tasks; -using Impostor.Api.Net.Messages; - -namespace Impostor.Api.Net -{ - public static class GameMessageWriterExtensions - { - public static ValueTask SendToAllExceptAsync(this IGameMessageWriter writer, LimboStates states, int? id) - { - return id.HasValue - ? writer.SendToAllExceptAsync(id.Value, states) - : writer.SendToAllAsync(states); - } - - public static ValueTask SendToAllExceptAsync(this IGameMessageWriter writer, LimboStates states, IClient client) - { - if (client == null) - { - throw new ArgumentNullException(nameof(client)); - } - - return writer.SendToAllExceptAsync(client.Id, states); - } - - public static ValueTask SendToAsync(this IGameMessageWriter writer, IClient client) - { - if (client == null) - { - throw new ArgumentNullException(nameof(client)); - } - - return writer.SendToAsync(client.Id); - } - - public static ValueTask SendToAsync(this IGameMessageWriter writer, IClientPlayer player) - { - return SendToAsync(writer, player.Client); - } - } -} \ No newline at end of file diff --git a/src/Impostor.Api/Net/IConnection.cs b/src/Impostor.Api/Net/IConnection.cs index 70edd01..3c8e1f5 100644 --- a/src/Impostor.Api/Net/IConnection.cs +++ b/src/Impostor.Api/Net/IConnection.cs @@ -1,5 +1,5 @@ using System.Net; -using Impostor.Api.Games; +using System.Threading.Tasks; using Impostor.Api.Net.Messages; namespace Impostor.Api.Net @@ -25,14 +25,10 @@ namespace Impostor.Api.Net IClient? Client { get; } /// - /// Create a message writer that can be send to the connection. + /// Sends a message writer to the connection. /// - /// - /// Be aware when implementing a custom connection handler that this method is not called when a message - /// is being send in . - /// - /// Type of the message. - /// Message writer for the current connection. - IConnectionMessageWriter CreateMessage(MessageType messageType); + /// The message. + /// + ValueTask SendAsync(IMessageWriter writer); } } \ No newline at end of file diff --git a/src/Impostor.Api/Net/Messages/IConnectionMessageWriter.cs b/src/Impostor.Api/Net/Messages/IConnectionMessageWriter.cs deleted file mode 100644 index 620046c..0000000 --- a/src/Impostor.Api/Net/Messages/IConnectionMessageWriter.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Threading.Tasks; - -namespace Impostor.Api.Net.Messages -{ - /// - /// Represents the message writer for . - /// - public interface IConnectionMessageWriter : IMessageWriter - { - /// - /// Gets the connection where the message writer belongs to. - /// - public IConnection Connection { get; } - - /// - /// Sends the message to the . - /// - /// Task. - ValueTask SendAsync(); - } -} \ No newline at end of file diff --git a/src/Impostor.Api/Net/Messages/IGameMessageWriter.cs b/src/Impostor.Api/Net/Messages/IGameMessageWriter.cs deleted file mode 100644 index 69c286c..0000000 --- a/src/Impostor.Api/Net/Messages/IGameMessageWriter.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Threading.Tasks; -using Impostor.Api.Games; - -namespace Impostor.Api.Net.Messages -{ - /// - /// Represents the message writer for . - /// - public interface IGameMessageWriter : IMessageWriter - { - /// - /// Send the message to all players. - /// - /// Required limbo state of the player. - /// A representing the asynchronous operation. - ValueTask SendToAllAsync(LimboStates states = LimboStates.NotLimbo); - - /// - /// Send the message to all players except one. - /// - /// The player to exclude from sending the message. - /// Required limbo state of the player. - /// A representing the asynchronous operation. - ValueTask SendToAllExceptAsync(int senderId, LimboStates states = LimboStates.NotLimbo); - - /// - /// Send a message to a specific player. - /// - /// ID of the client. - /// A representing the asynchronous operation. - ValueTask SendToAsync(int id); - } -} \ No newline at end of file diff --git a/src/Impostor.Api/Net/Messages/IMessage.cs b/src/Impostor.Api/Net/Messages/IMessage.cs deleted file mode 100644 index a7eb63e..0000000 --- a/src/Impostor.Api/Net/Messages/IMessage.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Impostor.Api.Net.Messages -{ - public interface IMessage - { - MessageType Type { get; } - - IMessageReader CreateReader(); - } -} \ No newline at end of file diff --git a/src/Impostor.Api/Net/Messages/IMessageWriter.cs b/src/Impostor.Api/Net/Messages/IMessageWriter.cs index eb009ab..5eb5798 100644 --- a/src/Impostor.Api/Net/Messages/IMessageWriter.cs +++ b/src/Impostor.Api/Net/Messages/IMessageWriter.cs @@ -9,6 +9,14 @@ namespace Impostor.Api.Net.Messages /// public interface IMessageWriter : IDisposable { + public byte[] Buffer { get; } + + public int Length { get; set; } + + public int Position { get; set; } + + public MessageType SendOption { get; } + /// /// Writes a boolean to the message. /// diff --git a/src/Impostor.Api/Net/Messages/MessageType.cs b/src/Impostor.Api/Net/Messages/MessageType.cs index 66335eb..92fa153 100644 --- a/src/Impostor.Api/Net/Messages/MessageType.cs +++ b/src/Impostor.Api/Net/Messages/MessageType.cs @@ -1,9 +1,12 @@ -namespace Impostor.Api.Net.Messages +using System; + +namespace Impostor.Api.Net.Messages { /// /// Specifies how a message should be sent between connections. /// - public enum MessageType + [Flags] + public enum MessageType : byte { /// /// Requests unreliable delivery with no fragmentation. diff --git a/src/Impostor.Hazel/Connection.cs b/src/Impostor.Hazel/Connection.cs index 0495cfa..c2ab579 100644 --- a/src/Impostor.Hazel/Connection.cs +++ b/src/Impostor.Hazel/Connection.cs @@ -1,6 +1,7 @@ using System; using System.Net; using System.Threading.Tasks; +using Impostor.Api.Net.Messages; using Serilog; namespace Hazel @@ -127,33 +128,33 @@ namespace Hazel } /// - /// Sends a number of bytes to the end point of the connection using the specified . + /// Sends a number of bytes to the end point of the connection using the specified . /// /// The message to send. /// /// /// - /// The sendOptions parameter is only a request to use those options and the actual method used to send the + /// The messageType parameter is only a request to use those options and the actual method used to send the /// data is up to the implementation. There are circumstances where this parameter may be ignored but in /// general any implementer should aim to always follow the user's request. /// /// - public abstract ValueTask Send(MessageWriter msg); + public abstract ValueTask Send(IMessageWriter msg); /// - /// Sends a number of bytes to the end point of the connection using the specified . + /// Sends a number of bytes to the end point of the connection using the specified . /// /// The bytes of the message to send. - /// The option specifying how the message should be sent. + /// The option specifying how the message should be sent. /// /// /// - /// The sendOptions parameter is only a request to use those options and the actual method used to send the + /// The messageType parameter is only a request to use those options and the actual method used to send the /// data is up to the implementation. There are circumstances where this parameter may be ignored but in /// general any implementer should aim to always follow the user's request. /// /// - public abstract ValueTask SendBytes(byte[] bytes, SendOption sendOption = SendOption.None); + public abstract ValueTask SendBytes(byte[] bytes, MessageType messageType = MessageType.Unreliable); /// /// Connects the connection to a server and begins listening. @@ -174,13 +175,13 @@ namespace Hazel /// Invokes the DataReceived event. /// /// The bytes received. - /// The the message was received with. + /// The the message was received with. /// /// Invokes the event on this connection to alert subscribers a new message has been /// received. The bytes and the send option that the message was sent with should be passed in to give to the /// subscribers. /// - protected async ValueTask InvokeDataReceived(MessageReader msg, SendOption sendOption) + protected async ValueTask InvokeDataReceived(IMessageReader msg, MessageType messageType) { // Make a copy to avoid race condition between null check and invocation var handler = DataReceived; @@ -188,7 +189,7 @@ namespace Hazel { try { - await handler(new DataReceivedEventArgs(this, msg, sendOption)); + await handler(new DataReceivedEventArgs(this, msg, messageType)); } catch (Exception e) { @@ -208,7 +209,7 @@ namespace Hazel /// by the end point or because an error occurred. If an error occurred the error should be passed in in order to /// pass to the subscribers, otherwise null can be passed in. /// - protected async ValueTask InvokeDisconnected(string e, MessageReader reader) + protected async ValueTask InvokeDisconnected(string e, IMessageReader reader) { // Make a copy to avoid race condition between null check and invocation var handler = Disconnected; diff --git a/src/Impostor.Hazel/ConnectionListener.cs b/src/Impostor.Hazel/ConnectionListener.cs index 156f253..f595432 100644 --- a/src/Impostor.Hazel/ConnectionListener.cs +++ b/src/Impostor.Hazel/ConnectionListener.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using Impostor.Api.Net.Messages; using Serilog; namespace Hazel @@ -69,7 +70,7 @@ namespace Hazel /// Implementers should call this to invoke the event before data is received so that /// subscribers do not miss any data that may have been sent immediately after connecting. /// - internal async Task InvokeNewConnection(MessageReader msg, Connection connection) + internal async Task InvokeNewConnection(IMessageReader msg, Connection connection) { // Make a copy to avoid race condition between null check and invocation var handler = NewConnection; diff --git a/src/Impostor.Hazel/DataReceivedEventArgs.cs b/src/Impostor.Hazel/DataReceivedEventArgs.cs index 18432fe..7aa824e 100644 --- a/src/Impostor.Hazel/DataReceivedEventArgs.cs +++ b/src/Impostor.Hazel/DataReceivedEventArgs.cs @@ -1,4 +1,6 @@ -namespace Hazel +using Impostor.Api.Net.Messages; + +namespace Hazel { public struct DataReceivedEventArgs { @@ -7,18 +9,18 @@ /// /// The bytes received from the client. /// - public readonly MessageReader Message; + public readonly IMessageReader Message; /// - /// The the data was sent with. + /// The the data was sent with. /// - public readonly SendOption SendOption; + public readonly MessageType Type; - public DataReceivedEventArgs(Connection sender, MessageReader msg, SendOption sendOption) + public DataReceivedEventArgs(Connection sender, IMessageReader msg, MessageType type) { this.Sender = sender; this.Message = msg; - this.SendOption = sendOption; + this.Type = type; } } } diff --git a/src/Impostor.Hazel/DisconnectedEventArgs.cs b/src/Impostor.Hazel/DisconnectedEventArgs.cs index a7fb05c..a029c7b 100644 --- a/src/Impostor.Hazel/DisconnectedEventArgs.cs +++ b/src/Impostor.Hazel/DisconnectedEventArgs.cs @@ -1,4 +1,5 @@ using System; +using Impostor.Api.Net.Messages; namespace Hazel { @@ -13,9 +14,9 @@ namespace Hazel /// Optional data sent with a disconnect message. May be null. /// You must not recycle this. If you need the message outside of a callback, you should copy it. /// - public readonly MessageReader Message; + public readonly IMessageReader Message; - public DisconnectedEventArgs(string reason, MessageReader message) + public DisconnectedEventArgs(string reason, IMessageReader message) { this.Reason = reason; this.Message = message; diff --git a/src/Impostor.Hazel/Impostor.Hazel.csproj b/src/Impostor.Hazel/Impostor.Hazel.csproj index 40ed188..cf15400 100644 --- a/src/Impostor.Hazel/Impostor.Hazel.csproj +++ b/src/Impostor.Hazel/Impostor.Hazel.csproj @@ -11,4 +11,8 @@ + + + + diff --git a/src/Impostor.Hazel/MessageReader.cs b/src/Impostor.Hazel/MessageReader.cs index f22042b..84e9ff2 100644 --- a/src/Impostor.Hazel/MessageReader.cs +++ b/src/Impostor.Hazel/MessageReader.cs @@ -2,10 +2,11 @@ using System.Buffers.Binary; using System.Runtime.CompilerServices; using System.Text; +using Impostor.Api.Net.Messages; namespace Hazel { - public class MessageReader + public class MessageReader : IMessageReader { public byte Tag { get; } public ReadOnlyMemory Buffer { get; } @@ -24,7 +25,7 @@ namespace Hazel Buffer = buffer; } - public MessageReader ReadMessage() + public IMessageReader ReadMessage() { var length = ReadUInt16(); var tag = ReadByte(); @@ -138,19 +139,19 @@ namespace Hazel return output; } - public void CopyTo(MessageWriter writer) + public void CopyTo(IMessageWriter writer) { writer.Write((ushort) Length); writer.Write((byte) Tag); writer.Write(Buffer); } - public MessageReader Slice(int start) + public IMessageReader Slice(int start) { return new MessageReader(Tag, Buffer.Slice(start)); } - public MessageReader Slice(int start, int length) + public IMessageReader Slice(int start, int length) { return new MessageReader(Tag, Buffer.Slice(start, length)); } diff --git a/src/Impostor.Hazel/MessageWriter.cs b/src/Impostor.Hazel/MessageWriter.cs index 099e614..276c174 100644 --- a/src/Impostor.Hazel/MessageWriter.cs +++ b/src/Impostor.Hazel/MessageWriter.cs @@ -1,20 +1,19 @@ using System; using System.Collections.Generic; +using System.Net; using System.Text; +using Impostor.Api.Games; +using Impostor.Api.Net.Messages; namespace Hazel { /// - public class MessageWriter : IRecyclable, IDisposable + public class MessageWriter : IMessageWriter, IRecyclable, IDisposable { public static int BufferSize = 64000; public static readonly ObjectPool WriterPool = new ObjectPool(() => new MessageWriter(BufferSize)); - public byte[] Buffer; - public int Length; - public int Position; - - public SendOption SendOption { get; private set; } + public MessageType SendOption { get; private set; } private Stack messageStarts = new Stack(); @@ -24,12 +23,15 @@ namespace Hazel this.Length = this.Buffer.Length; } - /// public MessageWriter(int bufferSize) { this.Buffer = new byte[bufferSize]; } + public byte[] Buffer { get; } + public int Length { get; set; } + public int Position { get; set; } + public byte[] ToByteArray(bool includeHeader) { if (includeHeader) @@ -42,13 +44,13 @@ namespace Hazel { switch (this.SendOption) { - case SendOption.Reliable: + case MessageType.Reliable: { byte[] output = new byte[this.Length - 3]; System.Buffer.BlockCopy(this.Buffer, 3, output, 0, this.Length - 3); return output; } - case SendOption.None: + case MessageType.Unreliable: { byte[] output = new byte[this.Length - 1]; System.Buffer.BlockCopy(this.Buffer, 1, output, 0, this.Length - 1); @@ -62,7 +64,7 @@ namespace Hazel /// /// The option specifying how the message should be sent. - public static MessageWriter Get(SendOption sendOption = SendOption.None) + public static MessageWriter Get(MessageType sendOption = MessageType.Unreliable) { var output = WriterPool.GetObject(); output.Clear(sendOption); @@ -72,7 +74,7 @@ namespace Hazel public bool HasBytes(int expected) { - if (this.SendOption == SendOption.None) + if (this.SendOption == MessageType.Unreliable) { return this.Length > 1 + expected; } @@ -80,6 +82,11 @@ namespace Hazel return this.Length > 3 + expected; } + public void Write(GameCode value) + { + this.Write(value.Value); + } + /// public void StartMessage(byte typeFlag) { @@ -104,7 +111,7 @@ namespace Hazel this.Length = this.Position; } - public void Clear(SendOption sendOption) + public void Clear(MessageType sendOption) { this.messageStarts.Clear(); this.SendOption = sendOption; @@ -112,10 +119,10 @@ namespace Hazel switch (sendOption) { default: - case SendOption.None: + case MessageType.Unreliable: this.Length = this.Position = 1; break; - case SendOption.Reliable: + case MessageType.Reliable: this.Length = this.Position = 3; break; } @@ -203,6 +210,11 @@ namespace Hazel this.Write(bytes); } + public void Write(IPAddress value) + { + this.Write(value.GetAddressBytes()); + } + public void WriteBytesAndSize(byte[] bytes) { this.WritePacked((uint)bytes.Length); @@ -277,10 +289,10 @@ namespace Hazel { switch (msg.SendOption) { - case SendOption.None: + case MessageType.Unreliable: offset = 1; break; - case SendOption.Reliable: + case MessageType.Reliable: offset = 3; break; } diff --git a/src/Impostor.Hazel/NetworkConnection.cs b/src/Impostor.Hazel/NetworkConnection.cs index fd155f7..68966ba 100644 --- a/src/Impostor.Hazel/NetworkConnection.cs +++ b/src/Impostor.Hazel/NetworkConnection.cs @@ -1,6 +1,7 @@ using System; using System.Net; using System.Threading.Tasks; +using Impostor.Api.Net.Messages; namespace Hazel @@ -56,7 +57,7 @@ namespace Hazel /// /// Called when the socket has been disconnected at the remote host. /// - protected async ValueTask DisconnectRemote(string reason, MessageReader reader) + protected async ValueTask DisconnectRemote(string reason, IMessageReader reader) { if (this.SendDisconnect(null)) { diff --git a/src/Impostor.Hazel/NewConnectionEventArgs.cs b/src/Impostor.Hazel/NewConnectionEventArgs.cs index 68fd37f..efc84bb 100644 --- a/src/Impostor.Hazel/NewConnectionEventArgs.cs +++ b/src/Impostor.Hazel/NewConnectionEventArgs.cs @@ -1,4 +1,6 @@ -namespace Hazel +using Impostor.Api.Net.Messages; + +namespace Hazel { public struct NewConnectionEventArgs { @@ -6,14 +8,14 @@ /// The data received from the client in the handshake. /// This data is yours. Remember to recycle it. /// - public readonly MessageReader HandshakeData; + public readonly IMessageReader HandshakeData; /// /// The to the new client. /// public readonly Connection Connection; - public NewConnectionEventArgs(MessageReader handshakeData, Connection connection) + public NewConnectionEventArgs(IMessageReader handshakeData, Connection connection) { this.HandshakeData = handshakeData; this.Connection = connection; diff --git a/src/Impostor.Hazel/SendOption.cs b/src/Impostor.Hazel/SendOption.cs deleted file mode 100644 index 385e88c..0000000 --- a/src/Impostor.Hazel/SendOption.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; - -namespace Hazel -{ - /// - /// Specifies how a message should be sent between connections. - /// - [Flags] - public enum SendOption : byte - { - /// - /// Requests unreliable delivery with no framentation. - /// - /// - /// Sending data using unreliable delivery means that data is not guaranteed to arrive at it's destination nor is - /// it guarenteed to arrive only once. However, unreliable delivery can be faster than other methods and it - /// typically requires a smaller number of protocol bytes than other methods. There is also typically less - /// processing involved and less memory needed as packets are not stored once sent. - /// - None = 0, - - /// - /// Requests data be sent reliably but with no fragmentation. - /// - /// - /// Sending data reliably means that data is guarenteed to arrive and to arrive only once. Reliable delivery - /// typically requires more processing, more memory (as packets need to be stored in case they need resending), - /// a larger number of protocol bytes and can be slower than unreliable delivery. - /// - Reliable = 1, - } -} diff --git a/src/Impostor.Hazel/Udp/UdpConnection.Reliable.cs b/src/Impostor.Hazel/Udp/UdpConnection.Reliable.cs index 11f15d8..d39cb5d 100644 --- a/src/Impostor.Hazel/Udp/UdpConnection.Reliable.cs +++ b/src/Impostor.Hazel/Udp/UdpConnection.Reliable.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; +using Impostor.Api.Net.Messages; namespace Hazel.Udp @@ -285,7 +286,7 @@ namespace Hazel.Udp { if (await ProcessReliableReceive(message.Buffer, 1)) { - await InvokeDataReceived(message.Slice(3), SendOption.Reliable); + await InvokeDataReceived(message.Slice(3), MessageType.Reliable); } Statistics.LogReliableReceive(message.Length - 3, message.Length); diff --git a/src/Impostor.Hazel/Udp/UdpConnection.cs b/src/Impostor.Hazel/Udp/UdpConnection.cs index 96429d7..c33ffb3 100644 --- a/src/Impostor.Hazel/Udp/UdpConnection.cs +++ b/src/Impostor.Hazel/Udp/UdpConnection.cs @@ -2,6 +2,7 @@ using System.Threading; using System.Threading.Channels; using System.Threading.Tasks; +using Impostor.Api.Net.Messages; using Serilog; namespace Hazel.Udp @@ -110,7 +111,7 @@ namespace Hazel.Udp protected abstract ValueTask WriteBytesToConnection(byte[] bytes, int length); /// - public override async ValueTask Send(MessageWriter msg) + public override async ValueTask Send(IMessageWriter msg) { if (this._state != ConnectionState.Connected) throw new InvalidOperationException("Could not send data as this Connection is not connected. Did you disconnect?"); @@ -120,7 +121,7 @@ namespace Hazel.Udp switch (msg.SendOption) { - case SendOption.Reliable: + case MessageType.Reliable: ResetKeepAliveTimer(); AttachReliableID(buffer, 1, buffer.Length); @@ -144,7 +145,7 @@ namespace Hazel.Udp /// until implemented. /// /// - public override async ValueTask SendBytes(byte[] bytes, SendOption sendOption = SendOption.None) + public override async ValueTask SendBytes(byte[] bytes, MessageType sendOption = MessageType.Unreliable) { //Add header information and send await HandleSend(bytes, (byte)sendOption); @@ -162,7 +163,7 @@ namespace Hazel.Udp switch (sendOption) { case (byte)UdpSendOption.Ping: - case (byte)SendOption.Reliable: + case (byte)MessageType.Reliable: case (byte)UdpSendOption.Hello: await ReliableSend(sendOption, data, ackCallback); break; @@ -192,7 +193,7 @@ namespace Hazel.Udp switch (message.Buffer.Span[0]) { //Handle reliable receives - case (byte)SendOption.Reliable: + case (byte)MessageType.Reliable: await ReliableMessageReceive(message); break; @@ -217,7 +218,7 @@ namespace Hazel.Udp //Treat everything else as unreliable default: - await InvokeDataReceived(message.Slice(1), SendOption.None); + await InvokeDataReceived(message.Slice(1), MessageType.Unreliable); Statistics.LogUnreliableReceive(message.Length - 1, message.Length); break; } diff --git a/src/Impostor.Hazel/Udp/UdpServerConnection.cs b/src/Impostor.Hazel/Udp/UdpServerConnection.cs index 8885ad4..c95cdb2 100644 --- a/src/Impostor.Hazel/Udp/UdpServerConnection.cs +++ b/src/Impostor.Hazel/Udp/UdpServerConnection.cs @@ -1,6 +1,7 @@ using System; using System.Net; using System.Threading.Tasks; +using Impostor.Api.Net.Messages; namespace Hazel.Udp { @@ -74,7 +75,7 @@ namespace Hazel.Udp var bytes = EmptyDisconnectBytes; if (data != null && data.Length > 0) { - if (data.SendOption != SendOption.None) throw new ArgumentException("Disconnect messages can only be unreliable."); + if (data.SendOption != MessageType.Unreliable) throw new ArgumentException("Disconnect messages can only be unreliable."); bytes = data.ToByteArray(true); bytes[0] = (byte)UdpSendOption.Disconnect; diff --git a/src/Impostor.Server/Net/Client.cs b/src/Impostor.Server/Net/Client.cs index dec73df..42a17ce 100644 --- a/src/Impostor.Server/Net/Client.cs +++ b/src/Impostor.Server/Net/Client.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using Hazel; using Impostor.Api.Games; using Impostor.Api.Innersloth; using Impostor.Api.Innersloth.Data; @@ -26,10 +27,8 @@ namespace Impostor.Server.Net _gameManager = gameManager; } - public override async ValueTask HandleMessageAsync(IMessage message) + public override async ValueTask HandleMessageAsync(IMessageReader reader, MessageType messageType) { - var reader = message.CreateReader(); - var flag = reader.Tag; _logger.LogTrace("[{0}] Server got {1}.", Id, flag); @@ -45,10 +44,11 @@ namespace Impostor.Server.Net var game = await _gameManager.CreateAsync(gameInfo); // Code in the packet below will be used in JoinGame. - using var writer = Connection.CreateMessage(MessageType.Reliable); - Message00HostGame.Serialize(writer, game.Code); - - await writer.SendAsync(); + using (var writer = MessageWriter.Get(MessageType.Reliable)) + { + Message00HostGame.Serialize(writer, game.Code); + await Connection.SendAsync(writer); + } break; } @@ -150,18 +150,19 @@ namespace Impostor.Server.Net await Player.Game.HandleGameData(readerCopy, Player, toPlayer); // Broadcast packet to all other players. - using var writer = Player.Game.CreateMessage(message.Type); - - if (toPlayer) - { - var target = reader.ReadPackedInt32(); - reader.CopyTo(writer); - await writer.SendToAsync(target); - } - else + using (var writer = MessageWriter.Get(messageType)) { - reader.CopyTo(writer); - await writer.SendToAllExceptAsync(Id); + if (toPlayer) + { + var target = reader.ReadPackedInt32(); + reader.CopyTo(writer); + await Player.Game.SendToAsync(writer, target); + } + else + { + reader.CopyTo(writer); + await Player.Game.SendToAllExceptAsync(writer, Id); + } } break; @@ -297,9 +298,10 @@ namespace Impostor.Server.Net /// All options given. /// At this moment, the client can only specify the map, impostor count and chat language. /// - private async ValueTask OnRequestGameList(GameOptionsData options) + private ValueTask OnRequestGameList(GameOptionsData options) { - using var message = Connection.CreateMessage(MessageType.Reliable); + using var message = MessageWriter.Get(MessageType.Reliable); + var games = _gameManager.FindListings((MapFlags)options.MapId, options.NumImpostors, options.Keywords); var skeldGameCount = _gameManager.GetGameCount(MapFlags.Skeld); @@ -308,19 +310,19 @@ namespace Impostor.Server.Net Message16GetGameListV2.Serialize(message, skeldGameCount, miraHqGameCount, polusGameCount, games); - await message.SendAsync(); + return Connection.SendAsync(message); } - private async ValueTask SendDisconnectReason(DisconnectReason reason, string message = null) + private ValueTask SendDisconnectReason(DisconnectReason reason, string message = null) { if (Connection == null) { - return; + return default; } - using var packet = Connection.CreateMessage(MessageType.Reliable); + using var packet = MessageWriter.Get(MessageType.Reliable); Message01JoinGame.SerializeError(packet, false, reason, message); - await packet.SendAsync(); + return Connection.SendAsync(packet); } } } \ No newline at end of file diff --git a/src/Impostor.Server/Net/ClientBase.cs b/src/Impostor.Server/Net/ClientBase.cs index ec2efcb..3dda4ca 100644 --- a/src/Impostor.Server/Net/ClientBase.cs +++ b/src/Impostor.Server/Net/ClientBase.cs @@ -29,7 +29,7 @@ namespace Impostor.Server.Net public ClientPlayer Player { get; set; } - public abstract ValueTask HandleMessageAsync(IMessage message); + public abstract ValueTask HandleMessageAsync(IMessageReader message, MessageType messageType); public abstract ValueTask HandleDisconnectAsync(string reason); } diff --git a/src/Impostor.Server/Net/Hazel/HazelConnection.cs b/src/Impostor.Server/Net/Hazel/HazelConnection.cs index e2694f8..e80e2ef 100644 --- a/src/Impostor.Server/Net/Hazel/HazelConnection.cs +++ b/src/Impostor.Server/Net/Hazel/HazelConnection.cs @@ -1,20 +1,16 @@ -using System; -using System.Net; +using System.Net; using System.Threading.Tasks; using Hazel; using Impostor.Api.Net.Messages; -using Impostor.Server.Hazel.Messages; -using Impostor.Server.Net.Hazel.Messages; -using Impostor.Server.Net.Messages; using Microsoft.Extensions.Logging; namespace Impostor.Server.Net.Hazel { internal partial class HazelConnection { - private readonly ILogger _logger; + private readonly ILogger _logger; - public HazelConnection(Connection innerConnection, ILogger logger) + public HazelConnection(Connection innerConnection, ILogger logger) { _logger = logger; InnerConnection = innerConnection; @@ -30,6 +26,11 @@ namespace Impostor.Server.Net.Hazel public ClientBase Client { get; set; } + public ValueTask SendAsync(IMessageWriter writer) + { + return InnerConnection.Send(writer); + } + private async ValueTask ConnectionOnDisconnected(DisconnectedEventArgs e) { if (Client != null) @@ -53,23 +54,8 @@ namespace Impostor.Server.Net.Hazel break; } - var reader = e.Message.ReadMessage(); - var type = e.SendOption switch - { - SendOption.None => MessageType.Unreliable, - SendOption.Reliable => MessageType.Reliable, - _ => throw new NotSupportedException() - }; - - using var message = new HazelMessage(reader, type); - - await Client.HandleMessageAsync(message); + await Client.HandleMessageAsync(e.Message.ReadMessage(), e.Type); } } - - public IConnectionMessageWriter CreateMessage(MessageType messageType) - { - return new HazelConnectionMessageWriter(messageType, this); - } } } \ No newline at end of file diff --git a/src/Impostor.Server/Net/Hazel/Messages/BufferMessageReader.cs b/src/Impostor.Server/Net/Hazel/Messages/BufferMessageReader.cs deleted file mode 100644 index 8491835..0000000 --- a/src/Impostor.Server/Net/Hazel/Messages/BufferMessageReader.cs +++ /dev/null @@ -1,160 +0,0 @@ -using System; -using System.Buffers.Binary; -using System.Runtime.CompilerServices; -using System.Text; -using Impostor.Api.Net.Messages; -using Impostor.Server.Net.Messages; - -namespace Impostor.Server.Hazel.Messages -{ - public class BufferMessageReader : IMessageReader - { - public byte Tag { get; } - public ReadOnlyMemory Buffer { get; } - public int Position { get; set; } - public int Length => Buffer.Length; - - public BufferMessageReader(byte tag, ReadOnlyMemory buffer) - { - Tag = tag; - Buffer = buffer; - } - - public IMessageReader ReadMessage() - { - var length = ReadUInt16(); - var tag = ReadByte(); - var pos = Position; - - Position += length; - - return new BufferMessageReader(tag, Buffer.Slice(pos, length)); - } - - public bool ReadBoolean() - { - byte val = FastByte(); - return val != 0; - } - - public sbyte ReadSByte() - { - return (sbyte)FastByte(); - } - - public byte ReadByte() - { - return FastByte(); - } - - public ushort ReadUInt16() - { - var output = BinaryPrimitives.ReadUInt16LittleEndian(Buffer.Span.Slice(Position)); - Position += sizeof(ushort); - return output; - } - - public short ReadInt16() - { - var output = BinaryPrimitives.ReadInt16LittleEndian(Buffer.Span.Slice(Position)); - Position += sizeof(short); - return output; - } - - public uint ReadUInt32() - { - var output = BinaryPrimitives.ReadUInt32LittleEndian(Buffer.Span.Slice(Position)); - Position += sizeof(uint); - return output; - } - - public int ReadInt32() - { - var output = BinaryPrimitives.ReadInt32LittleEndian(Buffer.Span.Slice(Position)); - Position += sizeof(int); - return output; - } - - public float ReadSingle() - { - var output = BinaryPrimitives.ReadSingleLittleEndian(Buffer.Span.Slice(Position)); - Position += sizeof(float); - return output; - } - - public string ReadString() - { - var len = ReadPackedInt32(); - var output = Encoding.UTF8.GetString(Buffer.Span.Slice(Position, len)); - Position += len; - return output; - } - - public ReadOnlyMemory ReadBytesAndSize() - { - var len = ReadPackedInt32(); - return ReadBytes(len); - } - - public ReadOnlyMemory ReadBytes(int length) - { - var output = Buffer.Slice(Position, length); - Position += length; - return output; - } - - public int ReadPackedInt32() - { - return (int)ReadPackedUInt32(); - } - - public uint ReadPackedUInt32() - { - bool readMore = true; - int shift = 0; - uint output = 0; - - while (readMore) - { - byte b = ReadByte(); - if (b >= 0x80) - { - readMore = true; - b ^= 0x80; - } - else - { - readMore = false; - } - - output |= (uint)(b << shift); - shift += 7; - } - - return output; - } - - public void CopyTo(IMessageWriter writer) - { - writer.Write((ushort) Length); - writer.Write(Tag); - writer.Write(Buffer); - } - - public IMessageReader Slice(int start) - { - return new BufferMessageReader(Tag, Buffer.Slice(start)); - } - - public IMessageReader Slice(int start, int length) - { - return new BufferMessageReader(Tag, Buffer.Slice(start, length)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private byte FastByte() - { - return Buffer.Span[Position++]; - } - } -} \ No newline at end of file diff --git a/src/Impostor.Server/Net/Hazel/Messages/HazelConnectionMessageWriter.cs b/src/Impostor.Server/Net/Hazel/Messages/HazelConnectionMessageWriter.cs deleted file mode 100644 index 4c77514..0000000 --- a/src/Impostor.Server/Net/Hazel/Messages/HazelConnectionMessageWriter.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Threading.Tasks; -using Impostor.Api.Net; -using Impostor.Api.Net.Messages; -using Impostor.Server.Net; -using Impostor.Server.Net.Messages; - -namespace Impostor.Server.Hazel.Messages -{ - internal class HazelConnectionMessageWriter : HazelMessageWriter, IConnectionMessageWriter - { - private readonly Net.Hazel.HazelConnection _connection; - - public HazelConnectionMessageWriter(MessageType type, Net.Hazel.HazelConnection connection) - : base(type) - { - _connection = connection; - } - - public IConnection Connection => _connection; - - public async ValueTask SendAsync() - { - await _connection.InnerConnection.Send(Writer); - } - } -} \ No newline at end of file diff --git a/src/Impostor.Server/Net/Hazel/Messages/HazelGameMessageWriter.cs b/src/Impostor.Server/Net/Hazel/Messages/HazelGameMessageWriter.cs deleted file mode 100644 index 3e4f6e2..0000000 --- a/src/Impostor.Server/Net/Hazel/Messages/HazelGameMessageWriter.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Hazel; -using Impostor.Api.Net; -using Impostor.Api.Net.Messages; -using Impostor.Server.Net; -using Impostor.Server.Net.Messages; -using Impostor.Server.Net.State; - -namespace Impostor.Server.Hazel.Messages -{ - internal class HazelGameMessageWriter : HazelMessageWriter, IGameMessageWriter - { - private readonly Game _game; - - public HazelGameMessageWriter(MessageType type, Game game) - : base(type) - { - _game = game; - } - - private IEnumerable GetConnections(Func filter) - { - return _game.Players - .Where(filter) - .Select(p => p.Client.Connection) - .OfType() - .Select(c => c.InnerConnection); - } - - public ValueTask SendToAllAsync(LimboStates states) - { - foreach (var connection in GetConnections(x => x.Limbo.HasFlag(states))) - { - connection.Send(Writer); - } - - return default; - } - - public ValueTask SendToAllExceptAsync(int senderId, LimboStates states) - { - foreach (var connection in GetConnections(x => - x.Limbo.HasFlag(states) && - x.Client.Id != senderId)) - { - connection.Send(Writer); - } - return default; - } - - public ValueTask SendToAsync(int id) - { - if (_game.TryGetPlayer(id, out var player) - && player.Client.Connection is Net.Hazel.HazelConnection hazelConnection) - { - hazelConnection.InnerConnection.Send(Writer); - } - - return default; - } - } -} \ No newline at end of file diff --git a/src/Impostor.Server/Net/Hazel/Messages/HazelMessage.cs b/src/Impostor.Server/Net/Hazel/Messages/HazelMessage.cs deleted file mode 100644 index 8799c48..0000000 --- a/src/Impostor.Server/Net/Hazel/Messages/HazelMessage.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using Hazel; -using Impostor.Api.Net.Messages; -using Impostor.Server.Hazel.Messages; -using Impostor.Server.Net.Messages; - -namespace Impostor.Server.Net.Hazel.Messages -{ - internal class HazelMessage : IMessage, IDisposable - { - private bool _isDisposed; - private readonly MessageReader _reader; - - public HazelMessage(MessageReader reader, MessageType type) - { - _reader = reader; - Type = type; - } - - public MessageType Type { get; } - - public IMessageReader CreateReader() - { - if (_isDisposed) - { - throw new ObjectDisposedException(nameof(_reader)); - } - - return new BufferMessageReader(_reader.Tag, _reader.Buffer); - } - - private void Dispose(bool disposing) - { - if (disposing) - { - _isDisposed = true; - } - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - ~HazelMessage() - { - Dispose(false); - } - } -} \ No newline at end of file diff --git a/src/Impostor.Server/Net/Hazel/Messages/HazelMessageWriter.cs b/src/Impostor.Server/Net/Hazel/Messages/HazelMessageWriter.cs deleted file mode 100644 index c43cdfb..0000000 --- a/src/Impostor.Server/Net/Hazel/Messages/HazelMessageWriter.cs +++ /dev/null @@ -1,128 +0,0 @@ -using System; -using System.Net; -using Hazel; -using Impostor.Api.Games; -using Impostor.Api.Net.Messages; -using Impostor.Server.Net.Messages; - -namespace Impostor.Server.Hazel.Messages -{ - internal abstract class HazelMessageWriter : IMessageWriter - { - protected readonly MessageWriter Writer; - - protected HazelMessageWriter(MessageType type) - { - Writer = MessageWriter.Get(ToSendOption(type)); - } - - private static SendOption ToSendOption(MessageType type) - { - return type switch - { - MessageType.Unreliable => SendOption.None, - MessageType.Reliable => SendOption.Reliable, - _ => throw new NotSupportedException($"Message type {type} is not supported") - }; - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - Writer.Recycle(); - } - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - public void Write(bool value) - { - Writer.Write(value); - } - - public void Write(sbyte value) - { - Writer.Write(value); - } - - public void Write(byte value) - { - Writer.Write(value); - } - - public void Write(short value) - { - Writer.Write(value); - } - - public void Write(ushort value) - { - Writer.Write(value); - } - - public void Write(uint value) - { - Writer.Write(value); - } - - public void Write(int value) - { - Writer.Write(value); - } - - public void Write(float value) - { - Writer.Write(value); - } - - public void Write(string value) - { - Writer.Write(value); - } - - public void Write(IPAddress value) - { - Writer.Write(value.GetAddressBytes()); - } - - public void WritePacked(int value) - { - Writer.WritePacked(value); - } - - public void WritePacked(uint value) - { - Writer.WritePacked(value); - } - - public void Write(ReadOnlyMemory data) - { - Writer.Write(data.ToArray()); // TODO: Fix memory allocation. - } - - public void StartMessage(byte typeFlag) - { - Writer.StartMessage(typeFlag); - } - - public void Write(GameCode value) - { - Write(value.Value); - } - - public void EndMessage() - { - Writer.EndMessage(); - } - - public void Clear(MessageType type) - { - Writer.Clear(ToSendOption(type)); - } - } -} \ No newline at end of file diff --git a/src/Impostor.Server/Net/Manager/ClientManager.cs b/src/Impostor.Server/Net/Manager/ClientManager.cs index 7a62fde..4a6a996 100644 --- a/src/Impostor.Server/Net/Manager/ClientManager.cs +++ b/src/Impostor.Server/Net/Manager/ClientManager.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using Hazel; using Impostor.Api.Innersloth; using Impostor.Api.Innersloth.Data; using Impostor.Api.Net; @@ -56,17 +57,17 @@ namespace Impostor.Server.Net.Manager { if (name.Length > 10) { - using var packet = connection.CreateMessage(MessageType.Reliable); + using var packet = MessageWriter.Get(MessageType.Reliable); Message01JoinGame.SerializeError(packet, false, DisconnectReason.Custom, DisconnectMessages.UsernameLength); - await packet.SendAsync(); + await connection.SendAsync(packet); return; } if (!SupportedVersions.Contains(clientVersion)) { - using var packet = connection.CreateMessage(MessageType.Reliable); + using var packet = MessageWriter.Get(MessageType.Reliable); Message01JoinGame.SerializeError(packet, false, DisconnectReason.IncorrectVersion); - await packet.SendAsync(); + await connection.SendAsync(packet); return; } diff --git a/src/Impostor.Server/Net/Redirector/ClientRedirector.cs b/src/Impostor.Server/Net/Redirector/ClientRedirector.cs index acdb9cf..a9ffa68 100644 --- a/src/Impostor.Server/Net/Redirector/ClientRedirector.cs +++ b/src/Impostor.Server/Net/Redirector/ClientRedirector.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using Hazel; using Impostor.Api.Innersloth; using Impostor.Api.Innersloth.Data; using Impostor.Api.Net.Messages; @@ -32,9 +33,8 @@ namespace Impostor.Server.Net.Redirector _nodeLocator = nodeLocator; } - public override async ValueTask HandleMessageAsync(IMessage message) + public override async ValueTask HandleMessageAsync(IMessageReader reader, MessageType messageType) { - var reader = message.CreateReader(); var flag = reader.Tag; Logger.Verbose("Server got {0}.", flag); @@ -43,9 +43,9 @@ namespace Impostor.Server.Net.Redirector { case MessageFlags.HostGame: { - using var packet = Connection.CreateMessage(MessageType.Reliable); + using var packet = MessageWriter.Get(MessageType.Reliable); Message13Redirect.Serialize(packet, false, _nodeProvider.Get()); - await packet.SendAsync(); + await Connection.SendAsync(packet); break; } @@ -56,7 +56,7 @@ namespace Impostor.Server.Net.Redirector out var gameCode, out _); - using var packet = Connection.CreateMessage(MessageType.Reliable); + using var packet = MessageWriter.Get(MessageType.Reliable); var endpoint = _nodeLocator.Find(GameCodeParser.IntToGameName(gameCode)); if (endpoint == null) { @@ -67,16 +67,16 @@ namespace Impostor.Server.Net.Redirector Message13Redirect.Serialize(packet, false, endpoint); } - await packet.SendAsync(); + await Connection.SendAsync(packet); break; } case MessageFlags.GetGameListV2: { // TODO: Implement. - using var packet = Connection.CreateMessage(MessageType.Reliable); + using var packet = MessageWriter.Get(MessageType.Reliable); Message01JoinGame.SerializeError(packet, false, DisconnectReason.Custom, DisconnectMessages.NotImplemented); - await packet.SendAsync(); + await Connection.SendAsync(packet); break; } diff --git a/src/Impostor.Server/Net/State/Game.Api.cs b/src/Impostor.Server/Net/State/Game.Api.cs index b90394f..a0d8b6f 100644 --- a/src/Impostor.Server/Net/State/Game.Api.cs +++ b/src/Impostor.Server/Net/State/Game.Api.cs @@ -3,7 +3,7 @@ using Impostor.Api.Net; namespace Impostor.Server.Net.State { - internal partial class Game : IGame + internal partial class Game { IClientPlayer IGame.Host => Host; } diff --git a/src/Impostor.Server/Net/State/Game.Incoming.cs b/src/Impostor.Server/Net/State/Game.Incoming.cs index 9a502b4..b162c4d 100644 --- a/src/Impostor.Server/Net/State/Game.Incoming.cs +++ b/src/Impostor.Server/Net/State/Game.Incoming.cs @@ -1,9 +1,9 @@ using System.Threading.Tasks; +using Hazel; using Impostor.Api.Games; using Impostor.Api.Innersloth.Data; using Impostor.Api.Net; using Impostor.Api.Net.Messages; -using Impostor.Server.Net.Messages; namespace Impostor.Server.Net.State { @@ -13,9 +13,9 @@ namespace Impostor.Server.Net.State { GameState = GameStates.Started; - using var packet = CreateMessage(MessageType.Reliable); + using var packet = MessageWriter.Get(MessageType.Reliable); message.CopyTo(packet); - await packet.SendToAllAsync(); + await SendToAllAsync(packet); } public async ValueTask AddClientAsync(ClientBase client) @@ -83,10 +83,10 @@ namespace Impostor.Server.Net.State GameState = GameStates.Ended; // Broadcast end of the game. - using (var packet = CreateMessage(MessageType.Reliable)) + using (var packet = MessageWriter.Get(MessageType.Reliable)) { message.CopyTo(packet); - await packet.SendToAllAsync(); + await SendToAllAsync(packet); } // Put all players in the correct limbo state. @@ -100,9 +100,9 @@ namespace Impostor.Server.Net.State { IsPublic = isPublic; - using var packet = CreateMessage(MessageType.Reliable); + using var packet = MessageWriter.Get(MessageType.Reliable); message.CopyTo(packet); - await packet.SendToAllExceptAsync(sender.Client.Id); + await SendToAllExceptAsync(packet, sender.Client.Id); } public async ValueTask HandleRemovePlayer(int playerId, DisconnectReason reason) @@ -115,21 +115,21 @@ namespace Impostor.Server.Net.State return; } - using var packet = CreateMessage(MessageType.Reliable); + using var packet = MessageWriter.Get(MessageType.Reliable); WriteRemovePlayerMessage(packet, false, playerId, reason); - await packet.SendToAllExceptAsync(playerId); + await SendToAllExceptAsync(packet, playerId); } public async ValueTask HandleKickPlayer(int playerId, bool isBan) { Logger.Information("{0} - Player {1} has left.", Code, playerId); - using var message = CreateMessage(MessageType.Reliable); + using var message = MessageWriter.Get(MessageType.Reliable); // Send message to everyone that this player was kicked. WriteKickPlayerMessage(message, false, playerId, isBan); - await message.SendToAllAsync(); + await SendToAllAsync(message); await PlayerRemove(playerId, isBan); // Remove the player from everyone's game. @@ -138,7 +138,8 @@ namespace Impostor.Server.Net.State true, playerId, isBan ? DisconnectReason.Banned : DisconnectReason.Kicked); - await message.SendToAllExceptAsync(playerId); + + await SendToAllExceptAsync(message, playerId); } private async ValueTask HandleJoinGameNew(ClientPlayer sender, bool isNew) @@ -151,14 +152,14 @@ namespace Impostor.Server.Net.State await PlayerAdd(sender); } - using (var message = CreateMessage(MessageType.Reliable)) + using (var message = MessageWriter.Get(MessageType.Reliable)) { WriteJoinedGameMessage(message, false, sender); WriteAlterGameMessage(message, false, IsPublic); sender.Limbo = LimboStates.NotLimbo; - await message.SendToAsync(sender); + await SendToAsync(message, sender.Client.Id); await BroadcastJoinMessage(message, true, sender); } } @@ -188,12 +189,13 @@ namespace Impostor.Server.Net.State sender.Limbo = LimboStates.WaitingForHost; - using var packet = CreateMessage(MessageType.Reliable); - - WriteWaitForHostMessage(packet, false, sender); - await packet.SendToAsync(sender.Client); + using (var packet = MessageWriter.Get(MessageType.Reliable)) + { + WriteWaitForHostMessage(packet, false, sender); - await BroadcastJoinMessage(packet, true, sender); + await SendToAsync(packet, sender.Client.Id); + await BroadcastJoinMessage(packet, true, sender); + } } } } \ 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 index 2fc4f3c..bc832e4 100644 --- a/src/Impostor.Server/Net/State/Game.Outgoing.cs +++ b/src/Impostor.Server/Net/State/Game.Outgoing.cs @@ -1,13 +1,47 @@ using System.Linq; +using System.Threading.Tasks; using Impostor.Api.Innersloth.Data; using Impostor.Api.Net; using Impostor.Api.Net.Messages; +using Impostor.Server.Net.Hazel; using Impostor.Server.Net.Messages; namespace Impostor.Server.Net.State { internal partial class Game { + public ValueTask SendToAllAsync(IMessageWriter writer, LimboStates states = LimboStates.NotLimbo) + { + foreach (var connection in GetConnections(x => x.Limbo.HasFlag(states))) + { + connection.Send(writer); + } + + return default; + } + + public ValueTask SendToAllExceptAsync(IMessageWriter writer, int senderId, LimboStates states = LimboStates.NotLimbo) + { + foreach (var connection in GetConnections(x => + x.Limbo.HasFlag(states) && + x.Client.Id != senderId)) + { + connection.Send(writer); + } + + return default; + } + + public ValueTask SendToAsync(IMessageWriter writer, int id) + { + if (TryGetPlayer(id, out var player) && player.Client.Connection is HazelConnection hazelConnection) + { + hazelConnection.InnerConnection.Send(writer); + } + + return default; + } + private void WriteRemovePlayerMessage(IMessageWriter message, bool clear, int playerId, DisconnectReason reason) { Message04RemovePlayer.Serialize(message, clear, Code, playerId, HostId, reason); diff --git a/src/Impostor.Server/Net/State/Game.State.cs b/src/Impostor.Server/Net/State/Game.State.cs index ab9dfbb..60f6e97 100644 --- a/src/Impostor.Server/Net/State/Game.State.cs +++ b/src/Impostor.Server/Net/State/Game.State.cs @@ -1,5 +1,6 @@ using System.Linq; using System.Threading.Tasks; +using Hazel; using Impostor.Api; using Impostor.Api.Events; using Impostor.Api.Innersloth.Data; @@ -95,7 +96,7 @@ namespace Impostor.Server.Net.State private async ValueTask CheckLimboPlayers() { - using var message = CreateMessage(MessageType.Reliable); + using var message = MessageWriter.Get(MessageType.Reliable); foreach (var (_, player) in _players.Where(x => x.Value.Limbo == LimboStates.WaitingForHost)) { @@ -103,7 +104,8 @@ namespace Impostor.Server.Net.State WriteAlterGameMessage(message, false, IsPublic); player.Limbo = LimboStates.NotLimbo; - await message.SendToAsync(player.Client); + + await SendToAsync(message, player.Client.Id); } } } diff --git a/src/Impostor.Server/Net/State/Game.cs b/src/Impostor.Server/Net/State/Game.cs index 4654c34..4b7f014 100644 --- a/src/Impostor.Server/Net/State/Game.cs +++ b/src/Impostor.Server/Net/State/Game.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; using System.Threading.Tasks; +using Hazel; using Impostor.Api.Events.Managers; using Impostor.Api.Games; using Impostor.Api.Innersloth; @@ -11,7 +12,7 @@ using Impostor.Api.Innersloth.Data; using Impostor.Api.Net; using Impostor.Api.Net.Messages; using Impostor.Server.Hazel; -using Impostor.Server.Hazel.Messages; +using Impostor.Server.Net.Hazel; using Impostor.Server.Net.Manager; using Impostor.Server.Net.Messages; using Impostor.Server.Net.Redirector; @@ -20,7 +21,7 @@ using ILogger = Serilog.ILogger; namespace Impostor.Server.Net.State { - internal partial class Game + internal partial class Game : IGame { private static readonly ILogger Logger = Log.ForContext(); @@ -79,11 +80,6 @@ namespace Impostor.Server.Net.State public IEnumerable Players => _players.Select(p => p.Value); - public IGameMessageWriter CreateMessage(MessageType type) - { - return new HazelGameMessageWriter(type, this); - } - public bool TryGetPlayer(int id, out ClientPlayer player) { if (_players.TryGetValue(id, out var result)) @@ -101,11 +97,20 @@ namespace Impostor.Server.Net.State return _gameManager.RemoveAsync(Code); } - private ValueTask BroadcastJoinMessage(IGameMessageWriter message, bool clear, ClientPlayer player) + private ValueTask BroadcastJoinMessage(IMessageWriter message, bool clear, ClientPlayer player) { Message01JoinGame.SerializeJoin(message, clear, Code, player.Client.Id, HostId); - return message.SendToAllExceptAsync(player.Client.Id); + return SendToAllExceptAsync(message, player.Client.Id); + } + + private IEnumerable GetConnections(Func filter) + { + return Players + .Where(filter) + .Select(p => p.Client.Connection) + .OfType() + .Select(c => c.InnerConnection); } } } \ No newline at end of file diff --git a/src/Impostor.Tests/Hazel/BufferMessageReaderTests.cs b/src/Impostor.Tests/Hazel/BufferMessageReaderTests.cs index 840fde3..6e516ed 100644 --- a/src/Impostor.Tests/Hazel/BufferMessageReaderTests.cs +++ b/src/Impostor.Tests/Hazel/BufferMessageReaderTests.cs @@ -1,7 +1,4 @@ using Hazel; -using Impostor.Api.Net.Messages; -using Impostor.Server.Net.Hazel.Messages; -using Impostor.Server.Net.Messages; using Xunit; namespace Impostor.Tests.Hazel @@ -23,8 +20,7 @@ namespace Impostor.Tests.Hazel Assert.Equal(11, msg.Length); Assert.Equal(msg.Length, msg.Position); - var message = new HazelMessage(new MessageReader(msg.Buffer), MessageType.Reliable); - var reader = message.CreateReader(); + var reader = new MessageReader(msg.Buffer); Assert.Equal(Test1, reader.ReadInt32()); Assert.Equal(Test2, reader.ReadInt32()); @@ -45,8 +41,7 @@ namespace Impostor.Tests.Hazel Assert.Equal(5, msg.Length); Assert.Equal(msg.Length, msg.Position); - var message = new HazelMessage(new MessageReader(msg.Buffer), MessageType.Reliable); - var reader = message.CreateReader(); + var reader = new MessageReader(msg.Buffer); Assert.Equal(Test1, reader.ReadBoolean()); Assert.Equal(Test2, reader.ReadBoolean()); @@ -67,8 +62,7 @@ namespace Impostor.Tests.Hazel Assert.Equal(msg.Length, msg.Position); - var message = new HazelMessage(new MessageReader(msg.Buffer), MessageType.Reliable); - var reader = message.CreateReader(); + var reader = new MessageReader(msg.Buffer); Assert.Equal(Test1, reader.ReadString()); Assert.Equal(Test2, reader.ReadString()); @@ -89,8 +83,7 @@ namespace Impostor.Tests.Hazel Assert.Equal(7, msg.Length); Assert.Equal(msg.Length, msg.Position); - var message = new HazelMessage(new MessageReader(msg.Buffer), MessageType.Reliable); - var reader = message.CreateReader(); + var reader = new MessageReader(msg.Buffer); Assert.Equal(Test1, reader.ReadSingle()); } @@ -111,8 +104,7 @@ namespace Impostor.Tests.Hazel msg.EndMessage(); - var message = new HazelMessage(new MessageReader(msg.Buffer), MessageType.Reliable); - var handleMessage = message.CreateReader(); + var handleMessage = new MessageReader(msg.Buffer); Assert.Equal(1, handleMessage.Tag); var parentReader = handleMessage.Slice(handleMessage.Position); @@ -142,8 +134,7 @@ namespace Impostor.Tests.Hazel Assert.Equal(msg.Length, msg.Position); - var message = new HazelMessage(new MessageReader(msg.Buffer), MessageType.Reliable); - var reader = message.CreateReader(); + var reader = new MessageReader(msg.Buffer); Assert.Equal(1, reader.Tag); Assert.Equal(65534, reader.ReadInt32()); // Content diff --git a/src/Impostor.Tools.Proxy/Program.cs b/src/Impostor.Tools.Proxy/Program.cs index 7af07f3..3023420 100644 --- a/src/Impostor.Tools.Proxy/Program.cs +++ b/src/Impostor.Tools.Proxy/Program.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using Hazel; using Hazel.Udp; +using Impostor.Api.Net.Messages; using PcapDotNet.Core; using PcapDotNet.Packets; @@ -68,9 +69,9 @@ namespace Impostor.Tools.Proxy // True if this is our own packet. using (var stream = udp.Payload.ToMemoryStream()) { - var reader = new MessageReader(stream.ToArray()); + var reader = (IMessageReader) new MessageReader(stream.ToArray()); var option = reader.Buffer.Span[0]; - if (option == (byte) SendOption.Reliable) + if (option == (byte) MessageType.Reliable) { reader = reader.Slice(3); } @@ -114,7 +115,7 @@ namespace Impostor.Tools.Proxy } } - private static void HandleToClient(string source, MessageReader packet) + private static void HandleToClient(string source, IMessageReader packet) { var tagName = TagMap.ContainsKey(packet.Tag) ? TagMap[packet.Tag] : "Unknown"; Console.ForegroundColor = ConsoleColor.Cyan; @@ -124,7 +125,7 @@ namespace Impostor.Tools.Proxy { case 14: case 13: - packet.Position = packet.Length; + // packet.Position = packet.Length; break; case 0: Console.WriteLine("- GameCode " + packet.ReadInt32()); @@ -132,7 +133,7 @@ namespace Impostor.Tools.Proxy case 5: case 6: Console.WriteLine(HexUtils.HexDump(packet.Buffer.ToArray().Take(packet.Length).ToArray())); - packet.Position = packet.Length; + // packet.Position = packet.Length; break; case 7: Console.WriteLine("- GameCode " + packet.ReadInt32()); @@ -153,7 +154,7 @@ namespace Impostor.Tools.Proxy } } - private static void HandleToServer(string source, MessageReader packet) + private static void HandleToServer(string source, IMessageReader packet) { var tagName = TagMap.ContainsKey(packet.Tag) ? TagMap[packet.Tag] : "Unknown"; Console.ForegroundColor = ConsoleColor.White; @@ -172,7 +173,7 @@ namespace Impostor.Tools.Proxy case 6: Console.WriteLine("- GameCode " + packet.ReadInt32()); Console.WriteLine(HexUtils.HexDump(packet.Buffer.ToArray().Take(packet.Length).ToArray())); - packet.Position = packet.Length; + // packet.Position = packet.Length; break; } }