mirror of
https://github.com/MirrorNetworking/Mirror.git
synced 2024-11-18 19:10:32 +00:00
549 lines
16 KiB
C#
549 lines
16 KiB
C#
#if ENABLE_UNET
|
|
using System;
|
|
using System.Text;
|
|
using UnityEngine;
|
|
|
|
namespace UnityEngine.Networking
|
|
{
|
|
// Binary stream Writer. Supports simple types, buffers, arrays, structs, and nested types
|
|
public class NetworkWriter
|
|
{
|
|
const int k_MaxStringLength = 1024 * 32;
|
|
NetBuffer m_Buffer;
|
|
|
|
public NetworkWriter()
|
|
{
|
|
m_Buffer = new NetBuffer();
|
|
}
|
|
|
|
public NetworkWriter(byte[] buffer)
|
|
{
|
|
m_Buffer = new NetBuffer(buffer);
|
|
}
|
|
|
|
// 'int' is the best type for .Position. 'short' is too small if we send >32kb which would result in negative .Position
|
|
// 'uint' is exact but we serialize/deserialize array.Lengths often which are int's, so 'int' is easier and big enough too.
|
|
public int Position
|
|
{
|
|
get
|
|
{
|
|
// uint to int conversion check. better safe than sorry.
|
|
if (m_Buffer.Position > Int32.MaxValue)
|
|
{
|
|
if (LogFilter.logError) { Debug.LogError("NetworkWriter.Position exceeds Int32.MaxValue"); }
|
|
}
|
|
return (int)m_Buffer.Position;
|
|
}
|
|
}
|
|
|
|
public byte[] ToArray()
|
|
{
|
|
var newArray = new byte[m_Buffer.AsArraySegment().Count];
|
|
Array.Copy(m_Buffer.AsArraySegment().Array, newArray, m_Buffer.AsArraySegment().Count);
|
|
return newArray;
|
|
}
|
|
|
|
public byte[] AsArray()
|
|
{
|
|
return AsArraySegment().Array;
|
|
}
|
|
|
|
internal ArraySegment<byte> AsArraySegment()
|
|
{
|
|
return m_Buffer.AsArraySegment();
|
|
}
|
|
|
|
// http://sqlite.org/src4/doc/trunk/www/varint.wiki
|
|
|
|
public void WritePackedUInt32(UInt32 value)
|
|
{
|
|
if (value <= 240)
|
|
{
|
|
Write((byte)value);
|
|
return;
|
|
}
|
|
if (value <= 2287)
|
|
{
|
|
Write((byte)((value - 240) / 256 + 241));
|
|
Write((byte)((value - 240) % 256));
|
|
return;
|
|
}
|
|
if (value <= 67823)
|
|
{
|
|
Write((byte)249);
|
|
Write((byte)((value - 2288) / 256));
|
|
Write((byte)((value - 2288) % 256));
|
|
return;
|
|
}
|
|
if (value <= 16777215)
|
|
{
|
|
Write((byte)250);
|
|
Write((byte)(value & 0xFF));
|
|
Write((byte)((value >> 8) & 0xFF));
|
|
Write((byte)((value >> 16) & 0xFF));
|
|
return;
|
|
}
|
|
|
|
// all other values of uint
|
|
Write((byte)251);
|
|
Write((byte)(value & 0xFF));
|
|
Write((byte)((value >> 8) & 0xFF));
|
|
Write((byte)((value >> 16) & 0xFF));
|
|
Write((byte)((value >> 24) & 0xFF));
|
|
}
|
|
|
|
public void WritePackedUInt64(UInt64 value)
|
|
{
|
|
if (value <= 240)
|
|
{
|
|
Write((byte)value);
|
|
return;
|
|
}
|
|
if (value <= 2287)
|
|
{
|
|
Write((byte)((value - 240) / 256 + 241));
|
|
Write((byte)((value - 240) % 256));
|
|
return;
|
|
}
|
|
if (value <= 67823)
|
|
{
|
|
Write((byte)249);
|
|
Write((byte)((value - 2288) / 256));
|
|
Write((byte)((value - 2288) % 256));
|
|
return;
|
|
}
|
|
if (value <= 16777215)
|
|
{
|
|
Write((byte)250);
|
|
Write((byte)(value & 0xFF));
|
|
Write((byte)((value >> 8) & 0xFF));
|
|
Write((byte)((value >> 16) & 0xFF));
|
|
return;
|
|
}
|
|
if (value <= 4294967295)
|
|
{
|
|
Write((byte)251);
|
|
Write((byte)(value & 0xFF));
|
|
Write((byte)((value >> 8) & 0xFF));
|
|
Write((byte)((value >> 16) & 0xFF));
|
|
Write((byte)((value >> 24) & 0xFF));
|
|
return;
|
|
}
|
|
if (value <= 1099511627775)
|
|
{
|
|
Write((byte)252);
|
|
Write((byte)(value & 0xFF));
|
|
Write((byte)((value >> 8) & 0xFF));
|
|
Write((byte)((value >> 16) & 0xFF));
|
|
Write((byte)((value >> 24) & 0xFF));
|
|
Write((byte)((value >> 32) & 0xFF));
|
|
return;
|
|
}
|
|
if (value <= 281474976710655)
|
|
{
|
|
Write((byte)253);
|
|
Write((byte)(value & 0xFF));
|
|
Write((byte)((value >> 8) & 0xFF));
|
|
Write((byte)((value >> 16) & 0xFF));
|
|
Write((byte)((value >> 24) & 0xFF));
|
|
Write((byte)((value >> 32) & 0xFF));
|
|
Write((byte)((value >> 40) & 0xFF));
|
|
return;
|
|
}
|
|
if (value <= 72057594037927935)
|
|
{
|
|
Write((byte)254);
|
|
Write((byte)(value & 0xFF));
|
|
Write((byte)((value >> 8) & 0xFF));
|
|
Write((byte)((value >> 16) & 0xFF));
|
|
Write((byte)((value >> 24) & 0xFF));
|
|
Write((byte)((value >> 32) & 0xFF));
|
|
Write((byte)((value >> 40) & 0xFF));
|
|
Write((byte)((value >> 48) & 0xFF));
|
|
return;
|
|
}
|
|
|
|
// all others
|
|
{
|
|
Write((byte)255);
|
|
Write((byte)(value & 0xFF));
|
|
Write((byte)((value >> 8) & 0xFF));
|
|
Write((byte)((value >> 16) & 0xFF));
|
|
Write((byte)((value >> 24) & 0xFF));
|
|
Write((byte)((value >> 32) & 0xFF));
|
|
Write((byte)((value >> 40) & 0xFF));
|
|
Write((byte)((value >> 48) & 0xFF));
|
|
Write((byte)((value >> 56) & 0xFF));
|
|
}
|
|
}
|
|
|
|
public void Write(NetworkInstanceId value)
|
|
{
|
|
WritePackedUInt32(value.Value);
|
|
}
|
|
|
|
public void Write(NetworkSceneId value)
|
|
{
|
|
WritePackedUInt32(value.Value);
|
|
}
|
|
|
|
public void Write(char value)
|
|
{
|
|
m_Buffer.WriteByte((byte)value);
|
|
}
|
|
|
|
public void Write(byte value)
|
|
{
|
|
m_Buffer.WriteByte(value);
|
|
}
|
|
|
|
public void Write(sbyte value)
|
|
{
|
|
m_Buffer.WriteByte((byte)value);
|
|
}
|
|
|
|
public void Write(short value)
|
|
{
|
|
m_Buffer.WriteByte2((byte)(value & 0xff), (byte)((value >> 8) & 0xff));
|
|
}
|
|
|
|
public void Write(ushort value)
|
|
{
|
|
m_Buffer.WriteByte2((byte)(value & 0xff), (byte)((value >> 8) & 0xff));
|
|
}
|
|
|
|
public void Write(int value)
|
|
{
|
|
// little endian...
|
|
m_Buffer.WriteByte4(
|
|
(byte)(value & 0xff),
|
|
(byte)((value >> 8) & 0xff),
|
|
(byte)((value >> 16) & 0xff),
|
|
(byte)((value >> 24) & 0xff));
|
|
}
|
|
|
|
public void Write(uint value)
|
|
{
|
|
m_Buffer.WriteByte4(
|
|
(byte)(value & 0xff),
|
|
(byte)((value >> 8) & 0xff),
|
|
(byte)((value >> 16) & 0xff),
|
|
(byte)((value >> 24) & 0xff));
|
|
}
|
|
|
|
public void Write(long value)
|
|
{
|
|
m_Buffer.WriteByte8(
|
|
(byte)(value & 0xff),
|
|
(byte)((value >> 8) & 0xff),
|
|
(byte)((value >> 16) & 0xff),
|
|
(byte)((value >> 24) & 0xff),
|
|
(byte)((value >> 32) & 0xff),
|
|
(byte)((value >> 40) & 0xff),
|
|
(byte)((value >> 48) & 0xff),
|
|
(byte)((value >> 56) & 0xff));
|
|
}
|
|
|
|
public void Write(ulong value)
|
|
{
|
|
m_Buffer.WriteByte8(
|
|
(byte)(value & 0xff),
|
|
(byte)((value >> 8) & 0xff),
|
|
(byte)((value >> 16) & 0xff),
|
|
(byte)((value >> 24) & 0xff),
|
|
(byte)((value >> 32) & 0xff),
|
|
(byte)((value >> 40) & 0xff),
|
|
(byte)((value >> 48) & 0xff),
|
|
(byte)((value >> 56) & 0xff));
|
|
}
|
|
|
|
public void Write(float value)
|
|
{
|
|
byte[] bytes = BitConverter.GetBytes(value);
|
|
Write(bytes, bytes.Length);
|
|
}
|
|
|
|
public void Write(double value)
|
|
{
|
|
byte[] bytes = BitConverter.GetBytes(value);
|
|
Write(bytes, bytes.Length);
|
|
}
|
|
|
|
public void Write(decimal value)
|
|
{
|
|
Int32[] bits = decimal.GetBits(value);
|
|
Write(bits[0]);
|
|
Write(bits[1]);
|
|
Write(bits[2]);
|
|
Write(bits[3]);
|
|
}
|
|
|
|
public void Write(string value)
|
|
{
|
|
if (value == null)
|
|
{
|
|
m_Buffer.WriteByte2(0, 0);
|
|
return;
|
|
}
|
|
|
|
Encoding encoding = new UTF8Encoding();
|
|
byte[] stringWriteBuffer = new byte[k_MaxStringLength];
|
|
|
|
int len = encoding.GetByteCount(value);
|
|
|
|
if (len >= k_MaxStringLength)
|
|
{
|
|
throw new IndexOutOfRangeException("Serialize(string) too long: " + value.Length);
|
|
}
|
|
|
|
Write((ushort)(len));
|
|
int numBytes = encoding.GetBytes(value, 0, value.Length, stringWriteBuffer, 0);
|
|
m_Buffer.WriteBytes(stringWriteBuffer, (ushort)numBytes);
|
|
}
|
|
|
|
public void Write(bool value)
|
|
{
|
|
if (value)
|
|
m_Buffer.WriteByte(1);
|
|
else
|
|
m_Buffer.WriteByte(0);
|
|
}
|
|
|
|
public void Write(byte[] buffer, int count)
|
|
{
|
|
if (count > UInt16.MaxValue)
|
|
{
|
|
if (LogFilter.logError) { Debug.LogError("NetworkWriter Write: buffer is too large (" + count + ") bytes. The maximum buffer size is 64K bytes."); }
|
|
return;
|
|
}
|
|
m_Buffer.WriteBytes(buffer, (UInt16)count);
|
|
}
|
|
|
|
public void Write(byte[] buffer, int offset, int count)
|
|
{
|
|
if (count > UInt16.MaxValue)
|
|
{
|
|
if (LogFilter.logError) { Debug.LogError("NetworkWriter Write: buffer is too large (" + count + ") bytes. The maximum buffer size is 64K bytes."); }
|
|
return;
|
|
}
|
|
m_Buffer.WriteBytesAtOffset(buffer, (ushort)offset, (ushort)count);
|
|
}
|
|
|
|
public void WriteBytesAndSize(byte[] buffer, int count)
|
|
{
|
|
if (buffer == null || count == 0)
|
|
{
|
|
Write((UInt16)0);
|
|
return;
|
|
}
|
|
|
|
if (count > UInt16.MaxValue)
|
|
{
|
|
if (LogFilter.logError) { Debug.LogError("NetworkWriter WriteBytesAndSize: buffer is too large (" + count + ") bytes. The maximum buffer size is 64K bytes."); }
|
|
return;
|
|
}
|
|
|
|
Write((UInt16)count);
|
|
m_Buffer.WriteBytes(buffer, (UInt16)count);
|
|
}
|
|
|
|
//NOTE: this will write the entire buffer.. including trailing empty space!
|
|
public void WriteBytesFull(byte[] buffer)
|
|
{
|
|
if (buffer == null)
|
|
{
|
|
Write((UInt16)0);
|
|
return;
|
|
}
|
|
if (buffer.Length > UInt16.MaxValue)
|
|
{
|
|
if (LogFilter.logError) { Debug.LogError("NetworkWriter WriteBytes: buffer is too large (" + buffer.Length + ") bytes. The maximum buffer size is 64K bytes."); }
|
|
return;
|
|
}
|
|
Write((UInt16)buffer.Length);
|
|
m_Buffer.WriteBytes(buffer, (UInt16)buffer.Length);
|
|
}
|
|
|
|
public void Write(Vector2 value)
|
|
{
|
|
Write(value.x);
|
|
Write(value.y);
|
|
}
|
|
|
|
public void Write(Vector3 value)
|
|
{
|
|
Write(value.x);
|
|
Write(value.y);
|
|
Write(value.z);
|
|
}
|
|
|
|
public void Write(Vector4 value)
|
|
{
|
|
Write(value.x);
|
|
Write(value.y);
|
|
Write(value.z);
|
|
Write(value.w);
|
|
}
|
|
|
|
public void Write(Color value)
|
|
{
|
|
Write(value.r);
|
|
Write(value.g);
|
|
Write(value.b);
|
|
Write(value.a);
|
|
}
|
|
|
|
public void Write(Color32 value)
|
|
{
|
|
Write(value.r);
|
|
Write(value.g);
|
|
Write(value.b);
|
|
Write(value.a);
|
|
}
|
|
|
|
public void Write(Quaternion value)
|
|
{
|
|
Write(value.x);
|
|
Write(value.y);
|
|
Write(value.z);
|
|
Write(value.w);
|
|
}
|
|
|
|
public void Write(Rect value)
|
|
{
|
|
Write(value.xMin);
|
|
Write(value.yMin);
|
|
Write(value.width);
|
|
Write(value.height);
|
|
}
|
|
|
|
public void Write(Plane value)
|
|
{
|
|
Write(value.normal);
|
|
Write(value.distance);
|
|
}
|
|
|
|
public void Write(Ray value)
|
|
{
|
|
Write(value.direction);
|
|
Write(value.origin);
|
|
}
|
|
|
|
public void Write(Matrix4x4 value)
|
|
{
|
|
Write(value.m00);
|
|
Write(value.m01);
|
|
Write(value.m02);
|
|
Write(value.m03);
|
|
Write(value.m10);
|
|
Write(value.m11);
|
|
Write(value.m12);
|
|
Write(value.m13);
|
|
Write(value.m20);
|
|
Write(value.m21);
|
|
Write(value.m22);
|
|
Write(value.m23);
|
|
Write(value.m30);
|
|
Write(value.m31);
|
|
Write(value.m32);
|
|
Write(value.m33);
|
|
}
|
|
|
|
public void Write(NetworkHash128 value)
|
|
{
|
|
Write(value.i0);
|
|
Write(value.i1);
|
|
Write(value.i2);
|
|
Write(value.i3);
|
|
Write(value.i4);
|
|
Write(value.i5);
|
|
Write(value.i6);
|
|
Write(value.i7);
|
|
Write(value.i8);
|
|
Write(value.i9);
|
|
Write(value.i10);
|
|
Write(value.i11);
|
|
Write(value.i12);
|
|
Write(value.i13);
|
|
Write(value.i14);
|
|
Write(value.i15);
|
|
}
|
|
|
|
public void Write(NetworkIdentity value)
|
|
{
|
|
if (value == null)
|
|
{
|
|
WritePackedUInt32(0);
|
|
return;
|
|
}
|
|
Write(value.netId);
|
|
}
|
|
|
|
public void Write(Transform value)
|
|
{
|
|
if (value == null || value.gameObject == null)
|
|
{
|
|
WritePackedUInt32(0);
|
|
return;
|
|
}
|
|
var uv = value.gameObject.GetComponent<NetworkIdentity>();
|
|
if (uv != null)
|
|
{
|
|
Write(uv.netId);
|
|
}
|
|
else
|
|
{
|
|
if (LogFilter.logWarn) { Debug.LogWarning("NetworkWriter " + value + " has no NetworkIdentity"); }
|
|
WritePackedUInt32(0);
|
|
}
|
|
}
|
|
|
|
public void Write(GameObject value)
|
|
{
|
|
if (value == null)
|
|
{
|
|
WritePackedUInt32(0);
|
|
return;
|
|
}
|
|
var uv = value.GetComponent<NetworkIdentity>();
|
|
if (uv != null)
|
|
{
|
|
Write(uv.netId);
|
|
}
|
|
else
|
|
{
|
|
if (LogFilter.logWarn) { Debug.LogWarning("NetworkWriter " + value + " has no NetworkIdentity"); }
|
|
WritePackedUInt32(0);
|
|
}
|
|
}
|
|
|
|
public void Write(MessageBase msg)
|
|
{
|
|
msg.Serialize(this);
|
|
}
|
|
|
|
public void SeekZero()
|
|
{
|
|
m_Buffer.SeekZero();
|
|
}
|
|
|
|
public void StartMessage(short msgType)
|
|
{
|
|
SeekZero();
|
|
|
|
// two bytes for size, will be filled out in FinishMessage
|
|
m_Buffer.WriteByte2(0, 0);
|
|
|
|
// two bytes for message type
|
|
Write(msgType);
|
|
}
|
|
|
|
public void FinishMessage()
|
|
{
|
|
// writes correct size into space at start of buffer
|
|
m_Buffer.FinishMessage();
|
|
}
|
|
};
|
|
}
|
|
#endif //ENABLE_UNET
|