From c87b1acbad4f0ae6a93e023b0f45333fc2aa208c Mon Sep 17 00:00:00 2001 From: sk89q Date: Sat, 1 Mar 2014 12:37:18 -0800 Subject: [PATCH] Added FlatRegionApplicator for FlatRegionFunctions. --- .../java/com/sk89q/worldedit/EditSession.java | 6 +- .../worldedit/commands/RegionCommands.java | 45 ++++------- .../operation/FlatRegionApplicator.java | 75 +++++++++++++++++++ .../operation/GroundFindingFunction.java | 50 +++++++++---- .../sk89q/worldedit/operation/Operation.java | 49 ++++++++++++ .../worldedit/operation/OperationHelper.java | 64 ++++++++++++++++ 6 files changed, 241 insertions(+), 48 deletions(-) create mode 100644 src/main/java/com/sk89q/worldedit/operation/FlatRegionApplicator.java create mode 100644 src/main/java/com/sk89q/worldedit/operation/Operation.java create mode 100644 src/main/java/com/sk89q/worldedit/operation/OperationHelper.java diff --git a/src/main/java/com/sk89q/worldedit/EditSession.java b/src/main/java/com/sk89q/worldedit/EditSession.java index ae61ff7e1..db9cbdbba 100644 --- a/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/src/main/java/com/sk89q/worldedit/EditSession.java @@ -2752,14 +2752,16 @@ public class EditSession { * @param treeGenerator the tree generator * @return number of trees created * @throws MaxChangedBlocksException + * @deprecated Use {@link com.sk89q.worldedit.generator.ForestGenerator} with a + * {@link com.sk89q.worldedit.operation.FlatRegionApplicator} */ + @Deprecated public int makeForest(Iterable it, int upperY, int lowerY, double density, TreeGenerator treeGenerator) throws WorldEditException { ForestGenerator generator = new ForestGenerator(this, treeGenerator); - generator.setLowerY(lowerY); - generator.setUpperY(upperY); + generator.setRange(lowerY, upperY); generator.setDensity(density); int affected = 0; diff --git a/src/main/java/com/sk89q/worldedit/commands/RegionCommands.java b/src/main/java/com/sk89q/worldedit/commands/RegionCommands.java index ed89e9ea6..be43ca045 100644 --- a/src/main/java/com/sk89q/worldedit/commands/RegionCommands.java +++ b/src/main/java/com/sk89q/worldedit/commands/RegionCommands.java @@ -30,7 +30,10 @@ import com.sk89q.worldedit.expression.ExpressionException; import com.sk89q.worldedit.filtering.GaussianKernel; import com.sk89q.worldedit.filtering.HeightMapFilter; import com.sk89q.worldedit.generator.FloraPlacer; +import com.sk89q.worldedit.generator.ForestGenerator; import com.sk89q.worldedit.masks.Mask; +import com.sk89q.worldedit.operation.FlatRegionApplicator; +import com.sk89q.worldedit.operation.OperationHelper; import com.sk89q.worldedit.patterns.Pattern; import com.sk89q.worldedit.patterns.SingleBlockPattern; import com.sk89q.worldedit.regions.*; @@ -538,20 +541,15 @@ public class RegionCommands { } Region region = session.getSelection(player.getWorld()); - FlatRegion flatRegion; - if (region instanceof FlatRegion) { - flatRegion = (FlatRegion) region; - } else { - player.print("(The given region is not a 'flat region', so a cuboid region will be used instead.)"); - flatRegion = CuboidRegion.makeCuboid(region); - } + ForestGenerator function = new ForestGenerator(editSession, new TreeGenerator(type)); + function.setRange(region); + function.setDensity(density); - int upperY = flatRegion.getMaximumY() + 1; // Increase by 1 to have trees generate above the selection 1 block - int lowerY = flatRegion.getMinimumY(); + FlatRegionApplicator operation = new FlatRegionApplicator(region, function); + OperationHelper.complete(operation); - int affected = editSession.makeForest(flatRegion.asFlatRegion(), upperY, lowerY, density, new TreeGenerator(type)); - player.print(affected + " trees created."); + player.print(operation.getAffected() + " trees created."); } @Command( @@ -567,28 +565,15 @@ public class RegionCommands { double density = args.argsLength() > 0 ? args.getDouble(0) / 100 : 0.1; Region region = session.getSelection(player.getWorld()); - FlatRegion flatRegion; - if (region instanceof FlatRegion) { - flatRegion = (FlatRegion) region; - } else { - player.print("(The given region is not a 'flat region', so a cuboid region will be used instead.)"); - flatRegion = CuboidRegion.makeCuboid(region); - } + FloraPlacer function = new FloraPlacer(editSession); + function.setRange(region); + function.setDensity(density); - FloraPlacer generator = new FloraPlacer(editSession); - generator.setLowerY(flatRegion.getMinimumY()); - generator.setUpperY(flatRegion.getMaximumY()); - generator.setDensity(density); - int affected = 0; + FlatRegionApplicator operation = new FlatRegionApplicator(region, function); + OperationHelper.complete(operation); - for (Vector2D pt : flatRegion.asFlatRegion()) { - if (generator.apply(pt)) { - affected++; - } - } - - player.print(affected + " flora created."); + player.print(operation.getAffected() + " flora created."); } } diff --git a/src/main/java/com/sk89q/worldedit/operation/FlatRegionApplicator.java b/src/main/java/com/sk89q/worldedit/operation/FlatRegionApplicator.java new file mode 100644 index 000000000..2173936b0 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/operation/FlatRegionApplicator.java @@ -0,0 +1,75 @@ +/* + * 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.operation; + +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.FlatRegion; +import com.sk89q.worldedit.regions.Region; + +/** + * Utility class to apply region functions to {@link com.sk89q.worldedit.regions.Region}. + */ +public class FlatRegionApplicator implements Operation { + + private final Region region; + private final FlatRegionFunction function; + private int affected = 0; + + public FlatRegionApplicator(Region region, FlatRegionFunction function) { + this.region = region; + this.function = function; + } + + /** + * Get the number of affected objects. + * + * @return the number of affected + */ + public int getAffected() { + return affected; + } + + @Override + public Operation resume() throws WorldEditException { + FlatRegion flatRegion; + + if (region instanceof FlatRegion) { + flatRegion = (FlatRegion) region; + } else { + flatRegion = CuboidRegion.makeCuboid(region); + } + + for (Vector2D pt : flatRegion.asFlatRegion()) { + if (function.apply(pt)) { + affected++; + } + } + + return null; + } + + @Override + public void cancel() { + } + +} + diff --git a/src/main/java/com/sk89q/worldedit/operation/GroundFindingFunction.java b/src/main/java/com/sk89q/worldedit/operation/GroundFindingFunction.java index cc4b21bb6..b503e3b4b 100644 --- a/src/main/java/com/sk89q/worldedit/operation/GroundFindingFunction.java +++ b/src/main/java/com/sk89q/worldedit/operation/GroundFindingFunction.java @@ -19,9 +19,13 @@ package com.sk89q.worldedit.operation; -import com.sk89q.worldedit.*; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BlockID; +import com.sk89q.worldedit.regions.Region; /** * An abstract implementation of {@link com.sk89q.worldedit.operation.FlatRegionFunction} @@ -68,16 +72,6 @@ public abstract class GroundFindingFunction implements FlatRegionFunction { return upperY; } - /** - * Set the upper Y coordinate to start the ground search from. - * - * @param upperY the upper Y coordinate - */ - public void setUpperY(int upperY) { - this.upperY = upperY; - checkYBounds(); - } - /** * Get the lower Y coordinate to end the ground search at. * @@ -88,19 +82,43 @@ public abstract class GroundFindingFunction implements FlatRegionFunction { } /** - * Set the lower Y coordinate to end the ground search at. + * Set the range of Y coordinates to perform a search for ground within. * - * @return lowerY the lower Y coordinate + * @param lowerY the lower Y coordinate + * @param upperY the upper Y coordinate (upperY >= lowerY) */ - public void setLowerY(int lowerY) { + public void setRange(int lowerY, int upperY) { this.lowerY = lowerY; + this.upperY = upperY; checkYBounds(); } + /** + * Set the range of Y coordinates to perform a search for ground within from + * the minimum and maximum Y of the given region. + * + * @param region the region + */ + public void setRange(Region region) { + setRange(region.getMinimumPoint().getBlockY(), region.getMaximumPoint().getBlockY()); + } + + /** + * Increase the upper Y by the given amount. + * + * @param y the amount to increase the upper Y by + */ + public void raiseCeiling(int y) { + if (y <= 0) { + throw new IllegalArgumentException("Can't raise by a negative"); + } + upperY += y; + } + @Override public final boolean apply(Vector2D pt) throws WorldEditException { // Don't want to be in the ground - if (!editSession.getBlock(pt.toVector(upperY)).isAir()) { + if (!editSession.getBlock(pt.toVector(upperY + 1)).isAir()) { return false; } @@ -108,7 +126,7 @@ public abstract class GroundFindingFunction implements FlatRegionFunction { return false; } - for (int y = upperY; y >= lowerY; --y) { + for (int y = upperY + 1; y >= lowerY; --y) { Vector testPt = pt.toVector(y); BaseBlock block = editSession.getBlock(testPt); diff --git a/src/main/java/com/sk89q/worldedit/operation/Operation.java b/src/main/java/com/sk89q/worldedit/operation/Operation.java new file mode 100644 index 000000000..0e6fc5f11 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/operation/Operation.java @@ -0,0 +1,49 @@ +/* + * 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.operation; + +import com.sk89q.worldedit.WorldEditException; + +/** + * An task that may be split into multiple steps to be run sequentially immediately + * or at a varying or fixed interval. Operations should attempt to break apart tasks + * into smaller tasks that can be completed in quicker successions. + */ +public interface Operation { + + /** + * Complete the next step. If this method returns true, then the method may be + * called again in the future, or possibly never. If this method returns false, + * then this method should not be called again. + * + * @return another operation to run that operation again, or null to stop + * @throws WorldEditException an error + */ + Operation resume() throws WorldEditException; + + /** + * Abort the current task. After the this method is called, {@link #resume()} should + * not be called at any point in the future. This method should not be called after + * successful completion of the operation. This method must be called if + * the operation is interrupted before completion. + */ + void cancel(); + +} diff --git a/src/main/java/com/sk89q/worldedit/operation/OperationHelper.java b/src/main/java/com/sk89q/worldedit/operation/OperationHelper.java new file mode 100644 index 000000000..76c372445 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/operation/OperationHelper.java @@ -0,0 +1,64 @@ +/* + * 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.operation; + +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.WorldEditException; + +/** + * Operation helper methods. + */ +public final class OperationHelper { + + private OperationHelper() { + } + + /** + * Complete a given operation synchronously until it completes. + * + * @param op operation to execute + * @throws WorldEditException WorldEdit exception + */ + public static void complete(Operation op) throws WorldEditException { + while (op != null) { + op = op.resume(); + } + } + + /** + * Complete a given operation synchronously until it completes. Catch all + * errors that is not {@link MaxChangedBlocksException} for legacy reasons. + * + * @param op operation to execute + * @throws MaxChangedBlocksException thrown when too many blocks have been changed + */ + public static void completeLegacy(Operation op) throws MaxChangedBlocksException { + while (op != null) { + try { + op = op.resume(); + } catch (MaxChangedBlocksException e) { + throw e; + } catch (WorldEditException e) { + throw new RuntimeException(e); + } + } + } + +}