Source code for mciwb.copier

"""
Provide copy and paste actions on Volumes of blocks
"""

from mcipc.rcon.enumerations import CloneMode, MaskMode
from mcipc.rcon.item import Item
from mcwb import Vec3, Volume

from mciwb.logging import log
from mciwb.threads import get_client

zero = Vec3(0, 0, 0)


[docs] class CopyPaste: """ Provides an interactive way to use copy and paste commands within a Minecraft world. """ def __init__(self): self.start_pos: Vec3 = None # type: ignore self.stop_pos: Vec3 = None # type: ignore self.paste_pos: Vec3 = None # type: ignore self._clone_dest = zero self.size = zero
[docs] def to_volume(self) -> Volume: """ Converts the copy buffer location and dimensions to a Volume """ v = Volume.from_corners(self.start_pos, self.stop_pos) return v
[docs] def apply_volume(self, vol: Volume): """ Use a Volume to set the copy buffer location and dimensions """ self._set_paste(vol.end) self._set_paste(vol.start) self.paste_pos = vol.start
[docs] def get_commands(self): """ return a list of command names and the callback functions they represent. For use in setting up a `Signs` object that can be used to interactively call the copy paste functions. """ return { "select": self.select, "paste": self.paste, "expand": self.expand_to, "clear": self.clear, }
[docs] def select(self, pos: Vec3): """ Select a new copy buffer start point in the world. The previous start point becomes the stop point (i.e. opposite corner of the paste buffer) """ self.stop_pos = self.start_pos or pos # init both to the same for first time self.start_pos = pos.with_ints() self.size = self.stop_pos - self.start_pos self._set_paste(Vec3(self.start_pos.x, self.start_pos.y, self.start_pos.z))
def _set_paste(self, pos: Vec3): """ Set the paste point to the specified position """ self.paste_pos = pos # adjust clone dest so the paste corner matches the start paste buffer self._clone_dest = self.paste_pos x_off = self.size.x if self.size.x < 0 else 0 y_off = self.size.y if self.size.y < 0 else 0 z_off = self.size.z if self.size.z < 0 else 0 self._clone_dest += Vec3(x_off, y_off, z_off)
[docs] def paste(self, pos: Vec3, force=True): """ Copy the contents of past buffer to pos """ client = get_client() self._set_paste(pos) mode = CloneMode.FORCE if force else CloneMode.NORMAL result = client.clone( self.start_pos, self.stop_pos, self._clone_dest, mask_mode=MaskMode.REPLACE, clone_mode=mode, ) log.info(result)
[docs] def paste_safe(self, pos: Vec3): """ Paste the contents of the paste buffer to pos, but only if the paste buffer does not overlap with the target area """ self.paste(pos, force=False)
[docs] def fill(self, pos: Vec3 = zero, item: Item = Item.AIR): """ fill the paste buffer offset by pos with Air or a specified block :param pos: offset from the paste buffer start point :param item: block to fill with """ client = get_client() offset = pos end = self.paste_pos + self.size + offset result = client.fill(self.paste_pos + offset, end, item.value) log.info(result)
[docs] def clear(self, _: Vec3 = zero): """ Clear the blocks in the current paste buffer """ self.fill()
[docs] def expand_to(self, pos: Vec3): """ expand one or more of the dimensions of the copy buffer by moving the faces outwards to the specified point """ # use mutable start and stop here to make the code more readable start = self.start_pos._asdict() stop = self.stop_pos._asdict() for dim in ["x", "y", "z"]: if start[dim] <= stop[dim]: if pos[dim] > stop[dim]: stop[dim] = pos[dim] elif pos[dim] < start[dim]: start[dim] = pos[dim] elif start[dim] >= stop[dim]: if pos[dim] < stop[dim]: stop[dim] = pos[dim] elif pos[dim] > start[dim]: start[dim] = pos[dim] self.select(Vec3(**stop)) self.select(Vec3(**start))
[docs] def expand(self, x=0, y=0, z=0): """ expand one or more of the dimensions of the copy buffer by relative amounts """ expander = Vec3(x, y, z) # use mutable start and stop here to make the code more readable start = self.start_pos._asdict() stop = self.stop_pos._asdict() for dim in ["x", "y", "z"]: if expander[dim] > 0: if start[dim] > stop[dim]: start[dim] += expander[dim] else: stop[dim] += expander[dim] elif expander[dim] < 0: if start[dim] < stop[dim]: start[dim] += expander[dim] else: stop[dim] += expander[dim] self.select(Vec3(**stop)) self.select(Vec3(**start))