From b609114a8a7a5595edbee295c24890877b9b48bc Mon Sep 17 00:00:00 2001 From: sk89q Date: Sat, 6 Nov 2010 21:03:34 -0700 Subject: [PATCH] Changed /forestgen to use Notch's tree generation code and made /pinegen to use the old generator. Both commands now support a density argument. --- src/EditSession.java | 138 +++++++++++++++++--------------- src/MinecraftSetBlockProxy.java | 89 ++++++++++++++++++++ src/ServerInterface.java | 62 ++++++++++++++ src/WorldEditListener.java | 21 ++++- 4 files changed, 241 insertions(+), 69 deletions(-) create mode 100644 src/MinecraftSetBlockProxy.java diff --git a/src/EditSession.java b/src/EditSession.java index 890d4c299..44ac76fcb 100644 --- a/src/EditSession.java +++ b/src/EditSession.java @@ -1275,67 +1275,6 @@ public class EditSession { return false; } - /** - * Makes a terrible looking pine tree. - * - * @param basePos - */ - private 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); - - int pos2[] = {-2, 2}; - - // 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); - } - /** * Makes a pumpkin patch. * @@ -1436,14 +1375,16 @@ public class EditSession { } /** - * Makes a terrible looking pine forest. + * Makes a forest. * * @param basePos * @param size + * @param density + * @param pineTree * @return number of trees created */ - public int makePineTreeForest(Vector basePos, int size) - throws MaxChangedBlocksException { + public int makeForest(Vector basePos, int size, double density, + boolean pineTree) throws MaxChangedBlocksException { int affected = 0; for (int x = basePos.getBlockX() - size; x <= basePos.getBlockX() + size; x++) { @@ -1452,13 +1393,17 @@ public class EditSession { if (!getBlock(new Vector(x, basePos.getBlockY(), z)).isAir()) continue; // The gods don't want a tree here - if (Math.random() < 0.95) { continue; } + if (Math.random() >= density) { continue; } // def 0.05 for (int y = basePos.getBlockY(); y >= basePos.getBlockY() - 10; y--) { // Check if we hit the ground int t = getBlock(new Vector(x, y, z)).getID(); if (t == 2 || t == 3) { - makePineTree(new Vector(x, y + 1, z)); + if (pineTree) { + makePineTree(new Vector(x, y + 1, z)); + } else { + ServerInterface.generateTree(this, new Vector(x, y + 1, z)); + } affected++; break; } else if (t != 0) { // Trees won't grow on this! @@ -1470,4 +1415,65 @@ public class EditSession { return affected; } + + /** + * Makes a terrible looking pine tree. + * + * @param basePos + */ + private 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); + + int pos2[] = {-2, 2}; + + // 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); + } } diff --git a/src/MinecraftSetBlockProxy.java b/src/MinecraftSetBlockProxy.java new file mode 100644 index 000000000..3e929f40d --- /dev/null +++ b/src/MinecraftSetBlockProxy.java @@ -0,0 +1,89 @@ +// $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 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 MinecraftSetBlockProxy extends el { + /** + * Edit session. + */ + private EditSession editSession; + + /** + * Constructor that should NOT be called. + * + * @param editSession + */ + public MinecraftSetBlockProxy(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 a(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)).getID(); + } + + /** + * @return + */ + public EditSession getEditSession() { + return editSession; + } + + /** + * @param editSession + */ + public void setEditSession(EditSession editSession) { + this.editSession = editSession; + } +} diff --git a/src/ServerInterface.java b/src/ServerInterface.java index b28210133..06035be96 100644 --- a/src/ServerInterface.java +++ b/src/ServerInterface.java @@ -19,14 +19,32 @@ import com.sk89q.worldedit.*; import com.sk89q.worldedit.blocks.BaseItem; +import java.util.logging.Logger; +import java.util.logging.Level; import java.util.Map; import java.util.HashMap; +import java.util.Random; +import java.lang.reflect.Constructor; +import sun.reflect.ReflectionFactory; /** * * @author sk89q */ public class ServerInterface { + /** + * 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 MinecraftSetBlockProxy proxy; + /** * Set block type. * @@ -165,4 +183,48 @@ public class ServerInterface { chest.update(); return true; } + + /** + * Generate a tree at a location. + * + * @param pt + * @return + */ + public static boolean generateTree(EditSession editSession, Vector pt) { + if (proxy == null) { + try { + proxy = createNoConstructor(MinecraftSetBlockProxy.class); + } catch (Throwable t) { + logger.log(Level.WARNING, "setBlock() proxy class failed to construct", + t); + return false; + } + } + proxy.setEditSession(editSession); + + bg treeGen = new gy(); + return treeGen.a(proxy, random, + pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + } + + /** + * Instantiate a class without calling its constructor. + * + * @param + * @param clazz + * @return + * @throws Throwable + */ + 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/WorldEditListener.java b/src/WorldEditListener.java index 28cefa0ce..1431f2798 100644 --- a/src/WorldEditListener.java +++ b/src/WorldEditListener.java @@ -159,7 +159,8 @@ public class WorldEditListener extends PluginListener { commands.put("/fixwater", "[Radius] - Level nearby pools of water"); commands.put("/fixlava", "[Radius] - Level nearby pools of lava"); commands.put("/ex", "[Size] - Extinguish fires"); - commands.put("/forestgen", " - Make an ugly pine tree forest"); + commands.put("/forestgen", " - Make Notch tree forest"); + commands.put("/pinegen", " - Make an ugly pine tree forest"); commands.put("/pumpkins", " - Make a pumpkin forest"); commands.put("/unstuck", "Go up to the first free spot"); commands.put("/ascend", "Go up one level"); @@ -892,12 +893,26 @@ public class WorldEditListener extends PluginListener { return true; - // Make pine tree forest + // Make tree forest } else if (split[0].equalsIgnoreCase("/forestgen")) { + checkArgs(split, 0, 2, split[0]); + int size = split.length > 1 ? Math.max(1, Integer.parseInt(split[1])) : 10; + double density = split.length > 2 ? Double.parseDouble(split[2]) / 100 : 0.05; + + int affected = editSession.makeForest(player.getPosition(), + size, density, false); + player.print(affected + " trees created."); + + return true; + + // Make pine tree forest + } else if (split[0].equalsIgnoreCase("/pinegen")) { checkArgs(split, 0, 1, split[0]); int size = split.length > 1 ? Math.max(1, Integer.parseInt(split[1])) : 10; + double density = split.length > 2 ? Double.parseDouble(split[2]) / 100 : 0.05; - int affected = editSession.makePineTreeForest(player.getPosition(), size); + int affected = editSession.makeForest(player.getPosition(), + size, density, true); player.print(affected + " pine trees created."); return true;