From 10b48e93441929d104827a3c74c2a83197fcab1d Mon Sep 17 00:00:00 2001 From: sk89q Date: Sun, 30 Jan 2011 14:54:42 -0800 Subject: [PATCH] Added more tree generators, removed CraftBukkit/MC dependency (yay!). --- build.xml | 2 - plugin.yml | 13 +- src/com/sk89q/worldedit/EditSession.java | 80 +----- src/com/sk89q/worldedit/LocalWorld.java | 33 ++- .../sk89q/worldedit/bukkit/BukkitUtil.java | 5 + .../sk89q/worldedit/bukkit/BukkitWorld.java | 64 +++-- .../bukkit/CraftBukkitInterface.java | 115 --------- ...java => EditSessionBlockChangeDegate.java} | 151 +++++------ .../commands/GenerationCommands.java | 38 +-- .../commands/SuperPickaxeCommands.java | 50 +--- .../superpickaxe/BigTreePlanter.java | 49 ---- .../superpickaxe/PineTreePlanter.java | 49 ---- .../worldedit/superpickaxe/TreePlanter.java | 13 +- .../sk89q/worldedit/util/TreeGenerator.java | 240 ++++++++++++++++++ 14 files changed, 430 insertions(+), 472 deletions(-) delete mode 100644 src/com/sk89q/worldedit/bukkit/CraftBukkitInterface.java rename src/com/sk89q/worldedit/bukkit/{WorldSetBlockProxy.java => EditSessionBlockChangeDegate.java} (56%) delete mode 100644 src/com/sk89q/worldedit/superpickaxe/BigTreePlanter.java delete mode 100644 src/com/sk89q/worldedit/superpickaxe/PineTreePlanter.java create mode 100644 src/com/sk89q/worldedit/util/TreeGenerator.java diff --git a/build.xml b/build.xml index 78db76589..cc633484f 100644 --- a/build.xml +++ b/build.xml @@ -11,8 +11,6 @@ - - diff --git a/plugin.yml b/plugin.yml index d764c00cf..7fd381c74 100644 --- a/plugin.yml +++ b/plugin.yml @@ -71,10 +71,7 @@ commands: usage: / [raised?] forestgen: description: Generate a forest - usage: / [size] [density] - pinegen: - description: Generate a pine forest - usage: / [size] [density] + usage: / [size] [type] [density] pumpkins: description: Generate pumpkin patches usage: / [size] @@ -197,12 +194,6 @@ commands: none: description: Turn off all superpickaxe alternate modes usage: / - bigtree: - description: Big tree generator tool - usage: / - pinetree: - description: Pine tree generator tool - usage: / repl: description: Block replacer tool usage: / @@ -226,7 +217,7 @@ commands: usage: / tree: description: Tree generator tool - usage: / + usage: / [type] /fillr: description: Fill a hole recursively usage: / [depth] diff --git a/src/com/sk89q/worldedit/EditSession.java b/src/com/sk89q/worldedit/EditSession.java index 9c9948911..dec9344e4 100755 --- a/src/com/sk89q/worldedit/EditSession.java +++ b/src/com/sk89q/worldedit/EditSession.java @@ -30,6 +30,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Random; import com.sk89q.worldedit.regions.*; +import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.bags.*; import com.sk89q.worldedit.blocks.*; import com.sk89q.worldedit.patterns.*; @@ -1788,7 +1789,7 @@ public class EditSession { * 0-1 chance * @return whether a block was changed */ - private boolean setChanceBlockIfAir(Vector pos, BaseBlock block, double c) + public boolean setChanceBlockIfAir(Vector pos, BaseBlock block, double c) throws MaxChangedBlocksException { if (Math.random() <= c) { return setBlockIfAir(pos, block); @@ -1915,11 +1916,11 @@ public class EditSession { * @param basePos * @param size * @param density - * @param pineTree + * @param treeGenerator * @return number of trees created */ public int makeForest(Vector basePos, int size, double density, - boolean pineTree) throws MaxChangedBlocksException { + TreeGenerator treeGenerator) throws MaxChangedBlocksException { int affected = 0; for (int x = basePos.getBlockX() - size; x <= basePos.getBlockX() @@ -1938,11 +1939,7 @@ public class EditSession { // Check if we hit the ground int t = getBlock(new Vector(x, y, z)).getType(); if (t == 2 || t == 3) { - if (pineTree) { - makePineTree(new Vector(x, y + 1, z)); - } else { - world.generateBigTree(this, new Vector(x, y, z)); - } + treeGenerator.generate(this, new Vector(x, y + 1, z)); affected++; break; } else if (t != 0) { // Trees won't grow on this! @@ -1955,64 +1952,6 @@ public class EditSession { return affected; } - /** - * Makes a terrible looking pine tree. - * - * @param basePos - */ - public void makePineTree(Vector basePos) throws MaxChangedBlocksException { - int trunkHeight = (int) Math.floor(Math.random() * 2) + 3; - int height = (int) Math.floor(Math.random() * 5) + 8; - - BaseBlock logBlock = new BaseBlock(17); - BaseBlock leavesBlock = new BaseBlock(18); - - // Create trunk - for (int i = 0; i < trunkHeight; i++) { - if (!setBlockIfAir(basePos.add(0, i, 0), logBlock)) { - return; - } - } - - // Move up - basePos = basePos.add(0, trunkHeight, 0); - - // Create tree + leaves - for (int i = 0; i < height; i++) { - setBlockIfAir(basePos.add(0, i, 0), logBlock); - - // Less leaves at these levels - double chance = ((i == 0 || i == height - 1) ? 0.6 : 1); - - // Inner leaves - setChanceBlockIfAir(basePos.add(-1, i, 0), leavesBlock, chance); - setChanceBlockIfAir(basePos.add(1, i, 0), leavesBlock, chance); - setChanceBlockIfAir(basePos.add(0, i, -1), leavesBlock, chance); - setChanceBlockIfAir(basePos.add(0, i, 1), leavesBlock, chance); - setChanceBlockIfAir(basePos.add(1, i, 1), leavesBlock, chance); - setChanceBlockIfAir(basePos.add(-1, i, 1), leavesBlock, chance); - setChanceBlockIfAir(basePos.add(1, i, -1), leavesBlock, chance); - setChanceBlockIfAir(basePos.add(-1, i, -1), leavesBlock, chance); - - if (!(i == 0 || i == height - 1)) { - for (int j = -2; j <= 2; j++) { - setChanceBlockIfAir(basePos.add(-2, i, j), leavesBlock, 0.6); - } - for (int j = -2; j <= 2; j++) { - setChanceBlockIfAir(basePos.add(2, i, j), leavesBlock, 0.6); - } - for (int j = -2; j <= 2; j++) { - setChanceBlockIfAir(basePos.add(j, i, -2), leavesBlock, 0.6); - } - for (int j = -2; j <= 2; j++) { - setChanceBlockIfAir(basePos.add(j, i, 2), leavesBlock, 0.6); - } - } - } - - setBlockIfAir(basePos.add(0, height, 0), leavesBlock); - } - /** * Count the number of blocks of a list of types in a region. * @@ -2183,4 +2122,13 @@ public class EditSession { public void setBlockBag(BlockBag blockBag) { this.blockBag = blockBag; } + + /** + * Get the world. + * + * @return + */ + public LocalWorld getWorld() { + return world; + } } diff --git a/src/com/sk89q/worldedit/LocalWorld.java b/src/com/sk89q/worldedit/LocalWorld.java index 4c4bc094a..1cb9b5e38 100644 --- a/src/com/sk89q/worldedit/LocalWorld.java +++ b/src/com/sk89q/worldedit/LocalWorld.java @@ -99,7 +99,8 @@ public abstract class LocalWorld { * @param pt * @return */ - public abstract boolean generateTree(EditSession editSession, Vector pt); + public abstract boolean generateTree(EditSession editSession, Vector pt) + throws MaxChangedBlocksException; /** * Generate a big tree at a location. @@ -107,7 +108,35 @@ public abstract class LocalWorld { * @param pt * @return */ - public abstract boolean generateBigTree(EditSession editSession, Vector pt); + public abstract boolean generateBigTree(EditSession editSession, Vector pt) + throws MaxChangedBlocksException; + + /** + * Generate a birch tree at a location. + * + * @param pt + * @return + */ + public abstract boolean generateBirchTree(EditSession editSession, Vector pt) + throws MaxChangedBlocksException; + + /** + * Generate a redwood tree at a location. + * + * @param pt + * @return + */ + public abstract boolean generateRedwoodTree(EditSession editSession, Vector pt) + throws MaxChangedBlocksException; + + /** + * Generate a tall redwood tree at a location. + * + * @param pt + * @return + */ + public abstract boolean generateTallRedwoodTree(EditSession editSession, Vector pt) + throws MaxChangedBlocksException; /** * Drop an item. diff --git a/src/com/sk89q/worldedit/bukkit/BukkitUtil.java b/src/com/sk89q/worldedit/bukkit/BukkitUtil.java index 8e32efa34..a05f34d54 100644 --- a/src/com/sk89q/worldedit/bukkit/BukkitUtil.java +++ b/src/com/sk89q/worldedit/bukkit/BukkitUtil.java @@ -24,6 +24,7 @@ import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.Location; import org.bukkit.Server; +import org.bukkit.World; import com.sk89q.worldedit.BlockVector; import com.sk89q.worldedit.Vector; @@ -31,6 +32,10 @@ public class BukkitUtil { private BukkitUtil() { } + public static Location toLocation(World world, Vector loc) { + return new Location(world, loc.getX(), loc.getY(), loc.getZ()); + } + public static BlockVector toVector(Block block) { return new BlockVector(block.getX(), block.getY(), block.getZ()); } diff --git a/src/com/sk89q/worldedit/bukkit/BukkitWorld.java b/src/com/sk89q/worldedit/bukkit/BukkitWorld.java index 9c677f245..1c71a82c7 100644 --- a/src/com/sk89q/worldedit/bukkit/BukkitWorld.java +++ b/src/com/sk89q/worldedit/bukkit/BukkitWorld.java @@ -19,8 +19,6 @@ package com.sk89q.worldedit.bukkit; -import java.util.logging.Level; -import java.util.logging.Logger; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.block.Furnace; @@ -31,6 +29,7 @@ import org.bukkit.entity.LivingEntity; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.Location; +import org.bukkit.TreeType; import org.bukkit.World; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalWorld; @@ -38,11 +37,6 @@ import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.blocks.*; public class BukkitWorld extends LocalWorld { - /** - * Logger. - */ - private final Logger logger = Logger.getLogger("Minecraft.WorldEdit"); - private World world; /** @@ -254,14 +248,8 @@ public class BukkitWorld extends LocalWorld { */ @Override public boolean generateTree(EditSession editSession, Vector pt) { - try { - return CraftBukkitInterface.generateTree(editSession, pt); - } catch (Throwable t) { - logger.log(Level.SEVERE, - "Failed to create tree (do you need to update WorldEdit " + - "due to a Minecraft update?)", t); - return false; - } + return world.generateTree(BukkitUtil.toLocation(world, pt), TreeType.TREE, + new EditSessionBlockChangeDegate(editSession)); } /** @@ -272,14 +260,44 @@ public class BukkitWorld extends LocalWorld { */ @Override public boolean generateBigTree(EditSession editSession, Vector pt) { - try { - return CraftBukkitInterface.generateBigTree(editSession, pt); - } catch (Throwable t) { - logger.log(Level.SEVERE, - "Failed to create tree (do you need to update WorldEdit " + - "due to a Minecraft update?)", t); - return false; - } + return world.generateTree(BukkitUtil.toLocation(world, pt), TreeType.BIG_TREE, + new EditSessionBlockChangeDegate(editSession)); + } + + /** + * Generate a birch tree at a location. + * + * @param pt + * @return + */ + @Override + public boolean generateBirchTree(EditSession editSession, Vector pt) { + return world.generateTree(BukkitUtil.toLocation(world, pt), TreeType.BIRCH, + new EditSessionBlockChangeDegate(editSession)); + } + + /** + * Generate a redwood tree at a location. + * + * @param pt + * @return + */ + @Override + public boolean generateRedwoodTree(EditSession editSession, Vector pt) { + return world.generateTree(BukkitUtil.toLocation(world, pt), TreeType.REDWOOD, + new EditSessionBlockChangeDegate(editSession)); + } + + /** + * Generate a redwood tree at a location. + * + * @param pt + * @return + */ + @Override + public boolean generateTallRedwoodTree(EditSession editSession, Vector pt) { + return world.generateTree(BukkitUtil.toLocation(world, pt), TreeType.TALL_REDWOOD, + new EditSessionBlockChangeDegate(editSession)); } /** diff --git a/src/com/sk89q/worldedit/bukkit/CraftBukkitInterface.java b/src/com/sk89q/worldedit/bukkit/CraftBukkitInterface.java deleted file mode 100644 index c26e6f8c4..000000000 --- a/src/com/sk89q/worldedit/bukkit/CraftBukkitInterface.java +++ /dev/null @@ -1,115 +0,0 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q - * - * 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.bukkit; - -import java.util.logging.Logger; -import java.util.logging.Level; -import java.util.Random; -import java.lang.reflect.*; -import net.minecraft.server.WorldGenBigTree; -import net.minecraft.server.WorldGenTrees; -import net.minecraft.server.WorldGenerator; -import sun.reflect.ReflectionFactory; -import com.sk89q.worldedit.*; - -/** - * - * @author sk89q - */ -public class CraftBukkitInterface { - /** - * Logger. - */ - private static final Logger logger = Logger.getLogger("Minecraft.WorldEdit"); - /** - * Random generator. - */ - private static Random random = new Random(); - /** - * Proxy for the tree generator. - */ - private static WorldSetBlockProxy proxy; - - /** - * Perform world generation at a location. - * - * @param pt - * @return - */ - private static boolean performWorldGen(EditSession editSession, Vector pt, - WorldGenerator worldGen) { - if (proxy == null) { - try { - proxy = createNoConstructor(WorldSetBlockProxy.class); - } catch (Throwable t) { - logger.log(Level.WARNING, "setBlock() proxy class failed to construct", - t); - return false; - } - } - proxy.setEditSession(editSession); - - WorldGenerator gen = worldGen; - return gen.a(proxy, random, - pt.getBlockX(), pt.getBlockY() + 1, pt.getBlockZ()); - } - - /** - * Generate a tree at a location. - * - * @param pt - * @return - */ - public static boolean generateTree(EditSession editSession, Vector pt) { - return performWorldGen(editSession, pt, new WorldGenTrees()); - } - - /** - * Generate a big tree at a location. - * - * @param pt - * @return - */ - public static boolean generateBigTree(EditSession editSession, Vector pt) { - return performWorldGen(editSession, pt, new WorldGenBigTree()); - } - - /** - * Instantiate a class without calling its constructor. - * - * @param - * @param clazz - * @return - * @throws Throwable - */ - @SuppressWarnings("rawtypes") - private static T createNoConstructor(Class clazz) throws Throwable { - try { - ReflectionFactory factory = ReflectionFactory.getReflectionFactory(); - Constructor objectConstructor = Object.class.getDeclaredConstructor(); - Constructor c = factory.newConstructorForSerialization( - clazz, objectConstructor - ); - return clazz.cast(c.newInstance()); - } catch (Throwable e) { - throw e; - } - } -} diff --git a/src/com/sk89q/worldedit/bukkit/WorldSetBlockProxy.java b/src/com/sk89q/worldedit/bukkit/EditSessionBlockChangeDegate.java similarity index 56% rename from src/com/sk89q/worldedit/bukkit/WorldSetBlockProxy.java rename to src/com/sk89q/worldedit/bukkit/EditSessionBlockChangeDegate.java index e252dbb15..f431c8890 100644 --- a/src/com/sk89q/worldedit/bukkit/WorldSetBlockProxy.java +++ b/src/com/sk89q/worldedit/bukkit/EditSessionBlockChangeDegate.java @@ -1,92 +1,59 @@ -package com.sk89q.worldedit.bukkit; -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q - * - * 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 . -*/ - -import net.minecraft.server.World; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.blocks.BaseBlock; - -/** - * Proxy class to catch calls to set blocks. - * - * @author sk89q - */ -public class WorldSetBlockProxy extends World { - /** - * Edit session. - */ - private EditSession editSession; - - /** - * Constructor that should NOT be called. - * - * @param editSession - */ - public WorldSetBlockProxy(EditSession editSession) { - super(null, "", (long)0, null); - throw new IllegalStateException("MinecraftSetBlockProxy constructor called (BAD)"); - } - - /** - * Called to set a block. - * - * @param x - * @param y - * @param z - * @param blockType - * @return - */ - @Override - public boolean b(int x, int y, int z, int blockType) { - try { - return editSession.setBlock(new Vector(x, y, z), new BaseBlock(blockType)); - } catch (MaxChangedBlocksException ex) { - return false; - } - } - - /** - * Called to get a block. - * - * @param x - * @param y - * @param z - * @return - */ - @Override - public int a(int x, int y, int z) { - return editSession.getBlock(new Vector(x, y, z)).getType(); - } - - /** - * @return - */ - public EditSession getEditSession() { - return editSession; - } - - /** - * @param editSession - */ - public void setEditSession(EditSession editSession) { - this.editSession = editSession; - } -} +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q + * + * 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.bukkit; + +import org.bukkit.BlockChangeDelegate; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.blocks.BaseBlock; + +/** + * Proxy class to catch calls to set blocks. + * + * @author sk89q + */ +public class EditSessionBlockChangeDegate implements BlockChangeDelegate { + private EditSession editSession; + + public EditSessionBlockChangeDegate(EditSession editSession) { + this.editSession = editSession; + } + + public boolean setTypeId(int x, int y, int z, int typeId) { + try { + return editSession.setBlock(new Vector(x, y, z), new BaseBlock(typeId)); + } catch (MaxChangedBlocksException ex) { + return false; + } + } + + public boolean setTypeIdAndData(int x, int y, int z, int typeId, int data) { + try { + return editSession.setBlock(new Vector(x, y, z), new BaseBlock(typeId, data)); + } catch (MaxChangedBlocksException ex) { + return false; + } + } + + public int getTypeId(int x, int y, int z) { + return editSession.getBlock(new Vector(x, y, z)).getType(); + } +} diff --git a/src/com/sk89q/worldedit/commands/GenerationCommands.java b/src/com/sk89q/worldedit/commands/GenerationCommands.java index 11e9698dd..3026bcbf6 100644 --- a/src/com/sk89q/worldedit/commands/GenerationCommands.java +++ b/src/com/sk89q/worldedit/commands/GenerationCommands.java @@ -23,6 +23,7 @@ import com.sk89q.util.commands.Command; import com.sk89q.util.commands.CommandContext; import com.sk89q.worldedit.*; import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.util.TreeGenerator; /** * Generation commands. @@ -132,7 +133,7 @@ public class GenerationCommands { @Command( aliases = {"forestgen"}, - usage = "[size] [density] ", + usage = "[size] [type] [density]", desc = "Generate a forest", min = 0, max = 2 @@ -141,35 +142,24 @@ public class GenerationCommands { public static void forestGen(CommandContext args, WorldEdit we, LocalSession session, LocalPlayer player, EditSession editSession) throws WorldEditException { - + int size = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) : 10; - double density = args.argsLength() > 1 ? Double.parseDouble(args.getString(1)) / 100 : 0.05; + TreeGenerator.TreeType type = args.argsLength() > 1 ? + type = TreeGenerator.lookup(args.getString(1)) + : TreeGenerator.TreeType.TREE; + double density = args.argsLength() > 2 ? args.getDouble(2) / 100 : 0.05; + if (type == null) { + player.printError("Tree type '" + args.getString(1) + "' is unknown."); + return; + } else { + } + int affected = editSession.makeForest(player.getPosition(), - size, density, false); + size, density, new TreeGenerator(type)); player.print(affected + " trees created."); } - @Command( - aliases = {"pinegen"}, - usage = "[size] [density]", - desc = "Generate a pine forest", - min = 0, - max = 2 - ) - @CommandPermissions({"worldedit.generation.forest"}) - public static void pineGen(CommandContext args, WorldEdit we, - LocalSession session, LocalPlayer player, EditSession editSession) - throws WorldEditException { - - int size = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) : 10; - double density = args.argsLength() > 1 ? Double.parseDouble(args.getString(1)) / 100 : 0.05; - - int affected = editSession.makeForest(player.getPosition(), - size, density, true); - player.print(affected + " pine trees created."); - } - @Command( aliases = {"pumpkins"}, usage = "[size]", diff --git a/src/com/sk89q/worldedit/commands/SuperPickaxeCommands.java b/src/com/sk89q/worldedit/commands/SuperPickaxeCommands.java index 5272ebe63..9509cf26b 100644 --- a/src/com/sk89q/worldedit/commands/SuperPickaxeCommands.java +++ b/src/com/sk89q/worldedit/commands/SuperPickaxeCommands.java @@ -24,6 +24,7 @@ import com.sk89q.util.commands.CommandContext; import com.sk89q.worldedit.*; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.superpickaxe.*; +import com.sk89q.worldedit.util.TreeGenerator; /** * Super pickaxe commands. @@ -152,55 +153,30 @@ public class SuperPickaxeCommands { @Command( aliases = {"tree"}, - usage = "", + usage = "[type]", desc = "Tree generator tool", min = 0, - max = 0 + max = 1 ) @CommandPermissions({"worldedit.superpickaxe.tree"}) public static void tree(CommandContext args, WorldEdit we, LocalSession session, LocalPlayer player, EditSession editSession) throws WorldEditException { + TreeGenerator.TreeType type = args.argsLength() > 0 ? + type = TreeGenerator.lookup(args.getString(0)) + : TreeGenerator.TreeType.TREE; + + if (type == null) { + player.printError("Tree type '" + args.getString(0) + "' is unknown."); + return; + } + session.setArmSwingMode(null); - session.setRightClickMode(new TreePlanter()); + session.setRightClickMode(new TreePlanter(new TreeGenerator(type))); player.print("Tree tool equipped. Right click grass with a pickaxe."); } - @Command( - aliases = {"bigtree"}, - usage = "", - desc = "Big tree generator tool", - min = 0, - max = 0 - ) - @CommandPermissions({"worldedit.superpickaxe.tree.big"}) - public static void bigTree(CommandContext args, WorldEdit we, - LocalSession session, LocalPlayer player, EditSession editSession) - throws WorldEditException { - - session.setArmSwingMode(null); - session.setRightClickMode(new BigTreePlanter()); - player.print("Big tree tool equipped. Right click grass with a pickaxe."); - } - - @Command( - aliases = {"pinetree"}, - usage = "", - desc = "Pine tree generator tool", - min = 0, - max = 0 - ) - @CommandPermissions({"worldedit.superpickaxe.tree.pine"}) - public static void pineTree(CommandContext args, WorldEdit we, - LocalSession session, LocalPlayer player, EditSession editSession) - throws WorldEditException { - - session.setArmSwingMode(null); - session.setRightClickMode(new PineTreePlanter()); - player.print("Pine tree tool equipped. Right click a block with a pickaxe."); - } - @Command( aliases = {"repl"}, usage = "", diff --git a/src/com/sk89q/worldedit/superpickaxe/BigTreePlanter.java b/src/com/sk89q/worldedit/superpickaxe/BigTreePlanter.java deleted file mode 100644 index 12d48f34b..000000000 --- a/src/com/sk89q/worldedit/superpickaxe/BigTreePlanter.java +++ /dev/null @@ -1,49 +0,0 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q - * - * 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.superpickaxe; - -import com.sk89q.worldedit.*; - -/** - * Plants a big tree. - * - * @author sk89q - */ -public class BigTreePlanter implements SuperPickaxeMode { - @Override - public boolean act(ServerInterface server, LocalConfiguration config, - LocalPlayer player, LocalSession session, WorldVector clicked) { - - LocalWorld world = clicked.getWorld(); - EditSession editSession = - new EditSession(server, world, session.getBlockChangeLimit()); - - try { - if (!world.generateBigTree(editSession, clicked)) { - player.printError("Notch won't let you put a tree there."); - } - } finally { - session.remember(editSession); - } - - return true; - } - -} diff --git a/src/com/sk89q/worldedit/superpickaxe/PineTreePlanter.java b/src/com/sk89q/worldedit/superpickaxe/PineTreePlanter.java deleted file mode 100644 index 3da511ae3..000000000 --- a/src/com/sk89q/worldedit/superpickaxe/PineTreePlanter.java +++ /dev/null @@ -1,49 +0,0 @@ -// $Id$ -/* - * WorldEdit - * Copyright (C) 2010 sk89q - * - * 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.superpickaxe; - -import com.sk89q.worldedit.*; - -/** - * Plants a pine tree. - * - * @author sk89q - */ -public class PineTreePlanter implements SuperPickaxeMode { - @Override - public boolean act(ServerInterface server, LocalConfiguration config, - LocalPlayer player, LocalSession session, WorldVector clicked) { - - LocalWorld world = clicked.getWorld(); - EditSession editSession = - new EditSession(server, world, session.getBlockChangeLimit()); - - try { - editSession.makePineTree(clicked.add(0, 1, 0)); - } catch (MaxChangedBlocksException e) { - player.printError("Max blocks change limit reached."); - } finally { - session.remember(editSession); - } - - return true; - } - -} diff --git a/src/com/sk89q/worldedit/superpickaxe/TreePlanter.java b/src/com/sk89q/worldedit/superpickaxe/TreePlanter.java index aa02b489d..ec5017634 100644 --- a/src/com/sk89q/worldedit/superpickaxe/TreePlanter.java +++ b/src/com/sk89q/worldedit/superpickaxe/TreePlanter.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.superpickaxe; import com.sk89q.worldedit.*; +import com.sk89q.worldedit.util.TreeGenerator; /** * Plants a tree. @@ -27,6 +28,12 @@ import com.sk89q.worldedit.*; * @author sk89q */ public class TreePlanter implements SuperPickaxeMode { + private TreeGenerator gen; + + public TreePlanter(TreeGenerator gen) { + this.gen = gen; + } + @Override public boolean act(ServerInterface server, LocalConfiguration config, LocalPlayer player, LocalSession session, WorldVector clicked) { @@ -36,9 +43,11 @@ public class TreePlanter implements SuperPickaxeMode { new EditSession(server, world, session.getBlockChangeLimit()); try { - if (!world.generateTree(editSession, clicked)) { - player.printError("Notch won't let you put a tree there."); + if (!gen.generate(editSession, clicked.add(0, 1, 0))) { + player.printError("A tree can't go there."); } + } catch (MaxChangedBlocksException e) { + player.printError("Max. blocks changed reached."); } finally { session.remember(editSession); } diff --git a/src/com/sk89q/worldedit/util/TreeGenerator.java b/src/com/sk89q/worldedit/util/TreeGenerator.java new file mode 100644 index 000000000..7bc2262cb --- /dev/null +++ b/src/com/sk89q/worldedit/util/TreeGenerator.java @@ -0,0 +1,240 @@ +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q + * + * 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.util; + +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalWorld; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; + +/** + * Tree generator. + * + * @author sk89q + */ +public class TreeGenerator { + public enum TreeType { + TREE("Regular tree", new String[] {"tree", "regular"}), + BIG_TREE("Big tree", new String[] {"big", "bigtree"}), + REDWOOD("Redwood", new String[] {"redwood", "sequoia", "sequoioideae"}), + TALL_REDWOOD("Tall redwood", new String[] {"tallredwood", "tallsequoia", "tallsequoioideae"}), + BIRCH("Birch", new String[] {"birch", "white", "whitebark"}), + PINE("Pine", new String[] {"pine"}), + RANDOM_REDWOOD("Random redwood", new String[] {"randredwood", "randomredwood", "anyredwood"}), + RANDOM("Random", new String[] {"rand", "random"}); + + /** + * Stores a map of the names for fast access. + */ + private static final Map lookup = new HashMap(); + + private final String name; + private final String[] lookupKeys; + + static { + for (TreeType type : EnumSet.allOf(TreeType.class)) { + for (String key : type.lookupKeys) { + lookup.put(key, type); + } + } + } + + TreeType(String name, String lookupKey) { + this.name = name; + this.lookupKeys = new String[]{ lookupKey }; + } + + TreeType(String name, String[] lookupKeys) { + this.name = name; + this.lookupKeys = lookupKeys; + } + + /** + * Get user-friendly tree type name. + * + * @return + */ + public String getName() { + return name; + } + + /** + * Return type from name. May return null. + * + * @param name + * @return + */ + public static TreeType lookup(String name) { + return lookup.get(name.toLowerCase()); + } + }; + + private static Random rand = new Random(); + + private TreeType type; + + /** + * Construct the tree generator with a tree type. + * + * @param type + */ + public TreeGenerator(TreeType type) { + this.type = type; + } + + /** + * Generate a tree. + * + * @param world + * @param editSession + * @param pos + * @return + * @throws MaxChangedBlocksException + */ + public boolean generate(EditSession editSession, Vector pos) + throws MaxChangedBlocksException { + return generate(type, editSession, pos); + } + + /** + * Generate a tree. + * + * @param world + * @param editSession + * @param pos + * @return + * @throws MaxChangedBlocksException + */ + private boolean generate(TreeType type, EditSession editSession, Vector pos) + throws MaxChangedBlocksException { + LocalWorld world = editSession.getWorld(); + + TreeType[] choices; + TreeType realType; + + switch (type) { + case TREE: + return world.generateTree(editSession, pos); + case BIG_TREE: + return world.generateBigTree(editSession, pos); + case BIRCH: + return world.generateBirchTree(editSession, pos); + case REDWOOD: + return world.generateRedwoodTree(editSession, pos); + case TALL_REDWOOD: + return world.generateTallRedwoodTree(editSession, pos); + case PINE: + makePineTree(editSession, pos); + return true; + case RANDOM_REDWOOD: + choices = + new TreeType[] { + TreeType.REDWOOD, TreeType.TALL_REDWOOD + }; + realType = choices[rand.nextInt(choices.length)]; + return generate(realType, editSession, pos); + case RANDOM: + choices = + new TreeType[] { + TreeType.TREE, TreeType.BIG_TREE, TreeType.BIRCH, + TreeType.REDWOOD, TreeType.TALL_REDWOOD, TreeType.PINE + }; + realType = choices[rand.nextInt(choices.length)]; + return generate(realType, editSession, pos); + } + + return false; + } + + /** + * Makes a terrible looking pine tree. + * + * @param basePos + */ + private static void makePineTree(EditSession editSession, Vector basePos) + throws MaxChangedBlocksException { + int trunkHeight = (int) Math.floor(Math.random() * 2) + 3; + int height = (int) Math.floor(Math.random() * 5) + 8; + + BaseBlock logBlock = new BaseBlock(17); + BaseBlock leavesBlock = new BaseBlock(18); + + // Create trunk + for (int i = 0; i < trunkHeight; i++) { + if (!editSession.setBlockIfAir(basePos.add(0, i, 0), logBlock)) { + return; + } + } + + // Move up + basePos = basePos.add(0, trunkHeight, 0); + + // Create tree + leaves + for (int i = 0; i < height; i++) { + editSession.setBlockIfAir(basePos.add(0, i, 0), logBlock); + + // Less leaves at these levels + double chance = ((i == 0 || i == height - 1) ? 0.6 : 1); + + // Inner leaves + editSession.setChanceBlockIfAir(basePos.add(-1, i, 0), leavesBlock, chance); + editSession.setChanceBlockIfAir(basePos.add(1, i, 0), leavesBlock, chance); + editSession.setChanceBlockIfAir(basePos.add(0, i, -1), leavesBlock, chance); + editSession.setChanceBlockIfAir(basePos.add(0, i, 1), leavesBlock, chance); + editSession.setChanceBlockIfAir(basePos.add(1, i, 1), leavesBlock, chance); + editSession.setChanceBlockIfAir(basePos.add(-1, i, 1), leavesBlock, chance); + editSession.setChanceBlockIfAir(basePos.add(1, i, -1), leavesBlock, chance); + editSession.setChanceBlockIfAir(basePos.add(-1, i, -1), leavesBlock, chance); + + if (!(i == 0 || i == height - 1)) { + for (int j = -2; j <= 2; j++) { + editSession.setChanceBlockIfAir(basePos.add(-2, i, j), leavesBlock, 0.6); + } + for (int j = -2; j <= 2; j++) { + editSession.setChanceBlockIfAir(basePos.add(2, i, j), leavesBlock, 0.6); + } + for (int j = -2; j <= 2; j++) { + editSession.setChanceBlockIfAir(basePos.add(j, i, -2), leavesBlock, 0.6); + } + for (int j = -2; j <= 2; j++) { + editSession.setChanceBlockIfAir(basePos.add(j, i, 2), leavesBlock, 0.6); + } + } + } + + editSession.setBlockIfAir(basePos.add(0, height, 0), leavesBlock); + } + + /** + * Looks up a tree type. May return null if a tree type by that + * name is not found. + * + * @param type + * @return + */ + public static TreeType lookup(String type) { + return TreeType.lookup(type); + } +}