From d16ba9bfc67e9c217859c76bddc9d056ed089f0a Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Mon, 29 Feb 2016 14:43:31 +1100 Subject: [PATCH] Optimise network reading - only need to move memory after all pending packets are processed, not after each field. --- .../Network/NetworkProcessor.CPE.cs | 15 ++---- .../Network/NetworkProcessor.Original.cs | 3 +- ClassicalSharp/Network/NetworkProcessor.cs | 15 +++--- .../Network/Utils/FixedBufferStream.cs | 28 ++++------ ClassicalSharp/Network/Utils/NetReader.cs | 51 +++++++++++-------- 5 files changed, 54 insertions(+), 58 deletions(-) diff --git a/ClassicalSharp/Network/NetworkProcessor.CPE.cs b/ClassicalSharp/Network/NetworkProcessor.CPE.cs index 71d63258a..d2353335d 100644 --- a/ClassicalSharp/Network/NetworkProcessor.CPE.cs +++ b/ClassicalSharp/Network/NetworkProcessor.CPE.cs @@ -469,16 +469,15 @@ namespace ClassicalSharp { int count = reader.ReadUInt8() + 1; if( game.Map.IsNotLoaded ) { Utils.LogDebug( "Server tried to update a block while still sending us the map!" ); - reader.Remove( bulkCount * (sizeof(int) + 1) ); + reader.Skip( bulkCount * (sizeof(int) + 1) ); return; - } - + } int* indices = stackalloc int[bulkCount]; for( int i = 0; i < count; i++ ) - indices[i] = ReadInt32( reader.buffer, i * 4 ); + indices[i] = reader.ReadInt32(); for( int i = 0; i < count; i++ ) { - byte block = reader.buffer[i + bulkCount * sizeof(int)]; + byte block = reader.ReadUInt8(); Vector3I coords = game.Map.GetCoords( indices[i] ); if( coords.X < 0 ) { @@ -487,12 +486,6 @@ namespace ClassicalSharp { } game.UpdateBlock( coords.X, coords.Y, coords.Z, block ); } - reader.Remove( bulkCount * (sizeof(int) + 1) ); - } - - static int ReadInt32( byte[] buffer, int offset ) { - return buffer[offset + 0] << 24 | buffer[offset + 1] << 16 - | buffer[offset + 2] << 8 | buffer[offset + 3]; } void HandleSetTextColor() { diff --git a/ClassicalSharp/Network/NetworkProcessor.Original.cs b/ClassicalSharp/Network/NetworkProcessor.Original.cs index 31881b381..19fc9d7cf 100644 --- a/ClassicalSharp/Network/NetworkProcessor.Original.cs +++ b/ClassicalSharp/Network/NetworkProcessor.Original.cs @@ -124,6 +124,7 @@ namespace ClassicalSharp { HandleLevelInit(); int usedLength = reader.ReadInt16(); gzippedMap.Position = 0; + gzippedMap.Offset = reader.index; gzippedMap.SetLength( usedLength ); if( gzipHeader.done || gzipHeader.ReadHeader( gzippedMap ) ) { @@ -140,7 +141,7 @@ namespace ClassicalSharp { } } - reader.Remove( 1024 ); + reader.Skip( 1024 ); byte progress = reader.ReadUInt8(); game.MapEvents.RaiseMapLoading( progress ); } diff --git a/ClassicalSharp/Network/NetworkProcessor.cs b/ClassicalSharp/Network/NetworkProcessor.cs index 95868c17e..33d169c89 100644 --- a/ClassicalSharp/Network/NetworkProcessor.cs +++ b/ClassicalSharp/Network/NetworkProcessor.cs @@ -77,11 +77,11 @@ namespace ClassicalSharp { throw; } - while( reader.size > 0 ) { - byte opcode = reader.buffer[0]; + while( (reader.size - reader.index) > 0 ) { + byte opcode = reader.buffer[reader.index]; // Workaround for older D3 servers which wrote one byte too many for HackControl packets. if( opcode == 0xFF && lastOpcode == PacketId.CpeHackControl ) { - reader.Remove( 1 ); + reader.Skip( 1 ); game.LocalPlayer.jumpVel = 0.42f; // assume default jump height game.LocalPlayer.serverJumpVel = game.LocalPlayer.jumpVel; continue; @@ -90,13 +90,14 @@ namespace ClassicalSharp { if( opcode >= maxHandledPacket ) { ErrorHandler.LogError( "NetworkProcessor.Tick", "received an invalid opcode of " + opcode ); - reader.Remove( 1 ); + reader.Skip( 1 ); continue; } - if( reader.size < packetSizes[opcode] ) break; + if( (reader.size - reader.index) < packetSizes[opcode] ) break; ReadPacket( opcode ); } + reader.RemoveRead(); Player player = game.LocalPlayer; if( receivedFirstPosition ) { @@ -134,7 +135,7 @@ namespace ClassicalSharp { PacketId lastOpcode; void ReadPacket( byte opcode ) { - reader.Remove( 1 ); // remove opcode + reader.Skip( 1 ); // remove opcode lastOpcode = (PacketId)opcode; Action handler = handlers[opcode]; lastPacket = DateTime.UtcNow; @@ -145,7 +146,7 @@ namespace ClassicalSharp { } void SkipPacketData( PacketId opcode ) { - reader.Remove( packetSizes[(byte)opcode] - 1 ); + reader.Skip( packetSizes[(byte)opcode] - 1 ); } Action[] handlers; diff --git a/ClassicalSharp/Network/Utils/FixedBufferStream.cs b/ClassicalSharp/Network/Utils/FixedBufferStream.cs index 21d859b5f..1ffa14648 100644 --- a/ClassicalSharp/Network/Utils/FixedBufferStream.cs +++ b/ClassicalSharp/Network/Utils/FixedBufferStream.cs @@ -8,23 +8,16 @@ namespace ClassicalSharp { internal class FixedBufferStream : Stream { public byte[] _buffer; - int _position, _length; + int _position, _length; + public int Offset; - public override bool CanRead { - get { return true; } - } + public override bool CanRead { get { return true; } } - public override bool CanSeek { - get { return false; } - } + public override bool CanSeek { get { return false; } } - public override bool CanWrite { - get { return false; } - } + public override bool CanWrite { get { return false; } } - public override long Length { - get { return _length; } - } + public override long Length { get { return _length; } } public override long Position { get { return _position; } @@ -35,22 +28,23 @@ namespace ClassicalSharp { _buffer = buffer; } - public override void Flush() { - } + public override void Flush() { } public override int Read( byte[] buffer, int offset, int count ) { int numBytes = _length - _position; if( numBytes > count ) numBytes = count; if( numBytes <= 0 ) return 0; - Buffer.BlockCopy( _buffer, _position, buffer, offset, numBytes ); + Buffer.BlockCopy( _buffer, Offset + _position, buffer, offset, numBytes ); _position += numBytes; return numBytes; } public override int ReadByte() { if( _position >= _length ) return -1; - return _buffer[_position++]; + byte value = _buffer[Offset + _position]; + _position++; + return value; } public override long Seek( long offset, SeekOrigin origin ) { diff --git a/ClassicalSharp/Network/Utils/NetReader.cs b/ClassicalSharp/Network/Utils/NetReader.cs index 374235e35..3c4843c41 100644 --- a/ClassicalSharp/Network/Utils/NetReader.cs +++ b/ClassicalSharp/Network/Utils/NetReader.cs @@ -6,7 +6,7 @@ namespace ClassicalSharp { internal class NetReader { public byte[] buffer = new byte[4096 * 5]; - public int size = 0; + public int index = 0, size = 0; public NetworkStream Stream; public NetReader( NetworkStream stream ) { @@ -21,52 +21,59 @@ namespace ClassicalSharp { size += received; } - public void Remove( int byteCount ) { - size -= byteCount; - Buffer.BlockCopy( buffer, byteCount, buffer, 0, size ); + public void Skip( int byteCount ) { + index += byteCount; + } + + public void RemoveProcessed() { + size -= index; + if( size > 0 ) // only copy left over bytes + Buffer.BlockCopy( buffer, index, buffer, 0, size ); + index = 0; // We don't need to zero the old bytes, since they will be overwritten when ReadData() is called. } public int ReadInt32() { - int value = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3]; - Remove( 4 ); + int value = buffer[index] << 24 | buffer[index + 1] << 16 | + buffer[index + 2] << 8 | buffer[index + 3]; + index += 4; return value; } public short ReadInt16() { - short value = (short)( buffer[0] << 8 | buffer[1] ); - Remove( 2 ); + short value = (short)(buffer[index] << 8 | buffer[index + 1]); + index += 2; return value; } public sbyte ReadInt8() { - sbyte value = (sbyte)buffer[0]; - Remove( 1 ); + sbyte value = (sbyte)buffer[index]; + index++; return value; } public byte ReadUInt8() { - byte value = buffer[0]; - Remove( 1 ); + byte value = buffer[index]; + index++; return value; } public byte[] ReadBytes( int length ) { byte[] data = new byte[length]; - Buffer.BlockCopy( buffer, 0, data, 0, length ); - Remove( length ); + Buffer.BlockCopy( buffer, index, data, 0, length ); + index += length; return data; } public string ReadCp437String() { - int length = GetString( buffer, false ); - Remove( 64 ); + int length = GetString( false ); + index += 64; return new String( characters, 0, length ); } public string ReadAsciiString() { - int length = GetString( buffer, true ); - Remove( 64 ); + int length = GetString( true ); + index += 64; return new String( characters, 0, length ); } @@ -75,8 +82,8 @@ namespace ClassicalSharp { return ReadCp437String(); messageType = (byte)MessageType.Normal; - int length = GetString( buffer, false ); - Remove( 64 ); + int length = GetString( false ); + index += 64; int offset = 0; if( length >= womDetail.Length && IsWomDetailString() ) { @@ -97,10 +104,10 @@ namespace ClassicalSharp { return true; } - static int GetString( byte[] data, bool ascii ) { + int GetString( bool ascii ) { int length = 0; for( int i = 63; i >= 0; i-- ) { - byte code = data[i]; + byte code = buffer[index + i]; if( length == 0 && !( code == 0 || code == 0x20 ) ) length = i + 1;