using System; using System.IO; using System.Text; namespace IgniteEngine.Networking { /// /// Class that represents a network message sent to and from a /// . /// public class NetworkMessage : Object { /// /// The type of the message. /// public NetworkCommand Command { get; private set; } /// /// Object to read data from the message. /// private readonly BinaryReader reader; /// /// The stream that contains the message data. /// private readonly MemoryStream stream; /// /// Object to write data to the message. /// private readonly BinaryWriter writer; /// /// Creates a new instance of the class. /// /// The message data. public NetworkMessage(byte[] buffer) { stream = new MemoryStream(buffer); reader = new BinaryReader(stream); Command = (NetworkCommand) ReadUInt16(); } /// /// Creates a new instance of the class. /// /// The type of message. public NetworkMessage(NetworkCommand command) { stream = new MemoryStream(); writer = new BinaryWriter(stream); Command = command; Write((ushort) command); } /// /// Sends multiple messages as a chunk. /// public static void SendChunk(NetworkConnection connection, params NetworkMessage[] messages) { connection.SendChunk = true; for (var i = 0; i < messages.Length; i++) { messages[i].Send(connection); } connection.SendChunk = false; } /// /// Fills the number of bytes with the value. /// /// The number of bytes to fill. /// The value to fill with. public void Fill(int count, byte value) { for (var i = 0; i < count; i++) { Write(value); } } /// /// Reads a boolean value from the current stream. /// public bool ReadBoolean() { return reader.ReadBoolean(); } /// /// Reads a byte value from the current stream. /// public byte ReadByte() { return reader.ReadByte(); } /// /// Reads an array of bytes from the current stream. /// /// The number of bytes to read. public byte[] ReadBytes(int count) { return reader.ReadBytes(count); } /// /// Reads a character value from the current stream. /// public char ReadChar() { return reader.ReadChar(); } /// /// Reads a decimal value from the current stream. /// public decimal ReadDecimal() { return reader.ReadDecimal(); } /// /// Reads a double value from the current stream. /// public double ReadDouble() { return reader.ReadDouble(); } /// /// Reads a 16-bit integer value from the current stream. /// public short ReadInt16() { return reader.ReadInt16(); } /// /// Reads a 32-bit integer value from the current stream. /// public int ReadInt32() { return reader.ReadInt32(); } /// /// Reads a 64-bit integer value from the current stream. /// /// public long ReadInt64() { return reader.ReadInt64(); } /// /// Reads a float value from the current stream. /// /// public float ReadSingle() { return reader.ReadSingle(); } /// /// Reads a string value from the current stream. /// public string ReadString() { return ReadString(ReadByte()); } /// /// Reads a string value from the current stream. /// /// The length of the stream. public string ReadString(int length) { var ret = string.Empty; var buffer = new byte[length]; var count = 0; stream.Read(buffer, 0, buffer.Length); if (buffer[length - 1] != 0) { count = length; } else { while (buffer[count] != 0 && count < length) { count++; } } if (count > 0) { ret = Encoding.ASCII.GetString(buffer, 0, count); } return ret; } /// /// Reads an unsigned 16-bit integer value from the current stream. /// public ushort ReadUInt16() { return reader.ReadUInt16(); } /// /// Reads an unsigned 32-bit integer value from the current stream. /// public uint ReadUInt32() { return reader.ReadUInt32(); } /// /// Reads an unsigned 64-bit integer value from the current stream. /// public ulong ReadUInt64() { return reader.ReadUInt64(); } /// /// Sends the message to the connection. /// /// The connection to send the message to. public void Send(NetworkConnection connection) { connection?.SendData(ToArray(connection)); Destroy(this); } /// /// Returns a byte array representing the message. /// /// public byte[] ToArray(NetworkConnection connection = null) { byte[] ret; var buffer = stream.ToArray(); if (connection != null) { if (connection.Type != NetworkConnectionType.NCT_CLIENT && connection.IsEstablished) { connection.DecryptBuffer(buffer, 0, buffer.Length); } } if (buffer.Length <= 0xff) { ret = new byte[buffer.Length + 1]; Buffer.BlockCopy(buffer, 0, ret, 1, buffer.Length); ret[0] = (byte) buffer.Length; } else { ret = new byte[buffer.Length + 3]; Buffer.BlockCopy(buffer, 0, ret, 3, buffer.Length); Buffer.BlockCopy(BitConverter.GetBytes((ushort) buffer.Length), 0, ret, 1, 2); } return ret; } /// /// Returns a string representing the message. /// public override string ToString() { return $"Command=0x{Command:X} ({Command}), Length={stream.Length - 2}"; } /// /// Writes a boolean value to the current stream. /// /// The value to write. public void Write(bool value) { writer.Write(value); } /// /// Writes a byte value to the current stream. /// /// The value to write. public void Write(byte value) { writer.Write(value); } /// /// Writes a signed byte value to the current stream. /// /// The value to write. public void Write(sbyte value) { writer.Write(value); } /// /// Writes a byte array to the current stream. /// /// The value to write. public void Write(byte[] value) { writer.Write(value); } /// /// Writes a 16-bit integer value to the current stream. /// /// The value to write. public void Write(short value) { writer.Write(value); } /// /// Writes a 32-bit integer value to the current stream. /// /// The value to write. public void Write(int value) { writer.Write(value); } /// /// Writes a 64-bit integer value to the current stream. /// /// The value to write. public void Write(long value) { writer.Write(value); } /// /// Writes an unsigned 16-bit integer value to the current stream. /// /// The value to write. public void Write(ushort value) { writer.Write(value); } /// /// Writes an unsigned 32-bit integer value to the current stream. /// /// The value to write. public void Write(uint value) { writer.Write(value); } /// /// Writes an unsigned 64-bit integer value to the current stream. /// /// The value to write. public void Write(ulong value) { writer.Write(value); } /// /// Writes a double value to the current stream. /// /// The value to write. public void Write(double value) { writer.Write(value); } /// /// Writes a decimal value to the current stream. /// /// The value to write. public void Write(decimal value) { writer.Write(value); } /// /// Writes a float value to the current stream. /// /// The value to write. public void Write(float value) { writer.Write(value); } /// /// Writes a string value to the current stream. /// /// The value to write. public void Write(string value) { Write(value, value.Length); } /// /// Writes a string value to the current stream. /// /// The value to write. /// The length of the string. public void Write(string value, int length) { var buffer = Encoding.ASCII.GetBytes(value); Write(buffer); for (var i = 0; i < length - buffer.Length; i++) { Write((byte) 0); } } /// /// Destroys the instance. /// protected override void Destroy() { // Reader and writer are not always initialized, so we need to check // for null before attempting to close them. reader?.Close(); writer?.Close(); stream.Close(); } } }