Esempio n. 1
0
    def encode(
        self,
        chunk: "Chunk",
        palette: AnyNDArray,
        max_world_version: Tuple[str, Union[int, Tuple[int, int, int]]],
        boxes: List[SelectionBox] = None,
    ) -> List[ConstructionSection]:
        sections = []
        for box in boxes:
            cx, cz = chunk.cx, chunk.cz
            for cy in box.chunk_y_locations():
                sub_box = box.intersection(
                    SelectionBox.create_sub_chunk_box(cx, cy, cz))
                entities = [e for e in chunk.entities if e.location in sub_box]
                if cy in chunk.blocks:
                    sections.append(
                        ConstructionSection(
                            sub_box.min,
                            sub_box.shape,
                            chunk.blocks[sub_box.chunk_slice(cx, cz)],
                            list(palette),
                            entities,
                            [
                                e for e in chunk.block_entities
                                if e.location in sub_box
                            ],
                        ))
                elif entities:
                    sections.append(
                        ConstructionSection(sub_box.min, sub_box.shape, None,
                                            [], entities, []))

        return sections
Esempio n. 2
0
        def test_replace_single_block(self):
            subbox1 = SelectionBox((1, 70, 3), (5, 71, 6))
            box1 = SelectionGroup((subbox1, ))

            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 3, OVERWORLD).blockstate,
            )
            self.assertEqual(
                "universal_minecraft:granite[polished=false]",
                self.world.get_block(1, 70, 5, OVERWORLD).blockstate,
            )

            replace(
                self.world,
                OVERWORLD,
                box1,
                {
                    "original_blocks": [
                        Block.from_string_blockstate(
                            "universal_minecraft:granite[polished=false]")
                    ],
                    "replacement_blocks": [
                        Block.from_string_blockstate(
                            "universal_minecraft:stone")
                    ],
                },
            )
            self.world.create_undo_point()

            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 3, OVERWORLD).blockstate,
            )
            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 5, OVERWORLD).blockstate,
            )

            self.world.undo()

            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 3, OVERWORLD).blockstate,
            )
            self.assertEqual(
                "universal_minecraft:granite[polished=false]",
                self.world.get_block(1, 70, 5, OVERWORLD).blockstate,
            )

            self.world.redo()

            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 3, OVERWORLD).blockstate,
            )
            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 5, OVERWORLD).blockstate,
            )
Esempio n. 3
0
    def set_selection_corners(
        self,
        selection_corners: Tuple[Tuple[Tuple[int, int, int], Tuple[int, int,
                                                                   int]], ...],
    ):
        """Set the minimum and maximum points of each selection
        Note this method will not trigger the history logic.
        You may instead want the selection_corners setter method.

        :param selection_corners: The minimum and maximum points of each selection
        :return:
        """
        selections = []
        for points in selection_corners:
            if len(points) == 2 and all(len(point) == 3 for point in points):
                selections.append(
                    tuple(tuple(int(p) for p in point) for point in points))
            else:
                log.error(
                    f"selection_corners must be of the format Tuple[Tuple[Tuple[int, int, int], Tuple[int, int, int]], ...]"
                )

        self.changed = True
        self._selection_corners = tuple(selections)
        self._selection_group = SelectionGroup(
            [SelectionBox(*box) for box in self._selection_corners])
        wx.PostEvent(self._canvas(), SelectionChangeEvent())
Esempio n. 4
0
    def encode(
        self,
        chunk: "Chunk",
        palette: AnyNDArray,
        max_world_version: Tuple[str, Union[int, Tuple[int, int, int]]],
        box: SelectionBox = None,
    ) -> SchematicChunk:
        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
        blocks_merged = palette[chunk.blocks[slices]]

        return SchematicChunk(
            box,
            blocks_merged[:, :, :, 0].astype(numpy.uint16),
            blocks_merged[:, :, :, 1].astype(numpy.uint8),
            block_entities,
            entities,
        )
Esempio n. 5
0
        def test_replace_single_block(self):
            subbox1 = SelectionBox((1, 70, 3), (5, 71, 6))
            box1 = SelectionGroup((subbox1,))

            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 3, "overworld").blockstate,
            )
            self.assertEqual(
                'universal_minecraft:granite[polished="false"]',
                self.world.get_block(1, 70, 5, "overworld").blockstate,
            )

            self.world.run_operation(
                replace,
                "overworld",
                box1,
                {
                    "original_blocks": [
                        blockstate_to_block(
                            "universal_minecraft:granite[polished=false]"
                        )
                    ],
                    "replacement_blocks": [
                        blockstate_to_block("universal_minecraft:stone")
                    ],
                },
            )

            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 3, "overworld").blockstate,
            )
            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 5, "overworld").blockstate,
            )

            self.world.undo()

            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 3, "overworld").blockstate,
            )
            self.assertEqual(
                'universal_minecraft:granite[polished="false"]',
                self.world.get_block(1, 70, 5, "overworld").blockstate,
            )

            self.world.redo()

            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 3, "overworld").blockstate,
            )
            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 5, "overworld").blockstate,
            )
    def _sub_chunks(
        self, blocks: Blocks
    ) -> List[Tuple[numpy.ndarray, Tuple[int, int, int]]]:
        """Create sub-chunk arrays that extend into the neighbour sub-chunks by one block.

        :param blocks: The Blocks array for the chunk.
        :return: A list of tuples containing the larger block array and the location of the sub-chunk
        """
        sub_chunks = []
        neighbour_chunks = {}
        for dx, dz in ((-1, 0), (1, 0), (0, -1), (0, 1)):
            try:
                neighbour_chunks[(dx, dz)] = self._level.get_chunk(
                    self.cx + dx, self.cz + dz, self.dimension
                ).blocks
            except ChunkLoadError:
                continue

        for cy in blocks.sub_chunks:
            sub_chunk = blocks.get_sub_chunk(cy)
            larger_blocks = numpy.zeros(
                sub_chunk.shape + numpy.array((2, 2, 2)), sub_chunk.dtype
            )
            sub_chunk_box = SelectionBox.create_sub_chunk_box(self.cx, cy, self.cz)
            if self._level.selection_bounds.intersects(sub_chunk_box):
                boxes = self._level.selection_bounds.intersection(sub_chunk_box)
                for box in boxes.selection_boxes:
                    larger_blocks[1:-1, 1:-1, 1:-1][
                        box.sub_chunk_slice(self.cx, cy, self.cz)
                    ] = sub_chunk[box.sub_chunk_slice(self.cx, cy, self.cz)]
                for chunk_offset, neighbour_blocks in neighbour_chunks.items():
                    if cy not in neighbour_blocks:
                        continue
                    if chunk_offset == (-1, 0):
                        larger_blocks[0, 1:-1, 1:-1] = neighbour_blocks.get_sub_chunk(
                            cy
                        )[-1, :, :]
                    elif chunk_offset == (1, 0):
                        larger_blocks[-1, 1:-1, 1:-1] = neighbour_blocks.get_sub_chunk(
                            cy
                        )[0, :, :]
                    elif chunk_offset == (0, -1):
                        larger_blocks[1:-1, 1:-1, 0] = neighbour_blocks.get_sub_chunk(
                            cy
                        )[:, :, -1]
                    elif chunk_offset == (0, 1):
                        larger_blocks[1:-1, 1:-1, -1] = neighbour_blocks.get_sub_chunk(
                            cy
                        )[:, :, 0]
                if cy - 1 in blocks:
                    larger_blocks[1:-1, 0, 1:-1] = blocks.get_sub_chunk(cy - 1)[
                        :, -1, :
                    ]
                if cy + 1 in blocks:
                    larger_blocks[1:-1, -1, 1:-1] = blocks.get_sub_chunk(cy + 1)[
                        :, 0, :
                    ]
                sub_chunks.append((larger_blocks, (0, cy * 16, 0)))
        return sub_chunks
Esempio n. 7
0
    def test_single_block_box(self):
        box_1 = SelectionBox((0, 0, 0), (1, 1, 2))

        self.assertEqual((1, 1, 2), box_1.shape)
        self.assertEqual(2, len([x for x in box_1]))

        self.assertIn((0, 0, 0), box_1)
        self.assertNotIn((1, 1, 2), box_1)
Esempio n. 8
0
 def _chunk_box(self,
                cx: int,
                cz: int,
                sub_chunk_size: Optional[int] = None):
     """Get a SelectionBox containing the whole of a given chunk"""
     if sub_chunk_size is None:
         sub_chunk_size = self.sub_chunk_size
     return SelectionBox.create_chunk_box(cx, cz, sub_chunk_size)
Esempio n. 9
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,
        )
Esempio n. 10
0
    def _sub_chunks(
        self, blocks: Blocks
    ) -> List[Tuple[numpy.ndarray, numpy.ndarray, Tuple[int, int, int]]]:
        sub_chunks = []
        neighbour_chunks = {}
        for dx, dz in ((-1, 0), (1, 0), (0, -1), (0, 1)):
            try:
                neighbour_chunks[(dx, dz)] = self._level.get_chunk(
                    self.cx + dx, self.cz + dz, self.dimension).blocks
            except ChunkLoadError:
                continue

        for cy in blocks.sub_chunks:
            sub_chunk = blocks.get_sub_chunk(cy)
            larger_blocks = numpy.zeros(
                sub_chunk.shape + numpy.array((2, 2, 2)), sub_chunk.dtype)
            sub_chunk_box = SelectionBox.create_sub_chunk_box(
                self.cx, cy, self.cz)
            if self._level.selection_bounds.intersects(sub_chunk_box):
                boxes = self._level.selection_bounds.intersection(
                    sub_chunk_box)
                for box in boxes.selection_boxes:
                    larger_blocks[1:-1, 1:-1, 1:-1][box.sub_chunk_slice(
                        self.cx, cy, self.cz)] = sub_chunk[box.sub_chunk_slice(
                            self.cx, cy, self.cz)]
                for chunk_offset, neighbour_blocks in neighbour_chunks.items():
                    if cy not in neighbour_blocks:
                        continue
                    if chunk_offset == (-1, 0):
                        larger_blocks[0, 1:-1,
                                      1:-1] = neighbour_blocks.get_sub_chunk(
                                          cy)[-1, :, :]
                    elif chunk_offset == (1, 0):
                        larger_blocks[-1, 1:-1,
                                      1:-1] = neighbour_blocks.get_sub_chunk(
                                          cy)[0, :, :]
                    elif chunk_offset == (0, -1):
                        larger_blocks[1:-1, 1:-1,
                                      0] = neighbour_blocks.get_sub_chunk(
                                          cy)[:, :, -1]
                    elif chunk_offset == (0, 1):
                        larger_blocks[1:-1, 1:-1,
                                      -1] = neighbour_blocks.get_sub_chunk(
                                          cy)[:, :, 0]
                if cy - 1 in blocks:
                    larger_blocks[1:-1, 0,
                                  1:-1] = blocks.get_sub_chunk(cy - 1)[:,
                                                                       -1, :]
                if cy + 1 in blocks:
                    larger_blocks[1:-1, -1,
                                  1:-1] = blocks.get_sub_chunk(cy + 1)[:, 0, :]
                unique_blocks = numpy.unique(larger_blocks)
                sub_chunks.append(
                    (larger_blocks, unique_blocks, (0, cy * 16, 0)))
        return sub_chunks
Esempio n. 11
0
 def _encode(
     self, chunk: Chunk, chunk_palette: AnyNDArray, interface: SchematicInterface,
 ):
     return interface.encode(
         chunk,
         chunk_palette,
         self.max_world_version,
         SelectionBox.create_chunk_box(chunk.cx, chunk.cz).intersection(
             self._selection
         ),
     )
Esempio n. 12
0
def load_level_from_world(level_folder, coord_box):
    # World is a amulet data structure
    world = load_level(level_folder)
    coord_start, coord_end = coord_box
    box = SelectionBox(coord_start, coord_end)
    # Level is a np array of Blocks
    coord_offset = np.array(box.min)
    print("Offset: {}".format(coord_offset))
    level = level_from_world(world, box)
    signs = get_signs(world, box, coord_offset)
    return level, signs
Esempio n. 13
0
    def test_sorted_iterator(self):
        box_1 = SelectionBox((0, 0, 0), (4, 4, 4))
        box_2 = SelectionBox((7, 7, 7), (10, 10, 10))
        box_3 = SelectionBox((15, 15, 15), (20, 20, 20))

        selection_1 = SelectionGroup(
            (
                box_1,
                box_2,
                box_3,
            )
        )
        selection_2 = SelectionGroup(
            (
                box_1,
                box_3,
                box_2,
            )
        )

        self.assertEqual(selection_1, selection_2)
Esempio n. 14
0
 def __init__(self, path: PathOrBuffer, mode: str = "r"):
     super().__init__(path)
     assert mode in ("r", "w"), 'Mode must be either "r" or "w".'
     self._mode = mode
     if isinstance(path, str):
         assert path.endswith(".schematic"), 'Path must end with ".schematic"'
         if mode == "r":
             assert os.path.isfile(path), "File specified does not exist."
     self._data: Optional[Union[SchematicWriter, SchematicReader]] = None
     self._open = False
     self._platform = "java"
     self._version = (1, 12, 2)
     self._selection: SelectionBox = SelectionBox((0, 0, 0), (0, 0, 0))
Esempio n. 15
0
 def test_subtract(self):
     box_1 = SelectionGroup(
         SelectionBox(
             (0, 0, 0),
             (32, 32, 32),
         )
     )
     box_2 = SelectionGroup(
         SelectionBox(
             (0, 0, 0),
             (16, 16, 16),
         )
     )
     box_3 = box_1.subtract(box_2)
     box_4 = SelectionGroup(
         (
             SelectionBox((0, 16, 0), (32, 32, 32)),
             SelectionBox((0, 0, 16), (32, 16, 32)),
             SelectionBox((16, 0, 0), (32, 16, 16)),
         )
     )
     self.assertEqual(box_3, box_4)
Esempio n. 16
0
        def test_fill_operation(self):
            subbox_1 = SelectionBox((1, 70, 3), (5, 71, 5))
            selection = SelectionGroup((subbox_1, ))

            # Start sanity check
            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 3, OVERWORLD).blockstate,
            )
            self.assertEqual(
                "universal_minecraft:granite[polished=false]",
                self.world.get_block(1, 70, 5, OVERWORLD).blockstate,
            )
            # End sanity check

            generator_unpacker(
                fill(
                    self.world,
                    OVERWORLD,
                    selection,
                    Block.from_string_blockstate("universal_minecraft:stone"),
                ))
            self.world.create_undo_point()

            for x, y, z in selection.blocks:
                self.assertEqual(
                    "universal_minecraft:stone",
                    self.world.get_block(x, y, z, OVERWORLD).blockstate,
                    f"Failed at coordinate ({x},{y},{z})",
                )

            self.world.undo()

            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 3, OVERWORLD).blockstate,
            )

            self.assertEqual(
                "universal_minecraft:granite[polished=false]",
                self.world.get_block(1, 70, 5, OVERWORLD).blockstate,
            )

            self.world.redo()

            for x, y, z in selection.blocks:
                self.assertEqual(
                    "universal_minecraft:stone",
                    self.world.get_block(x, y, z, OVERWORLD).blockstate,
                    f"Failed at coordinate ({x},{y},{z})",
                )
Esempio n. 17
0
    def open(self):
        """Open the database for reading and writing"""
        if self._open:
            return
        if self._mode == "r":
            assert (
                isinstance(self.path_or_buffer, str)
                and os.path.isfile(self.path_or_buffer)
            ) or hasattr(self.path_or_buffer, "read"), "File specified does not exist."
            self._data = ConstructionReader(self.path_or_buffer)
            self._platform = self._data.source_edition
            self._version = self._data.source_version
            self._selection = SelectionGroup(
                [
                    SelectionBox((minx, miny, minz), (maxx, maxy, maxz))
                    for minx, miny, minz, maxx, maxy, maxz in self._data.selection
                ]
            )

            self._chunk_to_section = {}
            for index, (x, _, z, _, _, _, _, _) in enumerate(self._data.sections):
                cx = x >> 4
                cz = z >> 4
                self._chunk_to_section.setdefault((cx, cz), []).append(index)
        else:
            self._data = ConstructionWriter(
                self.path_or_buffer,
                self.platform,
                self.version,
                [box.bounds for box in self.selection.selection_boxes],
            )
            self._chunk_to_box = {}
            for box in self.selection.selection_boxes:
                for cx, cz in box.chunk_locations():
                    self._chunk_to_box.setdefault((cx, cz), []).append(
                        box.intersection(SelectionBox.create_chunk_box(cx, cz))
                    )
        self._open = True
Esempio n. 18
0
        def test_get_blocks(self):
            selection_box = SelectionBox((0, 0, 0), (10, 10, 10))
            for selection in [SelectionGroup([selection_box]), selection_box]:
                chunk, box = next(self.world.get_chunk_boxes(selection, "overworld"))
                self.assertIsInstance(chunk, Chunk)
                self.assertIsInstance(box, SelectionBox)

                chunk, slices, _ = next(
                    self.world.get_chunk_slices(selection, "overworld")
                )
                self.assertIsInstance(chunk, Chunk)
                self.assertIsInstance(slices, tuple)
                for s in slices:
                    self.assertIsInstance(s, slice)
Esempio n. 19
0
        def test_delete_chunk(self):
            subbox1 = SelectionBox((1, 1, 1), (5, 5, 5))
            box1 = SelectionGroup((subbox1, ))

            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 3, OVERWORLD).blockstate,
            )
            self.assertEqual(
                "universal_minecraft:granite[polished=false]",
                self.world.get_block(1, 70, 5, OVERWORLD).blockstate,
            )

            generator_unpacker(delete_chunk(self.world, OVERWORLD, box1))
            self.world.create_undo_point()

            with self.assertRaises(ChunkDoesNotExist):
                _ = self.world.get_block(1, 70, 3, OVERWORLD).blockstate

            self.assertEqual(
                0,
                len([
                    x for x in self.world.get_chunk_slice_box(
                        OVERWORLD, subbox1)
                ]),
            )

            self.world.undo()

            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 3, OVERWORLD).blockstate,
            )
            self.assertEqual(
                "universal_minecraft:granite[polished=false]",
                self.world.get_block(1, 70, 5, OVERWORLD).blockstate,
            )

            self.world.redo()

            with self.assertRaises(ChunkDoesNotExist):
                _ = self.world.get_block(1, 70, 3, OVERWORLD).blockstate

            self.assertEqual(
                0,
                len([
                    x for x in self.world.get_chunk_slice_box(
                        OVERWORLD, subbox1)
                ]),
            )
Esempio n. 20
0
 def _encode(
     self,
     interface: MCStructureInterface,
     chunk: Chunk,
     dimension: Dimension,
     chunk_palette: AnyNDArray,
 ):
     return interface.encode(
         chunk,
         chunk_palette,
         self.max_world_version,
         SelectionBox.create_chunk_box(chunk.cx, chunk.cz).intersection(
             self._bounds[dimension].to_box()),
     )
Esempio n. 21
0
        def test_delete_chunk(self):
            subbox1 = SelectionBox((1, 1, 1), (5, 5, 5))
            box1 = SelectionGroup((subbox1, ))

            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 3, "overworld").blockstate,
            )
            self.assertEqual(
                'universal_minecraft:granite[polished="false"]',
                self.world.get_block(1, 70, 5, "overworld").blockstate,
            )

            self.world.run_operation(delete_chunk, "overworld", box1)

            with self.assertRaises(ChunkDoesNotExist):
                _ = self.world.get_block(1, 70, 3, "overworld").blockstate

            self.assertEqual(
                0,
                len([
                    x for x in self.world.get_chunk_slice_box(
                        "overworld", subbox1)
                ]),
            )

            self.world.undo()

            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 3, "overworld").blockstate,
            )
            self.assertEqual(
                'universal_minecraft:granite[polished="false"]',
                self.world.get_block(1, 70, 5, "overworld").blockstate,
            )

            self.world.redo()

            with self.assertRaises(ChunkDoesNotExist):
                _ = self.world.get_block(1, 70, 3, "overworld").blockstate

            self.assertEqual(
                0,
                len([
                    x for x in self.world.get_chunk_slice_box(
                        "overworld", subbox1)
                ]),
            )
Esempio n. 22
0
 def _on_input_release(self, evt: InputReleaseEvent):
     if evt.action_id == ACT_BOX_CLICK:
         if self._editing and time.time() - self._press_time > 0.1:
             self._editing = False
             box = SelectionBox(*self._get_editing_selection())
             if SelectionGroup(box).is_subset(
                     self._selection.selection_group):
                 # subtract
                 self._selection.selection_group = (
                     self._selection.selection_group.subtract(box))
             else:
                 self._selection.selection_group = (
                     self._selection.selection_group.union(box))
             self._create_undo()
     evt.Skip()
Esempio n. 23
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
        )
Esempio n. 24
0
        def test_fill_operation(self):
            subbox_1 = SelectionBox((1, 70, 3), (5, 71, 5))
            box = SelectionGroup((subbox_1,))

            # Start sanity check
            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 3, "overworld").blockstate,
            )
            self.assertEqual(
                'universal_minecraft:granite[polished="false"]',
                self.world.get_block(1, 70, 5, "overworld").blockstate,
            )
            # End sanity check

            self.world.run_operation(
                fill, "overworld", box, blockstate_to_block("universal_minecraft:stone")
            )

            for x, y, z in box:
                self.assertEqual(
                    "universal_minecraft:stone",
                    self.world.get_block(x, y, z, "overworld").blockstate,
                    f"Failed at coordinate ({x},{y},{z})",
                )

            self.world.undo()

            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 3, "overworld").blockstate,
            )

            self.assertEqual(
                'universal_minecraft:granite[polished="false"]',
                self.world.get_block(1, 70, 5, "overworld").blockstate,
            )

            self.world.redo()

            for x, y, z in box:
                self.assertEqual(
                    "universal_minecraft:stone",
                    self.world.get_block(x, y, z, "overworld").blockstate,
                    f"Failed at coordinate ({x},{y},{z})",
                )
Esempio n. 25
0
    def encode(
        self,
        chunk: "Chunk",
        palette: AnyNDArray,
        max_world_version: VersionIdentifierType,
        box: SelectionBox,
    ) -> SchematicChunk:
        """
        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
        blocks_merged = palette[chunk.blocks[slices]]

        return SchematicChunk(
            box,
            blocks_merged[:, :, :, 0].astype(numpy.uint16),
            blocks_merged[:, :, :, 1].astype(numpy.uint8),
            block_entities,
            entities,
        )
Esempio n. 26
0
    def encode(
        self,
        chunk: "Chunk",
        palette: AnyNDArray,
        max_world_version: VersionIdentifierType,
        boxes: List[SelectionBox],
    ) -> List[ConstructionSection]:
        """
        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 boxes: The volume(s) of the chunk to pack.
        :return: Raw data to be stored by the Format.
        """
        sections = []
        for box in boxes:
            cx, cz = chunk.cx, chunk.cz
            for cy in box.chunk_y_locations():
                sub_box = box.intersection(
                    SelectionBox.create_sub_chunk_box(cx, cy, cz))
                entities = [e for e in chunk.entities if e.location in sub_box]
                if cy in chunk.blocks:
                    sections.append(
                        ConstructionSection(
                            sub_box.min,
                            sub_box.shape,
                            numpy.asarray(chunk.blocks[sub_box.chunk_slice(
                                cx, cz)]),
                            list(palette),
                            entities,
                            [
                                e for e in chunk.block_entities
                                if e.location in sub_box
                            ],
                        ))
                elif entities:
                    sections.append(
                        ConstructionSection(sub_box.min, sub_box.shape, None,
                                            [], entities, []))

        return sections
Esempio n. 27
0
    def get_coord_box(
        self,
        dimension: Dimension,
        selection: Union[SelectionGroup, SelectionBox, None] = None,
        yield_missing_chunks=False,
    ) -> Generator[Tuple[ChunkCoordinates, SelectionBox], None, None]:
        """Given a selection will yield chunk coordinates and `SelectionBox`es into that chunk
        If not given a selection will use the bounds of the object.

        :param selection: SelectionGroup or SelectionBox into the level
        :param dimension: The dimension to take effect in
        :param yield_missing_chunks: If a chunk does not exist an empty one will be created (defaults to false). Use this with care.
        """
        if isinstance(selection, SelectionBox):
            selection = SelectionGroup(selection)
        elif selection is None:
            selection = self.selection_bounds
        elif not isinstance(selection, SelectionGroup):
            raise TypeError(
                f"Expected a SelectionGroup but got {type(selection)}")

        selection: SelectionGroup
        if yield_missing_chunks or selection.footprint_area < 1_000_000:
            if yield_missing_chunks:
                for coord, box in selection.chunk_boxes(self.sub_chunk_size):
                    yield coord, box
            else:
                for (cx,
                     cz), box in selection.chunk_boxes(self.sub_chunk_size):
                    if self.has_chunk(cx, cz, dimension):
                        yield (cx, cz), box

        else:
            # if the selection gets very large iterating over the whole selection and accessing chunks can get slow
            # instead we are going to iterate over the chunks and get the intersection of the selection
            for cx, cz in self.all_chunk_coords(dimension):
                box = SelectionGroup(
                    SelectionBox.create_chunk_box(cx, cz, self.sub_chunk_size))

                if selection.intersects(box):
                    chunk_selection = selection.intersection(box)
                    for sub_box in chunk_selection.selection_boxes:
                        yield (cx, cz), sub_box
Esempio n. 28
0
        def test_clone_operation(self):
            subbx1 = SelectionBox((1, 70, 3), (2, 71, 4))
            src_box = SelectionGroup((subbx1, ))

            target = {"x": 1, "y": 70, "z": 5}

            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 3, OVERWORLD).blockstate,
            )  # Sanity check
            self.assertEqual(
                "universal_minecraft:granite[polished=false]",
                self.world.get_block(1, 70, 5, OVERWORLD).blockstate,
            )

            clone(self.world, OVERWORLD, src_box, target)
            self.world.create_undo_point()

            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 5, OVERWORLD).blockstate,
            )

            self.world.undo()

            self.assertEqual(
                "universal_minecraft:granite[polished=false]",
                self.world.get_block(1, 70, 5, OVERWORLD).blockstate,
            )

            self.world.redo()

            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 5, OVERWORLD).blockstate,
            )

            self.world.undo()

            self.assertEqual(
                "universal_minecraft:granite[polished=false]",
                self.world.get_block(1, 70, 5, OVERWORLD).blockstate,
            )
Esempio n. 29
0
        def test_clone_operation(self):
            subbx1 = SelectionBox((1, 70, 3), (2, 71, 4))
            src_box = SelectionGroup((subbx1,))

            target = {"x": 1, "y": 70, "z": 5}

            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 3, "overworld").blockstate,
            )  # Sanity check
            self.assertEqual(
                'universal_minecraft:granite[polished="false"]',
                self.world.get_block(1, 70, 5, "overworld").blockstate,
            )

            self.world.run_operation(clone, "overworld", src_box, target)

            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 5, "overworld").blockstate,
            )

            self.world.undo()

            self.assertEqual(
                'universal_minecraft:granite[polished="false"]',
                self.world.get_block(1, 70, 5, "overworld").blockstate,
            )

            self.world.redo()

            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 5, "overworld").blockstate,
            )

            self.world.undo()

            self.assertEqual(
                'universal_minecraft:granite[polished="false"]',
                self.world.get_block(1, 70, 5, "overworld").blockstate,
            )
Esempio n. 30
0
 def _chunkify_selection(self):
     selections = []
     for box in self.canvas.selection.selection_group.selection_boxes:
         min_point = (
             numpy.floor(box.min_array / self.canvas.world.sub_chunk_size) *
             self.canvas.world.sub_chunk_size)
         max_point = (
             numpy.ceil(box.max_array / self.canvas.world.sub_chunk_size) *
             self.canvas.world.sub_chunk_size)
         bounds = self.canvas.world.bounds(self.canvas.dimension)
         min_point[1] = bounds.min[1]
         max_point[1] = bounds.max[1]
         selections.append(SelectionBox(min_point, max_point))
     selection_group = SelectionGroup(selections)
     if selection_group != self.canvas.selection.selection_group:
         # if the above code modified the selection
         self.canvas.selection.selection_group = selection_group
         # this will indirectly update the renderer by updating the global selection
     elif selection_group != self._selection.selection_group:
         # if the above code did not change the selection but it does not match the renderer
         self._selection.selection_group = selection_group