Search code examples
pythonpython-3.xminecraftfile-handling

How do I get .nbt file to save properly with a new nbtlib.tag.File object?


I am trying to make and save .nbt (structure block) files in Minecraft, using nbtlib. I first tried to see if I could edit an existing file using it, which worked well, but I'm trying to make a new one from scratch. The problem I'm having is when I try to save that new one, it gives me "Structure 'minecraft:t3' is not available" in the Minecraft chat ("t3" is the name of the structure I'm saving).

I have tried to see if I was doing the wrong format or class or anything, so I tested the one that I was saving initially against the one I'm making from scratch (the structure itself being the same for both) with a simple print(initial == mine) kind of setup, which returned True. This really confused me because it was the same, but one was working and the other wasn't even though they were the same?

This is the first time I'm using this so I might be getting something wrong with the library.

This is the code:

from nbtlib import tag, File
import os

folderPath = r"C:\Users\fullw\AppData\Roaming\.minecraft\saves\Python Generated\generated\minecraft\structures"

def path(name: str) -> str:
    return os.path.join(folderPath, name + ".nbt")

# Load the .nbt file
file = File.load(path("t4"), gzipped=True)


def toNBT(data: dict | list | int | str) -> tag.Base:
    if isinstance(data, dict):
        return tag.Compound({key: toNBT(value) for key, value in data.items()})
    elif isinstance(data, list):
        return tag.List([toNBT(element) for element in data])
    elif isinstance(data, int):
        return tag.Int(data)
    elif isinstance(data, str):
        return tag.String(data)
    else:
        raise ValueError(f"Unsupported data type: {type(data)}")

class Structure():
    def __init__(self, size: list[int], replaceWithAir: str = False):
        self.replaceWithAir = replaceWithAir
        self.structure = {"size": size, "blocks": [], "palette": [], "entities": [], "DataVersion": 3700}
    
    def finaliseStructure(self) -> File:
        result = File()
        for key, value in self.structure.items():
            result[key] = toNBT(value)
        return result

    def save(self, name: str) -> None:
        file = self.finaliseStructure()
        file.save(path(name))


struct = Structure([1,1,1])
print(struct.finaliseStructure() == file) # prints True
file = struct.finaliseStructure() # If this is uncommented, it doesn't work. If it is commented, it does.
file.save(path("t6"))

This is the code I used to edit just one, before I made the code above:

from nbtlib import File, tag
import os

folderPath = r"C:\Users\fullw\AppData\Roaming\.minecraft\saves\Python Generated\generated\minecraft\structures"

def path(name: str) -> str:
    return os.path.join(folderPath, name + ".nbt")

# Load the .nbt file
file = File.load(path("t1"), gzipped=True)

# Access and modify data
file["blocks"][0]["state"] = tag.Int(1)
del file["blocks"][0]

# Save the changes back to the file
file.save(path("t6"))

Solution

  • In the finaliseStructure method, I had to do gzipped=True. No clue why, but it seems to have solved it.