diff --git a/MinecraftClient/Protocol/Handlers/DataTypes.cs b/MinecraftClient/Protocol/Handlers/DataTypes.cs index 0b908055..2ca27533 100644 --- a/MinecraftClient/Protocol/Handlers/DataTypes.cs +++ b/MinecraftClient/Protocol/Handlers/DataTypes.cs @@ -46,6 +46,12 @@ namespace MinecraftClient.Protocol.Handlers return result; } + public void ReadDataReverse(Queue cache, Span dest) + { + for (int i = (dest.Length - 1); i >= 0; --i) + dest[i] = cache.Dequeue(); + } + /// /// Remove some data from the cache /// diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs index 26cc8de7..914a0156 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs @@ -554,12 +554,8 @@ namespace MinecraftClient.Protocol.Handlers int dataSize = dataTypes.ReadNextVarInt(packetData); // Size - Parallel.Invoke(() => - { - bool loaded = pTerrain.ProcessChunkColumnData(chunkX, chunkZ, verticalStripBitmask, packetData, cancellationToken); - if (loaded) - Interlocked.Decrement(ref handler.GetWorld().chunkLoadNotCompleted); - }); + if (pTerrain.ProcessChunkColumnData(chunkX, chunkZ, verticalStripBitmask, packetData, cancellationToken)) + Interlocked.Decrement(ref handler.GetWorld().chunkLoadNotCompleted); // Block Entity data: ignored // Light data: ignored @@ -578,12 +574,9 @@ namespace MinecraftClient.Protocol.Handlers int compressedDataSize = dataTypes.ReadNextInt(packetData); byte[] compressed = dataTypes.ReadData(compressedDataSize, packetData); byte[] decompressed = ZlibUtils.Decompress(compressed); - Parallel.Invoke(() => - { - bool loaded = pTerrain.ProcessChunkColumnData(chunkX, chunkZ, chunkMask, addBitmap, currentDimension == 0, chunksContinuous, currentDimension, new Queue(decompressed), cancellationToken); - if (loaded) - Interlocked.Decrement(ref handler.GetWorld().chunkLoadNotCompleted); - }); + + if (pTerrain.ProcessChunkColumnData(chunkX, chunkZ, chunkMask, addBitmap, currentDimension == 0, chunksContinuous, currentDimension, new Queue(decompressed), cancellationToken)) + Interlocked.Decrement(ref handler.GetWorld().chunkLoadNotCompleted); } else { @@ -607,12 +600,9 @@ namespace MinecraftClient.Protocol.Handlers else dataTypes.DropData(1024 * 4, packetData); // Biomes - 1.15 and above } int dataSize = dataTypes.ReadNextVarInt(packetData); - Parallel.Invoke(() => - { - bool loaded = pTerrain.ProcessChunkColumnData(chunkX, chunkZ, chunkMask, 0, false, chunksContinuous, currentDimension, packetData, cancellationToken); - if (loaded) - Interlocked.Decrement(ref handler.GetWorld().chunkLoadNotCompleted); - }); + + if (pTerrain.ProcessChunkColumnData(chunkX, chunkZ, chunkMask, 0, false, chunksContinuous, currentDimension, packetData, cancellationToken)) + Interlocked.Decrement(ref handler.GetWorld().chunkLoadNotCompleted); } } } diff --git a/MinecraftClient/Protocol/Handlers/Protocol18Terrain.cs b/MinecraftClient/Protocol/Handlers/Protocol18Terrain.cs index 2db3b0e6..84e2fe93 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18Terrain.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18Terrain.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; //using System.Linq; @@ -69,6 +70,8 @@ namespace MinecraftClient.Protocol.Handlers // Indirect Mode: For block states with bits per entry <= 4, 4 bits are used to represent a block. if (bitsPerEntry < 4) bitsPerEntry = 4; + int entryPerLong = 64 / bitsPerEntry; // entryPerLong = sizeof(long) / bitsPerEntry + // Direct Mode: Bit mask covering bitsPerEntry bits // EG, if bitsPerEntry = 5, valueMask = 00011111 in binary uint valueMask = (uint)((1 << bitsPerEntry) - 1); @@ -76,15 +79,16 @@ namespace MinecraftClient.Protocol.Handlers int paletteLength = 0; // Assume zero when length is absent if (usePalette) paletteLength = dataTypes.ReadNextVarInt(cache); - int[] palette = new int[paletteLength]; + Span palette = paletteLength < 256 ? stackalloc uint[paletteLength] : new uint[paletteLength]; for (int i = 0; i < paletteLength; i++) - palette[i] = dataTypes.ReadNextVarInt(cache); + palette[i] = (uint)dataTypes.ReadNextVarInt(cache); - // Block IDs are packed in the array of 64-bits integers - ulong[] dataArray = dataTypes.ReadNextULongArray(cache); + //// Block IDs are packed in the array of 64-bits integers + dataTypes.SkipNextVarInt(cache); + Span entryDataByte = stackalloc byte[8]; + dataTypes.ReadDataReverse(cache, entryDataByte); // read long Chunk chunk = new(); - int longIndex = 0; int startOffset = 0 - bitsPerEntry; for (int blockY = 0; blockY < Chunk.SizeY; blockY++) { @@ -103,12 +107,12 @@ namespace MinecraftClient.Protocol.Handlers // When overlapping, move forward to the beginning of the next Long startOffset = 0; - longIndex++; + dataTypes.ReadDataReverse(cache, entryDataByte); // read long } // NOTICE: In the future a single ushort may not store the entire block id; // the Block class may need to change if block state IDs go beyond 65535 - ushort blockId = (ushort)((dataArray[longIndex] >> startOffset) & valueMask); + ushort blockId = (ushort)((MemoryMarshal.Read(entryDataByte) >> startOffset) & valueMask); // Map small IDs to actual larger block IDs if (usePalette)