Fixes and changes to forest/forestgen.

* Sync up implementations of the two commands.
* Fix generating trees in spots with replaceable blocks.
* Make message when you mistype tree-type arg more correct.

Fixes WORLDEDIT-3869.
This commit is contained in:
wizjany 2019-03-20 21:05:11 -04:00
parent 1934006d14
commit 9b473cecbd
5 changed files with 38 additions and 49 deletions

View File

@ -44,6 +44,7 @@ import com.sk89q.worldedit.function.block.BlockDistributionCounter;
import com.sk89q.worldedit.function.block.BlockReplace; import com.sk89q.worldedit.function.block.BlockReplace;
import com.sk89q.worldedit.function.block.Counter; import com.sk89q.worldedit.function.block.Counter;
import com.sk89q.worldedit.function.block.Naturalizer; 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.generator.GardenPatchGenerator;
import com.sk89q.worldedit.function.mask.BlockMask; import com.sk89q.worldedit.function.mask.BlockMask;
import com.sk89q.worldedit.function.mask.BlockStateMask; 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 * @throws MaxChangedBlocksException thrown if too many blocks are changed
*/ */
public int makeForest(BlockVector3 basePosition, int size, double density, TreeGenerator.TreeType treeType) throws MaxChangedBlocksException { 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) { * Makes a forest.
for (int z = basePosition.getBlockZ() - size; z <= basePosition.getBlockZ() *
+ size; ++z) { * @param region the region to generate trees in
// Don't want to be in the ground * @param density between 0 and 1, inclusive
if (!getBlock(BlockVector3.at(x, basePosition.getBlockY(), z)).getBlockType().getMaterial().isAir()) { * @param treeType the tree type
continue; * @return number of trees created
} * @throws MaxChangedBlocksException thrown if too many blocks are changed
// The gods don't want a tree here */
if (Math.random() >= density) { public int makeForest(Region region, double density, TreeGenerator.TreeType treeType) throws MaxChangedBlocksException {
continue; ForestGenerator generator = new ForestGenerator(this, treeType);
} // def 0.05 GroundFunction ground = new GroundFunction(new ExistingBlockMask(this), generator);
LayerVisitor visitor = new LayerVisitor(asFlatRegion(region), minimumBlockY(region), maximumBlockY(region), ground);
for (int y = basePosition.getBlockY(); y >= basePosition.getBlockY() - 10; --y) { visitor.setMask(new NoiseFilter2D(new RandomNoise(), density));
// Check if we hit the ground Operations.completeLegacy(visitor);
BlockType t = getBlock(BlockVector3.at(x, y, z)).getBlockType(); return ground.getAffected();
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;
} }
/** /**

View File

@ -197,7 +197,8 @@ public class GenerationCommands {
) )
@CommandPermissions("worldedit.generation.forest") @CommandPermissions("worldedit.generation.forest")
@Logging(POSITION) @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; density = density / 100;
int affected = editSession.makeForest(session.getPlacementPosition(player), size, density, type); int affected = editSession.makeForest(session.getPlacementPosition(player), size, density, type);
player.print(affected + " trees created."); player.print(affected + " trees created.");

View File

@ -445,14 +445,8 @@ public class RegionCommands {
@Logging(REGION) @Logging(REGION)
public void forest(Player player, EditSession editSession, @Selection Region region, @Optional("tree") TreeType type, 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 { @Optional("5") @Range(min = 0, max = 100) double density) throws WorldEditException {
density = density / 100; int affected = editSession.makeForest(region, density / 100, type);
ForestGenerator generator = new ForestGenerator(editSession, type); player.print(affected + " trees created.");
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.");
} }
@Command( @Command(

View File

@ -54,15 +54,19 @@ public class ForestGenerator implements RegionFunction {
BlockType t = block.getBlockType(); BlockType t = block.getBlockType();
if (t == BlockTypes.GRASS_BLOCK || t == BlockTypes.DIRT) { if (t == BlockTypes.GRASS_BLOCK || t == BlockTypes.DIRT) {
treeType.generate(editSession, position.add(0, 1, 0)); return treeType.generate(editSession, position.add(0, 1, 0));
return true; } else if (t.getMaterial().isReplacedDuringPlacement()) {
} else if (t == BlockTypes.GRASS || t == BlockTypes.DEAD_BUSH || t == BlockTypes.POPPY || t == BlockTypes.DANDELION) { // TODO: This list needs to be moved // 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()); editSession.setBlock(position, BlockTypes.AIR.getDefaultState());
treeType.generate(editSession, position); // and then trick the generator here by directly setting into the world
return true; editSession.getWorld().setBlock(position, BlockTypes.AIR.getDefaultState());
} else if (t == BlockTypes.SNOW) { // so that now the generator can generate the tree
editSession.setBlock(position, BlockTypes.AIR.getDefaultState()); boolean success = treeType.generate(editSession, position);
return false; if (!success) {
editSession.setBlock(position, block); // restore on failure
}
return success;
} else { // Trees won't grow on this! } else { // Trees won't grow on this!
return false; return false;
} }

View File

@ -52,6 +52,7 @@ import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.registry.BiomeRegistry; import com.sk89q.worldedit.world.registry.BiomeRegistry;
import sun.reflect.generics.tree.Tree;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@ -290,7 +291,8 @@ public class WorldEditBinding extends BindingHelper {
return type; return type;
} else { } else {
throw new ParameterException( 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 { } else {
return TreeType.TREE; return TreeType.TREE;