Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Root creates an spurious Compound that is not in actual NBT data #145

@MestreLion

Description

@MestreLion

I've mentioned this a few years back, and now I'm familiar enough with NBT in binary form to raise this again, more confident that this is indeed a design bug in this awesome library.

Currently, when loading an NBT file like this (uncompressed for clarity):

00000000: 0a00 000b 0008 506f 7369 7469 6f6e 0000  ......Position..
00000010: 0002 ffff fff0 ffff ffef 0300 0b44 6174  .............Dat
00000020: 6156 6572 7369 6f6e 0000 0aaa 0900 0845  aVersion.......E
00000030: 6e74 6974 6965 730a 0000 0001 0900 064d  ntities........M
00000040: 6f74 696f 6e06 0000 0003 0000 0000 0000  otion...........
00000050: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000060: 0000 0200 0648 6561 6c74 6800 0501 000c  .....Health.....
00000070: 496e 7675 6c6e 6572 6162 6c65 0002 0003  Invulnerable....
00000080: 4169 7201 2c01 0008 4f6e 4772 6f75 6e64  Air.,...OnGround
00000090: 0003 000e 506f 7274 616c 436f 6f6c 646f  ....PortalCooldo
000000a0: 776e 0000 0000 0900 0852 6f74 6174 696f  wn.......Rotatio
000000b0: 6e05 0000 0002 4191 f848 0000 0000 0500  n.....A..H......
000000c0: 0c46 616c 6c44 6973 7461 6e63 6500 0000  .FallDistance...
000000d0: 000a 0004 4974 656d 0800 0269 6400 0e6d  ....Item...id..m
000000e0: 696e 6563 7261 6674 3a73 616e 6401 0005  inecraft:sand...
000000f0: 436f 756e 7401 0009 0003 506f 7306 0000  Count.....Pos...
00000100: 0003 c06f e0cb b28e cfd4 404b e000 0000  ...o......@K....
00000110: 0000 c070 8aaa 4f56 97f6 0200 0b50 6963  ...p..OV.....Pic
00000120: 6b75 7044 656c 6179 0000 0200 0446 6972  kupDelay.....Fir
00000130: 6500 0008 0002 6964 000e 6d69 6e65 6372  e.....id..minecr
00000140: 6166 743a 6974 656d 0b00 0455 5549 4400  aft:item...UUID.
00000150: 0000 045c 04d8 3949 9646 96b4 0160 7235  ...\..9I.F...`r5
00000160: acc2 cf02 0003 4167 6513 e900 00         ......Age....

We have this result:

{
    "": {
        Position: [I; -16, -17], 
        DataVersion: 2730, 
        Entities: [
            {
                Motion: [0.0d, 0.0d, 0.0d], 
                Health: 5s, 
                Invulnerable: 0b, 
                Air: 300s, 
                OnGround: 0b, 
                PortalCooldown: 0, 
                Rotation: [18.246231079101562f, 0.0f], 
                FallDistance: 0.0f, 
                Item: {
                    id: "minecraft:sand", 
                    Count: 1b
                }, 
                Pos: [-255.02486541645942d, 55.75d, -264.6665795691073d], 
                PickupDelay: 0s, 
                Fire: 0s, 
                id: "minecraft:item", 
                UUID: [I; 1543821369, 1234585238, -1274978190, 900514511], 
                Age: 5097s
            }
        ]
    }
}

It looks like we have a Compound as root, and then another (unnamed) Compound inside it. But that's not true, the binary data clearly shows there is a single (unnamed) Compound in the beginning. So the actual parsing result should be:

{
    Position: [I; -16, -17], 
    DataVersion: 2730, 
    Entities: [
        {
            Motion: [0.0d, 0.0d, 0.0d], 
            Health: 5s, 
            ...
            UUID: [I; 1543821369, 1234585238, -1274978190, 900514511], 
            Age: 5097s
        }
    ]
}

Notice the root name is not represented in the case. And it does not matter, as a tag's name is parsed by (and belongs to) a tag's parent. A tag by itself has no idea about its own name (and tags in lists don't even have one).

Ok, the root tag of an NBT data does have a name, even if 99% (all?) of real world NBT have it empty. But having a name does not make it a Compound with a single child named as itself. This is wrong! If forces some weird syntax to acess the content:

tag = nbtlib.load("somefile.dat")
tag['']["DataVersion"]  # or tag.root["DataVersion"]

Instead of a much simpler (and correct) tag["DataVersion"]

If Root is a Compound, it should not require extra syntax to access its contents. No other tag requires so. If preserving the root name is important for saving/loading integrity, it should be stored elsewhere (Root.name perhaps?)

If displaying this name whenever printing the root tag is needed (why would it be?), then I suggest this format:

"rootname": {
    Position: [I; -16, -17], 
    DataVersion: 2730, 
    Entities: [
        {
            Motion: [0.0d, 0.0d, 0.0d], 
            Health: 5s, 
            ...
            UUID: [I; 1543821369, 1234585238, -1274978190, 900514511], 
            Age: 5097s
        }
    ]
}

This does not imply there are two nested compounds in the beginning. Much cleaner, easier to use, and correctly reflects the NBT data. You can even completely omit the name for empty names, and start right away with { (as my previous example)

This format could also be used to display names for non-compound root tags too. A case that Minecraft seems not to use, and nbtlib does not support, but given the NBT spec there is no technical limitation:

"Age": 5097s

Anyway, allowing root to be a non-compound is a challenge for another day. But for now, removing the fake extra Compound would be very very nice!!!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions