aboutsummaryrefslogtreecommitdiff
path: root/Projects
diff options
context:
space:
mode:
Diffstat (limited to 'Projects')
-rw-r--r--Projects/Message/Message/Message.csproj13
-rw-r--r--Projects/Message/Message/MessageReader.cs252
-rw-r--r--Projects/Message/Message/MessageWriter.cs80
-rw-r--r--Projects/Message/Message/MessageWriterTests.cs260
-rw-r--r--Projects/Message/Message/Properties/Settings.Designer.cs26
-rw-r--r--Projects/Message/Message/Properties/Settings.settings6
-rw-r--r--Projects/Message/Message/UnitTest1.cs16
7 files changed, 500 insertions, 153 deletions
diff --git a/Projects/Message/Message/Message.csproj b/Projects/Message/Message/Message.csproj
index f2f13d5..a15b051 100644
--- a/Projects/Message/Message/Message.csproj
+++ b/Projects/Message/Message/Message.csproj
@@ -26,7 +26,7 @@
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <DefineConstants>TRACE;DEBUG;UNIT_TEST</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
@@ -54,12 +54,21 @@
<Compile Include="IRecyclable.cs" />
<Compile Include="MessageReader.cs" />
<Compile Include="MessageWriter.cs" />
+ <Compile Include="MessageWriterTests.cs" />
<Compile Include="ObjectPool.cs" />
- <Compile Include="UnitTest1.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="Properties\Settings.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTimeSharedInput>True</DesignTimeSharedInput>
+ <DependentUpon>Settings.settings</DependentUpon>
+ </Compile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
+ <None Include="Properties\Settings.settings">
+ <Generator>SettingsSingleFileGenerator</Generator>
+ <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+ </None>
</ItemGroup>
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
diff --git a/Projects/Message/Message/MessageReader.cs b/Projects/Message/Message/MessageReader.cs
index 7ec134b..b49f9e2 100644
--- a/Projects/Message/Message/MessageReader.cs
+++ b/Projects/Message/Message/MessageReader.cs
@@ -7,38 +7,63 @@ using System.Text;
namespace MultiplayerToolkit
{
/// <summary>
- ///
+ /// 可以处理嵌套消息的结构,和MessageWriter配对
/// </summary>
public class MessageReader : IRecyclable
{
public static readonly ObjectPool<MessageReader> ReaderPool = new ObjectPool<MessageReader>(() => new MessageReader());
- public byte[] Buffer; // √ 缓冲区,会被子协议共享这个缓冲区
- public byte Tag; // √ 协议名
+ public byte[] Buffer; // 缓冲区,会被子消息共享这个缓冲区
- public int Length; // √ 协议长度,对应的是MessageWriter里写入的2bytes包长度(不含length和tag)
- public int Offset; // √ length和tag后面的位置(在Buffer中的位置),不是游标,不会随读取发生改变。会影响readHead的值
+ // 消息长度,定值
+ // * 如果是非根消息,对应的是MessageWriter里写入的2bytes包长度,即不含length的长度
+ // * 如果是根消息,Length是整个有效数据在Buffer中的长度,包括Length
+ public int Length;
- //数据位于Buffer中Offset索引开始Length长度,协议位于Buffer中Offset-3开始的Length+3长度
+ // 有效数据偏移,定值,游标会在这个基础上偏移
+ // * 如果是非根消息,Offset在Length后面的位置
+ // * 如果是根消息,Offset等于0,表示有效数据在Buffer中的偏移
+ public int Offset;
public int BytesRemaining => this.Length - this.Position;
- private MessageReader Parent; // 保存父协议索引,和父协议共享父协议的Buffer
+ 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; // value是
+ this._position = value;
this.readHead = value + Offset;
}
}
- private int _position; // √ 读取游标,相对于协议内容部分的偏移,从0开始,子协议也是从0开始,不是在Buffer中的索引
- private int readHead; // √ 读取游标,协议头部在Buffer中的位置,参考ReadMessage()
+ private int _position; // 读取游标,相对于消息内容部分的偏移,从0开始,子消息也是从0开始,不是在Buffer中的索引
+ private int readHead; // 读取游标,消息头部在Buffer中的位置,参考ReadMessage()
- public static MessageReader GetSized(int minSize)
+#region 创建
+ /// <summary>
+ /// 创建一个容量至少为minSize的空缓冲区
+ /// </summary>
+ /// <param name="minSize"></param>
+ /// <param name="exactly"></param>
+ /// <returns></returns>
+ public static MessageReader GetSized(int minSize, bool exactly = false)
{
var output = ReaderPool.GetObject();
@@ -48,15 +73,25 @@ namespace MultiplayerToolkit
}
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.Tag = byte.MaxValue;
+ output.Parent = null;
return output;
}
+ /// <summary>
+ /// 将缓冲区封装为根MessageReader,不拷贝
+ /// </summary>
+ /// <param name="buffer"></param>
+ /// <returns></returns>
public static MessageReader Get(byte[] buffer)
{
var output = ReaderPool.GetObject();
@@ -65,53 +100,60 @@ namespace MultiplayerToolkit
output.Offset = 0;
output.Position = 0;
output.Length = buffer.Length;
- output.Tag = byte.MaxValue;
+ output.Parent = null;
return output;
}
/// <summary>
- /// 创建一个新的父message,保存source。用于缓存message,因为source所在的原父message可能会被销毁,如果需要延迟处理消息,需要拷贝一份新的
+ /// 拷贝buffer,封装为根MessageReader
/// </summary>
- /// <param name="source"></param>
+ /// <param name="buffer"></param>
/// <returns></returns>
- public static MessageReader CopyMessageIntoParent(MessageReader source)
+ public static MessageReader GetAndCopy(byte[] buffer)
{
- var output = MessageReader.GetSized(source.Length + 3); //3=2bytes(length) + 1byte(tag)
- System.Buffer.BlockCopy(source.Buffer, source.Offset - 3, output.Buffer, 0, source.Length + 3);
+ 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 = source.Length + 3;
+ output.Length = _buffer.Length;
+ output.Parent = null;
return output;
}
/// <summary>
- /// 完全复制 一份
+ /// 创建一个新的父message,保存source。用于缓存message,因为source所在的原父message可能会被销毁,如果需要延迟处理消息,需要拷贝一份新的
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
- public static MessageReader Get(MessageReader source)
+ public static MessageReader CopyMessageIntoParent(MessageReader source)
{
- var output = MessageReader.GetSized(source.Buffer.Length);
- System.Buffer.BlockCopy(source.Buffer, 0, output.Buffer, 0, source.Buffer.Length);
+ 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 = source.Offset;
-
- output._position = source._position;
- output.readHead = source.readHead;
-
- output.Length = source.Length;
- output.Tag = source.Tag;
+ output.Offset = 0;
+ output.Position = 0;
+ output.Length = source.Length + 2;
+ output.Parent = null;
return output;
}
- public static MessageReader Get(byte[] buffer, int offset)
+#if UNIT_TEST
+ /// <summary>
+ /// 用于测试,引用buffer的一部分作为child message,后续可以直接读取
+ /// </summary>
+ /// <param name="buffer"></param>
+ /// <param name="offset"></param>
+ /// <returns></returns>
+ public static MessageReader GetChildMessage(byte[] buffer, int offset)
{
- // Ensure there is at least a header
- if (offset + 3 > buffer.Length) return null;
+ // 确保至少有一个length
+ if (offset + 2 > buffer.Length) return null;
var output = ReaderPool.GetObject();
@@ -120,52 +162,54 @@ namespace MultiplayerToolkit
output.Position = 0;
output.Length = output.ReadUInt16(); // 读到的值为length
- output.Tag = output.ReadByte();
- output.Offset += 3;
+ output.Offset += 2;
output.Position = 0;
+ output.Parent = null;
return output;
}
+#endif
+
+#endregion
/// <summary>
- /// Produces a MessageReader using the parent's buffer. This MessageReader should **NOT** be recycled.
+ /// 返回一个可读子消息,引用了父缓冲区,**不要回收**
/// </summary>
public MessageReader ReadMessage()
{
- // Ensure there is at least a header
- if (this.BytesRemaining < 3) throw new InvalidDataException($"ReadMessage header is longer than message length: 3 of {this.BytesRemaining}");
+ // 至少有一个length
+ if (this.BytesRemaining < 2) throw new InvalidDataException($"ReadMessage header is longer than message length: 3 of {this.BytesRemaining}");
MessageReader output = new MessageReader();
output.Parent = this;
output.Buffer = this.Buffer;
- output.Offset = this.readHead; // 下面会读取
+ output.Offset = this.readHead;
output.Position = 0;
- // 读length和tag的值并保存在字段里
- output.Length = output.ReadUInt16();
- output.Tag = output.ReadByte();
+ output.Length = output.ReadUInt16(); // length
- // Offset, readHead齐步走,移到Length和Tag后面,_position=0
- output.Offset += 3; // 3=length+tag
+ output.Offset += 2; // 2=length
output.Position = 0;
- if (this.BytesRemaining < output.Length + 3) throw new InvalidDataException($"Message Length at Position {this.readHead} is longer than message length: {output.Length + 3} of {this.BytesRemaining}");
+ // 数据不全
+ 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 + 3; //跳过整个子协议
+ this.Position += output.Length + 2; //跳过整个子消息
return output;
}
+#if UNIT_TEST
/// <summary>
- /// Produces a MessageReader with a new buffer. This MessageReader should be recycled.
+ /// 仅用于测试,返回一个可读子消息,并且拷贝数据,可回收
+ /// Offset为0,开头没有Length数据
/// </summary>
public MessageReader ReadMessageAsNewBuffer()
{
- if (this.BytesRemaining < 3) throw new InvalidDataException($"ReadMessage header is longer than message length: 3 of {this.BytesRemaining}");
+ if (this.BytesRemaining < 2) throw new InvalidDataException($"ReadMessage header is longer than message length: 3 of {this.BytesRemaining}");
- var len = this.ReadUInt16();
- var tag = this.ReadByte();
+ 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}");
@@ -174,19 +218,14 @@ namespace MultiplayerToolkit
Array.Copy(this.Buffer, this.readHead, output.Buffer, 0, len);
output.Length = len;
- output.Tag = tag;
+ //output.Tag = tag;
this.Position += output.Length;
return output;
}
+#endif
- public MessageWriter StartWriter()
- {
- var output = new MessageWriter(this.Buffer);
- output.Position = this.readHead;
- return output;
- }
-
+#if UNIT_TEST
public MessageReader Duplicate()
{
var output = GetSized(this.Length);
@@ -200,60 +239,65 @@ namespace MultiplayerToolkit
public void RemoveMessage(MessageReader reader)
{
- var temp = MessageReader.GetSized(reader.Buffer.Length);
+ MessageReader temp = null;
try
{
- var headerOffset = reader.Offset - 3;
- var endOfMessage = reader.Offset + reader.Length;
- var len = reader.Buffer.Length - endOfMessage;
+ var headerOffset = reader.Offset - 2;
+ var endOfMessage = reader.Offset + reader.Length; // 有效部分的后一个byte
+ var len = this.TotalLength - 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 + 3);
+ this.AdjustLength(reader.Offset, reader.Length + 2);
}
finally
{
- temp.Recycle();
+ if(temp != null)
+ {
+ temp.Recycle();
+ }
}
}
- //public void InsertMessage(MessageReader reader, MessageWriter writer)
- //{
- // var temp = MessageReader.GetSized(reader.Buffer.Length);
- // try
- // {
- // var headerOffset = reader.Offset - 3;
- // var startOfMessage = reader.Offset;
- // var len = reader.Buffer.Length - startOfMessage;
- // int writerOffset = 3;
- // switch (writer.SendOption)
- // {
- // case SendOption.Reliable:
- // writerOffset = 3;
- // break;
- // case SendOption.None:
- // writerOffset = 1;
- // break;
- // }
-
- // //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();
- // }
- //}
+ /// <summary>
+ /// 在reader前面插入一条消息
+ /// </summary>
+ /// <param name="reader">父reader</param>
+ /// <param name="writer"></param>
+ public void InsertMessage(MessageReader reader, MessageWriter writer)
+ {
+ var temp = MessageReader.GetSized(reader.Buffer.Length);
+ try
+ {
+ var headerOffset = reader.Offset - 3; // headerOffset是length+tag,这个方法仅仅接受reader不含sendoption的情况
+ 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();
+ }
+ }
+ /// <summary>
+ /// 递归调整length值
+ /// </summary>
+ /// <param name="offset">子消息的Offset值</param>
+ /// <param name="amount">子消息总长度,含length</param>
private void AdjustLength(int offset, int amount)
{
if (this.readHead > offset)
@@ -263,7 +307,7 @@ namespace MultiplayerToolkit
if (Parent != null)
{
- var lengthOffset = this.Offset - 3;
+ var lengthOffset = this.Offset - 2;
var curLen = this.Buffer[lengthOffset]
| (this.Buffer[lengthOffset + 1] << 8);
@@ -271,19 +315,21 @@ namespace MultiplayerToolkit
this.Length -= amount;
this.Buffer[lengthOffset] = (byte)curLen;
- this.Buffer[lengthOffset + 1] = (byte)(this.Buffer[lengthOffset + 1] >> 8);
+ this.Buffer[lengthOffset + 1] = (byte)(curLen >> 8);
Parent.AdjustLength(offset, amount);
}
}
+#endif
+
public void Recycle()
{
this.Parent = null;
ReaderPool.PutObject(this);
}
- #region Read Methods
+#region Read Methods
public bool ReadBoolean()
{
byte val = this.FastByte();
@@ -444,7 +490,7 @@ namespace MultiplayerToolkit
return output;
}
- #endregion
+#endregion
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private byte FastByte()
diff --git a/Projects/Message/Message/MessageWriter.cs b/Projects/Message/Message/MessageWriter.cs
index 7646135..845a901 100644
--- a/Projects/Message/Message/MessageWriter.cs
+++ b/Projects/Message/Message/MessageWriter.cs
@@ -10,48 +10,42 @@ namespace MultiplayerToolkit
/// AmongUsùȥ˰ͷش
/// ṹ
/// -------------------------------------
- /// 2bytes (ushort)Эijȣ2bytes
- /// -------------------------------------
- /// 1byte ЭͣЭ0ԶЭ1
- /// (2byte) (ԶЭ飬ṩһmodţSteam.UGC.Itemidulong 8bytesе󣬻ţ֧65535mod)
- /// 2byte (ushort)ЭID 0-65535
+ /// 2bytes (ushort)Ϣijȣ2bytes
+ /// (-------------------------------------
+ /// 1byte ϢͣϢ0ԶϢ1
+ /// (2byte) (ԶϢṩһmodţSteam.UGC.Itemidulong 8bytesе󣬻ţ֧65535mod)
+ /// 2byte (ushort)ϢID 0-65535
///
- /// -------------------------------------
+ /// -------------------------------------)
/// </summary>
public class MessageWriter : IRecyclable
{
public const int BYTE_COUNT_OF_LENGTH = 2; // ռ2 bytes
- public static int BufferSize = 64000; // Э֧64000ֽڣ62.5KB
- public static readonly ObjectPool<MessageWriter> WriterPool = new ObjectPool<MessageWriter>(() => new MessageWriter(BufferSize));
+ public static int BUFFER_SIZE = 64000; // Ϣ֧64000ֽڣ62.5KB
+ public static readonly ObjectPool<MessageWriter> WriterPool = new ObjectPool<MessageWriter>(() => new MessageWriter(BUFFER_SIZE));
public byte[] Buffer;
- public int Length; // ЧbufferеijȣܰǶЭ
- public int Position; // дλ
-
- // lengthһڻĴСLengthһÿЭЭݲֵֽ
+ public int Length; // ЧbufferеijȣܰǶϢ
+ public int Position; // дα
- private Stack<int> messageStarts = new Stack<int>(); // ¼ЭbufferеʼλãǶ׽ṹ
+ // lengthһڻĴСLengthһÿϢϢݲֵֽ
- public MessageWriter(byte[] buffer)
- {
- this.Buffer = buffer;
- this.Length = this.Buffer.Length;
- }
+ private Stack<int> messageStarts = new Stack<int>(); // ¼ϢbufferеʼλãǶ׽ṹ
- ///
+#region
+ /// <summary>
+ /// һΪָСMessage
+ /// </summary>
+ /// <param name="bufferSize"></param>
public MessageWriter(int bufferSize)
{
this.Buffer = new byte[bufferSize];
}
- public byte[] ToByteArray()
- {
- byte[] output = new byte[this.Length];
- System.Buffer.BlockCopy(this.Buffer, 0, output, 0, this.Length);
- return output;
- }
-
- /// <param name="sendOption">The option specifying how the message should be sent.</param>
+ /// <summary>
+ /// ӳһСΪBufferSizeMessage
+ /// </summary>
+ /// <returns></returns>
public static MessageWriter Get()
{
MessageWriter output = WriterPool.GetObject();
@@ -59,6 +53,14 @@ namespace MultiplayerToolkit
return output;
}
+#endregion
+
+ public byte[] ToByteArray()
+ {
+ byte[] output = new byte[this.Length];
+ System.Buffer.BlockCopy(this.Buffer, 0, output, 0, this.Length);
+ return output;
+ }
/// <summary>
/// Ƿexpectedȵ
@@ -70,7 +72,14 @@ namespace MultiplayerToolkit
return this.Length >= expected;
}
- ///
+ public bool HasBytesExactly(int exact)
+ {
+ return this.Length == exact;
+ }
+
+ /// <summary>
+ /// ʼдϢд2bytesΪ
+ /// </summary>
public void StartMessage()
{
var messageStart = this.Position;
@@ -78,9 +87,12 @@ namespace MultiplayerToolkit
this.Buffer[messageStart] = 0; // length
this.Buffer[messageStart + 1] = 0; // length
this.Position += 2; // ushort length
+ this.Length = this.Position;
}
- ///
+ /// <summary>
+ /// ôϢȣ־Ϣ
+ /// </summary>
public void EndMessage()
{
var lastMessageStart = messageStarts.Pop();
@@ -117,18 +129,22 @@ namespace MultiplayerToolkit
#region WriteMethods
+ /// <summary>
+ /// дȡϢͨڷܵϢĹ㲥תҪStart\End
+ /// </summary>
+ /// <param name="target"></param>
public void CopyFrom(MessageReader target)
{
int offset, length;
- if (target.Tag == byte.MaxValue)
+ if (target.IsRoot)
{
offset = target.Offset;
length = target.Length;
}
else
{
- offset = target.Offset - 3;
- length = target.Length + 3;
+ offset = target.Offset - 2;
+ length = target.Length + 2;
}
System.Buffer.BlockCopy(target.Buffer, offset, this.Buffer, this.Position, length);
diff --git a/Projects/Message/Message/MessageWriterTests.cs b/Projects/Message/Message/MessageWriterTests.cs
new file mode 100644
index 0000000..9a873a5
--- /dev/null
+++ b/Projects/Message/Message/MessageWriterTests.cs
@@ -0,0 +1,260 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+
+namespace MultiplayerToolkit
+{
+
+ [TestClass]
+ public class MessageWriterTests
+ {
+
+ [TestMethod]
+ public void HasBytesExactly()
+ {
+ var msg = new MessageWriter(128);
+
+ msg.StartMessage();
+ Assert.IsTrue(msg.HasBytesExactly(2));
+ msg.Write((int)32);
+ Assert.IsTrue(msg.HasBytesExactly(6));
+ msg.EndMessage();
+
+ msg.StartMessage();
+ Assert.IsTrue(msg.HasBytesExactly(8));
+ msg.Write((short)2);
+ Assert.IsTrue(msg.HasBytesExactly(10));
+ msg.EndMessage();
+ Assert.IsTrue(msg.HasBytesExactly(10));
+ }
+
+ [TestMethod]
+ public void HasBytesExactlyNest()
+ {
+ var msg = new MessageWriter(128);
+
+ msg.StartMessage();
+ Assert.IsTrue(msg.HasBytesExactly(2));
+ msg.Write((int)32);
+ Assert.IsTrue(msg.HasBytesExactly(6));
+ //msg.EndMessage();
+
+ msg.StartMessage();
+ Assert.IsTrue(msg.HasBytesExactly(8));
+ msg.Write((short)2);
+ Assert.IsTrue(msg.HasBytesExactly(10));
+ msg.EndMessage();
+ msg.EndMessage();
+ Assert.IsTrue(msg.HasBytesExactly(10));
+ }
+
+ [TestMethod]
+ public void HasBytesExactlyGet()
+ {
+ var msg = MessageWriter.Get();
+
+ msg.StartMessage();
+ Assert.IsTrue(msg.HasBytesExactly(2));
+ msg.Write((int)32);
+ Assert.IsTrue(msg.HasBytesExactly(6));
+ msg.EndMessage();
+
+ msg.StartMessage();
+ Assert.IsTrue(msg.HasBytesExactly(8));
+ msg.Write((short)2);
+ Assert.IsTrue(msg.HasBytesExactly(10));
+ msg.EndMessage();
+ Assert.IsTrue(msg.HasBytesExactly(10));
+ }
+
+ [TestMethod]
+ public void CancelMessages()
+ {
+ var msg = new MessageWriter(128);
+
+ msg.StartMessage();
+ msg.Write(32);
+
+ msg.StartMessage();
+ msg.Write(2);
+ msg.CancelMessage();
+
+ Assert.AreEqual(6, msg.Length);
+ Assert.IsTrue(msg.HasBytes(6));
+
+ msg.CancelMessage();
+
+ Assert.AreEqual(0, msg.Length);
+ Assert.IsFalse(msg.HasBytes(1));
+ }
+
+
+ [TestMethod]
+ public void WriteProperInt()
+ {
+ const int Test1 = int.MaxValue;
+ const int Test2 = int.MinValue;
+
+ var msg = new MessageWriter(128);
+ msg.Write(Test1);
+ msg.Write(Test2);
+
+ Assert.AreEqual(8, msg.Length);
+ Assert.AreEqual(msg.Length, msg.Position);
+
+ using (MemoryStream m = new MemoryStream(msg.Buffer, 0, msg.Length))
+ using (BinaryReader reader = new BinaryReader(m))
+ {
+ Assert.AreEqual(Test1, reader.ReadInt32());
+ Assert.AreEqual(Test2, reader.ReadInt32());
+ }
+ }
+
+ [TestMethod]
+ public void WriteProperBool()
+ {
+ const bool Test1 = true;
+ const bool Test2 = false;
+
+ var msg = new MessageWriter(128);
+ msg.Write(Test1);
+ msg.Write(Test2);
+
+ Assert.AreEqual(2, msg.Length);
+ Assert.AreEqual(msg.Length, msg.Position);
+
+ using (MemoryStream m = new MemoryStream(msg.Buffer, 0, msg.Length))
+ using (BinaryReader reader = new BinaryReader(m))
+ {
+ Assert.AreEqual(Test1, reader.ReadBoolean());
+ Assert.AreEqual(Test2, reader.ReadBoolean());
+ }
+ }
+
+ [TestMethod]
+ public void WriteProperString()
+ {
+ const string Test1 = "Hello";
+ string Test2 = new string(' ', 1024);
+ var msg = new MessageWriter(2048);
+ msg.Write(Test1);
+ msg.Write(Test2);
+ msg.Write(string.Empty);
+
+ Assert.AreEqual(msg.Length, msg.Position);
+
+ using (MemoryStream m = new MemoryStream(msg.Buffer, 0, msg.Length))
+ using (BinaryReader reader = new BinaryReader(m))
+ {
+ Assert.AreEqual(Test1, reader.ReadString());
+ Assert.AreEqual(Test2, reader.ReadString());
+ Assert.AreEqual(string.Empty, reader.ReadString());
+ }
+ }
+
+ [TestMethod]
+ public void WriteProperFloat()
+ {
+ const float Test1 = 12.34f;
+
+ var msg = new MessageWriter(2048);
+ msg.Write(Test1);
+
+ Assert.AreEqual(msg.Length, msg.Position);
+
+ using (MemoryStream m = new MemoryStream(msg.Buffer, 0, msg.Length))
+ using (BinaryReader reader = new BinaryReader(m))
+ {
+ Assert.AreEqual(Test1, reader.ReadSingle());
+ }
+ }
+
+ [TestMethod]
+ public void WritePackedUint()
+ {
+ var msg = new MessageWriter(2048);
+ msg.StartMessage();
+ msg.WritePacked(8u);
+ msg.WritePacked(250u);
+ msg.WritePacked(68000u);
+ msg.EndMessage();
+
+ Assert.AreEqual(2 + 1 + 2 + 3, msg.Position);
+ Assert.AreEqual(msg.Length, msg.Position);
+
+ MessageReader reader = MessageReader.GetChildMessage(msg.Buffer, 0);
+
+ Assert.AreEqual(8u, reader.ReadPackedUInt32());
+ Assert.AreEqual(250u, reader.ReadPackedUInt32());
+ Assert.AreEqual(68000u, reader.ReadPackedUInt32());
+ }
+
+ [TestMethod]
+ public void WritePackedInt()
+ {
+ var msg = new MessageWriter(2048);
+ msg.StartMessage();
+ msg.WritePacked(8);
+ msg.WritePacked(250);
+ msg.WritePacked(68000);
+ msg.WritePacked(60168000);
+ msg.WritePacked(-68000);
+ msg.WritePacked(-250);
+ msg.WritePacked(-8);
+
+ msg.WritePacked(0);
+ msg.WritePacked(-1);
+ msg.WritePacked(int.MinValue);
+ msg.WritePacked(int.MaxValue);
+ msg.EndMessage();
+
+ Assert.AreEqual(2 + 1 + 2 + 3 + 4 + 5 + 5 + 5 + 1 + 5 + 5 + 5, msg.Position);
+ Assert.AreEqual(msg.Length, msg.Position);
+
+ MessageReader reader = MessageReader.GetChildMessage(msg.Buffer, 0);
+
+ Assert.AreEqual(8, reader.ReadPackedInt32());
+ Assert.AreEqual(250, reader.ReadPackedInt32());
+ Assert.AreEqual(68000, reader.ReadPackedInt32());
+ Assert.AreEqual(60168000, reader.ReadPackedInt32());
+
+ Assert.AreEqual(-68000, reader.ReadPackedInt32());
+ Assert.AreEqual(-250, reader.ReadPackedInt32());
+ Assert.AreEqual(-8, reader.ReadPackedInt32());
+
+ Assert.AreEqual(0, reader.ReadPackedInt32());
+ Assert.AreEqual(-1, reader.ReadPackedInt32());
+ Assert.AreEqual(int.MinValue, reader.ReadPackedInt32());
+ Assert.AreEqual(int.MaxValue, reader.ReadPackedInt32());
+ }
+
+ [TestMethod]
+ public void WritesMessageLength()
+ {
+ var msg = new MessageWriter(2048);
+ msg.StartMessage();
+ msg.Write(65534);
+ msg.EndMessage();
+
+ Assert.AreEqual(2 + 4, msg.Position);
+ Assert.AreEqual(msg.Length, msg.Position);
+
+ using (MemoryStream m = new MemoryStream(msg.Buffer, 0, msg.Length))
+ using (BinaryReader reader = new BinaryReader(m))
+ {
+ Assert.AreEqual(4, reader.ReadUInt16()); // Length After Type and Target
+ Assert.AreEqual(65534, reader.ReadInt32()); // Content
+ }
+ }
+
+ [TestMethod]
+ public void GetLittleEndian()
+ {
+ Assert.IsTrue(MessageWriter.IsLittleEndian());
+ }
+
+ }
+} \ No newline at end of file
diff --git a/Projects/Message/Message/Properties/Settings.Designer.cs b/Projects/Message/Message/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..47da87d
--- /dev/null
+++ b/Projects/Message/Message/Properties/Settings.Designer.cs
@@ -0,0 +1,26 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// 此代码由工具生成。
+// 运行时版本:4.0.30319.42000
+//
+// 对此文件的更改可能会导致不正确的行为,并且如果
+// 重新生成代码,这些更改将会丢失。
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace Message.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.4.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default {
+ get {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/Projects/Message/Message/Properties/Settings.settings b/Projects/Message/Message/Properties/Settings.settings
new file mode 100644
index 0000000..049245f
--- /dev/null
+++ b/Projects/Message/Message/Properties/Settings.settings
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
+ <Profiles>
+ <Profile Name="(Default)" />
+ </Profiles>
+</SettingsFile>
diff --git a/Projects/Message/Message/UnitTest1.cs b/Projects/Message/Message/UnitTest1.cs
deleted file mode 100644
index 2e02c6e..0000000
--- a/Projects/Message/Message/UnitTest1.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System;
-
-namespace Message
-{
- [TestClass]
- public class UnitTest1
- {
- [TestMethod]
- public void TestMethod1()
- {
-
- Assert.AreEqual(1, 1);
- }
- }
-}