fix: handle 1.21.5 chunk data format changes

In 1.21.5, two wire format changes in level chunk packets:
1. Heightmaps changed from NBT CompoundTag to map<VarInt, long[]> encoding
2. PalettedContainer data arrays no longer have VarInt length prefix
   (uses writeFixedSizeLongArray instead of writeLongArray)

Both changes affect ChunkData (level_chunk_with_light) packet parsing.
Without this fix, MCC crashes with "Queue empty" when processing chunks.

Made-with: Cursor
This commit is contained in:
BruceChen 2026-03-21 00:54:27 +08:00
parent 8df39ba74a
commit 9af6c643e3
2 changed files with 35 additions and 8 deletions

View file

@ -1511,7 +1511,22 @@ namespace MinecraftClient.Protocol.Handlers
dataTypes.ReadNextULongArray(
packetData); // Bit Mask Length and Primary Bit Mask
dataTypes.ReadNextNbt(packetData); // Heightmaps
if (protocolVersion >= MC_1_21_5_Version)
{
// 1.21.5: Heightmaps encoded as map<VarInt, long[]> instead of NBT
var hmCount = dataTypes.ReadNextVarInt(packetData);
for (var hm = 0; hm < hmCount; hm++)
{
dataTypes.ReadNextVarInt(packetData); // Heightmap type id
var longCount = dataTypes.ReadNextVarInt(packetData);
for (var l = 0; l < longCount; l++)
dataTypes.ReadNextLong(packetData);
}
}
else
{
dataTypes.ReadNextNbt(packetData); // Heightmaps (NBT format)
}
if (protocolVersion is MC_1_17_Version or MC_1_17_1_Version)
{

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Numerics;
using System.Runtime.CompilerServices;
@ -47,7 +47,8 @@ namespace MinecraftClient.Protocol.Handlers
ushort blockId = (ushort)dataTypes.ReadNextVarInt(cache);
Block block = new(blockId);
dataTypes.SkipNextVarInt(cache); // Data Array Length will be zero
if (protocolversion < Protocol18Handler.MC_1_21_5_Version)
dataTypes.SkipNextVarInt(cache); // Data Array Length will be zero (removed in 1.21.5)
// Empty chunks will not be stored
if (block.Type == Material.Air)
@ -80,7 +81,8 @@ namespace MinecraftClient.Protocol.Handlers
palette[i] = (uint)dataTypes.ReadNextVarInt(cache);
//// Block IDs are packed in the array of 64-bits integers
dataTypes.SkipNextVarInt(cache); // Entry length
if (protocolversion < Protocol18Handler.MC_1_21_5_Version)
dataTypes.SkipNextVarInt(cache); // Entry length (removed in 1.21.5)
Span<byte> entryDataByte = stackalloc byte[8];
Span<long> entryDataLong = MemoryMarshal.Cast<byte, long>(entryDataByte); // Faster than MemoryMarshal.Read<long>
@ -196,8 +198,8 @@ namespace MinecraftClient.Protocol.Handlers
if (bitsPerEntryBiome == 0)
{
dataTypes.SkipNextVarInt(cache); // Value
dataTypes.SkipNextVarInt(cache); // Data Array Length
// Data Array must be empty
if (protocolversion < Protocol18Handler.MC_1_21_5_Version)
dataTypes.SkipNextVarInt(cache); // Data Array Length (removed in 1.21.5)
}
else
{
@ -207,8 +209,18 @@ namespace MinecraftClient.Protocol.Handlers
for (int i = 0; i < paletteLength; i++)
dataTypes.SkipNextVarInt(cache); // Palette
}
int dataArrayLength = dataTypes.ReadNextVarInt(cache); // Data Array Length
dataTypes.DropData(dataArrayLength * 8, cache); // Data Array
if (protocolversion >= Protocol18Handler.MC_1_21_5_Version)
{
// 1.21.5: No VarInt length prefix; calculate from bits per entry
// Biome container has 64 entries (4x4x4)
int dataArrayLength = (64 * bitsPerEntryBiome + 63) / 64;
dataTypes.DropData(dataArrayLength * 8, cache);
}
else
{
int dataArrayLength = dataTypes.ReadNextVarInt(cache); // Data Array Length
dataTypes.DropData(dataArrayLength * 8, cache); // Data Array
}
}
}
}