From d2e93dfe232a1faf6080999f8cf3a6068523af8a Mon Sep 17 00:00:00 2001 From: sk89q Date: Sat, 1 Mar 2014 15:41:40 -0800 Subject: [PATCH] Added GardenPatchGenerator, GroundScatterFunction. /pumpkins now uses the new classes. --- .../java/com/sk89q/worldedit/EditSession.java | 145 ++----------- .../worldedit/commands/RegionCommands.java | 16 +- .../generator/GardenPatchGenerator.java | 199 ++++++++++++++++++ .../GroundScatterFunction.java} | 39 ++-- 4 files changed, 253 insertions(+), 146 deletions(-) create mode 100644 src/main/java/com/sk89q/worldedit/generator/GardenPatchGenerator.java rename src/main/java/com/sk89q/worldedit/{generator/FloraPlacer.java => operation/GroundScatterFunction.java} (55%) diff --git a/src/main/java/com/sk89q/worldedit/EditSession.java b/src/main/java/com/sk89q/worldedit/EditSession.java index db9cbdbba..2fe6a5cf7 100644 --- a/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/src/main/java/com/sk89q/worldedit/EditSession.java @@ -28,10 +28,14 @@ import com.sk89q.worldedit.expression.Expression; import com.sk89q.worldedit.expression.ExpressionException; import com.sk89q.worldedit.expression.runtime.RValue; import com.sk89q.worldedit.generator.ForestGenerator; +import com.sk89q.worldedit.generator.GardenPatchGenerator; +import com.sk89q.worldedit.operation.GroundScatterFunction; import com.sk89q.worldedit.interpolation.Interpolation; import com.sk89q.worldedit.interpolation.KochanekBartelsInterpolation; import com.sk89q.worldedit.interpolation.Node; 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.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; @@ -2566,134 +2570,31 @@ public class EditSession { } /** - * Makes a pumpkin patch. + * Makes pumpkin patches randomly in an area around the given position. * - * @param basePos - */ - private void makePumpkinPatch(Vector basePos) - throws MaxChangedBlocksException { - // BaseBlock logBlock = new BaseBlock(BlockID.LOG); - BaseBlock leavesBlock = new BaseBlock(BlockID.LEAVES); - - // setBlock(basePos.subtract(0, 1, 0), logBlock); - setBlockIfAir(basePos, leavesBlock); - - makePumpkinPatchVine(basePos, basePos.add(0, 0, 1)); - makePumpkinPatchVine(basePos, basePos.add(0, 0, -1)); - makePumpkinPatchVine(basePos, basePos.add(1, 0, 0)); - makePumpkinPatchVine(basePos, basePos.add(-1, 0, 0)); - } - - /** - * Make a pumpkin patch fine. - * - * @param basePos - * @param pos - */ - private void makePumpkinPatchVine(Vector basePos, Vector pos) - throws MaxChangedBlocksException { - if (pos.distance(basePos) > 4) return; - if (getBlockType(pos) != 0) return; - - for (int i = -1; i > -3; --i) { - Vector testPos = pos.add(0, i, 0); - if (getBlockType(testPos) == BlockID.AIR) { - pos = testPos; - } else { - break; - } - } - - setBlockIfAir(pos, new BaseBlock(BlockID.LEAVES)); - - int t = prng.nextInt(4); - int h = prng.nextInt(3) - 1; - - BaseBlock log = new BaseBlock(BlockID.LOG); - - switch (t) { - case 0: - if (prng.nextBoolean()) { - makePumpkinPatchVine(basePos, pos.add(1, 0, 0)); - } - if (prng.nextBoolean()) { - setBlockIfAir(pos.add(1, h, -1), log); - } - setBlockIfAir(pos.add(0, 0, -1), new BaseBlock(BlockID.PUMPKIN, prng.nextInt(4))); - break; - - case 1: - if (prng.nextBoolean()) { - makePumpkinPatchVine(basePos, pos.add(0, 0, 1)); - } - if (prng.nextBoolean()) { - setBlockIfAir(pos.add(1, h, 0), log); - } - setBlockIfAir(pos.add(1, 0, 1), new BaseBlock(BlockID.PUMPKIN, prng.nextInt(4))); - break; - - case 2: - if (prng.nextBoolean()) { - makePumpkinPatchVine(basePos, pos.add(0, 0, -1)); - } - if (prng.nextBoolean()) { - setBlockIfAir(pos.add(-1, h, 0), log); - } - setBlockIfAir(pos.add(-1, 0, 1), new BaseBlock(BlockID.PUMPKIN, prng.nextInt(4))); - break; - - case 3: - if (prng.nextBoolean()) { - makePumpkinPatchVine(basePos, pos.add(-1, 0, 0)); - } - if (prng.nextBoolean()) { - setBlockIfAir(pos.add(-1, h, -1), log); - } - setBlockIfAir(pos.add(-1, 0, -1), new BaseBlock(BlockID.PUMPKIN, prng.nextInt(4))); - break; - } - } - - /** - * Makes pumpkin patches. - * - * @param basePos - * @param size - * @return number of trees created + * @param position the base position + * @param apothem the apothem of the (square) area + * @return number of patches created * @throws MaxChangedBlocksException */ - public int makePumpkinPatches(Vector basePos, int size) - throws MaxChangedBlocksException { - int affected = 0; + public int makePumpkinPatches(Vector position, int apothem) throws MaxChangedBlocksException { + // We want to generate pumpkins + GardenPatchGenerator generator = new GardenPatchGenerator(this); + generator.setPlant(GardenPatchGenerator.getPumpkinPattern()); - for (int x = basePos.getBlockX() - size; x <= basePos.getBlockX() - + size; ++x) { - for (int z = basePos.getBlockZ() - size; z <= basePos.getBlockZ() - + size; ++z) { - // Don't want to be in the ground - if (!getBlock(new Vector(x, basePos.getBlockY(), z)).isAir()) { - continue; - } - // The gods don't want a pumpkin patch here - if (Math.random() < 0.98) { - continue; - } + // In a region of the given radius + Region region = new CuboidRegion(position.add(-apothem, -5, -apothem), position.add(apothem, 10, apothem)); - for (int y = basePos.getBlockY(); y >= basePos.getBlockY() - 10; --y) { - // Check if we hit the ground - int t = getBlock(new Vector(x, y, z)).getType(); - if (t == BlockID.GRASS || t == BlockID.DIRT) { - makePumpkinPatch(new Vector(x, y + 1, z)); - ++affected; - break; - } else if (t != BlockID.AIR) { // Trees won't grow on this! - break; - } - } - } - } + // And we want to scatter them + GroundScatterFunction scatter = new GroundScatterFunction(this, generator); + scatter.setDensity(0.02); + scatter.setRange(region); - return affected; + // Generate those patches! + FlatRegionApplicator operation = new FlatRegionApplicator(region, scatter); + OperationHelper.completeLegacy(operation); + + return operation.getAffected(); } /** diff --git a/src/main/java/com/sk89q/worldedit/commands/RegionCommands.java b/src/main/java/com/sk89q/worldedit/commands/RegionCommands.java index be43ca045..469d3278b 100644 --- a/src/main/java/com/sk89q/worldedit/commands/RegionCommands.java +++ b/src/main/java/com/sk89q/worldedit/commands/RegionCommands.java @@ -29,8 +29,9 @@ 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.generator.FloraPlacer; +import com.sk89q.worldedit.generator.FloraGenerator; import com.sk89q.worldedit.generator.ForestGenerator; +import com.sk89q.worldedit.operation.GroundScatterFunction; import com.sk89q.worldedit.masks.Mask; import com.sk89q.worldedit.operation.FlatRegionApplicator; import com.sk89q.worldedit.operation.OperationHelper; @@ -566,11 +567,16 @@ public class RegionCommands { Region region = session.getSelection(player.getWorld()); - FloraPlacer function = new FloraPlacer(editSession); - function.setRange(region); - function.setDensity(density); + // We want to generate flora + FloraGenerator generator = new FloraGenerator(editSession); - 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 flora + FlatRegionApplicator operation = new FlatRegionApplicator(region, scatter); OperationHelper.complete(operation); player.print(operation.getAffected() + " flora created."); diff --git a/src/main/java/com/sk89q/worldedit/generator/GardenPatchGenerator.java b/src/main/java/com/sk89q/worldedit/generator/GardenPatchGenerator.java new file mode 100644 index 000000000..61c57e86e --- /dev/null +++ b/src/main/java/com/sk89q/worldedit/generator/GardenPatchGenerator.java @@ -0,0 +1,199 @@ +/* + * 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.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.patterns.BlockChance; +import com.sk89q.worldedit.patterns.Pattern; +import com.sk89q.worldedit.patterns.RandomFillPattern; +import com.sk89q.worldedit.patterns.SingleBlockPattern; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class GardenPatchGenerator implements RegionFunction { + + private final Random random = new Random(); + private final EditSession editSession; + private Pattern plant = getPumpkinPattern(); + private int affected; + + /** + * Create a new instance. + * + * @param editSession the edit session + */ + public GardenPatchGenerator(EditSession editSession) { + this.editSession = editSession; + } + + /** + * Get the plant pattern that is placed. + * + * @return the plant pattern + */ + public Pattern getPlant() { + return plant; + } + + /** + * Set the plant pattern that is placed. + * + * @param plant the plant pattern + */ + public void setPlant(Pattern plant) { + this.plant = plant; + } + + /** + * Get the number of affected blocks. + * + * @return affected count + */ + public int getAffected() { + return affected; + } + + /** + * Make a patch vine. + * + * @param basePos the base position + * @param pos the vine position + */ + private void placeVine(Vector basePos, Vector pos) throws MaxChangedBlocksException { + if (pos.distance(basePos) > 4) return; + if (editSession.getBlockType(pos) != 0) return; + + for (int i = -1; i > -3; --i) { + Vector testPos = pos.add(0, i, 0); + if (editSession.getBlockType(testPos) == BlockID.AIR) { + pos = testPos; + } else { + break; + } + } + + editSession.setBlockIfAir(pos, new BaseBlock(BlockID.LEAVES)); + affected++; + + int t = random.nextInt(4); + int h = random.nextInt(3) - 1; + Vector p; + + BaseBlock log = new BaseBlock(BlockID.LOG); + + switch (t) { + case 0: + if (random.nextBoolean()) { + placeVine(basePos, pos.add(1, 0, 0)); + } + if (random.nextBoolean()) { + editSession.setBlockIfAir(pos.add(1, h, -1), log); + affected++; + } + editSession.setBlockIfAir(p = pos.add(0, 0, -1), plant.next(p)); + affected++; + break; + + case 1: + if (random.nextBoolean()) { + placeVine(basePos, pos.add(0, 0, 1)); + } + if (random.nextBoolean()) { + editSession.setBlockIfAir(pos.add(1, h, 0), log); + affected++; + } + editSession.setBlockIfAir(p = pos.add(1, 0, 1), plant.next(p)); + affected++; + break; + + case 2: + if (random.nextBoolean()) { + placeVine(basePos, pos.add(0, 0, -1)); + } + if (random.nextBoolean()) { + editSession.setBlockIfAir(pos.add(-1, h, 0), log); + affected++; + } + editSession.setBlockIfAir(p = pos.add(-1, 0, 1), plant.next(p)); + affected++; + break; + + case 3: + if (random.nextBoolean()) { + placeVine(basePos, pos.add(-1, 0, 0)); + } + if (random.nextBoolean()) { + editSession.setBlockIfAir(pos.add(-1, h, -1), log); + affected++; + } + editSession.setBlockIfAir(p = pos.add(-1, 0, -1), plant.next(p)); + affected++; + break; + } + } + + @Override + public boolean apply(Vector position) throws WorldEditException { + if (editSession.getBlock(position).getType() != BlockID.AIR) { + position = position.add(0, 1, 0); + } + + BaseBlock leavesBlock = new BaseBlock(BlockID.LEAVES); + + editSession.setBlockIfAir(position, leavesBlock); + + placeVine(position, position.add(0, 0, 1)); + placeVine(position, position.add(0, 0, -1)); + placeVine(position, position.add(1, 0, 0)); + placeVine(position, position.add(-1, 0, 0)); + + return true; + } + + /** + * Get a pattern that creates pumpkins with different faces. + * + * @return a pumpkin pattern + */ + public static Pattern getPumpkinPattern() { + List chance = new ArrayList(); + for (int i = 0; i < 4; i++) { + chance.add(new BlockChance(new BaseBlock(BlockID.PUMPKIN, i), 100)); + } + return new RandomFillPattern(chance); + } + + /** + * Get a pattern that creates melons. + * + * @return a melon pattern + */ + public static Pattern getMelonPattern() { + return new SingleBlockPattern(new BaseBlock(BlockID.MELON_BLOCK)); + } +} diff --git a/src/main/java/com/sk89q/worldedit/generator/FloraPlacer.java b/src/main/java/com/sk89q/worldedit/operation/GroundScatterFunction.java similarity index 55% rename from src/main/java/com/sk89q/worldedit/generator/FloraPlacer.java rename to src/main/java/com/sk89q/worldedit/operation/GroundScatterFunction.java index 0f4662ccc..e5821ef29 100644 --- a/src/main/java/com/sk89q/worldedit/generator/FloraPlacer.java +++ b/src/main/java/com/sk89q/worldedit/operation/GroundScatterFunction.java @@ -17,53 +17,54 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.generator; +package com.sk89q.worldedit.operation; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.generator.GroundGenerator; /** - * Generates flora over an applied area. + * 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 FloraPlacer extends GroundGenerator { +public class GroundScatterFunction extends GroundGenerator { - private final EditSession editSession; - private FloraGenerator floraGenerator; + private RegionFunction function; /** * Create a new instance. * * @param editSession the edit session + * @param function the function */ - public FloraPlacer(EditSession editSession) { + public GroundScatterFunction(EditSession editSession, RegionFunction function) { super(editSession); - this.editSession = editSession; - this.floraGenerator = new FloraGenerator(editSession); + this.function = function; } /** - * Get the flora generator. + * Get the function to apply. * - * @return the flora generator + * @return the region function */ - public FloraGenerator getFloraGenerator() { - return floraGenerator; + public RegionFunction getFunction() { + return function; } /** - * Set the flora generator. + * Set the function to apply. * - * @param floraGenerator the flora generator + * @param function the region function */ - public void setFloraGenerator(FloraGenerator floraGenerator) { - this.floraGenerator = floraGenerator; + public void setFunction(RegionFunction function) { + this.function = function; } @Override - protected boolean apply(Vector pt, BaseBlock block) throws WorldEditException { - return floraGenerator.apply(pt); + protected boolean apply(Vector position, BaseBlock block) throws WorldEditException { + return function.apply(position); } - }