using System; using System.Collections.Generic; using System.IO; using System.Text; namespace Hazel { /// /// 单向写入的Message,嵌套结构的Message,如果有嵌套,也只有一个header,子协议没有header /// 整个结构都会被socket发送,参见UdpConnection.cs /// 结构: /// -------------header----------------- /// 1bytes SendOption 是否是可靠传输 /// (2bytes) (可靠传输用到的) /// --------------数据------------------ /// 2bytes 包长度(不含这2bytes和下面的tag 1byte) /// 1bytes 协议ID,在AmongUS里是tags.cs里定义的tag和subtag /// 数据 包括嵌套的子协议 /// ------------------------------------ /// public class MessageWriter : IRecyclable { public static int BufferSize = 64000; public static readonly ObjectPool WriterPool = new ObjectPool(() => new MessageWriter(BufferSize)); public byte[] Buffer; // 缓冲区,保存了整个包体,包括头部和内容 public int Length; // 有效数据在buffer中的长度,包含header,可能包含多个嵌套子协议。Length>=Position public int Position; // 写入游标 public SendOption SendOption { get; private set; } private Stack messageStarts = new Stack(); // 没用,注释掉了 //public MessageWriter(byte[] buffer) //{ // this.Buffer = buffer; // this.Length = this.Buffer.Length; //} /// public MessageWriter(int bufferSize) { this.Buffer = new byte[bufferSize]; } /// /// 去掉header /// /// /// /// public byte[] ToByteArray(bool includeHeader) { if (includeHeader) { byte[] output = new byte[this.Length]; System.Buffer.BlockCopy(this.Buffer, 0, output, 0, this.Length); return output; } else { switch (this.SendOption) { case SendOption.Reliable: { byte[] output = new byte[this.Length - 3]; System.Buffer.BlockCopy(this.Buffer, 3, output, 0, this.Length - 3); return output; } case SendOption.None: { byte[] output = new byte[this.Length - 1]; System.Buffer.BlockCopy(this.Buffer, 1, output, 0, this.Length - 1); return output; } } } throw new NotImplementedException(); } /// /// The option specifying how the message should be sent. public static MessageWriter Get(SendOption sendOption = SendOption.None) { var output = WriterPool.GetObject(); output.Clear(sendOption); return output; } /// /// expected没有header /// /// /// public bool HasBytes(int expected) { if (this.SendOption == SendOption.None) { return this.Length > 1 + expected; // header=1 byte } return this.Length > 3 + expected; // header=3 bytes } /// public void StartMessage(byte typeFlag) { var messageStart = this.Position; messageStarts.Push(messageStart); this.Buffer[messageStart] = 0; // length this.Buffer[messageStart + 1] = 0; this.Position += 2; //this.Length = this.Position; this.Write(typeFlag); } /// public void EndMessage() { var lastMessageStart = messageStarts.Pop(); ushort length = (ushort)(this.Position - lastMessageStart - 3); // Minus length and type byte this.Buffer[lastMessageStart] = (byte)length; this.Buffer[lastMessageStart + 1] = (byte)(length >> 8); } /// public void CancelMessage() { this.Position = this.messageStarts.Pop(); this.Length = this.Position; } /// /// 重置为sendOption类型的空包 /// /// public void Clear(SendOption sendOption) { Array.Clear(this.Buffer, 0, this.Buffer.Length);//完全清空整个缓冲区 this.messageStarts.Clear(); this.SendOption = sendOption; this.Buffer[0] = (byte)sendOption; switch (sendOption) { default: case SendOption.None: this.Length = this.Position = 1; break; case SendOption.Reliable: this.Length = this.Position = 3; break; } } /// public void Recycle() { this.Position = this.Length = 0; WriterPool.PutObject(this); } #region WriteMethods public void CopyFrom(MessageReader target) { int offset, length; if (target.Tag == byte.MaxValue) { offset = target.Offset; length = target.Length; } else { offset = target.Offset - 3; length = target.Length + 3; } System.Buffer.BlockCopy(target.Buffer, offset, this.Buffer, this.Position, length); this.Position += length; if (this.Position > this.Length) this.Length = this.Position; } public void Write(bool value) { this.Buffer[this.Position++] = (byte)(value ? 1 : 0); if (this.Position > this.Length) this.Length = this.Position; } public void Write(sbyte value) { this.Buffer[this.Position++] = (byte)value; if (this.Position > this.Length) this.Length = this.Position; } public void Write(byte value) { this.Buffer[this.Position++] = value; if (this.Position > this.Length) this.Length = this.Position; } public void Write(short value) { this.Buffer[this.Position++] = (byte)value; this.Buffer[this.Position++] = (byte)(value >> 8); if (this.Position > this.Length) this.Length = this.Position; } public void Write(ushort value) { this.Buffer[this.Position++] = (byte)value; this.Buffer[this.Position++] = (byte)(value >> 8); if (this.Position > this.Length) this.Length = this.Position; } public void Write(uint value) { this.Buffer[this.Position++] = (byte)value; this.Buffer[this.Position++] = (byte)(value >> 8); this.Buffer[this.Position++] = (byte)(value >> 16); this.Buffer[this.Position++] = (byte)(value >> 24); if (this.Position > this.Length) this.Length = this.Position; } public void Write(int value) { this.Buffer[this.Position++] = (byte)value; this.Buffer[this.Position++] = (byte)(value >> 8); this.Buffer[this.Position++] = (byte)(value >> 16); this.Buffer[this.Position++] = (byte)(value >> 24); if (this.Position > this.Length) this.Length = this.Position; } public void Write(ulong value) { this.Buffer[this.Position++] = (byte)value; this.Buffer[this.Position++] = (byte)(value >> 8); this.Buffer[this.Position++] = (byte)(value >> 16); this.Buffer[this.Position++] = (byte)(value >> 24); this.Buffer[this.Position++] = (byte)(value >> 32); this.Buffer[this.Position++] = (byte)(value >> 40); this.Buffer[this.Position++] = (byte)(value >> 48); this.Buffer[this.Position++] = (byte)(value >> 56); if (this.Position > this.Length) this.Length = this.Position; } public void Write(long value) { this.Buffer[this.Position++] = (byte)value; this.Buffer[this.Position++] = (byte)(value >> 8); this.Buffer[this.Position++] = (byte)(value >> 16); this.Buffer[this.Position++] = (byte)(value >> 24); this.Buffer[this.Position++] = (byte)(value >> 32); this.Buffer[this.Position++] = (byte)(value >> 40); this.Buffer[this.Position++] = (byte)(value >> 48); this.Buffer[this.Position++] = (byte)(value >> 56); if (this.Position > this.Length) this.Length = this.Position; } public unsafe void Write(float value) { fixed (byte* ptr = &this.Buffer[this.Position]) { byte* valuePtr = (byte*)&value; *ptr = *valuePtr; *(ptr + 1) = *(valuePtr + 1); *(ptr + 2) = *(valuePtr + 2); *(ptr + 3) = *(valuePtr + 3); } this.Position += 4; if (this.Position > this.Length) this.Length = this.Position; } public void Write(string value) { var bytes = UTF8Encoding.UTF8.GetBytes(value); this.WritePacked(bytes.Length); this.Write(bytes); } public void WriteBytesAndSize(byte[] bytes) { this.WritePacked((uint)bytes.Length); this.Write(bytes); } public void WriteBytesAndSize(byte[] bytes, int length) { this.WritePacked((uint)length); this.Write(bytes, length); } public void WriteBytesAndSize(byte[] bytes, int offset, int length) { this.WritePacked((uint)length); this.Write(bytes, offset, length); } public void Write(byte[] bytes) { Array.Copy(bytes, 0, this.Buffer, this.Position, bytes.Length); this.Position += bytes.Length; if (this.Position > this.Length) this.Length = this.Position; } public void Write(byte[] bytes, int offset, int length) { Array.Copy(bytes, offset, this.Buffer, this.Position, length); this.Position += length; if (this.Position > this.Length) this.Length = this.Position; } public void Write(byte[] bytes, int length) { Array.Copy(bytes, 0, this.Buffer, this.Position, length); this.Position += length; if (this.Position > this.Length) this.Length = this.Position; } /// public void WritePacked(int value) { this.WritePacked((uint)value); } /// public void WritePacked(uint value) { do { byte b = (byte)(value & 0xFF); if (value >= 0x80) { b |= 0x80; } this.Write(b); value >>= 7; } while (value > 0); } #endregion public void Write(MessageWriter msg, bool includeHeader) { int offset = 0; if (!includeHeader) { switch (msg.SendOption) { case SendOption.None: offset = 1; break; case SendOption.Reliable: offset = 3; break; } } this.Write(msg.Buffer, offset, msg.Length - offset); } public unsafe static bool IsLittleEndian() { byte b; unsafe { int i = 1; byte* bp = (byte*)&i; b = *bp; } return b == 1; } } }