Example #1
0
class Fill(wx.Panel, OperationUI):
    def __init__(self, parent: wx.Window, canvas: "EditCanvas", world: "World",
                 options_path: str):
        wx.Panel.__init__(self, parent)
        OperationUI.__init__(self, parent, canvas, world, options_path)

        self._sizer = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(self._sizer)

        options = self._load_options({})

        self._block_define = BlockDefine(
            self,
            world.translation_manager,
            wx.VERTICAL,
            *(options.get("fill_block_options", [])
              or [world.world_wrapper.platform]),
            show_pick_block=True)
        self._block_click_registered = False
        self._block_define.Bind(EVT_PICK, self._on_pick_block_button)
        self._sizer.Add(self._block_define, 1,
                        wx.ALL | wx.ALIGN_CENTRE_HORIZONTAL, 5)

        self._run_button = wx.Button(self, label="Run Operation")
        self._run_button.Bind(wx.EVT_BUTTON, self._run_operation)
        self._sizer.Add(self._run_button, 0,
                        wx.ALL | wx.ALIGN_CENTRE_HORIZONTAL, 5)

        self.Layout()

    @property
    def wx_add_options(self) -> Tuple[int, ...]:
        return (1, )

    def _on_pick_block_button(self, evt):
        """Set up listening for the block click"""
        if not self._block_click_registered:
            self.canvas.Bind(EVT_BOX_CLICK, self._on_pick_block)
            self._block_click_registered = True
        evt.Skip()

    def _on_pick_block(self, evt):
        self.canvas.Unbind(EVT_BOX_CLICK, handler=self._on_pick_block)
        self._block_click_registered = False
        x, y, z = self.canvas.cursor_location
        self._block_define.universal_block = (
            self.world.get_block(x, y, z, self.canvas.dimension),
            None,
        )

    def _get_fill_block(self):
        return self._block_define.universal_block[0]

    def unload(self):
        self._save_options({
            "fill_block":
            self._get_fill_block(),
            "fill_block_options": (
                self._block_define.platform,
                self._block_define.version_number,
                self._block_define.force_blockstate,
                self._block_define.namespace,
                self._block_define.block_name,
                self._block_define.properties,
            ),
        })

    def _run_operation(self, _):
        self.canvas.run_operation(lambda: fill(
            self.world,
            self.canvas.dimension,
            self.canvas.selection_group,
            self._get_fill_block(),
        ))
class Fill(wx.Panel, DefaultOperationUI):
    def __init__(
        self,
        parent: wx.Window,
        canvas: "EditCanvas",
        world: "BaseLevel",
        options_path: str,
    ):
        wx.Panel.__init__(self, parent)
        DefaultOperationUI.__init__(self, parent, canvas, world, options_path)
        self.Freeze()
        self._sizer = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(self._sizer)

        options = self._load_options({})

        self._block_define = BlockDefine(
            self,
            world.translation_manager,
            wx.VERTICAL,
            *(options.get("fill_block_options", [])
              or [world.level_wrapper.platform]),
            show_pick_block=True)
        self._block_define.Bind(EVT_PICK, self._on_pick_block_button)
        self._sizer.Add(self._block_define, 1,
                        wx.ALL | wx.ALIGN_CENTRE_HORIZONTAL, 5)

        self._run_button = wx.Button(self, label="Run Operation")
        self._run_button.Bind(wx.EVT_BUTTON, self._run_operation)
        self._sizer.Add(self._run_button, 0,
                        wx.ALL | wx.ALIGN_CENTRE_HORIZONTAL, 5)

        self.Layout()
        self.Thaw()

    @property
    def wx_add_options(self) -> Tuple[int, ...]:
        return (1, )

    def _on_pick_block_button(self, evt):
        """Set up listening for the block click"""
        self._show_pointer = True

    def _on_box_click(self):
        if self._show_pointer:
            self._show_pointer = False
            x, y, z = self._pointer.pointer_base
            self._block_define.universal_block = (
                self.world.get_block(x, y, z, self.canvas.dimension),
                None,
            )

    def _get_fill_block(self):
        return self._block_define.universal_block[0]

    def disable(self):
        self._save_options({
            "fill_block":
            self._get_fill_block(),
            "fill_block_options": (
                self._block_define.platform,
                self._block_define.version_number,
                self._block_define.force_blockstate,
                self._block_define.namespace,
                self._block_define.block_name,
                self._block_define.properties,
            ),
        })

    def _run_operation(self, _):
        self.canvas.run_operation(lambda: fill(
            self.world,
            self.canvas.dimension,
            self.canvas.selection.selection_group,
            self._get_fill_block(),
        ))
Example #3
0
    def __init__(
        self, parent: wx.Window, canvas: "EditCanvas", world: "World", options_path: str
    ):
        wx.Panel.__init__(self, parent)
        OperationUI.__init__(self, parent, canvas, world, options_path)
        self.Freeze()

        self._sizer = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(self._sizer)

        options = self._load_options({})

        top_sizer = wx.BoxSizer(wx.HORIZONTAL)
        self._sizer.Add(top_sizer, 0, wx.EXPAND | wx.ALL, 5)

        help_button = wx.BitmapButton(
            self, bitmap=image.icon.tablericons.help.bitmap(22, 22)
        )
        top_sizer.Add(help_button)

        def on_button(evt):
            dialog = SimpleDialog(self, "Extra block help.")
            text = wx.TextCtrl(
                dialog,
                value="Blocks in the newer versions of Minecraft support having two blocks in the same location.\n"
                "This is how the game is able to have water and blocks like fences at the same location.\n"
                "In the example of waterlogged fences the fence is the first block and the water is the second. Unless it is water the second block is usually just visual.\n"
                "In Java currently the second block is strictly water but in Bedrock there is no limit on what the second block can be.\n"
                "It is not possible to set non-water second blocks in the game but this operation enables the use of that feature.\n"
                "There are a number of different modes which can be selected at the top. A description of how it works will appear.",
                style=wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_BESTWRAP,
            )
            dialog.sizer.Add(text, 1, wx.EXPAND)
            dialog.ShowModal()
            evt.Skip()

        help_button.Bind(wx.EVT_BUTTON, on_button)

        self._mode = wx.Choice(self, choices=list(MODES.keys()))
        self._mode.SetSelection(0)
        top_sizer.Add(self._mode, 1, wx.EXPAND | wx.LEFT, 5)
        self._mode.Bind(wx.EVT_CHOICE, self._on_mode_change)

        self._mode_description = wx.TextCtrl(
            self, style=wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_BESTWRAP
        )
        self._sizer.Add(self._mode_description, 0, wx.EXPAND | wx.LEFT | wx.RIGHT, 5)

        self._mode_description.SetLabel(
            MODES[self._mode.GetString(self._mode.GetSelection())]
        )
        self._mode_description.Fit()

        self._block_define = BlockDefine(
            self,
            world.world_wrapper.translation_manager,
            wx.VERTICAL,
            *(options.get("fill_block_options", []) or [world.world_wrapper.platform]),
            show_pick_block=True
        )
        self._block_click_registered = False
        self._block_define.Bind(EVT_PICK_BLOCK, self._on_pick_block_button)
        self._sizer.Add(self._block_define, 1, wx.ALL | wx.ALIGN_CENTRE_HORIZONTAL, 5)

        self._run_button = wx.Button(self, label="Run Operation")
        self._run_button.Bind(wx.EVT_BUTTON, self._run_operation)
        self._sizer.Add(self._run_button, 0, wx.ALL | wx.ALIGN_CENTRE_HORIZONTAL, 5)

        self.Layout()
        self.Thaw()
Example #4
0
class Waterlog(wx.Panel, OperationUI):
    def __init__(
        self, parent: wx.Window, canvas: "EditCanvas", world: "World", options_path: str
    ):
        wx.Panel.__init__(self, parent)
        OperationUI.__init__(self, parent, canvas, world, options_path)
        self.Freeze()

        self._sizer = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(self._sizer)

        options = self._load_options({})

        top_sizer = wx.BoxSizer(wx.HORIZONTAL)
        self._sizer.Add(top_sizer, 0, wx.EXPAND | wx.ALL, 5)

        help_button = wx.BitmapButton(
            self, bitmap=image.icon.tablericons.help.bitmap(22, 22)
        )
        top_sizer.Add(help_button)

        def on_button(evt):
            dialog = SimpleDialog(self, "Extra block help.")
            text = wx.TextCtrl(
                dialog,
                value="Blocks in the newer versions of Minecraft support having two blocks in the same location.\n"
                "This is how the game is able to have water and blocks like fences at the same location.\n"
                "In the example of waterlogged fences the fence is the first block and the water is the second. Unless it is water the second block is usually just visual.\n"
                "In Java currently the second block is strictly water but in Bedrock there is no limit on what the second block can be.\n"
                "It is not possible to set non-water second blocks in the game but this operation enables the use of that feature.\n"
                "There are a number of different modes which can be selected at the top. A description of how it works will appear.",
                style=wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_BESTWRAP,
            )
            dialog.sizer.Add(text, 1, wx.EXPAND)
            dialog.ShowModal()
            evt.Skip()

        help_button.Bind(wx.EVT_BUTTON, on_button)

        self._mode = wx.Choice(self, choices=list(MODES.keys()))
        self._mode.SetSelection(0)
        top_sizer.Add(self._mode, 1, wx.EXPAND | wx.LEFT, 5)
        self._mode.Bind(wx.EVT_CHOICE, self._on_mode_change)

        self._mode_description = wx.TextCtrl(
            self, style=wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_BESTWRAP
        )
        self._sizer.Add(self._mode_description, 0, wx.EXPAND | wx.LEFT | wx.RIGHT, 5)

        self._mode_description.SetLabel(
            MODES[self._mode.GetString(self._mode.GetSelection())]
        )
        self._mode_description.Fit()

        self._block_define = BlockDefine(
            self,
            world.world_wrapper.translation_manager,
            wx.VERTICAL,
            *(options.get("fill_block_options", []) or [world.world_wrapper.platform]),
            show_pick_block=True
        )
        self._block_click_registered = False
        self._block_define.Bind(EVT_PICK_BLOCK, self._on_pick_block_button)
        self._sizer.Add(self._block_define, 1, wx.ALL | wx.ALIGN_CENTRE_HORIZONTAL, 5)

        self._run_button = wx.Button(self, label="Run Operation")
        self._run_button.Bind(wx.EVT_BUTTON, self._run_operation)
        self._sizer.Add(self._run_button, 0, wx.ALL | wx.ALIGN_CENTRE_HORIZONTAL, 5)

        self.Layout()
        self.Thaw()

    @property
    def wx_add_options(self) -> Tuple[int, ...]:
        return (1,)

    def _on_mode_change(self, evt):
        self._mode_description.SetLabel(
            MODES[self._mode.GetString(self._mode.GetSelection())]
        )
        self._mode_description.Fit()
        self.Layout()
        evt.Skip()

    def _on_pick_block_button(self, evt):
        """Set up listening for the block click"""
        if not self._block_click_registered:
            self.canvas.Bind(EVT_BOX_CLICK, self._on_pick_block)
            self._block_click_registered = True
        evt.Skip()

    def _on_pick_block(self, evt):
        self.canvas.Unbind(EVT_BOX_CLICK, handler=self._on_pick_block)
        self._block_click_registered = False
        x, y, z = self.canvas.cursor_location
        self._block_define.universal_block = (
            self.world.get_block(x, y, z, self.canvas.dimension),
            None,
        )

    def _get_fill_block(self):
        return self._block_define.universal_block[0]

    def unload(self):
        self._save_options(
            {
                "fill_block": self._get_fill_block(),
                "fill_block_options": (
                    self._block_define.platform,
                    self._block_define.version_number,
                    self._block_define.force_blockstate,
                    self._block_define.namespace,
                    self._block_define.block_name,
                    self._block_define.properties,
                ),
            }
        )

    def _run_operation(self, _):
        self.canvas.run_operation(lambda: self._waterlog())

    def _waterlog(self):
        mode = self._mode.GetString(self._mode.GetSelection())
        waterlog_block = self._get_fill_block().base_block
        world = self.world
        selection = self.canvas.selection_group
        dimension = self.canvas.dimension
        iter_count = len(list(world.get_chunk_slices(selection, dimension, True)))
        count = 0
        for chunk, slices, _ in world.get_chunk_slices(selection, dimension, True):
            original_blocks = chunk.blocks[slices]
            palette, blocks = numpy.unique(original_blocks, return_inverse=True)
            blocks = blocks.reshape(original_blocks.shape)
            if mode == "Overlay":
                lut = numpy.array(
                    [
                        world.palette.get_add_block(
                            waterlog_block
                            if world.palette[block_id].namespaced_name
                            == "universal_minecraft:air"
                            else world.palette[block_id].base_block
                            + waterlog_block  # get the Block object for that id and add the user specified block
                        )  # register the new block / get the numerical id if it was already registered
                        for block_id in palette
                    ]  # add the new id to the palette
                )
            elif mode == "Underlay":
                lut = numpy.array(
                    [
                        world.palette.get_add_block(
                            waterlog_block
                            if world.palette[block_id].namespaced_name
                            == "universal_minecraft:air"
                            else waterlog_block
                            + world.palette[  # get the Block object for that id and add the user specified block
                                block_id
                            ].base_block
                        )  # register the new block / get the numerical id if it was already registered
                        for block_id in palette
                    ]  # add the new id to the palette
                )
            elif mode == "Normal Fill":
                lut = numpy.array(
                    [
                        world.palette.get_add_block(
                            waterlog_block
                        )  # register the new block / get the numerical id if it was already registered
                    ]
                    * len(palette)  # add the new id to the palette
                )
            elif mode == "Game Fill":
                lut = numpy.array(
                    [
                        world.palette.get_add_block(
                            waterlog_block + world.palette[block_id].base_block
                            if world.palette[block_id].namespaced_name
                            == "universal_minecraft:water"
                            else waterlog_block
                        )  # register the new block / get the numerical id if it was already registered
                        for block_id in palette
                    ]  # add the new id to the palette
                )
            elif mode == "Set First":
                lut = numpy.array(
                    [
                        world.palette.get_add_block(
                            waterlog_block + world.palette[block_id].extra_blocks[0]
                            if world.palette[block_id].extra_blocks
                            else waterlog_block
                        )  # register the new block / get the numerical id if it was already registered
                        for block_id in palette
                    ]  # add the new id to the palette
                )
            elif mode == "Set Second":
                lut = numpy.array(
                    [
                        world.palette.get_add_block(
                            world.palette[block_id].base_block + waterlog_block
                        )  # register the new block / get the numerical id if it was already registered
                        for block_id in palette
                    ]  # add the new id to the palette
                )
            else:
                raise Exception("hello")

            chunk.blocks[slices] = lut[blocks]

            chunk.changed = True
            count += 1
            yield count / iter_count
Example #5
0
class _CollapsibleBlockDefine(wx.Panel):
    def __init__(self,
                 parent: MultiBlockDefine,
                 translation_manager,
                 collapsed=False):
        super().__init__(parent, style=wx.BORDER_SIMPLE)

        self.EXPAND = MAXIMIZE.bitmap(18, 18)
        self.COLLAPSE = MINIMIZE.bitmap(18, 18)

        self._collapsed = collapsed

        sizer = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(sizer)

        header_sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(header_sizer, 0, wx.ALL, 5)

        self.expand_button = wx.BitmapButton(self, bitmap=self.EXPAND)
        header_sizer.Add(self.expand_button, 0, 5)

        self.up_button = wx.BitmapButton(self, bitmap=UP_CARET.bitmap(18, 18))
        header_sizer.Add(self.up_button, 0, wx.LEFT, 5)
        self.up_button.Bind(wx.EVT_BUTTON, lambda evt: parent.move_up(self))

        self.down_button = wx.BitmapButton(self,
                                           bitmap=DOWN_CARET.bitmap(18, 18))
        header_sizer.Add(self.down_button, 0, wx.LEFT, 5)
        self.down_button.Bind(wx.EVT_BUTTON,
                              lambda evt: parent.move_down(self))

        self.delete_button = wx.BitmapButton(self, bitmap=TRASH.bitmap(18, 18))
        header_sizer.Add(self.delete_button, 0, wx.LEFT, 5)
        self.delete_button.Bind(wx.EVT_BUTTON, lambda evt: parent.delete(self))

        self.block_define = BlockDefine(self, translation_manager,
                                        wx.HORIZONTAL)
        sizer.Add(self.block_define, 1,
                  wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, 5)
        self.collapsed = collapsed

        self.block_label = wx.StaticText(
            self,
            label=self._gen_block_string(),
            style=wx.ST_ELLIPSIZE_END | wx.ST_NO_AUTORESIZE,
            size=(500, -1),
        )
        header_sizer.Add(self.block_label, 1,
                         wx.ALIGN_CENTER_VERTICAL | wx.LEFT, 5)

        self.expand_button.Bind(wx.EVT_BUTTON,
                                lambda evt: self._toggle_block_expand(parent))
        self.block_define.Bind(EVT_PROPERTIES_CHANGE,
                               self._on_properties_change)

    @property
    def collapsed(self) -> bool:
        return self._collapsed

    @collapsed.setter
    def collapsed(self, collapsed: bool):
        self._collapsed = collapsed
        if self._collapsed:
            self.expand_button.SetBitmap(self.EXPAND)
            self.block_define.Hide()
        else:
            self.expand_button.SetBitmap(self.COLLAPSE)
            self.block_define.Show()
        self.TopLevelParent.Layout()

    def _toggle_block_expand(self, parent: MultiBlockDefine):
        if self.collapsed:
            parent.collapse()
        self.collapsed = not self.collapsed

    def _on_properties_change(self, evt):
        self.block_label.SetLabel(self._gen_block_string())
        self.TopLevelParent.Layout()
        evt.Skip()

    def _gen_block_string(self):
        base = f"{self.block_define.namespace}:{self.block_define.block_name}"
        properties = ",".join(
            (f"{key}={value}"
             for key, value in self.block_define.str_properties.items()))
        return f"{base}[{properties}]" if properties else base
Example #6
0
class Replace(SimpleScrollablePanel, OperationUI):
    def __init__(
        self, parent: wx.Window, canvas: "EditCanvas", world: "World", options_path: str
    ):
        SimpleScrollablePanel.__init__(self, parent)
        OperationUI.__init__(self, parent, canvas, world, options_path)
        self.Freeze()
        options = self._load_options({})

        self._block_click_registered = 0

        self._original_block = BlockDefine(
            self,
            world.world_wrapper.translation_manager,
            wx.VERTICAL,
            *(
                options.get("original_block_options", [])
                or [world.world_wrapper.platform]
            ),
            wildcard_properties=True,
            show_pick_block=True
        )
        self._sizer.Add(self._original_block, 1, wx.ALL | wx.ALIGN_CENTRE_HORIZONTAL, 5)
        self._original_block.Bind(
            EVT_PICK_BLOCK, lambda evt: self._on_pick_block_button(evt, 1)
        )
        self._replacement_block = BlockDefine(
            self,
            world.world_wrapper.translation_manager,
            wx.VERTICAL,
            *(
                options.get("replacement_block_options", [])
                or [world.world_wrapper.platform]
            ),
            show_pick_block=True
        )
        self._sizer.Add(
            self._replacement_block, 1, wx.ALL | wx.ALIGN_CENTRE_HORIZONTAL, 5
        )
        self._replacement_block.Bind(
            EVT_PICK_BLOCK, lambda evt: self._on_pick_block_button(evt, 2)
        )

        self._run_button = wx.Button(self, label="Run Operation")
        self._run_button.Bind(wx.EVT_BUTTON, self._run_operation)
        self._sizer.Add(self._run_button, 0, wx.ALL | wx.ALIGN_CENTRE_HORIZONTAL, 5)

        self.Layout()
        self.Thaw()

    @property
    def wx_add_options(self) -> Tuple[int, ...]:
        return (1,)

    def _on_pick_block_button(self, evt, code):
        """Set up listening for the block click"""
        if not self._block_click_registered:
            self.canvas.Bind(EVT_BOX_CLICK, self._on_pick_block)
            self._block_click_registered = code
        evt.Skip()

    def _on_pick_block(self, evt):
        self.canvas.Unbind(EVT_BOX_CLICK, handler=self._on_pick_block)
        x, y, z = self.canvas.cursor_location
        if self._block_click_registered == 1:
            self._original_block.universal_block = (
                self.world.get_block(x, y, z, self.canvas.dimension),
                None,
            )
        elif self._block_click_registered == 2:
            self._replacement_block.universal_block = (
                self.world.get_block(x, y, z, self.canvas.dimension),
                None,
            )
        self._block_click_registered = 0

    def _get_replacement_block(self) -> Block:
        return self._replacement_block.universal_block[0]

    def unload(self):
        self._save_options(
            {
                "original_block_options": (
                    self._original_block.platform,
                    self._original_block.version_number,
                    self._original_block.force_blockstate,
                    self._original_block.namespace,
                    self._original_block.block_name,
                    self._original_block.str_properties,
                ),
                "replacement_block": self._get_replacement_block(),
                "replacement_block_options": (
                    self._replacement_block.platform,
                    self._replacement_block.version_number,
                    self._replacement_block.force_blockstate,
                    self._replacement_block.namespace,
                    self._replacement_block.block_name,
                    self._replacement_block.str_properties,
                ),
            }
        )

    def _run_operation(self, _):
        self.canvas.run_operation(lambda: self._replace())

    def _replace(self):
        world = self.world
        selection = self.canvas.selection_group
        dimension = self.canvas.dimension

        (
            original_platform,
            original_version,
            original_blockstate,
            original_namespace,
            original_base_name,
            original_properties,
        ) = (
            self._original_block.platform,
            self._original_block.version_number,
            self._original_block.force_blockstate,
            self._original_block.namespace,
            self._original_block.block_name,
            self._original_block.str_properties,
        )
        replacement_block = self._get_replacement_block()

        replacement_block_id = world.palette.get_add_block(replacement_block)

        original_block_matches = []
        universal_block_count = 0

        iter_count = len(list(world.get_chunk_slices(selection, dimension)))
        count = 0

        for chunk, slices, _ in world.get_chunk_slices(selection, dimension):
            if universal_block_count < len(world.palette):
                for universal_block_id in range(
                    universal_block_count, len(world.palette)
                ):
                    version_block = world.translation_manager.get_version(
                        original_platform, original_version
                    ).block.from_universal(
                        world.palette[universal_block_id],
                        force_blockstate=original_blockstate,
                    )[
                        0
                    ]
                    if (
                        version_block.namespace == original_namespace
                        and version_block.base_name == original_base_name
                        and all(
                            original_properties.get(prop) in ["*", val.to_snbt()]
                            for prop, val in version_block.properties.items()
                        )
                    ):
                        original_block_matches.append(universal_block_id)

                universal_block_count = len(world.palette)
            blocks = chunk.blocks[slices]
            blocks[numpy.isin(blocks, original_block_matches)] = replacement_block_id
            chunk.blocks[slices] = blocks
            chunk.changed = True

            count += 1
            yield count / iter_count

    def DoGetBestClientSize(self):
        sizer = self.GetSizer()
        if sizer is None:
            return -1, -1
        else:
            sx, sy = self.GetSizer().CalcMin()
            return (
                sx + wx.SystemSettings.GetMetric(wx.SYS_VSCROLL_X),
                sy + wx.SystemSettings.GetMetric(wx.SYS_HSCROLL_Y),
            )