示例#1
0
    def test_intersects(self):
        box_1 = SelectionBox((0, 0, 0), (5, 5, 5))
        box_2 = SelectionBox((4, 4, 4), (10, 10, 10))
        box_3 = SelectionBox((5, 5, 5), (10, 10, 10))
        box_4 = SelectionBox((1, 20, 1), (4, 25, 4))

        self.assertTrue(box_1.intersects(box_2))
        self.assertTrue(box_2.intersects(box_1))
        self.assertFalse(box_1.intersects(box_3))
        self.assertFalse(box_3.intersects(box_1))
        self.assertFalse(box_1.intersects(box_4))
        self.assertFalse(box_4.intersects(box_1))
示例#2
0
    def test_is_rectangular(self):
        box_1 = SelectionBox((0, 0, 0), (5, 5, 5))
        box_2 = SelectionBox((0, 5, 0), (5, 10, 5))
        box_3 = SelectionBox((0, 0, 5), (5, 5, 10))
        box_4 = SelectionBox((0, 5, 5), (5, 10, 10))

        self.assertTrue(SelectionGroup(box_1).is_rectangular)
        self.assertTrue(SelectionGroup((box_1, box_2)).is_rectangular)
        self.assertFalse(SelectionGroup((box_1, box_2, box_3)).is_rectangular)
        self.assertTrue(SelectionGroup((box_1, box_2, box_3, box_4)).is_rectangular)
        self.assertTrue(
            SelectionGroup((box_1, box_2, box_3, box_4, box_2)).is_rectangular
        )
示例#3
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,
            )
示例#4
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())
示例#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,
            )
示例#6
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)
示例#7
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
示例#8
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)
示例#9
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)
 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))
示例#11
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})",
                )
示例#12
0
    def create(self, args: List[str]):
        if len(args) < 4:
            print('Usage: box.create "name" <x1,y1,z1> <x2,y2,z2> ....')

        box_name = args[1]

        if len(args[2:]) % 2 != 0:
            self.error("You must have an even amount of coordinate pairs")
            return

        if len(args[2:]) == 2:
            p1 = parse_coordinates(args[2])
            p2 = parse_coordinates(args[3])

            selection_box = SelectionBox((SubBox(p1, p2), ))
        else:
            selection_box = SelectionBox()
            for start in range(0, len(args[2:]), 2):
                p1 = parse_coordinates(args[2 + start])
                p2 = parse_coordinates(args[3 + start])
                selection_box.add_box(SubBox(p1, p2))

        self.handler.shared_data["boxes"][box_name] = selection_box
示例#13
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)
                ]),
            )
示例#14
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)
示例#15
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)
                ]),
            )
示例#16
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()
示例#17
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})",
                )
示例#18
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,
            )
示例#19
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,
            )
示例#20
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
示例#21
0
        def test_get_entities(
            self,
        ):  # TODO: Make a more complete test once we figure out what get_entities() returns
            box1 = SelectionGroup((SelectionBox((0, 0, 0), (17, 20, 17)), ))

            test_entity = {
                "id": "universal_minecraft:cow",
                "CustomName": "TestName",
                "Pos": [1.0, 4.0, 1.0],
            }

            entity_iter = self.world.get_entities_in_box(box1)
            for chunk_coords, entities in entity_iter:
                self.assertEqual(0, len(entities))

            self.world.add_entities([test_entity])

            entity_iter = self.world.get_entities_in_box(box1)
            for chunk_coords, entities in entity_iter:
                if chunk_coords == (0, 0):
                    self.assertEqual(1, len(entities))
                    test_entity["Pos"] = entities[0]["Pos"] = [
                        17.0, 20.0, 17.0
                    ]
                else:
                    self.assertEqual(0, len(entities))

            entity_iter = self.world.get_entities_in_box(box1)
            for chunk_coords, entities in entity_iter:
                if chunk_coords == (1, 1):
                    self.assertEqual(1, len(entities))
                else:
                    self.assertEqual(0, len(entities))

            self.world.delete_entities([test_entity])

            entity_iter = self.world.get_entities_in_box(box1)
            for chunk_coords, entities in entity_iter:
                self.assertEqual(0, len(entities))
示例#22
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
示例#23
0
    def _shallow_load(self):
        if os.path.isfile(self.path):
            with open(self.path, "rb") as f:
                magic_num_1 = f.read(magic_num_len)
                if magic_num_1 == magic_num:
                    format_version = struct.unpack(">B", f.read(1))[0]
                    if format_version == 0:
                        f.seek(-magic_num_len, os.SEEK_END)
                        magic_num_2 = f.read(magic_num_len)
                        if magic_num_2 == magic_num:
                            f.seek(-magic_num_len - INT_STRUCT.size,
                                   os.SEEK_END)
                            metadata_end = f.tell()
                            metadata_start = INT_STRUCT.unpack(
                                f.read(INT_STRUCT.size))[0]
                            f.seek(metadata_start)

                            metadata = amulet_nbt.load(
                                f.read(metadata_end - metadata_start),
                                compressed=True,
                            )

                            self._platform = metadata["export_version"][
                                "edition"].value
                            self._version = tuple(
                                map(
                                    lambda v: v.value,
                                    metadata["export_version"]["version"],
                                ))

                            selection_boxes = (
                                metadata["selection_boxes"].value.reshape(
                                    -1, 6).tolist())
                            self._bounds[self.dimensions[0]] = SelectionGroup([
                                SelectionBox((minx, miny, minz),
                                             (maxx, maxy, maxz)) for minx,
                                miny, minz, maxx, maxy, maxz in selection_boxes
                            ])
示例#24
0
 def selection_box(self) -> SelectionBox:
     return SelectionBox(self.point1, self.point2)
示例#25
0
    def _test_create(
        self,
        cls: Type[FormatWrapper],
        level_name: str,
        platform: str,
        version: VersionNumberAny,
    ):
        path = clean_temp_world(level_name)

        # create, initialise and save the level
        level = cls(path)
        if level.requires_selection:
            level.create_and_open(
                platform,
                version,
                SelectionGroup([SelectionBox((0, 0, 0), (1, 1, 1))]),
                overwrite=True,
            )
        else:
            level.create_and_open(platform, version, overwrite=True)

        self.assertTrue(level.is_open,
                        "The level was not opened by create_and_open()")
        self.assertTrue(level.has_lock,
                        "The lock was not acquired by create_and_open()")

        platform_ = level.platform
        version_ = level.version
        dimension_selections = {
            dim: level.bounds(dim)
            for dim in level.dimensions
        }

        level.save()
        level.close()

        self.assertFalse(level.is_open, "The level was not closed by close()")
        self.assertFalse(level.has_lock, "The lock was not lost by close()")

        self.assertTrue(os.path.exists(level.path))

        # reopen the level
        level2 = load_format(path)
        # check that the class is the same
        self.assertIs(level.__class__, level2.__class__)
        level2.open()

        self.assertTrue(level2.is_open, "The level was not opened by open()")
        self.assertTrue(level2.has_lock, "The lock was not acquired by open()")

        # check that the platform and version are the same
        self.assertEqual(level2.platform, platform_)
        self.assertEqual(level2.version, version_)
        self.assertEqual(set(level2.dimensions), set(dimension_selections))
        for dim, selection in dimension_selections.items():
            self.assertEqual(level2.bounds(dim), selection)
        level2.close()

        self.assertFalse(level2.is_open, "The level was not closed by close()")
        self.assertFalse(level2.has_lock, "The lock was not lost by close()")

        self.assertTrue(os.path.exists(level.path))

        level = cls(path)
        with self.assertRaises(ObjectWriteError):
            if level.requires_selection:
                level.create_and_open(
                    platform,
                    version,
                    SelectionGroup([SelectionBox((0, 0, 0), (1, 1, 1))]),
                )
            else:
                level.create_and_open(platform, version)

        clean_path(path)
示例#26
0
 def create_selection_group(self) -> SelectionGroup:
     return SelectionGroup([
         SelectionBox(box.min, box.max) for box in self._boxes
         if box.is_static
     ])
示例#27
0
    def get_moved_coord_slice_box(
        self,
        dimension: Dimension,
        destination_origin: BlockCoordinates,
        selection: Optional[Union[SelectionGroup, SelectionBox]] = None,
        destination_sub_chunk_shape: Optional[int] = None,
        yield_missing_chunks: bool = False,
    ) -> Generator[Tuple[ChunkCoordinates, Tuple[
            slice, slice, slice], SelectionBox, ChunkCoordinates, Tuple[
                slice, slice, slice], SelectionBox, ], None, None, ]:
        """
        Iterate over a selection and return slices into the source object and destination object
        given the origin of the destination. When copying a selection to a new area the slices will
        only be equal if the offset is a multiple of the chunk size. This will rarely be the case
        so the slices need to be split up into parts that intersect a chunk in the source and destination.

        :param dimension: The dimension to iterate over.
        :param destination_origin: The location where the minimum point of the selection will end up
        :param selection: An optional selection. The overlap of this and the dimensions bounds will be used
        :param destination_sub_chunk_shape: the chunk shape of the destination object (defaults to self.sub_chunk_size)
        :param yield_missing_chunks: Generate empty chunks if the chunk does not exist.
        :return:
        """
        if destination_sub_chunk_shape is None:
            destination_sub_chunk_shape = self.sub_chunk_size

        if selection is None:
            selection = self.bounds(dimension)
        else:
            selection = self.bounds(dimension).intersection(selection)
        # the offset from self.selection to the destination location
        offset = numpy.subtract(destination_origin,
                                self.bounds(dimension).min,
                                dtype=int)
        for (src_cx, src_cz), box in self.get_coord_box(
                dimension, selection,
                yield_missing_chunks=yield_missing_chunks):
            dst_full_box = SelectionBox(offset + box.min, offset + box.max)

            first_chunk = block_coords_to_chunk_coords(
                dst_full_box.min_x,
                dst_full_box.min_z,
                sub_chunk_size=destination_sub_chunk_shape,
            )
            last_chunk = block_coords_to_chunk_coords(
                dst_full_box.max_x - 1,
                dst_full_box.max_z - 1,
                sub_chunk_size=destination_sub_chunk_shape,
            )
            for dst_cx, dst_cz in itertools.product(
                    range(first_chunk[0], last_chunk[0] + 1),
                    range(first_chunk[1], last_chunk[1] + 1),
            ):
                chunk_box = self._chunk_box(dst_cx, dst_cz,
                                            destination_sub_chunk_shape)
                dst_box = chunk_box.intersection(dst_full_box)
                src_box = SelectionBox(-offset + dst_box.min,
                                       -offset + dst_box.max)
                src_slices = src_box.chunk_slice(src_cx, src_cz,
                                                 self.sub_chunk_size)
                dst_slices = dst_box.chunk_slice(dst_cx, dst_cz,
                                                 self.sub_chunk_size)
                yield (src_cx, src_cz), src_slices, src_box, (
                    dst_cx,
                    dst_cz,
                ), dst_slices, dst_box
示例#28
0
    def open_from(self, f: BinaryIO):
        f = BytesIO(f.read())
        magic_num_1 = f.read(8)
        assert magic_num_1 == magic_num, f"This file is not a construction file."
        self._format_version = struct.unpack(">B", f.read(1))[0]
        if self._format_version == 0:
            f.seek(-magic_num_len, os.SEEK_END)
            magic_num_2 = f.read(8)
            assert (
                magic_num_2 == magic_num
            ), "It looks like this file is corrupt. It probably wasn't saved properly"

            f.seek(-magic_num_len - INT_STRUCT.size, os.SEEK_END)
            metadata_end = f.tell()
            metadata_start = INT_STRUCT.unpack(f.read(INT_STRUCT.size))[0]
            f.seek(metadata_start)

            metadata = amulet_nbt.load(
                f.read(metadata_end - metadata_start),
                compressed=True,
            )

            try:
                self._platform = metadata["export_version"]["edition"].value
                self._version = tuple(
                    map(lambda v: v.value, metadata["export_version"]["version"])
                )
            except KeyError as e:
                raise KeyError(f'Missing export version identifying key "{e.args[0]}"')

            self._section_version = metadata["section_version"].value

            palette = unpack_palette(metadata["block_palette"])

            selection_boxes = metadata["selection_boxes"].value.reshape(-1, 6).tolist()

            self._selection = SelectionGroup(
                [
                    SelectionBox((minx, miny, minz), (maxx, maxy, maxz))
                    for minx, miny, minz, maxx, maxy, maxz in selection_boxes
                ]
            )

            self._populate_chunk_to_box()

            section_index_table = (
                metadata["section_index_table"].value.view(SECTION_ENTRY_TYPE).tolist()
            )

            if self._section_version == 0:
                for (
                    start_x,
                    start_y,
                    start_z,
                    shape_x,
                    shape_y,
                    shape_z,
                    position,
                    length,
                ) in section_index_table:
                    f.seek(position)
                    nbt_obj = amulet_nbt.load(f.read(length))
                    if nbt_obj["blocks_array_type"].value == -1:
                        blocks = None
                        block_entities = None
                    else:
                        blocks = numpy.reshape(
                            nbt_obj["blocks"].value, (shape_x, shape_y, shape_z)
                        )
                        block_entities = parse_block_entities(nbt_obj["block_entities"])

                    start = numpy.array([start_x, start_y, start_z])
                    chunk_index: numpy.ndarray = start // self.sub_chunk_size
                    shape = numpy.array([shape_x, shape_y, shape_z])
                    if numpy.any(shape <= 0):
                        continue  # skip sections with zero size
                    if numpy.any(
                        start + shape > (chunk_index + 1) * self.sub_chunk_size
                    ):
                        log.error(
                            f"section in construction file did not fit in one sub-chunk. Start: {start}, Shape: {shape}"
                        )
                    cx, cy, cz = chunk_index.tolist()
                    self._chunk_to_section.setdefault((cx, cz), []).append(
                        ConstructionSection(
                            (start_x, start_y, start_z),
                            (shape_x, shape_y, shape_z),
                            blocks,
                            palette,
                            parse_entities(nbt_obj["entities"]),
                            block_entities,
                        )
                    )
            else:
                raise Exception(
                    f"This wrapper does not support any construction section version higher than {max_section_version}"
                )

        else:
            raise Exception(
                f"This wrapper does not support any construction format version higher than {max_format_version}"
            )
示例#29
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)
示例#30
0
        def test_replace_multiblock(self):
            subbox1 = SelectionBox((1, 70, 3), (2, 75, 4))
            box1 = SelectionGroup((subbox1,))

            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 3, "overworld").blockstate,
            )
            for y in range(71, 75):
                self.assertEqual(
                    "universal_minecraft:air",
                    self.world.get_block(1, y, 3, "overworld").blockstate,
                    f"Failed at coordinate (1,{y},3)",
                )

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

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

            for y in range(71, 75):
                self.assertEqual(
                    "universal_minecraft:stone",
                    self.world.get_block(1, y, 3, "overworld").blockstate,
                    f"Failed at coordinate (1,{y},3)",
                )

            self.world.undo()

            self.assertEqual(
                "universal_minecraft:stone",
                self.world.get_block(1, 70, 3, "overworld").blockstate,
            )
            for y in range(71, 75):
                self.assertEqual(
                    "universal_minecraft:air",
                    self.world.get_block(1, y, 3, "overworld").blockstate,
                    f"Failed at coordinate (1,{y},3)",
                )

            self.world.redo()

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

            for y in range(71, 75):
                self.assertEqual(
                    "universal_minecraft:stone",
                    self.world.get_block(1, y, 3, "overworld").blockstate,
                    f"Failed at coordinate (1,{y},3)",
                )