Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add nbtlib.contrib package? #60

Open
vberlier opened this issue Dec 24, 2019 · 1 comment
Open

Add nbtlib.contrib package? #60

vberlier opened this issue Dec 24, 2019 · 1 comment

Comments

@vberlier
Copy link
Owner

vberlier commented Dec 24, 2019

From #1 (comment).

It could be interesting to provide the necessary abstractions to deal with common nbt use-cases in a contrib package.

The package could include:

  • Something to read and edit Minecraft region files
  • Schemas that are currently available in the examples directory
@vberlier vberlier changed the title Add nbtlib.contrib? Add nbtlib.contrib package? Dec 24, 2019
@max-ishere
Copy link

Here are 2 functions that allow you to read a region file header and then get the raw data from them

import zlib, gzip


def GetAnvilChunkData(region, x: int, z: int) -> dict:
    """Returns info stored in anvil header about a chunk at chunk coordinates
    Arguments:
    region -- a file object created with open('/path/')
    x, z -- chunk position (regardless if its region-local or global)
    """
    region.seek(4 * ((x % 32) + (z % 32) * 32), 0)

    offset = int.from_bytes(region.read(3), byteorder ='big')
    sectors = int.from_bytes(region.read(1), byteorder ='big')
    
    region.seek(4 * ((x % 32) + (z % 32) * 32) + 0x1000, 0)
    
    timestamp = int.from_bytes(region.read(4), byteorder ='big')
    
    return dict({'offset':    offset,
                'sectors':   sectors,
                 'timestamp': timestamp})

def GetChunkNbtData(region, x: int, z: int):
    """Finds chunk data sectors and returns uncompressed buffer with NBT data"""
    anvil_data = GetAnvilChunkData(region, x, z)

    if anvil_data['offset'] < 2:
        return bytes(0)
    
    region.seek(anvil_data['offset'] * 0x1000)

    length = int.from_bytes(region.read(4), byteorder ='big')
    compression_type = int.from_bytes(region.read(1), byteorder ='big')
    
    if compression_type == 3:
        return region.read(length)

    if compression_type == 2:
        return zlib.decompress(region.read(length))
    
    if compression_type == 1:
        return gzip.decompress(region.read(length))
    

Once you have those you can use code below to read raw nbt data and make a tree.

#!/bin/python
import nbtlib, io
from mvc.mca import GetChunkNbtData


def main():
    file = open('data/region.mca', 'rb')
    nbt_file = nbtlib.File.from_fileobj(io.BytesIO(GetChunkNbtData(file, 3, 3)))
    print(nbt_file.root.keys())

main()

Seems to work fine with my test data from hermitcraft.com S7:

$ python main.py
dict_keys(['Level', 'DataVersion'])

If this gets added then pls credit me, not that I am willing to do that rn myself... sorry have some stuff i want to finish

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants