From af61efc4fb7b0b7eb4636f4dc6cb7c95ef3e8c08 Mon Sep 17 00:00:00 2001 From: sk89q Date: Sat, 29 Mar 2014 18:31:53 -0700 Subject: [PATCH] Added LayerVisitor and LayerFunction. --- .../worldedit/function/LayerFunction.java | 48 +++++++ .../function/visitor/LayerVisitor.java | 123 ++++++++++++++++++ 2 files changed, 171 insertions(+) create mode 100644 src/main/java/com/sk89q/worldedit/function/LayerFunction.java create mode 100644 src/main/java/com/sk89q/worldedit/function/visitor/LayerVisitor.java diff --git a/src/main/java/com/sk89q/worldedit/function/LayerFunction.java b/src/main/java/com/sk89q/worldedit/function/LayerFunction.java new file mode 100644 index 000000000..57f8fbab2 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/LayerFunction.java @@ -0,0 +1,48 @@ +/* + * 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; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; + +/** + * A function that accepts layers of blocks. + */ +public interface LayerFunction { + + /** + * Returns whether the given block should be "passed through" when + * conducting the ground search. + * + * @param position return whether the given block is the ground + * @return true if the search should stop + */ + boolean isGround(Vector position); + + /** + * Apply the function to the given position. + * + * @param position the position + * @param depth the depth as a number starting from 0 + * @return true whether this method should be called for further layers + * @throws com.sk89q.worldedit.WorldEditException thrown on an error + */ + boolean apply(Vector position, int depth) throws WorldEditException; +} diff --git a/src/main/java/com/sk89q/worldedit/function/visitor/LayerVisitor.java b/src/main/java/com/sk89q/worldedit/function/visitor/LayerVisitor.java new file mode 100644 index 000000000..759f12360 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/function/visitor/LayerVisitor.java @@ -0,0 +1,123 @@ +/* + * 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.visitor; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.LayerFunction; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.masks.DummyMask2D; +import com.sk89q.worldedit.masks.Mask2D; +import com.sk89q.worldedit.regions.FlatRegion; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Visits the layers within a region. + *

+ * This class works by iterating over all the columns in a {@link FlatRegion}, + * finding the first ground block in each column (searching from a given + * maximum Y down to a minimum Y), and then applies a {@link LayerFunction} to + * each layer. + */ +public class LayerVisitor implements Operation { + + private final FlatRegion flatRegion; + private final LayerFunction function; + private Mask2D mask = new DummyMask2D(); + private int minY; + private int maxY; + + /** + * Create a new visitor. + * + * @param flatRegion the flat region to visit + * @param minY the minimum Y to stop the search at + * @param maxY the maximum Y to begin the search at + * @param function the layer function to apply t blocks + */ + public LayerVisitor(FlatRegion flatRegion, int minY, int maxY, LayerFunction function) { + checkNotNull(flatRegion); + checkArgument(minY <= maxY, "minY <= maxY required"); + checkNotNull(function); + + this.flatRegion = flatRegion; + this.minY = minY; + this.maxY = maxY; + this.function = function; + } + + /** + * Get the mask that determines which columns within the flat region + * will be visited. + * + * @return a 2D mask + */ + public Mask2D getMask() { + return mask; + } + + /** + * Set the mask that determines which columns within the flat region + * will be visited. + * + * @param mask a 2D mask + */ + public void setMask(Mask2D mask) { + checkNotNull(mask); + this.mask = mask; + } + + @Override + public Operation resume() throws WorldEditException { + for (Vector2D column : flatRegion.asFlatRegion()) { + // Abort if we are underground + if (function.isGround(column.toVector(maxY + 1))) { + return null; + } + + boolean found = false; + int groundY = 0; + for (int y = maxY; y >= minY; --y) { + Vector test = column.toVector(y); + if (!found) { + if (function.isGround(test)) { + found = true; + groundY = y; + } + } + + if (found) { + if (!function.apply(test, groundY - y)) { + break; + } + } + } + } + + return null; + } + + @Override + public void cancel() { + } +}