diff --git a/src/main/java/com/sk89q/worldedit/EditSession.java b/src/main/java/com/sk89q/worldedit/EditSession.java index 1f49bd86a..3d9ecdd2e 100644 --- a/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/src/main/java/com/sk89q/worldedit/EditSession.java @@ -45,8 +45,6 @@ import com.sk89q.worldedit.masks.*; import com.sk89q.worldedit.patterns.Pattern; import com.sk89q.worldedit.patterns.SingleBlockPattern; import com.sk89q.worldedit.regions.*; -import com.sk89q.worldedit.regions.search.GroundSearch; -import com.sk89q.worldedit.regions.search.MaskingGroundSearch; import com.sk89q.worldedit.shape.ArbitraryBiomeShape; import com.sk89q.worldedit.shape.ArbitraryShape; import com.sk89q.worldedit.shape.RegionShape; @@ -58,6 +56,7 @@ import java.util.*; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.regions.Regions.asFlatRegion; import static com.sk89q.worldedit.regions.Regions.maximumBlockY; import static com.sk89q.worldedit.regions.Regions.minimumBlockY; @@ -1155,17 +1154,13 @@ public class EditSession { checkNotNull(region); checkNotNull(pattern); - int lowerY = region.getMinimumPoint().getBlockY(); - int upperY = region.getMaximumPoint().getBlockY(); - BlockReplace replace = new BlockReplace(this, pattern); RegionOffset offset = new RegionOffset(new Vector(0, 1, 0), replace); - GroundSearch search = new MaskingGroundSearch(this, new ExistingBlockMask()); - GroundFunction groundFunction = new GroundFunction(search, lowerY, upperY, offset); - FlatRegionVisitor operation = new FlatRegionVisitor(Regions.asFlatRegion(region), groundFunction); - OperationHelper.completeLegacy(operation); - - return operation.getAffected(); + GroundFunction ground = new GroundFunction(this, offset); + LayerVisitor visitor = new LayerVisitor( + this, asFlatRegion(region), minimumBlockY(region), maximumBlockY(region), ground); + OperationHelper.completeLegacy(visitor); + return ground.getAffected(); } /** @@ -1181,7 +1176,8 @@ public class EditSession { Naturalizer naturalizer = new Naturalizer(this); FlatRegion flatRegion = Regions.asFlatRegion(region); - LayerVisitor visitor = new LayerVisitor(flatRegion, minimumBlockY(region), maximumBlockY(region), naturalizer); + LayerVisitor visitor = new LayerVisitor( + this, flatRegion, minimumBlockY(region), maximumBlockY(region), naturalizer); OperationHelper.completeLegacy(visitor); return naturalizer.getAffected(); } @@ -1948,28 +1944,18 @@ public class EditSession { generator.setPlant(GardenPatchGenerator.getPumpkinPattern()); // In a region of the given radius - Region region = new CuboidRegion( + FlatRegion region = new CuboidRegion( getWorld(), // Causes clamping of Y range position.add(-apothem, -5, -apothem), position.add(apothem, 10, apothem)); - - int lowerY = region.getMinimumPoint().getBlockY(); - int upperY = region.getMaximumPoint().getBlockY(); double density = 0.02; - // We want to find the ground - GroundSearch search = new MaskingGroundSearch(this, new ExistingBlockMask()); - GroundFunction groundFunction = new GroundFunction(search, lowerY, upperY, generator); - - // We don't want to place a patch in every column - Mask2D mask = new NoiseFilter2D(new RandomNoise(), density); - FlatRegionMaskingFilter filter = new FlatRegionMaskingFilter(this, mask, groundFunction); - - // Generate those patches! - FlatRegionVisitor operation = new FlatRegionVisitor(Regions.asFlatRegion(region), filter); - OperationHelper.completeLegacy(operation); - - return operation.getAffected(); + GroundFunction ground = new GroundFunction(this, generator); + LayerVisitor visitor = new LayerVisitor( + this, region, minimumBlockY(region), maximumBlockY(region), ground); + visitor.setMask(new NoiseFilter2D(new RandomNoise(), density)); + OperationHelper.completeLegacy(visitor); + return ground.getAffected(); } /** @@ -2018,40 +2004,6 @@ public class EditSession { return affected; } - /** - * Makes a forest. - * - * @param it an iterator over the points within the region - * @param upperY the Y to start from (upperY >= lowerY), inclusive - * @param lowerY the Y to end at (upperY >= lowerY), inclusive - * @param density density of the forest - * @param treeGenerator the tree generator - * @return number of trees created - * @throws MaxChangedBlocksException - * @deprecated Use {@link com.sk89q.worldedit.function.generator.ForestGenerator} with a - * {@link com.sk89q.worldedit.function.visitor.FlatRegionVisitor} - */ - @Deprecated - public int makeForest(Iterable it, int upperY, int lowerY, - double density, TreeGenerator treeGenerator) - throws WorldEditException { - - ForestGenerator generator = new ForestGenerator(this, treeGenerator); - GroundSearch search = new MaskingGroundSearch(this, new ExistingBlockMask()); - GroundFunction groundFunction = new GroundFunction(search, lowerY, upperY, generator); - Mask2D mask = new NoiseFilter2D(new RandomNoise(), density); - FlatRegionMaskingFilter filter = new FlatRegionMaskingFilter(this, mask, groundFunction); - - int affected = 0; - for (Vector2D pt : it) { - if (filter.apply(pt)) { - affected++; - } - } - - return affected; - } - /** * Get the block distribution inside a region. * diff --git a/src/main/java/com/sk89q/worldedit/commands/RegionCommands.java b/src/main/java/com/sk89q/worldedit/commands/RegionCommands.java index 01a6ad7b1..9ace6d32b 100644 --- a/src/main/java/com/sk89q/worldedit/commands/RegionCommands.java +++ b/src/main/java/com/sk89q/worldedit/commands/RegionCommands.java @@ -29,29 +29,28 @@ import com.sk89q.worldedit.blocks.BlockID; import com.sk89q.worldedit.expression.ExpressionException; import com.sk89q.worldedit.filtering.GaussianKernel; import com.sk89q.worldedit.filtering.HeightMapFilter; +import com.sk89q.worldedit.function.GroundFunction; import com.sk89q.worldedit.function.generator.FloraGenerator; import com.sk89q.worldedit.function.generator.ForestGenerator; -import com.sk89q.worldedit.masks.ExistingBlockMask; -import com.sk89q.worldedit.masks.Mask2D; -import com.sk89q.worldedit.masks.NoiseFilter2D; -import com.sk89q.worldedit.function.FlatRegionMaskingFilter; -import com.sk89q.worldedit.function.GroundFunction; -import com.sk89q.worldedit.regions.search.GroundSearch; -import com.sk89q.worldedit.regions.search.MaskingGroundSearch; -import com.sk89q.worldedit.util.noise.RandomNoise; -import com.sk89q.worldedit.function.visitor.FlatRegionVisitor; -import com.sk89q.worldedit.masks.Mask; import com.sk89q.worldedit.function.operation.OperationHelper; +import com.sk89q.worldedit.function.visitor.LayerVisitor; +import com.sk89q.worldedit.masks.Mask; +import com.sk89q.worldedit.masks.NoiseFilter2D; import com.sk89q.worldedit.patterns.Pattern; import com.sk89q.worldedit.patterns.SingleBlockPattern; -import com.sk89q.worldedit.regions.*; +import com.sk89q.worldedit.regions.ConvexPolyhedralRegion; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.RegionOperationException; import com.sk89q.worldedit.util.TreeGenerator; +import com.sk89q.worldedit.util.noise.RandomNoise; import java.util.ArrayList; import java.util.List; import java.util.Set; import static com.sk89q.minecraft.util.commands.Logging.LogMode.*; +import static com.sk89q.worldedit.regions.Regions.*; /** * Region related commands. @@ -551,20 +550,13 @@ public class RegionCommands { Region region = session.getSelection(player.getWorld()); ForestGenerator generator = new ForestGenerator(editSession, new TreeGenerator(type)); + GroundFunction ground = new GroundFunction(editSession, generator); + LayerVisitor visitor = new LayerVisitor( + editSession, asFlatRegion(region), minimumBlockY(region), maximumBlockY(region), ground); + visitor.setMask(new NoiseFilter2D(new RandomNoise(), density)); + OperationHelper.completeLegacy(visitor); - int lowerY = region.getMinimumPoint().getBlockY(); - int upperY = region.getMaximumPoint().getBlockY(); - - GroundSearch search = new MaskingGroundSearch(editSession, new ExistingBlockMask()); - GroundFunction groundFunction = new GroundFunction(search, lowerY, upperY, generator); - Mask2D mask = new NoiseFilter2D(new RandomNoise(), density); - FlatRegionMaskingFilter filter = new FlatRegionMaskingFilter(editSession, mask, groundFunction); - - // Execute - FlatRegionVisitor operation = new FlatRegionVisitor(Regions.asFlatRegion(region), filter); - OperationHelper.complete(operation); - - player.print(operation.getAffected() + " trees created."); + player.print(ground.getAffected() + " trees created."); } @Command( @@ -581,20 +573,13 @@ public class RegionCommands { Region region = session.getSelection(player.getWorld()); FloraGenerator generator = new FloraGenerator(editSession); + GroundFunction ground = new GroundFunction(editSession, generator); + LayerVisitor visitor = new LayerVisitor( + editSession, asFlatRegion(region), minimumBlockY(region), maximumBlockY(region), ground); + visitor.setMask(new NoiseFilter2D(new RandomNoise(), density)); + OperationHelper.completeLegacy(visitor); - int lowerY = region.getMinimumPoint().getBlockY(); - int upperY = region.getMaximumPoint().getBlockY(); - - GroundSearch search = new MaskingGroundSearch(editSession, new ExistingBlockMask()); - GroundFunction groundFunction = new GroundFunction(search, lowerY, upperY, generator); - Mask2D mask = new NoiseFilter2D(new RandomNoise(), density); - FlatRegionMaskingFilter filter = new FlatRegionMaskingFilter(editSession, mask, groundFunction); - - // Execute - FlatRegionVisitor operation = new FlatRegionVisitor(Regions.asFlatRegion(region), filter); - OperationHelper.complete(operation); - - player.print(operation.getAffected() + " flora created."); + player.print(ground.getAffected() + " flora created."); } } diff --git a/src/main/java/com/sk89q/worldedit/function/GroundFunction.java b/src/main/java/com/sk89q/worldedit/function/GroundFunction.java index ced5546ff..ee7af86ba 100644 --- a/src/main/java/com/sk89q/worldedit/function/GroundFunction.java +++ b/src/main/java/com/sk89q/worldedit/function/GroundFunction.java @@ -19,46 +19,79 @@ package com.sk89q.worldedit.function; +import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.Vector2D; import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.regions.search.GroundSearch; +import com.sk89q.worldedit.masks.ExistingBlockMask; +import com.sk89q.worldedit.masks.Mask; -import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; /** - * Accepts 2D coordinates to columns, finds the first ground block in each - * column, and applies the given {@link RegionFunction} onto the ground blocks. + * Applies a {@link RegionFunction} to the first ground block. */ -public class GroundFunction implements FlatRegionFunction { +public class GroundFunction implements LayerFunction { + private final EditSession editSession; private final RegionFunction function; - private GroundSearch groundSearch; - private int minY; - private int maxY; + private Mask mask = new ExistingBlockMask(); + private int affected; /** - * Create a new instance. + * Create a new ground function. * - * @param groundSearch the ground search implementation - * @param minY the minimum Y (inclusive) - * @param maxY the maximum Y (inclusive) - * @param function the function to apply on ground blocks + * @param editSession an edit session + * @param function the function to apply */ - public GroundFunction(GroundSearch groundSearch, int minY, int maxY, RegionFunction function) { + public GroundFunction(EditSession editSession, RegionFunction function) { + checkNotNull(editSession); checkNotNull(function); - checkNotNull(groundSearch); - checkArgument(minY <= maxY, "minY <= maxY required"); + this.editSession = editSession; this.function = function; - this.groundSearch = groundSearch; - this.minY = minY; - this.maxY = maxY; + } + + /** + * Get the mask that determines what the ground consists of. + * + * @return a mask + */ + public Mask getMask() { + return mask; + } + + /** + * Set the mask that determines what the ground consists of. + * + * @param mask a mask + */ + public void setMask(Mask mask) { + checkNotNull(mask); + this.mask = mask; + } + + /** + * Get the number of affected objects. + * + * @return the number of affected + */ + public int getAffected() { + return affected; } @Override - public boolean apply(Vector2D pt) throws WorldEditException { - Vector ground = groundSearch.findGround(pt.toVector(maxY), minY); - return ground != null && function.apply(ground); + public boolean isGround(Vector position) { + return mask.matches(editSession, position); } + + @Override + public boolean apply(Vector position, int depth) throws WorldEditException { + if (depth == 0) { + if (function.apply(position)) { + affected++; + } + } + + return false; + } + } diff --git a/src/main/java/com/sk89q/worldedit/function/visitor/LayerVisitor.java b/src/main/java/com/sk89q/worldedit/function/visitor/LayerVisitor.java index 759f12360..3872f4f4a 100644 --- a/src/main/java/com/sk89q/worldedit/function/visitor/LayerVisitor.java +++ b/src/main/java/com/sk89q/worldedit/function/visitor/LayerVisitor.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.function.visitor; +import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector2D; import com.sk89q.worldedit.WorldEditException; @@ -41,6 +42,7 @@ import static com.google.common.base.Preconditions.checkNotNull; */ public class LayerVisitor implements Operation { + private final EditSession editSession; private final FlatRegion flatRegion; private final LayerFunction function; private Mask2D mask = new DummyMask2D(); @@ -55,11 +57,13 @@ public class LayerVisitor implements Operation { * @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) { + public LayerVisitor(EditSession editSession, FlatRegion flatRegion, int minY, int maxY, LayerFunction function) { + checkNotNull(editSession); checkNotNull(flatRegion); checkArgument(minY <= maxY, "minY <= maxY required"); checkNotNull(function); + this.editSession = editSession; this.flatRegion = flatRegion; this.minY = minY; this.maxY = maxY; @@ -90,6 +94,10 @@ public class LayerVisitor implements Operation { @Override public Operation resume() throws WorldEditException { for (Vector2D column : flatRegion.asFlatRegion()) { + if (!mask.matches(editSession, column)) { + continue; + } + // Abort if we are underground if (function.isGround(column.toVector(maxY + 1))) { return null; diff --git a/src/main/java/com/sk89q/worldedit/regions/search/AbstractGroundSearch.java b/src/main/java/com/sk89q/worldedit/regions/search/AbstractGroundSearch.java deleted file mode 100644 index 94ca881b9..000000000 --- a/src/main/java/com/sk89q/worldedit/regions/search/AbstractGroundSearch.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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.regions.search; - -import com.sk89q.worldedit.Vector; - -import static com.google.common.base.Preconditions.checkArgument; -import static net.minecraft.util.com.google.common.base.Preconditions.checkNotNull; - -/** - * Utility class for finding the first ground block starting from a certain - * position and traversing down. - */ -public abstract class AbstractGroundSearch implements GroundSearch { - - /** - * 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 - */ - protected abstract boolean isGround(Vector position); - - /** - * Find the ground block starting from the given position and traversing - * downward until reaching minY (inclusive). - *

- * The highest ground block that may be returned is at the location of - * the origin location. The lowest ground block that may be returned is - * in the same column as the origin but with y = minY. - *

- * It is possible for no ground block to be found if the given origin - * block is underground to begin with. - * - * @param origin the origin - * @param minY the minimum Y to end the search at - * @return the location of a ground block, or null if none was found - */ - public Vector findGround(Vector origin, int minY) { - checkNotNull(origin); - checkArgument(minY <= origin.getBlockY(), "minY <= origin Y"); - - // Don't want to be in the ground - if (isGround(origin.add(0, 1, 0))) { - return null; - } - - for (int y = origin.getBlockY() + 1; y >= minY; --y) { - Vector test = origin.setY(y); - if (isGround(test)) { - return test; - } - } - - return null; - } - -} diff --git a/src/main/java/com/sk89q/worldedit/regions/search/GroundSearch.java b/src/main/java/com/sk89q/worldedit/regions/search/GroundSearch.java deleted file mode 100644 index 0f0aa3ada..000000000 --- a/src/main/java/com/sk89q/worldedit/regions/search/GroundSearch.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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.regions.search; - -import com.sk89q.worldedit.Vector; - -/** - * Given a column of blocks in the world, finds the first ground block - * starting from a given Y. - */ -public interface GroundSearch { - - /** - * Find the ground block starting from the given position and traversing - * downward until reaching minY (inclusive). - *

- * The highest ground block that may be returned is at the location of - * the origin location. The lowest ground block that may be returned is - * in the same column as the origin but with y = minY. - *

- * It is possible for no ground block to be found if the given origin - * block is underground. - * - * @param origin the origin - * @param minY the minimum Y to end the search at - * @return the location of a ground block, or null if none was found - */ - Vector findGround(Vector origin, int minY); - -} diff --git a/src/main/java/com/sk89q/worldedit/regions/search/MaskingGroundSearch.java b/src/main/java/com/sk89q/worldedit/regions/search/MaskingGroundSearch.java deleted file mode 100644 index 27c196c22..000000000 --- a/src/main/java/com/sk89q/worldedit/regions/search/MaskingGroundSearch.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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.regions.search; - -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.masks.Mask; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * A ground finder that uses a {@link com.sk89q.worldedit.masks.Mask} to determine - * ground blocks. - */ -public class MaskingGroundSearch extends AbstractGroundSearch { - - private final EditSession editSession; - private final Mask mask; - - /** - * Create a new instance. - *

- * If a mask that matches non-ground blocks is available, it can be inverted with - * {@link com.sk89q.worldedit.masks.InvertedMask}. - * - * @param editSession an edit session - * @param mask a mask that matches ground blocks - */ - public MaskingGroundSearch(EditSession editSession, Mask mask) { - checkNotNull(editSession); - checkNotNull(mask); - - this.editSession = editSession; - this.mask = mask; - } - - /** - * Get the mask that matches ground blocks. - * - * @return the mask - */ - public Mask getMask() { - return mask; - } - - @Override - protected boolean isGround(Vector position) { - return mask.matches(editSession, position); - } - -}