Added more tree generators, removed CraftBukkit/MC dependency (yay!).

Dieser Commit ist enthalten in:
sk89q 2011-01-30 14:54:42 -08:00
Ursprung 68b12f4c7d
Commit 10b48e9344
14 geänderte Dateien mit 430 neuen und 472 gelöschten Zeilen

Datei anzeigen

@ -11,8 +11,6 @@
<fileset dir="${lib.dir}" id="libs">
<include name="truezip.jar" />
<include name="minecraft_server_cb.jar" />
<include name="CraftBukkit.jar" />
<include name="Bukkit.jar" />
<include name="GroupUsers.jar" />
<include name="Permissions.jar" />

Datei anzeigen

@ -71,10 +71,7 @@ commands:
usage: /<command> <block> <radius> [raised?]
forestgen:
description: Generate a forest
usage: /<command> [size] [density]
pinegen:
description: Generate a pine forest
usage: /<command> [size] [density]
usage: /<command> [size] [type] [density]
pumpkins:
description: Generate pumpkin patches
usage: /<command> [size]
@ -197,12 +194,6 @@ commands:
none:
description: Turn off all superpickaxe alternate modes
usage: /<command>
bigtree:
description: Big tree generator tool
usage: /<command>
pinetree:
description: Pine tree generator tool
usage: /<command>
repl:
description: Block replacer tool
usage: /<command> <block>
@ -226,7 +217,7 @@ commands:
usage: /<command>
tree:
description: Tree generator tool
usage: /<command>
usage: /<command> [type]
/fillr:
description: Fill a hole recursively
usage: /<command> <block> <radius> [depth]

Datei anzeigen

@ -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;
}
}

Datei anzeigen

@ -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.

Datei anzeigen

@ -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());
}

Datei anzeigen

@ -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));
}
/**

Datei anzeigen

@ -1,115 +0,0 @@
// $Id$
/*
* WorldEdit
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
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 <T>
* @param clazz
* @return
* @throws Throwable
*/
@SuppressWarnings("rawtypes")
private static <T> T createNoConstructor(Class<T> 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;
}
}
}

Datei anzeigen

@ -1,4 +1,3 @@
package com.sk89q.worldedit.bukkit;
// $Id$
/*
* WorldEdit
@ -18,7 +17,9 @@ package com.sk89q.worldedit.bukkit;
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import net.minecraft.server.World;
package com.sk89q.worldedit.bukkit;
import org.bukkit.BlockChangeDelegate;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.MaxChangedBlocksException;
@ -29,64 +30,30 @@ import com.sk89q.worldedit.blocks.BaseBlock;
*
* @author sk89q
*/
public class WorldSetBlockProxy extends World {
/**
* Edit session.
*/
public class EditSessionBlockChangeDegate implements BlockChangeDelegate {
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)");
public EditSessionBlockChangeDegate(EditSession editSession) {
this.editSession = editSession;
}
/**
* 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) {
public boolean setTypeId(int x, int y, int z, int typeId) {
try {
return editSession.setBlock(new Vector(x, y, z), new BaseBlock(blockType));
return editSession.setBlock(new Vector(x, y, z), new BaseBlock(typeId));
} 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) {
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();
}
/**
* @return
*/
public EditSession getEditSession() {
return editSession;
}
/**
* @param editSession
*/
public void setEditSession(EditSession editSession) {
this.editSession = editSession;
}
}

Datei anzeigen

@ -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
@ -143,31 +144,20 @@ public class GenerationCommands {
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;
int affected = editSession.makeForest(player.getPosition(),
size, density, false);
player.print(affected + " trees created.");
if (type == null) {
player.printError("Tree type '" + args.getString(1) + "' is unknown.");
return;
} else {
}
@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.");
size, density, new TreeGenerator(type));
player.print(affected + " trees created.");
}
@Command(

Datei anzeigen

@ -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 = "<block>",

Datei anzeigen

@ -1,49 +0,0 @@
// $Id$
/*
* WorldEdit
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
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;
}
}

Datei anzeigen

@ -1,49 +0,0 @@
// $Id$
/*
* WorldEdit
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
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;
}
}

Datei anzeigen

@ -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);
}

Datei anzeigen

@ -0,0 +1,240 @@
// $Id$
/*
* WorldEdit
* Copyright (C) 2010, 2011 sk89q <http://www.sk89q.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
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<String,TreeType> lookup = new HashMap<String,TreeType>();
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);
}
}