Пример #1
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}"
         )
Пример #2
0
    def _unpack_blocks(
        translation_manager: "TranslationManager",
        version_identifier: VersionIdentifierType,
        chunk: Chunk,
        block_palette: AnyNDArray,
    ):
        """
        Unpack the version-specific block_palette into the stringified version where needed.

        :return: The block_palette converted to block objects.
        """
        version = translation_manager.get_version(*version_identifier)
        for index, block in enumerate(block_palette):
            block: Block
            if version.block.is_waterloggable(block.namespaced_name):
                properties = block.properties
                if "waterlogged" in properties:
                    waterlogged = properties["waterlogged"]
                    del properties["waterlogged"]
                    block = Block(
                        namespace=block.namespace,
                        base_name=block.base_name,
                        properties=properties,
                    )
                else:
                    waterlogged = amulet_nbt.TAG_String("false")

                if waterlogged == amulet_nbt.TAG_String("true"):
                    block_palette[index] = block + water
                else:
                    block_palette[index] = block
            elif version.block.is_waterloggable(block.namespaced_name, True):
                block_palette[index] = block + water

        chunk._block_palette = BlockManager(block_palette)
Пример #3
0
 def __init__(self, namespace: str, base_name: str, metadata: dict = None):
     super().__init__(
         {
             "namespace": amulet_nbt.TAG_String(namespace),
             "base_name": amulet_nbt.TAG_String(base_name),
             "metadata": amulet_nbt.TAG_Compound(metadata or {}),
         }
     )
Пример #4
0
    def _encode_base_entity(
        entity: Union[Entity, BlockEntity],
        id_type: EntityIDType,
        coord_type: EntityCoordType,
    ) -> Optional[amulet_nbt.NBTFile]:
        if not isinstance(entity.nbt, amulet_nbt.NBTFile) and isinstance(
                entity.nbt.value, amulet_nbt.TAG_Compound):
            return
        nbt = entity.nbt

        if id_type == EntityIDType.namespace_str_id:
            nbt["id"] = amulet_nbt.TAG_String(entity.namespaced_name)
        elif id_type == EntityIDType.namespace_str_Id:
            nbt["Id"] = amulet_nbt.TAG_String(entity.namespaced_name)
        elif id_type == EntityIDType.namespace_str_identifier:
            nbt["identifier"] = amulet_nbt.TAG_String(entity.namespaced_name)
        elif id_type == EntityIDType.str_id:
            nbt["id"] = amulet_nbt.TAG_String(entity.base_name)
        elif id_type == EntityIDType.int_id:
            if not entity.base_name.isnumeric():
                return
            nbt["id"] = amulet_nbt.TAG_Int(int(entity.base_name))
        else:
            raise NotImplementedError(f"Entity id type {id_type}")

        if coord_type == EntityCoordType.Pos_list_double:
            nbt["Pos"] = amulet_nbt.TAG_List([
                amulet_nbt.TAG_Double(float(entity.x)),
                amulet_nbt.TAG_Double(float(entity.y)),
                amulet_nbt.TAG_Double(float(entity.z)),
            ])
        elif coord_type == EntityCoordType.Pos_list_float:
            nbt["Pos"] = amulet_nbt.TAG_List([
                amulet_nbt.TAG_Float(float(entity.x)),
                amulet_nbt.TAG_Float(float(entity.y)),
                amulet_nbt.TAG_Float(float(entity.z)),
            ])
        elif coord_type == EntityCoordType.Pos_list_int:
            nbt["Pos"] = amulet_nbt.TAG_List([
                amulet_nbt.TAG_Int(int(entity.x)),
                amulet_nbt.TAG_Int(int(entity.y)),
                amulet_nbt.TAG_Int(int(entity.z)),
            ])
        elif coord_type == EntityCoordType.Pos_array_int:
            nbt["Pos"] = amulet_nbt.TAG_Int_Array(
                [int(entity.x), int(entity.y),
                 int(entity.z)])
        elif coord_type == EntityCoordType.xyz_int:
            nbt["x"] = amulet_nbt.TAG_Int(int(entity.x))
            nbt["y"] = amulet_nbt.TAG_Int(int(entity.y))
            nbt["z"] = amulet_nbt.TAG_Int(int(entity.z))
        else:
            raise NotImplementedError(f"Entity coord type {coord_type}")

        return nbt
 def parse_state_val(val) -> list:
     """Convert the json block state format into a consistent format."""
     if isinstance(val, str):
         return [amulet_nbt.TAG_String(v) for v in val.split("|")]
     elif isinstance(val, bool):
         return [
             amulet_nbt.TAG_String("true")
             if val else amulet_nbt.TAG_String("false")
         ]
     else:
         raise Exception(f"Could not parse state val {val}")
Пример #6
0
def generate_block_entry(block: Block, palette_len,
                         extra_blocks) -> amulet_nbt.TAG_Compound:
    return amulet_nbt.TAG_Compound({
        "namespace":
        amulet_nbt.TAG_String(block.namespace),
        "blockname":
        amulet_nbt.TAG_String(block.base_name),
        "properties":
        amulet_nbt.TAG_Compound(block.properties),
        "extra_blocks":
        amulet_nbt.TAG_List([
            amulet_nbt.TAG_Int(palette_len + extra_blocks.index(_extra_block))
            for _extra_block in block.extra_blocks
        ]),
    })
Пример #7
0
    def _create(
        self,
        overwrite: bool,
        bounds: Union[SelectionGroup,
                      Dict[Dimension, Optional[SelectionGroup]], None] = None,
        **kwargs,
    ):
        if os.path.isdir(self.path):
            if overwrite:
                shutil.rmtree(self.path)
            else:
                raise ObjectWriteError(
                    f"A world already exists at the path {self.path}")

        version = self.translation_manager.get_version(
            self.platform, self.version).version_number
        self._version = version + (0, ) * (5 - len(version))

        self.root_tag = root = nbt.TAG_Compound()
        root["StorageVersion"] = nbt.TAG_Int(8)
        root["lastOpenedWithVersion"] = nbt.TAG_List(
            [nbt.TAG_Int(i) for i in self._version])
        root["Generator"] = nbt.TAG_Int(1)
        root["LastPlayed"] = nbt.TAG_Long(int(time.time()))
        root["LevelName"] = nbt.TAG_String("World Created By Amulet")

        os.makedirs(self.path, exist_ok=True)
        self.root_tag.save(os.path.join(self.path, "level.dat"))

        db = LevelDB(os.path.join(self.path, "db"), True)
        db.close()

        self._reload_world()
Пример #8
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
Пример #9
0
 def _serialise_entities(entities: List[Entity]) -> amulet_nbt.TAG_List:
     return amulet_nbt.TAG_List(
         [
             amulet_nbt.TAG_Compound(
                 {
                     "namespace": amulet_nbt.TAG_String(entity.namespace),
                     "base_name": amulet_nbt.TAG_String(entity.base_name),
                     "x": amulet_nbt.TAG_Double(entity.x),
                     "y": amulet_nbt.TAG_Double(entity.y),
                     "z": amulet_nbt.TAG_Double(entity.z),
                     "nbt": entity.nbt.value,
                 }
             )
             for entity in entities
         ]
     )
Пример #10
0
    def _create(
        self,
        overwrite: bool,
        bounds: Union[SelectionGroup,
                      Dict[Dimension, Optional[SelectionGroup]], None] = None,
        **kwargs,
    ):
        if os.path.isdir(self.path):
            if overwrite:
                shutil.rmtree(self.path)
            else:
                raise ObjectWriteError(
                    f"A world already exists at the path {self.path}")
        self._version = self.translation_manager.get_version(
            self.platform, self.version).data_version

        self.root_tag = root = nbt.TAG_Compound()
        root["Data"] = data = nbt.TAG_Compound()
        data["version"] = nbt.TAG_Int(19133)
        data["DataVersion"] = nbt.TAG_Int(self._version)
        data["LastPlayed"] = nbt.TAG_Long(int(time.time() * 1000))
        data["LevelName"] = nbt.TAG_String("World Created By Amulet")

        os.makedirs(self.path, exist_ok=True)
        self.root_tag.save_to(os.path.join(self.path, "level.dat"))
        self._reload_world()
Пример #11
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")\
                        })))
Пример #12
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
Пример #13
0
    def _encode_base_entity(
        entity: Union[Entity, BlockEntity], id_type: str, coord_type: str
    ) -> Optional[amulet_nbt.NBTFile]:
        if not isinstance(entity.nbt, amulet_nbt.NBTFile) and isinstance(
            entity.nbt.value, amulet_nbt.TAG_Compound
        ):
            return
        nbt = entity.nbt

        if id_type == "namespace-str-id":
            nbt["id"] = amulet_nbt.TAG_String(entity.namespaced_name)
        elif id_type == "namespace-str-identifier":
            nbt["identifier"] = amulet_nbt.TAG_String(entity.namespaced_name)
        elif id_type == "str-id":
            nbt["id"] = amulet_nbt.TAG_String(entity.base_name)
        elif id_type == "int-id":
            if not entity.base_name.isnumeric():
                return
            nbt["id"] = amulet_nbt.TAG_Int(int(entity.base_name))
        else:
            raise NotImplementedError(f"Entity id type {id_type}")

        if coord_type == "Pos-list-double":
            nbt["Pos"] = amulet_nbt.TAG_List(
                [
                    amulet_nbt.TAG_Double(float(entity.x)),
                    amulet_nbt.TAG_Double(float(entity.y)),
                    amulet_nbt.TAG_Double(float(entity.z)),
                ]
            )
        elif coord_type == "Pos-list-float":
            nbt["Pos"] = amulet_nbt.TAG_List(
                [
                    amulet_nbt.TAG_Float(float(entity.x)),
                    amulet_nbt.TAG_Float(float(entity.y)),
                    amulet_nbt.TAG_Float(float(entity.z)),
                ]
            )
        elif coord_type == "xyz-int":
            nbt["x"] = amulet_nbt.TAG_Int(int(entity.x))
            nbt["y"] = amulet_nbt.TAG_Int(int(entity.y))
            nbt["z"] = amulet_nbt.TAG_Int(int(entity.z))
        else:
            raise NotImplementedError(f"Entity coord type {coord_type}")

        return nbt
Пример #14
0
 def _serialise_block_entities(
     block_entities: List[BlockEntity], ) -> amulet_nbt.TAG_List:
     return amulet_nbt.TAG_List([
         amulet_nbt.TAG_Compound({
             "namespace":
             amulet_nbt.TAG_String(block_entity.namespace),
             "base_name":
             amulet_nbt.TAG_String(block_entity.base_name),
             "x":
             amulet_nbt.TAG_Int(block_entity.x),
             "y":
             amulet_nbt.TAG_Int(block_entity.y),
             "z":
             amulet_nbt.TAG_Int(block_entity.z),
             "nbt":
             block_entity.nbt.value,
         }) for block_entity in block_entities
     ])
Пример #15
0
 def _encode_palette(blockstates: list) -> amulet_nbt.TAG_List:
     palette = amulet_nbt.TAG_List()
     for block in blockstates:
         entry = amulet_nbt.TAG_Compound()
         entry["Name"] = amulet_nbt.TAG_String(
             f"{block.namespace}:{block.base_name}")
         entry["Properties"] = amulet_nbt.TAG_Compound(block.properties)
         palette.append(entry)
     return palette
Пример #16
0
    def encode(
        self,
        chunk: "Chunk",
        palette: AnyNDArray,
        max_world_version: VersionIdentifierType,
        box: SelectionBox,
    ) -> MCStructureChunk:
        """
        Take a version-specific chunk and encode it to raw data for the format to store.
        :param chunk: The already translated version-specfic chunk to encode.
        :param palette: The block_palette the ids in the chunk correspond to.
        :type palette: numpy.ndarray[Block]
        :param max_world_version: The key to use to find the encoder.
        :param box: The volume of the chunk to pack.
        :return: Raw data to be stored by the Format.
        """
        entities = []
        for e in chunk.entities:
            if e.location in box:
                entities.append(
                    self._encode_entity(e, self._entity_id_type,
                                        self._entity_coord_type).value)
        block_entities = []
        for e in chunk.block_entities:
            if e.location in box:
                block_entities.append(
                    self._encode_block_entity(
                        e, self._block_entity_id_type,
                        self._block_entity_coord_type).value)

        slices = box.create_moved_box((chunk.cx * 16, 0, chunk.cz * 16),
                                      subtract=True).slice

        out_palette = numpy.empty(palette.shape, dtype=object)
        for index, block_layers in enumerate(palette):
            blocks_out = []
            for version, block in block_layers:
                block = amulet_nbt.TAG_Compound({
                    "name":
                    amulet_nbt.TAG_String(
                        f"{block.namespace}:{block.base_name}"),
                    "states":
                    amulet_nbt.TAG_Compound(block.properties),
                })
                if version:
                    block["version"] = amulet_nbt.TAG_Int(version)
                blocks_out.append(block)
            out_palette[index] = blocks_out

        return MCStructureChunk(
            box,
            numpy.asarray(chunk.blocks[slices]),
            out_palette,
            block_entities,
            entities,
        )
Пример #17
0
    def parse_blockstate_string(
            blockstate: str,
            snbt: bool = False) -> Tuple[str, str, PropertyType]:
        """
        Parse a Java or SNBT blockstate string and return the raw data.

        To parse the blockstate and return a :class:`Block` instance use :func:`from_string_blockstate` or :func:`from_snbt_blockstate`

        :param blockstate: The blockstate to parse
        :param snbt: Are the property values in SNBT format. If false all values must be an instance of :class:`~amulet_nbt.TAG_String`
        :return: namespace, block_name, properties

        """
        if snbt:
            match = Block.snbt_blockstate_regex.match(blockstate)
        else:
            match = Block.blockstate_regex.match(blockstate)
        namespace = match.group("namespace") or "minecraft"
        base_name = match.group("base_name")

        if match.group("property_name") is not None:
            properties = {
                match.group("property_name"): match.group("property_value")
            }
            properties_string = match.group("properties")
            if properties_string is not None:
                if snbt:
                    for match in Block.snbt_properties_regex.finditer(
                            properties_string):
                        properties[match.group("name")] = match.group("value")
                else:
                    for match in Block.properties_regex.finditer(
                            properties_string):
                        properties[match.group("name")] = match.group("value")
        else:
            properties = {}

        if snbt:
            properties_dict = {
                k: amulet_nbt.from_snbt(v)
                for k, v in sorted(properties.items())
            }
        else:
            properties_dict = {
                k: amulet_nbt.TAG_String(v)
                for k, v in sorted(properties.items())
            }

        return (
            namespace,
            base_name,
            properties_dict,
        )
Пример #18
0
def set_block_property(block, key, val):
    p = block.properties.copy()
    nbt_val = None
    if isinstance(val, str):
        nbt_val = amulet_nbt.TAG_String(val)
    #TODO: can blocks actually have non-string properties?
    # Why are things like glass panes facings stored as strings?
    else:
        assert False, "Bad Property"
    p[key] = nbt_val
    block2 = Block(block.namespace, block.base_name, p)
    return block2
Пример #19
0
 def _pack_block_palette(self, version: "Version",
                         palette: BlockNDArray) -> AnyNDArray:
     """
     Translate the list of block objects into a version-specific block_palette.
     :return: The block_palette converted into version-specific blocks (ie id, data tuples for 1.12)
     """
     for index, block in enumerate(palette):
         block: Block
         if version.block.is_waterloggable(block.namespaced_name):
             properties = block.properties
             extra_blocks = block.extra_blocks
             if (extra_blocks and extra_blocks[0].namespaced_name
                     == water.namespaced_name):
                 properties["waterlogged"] = amulet_nbt.TAG_String("true")
             else:
                 properties["waterlogged"] = amulet_nbt.TAG_String("false")
             palette[index] = Block(
                 namespace=block.namespace,
                 base_name=block.base_name,
                 properties=properties,
             )
     return palette
Пример #20
0
def createBlocks(world):
    """generates all needed Block objects"""

    barrel = getBlock(
        world,
        Block(
            "minecraft", "barrel", {
                "facing": amulet_nbt.TAG_String("up"),
                "open": amulet_nbt.TAG_String("false")
            }))

    wool = getBlock(world, Block("minecraft", "red_wool"))

    air = getBlock(world, Block("minecraft", "air"))

    stone = getBlock(world, Block("minecraft", "stone"))

    glowstone = getBlock(world, Block("minecraft", "glowstone"))

    lantern = getBlock(
        world,
        Block("minecraft", "lantern",
              {"hanging": amulet_nbt.TAG_String("false")}))

    sign_north = getBlock(
        world,
        Block("minecraft", "acacia_wall_sign",
              {"facing": amulet_nbt.TAG_String("north")}))
    sign_south = getBlock(
        world,
        Block("minecraft", "acacia_wall_sign",
              {"facing": amulet_nbt.TAG_String("south")}))

    return [
        barrel, wool, glowstone, sign_north, sign_south, air, stone, lantern
    ]
Пример #21
0
    def encode(
        self,
        chunk: "Chunk",
        palette: AnyNDArray,
        max_world_version: Tuple[str, Union[int, Tuple[int, int, int]]],
        box: SelectionBox = None,
    ) -> MCStructureChunk:
        entities = []
        for e in chunk.entities:
            if e.location in box:
                entities.append(
                    self._encode_entity(
                        e, self._entity_id_type, self._entity_coord_type
                    ).value
                )
        block_entities = []
        for e in chunk.block_entities:
            if e.location in box:
                block_entities.append(
                    self._encode_block_entity(
                        e, self._block_entity_id_type, self._block_entity_coord_type
                    ).value
                )

        slices = box.create_moved_box(
            (chunk.cx * 16, 0, chunk.cz * 16), subtract=True
        ).slice

        out_palette = numpy.empty(palette.shape, dtype=object)
        for index, block_layers in enumerate(palette):
            blocks_out = []
            for version, block in block_layers:
                block = amulet_nbt.TAG_Compound(
                    {
                        "name": amulet_nbt.TAG_String(
                            f"{block.namespace}:{block.base_name}"
                        ),
                        "states": amulet_nbt.TAG_Compound(block.properties),
                    }
                )
                if version:
                    block["version"] = amulet_nbt.TAG_Int(version)
                blocks_out.append(block)
            out_palette[index] = blocks_out

        return MCStructureChunk(
            box, chunk.blocks[slices], out_palette, block_entities, entities
        )
Пример #22
0
    def __init__(self, path_or_buffer: PathOrBuffer):
        if isinstance(path_or_buffer, str):
            assert path_or_buffer.endswith(
                ".schematic"), "File selected is not a .schematic file"
            assert os.path.isfile(
                path_or_buffer
            ), f"There is no schematic file at path {path_or_buffer}"
            schematic = amulet_nbt.load(path_or_buffer)
            assert not all(key in schematic for key in (
                "Version", "Data Version",
                "BlockData")), "This file is not a legacy schematic file."
        else:
            assert hasattr(path_or_buffer,
                           "read"), "Object does not have a read method"
            schematic = amulet_nbt.load(buffer=path_or_buffer)

        materials = schematic.get("Materials", amulet_nbt.TAG_String()).value
        if materials == "Alpha":
            self._platform = "java"
        elif materials == "Pocket":
            self._platform = "bedrock"
        else:
            raise Exception(
                f'"{materials}" is not a supported platform for a schematic file.'
            )
        self._chunks: Dict[ChunkCoordinates,
                           Tuple[SelectionBox, BlockArrayType,
                                 BlockDataArrayType, list, list], ] = {}
        self._selection = SelectionBox(
            (0, 0, 0),
            (
                schematic["Width"].value,
                schematic["Height"].value,
                schematic["Length"].value,
            ),
        )
        entities: amulet_nbt.TAG_List = schematic.get("Entities",
                                                      amulet_nbt.TAG_List())
        block_entities: amulet_nbt.TAG_List = schematic.get(
            "TileEntities", amulet_nbt.TAG_List())
        blocks: numpy.ndarray = schematic["Blocks"].value.astype(
            numpy.uint8).astype(numpy.uint16)
        if "AddBlocks" in schematic:
            add_blocks = schematic["AddBlocks"]
            blocks = blocks + (numpy.concatenate([
                [(add_blocks & 0xF0) >> 4], [add_blocks & 0xF]
            ]).T.ravel().astype(numpy.uint16) << 8)[:blocks.size]
        max_point = self._selection.max
        temp_shape = (max_point[1], max_point[2], max_point[0])
        blocks = numpy.transpose(blocks.reshape(temp_shape),
                                 (2, 0, 1))  # YZX => XYZ
        data = numpy.transpose(schematic["Data"].value.reshape(temp_shape),
                               (2, 0, 1))
        for cx, cz in self._selection.chunk_locations():
            box = SelectionBox(
                (cx * 16, 0, cz * 16),
                (
                    min((cx + 1) * 16, self._selection.size_x),
                    self._selection.size_y,
                    min((cz + 1) * 16, self._selection.size_z),
                ),
            )
            self._chunks[(cx, cz)] = (box, blocks[box.slice], data[box.slice],
                                      [], [])
        for e in block_entities:
            if all(key in e for key in ("x", "y", "z")):
                x, y, z = e["x"].value, e["y"].value, e["z"].value
                if (x, y, z) in self._selection:
                    cx = x >> 4
                    cz = z >> 4
                    self._chunks[(cx, cz)][3].append(e)
        for e in entities:
            if "Pos" in e:
                pos: PointCoordinates = tuple(
                    map(lambda t: t.value, e["Pos"].value))
                if pos in self._selection:
                    cx = int(pos[0]) >> 4
                    cz = int(pos[2]) >> 4
                    self._chunks[(cx, cz)][4].append(e)
Пример #23
0
 def world_name(self, value: str):
     self.root_tag["LevelName"] = nbt.TAG_String(value)
Пример #24
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
    def _get_model(self, block: Block) -> BlockMesh:
        """Find the model paths for a given block state and load them."""
        if (block.namespace, block.base_name) in self._blockstate_files:
            blockstate: dict = self._blockstate_files[(block.namespace,
                                                       block.base_name)]
            if "variants" in blockstate:
                for variant in blockstate["variants"]:
                    if variant == "":
                        try:
                            return self._load_blockstate_model(
                                block, blockstate["variants"][variant])
                        except Exception as e:
                            log.error(
                                f"Failed to load block model for {blockstate['variants'][variant]}\n{e}"
                            )
                    else:
                        properties_match = Block.properties_regex.finditer(
                            f",{variant}")
                        if all(
                                block.properties.get(
                                    match.group("name"),
                                    amulet_nbt.TAG_String(match.group(
                                        "value")),
                                ).value == match.group("value")
                                for match in properties_match):
                            try:
                                return self._load_blockstate_model(
                                    block, blockstate["variants"][variant])
                            except Exception as e:
                                log.error(
                                    f"Failed to load block model for {blockstate['variants'][variant]}\n{e}"
                                )

            elif "multipart" in blockstate:
                models = []

                for case in blockstate["multipart"]:
                    try:
                        if "when" in case:
                            if "OR" in case["when"]:
                                if not any(
                                        all(
                                            block.properties.get(prop, None) in
                                            self.parse_state_val(val) for prop,
                                            val in prop_match.items())
                                        for prop_match in case["when"]["OR"]):
                                    continue
                            elif not all(
                                    block.properties.get(prop, None) in
                                    self.parse_state_val(val)
                                    for prop, val in case["when"].items()):
                                continue

                        if "apply" in case:
                            try:
                                models.append(
                                    self._load_blockstate_model(
                                        block, case["apply"]))

                            except:
                                pass
                    except:
                        pass
Пример #26
0
 def level_name(self, value: str):
     self.root_tag["Data"]["LevelName"] = nbt.TAG_String(value)
Пример #27
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}"
            )
Пример #28
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)
Пример #29
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
Пример #30
0
    def _decode_base_entity(
        nbt: amulet_nbt.NBTFile, id_type: EntityIDType,
        coord_type: EntityCoordType
    ) -> Optional[Tuple[str, str, Union[int, float], Union[int, float], Union[
            int, float], amulet_nbt.NBTFile, ]]:
        if not (isinstance(nbt, amulet_nbt.NBTFile)
                and isinstance(nbt.value, amulet_nbt.TAG_Compound)):
            return

        if id_type == EntityIDType.namespace_str_id:
            entity_id = nbt.pop("id", amulet_nbt.TAG_String(""))
            if (not isinstance(entity_id, amulet_nbt.TAG_String)
                    or entity_id.value == "" or ":" not in entity_id.value):
                return
            namespace, base_name = entity_id.value.split(":", 1)

        elif id_type == EntityIDType.namespace_str_Id:
            entity_id = nbt.pop("Id", amulet_nbt.TAG_String(""))
            if (not isinstance(entity_id, amulet_nbt.TAG_String)
                    or entity_id.value == "" or ":" not in entity_id.value):
                return
            namespace, base_name = entity_id.value.split(":", 1)

        elif id_type == EntityIDType.str_id:
            entity_id = nbt.pop("id", amulet_nbt.TAG_String(""))
            if (not isinstance(entity_id, amulet_nbt.TAG_String)
                    or entity_id.value == ""):
                return
            namespace = ""
            base_name = entity_id.value

        elif id_type in [
                EntityIDType.namespace_str_identifier, EntityIDType.int_id
        ]:
            if "identifier" in nbt:
                entity_id = nbt.pop("identifier")
                if (not isinstance(entity_id, amulet_nbt.TAG_String)
                        or entity_id.value == ""
                        or ":" not in entity_id.value):
                    return
                namespace, base_name = entity_id.value.split(":", 1)
            elif "id" in nbt:
                entity_id = nbt.pop("id")
                if not isinstance(entity_id, amulet_nbt.TAG_Int):
                    return
                namespace = ""
                base_name = str(entity_id.value)
            else:
                return
        else:
            raise NotImplementedError(f"Entity id type {id_type}")

        if coord_type in [
                EntityCoordType.Pos_list_double,
                EntityCoordType.Pos_list_float,
                EntityCoordType.Pos_list_int,
        ]:
            if "Pos" not in nbt:
                return
            pos = nbt.pop("Pos")
            pos: amulet_nbt.TAG_List

            if (not isinstance(pos, amulet_nbt.TAG_List) or len(pos) != 3
                    or PosTypeMap.get(pos.list_data_type) != coord_type):
                return
            x, y, z = [c.value for c in pos]
        elif coord_type == EntityCoordType.Pos_array_int:
            if "Pos" not in nbt:
                return
            pos = nbt.pop("Pos")
            pos: amulet_nbt.TAG_Int_Array

            if not isinstance(pos, amulet_nbt.TAG_Int_Array) or len(pos) != 3:
                return
            x, y, z = pos
        elif coord_type == EntityCoordType.xyz_int:
            if not all(c in nbt and isinstance(nbt[c], amulet_nbt.TAG_Int)
                       for c in ("x", "y", "z")):
                return
            x, y, z = [nbt.pop(c).value for c in ("x", "y", "z")]
        else:
            raise NotImplementedError(f"Entity coord type {coord_type}")

        return namespace, base_name, x, y, z, nbt