diff --git a/core/src/main/java/com/boydti/fawe/Fawe.java b/core/src/main/java/com/boydti/fawe/Fawe.java index 21987150..b99e2b0a 100644 --- a/core/src/main/java/com/boydti/fawe/Fawe.java +++ b/core/src/main/java/com/boydti/fawe/Fawe.java @@ -53,6 +53,8 @@ import com.sk89q.worldedit.function.mask.FuzzyBlockMask; import com.sk89q.worldedit.function.mask.Masks; import com.sk89q.worldedit.function.mask.OffsetMask; import com.sk89q.worldedit.function.mask.SolidBlockMask; +import com.sk89q.worldedit.function.operation.ChangeSetExecutor; +import com.sk89q.worldedit.function.operation.ForwardExtentCopy; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.ClipboardPattern; import com.sk89q.worldedit.function.pattern.Patterns; @@ -389,6 +391,8 @@ public class Fawe { Masks.inject(); // // Operations Operations.inject(); // Optimizations + ForwardExtentCopy.inject(); // Fixes + optimizations + ChangeSetExecutor.inject(); // Optimizations // BlockData BlockData.inject(); // Temporary fix for 1.9.4 BundledBlockData.inject(); // Add custom rotation diff --git a/core/src/main/java/com/sk89q/worldedit/function/operation/ChangeSetExecutor.java b/core/src/main/java/com/sk89q/worldedit/function/operation/ChangeSetExecutor.java index b3c70e31..69e88e30 100644 --- a/core/src/main/java/com/sk89q/worldedit/function/operation/ChangeSetExecutor.java +++ b/core/src/main/java/com/sk89q/worldedit/function/operation/ChangeSetExecutor.java @@ -104,4 +104,7 @@ public class ChangeSetExecutor implements Operation { return new ChangeSetExecutor(changeSet, Type.REDO, context); } + public static Class inject() { + return ChangeSetExecutor.class; + } } diff --git a/core/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java b/core/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java new file mode 100644 index 00000000..d75cbaa9 --- /dev/null +++ b/core/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java @@ -0,0 +1,256 @@ +/* + * 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 Lesser 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.function.operation; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.CombinedRegionFunction; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.RegionMaskingFilter; +import com.sk89q.worldedit.function.block.ExtentBlockCopy; +import com.sk89q.worldedit.function.entity.ExtentEntityCopy; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.Masks; +import com.sk89q.worldedit.function.visitor.EntityVisitor; +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 java.util.List; + +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 from; + private final Vector to; + private int repetitions = 1; + private Mask sourceMask = Masks.alwaysTrue(); + private boolean removingEntities; + private RegionFunction sourceFunction = null; + private Transform transform = new Identity(); + private Transform currentTransform = null; + private RegionVisitor lastVisitor; + private int affected; + + /** + * Create a new copy using the region's lowest minimum point as the + * "from" position. + * + * @param source the source extent + * @param region the region to copy + * @param destination the destination extent + * @param to the destination position + * @see #ForwardExtentCopy(Extent, Region, Vector, Extent, Vector) the main constructor + */ + public ForwardExtentCopy(Extent source, Region region, Extent destination, Vector to) { + this(source, region, region.getMinimumPoint(), destination, to); + } + + /** + * Create a new copy. + * + * @param source the source extent + * @param region the region to copy + * @param from the source position + * @param destination the destination extent + * @param to the destination position + */ + public ForwardExtentCopy(Extent source, Region region, Vector from, Extent destination, Vector to) { + checkNotNull(source); + checkNotNull(region); + checkNotNull(from); + checkNotNull(destination); + checkNotNull(to); + this.source = source; + this.destination = destination; + this.region = region; + this.from = from; + 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 function that gets applied to all source blocks after + * the copy has been made. + * + * @return a source function, or null if none is to be applied + */ + public RegionFunction getSourceFunction() { + return sourceFunction; + } + + /** + * Set the function that gets applied to all source blocks after + * the copy has been made. + * + * @param function a source function, or null if none is to be applied + */ + public void setSourceFunction(RegionFunction function) { + this.sourceFunction = function; + } + + /** + * 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; + } + + /** + * Return whether entities that are copied should be removed. + * + * @return true if removing + */ + public boolean isRemovingEntities() { + return removingEntities; + } + + /** + * Set whether entities that are copied should be removed. + * + * @param removingEntities true if removing + */ + public void setRemovingEntities(boolean removingEntities) { + this.removingEntities = removingEntities; + } + + /** + * Get the number of affected objects. + * + * @return the number of affected + */ + public int getAffected() { + return affected; + } + + @Override + public Operation resume(RunContext run) throws WorldEditException { + if (lastVisitor != null) { + affected += lastVisitor.getAffected(); + lastVisitor = null; + } + + if (currentTransform == null) { + currentTransform = transform; + } + + List entities = source.getEntities(region); + + for (int i = 0; i < repetitions; i++) { + ExtentBlockCopy blockCopy = new ExtentBlockCopy(source, from, destination, to, currentTransform); + RegionMaskingFilter filter = new RegionMaskingFilter(sourceMask, blockCopy); + RegionFunction function = sourceFunction != null ? new CombinedRegionFunction(filter, sourceFunction) : filter; + RegionVisitor blockVisitor = new RegionVisitor(region, function); + + ExtentEntityCopy entityCopy = new ExtentEntityCopy(from, destination, to, currentTransform); + entityCopy.setRemoving(removingEntities); + EntityVisitor entityVisitor = new EntityVisitor(entities.iterator(), entityCopy); + + lastVisitor = blockVisitor; + + currentTransform = currentTransform.combine(transform); + Operations.completeBlindly(blockVisitor); + Operations.completeBlindly(entityVisitor); + } + return null; + } + + @Override + public void cancel() { + } + + @Override + public void addStatusMessages(List messages) { + } + + public static Class inject() { + return ForwardExtentCopy.class; + } +}