C4K3 / nbted

Command-line NBT editor
Creative Commons Zero v1.0 Universal
100 stars 8 forks source link

Bedrock edition level.dat #4

Open richbirch opened 3 years ago

richbirch commented 3 years ago

Hi

Do you plan to support bedrock edition level.dat files? Currently when I try to open them I get:

Error: Unable to parse level.dat_old, are you sure it's an NBT file?
    caused by: Unknown compression format where first byte is 8
For help, run with --help or read the manpage.

It'd be awesome to be able to change settings via a command line tool

Thanks Rich

C4K3 commented 3 years ago

https://minecraft.gamepedia.com/Bedrock_Edition_level_format sounds like bedrock uses zlib-compressed nbt (which should be supported.)

I don't have bedrock edition and have never tested with it, are you able to post a failing level.dat and then myself or somebody else may be able to debug it.

richbirch commented 3 years ago

Thanks for the quick response. Here's a zipped copy

level.zip

MalbaCato commented 3 years ago

Documented here https://wiki.vg/NBT#Bedrock_edition are (hopefully all) changes to the nbt format with the Bedrock edition. To make your life annoying values are Little-endian, and sometimes use VarInts.

stsquad commented 2 years ago

I'm finding it hard to find a canonical description of the level.dat data format - but the the leveldb_mcpe repository also seems to support the snappy compression format. Could this be what the header is indicating?

stsquad commented 2 years ago

Actually I think the file may be uncompressed:

00000000  08 00 00 00 b9 08 00 00  0a 00 00 08 0d 00 42 69  |..............Bi|
00000010  6f 6d 65 4f 76 65 72 72  69 64 65 00 00 01 12 00  |omeOverride.....|
00000020  43 65 6e 74 65 72 4d 61  70 73 54 6f 4f 72 69 67  |CenterMapsToOrig|
00000030  69 6e 00 01 1e 00 43 6f  6e 66 69 72 6d 65 64 50  |in....ConfirmedP|
00000040  6c 61 74 66 6f 72 6d 4c  6f 63 6b 65 64 43 6f 6e  |latformLockedCon|
00000050  74 65 6e 74 00 03 0a 00  44 69 66 66 69 63 75 6c  |tent....Difficul|
00000060  74 79 01 00 00 00 08 0f  00 46 6c 61 74 57 6f 72  |ty.......FlatWor|

Which seems to conform to 4 bytes (LE) of a version (8) followed by 4 bytes LE which correspond to the size of the file - 8. Assuming the tags are 2 byte LE you then get a TAG_Compound, TAG_String, 13 byte length and the first string starting with 'B'.

stsquad commented 2 years ago

Confirmed. With a quick and dirty hack to https://github.com/chmod222/cNBT to skip 8 bytes and byte swap everything (including the strings) I was able to parse a valid set of NBT tags:

TAG_Compound("")                
{                            
    TAG_String("edirrevOemoiB"): 
    TAG_Byte("nigirOoTspaMretneC"): 0
    TAG_Byte("tnetnoCdekcoLmroftalPdemrifnoC"): 0
    TAG_Int("ytluciffiD"): 1          
    TAG_String("sreyaLdlroWtalF"):                                                    
llun                                
    TAG_Byte("epyTemaGecroF"): 0                                                      
    TAG_Int("epyTemaG"): 0    
    TAG_Int("rotareneG"): 1           
    TAG_String("noisreVyrotnevnI"): 1.61.1
    TAG_Byte("tsacdaorBNAL"): 1     
    TAG_Byte("tnetnItsacdaorBNAL"): 1
    TAG_Long("deyalPtsaL"): 1632749302 
    TAG_String("emaNleveL"): level kcordeB
    TAG_Int("XnigirOdlroWdetimiL"): 292                                               
    TAG_Int("YnigirOdlroWdetimiL"): 32767
    TAG_Int("ZnigirOdlroWdetimiL"): 16
    TAG_List("noisreVtneilCelbitapmoCmuminiM") [TAG_INT]

So it looks like all (?) that needs doing is a) recognise a Bedrock header and b) read LE bytes for most of the tag data.

richbirch commented 2 years ago

Fantastic work! Thanks @stsquad

stsquad commented 2 years ago

@richbirch well the hack was the easy bit. The reason I hacked it in the C library was it was the quickest way for me to test the theory. The real fix requires doing a bit of re-factoring to nbted so the low level tag accessors can take the endianess required. However my rust is very much beginner level at the moment so it will have to wait until I get a decent free weekend to work on it.

richbirch commented 2 years ago

Thanks for looking at this @stsquad. I've actually dived in and coded a parser for this file myself in my preferred language, Scala. It only took a couple of hours thanks to the hints you gave above. My next step is to convert parsed data back to the level.dat format so I can update values as required.

The exciting thing is that this opens up the possibility of doing things like creating a flat world on a server without having to first create it locally and then upload the world to the server.