Esempio n. 1
0
    def __init__(self, path_or_buffer: str, platform: str, selection: SelectionBox):
        self._path_or_buffer = path_or_buffer
        if platform == "java":
            self._materials = "Alpha"
        elif platform == "bedrock":
            self._materials = "Pocket"
        else:
            raise Exception(
                f'"{platform}" is not a supported platform for a schematic file.'
            )
        self._selection = selection

        self._data = amulet_nbt.NBTFile(
            amulet_nbt.TAG_Compound(
                {
                    "TileTicks": amulet_nbt.TAG_List(),
                    "Width": amulet_nbt.TAG_Short(selection.size_x),
                    "Height": amulet_nbt.TAG_Short(selection.size_y),
                    "Length": amulet_nbt.TAG_Short(selection.size_z),
                    "Materials": amulet_nbt.TAG_String(self._materials),
                }
            ),
            "Schematic",
        )

        self._entities = []
        self._block_entities = []
        self._blocks = numpy.zeros(
            selection.shape, dtype=numpy.uint16
        )  # only 12 bits are actually used at most
        self._block_data = numpy.zeros(
            selection.shape, dtype=numpy.uint8
        )  # only 4 bits are used
Esempio n. 2
0
 def __init__(self, directory: str):
     super().__init__(directory)
     self._lock = False
     self._platform = "bedrock"
     self.root_tag: nbt.NBTFile = nbt.NBTFile()
     self._load_level_dat()
     self._level_manager: Optional[LevelDBDimensionManager] = None
Esempio n. 3
0
 def _init_write(self):
     """data to be written at init in write mode"""
     self._buffer.write(magic_num)
     self._buffer.write(struct.pack(">B", self._format_version))
     if self._format_version == 0:
         self._metadata = amulet_nbt.NBTFile(
             amulet_nbt.TAG_Compound({
                 "created_with":
                 amulet_nbt.TAG_String("amulet_python_wrapper"),
                 "selection_boxes":
                 amulet_nbt.TAG_Int_Array([
                     c for box in self._selection_boxes
                     if len(box) == 6 and all(
                         isinstance(c, int) for c in box) for c in box
                 ]),
                 "section_version":
                 amulet_nbt.TAG_Byte(self._section_version),
                 "export_version":
                 amulet_nbt.TAG_Compound({
                     "edition":
                     amulet_nbt.TAG_String(self._source_edition),
                     "version":
                     amulet_nbt.TAG_List([
                         amulet_nbt.TAG_Int(v) for v in self._source_version
                     ]),
                 }),
             }))
     else:
         raise Exception(
             f"This wrapper doesn't support any construction version higher than {max_format_version}"
         )
Esempio n. 4
0
    def _save_subchunks_1(self, blocks: "Blocks",
                          palette: AnyNDArray) -> List[Optional[bytes]]:
        for index, block in enumerate(palette):
            block: Tuple[Tuple[None, Block], ...]
            block_data = block[0][1].properties.get("block_data",
                                                    amulet_nbt.TAG_Int(0))
            if isinstance(block_data, amulet_nbt.TAG_Int):
                block_data = block_data.value
                # if block_data >= 16:
                #     block_data = 0
            else:
                block_data = 0

            palette[index] = amulet_nbt.NBTFile(
                amulet_nbt.TAG_Compound({
                    "name":
                    amulet_nbt.TAG_String(block[0][1].namespaced_name),
                    "val":
                    amulet_nbt.TAG_Short(block_data),
                }))
        chunk = []
        for cy in range(16):
            if cy in blocks:
                palette_index, sub_chunk = fast_unique(
                    blocks.get_sub_chunk(cy))
                sub_chunk_palette = list(palette[palette_index])
                chunk.append(b"\x01" + self._save_palette_subchunk(
                    sub_chunk.ravel(), sub_chunk_palette))
            else:
                chunk.append(None)
        return chunk
Esempio n. 5
0
    def __init__(self, path_or_buffer: str, selection: SelectionBox):
        self._path_or_buffer = path_or_buffer
        self._selection = selection

        self._data = amulet_nbt.NBTFile(
            amulet_nbt.TAG_Compound({
                "format_version":
                amulet_nbt.TAG_Int(1),
                "structure_world_origin":
                amulet_nbt.TAG_List([
                    amulet_nbt.TAG_Int(selection.min_x),
                    amulet_nbt.TAG_Int(selection.min_y),
                    amulet_nbt.TAG_Int(selection.min_z),
                ]),
                "size":
                amulet_nbt.TAG_List([
                    amulet_nbt.TAG_Int(selection.size_x),
                    amulet_nbt.TAG_Int(selection.size_y),
                    amulet_nbt.TAG_Int(selection.size_z),
                ]),
            }))

        self._entities = []
        self._block_entities = []
        self._blocks = numpy.zeros(
            selection.shape,
            dtype=numpy.uint32)  # only 12 bits are actually used at most
        self._palette: List[AnyNDArray] = []
        self._palette_len = 0
Esempio n. 6
0
 def root_tag(self, root_tag: Union[nbt.NBTFile, nbt.TAG_Compound]):
     if isinstance(root_tag, nbt.TAG_Compound):
         self._root_tag = nbt.NBTFile(root_tag)
     elif isinstance(root_tag, nbt.NBTFile):
         self._root_tag = root_tag
     else:
         raise ValueError("root_tag must be a TAG_Compound or NBTFile")
Esempio n. 7
0
 def __init__(
     self,
     namespace: str,
     base_name: str,
     x: _Coord,
     y: _Coord,
     z: _Coord,
     nbt: amulet_nbt.NBTFile,
 ):
     assert isinstance(namespace, str), "namespace must be a string"
     assert isinstance(base_name, str), "base_name must be a string"
     self._namespace = namespace
     self._base_name = base_name
     self._namespaced_name = None
     self._gen_namespaced_name()
     assert all(
         isinstance(c, self.coord_types) for c in (x, y, z)
     ), f"coordinates type must be in {self.coord_types}"
     self._x = self.coord_types[0](x)
     self._y = self.coord_types[0](y)
     self._z = self.coord_types[0](z)
     if isinstance(nbt, amulet_nbt.TAG_Compound):
         self._nbt = amulet_nbt.NBTFile(nbt)
     elif isinstance(nbt, amulet_nbt.NBTFile):
         self._nbt = nbt
     else:
         raise Exception(f"nbt must be an NBTFile. Got {nbt}")
Esempio n. 8
0
 def __init__(self, directory: str):
     super().__init__(directory)
     self.root_tag: nbt.NBTFile = nbt.NBTFile()
     self._load_level_dat()
     self._levels: Dict[InternalDimension, AnvilLevelManager] = {}
     self._dimension_name_map: Dict["Dimension", InternalDimension] = {}
     self._mcc_support: Optional[bool] = None
     self._lock = None
Esempio n. 9
0
 def _parse_entities(entities: amulet_nbt.TAG_List) -> List[Entity]:
     return [
         Entity(
             entity["namespace"].value,
             entity["base_name"].value,
             entity["x"].value,
             entity["y"].value,
             entity["z"].value,
             amulet_nbt.NBTFile(entity["nbt"]),
         ) for entity in entities
     ]
Esempio n. 10
0
 def _parse_block_entities(
         block_entities: amulet_nbt.TAG_List) -> List[BlockEntity]:
     return [
         BlockEntity(
             block_entity["namespace"].value,
             block_entity["base_name"].value,
             block_entity["x"].value,
             block_entity["y"].value,
             block_entity["z"].value,
             amulet_nbt.NBTFile(block_entity["nbt"]),
         ) for block_entity in block_entities
     ]
Esempio n. 11
0
    def _decode_block_entities(
            self, block_entities: amulet_nbt.TAG_List) -> List["BlockEntity"]:
        entities_out = []
        for nbt in block_entities:
            entity = self._decode_block_entity(
                amulet_nbt.NBTFile(nbt),
                self.features["block_entity_format"],
                self.features["block_entity_coord_format"],
            )
            if entity is not None:
                entities_out.append(entity)

        return entities_out
Esempio n. 12
0
def generateSignEntity(x, y, z, direction):
    """Generates the entity to make the sign display its position"""
    return BlockEntity("java", "acacia_wall_sign", x, y, z,\
                amulet_nbt.NBTFile(\
                    value = amulet_nbt.TAG_Compound(\
                        {\
                            "utags": amulet_nbt.TAG_Compound(\
                                {\
                                    "keepPacked": amulet_nbt.TAG_Byte(0),\
                                    "Text4": amulet_nbt.TAG_String("{\"text\":\"\"}"),\
                                    "Text3": amulet_nbt.TAG_String("{\"text\":\"\"}"),\
                                    "Text2": amulet_nbt.TAG_String("{\"text\":\"%d - %d\"}"%(z + direction, z + direction * 6)), \
                                    "Text1": amulet_nbt.TAG_String("{\"text\":\"%d\"}"%x)\
                                }),\
                            "Color": amulet_nbt.TAG_String("black")\
                        })))
Esempio n. 13
0
    def write(self, section: ConstructionSection):
        if self._section_version == 0:
            sx, sy, sz = section.location
            shapex, shapey, shapez = section.shape
            blocks = section.blocks
            entities = section.entities
            block_entities = section.block_entities
            palette = section.palette
            for point, shape in zip((sx, sy, sz), (shapex, shapey, shapez)):
                assert shape >= 0, "Shape must be positive"
                assert point + shape <= (
                    ((point >> 4) + 1) << 4
                ), "Section does not fit in a sub-chunk"
            position = self._buffer.tell()

            _tag = amulet_nbt.TAG_Compound(
                {"entities": self._serialise_entities(entities)}
            )

            if blocks is None:
                _tag["blocks_array_type"] = amulet_nbt.TAG_Byte(-1)
            else:
                flattened_array = blocks.ravel()
                index, flattened_array = numpy.unique(
                    flattened_array, return_inverse=True
                )
                palette = numpy.array(palette, dtype=object)[index]
                lut = numpy.vectorize(self._palette.get_add_block)(palette)
                flattened_array = lut[flattened_array]
                array_type = self._find_fitting_array_type(flattened_array)
                _tag["blocks_array_type"] = amulet_nbt.TAG_Byte(array_type().tag_id)
                _tag["blocks"] = array_type(flattened_array)
                _tag["block_entities"] = self._serialise_block_entities(
                    block_entities or []
                )

            amulet_nbt.NBTFile(_tag).save_to(self._buffer)

            length = self._buffer.tell() - position
            self._section_index_table.append(
                (sx, sy, sz, shapex, shapey, shapez, position, length)
            )
        else:
            raise Exception(
                f"This wrapper doesn't support any section version higher than {max_section_version}"
            )
Esempio n. 14
0
    def __init__(self, path: str):
        """
        Construct a new instance of :class:`AnvilFormat`.

        This should not be used directly. You should instead use :func:`amulet.load_format`.

        :param path: The file path to the serialised data.
        """
        super().__init__(path)
        self._platform = "java"
        self._root_tag: nbt.NBTFile = nbt.NBTFile()
        self._levels: Dict[InternalDimension, AnvilDimensionManager] = {}
        self._dimension_name_map: Dict[Dimension, InternalDimension] = {}
        self._mcc_support: Optional[bool] = None
        self._lock_time = None
        self._data_pack: Optional[DataPackManager] = None
        self._shallow_load()
Esempio n. 15
0
    def save_to(self, f: BinaryIO):
        if self._platform == "java":
            materials = "Alpha"
        elif self._platform == "bedrock":
            materials = "Pocket"
        else:
            raise ObjectWriteError(
                f'"{self._platform}" is not a supported platform for a schematic file.'
            )

        selection = self._selection.selection_boxes[0]

        data = amulet_nbt.NBTFile(
            amulet_nbt.TAG_Compound({
                "TileTicks":
                amulet_nbt.TAG_List(),
                "Width":
                amulet_nbt.TAG_Short(selection.size_x),
                "Height":
                amulet_nbt.TAG_Short(selection.size_y),
                "Length":
                amulet_nbt.TAG_Short(selection.size_z),
                "Materials":
                amulet_nbt.TAG_String(materials),
            }),
            "Schematic",
        )

        entities = []
        block_entities = []
        blocks = numpy.zeros(
            selection.shape,
            dtype=numpy.uint16)  # only 12 bits are actually used at most
        block_data = numpy.zeros(selection.shape,
                                 dtype=numpy.uint8)  # only 4 bits are used

        for (
                selection_,
                blocks_,
                data_,
                block_entities_,
                entities_,
        ) in self._chunks.values():
            if selection_.intersects(selection):
                box = selection_.create_moved_box(selection.min, subtract=True)
                blocks[box.slice] = blocks_
                block_data[box.slice] = data_
                for be in block_entities_:
                    coord_type = be["x"].__class__
                    be["x"] = coord_type(be["x"] - selection.min_x)
                    be["y"] = coord_type(be["y"] - selection.min_y)
                    be["z"] = coord_type(be["z"] - selection.min_z)
                    block_entities.append(be)
                for e in entities_:
                    coord_type = e["Pos"][0].__class__
                    e["Pos"][0] = coord_type(e["Pos"][0] - selection.min_x)
                    e["Pos"][1] = coord_type(e["Pos"][1] - selection.min_y)
                    e["Pos"][2] = coord_type(e["Pos"][2] - selection.min_z)
                    entities.append(e)

        data["Entities"] = amulet_nbt.TAG_List(entities)
        data["TileEntities"] = amulet_nbt.TAG_List(block_entities)
        data["Data"] = amulet_nbt.TAG_Byte_Array(
            numpy.transpose(block_data, (1, 2, 0))  # XYZ => YZX
        )
        data["Blocks"] = amulet_nbt.TAG_Byte_Array(
            numpy.transpose((blocks & 0xFF).astype(numpy.uint8), (1, 2, 0)))
        if numpy.max(blocks) > 0xFF:
            add_blocks = numpy.transpose(blocks & 0xF00, (1, 2, 0)) >> 8
            data["AddBlocks"] = amulet_nbt.TAG_Byte_Array(
                add_blocks[::2] + (add_blocks[1::2] << 4))
        data.save_to(f)
Esempio n. 16
0
    def save_to(self, f: BinaryIO):
        if self._schem_version == 1:
            raise SpongeSchemReadError(
                "Sponge Schematic Version 1 is not supported currently.")
        elif self._schem_version == 2:
            selection = self._bounds[self.dimensions[0]].selection_boxes[0]
            if any(s > 2**16 - 1 for s in selection.shape):
                raise SpongeSchemWriteError(
                    "The structure is too large to be exported to a Sponge Schematic file. It must be 2^16 - 1 at most in each dimension."
                )
            overflowed_shape = [
                s if s < 2**15 else s - 2**16 for s in selection.shape
            ]
            data = amulet_nbt.NBTFile(
                amulet_nbt.TAG_Compound({
                    "Version":
                    amulet_nbt.TAG_Int(2),
                    "DataVersion":
                    amulet_nbt.TAG_Int(self._version),
                    "Width":
                    amulet_nbt.TAG_Short(overflowed_shape[0]),
                    "Height":
                    amulet_nbt.TAG_Short(overflowed_shape[1]),
                    "Length":
                    amulet_nbt.TAG_Short(overflowed_shape[2]),
                    "Offset":
                    amulet_nbt.TAG_Int_Array(selection.min),
                }),
                name="Schematic",
            )

            entities = []
            block_entities = []
            blocks = numpy.zeros(selection.shape, dtype=numpy.uint32)
            palette: List[AnyNDArray] = []
            if self._version < 1500:
                raise Exception(
                    "Writing to Sponge Schematic files in pre-1.13 format is not currently supported."
                )
            else:
                arr = numpy.empty(1, dtype=object)
                arr[0] = Block("minecraft", "air")
                palette.append((arr))

            palette_len = 1

            for (
                    selection_,
                    blocks_,
                    palette_,
                    block_entities_,
                    entities_,
            ) in self._chunks.values():
                if selection_.intersects(selection):
                    box = selection_.create_moved_box(selection.min,
                                                      subtract=True)
                    blocks[box.slice] = blocks_ + palette_len
                    palette.append(palette_)
                    palette_len += len(palette_)
                    for be in block_entities_:
                        be = copy.deepcopy(be)
                        be["Pos"] = amulet_nbt.TAG_Int_Array(be["Pos"] -
                                                             selection.min)
                        block_entities.append(be)

                    for e in entities_:
                        e = copy.deepcopy(e)
                        x, y, z = e["Pos"]
                        e["Pos"] = amulet_nbt.TAG_List([
                            amulet_nbt.TAG_Int(x - selection.min_x),
                            amulet_nbt.TAG_Int(y - selection.min_y),
                            amulet_nbt.TAG_Int(z - selection.min_z),
                        ])
                        entities.append(e)

            compact_palette, lut = brute_sort_objects_no_hash(
                numpy.concatenate(palette))
            blocks = numpy.transpose(lut[blocks],
                                     (1, 2, 0)).ravel()  # XYZ => YZX
            block_palette = []
            for index, block in enumerate(compact_palette):
                block: Block
                block_palette.append(block.blockstate)

            data["PaletteMax"] = amulet_nbt.TAG_Int(len(compact_palette))
            data["Palette"] = amulet_nbt.TAG_Compound({
                blockstate: amulet_nbt.TAG_Int(index)
                for index, blockstate in enumerate(block_palette)
            })
            data["BlockData"] = amulet_nbt.TAG_Byte_Array(
                list(encode_array(blocks)))
            if block_entities:
                data["BlockEntities"] = amulet_nbt.TAG_List(block_entities)
            if entities:
                data["Entities"] = amulet_nbt.TAG_List(entities)

            data.save_to(f)
        else:
            raise SpongeSchemReadError(
                f"Sponge Schematic Version {self._schem_version} is not supported currently."
            )
Esempio n. 17
0
 def __init__(self, directory: str):
     super().__init__(directory)
     self._lock = False
     self.root_tag: nbt.NBTFile = nbt.NBTFile()
     self._load_level_dat()
     self._level_manager: Optional[LevelDBLevelManager] = None
Esempio n. 18
0
    def encode(self, chunk: "Chunk", palette: AnyNDArray,
               max_world_version: Tuple[str, int]) -> amulet_nbt.NBTFile:
        """
        Encode a version-specific chunk to raw data for the format to store.
        :param chunk: The version-specific chunk to translate and encode.
        :param palette: The block_palette the ids in the chunk correspond to.
        :param max_world_version: The key to use to find the encoder.
        :return: amulet_nbt.NBTFile
        """

        misc = chunk.misc
        data = amulet_nbt.NBTFile(amulet_nbt.TAG_Compound(), "")
        data["Level"] = amulet_nbt.TAG_Compound()
        data["Level"]["xPos"] = amulet_nbt.TAG_Int(chunk.cx)
        data["Level"]["zPos"] = amulet_nbt.TAG_Int(chunk.cz)
        if self.features["data_version"] == "int":
            data["DataVersion"] = amulet_nbt.TAG_Int(max_world_version[1])

        if self.features["last_update"] == "long":
            data["Level"]["LastUpdate"] = amulet_nbt.TAG_Long(
                misc.get("last_update", 0))

        # Order the float value based on the order they would be run. Newer replacements for the same come just after
        # to save back find the next lowest valid value.
        if self.features["status"] in ["j13", "j14"]:
            status = chunk.status.as_type(self.features["status"])
            data["Level"]["Status"] = amulet_nbt.TAG_String(status)

        else:
            status = chunk.status.as_type("float")
            if self.features["terrain_populated"] == "byte":
                data["Level"]["TerrainPopulated"] = amulet_nbt.TAG_Byte(
                    int(status > -0.3))

            if self.features["light_populated"] == "byte":
                data["Level"]["LightPopulated"] = amulet_nbt.TAG_Byte(
                    int(status > -0.2))

        if self.features["V"] == "byte":
            data["Level"]["V"] = amulet_nbt.TAG_Byte(misc.get("V", 1))

        if self.features["inhabited_time"] == "long":
            data["Level"]["InhabitedTime"] = amulet_nbt.TAG_Long(
                misc.get("inhabited_time", 0))

        if self.features["biomes"] == "256BA":
            if chunk.status.value > -0.7:
                data["Level"]["Biomes"] = amulet_nbt.TAG_Byte_Array(
                    chunk.biomes.convert_to_format(256).astype(
                        dtype=numpy.uint8))
        elif self.features["biomes"] == "256IA":
            if chunk.status.value > -0.7:
                data["Level"]["Biomes"] = amulet_nbt.TAG_Int_Array(
                    chunk.biomes.convert_to_format(256).astype(
                        dtype=numpy.uint32))
        elif self.features["biomes"] == "1024IA":
            if chunk.status.value > -0.7:
                data["Level"]["Biomes"] = amulet_nbt.TAG_Int_Array(
                    chunk.biomes.convert_to_format(1024).astype(
                        dtype=numpy.uint32))

        if self.features["height_map"] == "256IA":
            data["Level"]["HeightMap"] = amulet_nbt.TAG_Int_Array(
                misc.get("height_map256IA", numpy.zeros(256,
                                                        dtype=numpy.uint32)))
        elif self.features["height_map"] in [
                "C|36LA|V1",
                "C|36LA|V2",
                "C|36LA|V3",
                "C|36LA|V4",
        ]:
            maps = [
                "WORLD_SURFACE_WG",
                "OCEAN_FLOOR_WG",
                "MOTION_BLOCKING",
                "MOTION_BLOCKING_NO_LEAVES",
                "OCEAN_FLOOR",
            ]
            if self.features["height_map"] == "C|36LA|V1":  # 1466
                maps = ("LIQUID", "SOILD", "LIGHT", "RAIN")
            elif self.features["height_map"] == "C|36LA|V2":  # 1484
                maps.append("LIGHT_BLOCKING")
            elif self.features["height_map"] == "C|36LA|V3":  # 1503
                maps.append("LIGHT_BLOCKING")
                maps.append("WORLD_SURFACE")
            elif self.features["height_map"] == "C|36LA|V4":  # 1908
                maps.append("WORLD_SURFACE")
            else:
                raise Exception
            heightmaps = misc.get("height_mapC|36LA",
                                  amulet_nbt.TAG_Compound())
            for heightmap in maps:
                if heightmap not in heightmaps:
                    heightmaps[heightmap] = amulet_nbt.TAG_Long_Array(
                        numpy.zeros(36, dtype=">i8"))
            data["Level"]["Heightmaps"] = heightmaps

        if self.features["blocks"] in [
                "Sections|(Blocks,Data,Add)",
                "Sections|(BlockStates,Palette)",
        ]:
            data["Level"]["Sections"] = self._encode_blocks(
                chunk.blocks, palette)
        else:
            raise Exception(
                f'Unsupported block format {self.features["blocks"]}')

        if self.features["block_light"] in [
                "Sections|2048BA"
        ] or self.features["sky_light"] in ["Sections|2048BA"]:
            for section in data["Level"]["Sections"]:
                y = section["Y"].value
                if self.features["block_light"] == "Sections|2048BA":
                    block_light = misc.get("block_light", {})
                    if y in block_light:
                        section["BlockLight"] = block_light[y]
                    else:
                        section["BlockLight"] = amulet_nbt.TAG_Byte_Array(
                            numpy.full(2048, 255, dtype=numpy.uint8))
                if self.features["sky_light"] == "Sections|2048BA":
                    sky_light = misc.get("sky_light", {})
                    if y in sky_light:
                        section["SkyLight"] = sky_light[y]
                    else:
                        section["SkyLight"] = amulet_nbt.TAG_Byte_Array(
                            numpy.full(2048, 255, dtype=numpy.uint8))

        if self.features["entities"] == "list":
            if amulet.entity_support:
                data["Level"]["Entities"] = self._encode_entities(
                    chunk.entities)
            else:
                data["Level"]["Entities"] = self._encode_entities(
                    misc.get("java_entities_temp", amulet_nbt.TAG_List()))

        if self.features["block_entities"] == "list":
            data["Level"]["TileEntities"] = self._encode_block_entities(
                chunk.block_entities)

        if self.features["tile_ticks"] in ["list", "list(optional)"]:
            ticks = misc.get("tile_ticks", amulet_nbt.TAG_List())
            if self.features["tile_ticks"] == "list(optional)":
                if len(ticks) > 0:
                    data["Level"]["TileTicks"] = ticks
            elif self.features["tile_ticks"] == "list":
                data["Level"]["TileTicks"] = ticks

        if self.features["liquid_ticks"] == "list":
            data["Level"]["LiquidTicks"] = misc.get("liquid_ticks",
                                                    amulet_nbt.TAG_List())

        if self.features["liquids_to_be_ticked"] == "16list|list":
            data["Level"]["LiquidsToBeTicked"] = misc.get(
                "liquids_to_be_ticked",
                amulet_nbt.TAG_List([amulet_nbt.TAG_List()
                                     for _ in range(16)]),
            )

        if self.features["to_be_ticked"] == "16list|list":
            data["Level"]["ToBeTicked"] = misc.get(
                "to_be_ticked",
                amulet_nbt.TAG_List([amulet_nbt.TAG_List()
                                     for _ in range(16)]),
            )

        if self.features["post_processing"] == "16list|list":
            data["Level"]["PostProcessing"] = misc.get(
                "post_processing",
                amulet_nbt.TAG_List([amulet_nbt.TAG_List()
                                     for _ in range(16)]),
            )

        if self.features["structures"] == "compound":
            data["Level"]["Structures"] = misc.get(
                "structures",
                amulet_nbt.TAG_Compound({
                    "References": amulet_nbt.TAG_Compound(),
                    "Starts": amulet_nbt.TAG_Compound(),
                }),
            )

        return data
Esempio n. 19
0
    def _encode_subchunks(
        self,
        blocks: "Blocks",
        palette: AnyNDArray,
        bounds: Tuple[int, int],
        max_world_version: VersionNumberTuple,
    ) -> Dict[int, Optional[bytes]]:
        # Encode sub-chunk block format 8
        palette_depth = numpy.array([len(block) for block in palette])
        min_y = bounds[0] // 16
        max_y = bounds[1] // 16
        if palette.size:
            if palette[0][0][0] is None:
                air = amulet_nbt.NBTFile(
                    amulet_nbt.TAG_Compound({
                        "name":
                        amulet_nbt.TAG_String("minecraft:air"),
                        "val":
                        amulet_nbt.TAG_Short(0),
                    }))
            else:
                air = amulet_nbt.NBTFile(
                    amulet_nbt.TAG_Compound({
                        "name":
                        amulet_nbt.TAG_String("minecraft:air"),
                        "states":
                        amulet_nbt.TAG_Compound({}),
                        "version":
                        amulet_nbt.TAG_Int(17_629_184),  # 1, 13, 0, 0
                    }))

            for index, block in enumerate(palette):
                block: Tuple[Tuple[Optional[int], Block], ...]
                full_block = []
                for sub_block_version, sub_block in block:
                    properties = sub_block.properties
                    if sub_block_version is None:
                        block_data = properties.get("block_data",
                                                    amulet_nbt.TAG_Int(0))
                        if isinstance(block_data, amulet_nbt.TAG_Int):
                            block_data = block_data.value
                            # if block_data >= 16:
                            #     block_data = 0
                        else:
                            block_data = 0
                        sub_block_ = amulet_nbt.NBTFile(
                            amulet_nbt.TAG_Compound({
                                "name":
                                amulet_nbt.TAG_String(
                                    sub_block.namespaced_name),
                                "val":
                                amulet_nbt.TAG_Short(block_data),
                            }))
                    else:
                        sub_block_ = amulet_nbt.NBTFile(
                            amulet_nbt.TAG_Compound({
                                "name":
                                amulet_nbt.TAG_String(
                                    sub_block.namespaced_name),
                                "states":
                                amulet_nbt.TAG_Compound({
                                    key: val
                                    for key, val in properties.items()
                                    if isinstance(val, PropertyDataTypes)
                                }),
                                "version":
                                amulet_nbt.TAG_Int(sub_block_version),
                            }))

                    full_block.append(sub_block_)
                palette[index] = tuple(full_block)

            chunk = {}
            for cy in range(min_y, max_y):
                if cy in blocks:
                    palette_index, sub_chunk = fast_unique(
                        blocks.get_sub_chunk(cy))
                    sub_chunk_palette = palette[palette_index]
                    sub_chunk_depth = palette_depth[palette_index].max()

                    if (sub_chunk_depth == 1 and len(sub_chunk_palette) == 1
                            and sub_chunk_palette[0][0]["name"].value
                            == "minecraft:air"):
                        chunk[cy] = None
                    else:
                        # pad block_palette with air in the extra layers
                        sub_chunk_palette_full = numpy.empty(
                            (sub_chunk_palette.size, sub_chunk_depth),
                            dtype=object)
                        sub_chunk_palette_full.fill(air)

                        for index, block_tuple in enumerate(sub_chunk_palette):
                            for sub_index, block in enumerate(block_tuple):
                                sub_chunk_palette_full[index,
                                                       sub_index] = block
                        # should now be a 2D array with an amulet_nbt.NBTFile in each element

                        if max_world_version[1] >= (
                                1,
                                17,
                                30,
                        ):  # Why do I need to check against game version and not chunk version
                            sub_chunk_bytes = [
                                b"\x09",
                                bytes([sub_chunk_depth]),
                                struct.pack("b", cy),
                            ]
                        else:
                            sub_chunk_bytes = [
                                b"\x08", bytes([sub_chunk_depth])
                            ]
                        for sub_chunk_layer_index in range(sub_chunk_depth):
                            # TODO: sort out a way to do this quicker without brute forcing it.
                            (
                                sub_chunk_layer_palette,
                                sub_chunk_remap,
                            ) = brute_sort_objects_no_hash(
                                sub_chunk_palette_full[:,
                                                       sub_chunk_layer_index])
                            sub_chunk_layer = sub_chunk_remap[
                                sub_chunk.ravel()]

                            # sub_chunk_layer, sub_chunk_layer_palette = sub_chunk, sub_chunk_palette_full[:, sub_chunk_layer_index]
                            sub_chunk_bytes.append(
                                self._save_palette_subchunk(
                                    sub_chunk_layer.reshape(16, 16, 16),
                                    list(sub_chunk_layer_palette.ravel()),
                                ))

                        chunk[cy] = b"".join(sub_chunk_bytes)
                else:
                    chunk[cy] = None
        else:
            chunk = {i: None for i in range(min_y, max_y)}

        return chunk
Esempio n. 20
0
    def save_to(self, f: BinaryIO):
        selection = self._selection.selection_boxes[0]
        data = amulet_nbt.NBTFile(
            amulet_nbt.TAG_Compound(
                {
                    "format_version": amulet_nbt.TAG_Int(1),
                    "structure_world_origin": amulet_nbt.TAG_List(
                        [
                            amulet_nbt.TAG_Int(selection.min_x),
                            amulet_nbt.TAG_Int(selection.min_y),
                            amulet_nbt.TAG_Int(selection.min_z),
                        ]
                    ),
                    "size": amulet_nbt.TAG_List(
                        [
                            amulet_nbt.TAG_Int(selection.size_x),
                            amulet_nbt.TAG_Int(selection.size_y),
                            amulet_nbt.TAG_Int(selection.size_z),
                        ]
                    ),
                }
            )
        )

        entities = []
        block_entities = []
        blocks = numpy.zeros(
            selection.shape, dtype=numpy.uint32
        )  # only 12 bits are actually used at most
        palette: List[AnyNDArray] = []
        palette_len = 0

        for (
            selection_,
            blocks_,
            palette_,
            block_entities_,
            entities_,
        ) in self._chunks.values():
            if selection_.intersects(selection):
                box = selection_.create_moved_box(selection.min, subtract=True)
                blocks[box.slice] = blocks_ + palette_len
                palette.append(palette_)
                palette_len += len(palette_)
                block_entities += block_entities_
                entities += entities_

        compact_palette, lut = brute_sort_objects_no_hash(numpy.concatenate(palette))
        blocks = lut[blocks].ravel()
        block_palette = []
        block_palette_indices = []
        for block_list in compact_palette:
            indexed_block = [-1] * 2
            for block_layer, block in enumerate(block_list):
                if block_layer >= 2:
                    break
                if block in block_palette:
                    indexed_block[block_layer] = block_palette.index(block)
                else:
                    indexed_block[block_layer] = len(block_palette)
                    block_palette.append(block)
            block_palette_indices.append(indexed_block)

        block_indices = numpy.array(block_palette_indices, dtype=numpy.int32)[blocks].T

        data["structure"] = amulet_nbt.TAG_Compound(
            {
                "block_indices": amulet_nbt.TAG_List(
                    [  # a list of tag ints that index into the block_palette. One list per block layer
                        amulet_nbt.TAG_List(
                            [amulet_nbt.TAG_Int(block) for block in layer]
                        )
                        for layer in block_indices
                    ]
                ),
                "entities": amulet_nbt.TAG_List(entities),
                "palette": amulet_nbt.TAG_Compound(
                    {
                        "default": amulet_nbt.TAG_Compound(
                            {
                                "block_palette": amulet_nbt.TAG_List(block_palette),
                                "block_position_data": amulet_nbt.TAG_Compound(
                                    {
                                        str(
                                            (
                                                (
                                                    block_entity["x"].value
                                                    - selection.min_x
                                                )
                                                * selection.size_y
                                                + (
                                                    block_entity["y"].value
                                                    - selection.min_y
                                                )
                                            )
                                            * selection.size_z
                                            + block_entity["z"].value
                                            - selection.min_z
                                        ): amulet_nbt.TAG_Compound(
                                            {"block_entity_data": block_entity}
                                        )
                                        for block_entity in block_entities
                                    }
                                ),
                            }
                        )
                    }
                ),
            }
        )
        data.save_to(f, compressed=False, little_endian=True)
Esempio n. 21
0
def fillbarrels(chunk, barrelPositionList, barrelBlock, currentArticle,
                booksPerBarrel, zimFilePath, chunkList, target_pos):
    """Generates all barrels in the chunk and fills them with books/articles"""

    for barrelPos in barrelPositionList:
        books = []
        titles = []

        start = time.perf_counter()

        if booksPerBarrel > 30:
            pool = Pool(
                processes=4
            )  #on my laptop ~4 processes was faster than any amount of threads (4 = logic core count)
        else:
            pool = ThreadPool(
                processes=3
            )  #the article reading is mostly cpu limited, so going high on process count doesnt help
        outputs = pool.map(
            partial(tryGetArticle,
                    zimFilePath=zimFilePath,
                    barrelPositionList=barrelPositionList,
                    booksPerBarrel=booksPerBarrel,
                    chunkList=chunkList,
                    target_pos=target_pos),
            range(currentArticle, currentArticle + booksPerBarrel))
        pool.close()
        #outputs = []
        #for id in range(currentArticle, currentArticle + booksPerBarrel):
        #    outputs.append(tryGetArticle(id, zimFilePath))

        currentArticle += booksPerBarrel
        for output in outputs:
            if output[0] == None:
                continue
            titles.append(output[1])
            books.append(output[0])

        stop = time.perf_counter()
        #print("generating a book", (stop-start)/booksPerBarrel)

        chunk.blocks[barrelPos] = barrelBlock
        barrelEntity = BlockEntity("java", "barrel", barrelPos[0] + chunk.cx * 16, barrelPos[1], barrelPos[2] + chunk.cz * 16,\
            amulet_nbt.NBTFile(\
                value = amulet_nbt.TAG_Compound(\
                {\
                    "utags": amulet_nbt.TAG_Compound(\
                    {\
                        "keepPacked": amulet_nbt.TAG_Byte(0),\
                        "isMovable": amulet_nbt.TAG_Byte(1),\
                        "Findable": amulet_nbt.TAG_Byte(0),\
                        "CustomName": amulet_nbt.TAG_String("{\"text\":\"x:%d y:%d z:%d\"}"%(barrelPos[0] + chunk.cx * 16, barrelPos[1], barrelPos[2] + chunk.cz * 16)),\
                        "Items": amulet_nbt.TAG_List(\
                            value = [
                                amulet_nbt.TAG_Compound(\
                                {\
                                    "Slot": amulet_nbt.TAG_Byte(iBook),\
                                    "Count": amulet_nbt.TAG_Byte(1),\
                                    "id": amulet_nbt.TAG_String("minecraft:written_book"),\
                                    "tag": amulet_nbt.TAG_Compound(\
                                    {
                                        "pages": amulet_nbt.TAG_List(\
                                            value=[amulet_nbt.TAG_String(page) for page in books[iBook]],\
                                            list_data_type = 8\
                                        ),\
                                        "title": amulet_nbt.TAG_String(titles[iBook]),\
                                        "author": amulet_nbt.TAG_String("Pos: x:%d y:%d z:%d, ID: %d"%(barrelPos[0] + chunk.cx * 16, barrelPos[1], barrelPos[2] + chunk.cz * 16, currentArticle + iBook)),
                                    })
                                })
                                for iBook in range(len(books))
                            ], list_data_type = 9\
                        )
                    })\
                })))
        chunk.block_entities.insert(barrelEntity)
Esempio n. 22
0
    def save_to(self, f: BinaryIO):
        palette: BlockManager = BlockManager()
        f.write(magic_num)
        f.write(struct.pack(">B", self._format_version))
        if self._format_version == 0:
            metadata = amulet_nbt.NBTFile(
                amulet_nbt.TAG_Compound(
                    {
                        "created_with": amulet_nbt.TAG_String(
                            "amulet_python_wrapper_v2"
                        ),
                        "selection_boxes": amulet_nbt.TAG_Int_Array(
                            [
                                c
                                for box in self._selection.selection_boxes
                                for c in (*box.min, *box.max)
                            ]
                        ),
                        "section_version": amulet_nbt.TAG_Byte(self._section_version),
                        "export_version": amulet_nbt.TAG_Compound(
                            {
                                "edition": amulet_nbt.TAG_String(self._platform),
                                "version": amulet_nbt.TAG_List(
                                    [amulet_nbt.TAG_Int(v) for v in self._version]
                                ),
                            }
                        ),
                    }
                )
            )
            section_index_table: List[
                Tuple[int, int, int, int, int, int, int, int]
            ] = []
            if self._section_version == 0:
                for section_list in self._chunk_to_section.values():
                    for section in section_list:
                        sx, sy, sz = section.location
                        shapex, shapey, shapez = section.shape
                        blocks = section.blocks
                        entities = section.entities
                        block_entities = section.block_entities
                        section_palette = section.palette
                        position = f.tell()

                        _tag = amulet_nbt.TAG_Compound(
                            {"entities": serialise_entities(entities)}
                        )

                        if blocks is None:
                            _tag["blocks_array_type"] = amulet_nbt.TAG_Byte(-1)
                        else:
                            flattened_array = blocks.ravel()
                            index, flattened_array = numpy.unique(
                                flattened_array, return_inverse=True
                            )
                            section_palette = numpy.array(
                                section_palette, dtype=object
                            )[index]
                            lut = numpy.vectorize(palette.get_add_block)(
                                section_palette
                            )
                            flattened_array = lut[flattened_array]
                            array_type = find_fitting_array_type(flattened_array)
                            _tag["blocks_array_type"] = amulet_nbt.TAG_Byte(
                                array_type().tag_id
                            )
                            _tag["blocks"] = array_type(flattened_array)
                            _tag["block_entities"] = serialise_block_entities(
                                block_entities or []
                            )

                        amulet_nbt.NBTFile(_tag).save_to(f)

                        length = f.tell() - position
                        section_index_table.append(
                            (sx, sy, sz, shapex, shapey, shapez, position, length)
                        )
            else:
                raise Exception(
                    f"This wrapper doesn't support any section version higher than {max_section_version}"
                )
            metadata_start = f.tell()
            metadata["section_index_table"] = amulet_nbt.TAG_Byte_Array(
                numpy.array(section_index_table, dtype=SECTION_ENTRY_TYPE).view(
                    numpy.int8
                )
            )
            metadata["block_palette"] = pack_palette(palette)
            metadata.save_to(f)
            f.write(INT_STRUCT.pack(metadata_start))
            f.write(magic_num)
        else:
            raise Exception(
                f"This wrapper doesn't support any construction version higher than {max_format_version}"
            )
Esempio n. 23
0
        """
        Create a shallow copy of the entity container.
        """
        return EntityList(self)

    def __iter__(self) -> Iterable[Entity]:
        """
        An iterable of all the :class:`Entity` objects.
        """
        yield from self.data

    def __repr__(self) -> str:
        """Return repr(self)."""
        return f"EntityList({super().__repr__()})"


if __name__ == "__main__":
    import amulet_nbt

    entities_ = EntityList()
    block_ents = [
        Entity("minecraft", "creeper", 0.0, 0.0, 0.0, amulet_nbt.NBTFile()),
        Entity("minecraft", "cow", 0.0, 0.0, 0.0, amulet_nbt.NBTFile()),
        Entity("minecraft", "pig", 0.0, 0.0, 0.0, amulet_nbt.NBTFile()),
        Entity("minecraft", "sheep", 0.0, 0.0, 0.0, amulet_nbt.NBTFile()),
    ]
    entities_.append(
        Entity("minecraft", "cow", 0.0, 0.0, 0.0, amulet_nbt.NBTFile()))
    entities_ += block_ents
    print(entities_)
Esempio n. 24
0
    def _save_subchunks_8(self, blocks: "Blocks",
                          palette: AnyNDArray) -> List[Optional[bytes]]:
        palette_depth = numpy.array([len(block) for block in palette])
        if palette.size:
            if palette[0][0][0] is None:
                air = amulet_nbt.NBTFile(
                    amulet_nbt.TAG_Compound({
                        "name":
                        amulet_nbt.TAG_String("minecraft:air"),
                        "val":
                        amulet_nbt.TAG_Short(0),
                    }))
            else:
                air = amulet_nbt.NBTFile(
                    amulet_nbt.TAG_Compound({
                        "name":
                        amulet_nbt.TAG_String("minecraft:air"),
                        "states":
                        amulet_nbt.TAG_Compound({}),
                        "version":
                        amulet_nbt.TAG_Int(17_629_184),  # 1, 13, 0, 0
                    }))

            for index, block in enumerate(palette):
                block: Tuple[Tuple[Optional[int], Block], ...]
                full_block = []
                for sub_block_version, sub_block in block:
                    properties = sub_block.properties
                    if sub_block_version is None:
                        block_data = properties.get("block_data",
                                                    amulet_nbt.TAG_Int(0))
                        if isinstance(block_data, amulet_nbt.TAG_Int):
                            block_data = block_data.value
                            # if block_data >= 16:
                            #     block_data = 0
                        else:
                            block_data = 0
                        sub_block_ = amulet_nbt.NBTFile(
                            amulet_nbt.TAG_Compound({
                                "name":
                                amulet_nbt.TAG_String(
                                    sub_block.namespaced_name),
                                "val":
                                amulet_nbt.TAG_Short(block_data),
                            }))
                    else:
                        sub_block_ = amulet_nbt.NBTFile(
                            amulet_nbt.TAG_Compound({
                                "name":
                                amulet_nbt.TAG_String(
                                    sub_block.namespaced_name),
                                "states":
                                amulet_nbt.TAG_Compound({
                                    key: val
                                    for key, val in properties.items()
                                    if isinstance(val, PropertyDataTypes)
                                }),
                                "version":
                                amulet_nbt.TAG_Int(sub_block_version),
                            }))

                    full_block.append(sub_block_)
                palette[index] = tuple(full_block)

            chunk = []
            for cy in range(16):
                if cy in blocks:
                    palette_index, sub_chunk = fast_unique(
                        blocks.get_sub_chunk(cy))
                    sub_chunk_palette = palette[palette_index]
                    sub_chunk_depth = palette_depth[palette_index].max()

                    if (sub_chunk_depth == 1 and len(sub_chunk_palette) == 1
                            and sub_chunk_palette[0][0]["name"].value
                            == "minecraft:air"):
                        chunk.append(None)
                    else:
                        # pad block_palette with air in the extra layers
                        sub_chunk_palette_full = numpy.empty(
                            (sub_chunk_palette.size, sub_chunk_depth),
                            dtype=object)
                        sub_chunk_palette_full.fill(air)

                        for index, block_tuple in enumerate(sub_chunk_palette):
                            for sub_index, block in enumerate(block_tuple):
                                sub_chunk_palette_full[index,
                                                       sub_index] = block
                        # should now be a 2D array with an amulet_nbt.NBTFile in each element

                        sub_chunk_bytes = [b"\x08", bytes([sub_chunk_depth])]
                        for sub_chunk_layer_index in range(sub_chunk_depth):
                            # TODO: sort out a way to do this quicker without brute forcing it.
                            (
                                sub_chunk_layer_palette,
                                sub_chunk_remap,
                            ) = brute_sort_objects_no_hash(
                                sub_chunk_palette_full[:,
                                                       sub_chunk_layer_index])
                            sub_chunk_layer = sub_chunk_remap[
                                sub_chunk.ravel()]

                            # sub_chunk_layer, sub_chunk_layer_palette = sub_chunk, sub_chunk_palette_full[:, sub_chunk_layer_index]
                            sub_chunk_bytes.append(
                                self._save_palette_subchunk(
                                    sub_chunk_layer.reshape(16, 16, 16),
                                    list(sub_chunk_layer_palette.ravel()),
                                ))

                        chunk.append(b"".join(sub_chunk_bytes))
                else:
                    chunk.append(None)
        else:
            chunk = [None] * 16

        return chunk
Esempio n. 25
0
    def save_to(self, f: BinaryIO):
        selection = self._bounds[self.dimensions[0]].selection_boxes[0]
        data = amulet_nbt.NBTFile(
            amulet_nbt.TAG_Compound({
                "format_version":
                amulet_nbt.TAG_Int(1),
                "structure_world_origin":
                amulet_nbt.TAG_List([
                    amulet_nbt.TAG_Int(selection.min_x),
                    amulet_nbt.TAG_Int(selection.min_y),
                    amulet_nbt.TAG_Int(selection.min_z),
                ]),
                "size":
                amulet_nbt.TAG_List([
                    amulet_nbt.TAG_Int(selection.size_x),
                    amulet_nbt.TAG_Int(selection.size_y),
                    amulet_nbt.TAG_Int(selection.size_z),
                ]),
            }))

        entities = []
        block_entities = []
        blocks = numpy.zeros(selection.shape, dtype=numpy.uint32)
        palette: List[AnyNDArray] = []
        if self.version < (1, 13, 0):
            raise Exception(
                "Writing to mcstructre files in pre-1.13 format is not currently supported."
            )
        else:
            arr = numpy.empty(1, dtype=object)
            arr[0] = [
                amulet_nbt.TAG_Compound({
                    "name":
                    amulet_nbt.TAG_String("minecraft:air"),
                    "states":
                    amulet_nbt.TAG_Compound(),
                    "version":
                    amulet_nbt.TAG_Int(17694723),
                })
            ]
            palette.append(arr)

        palette_len = 1

        for (
                selection_,
                blocks_,
                palette_,
                block_entities_,
                entities_,
        ) in self._chunks.values():
            if selection_.intersects(selection):
                box = selection_.create_moved_box(selection.min, subtract=True)
                blocks[box.slice] = blocks_ + palette_len
                palette.append(palette_)
                palette_len += len(palette_)
                block_entities += block_entities_
                entities += entities_

        compact_palette, lut = brute_sort_objects_no_hash(
            numpy.concatenate(palette))
        blocks = lut[blocks].ravel()
        block_palette = []
        block_palette_indices = []
        for block_list in compact_palette:
            indexed_block = [-1] * 2
            for block_layer, block in enumerate(block_list):
                if block_layer >= 2:
                    break
                if block["name"] != "minecraft:structure_void":
                    if block in block_palette:
                        indexed_block[block_layer] = block_palette.index(block)
                    else:
                        indexed_block[block_layer] = len(block_palette)
                        block_palette.append(block)
            block_palette_indices.append(indexed_block)

        block_indices = numpy.array(block_palette_indices,
                                    dtype=numpy.int32)[blocks].T

        data["structure"] = amulet_nbt.TAG_Compound({
            "block_indices":
            amulet_nbt.TAG_List(
                [  # a list of tag ints that index into the block_palette. One list per block layer
                    amulet_nbt.TAG_List(
                        [amulet_nbt.TAG_Int(block) for block in layer])
                    for layer in block_indices
                ]),
            "entities":
            amulet_nbt.TAG_List(entities),
            "palette":
            amulet_nbt.TAG_Compound({
                "default":
                amulet_nbt.TAG_Compound({
                    "block_palette":
                    amulet_nbt.TAG_List(block_palette),
                    "block_position_data":
                    amulet_nbt.TAG_Compound({
                        str(((block_entity["x"].value - selection.min_x) *
                             selection.size_y +
                             (block_entity["y"].value - selection.min_y)) *
                            selection.size_z + block_entity["z"].value -
                            selection.min_z): amulet_nbt.TAG_Compound(
                                {"block_entity_data": block_entity})
                        for block_entity in block_entities
                    }),
                })
            }),
        })
        data.save_to(f, compressed=False, little_endian=True)