From 803c84a6215f9afb960bc970c38ab9495018c419 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Mon, 21 Aug 2017 00:40:10 +1000 Subject: [PATCH] Add direction argument to fill --- .../java/com/sk89q/worldedit/EditSession.java | 96 ++++++++----------- .../worldedit/command/UtilityCommands.java | 20 ++-- .../function/visitor/DirectionalVisitor.java | 86 +++++++++++++++++ 3 files changed, 130 insertions(+), 72 deletions(-) create mode 100644 core/src/main/java/com/sk89q/worldedit/function/visitor/DirectionalVisitor.java diff --git a/core/src/main/java/com/sk89q/worldedit/EditSession.java b/core/src/main/java/com/sk89q/worldedit/EditSession.java index f5af4a26..9eaa4776 100644 --- a/core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -106,6 +106,7 @@ import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.util.RegionOffset; +import com.sk89q.worldedit.function.visitor.DirectionalVisitor; import com.sk89q.worldedit.function.visitor.DownwardVisitor; import com.sk89q.worldedit.function.visitor.FlatRegionVisitor; import com.sk89q.worldedit.function.visitor.LayerVisitor; @@ -1446,6 +1447,43 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting return this.changes; } + /** + * Fills an area recursively in the X/Z directions. + * + * @param origin the location to start from + * @param pattern the block to fill with + * @param radius the radius of the spherical area to fill + * @param depth the maximum depth, starting from the origin + * @param direction the direction to fill + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int fillDirection(final Vector origin, final Pattern pattern, final double radius, final int depth, Vector direction) { + checkNotNull(origin); + checkNotNull(pattern); + checkArgument(radius >= 0, "radius >= 0"); + checkArgument(depth >= 1, "depth >= 1"); + initTransform(origin); + if (direction.equals(new Vector(0, -1, 0))) { + System.out.println("Fill down"); + return fillXZ(origin, pattern, radius, depth, false); + } + final MaskIntersection mask = new MaskIntersection(new RegionMask(new EllipsoidRegion(null, origin, new Vector(radius, radius, radius))), Masks.negate(new ExistingBlockMask(EditSession.this))); + + // Want to replace blocks + final BlockReplace replace = new BlockReplace(EditSession.this, pattern); + + // Pick how we're going to visit blocks + RecursiveVisitor visitor = new DirectionalVisitor(mask, replace, origin, direction, (int) (radius * 2 + 1), this); + + // Start at the origin + visitor.visit(origin); + + // Execute + Operations.completeBlindly(visitor); + return this.changes = visitor.getAffected(); + } + /** * Fills an area recursively in the X/Z directions. * @@ -1502,64 +1540,6 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting return this.changes = visitor.getAffected(); } -// public int fillDirection(final Vector origin, PlayerDirection direction, final Pattern pattern, final double radius, final int depth, final boolean recursive) { -// checkNotNull(origin); -// checkNotNull(pattern); -// checkArgument(radius >= 0, "radius >= 0"); -// checkArgument(depth >= 1, "depth >= 1"); -// -// Vector dirVec = direction.vector(); -// BlockVector min = origin.toBlockVector(); -// BlockVector max = origin.toBlockVector(); -// -// CuboidRegion cuboid = new CuboidRegion(new Vector(), new Vector()); -// switch (direction) { -// case NORTH: -// break; -// case NORTH_EAST: -// break; -// case EAST: -// break; -// case SOUTH_EAST: -// break; -// case SOUTH: -// break; -// case SOUTH_WEST: -// break; -// case WEST: -// break; -// case NORTH_WEST: -// break; -// case UP: -// break; -// case DOWN: -// break; -// } -// -// -// -// final MaskIntersection mask = new MaskIntersection(new RegionMask(new EllipsoidRegion(null, origin, new Vector(radius, radius, radius))), new BoundedHeightMask(Math.max( -// (origin.getBlockY() - depth) + 1, 0), Math.min(EditSession.this.getMaximumPoint().getBlockY(), origin.getBlockY())), Masks.negate(new ExistingBlockMask(EditSession.this))); -// -// // Want to replace blocks -// final BlockReplace replace = new BlockReplace(EditSession.this, pattern); -// -// // Pick how we're going to visit blocks -// RecursiveVisitor visitor; -// if (recursive) { -// visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1), this); -// } else { -// visitor = new DownwardVisitor(mask, replace, origin.getBlockY(), (int) (radius * 2 + 1), this); -// } -// -// // Start at the origin -// visitor.visit(origin); -// -// // Execute -// Operations.completeBlindly(visitor); -// return this.changes = visitor.getAffected(); -// } - /** * Remove a cuboid above the given position with a given apothem and a given height. * diff --git a/core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index 05b5c369..467291f1 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -57,6 +57,7 @@ import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.visitor.EntityVisitor; +import com.sk89q.worldedit.internal.annotation.Direction; import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.internal.expression.runtime.EvaluationException; @@ -175,19 +176,15 @@ public class UtilityCommands extends MethodCommands { usage = " [depth]", desc = "Fill a hole", min = 2, - max = 3 + max = 4 ) @CommandPermissions("worldedit.fill") @Logging(PLACEMENT) - public void fill(Player player, LocalSession session, EditSession editSession, Pattern pattern, double radius, @Optional("1") double depth) throws WorldEditException { + public void fill(Player player, LocalSession session, EditSession editSession, Pattern pattern, double radius, @Optional("1") double depth, @Optional("down") @Direction Vector direction) throws WorldEditException { worldEdit.checkMaxRadius(radius); Vector pos = session.getPlacementPosition(player); - int affected = 0; - if (pattern instanceof BaseBlock) { - affected = editSession.fillXZ(pos, ((BaseBlock) pattern), radius, (int) depth, false); - } else { - affected = editSession.fillXZ(pos, pattern, radius, (int) depth, false); - } + int affected; + affected = editSession.fillDirection(pos, pattern, radius, (int) depth, direction); player.print(BBC.getPrefix() + affected + " block(s) have been created."); } @@ -203,12 +200,7 @@ public class UtilityCommands extends MethodCommands { public void fillr(Player player, LocalSession session, EditSession editSession, Pattern pattern, double radius, @Optional("1") double depth) throws WorldEditException { worldEdit.checkMaxRadius(radius); Vector pos = session.getPlacementPosition(player); - int affected; - if (pattern instanceof BaseBlock) { - affected = editSession.fillXZ(pos, ((BaseBlock) pattern), radius, (int) depth, true); - } else { - affected = editSession.fillXZ(pos, pattern, radius, (int) depth, true); - } + int affected = editSession.fillXZ(pos, pattern, radius, (int) depth, true); player.print(BBC.getPrefix() + affected + " block(s) have been created."); } diff --git a/core/src/main/java/com/sk89q/worldedit/function/visitor/DirectionalVisitor.java b/core/src/main/java/com/sk89q/worldedit/function/visitor/DirectionalVisitor.java new file mode 100644 index 00000000..ecdcbb69 --- /dev/null +++ b/core/src/main/java/com/sk89q/worldedit/function/visitor/DirectionalVisitor.java @@ -0,0 +1,86 @@ +/* + * 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.visitor; + +import com.boydti.fawe.object.HasFaweQueue; +import com.sk89q.worldedit.MutableBlockVector; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.mask.Mask; +import java.util.Collection; + + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Visits adjacent points on the same X-Z plane as long as the points + * pass the given mask, and then executes the provided region + * function on the entire column. + *

+ *

This is used by {@code //fill}.

+ */ +public class DirectionalVisitor extends RecursiveVisitor { + + private final Vector origin; + private final Vector dirVec; + + public DirectionalVisitor(Mask mask, RegionFunction function, Vector origin, Vector direction) { + this(mask, function, origin, direction, Integer.MAX_VALUE, null); + } + + public DirectionalVisitor(Mask mask, RegionFunction function, Vector origin, Vector direction, int distance, HasFaweQueue hasFaweQueue) { + super(mask, function, distance, hasFaweQueue); + checkNotNull(mask); + this.origin = origin; + this.dirVec = new MutableBlockVector(direction); + final Collection directions = this.getDirections(); + directions.clear(); + directions.add(new Vector(1, 0, 0)); + directions.add(new Vector(-1, 0, 0)); + directions.add(new Vector(0, 0, 1)); + directions.add(new Vector(0, 0, -1)); + directions.add(new Vector(0, -1, 0)); + directions.add(new Vector(0, 1, 0)); + } + + @Override + public boolean isVisitable(final Vector from, final Vector to) { + int dx = to.getBlockX() - from.getBlockX(); + int dz = to.getBlockZ() - from.getBlockZ(); + int dy = to.getBlockY() - from.getBlockY(); + + if (dx != 0) { + if (dirVec.getBlockX() != 0 && dirVec.getBlockX() != dx) { + return false; + } + } + if (dy != 0) { + if (dirVec.getBlockY() != 0 && dirVec.getBlockY() != dy) { + return false; + } + } + if (dz != 0) { + if (dirVec.getBlockZ() != 0 && dirVec.getBlockZ() != dz) { + return false; + } + } + return super.isVisitable(from, to); + } +} \ No newline at end of file