diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index 39c72c93f..07d3d084c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -44,6 +44,7 @@ import com.sk89q.worldedit.function.block.BlockDistributionCounter; import com.sk89q.worldedit.function.block.BlockReplace; import com.sk89q.worldedit.function.block.Counter; import com.sk89q.worldedit.function.block.Naturalizer; +import com.sk89q.worldedit.function.generator.ForestGenerator; import com.sk89q.worldedit.function.generator.GardenPatchGenerator; import com.sk89q.worldedit.function.mask.BlockMask; import com.sk89q.worldedit.function.mask.BlockStateMask; @@ -1832,38 +1833,25 @@ public class EditSession implements Extent, AutoCloseable { * @throws MaxChangedBlocksException thrown if too many blocks are changed */ public int makeForest(BlockVector3 basePosition, int size, double density, TreeGenerator.TreeType treeType) throws MaxChangedBlocksException { - int affected = 0; + return makeForest(CuboidRegion.fromCenter(basePosition, size), density, treeType); + } - for (int x = basePosition.getBlockX() - size; x <= basePosition.getBlockX() - + size; ++x) { - for (int z = basePosition.getBlockZ() - size; z <= basePosition.getBlockZ() - + size; ++z) { - // Don't want to be in the ground - if (!getBlock(BlockVector3.at(x, basePosition.getBlockY(), z)).getBlockType().getMaterial().isAir()) { - continue; - } - // The gods don't want a tree here - if (Math.random() >= density) { - continue; - } // def 0.05 - - for (int y = basePosition.getBlockY(); y >= basePosition.getBlockY() - 10; --y) { - // Check if we hit the ground - BlockType t = getBlock(BlockVector3.at(x, y, z)).getBlockType(); - if (t == BlockTypes.GRASS_BLOCK || t == BlockTypes.DIRT) { - treeType.generate(this, BlockVector3.at(x, y + 1, z)); - ++affected; - break; - } else if (t == BlockTypes.SNOW) { - setBlock(BlockVector3.at(x, y, z), BlockTypes.AIR.getDefaultState()); - } else if (!t.getMaterial().isAir()) { // Trees won't grow on this! - break; - } - } - } - } - - return affected; + /** + * Makes a forest. + * + * @param region the region to generate trees in + * @param density between 0 and 1, inclusive + * @param treeType the tree type + * @return number of trees created + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int makeForest(Region region, double density, TreeGenerator.TreeType treeType) throws MaxChangedBlocksException { + ForestGenerator generator = new ForestGenerator(this, treeType); + GroundFunction ground = new GroundFunction(new ExistingBlockMask(this), generator); + LayerVisitor visitor = new LayerVisitor(asFlatRegion(region), minimumBlockY(region), maximumBlockY(region), ground); + visitor.setMask(new NoiseFilter2D(new RandomNoise(), density)); + Operations.completeLegacy(visitor); + return ground.getAffected(); } /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java index d16edd976..971fb58d8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java @@ -197,7 +197,8 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.forest") @Logging(POSITION) - public void forestGen(Player player, LocalSession session, EditSession editSession, @Optional("10") int size, @Optional("tree") TreeType type, @Optional("5") double density) throws WorldEditException { + public void forestGen(Player player, LocalSession session, EditSession editSession, @Optional("10") int size, + @Optional("tree") TreeType type, @Optional("5") @Range(min = 0, max = 100) double density) throws WorldEditException { density = density / 100; int affected = editSession.makeForest(session.getPlacementPosition(player), size, density, type); player.print(affected + " trees created."); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index b02b2ba42..1e5fb3fee 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java @@ -445,14 +445,8 @@ public class RegionCommands { @Logging(REGION) public void forest(Player player, EditSession editSession, @Selection Region region, @Optional("tree") TreeType type, @Optional("5") @Range(min = 0, max = 100) double density) throws WorldEditException { - density = density / 100; - ForestGenerator generator = new ForestGenerator(editSession, type); - GroundFunction ground = new GroundFunction(new ExistingBlockMask(editSession), generator); - LayerVisitor visitor = new LayerVisitor(asFlatRegion(region), minimumBlockY(region), maximumBlockY(region), ground); - visitor.setMask(new NoiseFilter2D(new RandomNoise(), density)); - Operations.completeLegacy(visitor); - - player.print(ground.getAffected() + " trees created."); + int affected = editSession.makeForest(region, density / 100, type); + player.print(affected + " trees created."); } @Command( diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/ForestGenerator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/ForestGenerator.java index 231cfc79e..e45acd24b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/ForestGenerator.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/ForestGenerator.java @@ -54,15 +54,19 @@ public class ForestGenerator implements RegionFunction { BlockType t = block.getBlockType(); if (t == BlockTypes.GRASS_BLOCK || t == BlockTypes.DIRT) { - treeType.generate(editSession, position.add(0, 1, 0)); - return true; - } else if (t == BlockTypes.GRASS || t == BlockTypes.DEAD_BUSH || t == BlockTypes.POPPY || t == BlockTypes.DANDELION) { // TODO: This list needs to be moved + return treeType.generate(editSession, position.add(0, 1, 0)); + } else if (t.getMaterial().isReplacedDuringPlacement()) { + // since the implementation's tree generators generally don't generate in non-air spots, + // we trick editsession history here in the first call editSession.setBlock(position, BlockTypes.AIR.getDefaultState()); - treeType.generate(editSession, position); - return true; - } else if (t == BlockTypes.SNOW) { - editSession.setBlock(position, BlockTypes.AIR.getDefaultState()); - return false; + // and then trick the generator here by directly setting into the world + editSession.getWorld().setBlock(position, BlockTypes.AIR.getDefaultState()); + // so that now the generator can generate the tree + boolean success = treeType.generate(editSession, position); + if (!success) { + editSession.setBlock(position, block); // restore on failure + } + return success; } else { // Trees won't grow on this! return false; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/WorldEditBinding.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/WorldEditBinding.java index 267dfb7bf..3a8a895b9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/WorldEditBinding.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/WorldEditBinding.java @@ -52,6 +52,7 @@ import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.registry.BiomeRegistry; +import sun.reflect.generics.tree.Tree; import java.util.Arrays; import java.util.Collection; @@ -290,7 +291,8 @@ public class WorldEditBinding extends BindingHelper { return type; } else { throw new ParameterException( - String.format("Can't recognize tree type '%s' -- choose from: %s", input, Arrays.toString(TreeType.values()))); + String.format("Can't recognize tree type '%s' -- choose from: %s", input, + TreeType.getPrimaryAliases())); } } else { return TreeType.TREE;