Mirror/Unity-Technologies-networking/Runtime/NetworkBuffer.cs

194 lines
5.6 KiB
C#

#if ENABLE_UNET
using System;
using System.Runtime.InteropServices;
namespace UnityEngine.Networking
{
// A growable buffer class used by NetworkReader and NetworkWriter.
// this is used instead of MemoryStream and BinaryReader/BinaryWriter to avoid allocations.
class NetBuffer
{
byte[] m_Buffer;
uint m_Pos;
const int k_InitialSize = 64;
const float k_GrowthFactor = 1.5f;
const int k_BufferSizeWarning = 1024 * 1024 * 128;
public uint Position { get { return m_Pos; } }
public int Length { get { return m_Buffer.Length; } }
public NetBuffer()
{
m_Buffer = new byte[k_InitialSize];
}
// this does NOT copy the buffer
public NetBuffer(byte[] buffer)
{
m_Buffer = buffer;
}
public byte ReadByte()
{
if (m_Pos >= m_Buffer.Length)
{
throw new IndexOutOfRangeException("NetworkReader:ReadByte out of range:" + ToString());
}
return m_Buffer[m_Pos++];
}
public void ReadBytes(byte[] buffer, uint count)
{
if (m_Pos + count > m_Buffer.Length)
{
throw new IndexOutOfRangeException("NetworkReader:ReadBytes out of range: (" + count + ") " + ToString());
}
for (ushort i = 0; i < count; i++)
{
buffer[i] = m_Buffer[m_Pos + i];
}
m_Pos += count;
}
internal ArraySegment<byte> AsArraySegment()
{
return new ArraySegment<byte>(m_Buffer, 0, (int)m_Pos);
}
public void WriteByte(byte value)
{
WriteCheckForSpace(1);
m_Buffer[m_Pos] = value;
m_Pos += 1;
}
public void WriteByte2(byte value0, byte value1)
{
WriteCheckForSpace(2);
m_Buffer[m_Pos] = value0;
m_Buffer[m_Pos + 1] = value1;
m_Pos += 2;
}
public void WriteByte4(byte value0, byte value1, byte value2, byte value3)
{
WriteCheckForSpace(4);
m_Buffer[m_Pos] = value0;
m_Buffer[m_Pos + 1] = value1;
m_Buffer[m_Pos + 2] = value2;
m_Buffer[m_Pos + 3] = value3;
m_Pos += 4;
}
public void WriteByte8(byte value0, byte value1, byte value2, byte value3, byte value4, byte value5, byte value6, byte value7)
{
WriteCheckForSpace(8);
m_Buffer[m_Pos] = value0;
m_Buffer[m_Pos + 1] = value1;
m_Buffer[m_Pos + 2] = value2;
m_Buffer[m_Pos + 3] = value3;
m_Buffer[m_Pos + 4] = value4;
m_Buffer[m_Pos + 5] = value5;
m_Buffer[m_Pos + 6] = value6;
m_Buffer[m_Pos + 7] = value7;
m_Pos += 8;
}
// every other Write() function in this class writes implicitly at the end-marker m_Pos.
// this is the only Write() function that writes to a specific location within the buffer
public void WriteBytesAtOffset(byte[] buffer, ushort targetOffset, ushort count)
{
uint newEnd = (uint)(count + targetOffset);
WriteCheckForSpace((ushort)newEnd);
if (targetOffset == 0 && count == buffer.Length)
{
buffer.CopyTo(m_Buffer, (int)m_Pos);
}
else
{
//CopyTo doesnt take a count :(
for (int i = 0; i < count; i++)
{
m_Buffer[targetOffset + i] = buffer[i];
}
}
// although this writes within the buffer, it could move the end-marker
if (newEnd > m_Pos)
{
m_Pos = newEnd;
}
}
public void WriteBytes(byte[] buffer, ushort count)
{
WriteCheckForSpace(count);
if (count == buffer.Length)
{
buffer.CopyTo(m_Buffer, (int)m_Pos);
}
else
{
//CopyTo doesnt take a count :(
for (int i = 0; i < count; i++)
{
m_Buffer[m_Pos + i] = buffer[i];
}
}
m_Pos += count;
}
void WriteCheckForSpace(ushort count)
{
if (m_Pos + count < m_Buffer.Length)
return;
int newLen = (int)Math.Ceiling(m_Buffer.Length * k_GrowthFactor);
while (m_Pos + count >= newLen)
{
newLen = (int)Math.Ceiling(newLen * k_GrowthFactor);
if (newLen > k_BufferSizeWarning)
{
Debug.LogWarning("NetworkBuffer size is " + newLen + " bytes!");
}
}
// only do the copy once, even if newLen is increased multiple times
byte[] tmp = new byte[newLen];
m_Buffer.CopyTo(tmp, 0);
m_Buffer = tmp;
}
public void FinishMessage()
{
// two shorts (size and msgType) are in header.
ushort sz = (ushort)(m_Pos - (sizeof(ushort) * 2));
m_Buffer[0] = (byte)(sz & 0xff);
m_Buffer[1] = (byte)((sz >> 8) & 0xff);
}
public void SeekZero()
{
m_Pos = 0;
}
public void Replace(byte[] buffer)
{
m_Buffer = buffer;
m_Pos = 0;
}
public override string ToString()
{
return String.Format("NetBuf sz:{0} pos:{1}", m_Buffer.Length, m_Pos);
}
} // end NetBuffer
}
#endif