// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. using System; using System.Text; using FlaxEngine.Assertions; namespace FlaxEngine.Networking { public unsafe partial struct NetworkMessage { /// /// Writes raw bytes into the message. /// /// The bytes that will be written. /// The amount of bytes to write from the bytes pointer. public void WriteBytes(byte* bytes, int length) { Assert.IsTrue(Position + length <= BufferSize, $"Could not write data of length {length} into message with id={MessageId}! Current write position={Position}"); Utils.MemoryCopy(new IntPtr(Buffer + Position), new IntPtr(bytes), (ulong)length); Position += (uint)length; Length = Position; } /// /// Reads raw bytes from the message into the given byte array. /// /// /// The buffer pointer that will be used to store the bytes. /// Should be of the same length as length or longer. /// /// The minimal amount of bytes that the buffer contains. public void ReadBytes(byte* buffer, int length) { Assert.IsTrue(Position + length <= Length, $"Could not read data of length {length} from message with id={MessageId} and size of {Length}B! Current read position={Position}"); Utils.MemoryCopy(new IntPtr(buffer), new IntPtr(Buffer + Position), (ulong)length); Position += (uint)length; } /// /// Writes raw bytes into the message. /// /// The bytes that will be written. /// The amount of bytes to write from the bytes array. public void WriteBytes(byte[] bytes, int length) { fixed (byte* bytesPtr = bytes) { WriteBytes(bytesPtr, length); } } /// /// Reads raw bytes from the message into the given byte array. /// /// /// The buffer that will be used to store the bytes. /// Should be of the same length as length or longer. /// /// The minimal amount of bytes that the buffer contains. public void ReadBytes(byte[] buffer, int length) { fixed (byte* bufferPtr = buffer) { ReadBytes(bufferPtr, length); } } /// /// Writes data of type into the message. /// public void WriteInt64(long value) { WriteBytes((byte*)&value, sizeof(long)); } /// /// Reads and returns data of type from the message. /// public long ReadInt64() { long value = 0; ReadBytes((byte*)&value, sizeof(long)); return value; } /// /// Writes data of type into the message. /// public void WriteInt32(int value) { WriteBytes((byte*)&value, sizeof(int)); } /// /// Reads and returns data of type from the message. /// public int ReadInt32() { int value = 0; ReadBytes((byte*)&value, sizeof(int)); return value; } /// /// Writes data of type into the message. /// public void WriteInt16(short value) { WriteBytes((byte*)&value, sizeof(short)); } /// /// Reads and returns data of type from the message. /// public short ReadInt16() { short value = 0; ReadBytes((byte*)&value, sizeof(short)); return value; } /// /// Writes data of type into the message. /// public void WriteSByte(sbyte value) { WriteBytes((byte*)&value, sizeof(sbyte)); } /// /// Reads and returns data of type from the message. /// public sbyte ReadSByte() { sbyte value = 0; ReadBytes((byte*)&value, sizeof(sbyte)); return value; } /// /// Writes data of type into the message. /// public void WriteUInt64(ulong value) { WriteBytes((byte*)&value, sizeof(ulong)); } /// /// Reads and returns data of type from the message. /// public ulong ReadUInt64() { ulong value = 0; ReadBytes((byte*)&value, sizeof(ulong)); return value; } /// /// Writes data of type into the message. /// public void WriteUInt32(uint value) { WriteBytes((byte*)&value, sizeof(uint)); } /// /// Reads and returns data of type from the message. /// public uint ReadUInt32() { uint value = 0; ReadBytes((byte*)&value, sizeof(uint)); return value; } /// /// Writes data of type into the message. /// public void WriteUInt16(ushort value) { WriteBytes((byte*)&value, sizeof(ushort)); } /// /// Reads and returns data of type from the message. /// public ushort ReadUInt16() { ushort value = 0; ReadBytes((byte*)&value, sizeof(ushort)); return value; } /// /// Writes data of type into the message. /// public void WriteByte(byte value) { WriteBytes(&value, sizeof(byte)); } /// /// Reads and returns data of type from the message. /// public byte ReadByte() { byte value = 0; ReadBytes(&value, sizeof(byte)); return value; } /// /// Writes data of type into the message. /// public void WriteSingle(float value) { WriteBytes((byte*)&value, sizeof(float)); } /// /// Reads and returns data of type from the message. /// public float ReadSingle() { float value = 0.0f; ReadBytes((byte*)&value, sizeof(float)); return value; } /// /// Writes data of type into the message. /// public void WriteDouble(double value) { WriteBytes((byte*)&value, sizeof(double)); } /// /// Reads and returns data of type from the message. /// public double ReadDouble() { double value = 0.0; ReadBytes((byte*)&value, sizeof(double)); return value; } /// /// Writes data of type into the message. UTF-16 encoded. /// public void WriteString(string value) { // Note: Make sure that this is consistent with the C++ message API! var data = Encoding.Unicode.GetBytes(value); var dataLength = data.Length; var stringLength = value.Length; WriteUInt16((ushort)stringLength); // TODO: Use 1-byte length when possible WriteBytes(data, dataLength); } /// /// Reads and returns data of type from the message. UTF-16 encoded. /// public string ReadString() { // Note: Make sure that this is consistent with the C++ message API! var stringLength = ReadUInt16(); // In chars var dataLength = stringLength * sizeof(char); // In bytes var bytes = stackalloc char[stringLength]; ReadBytes((byte*)bytes, dataLength); return new string(bytes, 0, stringLength); } /// /// Writes data of type into the message. /// public void WriteGuid(Guid value) { WriteBytes((byte*)&value, sizeof(Guid)); } /// /// Reads and returns data of type from the message. /// public Guid ReadGuid() { var guidData = stackalloc Guid[1]; ReadBytes((byte*)guidData, sizeof(Guid)); return guidData[0]; } /// /// Writes data of type into the message. /// public void WriteVector2(Vector2 value) { WriteSingle((float)value.X); WriteSingle((float)value.Y); } /// /// Reads and returns data of type from the message. /// public Vector2 ReadVector2() { return new Vector2(ReadSingle(), ReadSingle()); } /// /// Writes data of type into the message. /// public void WriteVector3(Vector3 value) { WriteSingle((float)value.X); WriteSingle((float)value.Y); WriteSingle((float)value.Z); } /// /// Reads and returns data of type from the message. /// public Vector3 ReadVector3() { return new Vector3(ReadSingle(), ReadSingle(), ReadSingle()); } /// /// Writes data of type into the message. /// public void WriteVector4(Vector4 value) { WriteSingle((float)value.X); WriteSingle((float)value.Y); WriteSingle((float)value.Z); WriteSingle((float)value.W); } /// /// Reads and returns data of type from the message. /// public Vector4 ReadVector4() { return new Vector4(ReadSingle(), ReadSingle(), ReadSingle(), ReadSingle()); } /// /// Writes data of type into the message. /// public void WriteQuaternion(Quaternion value) { WriteSingle(value.X); WriteSingle(value.Y); WriteSingle(value.Z); WriteSingle(value.W); } /// /// Reads and returns data of type from the message. /// public Quaternion ReadQuaternion() { return new Quaternion(ReadSingle(), ReadSingle(), ReadSingle(), ReadSingle()); } /// /// Writes data of type into the message. /// public void WriteBoolean(bool value) { WriteBytes((byte*)&value, sizeof(bool)); } /// /// Reads and returns data of type from the message. /// public bool ReadBoolean() { bool value = default; ReadBytes((byte*)&value, sizeof(bool)); return value; } } }