Use separate threads for decryption and decompression

This commit is contained in:
BruceChen 2022-08-30 17:37:46 +08:00
parent c941d086d9
commit 1a90b6d942
8 changed files with 47 additions and 37 deletions

View file

@ -55,7 +55,7 @@ namespace MinecraftClient.Mapping
/// <param name="blockX">Location of the block into the chunk</param> /// <param name="blockX">Location of the block into the chunk</param>
/// <param name="blockY">Location of the block into the world</param> /// <param name="blockY">Location of the block into the world</param>
/// <param name="blockZ">Location of the block into the chunk</param> /// <param name="blockZ">Location of the block into the chunk</param>
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public Location(int chunkX, int chunkZ, int blockX, int blockY, int blockZ) public Location(int chunkX, int chunkZ, int blockX, int blockY, int blockZ)
{ {
X = chunkX * Chunk.SizeX + blockX; X = chunkX * Chunk.SizeX + blockX;

View file

@ -141,8 +141,6 @@ namespace Ionic.Zlib
return oldCheck; return oldCheck;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
internal int Process(int r) internal int Process(int r)
{ {
int t; // temporary storage int t; // temporary storage
@ -676,7 +674,6 @@ namespace Ionic.Zlib
} }
// copy as much as possible from the sliding window to the output area // copy as much as possible from the sliding window to the output area
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
internal int Flush(int r) internal int Flush(int r)
{ {
int nBytes; int nBytes;
@ -803,7 +800,7 @@ namespace Ionic.Zlib
tree = null; tree = null;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
internal int Process(InflateBlocks blocks, int r) internal int Process(InflateBlocks blocks, int r)
{ {
int j; // temporary storage int j; // temporary storage
@ -1165,8 +1162,7 @@ namespace Ionic.Zlib
// (the maximum string length) and number of input bytes available // (the maximum string length) and number of input bytes available
// at least ten. The ten bytes are six bytes for the longest length/ // at least ten. The ten bytes are six bytes for the longest length/
// distance pair plus four bytes for overloading the bit buffer. // distance pair plus four bytes for overloading the bit buffer.
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.AggressiveOptimization)]
internal int InflateFast(int bl, int bd, int[] tl, int tl_index, int[] td, int td_index, InflateBlocks s, ZlibCodec z) internal int InflateFast(int bl, int bd, int[] tl, int tl_index, int[] td, int td_index, InflateBlocks s, ZlibCodec z)
{ {
int t; // temporary pointer int t; // temporary pointer
@ -1515,7 +1511,6 @@ namespace Ionic.Zlib
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
internal int Inflate(FlushType flush) internal int Inflate(FlushType flush)
{ {
int b; int b;

View file

@ -171,7 +171,6 @@ namespace Ionic.Zlib
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private void finish() private void finish()
{ {
if (_z == null) return; if (_z == null) return;
@ -301,7 +300,6 @@ namespace Ionic.Zlib
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public override void Close() public override void Close()
{ {
if (_stream == null) return; if (_stream == null) return;
@ -416,7 +414,6 @@ namespace Ionic.Zlib
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public override System.Int32 Read(System.Byte[] buffer, System.Int32 offset, System.Int32 count) public override System.Int32 Read(System.Byte[] buffer, System.Int32 offset, System.Int32 count)
{ {
// According to MS documentation, any implementation of the IO.Stream.Read function must: // According to MS documentation, any implementation of the IO.Stream.Read function must:

View file

@ -352,7 +352,6 @@ namespace Ionic.Zlib
/// </example> /// </example>
/// <param name="flush">The flush to use when inflating.</param> /// <param name="flush">The flush to use when inflating.</param>
/// <returns>Z_OK if everything goes well.</returns> /// <returns>Z_OK if everything goes well.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public int Inflate(FlushType flush) public int Inflate(FlushType flush)
{ {
if (istate == null) if (istate == null)

View file

@ -410,7 +410,6 @@ namespace Ionic.Zlib
/// <param name="disposing"> /// <param name="disposing">
/// indicates whether the Dispose method was invoked by user code. /// indicates whether the Dispose method was invoked by user code.
/// </param> /// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
try try
@ -545,10 +544,9 @@ namespace Ionic.Zlib
/// <param name="count">the number of bytes to read.</param> /// <param name="count">the number of bytes to read.</param>
/// ///
/// <returns>the number of bytes read</returns> /// <returns>the number of bytes read</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public override int Read(byte[] buffer, int offset, int count) public override int Read(byte[] buffer, int offset, int count)
{ {
if (_disposed) throw new ObjectDisposedException("ZlibStream"); if (_disposed) throw new ObjectDisposedException("ZlibStream");
return _baseStream.Read(buffer, offset, count); return _baseStream.Read(buffer, offset, count);
} }

View file

@ -20,6 +20,7 @@ using System.Threading.Tasks;
using MinecraftClient.Protocol.Keys; using MinecraftClient.Protocol.Keys;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using MinecraftClient.Protocol.Session; using MinecraftClient.Protocol.Session;
using System.Collections.Concurrent;
namespace MinecraftClient.Protocol.Handlers namespace MinecraftClient.Protocol.Handlers
{ {
@ -65,6 +66,7 @@ namespace MinecraftClient.Protocol.Handlers
private bool login_phase = true; private bool login_phase = true;
private int protocolversion; private int protocolversion;
private int currentDimension; private int currentDimension;
private readonly BlockingCollection<Tuple<int, Queue<byte>>> packetQueue = new();
Protocol18Forge pForge; Protocol18Forge pForge;
Protocol18Terrain pTerrain; Protocol18Terrain pTerrain;
@ -211,30 +213,54 @@ namespace MinecraftClient.Protocol.Handlers
private bool Update() private bool Update()
{ {
handler.OnUpdate(); handler.OnUpdate();
if (!socketWrapper.IsConnected())
if (packetQueue.IsAddingCompleted)
return false; return false;
try
while (packetQueue.TryTake(out Tuple<int, Queue<byte>>? packetInfo))
{ {
while (socketWrapper.HasDataAvailable()) (int packetID, Queue<byte> packetData) = packetInfo;
HandlePacket(packetID, packetData);
if (handler.GetNetworkPacketCaptureEnabled())
{ {
int packetID = 0; List<byte> clone = packetData.ToList();
Queue<byte> packetData = ReadNextPacket(ref packetID); handler.OnNetworkPacket(packetID, clone, login_phase, true);
HandlePacket(packetID, packetData);
} }
} }
catch (System.IO.IOException) { return false; }
catch (SocketException) { return false; }
catch (NullReferenceException) { return false; }
catch (Ionic.Zlib.ZlibException) { return false; }
return true; return true;
} }
/// <summary>
/// Read and decompress packets.
/// </summary>
internal void PacketReader()
{
while (socketWrapper.IsConnected())
{
try
{
while (socketWrapper.HasDataAvailable())
packetQueue.Add(ReadNextPacket());
}
catch (System.IO.IOException) { break; }
catch (SocketException) { break; }
catch (NullReferenceException) { break; }
catch (Ionic.Zlib.ZlibException) { break; }
Thread.Sleep(10);
}
packetQueue.CompleteAdding();
}
/// <summary> /// <summary>
/// Read the next packet from the network /// Read the next packet from the network
/// </summary> /// </summary>
/// <param name="packetID">will contain packet ID</param> /// <param name="packetID">will contain packet ID</param>
/// <param name="packetData">will contain raw packet Data</param> /// <param name="packetData">will contain raw packet Data</param>
internal Queue<byte> ReadNextPacket(ref int packetID) internal Tuple<int, Queue<byte>> ReadNextPacket()
{ {
int size = dataTypes.ReadNextVarIntRAW(socketWrapper); //Packet size int size = dataTypes.ReadNextVarIntRAW(socketWrapper); //Packet size
Queue<byte> packetData = new(socketWrapper.ReadDataRAW(size)); //Packet contents Queue<byte> packetData = new(socketWrapper.ReadDataRAW(size)); //Packet contents
@ -252,7 +278,7 @@ namespace MinecraftClient.Protocol.Handlers
} }
} }
packetID = dataTypes.ReadNextVarInt(packetData); //Packet ID int packetID = dataTypes.ReadNextVarInt(packetData); //Packet ID
if (handler.GetNetworkPacketCaptureEnabled()) if (handler.GetNetworkPacketCaptureEnabled())
{ {
@ -260,7 +286,7 @@ namespace MinecraftClient.Protocol.Handlers
handler.OnNetworkPacket(packetID, clone, login_phase, true); handler.OnNetworkPacket(packetID, clone, login_phase, true);
} }
return packetData; return new(packetID, packetData);
} }
/// <summary> /// <summary>
@ -1447,6 +1473,7 @@ namespace MinecraftClient.Protocol.Handlers
/// </summary> /// </summary>
private void StartUpdating() private void StartUpdating()
{ {
new Thread(new ThreadStart(PacketReader)).Start();
netRead = new Tuple<Thread, CancellationTokenSource>(new Thread(new ParameterizedThreadStart(Updater)), new CancellationTokenSource()); netRead = new Tuple<Thread, CancellationTokenSource>(new Thread(new ParameterizedThreadStart(Updater)), new CancellationTokenSource());
netRead.Item1.Name = "ProtocolPacketHandler"; netRead.Item1.Name = "ProtocolPacketHandler";
@ -1552,10 +1579,9 @@ namespace MinecraftClient.Protocol.Handlers
} }
SendPacket(0x00, fullLoginPacket); SendPacket(0x00, fullLoginPacket);
int packetID = -1;
while (true) while (true)
{ {
Queue<byte> packetData = ReadNextPacket(ref packetID); (int packetID, Queue<byte> packetData) = ReadNextPacket();
if (packetID == 0x00) //Login rejected if (packetID == 0x00) //Login rejected
{ {
handler.OnConnectionLost(ChatBot.DisconnectReason.LoginRejected, ChatParser.ParseText(dataTypes.ReadNextString(packetData))); handler.OnConnectionLost(ChatBot.DisconnectReason.LoginRejected, ChatParser.ParseText(dataTypes.ReadNextString(packetData)));
@ -1660,8 +1686,7 @@ namespace MinecraftClient.Protocol.Handlers
int loopPrevention = UInt16.MaxValue; int loopPrevention = UInt16.MaxValue;
while (true) while (true)
{ {
int packetID = -1; (int packetID, Queue<byte> packetData) = ReadNextPacket();
Queue<byte> packetData = ReadNextPacket(ref packetID);
if (packetID < 0 || loopPrevention-- < 0) // Failed to read packet or too many iterations (issue #1150) if (packetID < 0 || loopPrevention-- < 0) // Failed to read packet or too many iterations (issue #1150)
{ {
handler.OnConnectionLost(ChatBot.DisconnectReason.ConnectionLost, Translations.Get("error.invalid_encrypt")); handler.OnConnectionLost(ChatBot.DisconnectReason.ConnectionLost, Translations.Get("error.invalid_encrypt"));

View file

@ -56,11 +56,9 @@ namespace MinecraftClient.Protocol.Handlers
{ {
if (ForgeEnabled() && forgeInfo.Version == FMLVersion.FML) if (ForgeEnabled() && forgeInfo.Version == FMLVersion.FML)
{ {
int packetID = -1;
while (fmlHandshakeState != FMLHandshakeClientState.DONE) while (fmlHandshakeState != FMLHandshakeClientState.DONE)
{ {
Queue<byte> packetData = protocol18.ReadNextPacket(ref packetID); (int packetID, Queue<byte> packetData) = protocol18.ReadNextPacket();
if (packetID == 0x40) // Disconnect if (packetID == 0x40) // Disconnect
{ {

View file

@ -40,7 +40,6 @@ namespace MinecraftClient.Protocol.Handlers
/// <param name="to_decompress">Data to decompress</param> /// <param name="to_decompress">Data to decompress</param>
/// <param name="size_uncompressed">Size of the data once decompressed</param> /// <param name="size_uncompressed">Size of the data once decompressed</param>
/// <returns>Decompressed data as a byte array</returns> /// <returns>Decompressed data as a byte array</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static byte[] Decompress(byte[] to_decompress, int size_uncompressed) public static byte[] Decompress(byte[] to_decompress, int size_uncompressed)
{ {
ZlibStream stream = new ZlibStream(new System.IO.MemoryStream(to_decompress, false), CompressionMode.Decompress); ZlibStream stream = new ZlibStream(new System.IO.MemoryStream(to_decompress, false), CompressionMode.Decompress);
@ -55,7 +54,6 @@ namespace MinecraftClient.Protocol.Handlers
/// </summary> /// </summary>
/// <param name="to_decompress">Data to decompress</param> /// <param name="to_decompress">Data to decompress</param>
/// <returns>Decompressed data as byte array</returns> /// <returns>Decompressed data as byte array</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static byte[] Decompress(byte[] to_decompress) public static byte[] Decompress(byte[] to_decompress)
{ {
ZlibStream stream = new ZlibStream(new System.IO.MemoryStream(to_decompress, false), CompressionMode.Decompress); ZlibStream stream = new ZlibStream(new System.IO.MemoryStream(to_decompress, false), CompressionMode.Decompress);