diff --git a/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java b/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java new file mode 100644 index 000000000..c0ba48fae --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java @@ -0,0 +1,70 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.function.block; + +import com.sk89q.worldedit.Extent; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.math.transform.Transform; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Copies blocks from one extent to another. + */ +public class ExtentBlockCopy implements RegionFunction { + + private final Extent source; + private final Extent destination; + private final Vector from; + private final Vector to; + private final Transform transform; + + /** + * Make a new copy. + * + * @param source the source extent + * @param from the source offset + * @param destination the destination extent + * @param to the destination offset + * @param transform a transform to apply to positions (after source offset, before destination offset) + */ + public ExtentBlockCopy(Extent source, Vector from, Extent destination, Vector to, Transform transform) { + checkNotNull(source); + checkNotNull(from); + checkNotNull(destination); + checkNotNull(to); + checkNotNull(transform); + this.source = source; + this.from = from; + this.destination = destination; + this.to = to; + this.transform = transform; + } + + @Override + public boolean apply(Vector position) throws WorldEditException { + BaseBlock block = source.getBlock(position); + return destination.setBlock(transform.apply(position.subtract(from)).add(to), block, true); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java b/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java new file mode 100644 index 000000000..286b081ad --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java @@ -0,0 +1,177 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.function.operation; + +import com.sk89q.worldedit.Extent; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.RegionMaskingFilter; +import com.sk89q.worldedit.function.block.ExtentBlockCopy; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.Masks; +import com.sk89q.worldedit.function.visitor.RegionVisitor; +import com.sk89q.worldedit.math.transform.Identity; +import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.regions.Region; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Makes a copy of a portion of one extent to another extent or another point. + *

+ * This is a forward extent copy, meaning that it iterates over the blocks in the + * source extent, and will copy as many blocks as there are in the source. + * Therefore, interpolation will not occur to fill in the gaps. + */ +public class ForwardExtentCopy implements Operation { + + private final Extent source; + private final Extent destination; + private final Region region; + private final Vector to; + private int repetitions = 1; + private Mask sourceMask = Masks.alwaysTrue(); + private Transform transform = new Identity(); + private Transform currentTransform = null; + private RegionVisitor lastVisitor; + private int affected; + + /** + * Create a new copy. + * + * @param source the source extent + * @param region the region to copy + * @param destination the destination extent + * @param to the destination position, starting from the the lowest X, Y, Z + */ + public ForwardExtentCopy(Extent source, Region region, Extent destination, Vector to) { + checkNotNull(source); + checkNotNull(region); + checkNotNull(destination); + checkNotNull(to); + this.source = source; + this.destination = destination; + this.region = region; + this.to = to; + } + + /** + * Get the transformation that will occur on every point. + *

+ * The transformation will stack with each repetition. + * + * @return a transformation + */ + public Transform getTransform() { + return transform; + } + + /** + * Set the transformation that will occur on every point. + * + * @param transform a transformation + * @see #getTransform() + */ + public void setTransform(Transform transform) { + checkNotNull(transform); + this.transform = transform; + } + + /** + * Get the mask that gets applied to the source extent. + *

+ * This mask can be used to filter what will be copied from the source. + * + * @return a source mask + */ + public Mask getSourceMask() { + return sourceMask; + } + + /** + * Set a mask that gets applied to the source extent. + * + * @param sourceMask a source mask + * @see #getSourceMask() + */ + public void setSourceMask(Mask sourceMask) { + checkNotNull(sourceMask); + this.sourceMask = sourceMask; + } + + /** + * Get the number of repetitions left. + * + * @return the number of repetitions + */ + public int getRepetitions() { + return repetitions; + } + + /** + * Set the number of repetitions left. + * + * @param repetitions the number of repetitions + */ + public void setRepetitions(int repetitions) { + checkArgument(repetitions >= 0, "number of repetitions must be non-negative"); + this.repetitions = repetitions; + } + + /** + * Get the number of affected objects. + * + * @return the number of affected + */ + public int getAffected() { + return affected; + } + + @Override + public Operation resume() throws WorldEditException { + if (lastVisitor != null) { + affected += lastVisitor.getAffected(); + lastVisitor = null; + } + + if (repetitions > 0) { + repetitions--; + + if (currentTransform == null) { + currentTransform = transform; + } + + ExtentBlockCopy copy = new ExtentBlockCopy(source, region.getMinimumPoint(), destination, to, currentTransform); + RegionMaskingFilter filter = new RegionMaskingFilter(sourceMask, copy); + RegionVisitor visitor = new RegionVisitor(region, filter); + lastVisitor = visitor; + currentTransform = currentTransform.combine(transform); + return new DelegateOperation(this, visitor); + } else { + return null; + } + } + + @Override + public void cancel() { + } + +}