Amulet-Team / Amulet-Map-Editor

A new Minecraft world editor and converter that supports all versions since Java 1.12 and Bedrock 1.7.
https://www.amuletmc.com/
1.78k stars 123 forks source link

Amulet can't decompress LZ4-compressed chunks (Minecraft Java Edition 1.20.5) #1027

Closed msbmteam closed 9 months ago

msbmteam commented 9 months ago

Bug Report

In Minecraft Java Edition 1.20.5, some additional compression schemes are being added for dedicated servers, including LZ4 (compression type 4). Amulet cannot currently decompress LZ4-compressed chunks.

Current Behaviour:

ERROR - Error loading chunk 181 186 minecraft:overworld
Traceback (most recent call last):
  File "amulet\api\wrapper\format_wrapper.py", line 442, in _safe_load
  File "amulet\api\wrapper\format_wrapper.py", line 483, in _load_chunk
  File "amulet\level\formats\anvil_world\format.py", line 666, in _get_raw_chunk_data
  File "amulet\level\formats\anvil_world\dimension.py", line 66, in get_chunk_data_layers
  File "amulet\level\formats\anvil_world\dimension.py", line 159, in get_chunk_data
  File "amulet\level\formats\anvil_world\region.py", line 236, in get_data
  File "amulet\level\formats\anvil_world\region.py", line 59, in _decompress
amulet.api.errors.ChunkLoadError: Invalid compression type 4

Expected behavior:

Amulet should be able to decompress chunks that were compressed with LZ4 block format.

Steps To Reproduce:

The LZ4 compression scheme is only accessible to dedicated Minecraft servers, so to reproduce this issue, you have to host a Minecraft server, not a single player world

  1. Prepare to run a Minecraft server with the latest 1.20.5 snapshot (24w07a)
  2. Before running the server, modify server.properties to have the following line: region-file-compression=lz4
  3. Start the server
  4. Make sure a few chunks are generated before closing the server
  5. Access the .mca files in the server's world directory

Environment:

Attachments

Here are two versions of the same MCA file, but with different compression schemes:

gentlegiantJGC commented 9 months ago

The example you have sent starts with LZ4Block so I assume it is using block compression. image

gentlegiantJGC commented 9 months ago

I think it is using this Java library https://github.com/lz4/lz4-java/blob/master/src/java/net/jpountz/lz4/LZ4BlockInputStream.java#L129

gentlegiantJGC commented 9 months ago

Looks like this bit here is what we need. https://github.com/lz4/lz4-java/blob/7c931bef32d179ec3d3286ee71638b23ebde3459/src/java/net/jpountz/lz4/LZ4BlockInputStream.java#L200 The java library adds header data to each block so we need to parse that before decompressing.

gentlegiantJGC commented 9 months ago

That works. I will hold off on releasing a new version because there is probably other things that need updating.