--- /dev/null
+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
using System.Collections.Generic;
using System.Net;
+using System.Threading.Tasks;
using Impostor.Api.Innersloth;
using Impostor.Api.Innersloth.Data;
using Impostor.Api.Net;
int HostId { get; }
- IGameMessageWriter CreateMessage(MessageType type);
+ /// <summary>
+ /// Send the message to all players.
+ /// </summary>
+ /// <param name="writer">Message to send.</param>
+ /// <param name="states">Required limbo state of the player.</param>
+ /// <returns>A <see cref="ValueTask"/> representing the asynchronous operation.</returns>
+ ValueTask SendToAllAsync(IMessageWriter writer, LimboStates states = LimboStates.NotLimbo);
+
+ /// <summary>
+ /// Send the message to all players except one.
+ /// </summary>
+ /// <param name="writer">Message to send.</param>
+ /// <param name="senderId">The player to exclude from sending the message.</param>
+ /// <param name="states">Required limbo state of the player.</param>
+ /// <returns>A <see cref="ValueTask"/> representing the asynchronous operation.</returns>
+ ValueTask SendToAllExceptAsync(IMessageWriter writer, int senderId, LimboStates states = LimboStates.NotLimbo);
+
+ /// <summary>
+ /// Send a message to a specific player.
+ /// </summary>
+ /// <param name="writer">Message to send.</param>
+ /// <param name="id">ID of the client.</param>
+ /// <returns>A <see cref="ValueTask"/> representing the asynchronous operation.</returns>
+ ValueTask SendToAsync(IMessageWriter writer, int id);
}
}
\ No newline at end of file
+++ /dev/null
-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
using System.Net;
-using Impostor.Api.Games;
+using System.Threading.Tasks;
using Impostor.Api.Net.Messages;
namespace Impostor.Api.Net
IClient? Client { get; }
/// <summary>
- /// Create a message writer that can be send to the connection.
+ /// Sends a message writer to the connection.
/// </summary>
- /// <remarks>
- /// Be aware when implementing a custom connection handler that this method is not called when a message
- /// is being send in <see cref="IGame"/>.
- /// </remarks>
- /// <param name="messageType">Type of the message.</param>
- /// <returns>Message writer for the current connection.</returns>
- IConnectionMessageWriter CreateMessage(MessageType messageType);
+ /// <param name="writer">The message.</param>
+ /// <returns></returns>
+ ValueTask SendAsync(IMessageWriter writer);
}
}
\ No newline at end of file
+++ /dev/null
-using System.Threading.Tasks;
-
-namespace Impostor.Api.Net.Messages
-{
- /// <summary>
- /// Represents the message writer for <see cref="IConnection"/>.
- /// </summary>
- public interface IConnectionMessageWriter : IMessageWriter
- {
- /// <summary>
- /// Gets the connection where the message writer belongs to.
- /// </summary>
- public IConnection Connection { get; }
-
- /// <summary>
- /// Sends the message to the <see cref="Connection"/>.
- /// </summary>
- /// <returns>Task.</returns>
- ValueTask SendAsync();
- }
-}
\ No newline at end of file
+++ /dev/null
-using System.Threading.Tasks;
-using Impostor.Api.Games;
-
-namespace Impostor.Api.Net.Messages
-{
- /// <summary>
- /// Represents the message writer for <see cref="IGame"/>.
- /// </summary>
- public interface IGameMessageWriter : IMessageWriter
- {
- /// <summary>
- /// Send the message to all players.
- /// </summary>
- /// <param name="states">Required limbo state of the player.</param>
- /// <returns>A <see cref="ValueTask"/> representing the asynchronous operation.</returns>
- ValueTask SendToAllAsync(LimboStates states = LimboStates.NotLimbo);
-
- /// <summary>
- /// Send the message to all players except one.
- /// </summary>
- /// <param name="senderId">The player to exclude from sending the message.</param>
- /// <param name="states">Required limbo state of the player.</param>
- /// <returns>A <see cref="ValueTask"/> representing the asynchronous operation.</returns>
- ValueTask SendToAllExceptAsync(int senderId, LimboStates states = LimboStates.NotLimbo);
-
- /// <summary>
- /// Send a message to a specific player.
- /// </summary>
- /// <param name="id">ID of the client.</param>
- /// <returns>A <see cref="ValueTask"/> representing the asynchronous operation.</returns>
- ValueTask SendToAsync(int id);
- }
-}
\ No newline at end of file
+++ /dev/null
-namespace Impostor.Api.Net.Messages
-{
- public interface IMessage
- {
- MessageType Type { get; }
-
- IMessageReader CreateReader();
- }
-}
\ No newline at end of file
/// </summary>
public interface IMessageWriter : IDisposable
{
+ public byte[] Buffer { get; }
+
+ public int Length { get; set; }
+
+ public int Position { get; set; }
+
+ public MessageType SendOption { get; }
+
/// <summary>
/// Writes a boolean to the message.
/// </summary>
-namespace Impostor.Api.Net.Messages
+using System;
+
+namespace Impostor.Api.Net.Messages
{
/// <summary>
/// Specifies how a message should be sent between connections.
/// </summary>
- public enum MessageType
+ [Flags]
+ public enum MessageType : byte
{
/// <summary>
/// Requests unreliable delivery with no fragmentation.
using System;
using System.Net;
using System.Threading.Tasks;
+using Impostor.Api.Net.Messages;
using Serilog;
namespace Hazel
}
/// <summary>
- /// Sends a number of bytes to the end point of the connection using the specified <see cref="SendOption"/>.
+ /// Sends a number of bytes to the end point of the connection using the specified <see cref="MessageType"/>.
/// </summary>
/// <param name="msg">The message to send.</param>
/// <remarks>
/// <include file="DocInclude/common.xml" path="docs/item[@name='Connection_SendBytes_General']/*" />
/// <para>
- /// 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.
/// </para>
/// </remarks>
- public abstract ValueTask Send(MessageWriter msg);
+ public abstract ValueTask Send(IMessageWriter msg);
/// <summary>
- /// Sends a number of bytes to the end point of the connection using the specified <see cref="SendOption"/>.
+ /// Sends a number of bytes to the end point of the connection using the specified <see cref="MessageType"/>.
/// </summary>
/// <param name="bytes">The bytes of the message to send.</param>
- /// <param name="sendOption">The option specifying how the message should be sent.</param>
+ /// <param name="messageType">The option specifying how the message should be sent.</param>
/// <remarks>
/// <include file="DocInclude/common.xml" path="docs/item[@name='Connection_SendBytes_General']/*" />
/// <para>
- /// 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.
/// </para>
/// </remarks>
- public abstract ValueTask SendBytes(byte[] bytes, SendOption sendOption = SendOption.None);
+ public abstract ValueTask SendBytes(byte[] bytes, MessageType messageType = MessageType.Unreliable);
/// <summary>
/// Connects the connection to a server and begins listening.
/// Invokes the DataReceived event.
/// </summary>
/// <param name="msg">The bytes received.</param>
- /// <param name="sendOption">The <see cref="SendOption"/> the message was received with.</param>
+ /// <param name="messageType">The <see cref="MessageType"/> the message was received with.</param>
/// <remarks>
/// Invokes the <see cref="DataReceived"/> 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.
/// </remarks>
- 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;
{
try
{
- await handler(new DataReceivedEventArgs(this, msg, sendOption));
+ await handler(new DataReceivedEventArgs(this, msg, messageType));
}
catch (Exception e)
{
/// 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.
/// </remarks>
- 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;
using System;
using System.Threading.Tasks;
+using Impostor.Api.Net.Messages;
using Serilog;
namespace Hazel
/// Implementers should call this to invoke the <see cref="NewConnection"/> event before data is received so that
/// subscribers do not miss any data that may have been sent immediately after connecting.
/// </remarks>
- 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;
-namespace Hazel
+using Impostor.Api.Net.Messages;
+
+namespace Hazel
{
public struct DataReceivedEventArgs
{
/// <summary>
/// The bytes received from the client.
/// </summary>
- public readonly MessageReader Message;
+ public readonly IMessageReader Message;
/// <summary>
- /// The <see cref="SendOption"/> the data was sent with.
+ /// The <see cref="Type"/> the data was sent with.
/// </summary>
- 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;
}
}
}
using System;
+using Impostor.Api.Net.Messages;
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.
/// </summary>
- 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;
<PackageReference Include="Serilog" Version="2.10.0" />
</ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Impostor.Api\Impostor.Api.csproj" />
+ </ItemGroup>
+
</Project>
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<byte> Buffer { get; }
Buffer = buffer;
}
- public MessageReader ReadMessage()
+ public IMessageReader ReadMessage()
{
var length = ReadUInt16();
var tag = ReadByte();
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));
}
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<MessageWriter> WriterPool = new ObjectPool<MessageWriter>(() => 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<int> messageStarts = new Stack<int>();
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)
{
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);
///
/// <param name="sendOption">The option specifying how the message should be sent.</param>
- public static MessageWriter Get(SendOption sendOption = SendOption.None)
+ public static MessageWriter Get(MessageType sendOption = MessageType.Unreliable)
{
var output = WriterPool.GetObject();
output.Clear(sendOption);
public bool HasBytes(int expected)
{
- if (this.SendOption == SendOption.None)
+ if (this.SendOption == MessageType.Unreliable)
{
return this.Length > 1 + expected;
}
return this.Length > 3 + expected;
}
+ public void Write(GameCode value)
+ {
+ this.Write(value.Value);
+ }
+
///
public void StartMessage(byte typeFlag)
{
this.Length = this.Position;
}
- public void Clear(SendOption sendOption)
+ public void Clear(MessageType sendOption)
{
this.messageStarts.Clear();
this.SendOption = sendOption;
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;
}
this.Write(bytes);
}
+ public void Write(IPAddress value)
+ {
+ this.Write(value.GetAddressBytes());
+ }
+
public void WriteBytesAndSize(byte[] bytes)
{
this.WritePacked((uint)bytes.Length);
{
switch (msg.SendOption)
{
- case SendOption.None:
+ case MessageType.Unreliable:
offset = 1;
break;
- case SendOption.Reliable:
+ case MessageType.Reliable:
offset = 3;
break;
}
using System;
using System.Net;
using System.Threading.Tasks;
+using Impostor.Api.Net.Messages;
namespace Hazel
/// <summary>
/// Called when the socket has been disconnected at the remote host.
/// </summary>
- protected async ValueTask DisconnectRemote(string reason, MessageReader reader)
+ protected async ValueTask DisconnectRemote(string reason, IMessageReader reader)
{
if (this.SendDisconnect(null))
{
-namespace Hazel
+using Impostor.Api.Net.Messages;
+
+namespace Hazel
{
public struct NewConnectionEventArgs
{
/// The data received from the client in the handshake.
/// This data is yours. Remember to recycle it.
/// </summary>
- public readonly MessageReader HandshakeData;
+ public readonly IMessageReader HandshakeData;
/// <summary>
/// The <see cref="Connection"/> to the new client.
/// </summary>
public readonly Connection Connection;
- public NewConnectionEventArgs(MessageReader handshakeData, Connection connection)
+ public NewConnectionEventArgs(IMessageReader handshakeData, Connection connection)
{
this.HandshakeData = handshakeData;
this.Connection = connection;
+++ /dev/null
-using System;
-
-namespace Hazel
-{
- /// <summary>
- /// Specifies how a message should be sent between connections.
- /// </summary>
- [Flags]
- public enum SendOption : byte
- {
- /// <summary>
- /// Requests unreliable delivery with no framentation.
- /// </summary>
- /// <remarks>
- /// 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.
- /// </remarks>
- None = 0,
-
- /// <summary>
- /// Requests data be sent reliably but with no fragmentation.
- /// </summary>
- /// <remarks>
- /// 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.
- /// </remarks>
- Reliable = 1,
- }
-}
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
+using Impostor.Api.Net.Messages;
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);
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
+using Impostor.Api.Net.Messages;
using Serilog;
namespace Hazel.Udp
protected abstract ValueTask WriteBytesToConnection(byte[] bytes, int length);
/// <inheritdoc/>
- 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?");
switch (msg.SendOption)
{
- case SendOption.Reliable:
+ case MessageType.Reliable:
ResetKeepAliveTimer();
AttachReliableID(buffer, 1, buffer.Length);
/// <see cref="SendOption.None"/> until implemented.
/// </para>
/// </remarks>
- 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);
switch (sendOption)
{
case (byte)UdpSendOption.Ping:
- case (byte)SendOption.Reliable:
+ case (byte)MessageType.Reliable:
case (byte)UdpSendOption.Hello:
await ReliableSend(sendOption, data, ackCallback);
break;
switch (message.Buffer.Span[0])
{
//Handle reliable receives
- case (byte)SendOption.Reliable:
+ case (byte)MessageType.Reliable:
await ReliableMessageReceive(message);
break;
//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;
}
using System;
using System.Net;
using System.Threading.Tasks;
+using Impostor.Api.Net.Messages;
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;
using System;
using System.Threading.Tasks;
+using Hazel;
using Impostor.Api.Games;
using Impostor.Api.Innersloth;
using Impostor.Api.Innersloth.Data;
_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);
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;
}
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;
/// All options given.
/// At this moment, the client can only specify the map, impostor count and chat language.
/// </param>
- 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);
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
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);
}
-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<Net.Hazel.HazelConnection> _logger;
+ private readonly ILogger<HazelConnection> _logger;
- public HazelConnection(Connection innerConnection, ILogger<Net.Hazel.HazelConnection> logger)
+ public HazelConnection(Connection innerConnection, ILogger<HazelConnection> logger)
{
_logger = logger;
InnerConnection = innerConnection;
public ClientBase Client { get; set; }
+ public ValueTask SendAsync(IMessageWriter writer)
+ {
+ return InnerConnection.Send(writer);
+ }
+
private async ValueTask ConnectionOnDisconnected(DisconnectedEventArgs e)
{
if (Client != null)
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
+++ /dev/null
-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<byte> Buffer { get; }
- public int Position { get; set; }
- public int Length => Buffer.Length;
-
- public BufferMessageReader(byte tag, ReadOnlyMemory<byte> 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<byte> ReadBytesAndSize()
- {
- var len = ReadPackedInt32();
- return ReadBytes(len);
- }
-
- public ReadOnlyMemory<byte> 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
+++ /dev/null
-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
+++ /dev/null
-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<Connection> GetConnections(Func<IClientPlayer, bool> filter)
- {
- return _game.Players
- .Where(filter)
- .Select(p => p.Client.Connection)
- .OfType<Net.Hazel.HazelConnection>()
- .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
+++ /dev/null
-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
+++ /dev/null
-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<byte> 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
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;
{
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;
}
using System.Threading.Tasks;
+using Hazel;
using Impostor.Api.Innersloth;
using Impostor.Api.Innersloth.Data;
using Impostor.Api.Net.Messages;
_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);
{
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;
}
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)
{
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;
}
namespace Impostor.Server.Net.State
{
- internal partial class Game : IGame
+ internal partial class Game
{
IClientPlayer IGame.Host => Host;
}
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
{
{
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<GameJoinResult> AddClientAsync(ClientBase client)
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.
{
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)
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.
true,
playerId,
isBan ? DisconnectReason.Banned : DisconnectReason.Kicked);
- await message.SendToAllExceptAsync(playerId);
+
+ await SendToAllExceptAsync(message, playerId);
}
private async ValueTask HandleJoinGameNew(ClientPlayer sender, bool isNew)
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);
}
}
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
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);
using System.Linq;
using System.Threading.Tasks;
+using Hazel;
using Impostor.Api;
using Impostor.Api.Events;
using Impostor.Api.Innersloth.Data;
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))
{
WriteAlterGameMessage(message, false, IsPublic);
player.Limbo = LimboStates.NotLimbo;
- await message.SendToAsync(player.Client);
+
+ await SendToAsync(message, player.Client.Id);
}
}
}
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;
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;
namespace Impostor.Server.Net.State
{
- internal partial class Game
+ internal partial class Game : IGame
{
private static readonly ILogger Logger = Log.ForContext<Game>();
public IEnumerable<IClientPlayer> 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))
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<Connection> GetConnections(Func<IClientPlayer, bool> filter)
+ {
+ return Players
+ .Where(filter)
+ .Select(p => p.Client.Connection)
+ .OfType<HazelConnection>()
+ .Select(c => c.InnerConnection);
}
}
}
\ No newline at end of file
using Hazel;
-using Impostor.Api.Net.Messages;
-using Impostor.Server.Net.Hazel.Messages;
-using Impostor.Server.Net.Messages;
using Xunit;
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());
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());
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());
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());
}
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);
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
using System.Linq;
using Hazel;
using Hazel.Udp;
+using Impostor.Api.Net.Messages;
using PcapDotNet.Core;
using PcapDotNet.Packets;
// 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);
}
}
}
- 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;
{
case 14:
case 13:
- packet.Position = packet.Length;
+ // packet.Position = packet.Length;
break;
case 0:
Console.WriteLine("- GameCode " + packet.ReadInt32());
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());
}
}
- 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;
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;
}
}