From 852e4d13026c2a3af0bfc5d67dbca24cace16a7f Mon Sep 17 00:00:00 2001
From: chai <215380520@qq.com>
Date: Sat, 14 Oct 2023 12:50:22 +0800
Subject: * move
---
Projects/Message/Message/IRecyclable.cs | 29 --
Projects/Message/Message/MessageReader.cs | 530 ---------------------
Projects/Message/Message/MessageWriter.cs | 341 -------------
Projects/Message/Message/MessageWriterTests.cs | 1 -
.../Message/MultiplayerToolkit/IRecyclable.cs | 29 ++
.../Message/MultiplayerToolkit/MessageReader.cs | 530 +++++++++++++++++++++
.../Message/MultiplayerToolkit/MessageWriter.cs | 341 +++++++++++++
.../Message/MultiplayerToolkit/ObjectPool.cs | 108 +++++
Projects/Message/Message/ObjectPool.cs | 108 -----
9 files changed, 1008 insertions(+), 1009 deletions(-)
delete mode 100644 Projects/Message/Message/IRecyclable.cs
delete mode 100644 Projects/Message/Message/MessageReader.cs
delete mode 100644 Projects/Message/Message/MessageWriter.cs
create mode 100644 Projects/Message/Message/MultiplayerToolkit/IRecyclable.cs
create mode 100644 Projects/Message/Message/MultiplayerToolkit/MessageReader.cs
create mode 100644 Projects/Message/Message/MultiplayerToolkit/MessageWriter.cs
create mode 100644 Projects/Message/Message/MultiplayerToolkit/ObjectPool.cs
delete mode 100644 Projects/Message/Message/ObjectPool.cs
(limited to 'Projects/Message')
diff --git a/Projects/Message/Message/IRecyclable.cs b/Projects/Message/Message/IRecyclable.cs
deleted file mode 100644
index 17d3104..0000000
--- a/Projects/Message/Message/IRecyclable.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace MultiplayerToolkit
-{
- ///
- /// Interface for all items that can be returned to an object pool.
- ///
- ///
- public interface IRecyclable
- {
- ///
- /// Returns this object back to the object pool.
- ///
- ///
- ///
- /// Calling this when you are done with the object returns the object back to a pool in order to be reused.
- /// This can reduce the amount of work the GC has to do dramatically but it is optional to call this.
- ///
- ///
- /// Calling this indicates to Hazel that this can be reused and thus you should only call this when you are
- /// completely finished with the object as the contents can be overwritten at any point after.
- ///
- ///
- void Recycle();
- }
-}
diff --git a/Projects/Message/Message/MessageReader.cs b/Projects/Message/Message/MessageReader.cs
deleted file mode 100644
index 32b0218..0000000
--- a/Projects/Message/Message/MessageReader.cs
+++ /dev/null
@@ -1,530 +0,0 @@
-using System;
-using System.IO;
-using System.Linq;
-using System.Runtime.CompilerServices;
-using System.Text;
-
-namespace MultiplayerToolkit
-{
- ///
- /// 可以处理嵌套消息的结构,和MessageWriter配对
- ///
- public class MessageReader : IRecyclable
- {
- public static readonly ObjectPool ReaderPool = new ObjectPool(() => new MessageReader());
-
- public byte[] Buffer; // 缓冲区,会被子消息共享这个缓冲区
-
- // 消息长度,定值
- // * 如果是非根消息,对应的是MessageWriter里写入的2bytes包长度,即不含length的长度
- // * 如果是根消息,Length是整个有效数据在Buffer中的长度,包括Length
- public int Length;
-
- // 有效数据偏移,定值,游标会在这个基础上偏移
- // * 如果是非根消息,Offset在Length后面的位置
- // * 如果是根消息,Offset等于0,表示有效数据在Buffer中的偏移
- public int Offset;
-
- public int BytesRemaining => this.Length - this.Position;
-
- public int TotalLength => this.Length + this.Offset;
-
- private MessageReader Parent; // 保存父消息索引,和父消息共享父消息的Buffer
-
- // 是否是根消息,根消息下面包含多个子消息,子消息可以嵌套重孙消息
- public bool IsRoot
- {
- get { return Parent == null; }
- }
-
- // 子消息可读
- public bool IsReadable
- {
- get { return this.Parent != null; }
- }
-
- public int Position
- {
- get { return this._position; }
- set
- {
- this._position = value;
- this.readHead = value + Offset;
- }
- }
-
- private int _position; // 读取游标,相对于消息内容部分的偏移,从0开始,子消息也是从0开始,不是在Buffer中的索引
- private int readHead; // 读取游标,消息头部在Buffer中的位置,参考ReadMessage()
-
-#region 创建
- ///
- /// 创建一个容量至少为minSize的空缓冲区
- ///
- ///
- ///
- ///
- public static MessageReader GetSized(int minSize, bool exactly = false)
- {
- var output = ReaderPool.GetObject();
-
- if (output.Buffer == null || output.Buffer.Length < minSize)
- {
- output.Buffer = new byte[minSize];
- }
- else
- {
- if(exactly && output.Buffer.Length > minSize)
- {
- output.Buffer = new byte[minSize];
- }
- Array.Clear(output.Buffer, 0, output.Buffer.Length);
- }
-
- output.Offset = 0;
- output.Length = 0;
- output.Position = 0;
- output.Parent = null;
- return output;
- }
-
- ///
- /// 将缓冲区封装为根消息,不拷贝
- ///
- ///
- ///
- public static MessageReader Get(byte[] buffer)
- {
- var output = ReaderPool.GetObject();
-
- output.Buffer = buffer;
- output.Offset = 0;
- output.Position = 0;
- output.Length = buffer.Length;
- output.Parent = null;
-
- return output;
- }
-
- ///
- /// 将缓冲区封装为根消息,拷贝
- ///
- ///
- ///
- public static MessageReader GetAndCopy(byte[] buffer)
- {
- var output = ReaderPool.GetObject();
-
- byte[] _buffer = new byte[buffer.Length];
- Array.Copy(buffer, _buffer, buffer.Length);
- output.Buffer = _buffer;
- output.Offset = 0;
- output.Position = 0;
- output.Length = _buffer.Length;
- output.Parent = null;
-
- return output;
- }
-
- ///
- /// 创建一个新的父message,保存source。用于缓存message,因为source所在的原父message可能会被销毁,如果需要延迟处理消息,需要拷贝一份新的
- ///
- ///
- ///
- public static MessageReader CopyMessageIntoParent(MessageReader source)
- {
- var output = MessageReader.GetSized(source.Length + 2); //2=2bytes(length)
- System.Buffer.BlockCopy(source.Buffer, source.Offset - 2, output.Buffer, 0, source.Length + 2);
-
- output.Offset = 0;
- output.Position = 0;
- output.Length = source.Length + 2;
- output.Parent = null;
-
- return output;
- }
-
-#if UNIT_TEST
- ///
- /// 用于测试,引用buffer的一部分作为child message,后续可以直接读取
- ///
- ///
- ///
- ///
- public static MessageReader GetChildMessage(byte[] buffer, int offset)
- {
- // 确保至少有一个length
- if (offset + 2 > buffer.Length) return null;
-
- var output = ReaderPool.GetObject();
-
- output.Buffer = buffer;
- output.Offset = offset;
- output.Position = 0;
-
- output.Length = output.ReadUInt16(); // 读到的值为length
-
- output.Offset += 2;
- output.Position = 0;
- output.Parent = null;
-
- return output;
- }
-
- public static MessageReader Copy(MessageReader source)
- {
- var output = MessageReader.GetSized(source.Buffer.Length);
- System.Buffer.BlockCopy(source.Buffer, 0, output.Buffer, 0, source.Buffer.Length);
-
- output.Offset = source.Offset;
-
- output._position = source._position;
- output.readHead = source.readHead;
-
- output.Length = source.Length;
-
- return output;
- }
-
-#endif
-
- #endregion
-
- ///
- /// 返回一个可读子消息,引用了父缓冲区,**不要回收**
- ///
- public MessageReader ReadMessage()
- {
- // 至少有一个length
- if (this.BytesRemaining < 2) throw new InvalidDataException($"ReadMessage header is longer than message length: 2 of {this.BytesRemaining}");
-
- MessageReader output = new MessageReader();
-
- output.Parent = this;
- output.Buffer = this.Buffer;
- output.Offset = this.readHead;
- output.Position = 0;
-
- output.Length = output.ReadUInt16(); // length
-
- output.Offset += 2; // 2=length
- output.Position = 0;
-
- // 数据不全
- if (this.BytesRemaining < output.Length + 2) throw new InvalidDataException($"Message Length at Position {this.readHead} is longer than message length: {output.Length + 2} of {this.BytesRemaining}");
-
- this.Position += output.Length + 2; //跳过整个子消息
- return output;
- }
-
-#if UNIT_TEST
- ///
- /// 仅用于测试,返回一个可读子消息,并且拷贝数据,可回收
- /// Offset为0,开头没有Length数据
- ///
- public MessageReader ReadMessageAsNewBuffer()
- {
- if (this.BytesRemaining < 2) throw new InvalidDataException($"ReadMessage header is longer than message length: 2 of {this.BytesRemaining}");
-
- var len = this.ReadUInt16(); // Position += 2
-
- if (this.BytesRemaining < len) throw new InvalidDataException($"Message Length at Position {this.readHead} is longer than message length: {len} of {this.BytesRemaining}");
-
- var output = MessageReader.GetSized(len);
-
- Array.Copy(this.Buffer, this.readHead, output.Buffer, 0, len);
-
- output.Length = len;
-
- this.Position += output.Length;
- return output;
- }
-#endif
-
-#if UNIT_TEST
- public MessageReader Duplicate()
- {
- var output = GetSized(this.Length);
- Array.Copy(this.Buffer, this.Offset, output.Buffer, 0, this.Length);
- output.Length = this.Length;
- output.Offset = 0;
- output.Position = 0;
-
- return output;
- }
-
- public void RemoveMessage(MessageReader reader)
- {
- MessageReader temp = null;
- try
- {
- var headerOffset = reader.Offset - 2;
- var endOfMessage = reader.Offset + reader.Length; // 有效部分的后一个byte
- var len = reader.Buffer.Length - endOfMessage;
-
- temp = MessageReader.GetSized(len);
- Array.Copy(reader.Buffer, endOfMessage, temp.Buffer, 0, len);
- Array.Copy(temp.Buffer, 0, this.Buffer, headerOffset, len);
-
- this.AdjustLength(reader.Offset, reader.Length + 2);
- }
- finally
- {
- if(temp != null)
- {
- temp.Recycle();
- }
- }
- }
-
- ///
- /// 在reader前面插入一条消息
- ///
- /// 父reader
- ///
- public void InsertMessage(MessageReader reader, MessageWriter writer)
- {
- var temp = MessageReader.GetSized(reader.Buffer.Length);
- try
- {
- var headerOffset = reader.Offset - 2;
- var startOfMessage = reader.Offset;
- var len = reader.Buffer.Length - headerOffset; // 疑似写错了,应该是headerOffset
- int writerOffset = 0;
-
- //store the original buffer in temp
- Array.Copy(reader.Buffer, headerOffset, temp.Buffer, 0, len);
-
- //put the contents of writer in at headerOffset
- Array.Copy(writer.Buffer, writerOffset, this.Buffer, headerOffset, writer.Length - writerOffset);
-
- //put the original buffer in after that
- Array.Copy(temp.Buffer, 0, this.Buffer, headerOffset + (writer.Length - writerOffset), len - writer.Length);
-
- this.AdjustLength(-1 * reader.Offset, -1 * (writer.Length - writerOffset));
- }
- finally
- {
- temp.Recycle();
- }
- }
-
- ///
- /// 递归调整length值
- ///
- /// 子消息的Offset值
- /// 子消息总长度,含length
- private void AdjustLength(int offset, int amount)
- {
- if (this.readHead > offset)
- {
- this.Position -= amount;
- }
-
- if (Parent != null)
- {
- var lengthOffset = this.Offset - 2;
- var curLen = this.Buffer[lengthOffset]
- | (this.Buffer[lengthOffset + 1] << 8);
-
- curLen -= amount;
- this.Length -= amount;
-
- this.Buffer[lengthOffset] = (byte)curLen;
- this.Buffer[lengthOffset + 1] = (byte)(curLen >> 8);
-
- Parent.AdjustLength(offset, amount);
- }
- }
-
-#endif
-
- public void Recycle()
- {
- this.Parent = null;
- ReaderPool.PutObject(this);
- }
-
-#region Read Methods
- public bool ReadBoolean()
- {
- byte val = this.FastByte();
- return val != 0;
- }
-
- public sbyte ReadSByte()
- {
- return (sbyte)this.FastByte();
- }
-
- public byte ReadByte()
- {
- return this.FastByte();
- }
-
- public ushort ReadUInt16()
- {
- ushort output =
- (ushort)(this.FastByte()
- | this.FastByte() << 8);
- return output;
- }
-
- public short ReadInt16()
- {
- short output =
- (short)(this.FastByte()
- | this.FastByte() << 8);
- return output;
- }
-
- public uint ReadUInt32()
- {
- uint output = this.FastByte()
- | (uint)this.FastByte() << 8
- | (uint)this.FastByte() << 16
- | (uint)this.FastByte() << 24;
-
- return output;
- }
-
- public int ReadInt32()
- {
- int output = this.FastByte()
- | this.FastByte() << 8
- | this.FastByte() << 16
- | this.FastByte() << 24;
-
- return output;
- }
-
- public ulong ReadUInt64()
- {
- ulong output = (ulong)this.FastByte()
- | (ulong)this.FastByte() << 8
- | (ulong)this.FastByte() << 16
- | (ulong)this.FastByte() << 24
- | (ulong)this.FastByte() << 32
- | (ulong)this.FastByte() << 40
- | (ulong)this.FastByte() << 48
- | (ulong)this.FastByte() << 56;
-
- return output;
- }
-
- public long ReadInt64()
- {
- long output = (long)this.FastByte()
- | (long)this.FastByte() << 8
- | (long)this.FastByte() << 16
- | (long)this.FastByte() << 24
- | (long)this.FastByte() << 32
- | (long)this.FastByte() << 40
- | (long)this.FastByte() << 48
- | (long)this.FastByte() << 56;
-
- return output;
- }
-
- public unsafe float ReadSingle()
- {
- float output = 0;
- fixed (byte* bufPtr = &this.Buffer[this.readHead])
- {
- byte* outPtr = (byte*)&output;
-
- *outPtr = *bufPtr;
- *(outPtr + 1) = *(bufPtr + 1);
- *(outPtr + 2) = *(bufPtr + 2);
- *(outPtr + 3) = *(bufPtr + 3);
- }
-
- this.Position += 4;
- return output;
- }
-
- public string ReadString()
- {
- int len = this.ReadPackedInt32();
- if (this.BytesRemaining < len) throw new InvalidDataException($"Read length is longer than message length: {len} of {this.BytesRemaining}");
-
- string output = UTF8Encoding.UTF8.GetString(this.Buffer, this.readHead, len);
-
- this.Position += len;
- return output;
- }
-
- public byte[] ReadBytesAndSize()
- {
- int len = this.ReadPackedInt32();
- if (this.BytesRemaining < len) throw new InvalidDataException($"Read length is longer than message length: {len} of {this.BytesRemaining}");
-
- return this.ReadBytes(len);
- }
-
- public byte[] ReadBytes(int length)
- {
- if (this.BytesRemaining < length) throw new InvalidDataException($"Read length is longer than message length: {length} of {this.BytesRemaining}");
-
- byte[] output = new byte[length];
- Array.Copy(this.Buffer, this.readHead, output, 0, output.Length);
- this.Position += output.Length;
- return output;
- }
-
- ///
- public int ReadPackedInt32()
- {
- return (int)this.ReadPackedUInt32();
- }
-
- ///
- public uint ReadPackedUInt32()
- {
- bool readMore = true;
- int shift = 0;
- uint output = 0;
-
- while (readMore)
- {
- if (this.BytesRemaining < 1) throw new InvalidDataException($"Read length is longer than message length.");
-
- byte b = this.ReadByte();
- if (b >= 0x80)
- {
- readMore = true;
- b ^= 0x80;
- }
- else
- {
- readMore = false;
- }
-
- output |= (uint)(b << shift);
- shift += 7;
- }
-
- return output;
- }
-#endregion
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private byte FastByte()
- {
- this._position++;
- return this.Buffer[this.readHead++];
- }
-
- public unsafe static bool IsLittleEndian()
- {
- byte b;
- unsafe
- {
- int i = 1;
- byte* bp = (byte*)&i;
- b = *bp;
- }
-
- return b == 1;
- }
- }
-}
diff --git a/Projects/Message/Message/MessageWriter.cs b/Projects/Message/Message/MessageWriter.cs
deleted file mode 100644
index 68a5ac3..0000000
--- a/Projects/Message/Message/MessageWriter.cs
+++ /dev/null
@@ -1,341 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Text;
-
-namespace MultiplayerToolkit
-{
-
- ///
- /// AmongUsùȥ˰ͷش
- /// ṹ
- /// -------------------------------------
- /// 2bytes (ushort)Ϣijȣ2bytes
- /// (-------------------------------------
- /// 1byte ϢͣϢ0ԶϢ1
- /// (2byte) (ԶϢṩһmodţSteam.UGC.Itemidulong 8bytesеţ֧65535mod)
- /// 2byte (ushort)ϢID 0-65535
- ///
- /// -------------------------------------)
- ///
- public class MessageWriter : IRecyclable
- {
- public const int BYTE_COUNT_OF_LENGTH = 2; // ռ2 bytes
- public static int BUFFER_SIZE = 64000; // Ϣ֧64000ֽڣ62.5KB
- public static readonly ObjectPool WriterPool = new ObjectPool(() => new MessageWriter(BUFFER_SIZE));
-
- public byte[] Buffer;
- public int Length; // ЧbufferеijȣܰǶϢ
- public int Position; // дα
-
- // lengthһڻĴСLengthһÿϢϢݲֵֽ
-
- private Stack messageStarts = new Stack(); // ¼ϢbufferеʼλãǶṹ
-
-#region
- ///
- /// һΪָСMessage
- ///
- ///
- public MessageWriter(int bufferSize)
- {
- this.Buffer = new byte[bufferSize];
- }
-
- ///
- /// ӳһСΪBufferSizeMessage
- ///
- ///
- public static MessageWriter Get()
- {
- MessageWriter output = WriterPool.GetObject();
- output.Clear();
-
- return output;
- }
-#endregion
-
- public byte[] ToByteArray()
- {
- byte[] output = new byte[this.Length];
- System.Buffer.BlockCopy(this.Buffer, 0, output, 0, this.Length);
- return output;
- }
-
- ///
- /// Ƿexpectedȵ
- ///
- ///
- ///
- public bool HasBytes(int expected)
- {
- return this.Length >= expected;
- }
-
- public bool HasBytesExactly(int exact)
- {
- return this.Length == exact;
- }
-
- ///
- /// ʼдϢд2bytesΪ
- ///
- public void StartMessage()
- {
- var messageStart = this.Position;
- messageStarts.Push(messageStart);
- this.Buffer[messageStart] = 0; // length
- this.Buffer[messageStart + 1] = 0; // length
- this.Position += 2; // ushort length
- this.Length = this.Position;
- }
-
-#if UNIT_TEST
- public void StartMessage(int dummy)
- {
- StartMessage();
- }
-#endif
-
- ///
- /// ôϢȣ־Ϣ
- ///
- public void EndMessage()
- {
- var lastMessageStart = messageStarts.Pop();
- ushort length = (ushort)(this.Position - lastMessageStart - 2); // Minus length
- this.Buffer[lastMessageStart] = (byte)length;
- this.Buffer[lastMessageStart + 1] = (byte)(length >> 8);
- }
-
- ///
- /// ȡǰ༭messageصһ
- ///
- public void CancelMessage()
- {
- this.Position = this.messageStarts.Pop();
- this.Length = this.Position;
- }
-
- public void Clear()
- {
- Array.Clear(this.Buffer, 0, this.Buffer.Length);
- this.messageStarts.Clear();
- this.Length = 0;
- this.Position = 0;
- }
-
- ///
- /// message
- ///
- public void Recycle()
- {
- this.Position = this.Length = 0;
- WriterPool.PutObject(this);
- }
-
-#region WriteMethods
-
- ///
- /// дȡϢͨڷܵϢĹ㲥תҪStart\End
- ///
- ///
- public void CopyFrom(MessageReader target)
- {
- int offset, length;
- if (target.IsRoot)
- {
- offset = target.Offset;
- length = target.Length;
- }
- else
- {
- offset = target.Offset - 2;
- length = target.Length + 2;
- }
-
- 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)
- {
- this.Write(msg.Buffer, 0, msg.Length);
- }
-
- public unsafe static bool IsLittleEndian()
- {
- byte b;
- unsafe
- {
- int i = 1;
- byte* bp = (byte*)&i;
- b = *bp;
- }
-
- return b == 1;
- }
- }
-}
diff --git a/Projects/Message/Message/MessageWriterTests.cs b/Projects/Message/Message/MessageWriterTests.cs
index 9a873a5..b6efba0 100644
--- a/Projects/Message/Message/MessageWriterTests.cs
+++ b/Projects/Message/Message/MessageWriterTests.cs
@@ -4,7 +4,6 @@ using System.Collections.Generic;
using System.IO;
using System.Text;
-
namespace MultiplayerToolkit
{
diff --git a/Projects/Message/Message/MultiplayerToolkit/IRecyclable.cs b/Projects/Message/Message/MultiplayerToolkit/IRecyclable.cs
new file mode 100644
index 0000000..17d3104
--- /dev/null
+++ b/Projects/Message/Message/MultiplayerToolkit/IRecyclable.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MultiplayerToolkit
+{
+ ///
+ /// Interface for all items that can be returned to an object pool.
+ ///
+ ///
+ public interface IRecyclable
+ {
+ ///
+ /// Returns this object back to the object pool.
+ ///
+ ///
+ ///
+ /// Calling this when you are done with the object returns the object back to a pool in order to be reused.
+ /// This can reduce the amount of work the GC has to do dramatically but it is optional to call this.
+ ///
+ ///
+ /// Calling this indicates to Hazel that this can be reused and thus you should only call this when you are
+ /// completely finished with the object as the contents can be overwritten at any point after.
+ ///
+ ///
+ void Recycle();
+ }
+}
diff --git a/Projects/Message/Message/MultiplayerToolkit/MessageReader.cs b/Projects/Message/Message/MultiplayerToolkit/MessageReader.cs
new file mode 100644
index 0000000..32b0218
--- /dev/null
+++ b/Projects/Message/Message/MultiplayerToolkit/MessageReader.cs
@@ -0,0 +1,530 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Text;
+
+namespace MultiplayerToolkit
+{
+ ///
+ /// 可以处理嵌套消息的结构,和MessageWriter配对
+ ///
+ public class MessageReader : IRecyclable
+ {
+ public static readonly ObjectPool ReaderPool = new ObjectPool(() => new MessageReader());
+
+ public byte[] Buffer; // 缓冲区,会被子消息共享这个缓冲区
+
+ // 消息长度,定值
+ // * 如果是非根消息,对应的是MessageWriter里写入的2bytes包长度,即不含length的长度
+ // * 如果是根消息,Length是整个有效数据在Buffer中的长度,包括Length
+ public int Length;
+
+ // 有效数据偏移,定值,游标会在这个基础上偏移
+ // * 如果是非根消息,Offset在Length后面的位置
+ // * 如果是根消息,Offset等于0,表示有效数据在Buffer中的偏移
+ public int Offset;
+
+ public int BytesRemaining => this.Length - this.Position;
+
+ public int TotalLength => this.Length + this.Offset;
+
+ private MessageReader Parent; // 保存父消息索引,和父消息共享父消息的Buffer
+
+ // 是否是根消息,根消息下面包含多个子消息,子消息可以嵌套重孙消息
+ public bool IsRoot
+ {
+ get { return Parent == null; }
+ }
+
+ // 子消息可读
+ public bool IsReadable
+ {
+ get { return this.Parent != null; }
+ }
+
+ public int Position
+ {
+ get { return this._position; }
+ set
+ {
+ this._position = value;
+ this.readHead = value + Offset;
+ }
+ }
+
+ private int _position; // 读取游标,相对于消息内容部分的偏移,从0开始,子消息也是从0开始,不是在Buffer中的索引
+ private int readHead; // 读取游标,消息头部在Buffer中的位置,参考ReadMessage()
+
+#region 创建
+ ///
+ /// 创建一个容量至少为minSize的空缓冲区
+ ///
+ ///
+ ///
+ ///
+ public static MessageReader GetSized(int minSize, bool exactly = false)
+ {
+ var output = ReaderPool.GetObject();
+
+ if (output.Buffer == null || output.Buffer.Length < minSize)
+ {
+ output.Buffer = new byte[minSize];
+ }
+ else
+ {
+ if(exactly && output.Buffer.Length > minSize)
+ {
+ output.Buffer = new byte[minSize];
+ }
+ Array.Clear(output.Buffer, 0, output.Buffer.Length);
+ }
+
+ output.Offset = 0;
+ output.Length = 0;
+ output.Position = 0;
+ output.Parent = null;
+ return output;
+ }
+
+ ///
+ /// 将缓冲区封装为根消息,不拷贝
+ ///
+ ///
+ ///
+ public static MessageReader Get(byte[] buffer)
+ {
+ var output = ReaderPool.GetObject();
+
+ output.Buffer = buffer;
+ output.Offset = 0;
+ output.Position = 0;
+ output.Length = buffer.Length;
+ output.Parent = null;
+
+ return output;
+ }
+
+ ///
+ /// 将缓冲区封装为根消息,拷贝
+ ///
+ ///
+ ///
+ public static MessageReader GetAndCopy(byte[] buffer)
+ {
+ var output = ReaderPool.GetObject();
+
+ byte[] _buffer = new byte[buffer.Length];
+ Array.Copy(buffer, _buffer, buffer.Length);
+ output.Buffer = _buffer;
+ output.Offset = 0;
+ output.Position = 0;
+ output.Length = _buffer.Length;
+ output.Parent = null;
+
+ return output;
+ }
+
+ ///
+ /// 创建一个新的父message,保存source。用于缓存message,因为source所在的原父message可能会被销毁,如果需要延迟处理消息,需要拷贝一份新的
+ ///
+ ///
+ ///
+ public static MessageReader CopyMessageIntoParent(MessageReader source)
+ {
+ var output = MessageReader.GetSized(source.Length + 2); //2=2bytes(length)
+ System.Buffer.BlockCopy(source.Buffer, source.Offset - 2, output.Buffer, 0, source.Length + 2);
+
+ output.Offset = 0;
+ output.Position = 0;
+ output.Length = source.Length + 2;
+ output.Parent = null;
+
+ return output;
+ }
+
+#if UNIT_TEST
+ ///
+ /// 用于测试,引用buffer的一部分作为child message,后续可以直接读取
+ ///
+ ///
+ ///
+ ///
+ public static MessageReader GetChildMessage(byte[] buffer, int offset)
+ {
+ // 确保至少有一个length
+ if (offset + 2 > buffer.Length) return null;
+
+ var output = ReaderPool.GetObject();
+
+ output.Buffer = buffer;
+ output.Offset = offset;
+ output.Position = 0;
+
+ output.Length = output.ReadUInt16(); // 读到的值为length
+
+ output.Offset += 2;
+ output.Position = 0;
+ output.Parent = null;
+
+ return output;
+ }
+
+ public static MessageReader Copy(MessageReader source)
+ {
+ var output = MessageReader.GetSized(source.Buffer.Length);
+ System.Buffer.BlockCopy(source.Buffer, 0, output.Buffer, 0, source.Buffer.Length);
+
+ output.Offset = source.Offset;
+
+ output._position = source._position;
+ output.readHead = source.readHead;
+
+ output.Length = source.Length;
+
+ return output;
+ }
+
+#endif
+
+ #endregion
+
+ ///
+ /// 返回一个可读子消息,引用了父缓冲区,**不要回收**
+ ///
+ public MessageReader ReadMessage()
+ {
+ // 至少有一个length
+ if (this.BytesRemaining < 2) throw new InvalidDataException($"ReadMessage header is longer than message length: 2 of {this.BytesRemaining}");
+
+ MessageReader output = new MessageReader();
+
+ output.Parent = this;
+ output.Buffer = this.Buffer;
+ output.Offset = this.readHead;
+ output.Position = 0;
+
+ output.Length = output.ReadUInt16(); // length
+
+ output.Offset += 2; // 2=length
+ output.Position = 0;
+
+ // 数据不全
+ if (this.BytesRemaining < output.Length + 2) throw new InvalidDataException($"Message Length at Position {this.readHead} is longer than message length: {output.Length + 2} of {this.BytesRemaining}");
+
+ this.Position += output.Length + 2; //跳过整个子消息
+ return output;
+ }
+
+#if UNIT_TEST
+ ///
+ /// 仅用于测试,返回一个可读子消息,并且拷贝数据,可回收
+ /// Offset为0,开头没有Length数据
+ ///
+ public MessageReader ReadMessageAsNewBuffer()
+ {
+ if (this.BytesRemaining < 2) throw new InvalidDataException($"ReadMessage header is longer than message length: 2 of {this.BytesRemaining}");
+
+ var len = this.ReadUInt16(); // Position += 2
+
+ if (this.BytesRemaining < len) throw new InvalidDataException($"Message Length at Position {this.readHead} is longer than message length: {len} of {this.BytesRemaining}");
+
+ var output = MessageReader.GetSized(len);
+
+ Array.Copy(this.Buffer, this.readHead, output.Buffer, 0, len);
+
+ output.Length = len;
+
+ this.Position += output.Length;
+ return output;
+ }
+#endif
+
+#if UNIT_TEST
+ public MessageReader Duplicate()
+ {
+ var output = GetSized(this.Length);
+ Array.Copy(this.Buffer, this.Offset, output.Buffer, 0, this.Length);
+ output.Length = this.Length;
+ output.Offset = 0;
+ output.Position = 0;
+
+ return output;
+ }
+
+ public void RemoveMessage(MessageReader reader)
+ {
+ MessageReader temp = null;
+ try
+ {
+ var headerOffset = reader.Offset - 2;
+ var endOfMessage = reader.Offset + reader.Length; // 有效部分的后一个byte
+ var len = reader.Buffer.Length - endOfMessage;
+
+ temp = MessageReader.GetSized(len);
+ Array.Copy(reader.Buffer, endOfMessage, temp.Buffer, 0, len);
+ Array.Copy(temp.Buffer, 0, this.Buffer, headerOffset, len);
+
+ this.AdjustLength(reader.Offset, reader.Length + 2);
+ }
+ finally
+ {
+ if(temp != null)
+ {
+ temp.Recycle();
+ }
+ }
+ }
+
+ ///
+ /// 在reader前面插入一条消息
+ ///
+ /// 父reader
+ ///
+ public void InsertMessage(MessageReader reader, MessageWriter writer)
+ {
+ var temp = MessageReader.GetSized(reader.Buffer.Length);
+ try
+ {
+ var headerOffset = reader.Offset - 2;
+ var startOfMessage = reader.Offset;
+ var len = reader.Buffer.Length - headerOffset; // 疑似写错了,应该是headerOffset
+ int writerOffset = 0;
+
+ //store the original buffer in temp
+ Array.Copy(reader.Buffer, headerOffset, temp.Buffer, 0, len);
+
+ //put the contents of writer in at headerOffset
+ Array.Copy(writer.Buffer, writerOffset, this.Buffer, headerOffset, writer.Length - writerOffset);
+
+ //put the original buffer in after that
+ Array.Copy(temp.Buffer, 0, this.Buffer, headerOffset + (writer.Length - writerOffset), len - writer.Length);
+
+ this.AdjustLength(-1 * reader.Offset, -1 * (writer.Length - writerOffset));
+ }
+ finally
+ {
+ temp.Recycle();
+ }
+ }
+
+ ///
+ /// 递归调整length值
+ ///
+ /// 子消息的Offset值
+ /// 子消息总长度,含length
+ private void AdjustLength(int offset, int amount)
+ {
+ if (this.readHead > offset)
+ {
+ this.Position -= amount;
+ }
+
+ if (Parent != null)
+ {
+ var lengthOffset = this.Offset - 2;
+ var curLen = this.Buffer[lengthOffset]
+ | (this.Buffer[lengthOffset + 1] << 8);
+
+ curLen -= amount;
+ this.Length -= amount;
+
+ this.Buffer[lengthOffset] = (byte)curLen;
+ this.Buffer[lengthOffset + 1] = (byte)(curLen >> 8);
+
+ Parent.AdjustLength(offset, amount);
+ }
+ }
+
+#endif
+
+ public void Recycle()
+ {
+ this.Parent = null;
+ ReaderPool.PutObject(this);
+ }
+
+#region Read Methods
+ public bool ReadBoolean()
+ {
+ byte val = this.FastByte();
+ return val != 0;
+ }
+
+ public sbyte ReadSByte()
+ {
+ return (sbyte)this.FastByte();
+ }
+
+ public byte ReadByte()
+ {
+ return this.FastByte();
+ }
+
+ public ushort ReadUInt16()
+ {
+ ushort output =
+ (ushort)(this.FastByte()
+ | this.FastByte() << 8);
+ return output;
+ }
+
+ public short ReadInt16()
+ {
+ short output =
+ (short)(this.FastByte()
+ | this.FastByte() << 8);
+ return output;
+ }
+
+ public uint ReadUInt32()
+ {
+ uint output = this.FastByte()
+ | (uint)this.FastByte() << 8
+ | (uint)this.FastByte() << 16
+ | (uint)this.FastByte() << 24;
+
+ return output;
+ }
+
+ public int ReadInt32()
+ {
+ int output = this.FastByte()
+ | this.FastByte() << 8
+ | this.FastByte() << 16
+ | this.FastByte() << 24;
+
+ return output;
+ }
+
+ public ulong ReadUInt64()
+ {
+ ulong output = (ulong)this.FastByte()
+ | (ulong)this.FastByte() << 8
+ | (ulong)this.FastByte() << 16
+ | (ulong)this.FastByte() << 24
+ | (ulong)this.FastByte() << 32
+ | (ulong)this.FastByte() << 40
+ | (ulong)this.FastByte() << 48
+ | (ulong)this.FastByte() << 56;
+
+ return output;
+ }
+
+ public long ReadInt64()
+ {
+ long output = (long)this.FastByte()
+ | (long)this.FastByte() << 8
+ | (long)this.FastByte() << 16
+ | (long)this.FastByte() << 24
+ | (long)this.FastByte() << 32
+ | (long)this.FastByte() << 40
+ | (long)this.FastByte() << 48
+ | (long)this.FastByte() << 56;
+
+ return output;
+ }
+
+ public unsafe float ReadSingle()
+ {
+ float output = 0;
+ fixed (byte* bufPtr = &this.Buffer[this.readHead])
+ {
+ byte* outPtr = (byte*)&output;
+
+ *outPtr = *bufPtr;
+ *(outPtr + 1) = *(bufPtr + 1);
+ *(outPtr + 2) = *(bufPtr + 2);
+ *(outPtr + 3) = *(bufPtr + 3);
+ }
+
+ this.Position += 4;
+ return output;
+ }
+
+ public string ReadString()
+ {
+ int len = this.ReadPackedInt32();
+ if (this.BytesRemaining < len) throw new InvalidDataException($"Read length is longer than message length: {len} of {this.BytesRemaining}");
+
+ string output = UTF8Encoding.UTF8.GetString(this.Buffer, this.readHead, len);
+
+ this.Position += len;
+ return output;
+ }
+
+ public byte[] ReadBytesAndSize()
+ {
+ int len = this.ReadPackedInt32();
+ if (this.BytesRemaining < len) throw new InvalidDataException($"Read length is longer than message length: {len} of {this.BytesRemaining}");
+
+ return this.ReadBytes(len);
+ }
+
+ public byte[] ReadBytes(int length)
+ {
+ if (this.BytesRemaining < length) throw new InvalidDataException($"Read length is longer than message length: {length} of {this.BytesRemaining}");
+
+ byte[] output = new byte[length];
+ Array.Copy(this.Buffer, this.readHead, output, 0, output.Length);
+ this.Position += output.Length;
+ return output;
+ }
+
+ ///
+ public int ReadPackedInt32()
+ {
+ return (int)this.ReadPackedUInt32();
+ }
+
+ ///
+ public uint ReadPackedUInt32()
+ {
+ bool readMore = true;
+ int shift = 0;
+ uint output = 0;
+
+ while (readMore)
+ {
+ if (this.BytesRemaining < 1) throw new InvalidDataException($"Read length is longer than message length.");
+
+ byte b = this.ReadByte();
+ if (b >= 0x80)
+ {
+ readMore = true;
+ b ^= 0x80;
+ }
+ else
+ {
+ readMore = false;
+ }
+
+ output |= (uint)(b << shift);
+ shift += 7;
+ }
+
+ return output;
+ }
+#endregion
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private byte FastByte()
+ {
+ this._position++;
+ return this.Buffer[this.readHead++];
+ }
+
+ public unsafe static bool IsLittleEndian()
+ {
+ byte b;
+ unsafe
+ {
+ int i = 1;
+ byte* bp = (byte*)&i;
+ b = *bp;
+ }
+
+ return b == 1;
+ }
+ }
+}
diff --git a/Projects/Message/Message/MultiplayerToolkit/MessageWriter.cs b/Projects/Message/Message/MultiplayerToolkit/MessageWriter.cs
new file mode 100644
index 0000000..0b37c5d
--- /dev/null
+++ b/Projects/Message/Message/MultiplayerToolkit/MessageWriter.cs
@@ -0,0 +1,341 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace MultiplayerToolkit
+{
+
+ ///
+ /// AmongUsùȥ˰ͷش
+ /// ṹ
+ /// -------------------------------------
+ /// 2bytes (ushort)Ϣijȣ2bytes
+ /// (-------------------------------------
+ /// 1byte ϢͣϢ0ԶϢ1
+ /// (2byte) (ԶϢṩһmodţSteam.UGC.Itemidulong 8bytesеţ֧65535mod)
+ /// 2byte (ushort)ϢID 0-65535
+ ///
+ /// -------------------------------------)
+ ///
+ public class MessageWriter : IRecyclable
+ {
+ public const int BYTE_COUNT_OF_LENGTH = 2; // ռ2 bytes
+ public static int BUFFER_SIZE = 64000; // Ϣ֧64000ֽڣ62.5KB
+ public static readonly ObjectPool WriterPool = new ObjectPool(() => new MessageWriter(BUFFER_SIZE));
+
+ public byte[] Buffer;
+ public int Length; // ЧbufferеijȣܰǶϢ
+ public int Position; // дα
+
+ // lengthһڻĴСLengthһÿϢϢݲֵֽ
+
+ private Stack messageStarts = new Stack();
+
+#region
+ ///
+ /// һΪָСMessage
+ ///
+ ///
+ public MessageWriter(int bufferSize)
+ {
+ this.Buffer = new byte[bufferSize];
+ }
+
+ ///
+ /// ӳһСΪBufferSizeMessage
+ ///
+ ///
+ public static MessageWriter Get()
+ {
+ MessageWriter output = WriterPool.GetObject();
+ output.Clear();
+
+ return output;
+ }
+#endregion
+
+ public byte[] ToByteArray()
+ {
+ byte[] output = new byte[this.Length];
+ System.Buffer.BlockCopy(this.Buffer, 0, output, 0, this.Length);
+ return output;
+ }
+
+ ///
+ /// Ƿexpectedȵ
+ ///
+ ///
+ ///
+ public bool HasBytes(int expected)
+ {
+ return this.Length >= expected;
+ }
+
+ public bool HasBytesExactly(int exact)
+ {
+ return this.Length == exact;
+ }
+
+ ///
+ /// ʼдϢд2bytesΪ
+ ///
+ public void StartMessage()
+ {
+ var messageStart = this.Position;
+ messageStarts.Push(messageStart);
+ this.Buffer[messageStart] = 0; // length
+ this.Buffer[messageStart + 1] = 0; // length
+ this.Position += 2; // ushort length
+ this.Length = this.Position;
+ }
+
+#if UNIT_TEST
+ public void StartMessage(int dummy)
+ {
+ StartMessage();
+ }
+#endif
+
+ ///
+ /// ôϢȣ־Ϣ
+ ///
+ public void EndMessage()
+ {
+ var lastMessageStart = messageStarts.Pop();
+ ushort length = (ushort)(this.Position - lastMessageStart - 2); // Minus length
+ this.Buffer[lastMessageStart] = (byte)length;
+ this.Buffer[lastMessageStart + 1] = (byte)(length >> 8);
+ }
+
+ ///
+ /// ȡǰ༭messageصһ
+ ///
+ public void CancelMessage()
+ {
+ this.Position = this.messageStarts.Pop();
+ this.Length = this.Position;
+ }
+
+ public void Clear()
+ {
+ Array.Clear(this.Buffer, 0, this.Buffer.Length);
+ this.messageStarts.Clear();
+ this.Length = 0;
+ this.Position = 0;
+ }
+
+ ///
+ /// message
+ ///
+ public void Recycle()
+ {
+ this.Position = this.Length = 0;
+ WriterPool.PutObject(this);
+ }
+
+#region WriteMethods
+
+ ///
+ /// дȡϢͨڷܵϢĹ㲥תҪStart\End
+ ///
+ ///
+ public void CopyFrom(MessageReader target)
+ {
+ int offset, length;
+ if (target.IsRoot)
+ {
+ offset = target.Offset;
+ length = target.Length;
+ }
+ else
+ {
+ offset = target.Offset - 2;
+ length = target.Length + 2;
+ }
+
+ 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)
+ {
+ this.Write(msg.Buffer, 0, msg.Length);
+ }
+
+ public unsafe static bool IsLittleEndian()
+ {
+ byte b;
+ unsafe
+ {
+ int i = 1;
+ byte* bp = (byte*)&i;
+ b = *bp;
+ }
+
+ return b == 1;
+ }
+ }
+}
diff --git a/Projects/Message/Message/MultiplayerToolkit/ObjectPool.cs b/Projects/Message/Message/MultiplayerToolkit/ObjectPool.cs
new file mode 100644
index 0000000..e42cdd6
--- /dev/null
+++ b/Projects/Message/Message/MultiplayerToolkit/ObjectPool.cs
@@ -0,0 +1,108 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace MultiplayerToolkit
+{
+ ///
+ /// A fairly simple object pool for items that will be created a lot.
+ ///
+ /// The type that is pooled.
+ ///
+ public sealed class ObjectPool where T : IRecyclable
+ {
+ private int numberCreated;
+ public int NumberCreated { get { return numberCreated; } }
+
+ public int NumberInUse { get { return this.inuse.Count; } }
+ public int NumberNotInUse { get { return this.pool.Count; } }
+ public int Size { get { return this.NumberInUse + this.NumberNotInUse; } }
+
+#if HAZEL_BAG
+ private readonly ConcurrentBag pool = new ConcurrentBag();
+#else
+ private readonly List pool = new List();
+#endif
+
+ // Unavailable objects
+ private readonly ConcurrentDictionary inuse = new ConcurrentDictionary();
+
+ ///
+ /// The generator for creating new objects.
+ ///
+ ///
+ private readonly Func objectFactory;
+
+ ///
+ /// Internal constructor for our ObjectPool.
+ ///
+ internal ObjectPool(Func objectFactory)
+ {
+ this.objectFactory = objectFactory;
+ }
+
+ ///
+ /// Returns a pooled object of type T, if none are available another is created.
+ ///
+ /// An instance of T.
+ internal T GetObject()
+ {
+#if HAZEL_BAG
+ if (!pool.TryTake(out T item))
+ {
+ Interlocked.Increment(ref numberCreated);
+ item = objectFactory.Invoke();
+ }
+#else
+ T item;
+ lock (this.pool)
+ {
+ if (this.pool.Count > 0)
+ {
+ var idx = this.pool.Count - 1;
+ item = this.pool[idx];
+ this.pool.RemoveAt(idx);
+ }
+ else
+ {
+ Interlocked.Increment(ref numberCreated);
+ item = objectFactory.Invoke();
+ }
+ }
+#endif
+
+ if (!inuse.TryAdd(item, true))
+ {
+ throw new Exception("Duplicate pull " + typeof(T).Name);
+ }
+
+ return item;
+ }
+
+ ///
+ /// Returns an object to the pool.
+ ///
+ /// The item to return.
+ internal void PutObject(T item)
+ {
+ if (inuse.TryRemove(item, out bool b))
+ {
+#if HAZEL_BAG
+ pool.Add(item);
+#else
+ lock (this.pool)
+ {
+ pool.Add(item);
+ }
+#endif
+ }
+ else
+ {
+#if DEBUG
+ throw new Exception("Duplicate add " + typeof(T).Name);
+#endif
+ }
+ }
+ }
+}
diff --git a/Projects/Message/Message/ObjectPool.cs b/Projects/Message/Message/ObjectPool.cs
deleted file mode 100644
index e42cdd6..0000000
--- a/Projects/Message/Message/ObjectPool.cs
+++ /dev/null
@@ -1,108 +0,0 @@
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Threading;
-
-namespace MultiplayerToolkit
-{
- ///
- /// A fairly simple object pool for items that will be created a lot.
- ///
- /// The type that is pooled.
- ///
- public sealed class ObjectPool where T : IRecyclable
- {
- private int numberCreated;
- public int NumberCreated { get { return numberCreated; } }
-
- public int NumberInUse { get { return this.inuse.Count; } }
- public int NumberNotInUse { get { return this.pool.Count; } }
- public int Size { get { return this.NumberInUse + this.NumberNotInUse; } }
-
-#if HAZEL_BAG
- private readonly ConcurrentBag pool = new ConcurrentBag();
-#else
- private readonly List pool = new List();
-#endif
-
- // Unavailable objects
- private readonly ConcurrentDictionary inuse = new ConcurrentDictionary();
-
- ///
- /// The generator for creating new objects.
- ///
- ///
- private readonly Func objectFactory;
-
- ///
- /// Internal constructor for our ObjectPool.
- ///
- internal ObjectPool(Func objectFactory)
- {
- this.objectFactory = objectFactory;
- }
-
- ///
- /// Returns a pooled object of type T, if none are available another is created.
- ///
- /// An instance of T.
- internal T GetObject()
- {
-#if HAZEL_BAG
- if (!pool.TryTake(out T item))
- {
- Interlocked.Increment(ref numberCreated);
- item = objectFactory.Invoke();
- }
-#else
- T item;
- lock (this.pool)
- {
- if (this.pool.Count > 0)
- {
- var idx = this.pool.Count - 1;
- item = this.pool[idx];
- this.pool.RemoveAt(idx);
- }
- else
- {
- Interlocked.Increment(ref numberCreated);
- item = objectFactory.Invoke();
- }
- }
-#endif
-
- if (!inuse.TryAdd(item, true))
- {
- throw new Exception("Duplicate pull " + typeof(T).Name);
- }
-
- return item;
- }
-
- ///
- /// Returns an object to the pool.
- ///
- /// The item to return.
- internal void PutObject(T item)
- {
- if (inuse.TryRemove(item, out bool b))
- {
-#if HAZEL_BAG
- pool.Add(item);
-#else
- lock (this.pool)
- {
- pool.Add(item);
- }
-#endif
- }
- else
- {
-#if DEBUG
- throw new Exception("Duplicate add " + typeof(T).Name);
-#endif
- }
- }
- }
-}
--
cgit v1.1-26-g67d0