diff --git a/src/main/java/com/sk89q/worldedit/EditSession.java b/src/main/java/com/sk89q/worldedit/EditSession.java index 2fe6a5cf7..f07c45ac8 100644 --- a/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/src/main/java/com/sk89q/worldedit/EditSession.java @@ -2662,12 +2662,16 @@ public class EditSession { throws WorldEditException { ForestGenerator generator = new ForestGenerator(this, treeGenerator); - generator.setRange(lowerY, upperY); - generator.setDensity(density); + + // And we want to scatter them + GroundScatterFunction scatter = new GroundScatterFunction(this, generator); + scatter.setDensity(density); + scatter.setRange(lowerY, upperY); + int affected = 0; for (Vector2D pt : it) { - if (generator.apply(pt)) { + if (scatter.apply(pt)) { affected++; } } diff --git a/src/main/java/com/sk89q/worldedit/commands/RegionCommands.java b/src/main/java/com/sk89q/worldedit/commands/RegionCommands.java index 469d3278b..be7725879 100644 --- a/src/main/java/com/sk89q/worldedit/commands/RegionCommands.java +++ b/src/main/java/com/sk89q/worldedit/commands/RegionCommands.java @@ -543,11 +543,16 @@ public class RegionCommands { Region region = session.getSelection(player.getWorld()); - ForestGenerator function = new ForestGenerator(editSession, new TreeGenerator(type)); - function.setRange(region); - function.setDensity(density); + // We want to generate trees + ForestGenerator generator = new ForestGenerator(editSession, new TreeGenerator(type)); - FlatRegionApplicator operation = new FlatRegionApplicator(region, function); + // And we want to scatter them + GroundScatterFunction scatter = new GroundScatterFunction(editSession, generator); + scatter.setDensity(density); + scatter.setRange(region); + + // Generate that forest + FlatRegionApplicator operation = new FlatRegionApplicator(region, scatter); OperationHelper.complete(operation); player.print(operation.getAffected() + " trees created."); diff --git a/src/main/java/com/sk89q/worldedit/generator/ForestGenerator.java b/src/main/java/com/sk89q/worldedit/generator/ForestGenerator.java index 60ba0a622..74b41d581 100644 --- a/src/main/java/com/sk89q/worldedit/generator/ForestGenerator.java +++ b/src/main/java/com/sk89q/worldedit/generator/ForestGenerator.java @@ -20,17 +20,18 @@ package com.sk89q.worldedit.generator; import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BlockID; +import com.sk89q.worldedit.operation.RegionFunction; import com.sk89q.worldedit.util.TreeGenerator; /** * Generates forests by searching for the ground starting from the given upper Y * coordinate for every column given. */ -public class ForestGenerator extends GroundGenerator { +public class ForestGenerator implements RegionFunction { private final TreeGenerator treeGenerator; private final EditSession editSession; @@ -42,25 +43,23 @@ public class ForestGenerator extends GroundGenerator { * @param treeGenerator a tree generator */ public ForestGenerator(EditSession editSession, TreeGenerator treeGenerator) { - super(editSession); this.editSession = editSession; this.treeGenerator = treeGenerator; } @Override - protected boolean apply(Vector pt, BaseBlock block) throws MaxChangedBlocksException { + public boolean apply(Vector position) throws WorldEditException { + BaseBlock block = editSession.getBlock(position); int t = block.getType(); if (t == BlockID.GRASS || t == BlockID.DIRT) { - treeGenerator.generate(editSession, pt.add(0, 1, 0)); + treeGenerator.generate(editSession, position.add(0, 1, 0)); return true; } else if (t == BlockID.SNOW) { - editSession.setBlock(pt, new BaseBlock(BlockID.AIR)); + editSession.setBlock(position, new BaseBlock(BlockID.AIR)); return false; } else { // Trees won't grow on this! return false; } } - - } diff --git a/src/main/java/com/sk89q/worldedit/generator/GroundGenerator.java b/src/main/java/com/sk89q/worldedit/generator/GroundGenerator.java deleted file mode 100644 index 8265f025d..000000000 --- a/src/main/java/com/sk89q/worldedit/generator/GroundGenerator.java +++ /dev/null @@ -1,67 +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.generator; - -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.Vector2D; -import com.sk89q.worldedit.operation.GroundFindingFunction; - -/** - * An abstract implementation for generators. - */ -public abstract class GroundGenerator extends GroundFindingFunction { - - private double density; - - /** - * Create a new instance. - * - * @param editSession the edit session - */ - protected GroundGenerator(EditSession editSession) { - super(editSession); - } - - /** - * Set the density (0 <= density <= 1) which indicates the percentage chance - * that an object will spawn in each column. - * - * @return the density - */ - public double getDensity() { - return density; - } - - /** - * Get the density (0 <= density <= 1) which indicates the percentage chance - * that an object will spawn in each column. - * - * @param density the density - */ - public void setDensity(double density) { - this.density = density; - } - - @Override - protected boolean shouldContinue(Vector2D pt) { - return Math.random() < density; - } - -} diff --git a/src/main/java/com/sk89q/worldedit/noise/NoiseGenerator.java b/src/main/java/com/sk89q/worldedit/noise/NoiseGenerator.java new file mode 100644 index 000000000..7e95f5f4a --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/noise/NoiseGenerator.java @@ -0,0 +1,46 @@ +/* + * 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.noise; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; + +/** + * Generates noise in a deterministic or non-deterministic manner. + */ +public interface NoiseGenerator { + + /** + * Get the noise for the given position. + * + * @param position the position + * @return a noise value between 0 (inclusive) and 1 (inclusive) + */ + float noise(Vector2D position); + + /** + * Get the noise for the given position. + * + * @param position the position + * @return a noise value between 0 (inclusive) and 1 (inclusive) + */ + float noise(Vector position); + +} diff --git a/src/main/java/com/sk89q/worldedit/noise/RandomNoise.java b/src/main/java/com/sk89q/worldedit/noise/RandomNoise.java new file mode 100644 index 000000000..f60480e15 --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/noise/RandomNoise.java @@ -0,0 +1,61 @@ +/* + * 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.noise; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; + +import java.util.Random; + +/** + * Generates noise non-deterministically using {@link java.util.Random}. + */ +public class RandomNoise implements NoiseGenerator { + + private final Random random; + + /** + * Create a new noise generator using the given Random. + * + * @param random the random instance + */ + public RandomNoise(Random random) { + this.random = random; + } + + /** + * Create a new noise generator with a newly constructed Random + * instance. + */ + public RandomNoise() { + this(new Random()); + } + + @Override + public float noise(Vector2D position) { + return random.nextFloat(); + } + + @Override + public float noise(Vector position) { + return random.nextFloat(); + } + +} diff --git a/src/main/java/com/sk89q/worldedit/operation/GroundScatterFunction.java b/src/main/java/com/sk89q/worldedit/operation/GroundScatterFunction.java index e5821ef29..474d70214 100644 --- a/src/main/java/com/sk89q/worldedit/operation/GroundScatterFunction.java +++ b/src/main/java/com/sk89q/worldedit/operation/GroundScatterFunction.java @@ -21,18 +21,32 @@ package com.sk89q.worldedit.operation; 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.generator.GroundGenerator; +import com.sk89q.worldedit.noise.NoiseGenerator; +import com.sk89q.worldedit.noise.RandomNoise; /** * Randomly applies the given {@link RegionFunction} onto random ground blocks. *

* This class can be used to generate a structure randomly over an area. */ -public class GroundScatterFunction extends GroundGenerator { +public class GroundScatterFunction extends GroundFindingFunction { + private NoiseGenerator noiseGenerator; private RegionFunction function; + private double density; + + /** + * Create a new instance using a {@link RandomNoise} as the noise generator. + * + * @param editSession the edit session + * @param function the function + */ + public GroundScatterFunction(EditSession editSession, RegionFunction function) { + this(editSession, function, new RandomNoise()); + } /** * Create a new instance. @@ -40,9 +54,48 @@ public class GroundScatterFunction extends GroundGenerator { * @param editSession the edit session * @param function the function */ - public GroundScatterFunction(EditSession editSession, RegionFunction function) { + public GroundScatterFunction(EditSession editSession, RegionFunction function, NoiseGenerator noiseGenerator) { super(editSession); this.function = function; + this.noiseGenerator = noiseGenerator; + } + + /** + * Get the density (0 <= density <= 1) which indicates the threshold that + * must be met for the function to be applied to a column. + * + * @return the density + */ + public double getDensity() { + return density; + } + + /** + * Set the density (0 <= density <= 1) which indicates the threshold that + * must be met for the function to be applied to a column. + * + * @param density the density + */ + public void setDensity(double density) { + this.density = density; + } + + /** + * Get the noise generator. + * + * @return the noise generator + */ + public NoiseGenerator getNoiseGenerator() { + return noiseGenerator; + } + + /** + * Set the noise generator. + * + * @param noiseGenerator the noise generator + */ + public void setNoiseGenerator(NoiseGenerator noiseGenerator) { + this.noiseGenerator = noiseGenerator; } /** @@ -63,6 +116,11 @@ public class GroundScatterFunction extends GroundGenerator { this.function = function; } + @Override + protected boolean shouldContinue(Vector2D pt) { + return noiseGenerator.noise(pt) <= density; + } + @Override protected boolean apply(Vector position, BaseBlock block) throws WorldEditException { return function.apply(position);