2018-06-07 13:41:08 +00:00
#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 ) ;
}
2018-06-08 13:30:54 +00:00
// '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 ;
}
}
2018-06-07 13:41:08 +00:00
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 ) ) ;
}
static UIntFloat s_FloatConverter ;
public void Write ( float value )
{
s_FloatConverter . floatValue = value ;
Write ( s_FloatConverter . intValue ) ;
}
public void Write ( double value )
{
s_FloatConverter . doubleValue = value ;
Write ( s_FloatConverter . longValue ) ;
}
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 ;
}
2018-06-11 18:24:56 +00:00
Encoding encoding = new UTF8Encoding ( ) ;
byte [ ] stringWriteBuffer = new byte [ k_MaxStringLength ] ;
int len = encoding . GetByteCount ( value ) ;
2018-06-07 13:41:08 +00:00
if ( len > = k_MaxStringLength )
{
throw new IndexOutOfRangeException ( "Serialize(string) too long: " + value . Length ) ;
}
Write ( ( ushort ) ( len ) ) ;
2018-06-11 18:24:56 +00:00
int numBytes = encoding . GetBytes ( value , 0 , value . Length , stringWriteBuffer , 0 ) ;
m_Buffer . WriteBytes ( stringWriteBuffer , ( ushort ) numBytes ) ;
2018-06-07 13:41:08 +00:00
}
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