From 360ae06d653e52e4f92e31fe8ece4f74f8b798c0 Mon Sep 17 00:00:00 2001 From: sk89q Date: Sun, 23 Jan 2011 00:36:26 -0800 Subject: [PATCH] Added full block data support for Bukkit. --- src/com/sk89q/worldedit/CuboidClipboard.java | 34 +- src/com/sk89q/worldedit/EditSession.java | 68 ++- src/com/sk89q/worldedit/LocalWorld.java | 49 +-- src/com/sk89q/worldedit/blocks/BlockID.java | 7 + src/com/sk89q/worldedit/blocks/BlockType.java | 13 + .../sk89q/worldedit/blocks/ChestBlock.java | 2 +- .../worldedit/blocks/ContainerBlock.java | 41 ++ .../worldedit/blocks/DispenserBlock.java | 167 ++++++++ .../sk89q/worldedit/blocks/FurnaceBlock.java | 216 ++++++++++ .../worldedit/blocks/MobSpawnerBlock.java | 15 +- src/com/sk89q/worldedit/blocks/NoteBlock.java | 117 ++++++ .../bukkit/BukkitServerInterface.java | 4 +- .../sk89q/worldedit/bukkit/BukkitWorld.java | 388 +++++++++++++++--- 13 files changed, 971 insertions(+), 150 deletions(-) create mode 100644 src/com/sk89q/worldedit/blocks/ContainerBlock.java create mode 100644 src/com/sk89q/worldedit/blocks/DispenserBlock.java create mode 100644 src/com/sk89q/worldedit/blocks/FurnaceBlock.java create mode 100644 src/com/sk89q/worldedit/blocks/NoteBlock.java diff --git a/src/com/sk89q/worldedit/CuboidClipboard.java b/src/com/sk89q/worldedit/CuboidClipboard.java index 24449d4d0..fdea88da4 100644 --- a/src/com/sk89q/worldedit/CuboidClipboard.java +++ b/src/com/sk89q/worldedit/CuboidClipboard.java @@ -445,27 +445,27 @@ public class CuboidClipboard { BlockVector pt = new BlockVector(x, y, z); BaseBlock block; - if (blocks[index] == 63 || blocks[index] == 68) { // Signs + if (blocks[index] == BlockID.WALL_SIGN || blocks[index] == BlockID.SIGN_POST) { block = new SignBlock(blocks[index], blockData[index]); - if (tileEntitiesMap.containsKey(pt)) { - ((TileEntityBlock)block).fromTileEntityNBT( - tileEntitiesMap.get(pt)); - } - } else if(blocks[index] == 54) { // Chest - block = new ChestBlock(); - if (tileEntitiesMap.containsKey(pt)) { - ((TileEntityBlock)block).fromTileEntityNBT( - tileEntitiesMap.get(pt)); - } - } else if(blocks[index] == 52) { // Mob spawner - block = new MobSpawnerBlock(); - if (tileEntitiesMap.containsKey(pt)) { - ((TileEntityBlock)block).fromTileEntityNBT( - tileEntitiesMap.get(pt)); - } + } else if (blocks[index] == BlockID.CHEST) { + block = new ChestBlock(blockData[index]); + } else if (blocks[index] == BlockID.FURNACE || blocks[index] == BlockID.BURNING_FURNACE) { + block = new FurnaceBlock(blocks[index], blockData[index]); + } else if (blocks[index] == BlockID.DISPENSER) { + block = new DispenserBlock(blockData[index]); + } else if (blocks[index] == BlockID.MOB_SPAWNER) { + block = new MobSpawnerBlock(blockData[index]); + } else if (blocks[index] == BlockID.NOTE_BLOCK) { + block = new NoteBlock(blockData[index]); } else { block = new BaseBlock(blocks[index], blockData[index]); } + + if (block instanceof TileEntityBlock + && tileEntitiesMap.containsKey(pt)) { + ((TileEntityBlock)block).fromTileEntityNBT( + tileEntitiesMap.get(pt)); + } clipboard.data[x][y][z] = block; } diff --git a/src/com/sk89q/worldedit/EditSession.java b/src/com/sk89q/worldedit/EditSession.java index 5d8359273..ee3b1dbdb 100755 --- a/src/com/sk89q/worldedit/EditSession.java +++ b/src/com/sk89q/worldedit/EditSession.java @@ -150,9 +150,9 @@ public class EditSession { int existing = world.getBlockType(pt); - // Clear the chest so that it doesn't drop items - if (existing == 54 && blockBag == null) { - world.clearChest(pt); + // Clear the container block so that it doesn't drop items + if (BlockType.isContainerBlock(existing) && blockBag == null) { + world.clearContainerBlockContents(pt); // Ice turns until water so this has to be done first } else if (existing == BlockID.ICE) { world.setBlockType(pt, 0); @@ -189,16 +189,27 @@ public class EditSession { // Signs if (block instanceof SignBlock) { SignBlock signBlock = (SignBlock) block; - String[] text = signBlock.getText(); - world.setSignText(pt, text); - // Chests + world.copyToWorld(pt, signBlock); + // Chests } else if (block instanceof ChestBlock && blockBag == null) { ChestBlock chestBlock = (ChestBlock) block; - world.setChestContents(pt, chestBlock.getItems()); - // Mob spawners + world.copyToWorld(pt, chestBlock); + // Furnaces + } else if (block instanceof FurnaceBlock && blockBag == null) { + FurnaceBlock furnaceBlock = (FurnaceBlock) block; + world.copyToWorld(pt, furnaceBlock); + // Dispenser + } else if (block instanceof DispenserBlock && blockBag == null) { + DispenserBlock dispenserBlock = (DispenserBlock) block; + world.copyToWorld(pt, dispenserBlock); + // Mob spawners } else if (block instanceof MobSpawnerBlock) { MobSpawnerBlock mobSpawnerblock = (MobSpawnerBlock) block; - world.setMobSpawnerType(pt, mobSpawnerblock.getMobType()); + world.copyToWorld(pt, mobSpawnerblock); + // Note blocks + } else if (block instanceof NoteBlock) { + NoteBlock noteBlock = (NoteBlock) block; + world.copyToWorld(pt, noteBlock); } } @@ -305,16 +316,35 @@ public class EditSession { int data = world.getBlockData(pt); // Sign - if (type == 63 || type == 68) { - String[] text = world.getSignText(pt); - return new SignBlock(type, data, text); - // Chest - } else if (type == 54) { - BaseItemStack[] items = world.getChestContents(pt); - return new ChestBlock(data, items); - // Mob spawner - } else if (type == 52) { - return new MobSpawnerBlock(data, world.getMobSpawnerType(pt)); + if (type == BlockID.WALL_SIGN || type == BlockID.SIGN_POST) { + SignBlock block = new SignBlock(type, data); + world.copyFromWorld(pt, block); + return block; + // Chest + } else if (type == BlockID.CHEST) { + ChestBlock block = new ChestBlock(data); + world.copyFromWorld(pt, block); + return block; + // Furnace + } else if (type == BlockID.FURNACE || type == BlockID.BURNING_FURNACE) { + FurnaceBlock block = new FurnaceBlock(type, data); + world.copyFromWorld(pt, block); + return block; + // Dispenser + } else if (type == BlockID.DISPENSER) { + DispenserBlock block = new DispenserBlock(data); + world.copyFromWorld(pt, block); + return block; + // Mob spawner + } else if (type == BlockID.MOB_SPAWNER) { + MobSpawnerBlock block = new MobSpawnerBlock(data); + world.copyFromWorld(pt, block); + return block; + // Note block + } else if (type == BlockID.NOTE_BLOCK) { + NoteBlock block = new NoteBlock(data); + world.copyFromWorld(pt, block); + return block; } else { return new BaseBlock(type, data); } diff --git a/src/com/sk89q/worldedit/LocalWorld.java b/src/com/sk89q/worldedit/LocalWorld.java index c56d2e00a..2a6fd9fa5 100644 --- a/src/com/sk89q/worldedit/LocalWorld.java +++ b/src/com/sk89q/worldedit/LocalWorld.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit; import java.util.Random; +import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseItemStack; /** @@ -68,63 +69,29 @@ public abstract class LocalWorld { public abstract int getBlockData(Vector pt); /** - * Set sign text. - * - * @param pt - * @param text - */ - public abstract void setSignText(Vector pt, String[] text); - - /** - * Get sign text. + * Attempts to accurately copy a BaseBlock's extra data to the world. * * @param pt + * @param block * @return */ - public abstract String[] getSignText(Vector pt); + public abstract boolean copyToWorld(Vector pt, BaseBlock block); /** - * Gets the contents of chests. Will return null if the chest does not - * really exist or it is the second block for a double chest. + * Attempts to read a BaseBlock's extra data from the world. * * @param pt + * @param block * @return */ - public abstract BaseItemStack[] getChestContents(Vector pt); - - /** - * Sets a chest slot. - * - * @param pt - * @param contents - * @return - */ - public abstract boolean setChestContents(Vector pt, - BaseItemStack[] contents); + public abstract boolean copyFromWorld(Vector pt, BaseBlock block); /** * Clear a chest's contents. * * @param pt */ - public abstract boolean clearChest(Vector pt); - - /** - * Set mob spawner mob type. - * - * @param pt - * @param mobType - */ - public abstract void setMobSpawnerType(Vector pt, - String mobType); - - /** - * Get mob spawner mob type. May return an empty string. - * - * @param pt - * @param mobType - */ - public abstract String getMobSpawnerType(Vector pt); + public abstract boolean clearContainerBlockContents(Vector pt); /** * Generate a tree at a location. diff --git a/src/com/sk89q/worldedit/blocks/BlockID.java b/src/com/sk89q/worldedit/blocks/BlockID.java index d62d9cf29..b73029d75 100644 --- a/src/com/sk89q/worldedit/blocks/BlockID.java +++ b/src/com/sk89q/worldedit/blocks/BlockID.java @@ -46,6 +46,11 @@ public final class BlockID { public static final int LEAVES = 18; public static final int SPONGE = 19; public static final int GLASS = 20; + public static final int LAPIS_LAZULI_ORE = 21; + public static final int LAPIS_LAZULI_BLOCK = 22; + public static final int DISPENSER = 23; + public static final int SANDSTONE = 24; + public static final int NOTE_BLOCK = 25; public static final int CLOTH = 35; public static final int YELLOW_FLOWER = 37; public static final int RED_FLOWER = 38; @@ -98,8 +103,10 @@ public final class BlockID { public static final int FENCE = 85; public static final int PUMPKIN = 86; public static final int NETHERSTONE = 87; + public static final int NETHERRACK = 87; public static final int SLOW_SAND = 88; public static final int LIGHTSTONE = 89; public static final int PORTAL = 90; public static final int JACKOLANTERN = 91; + public static final int CAKE_BLOCK = 92; } diff --git a/src/com/sk89q/worldedit/blocks/BlockType.java b/src/com/sk89q/worldedit/blocks/BlockType.java index bd981f22d..3e3cccb7d 100644 --- a/src/com/sk89q/worldedit/blocks/BlockType.java +++ b/src/com/sk89q/worldedit/blocks/BlockType.java @@ -399,6 +399,19 @@ public enum BlockType { || id == 86 // Pumpkin || id == 91; // Jack-o-lantern } + + /** + * Returns true if the block is a container block. + * + * @param id + * @return + */ + public static boolean isContainerBlock(int id) { + return id == 23 // Dispenser + || id == 61 // Furnace + || id == 62 // Furnace + || id == 54; // Chest + } /** * Get the block or item that would have been dropped. If nothing is diff --git a/src/com/sk89q/worldedit/blocks/ChestBlock.java b/src/com/sk89q/worldedit/blocks/ChestBlock.java index 5ef9a033f..f77a2c665 100644 --- a/src/com/sk89q/worldedit/blocks/ChestBlock.java +++ b/src/com/sk89q/worldedit/blocks/ChestBlock.java @@ -31,7 +31,7 @@ import org.jnbt.*; * * @author sk89q */ -public class ChestBlock extends BaseBlock implements TileEntityBlock { +public class ChestBlock extends BaseBlock implements TileEntityBlock, ContainerBlock { /** * Store the list of items. */ diff --git a/src/com/sk89q/worldedit/blocks/ContainerBlock.java b/src/com/sk89q/worldedit/blocks/ContainerBlock.java new file mode 100644 index 000000000..186f5b515 --- /dev/null +++ b/src/com/sk89q/worldedit/blocks/ContainerBlock.java @@ -0,0 +1,41 @@ +// $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.blocks; + +/** + * Represents a block that stores items. + * + * @author sk89q + */ +public interface ContainerBlock { + /** + * Get the list of items. + * + * @return + */ + public BaseItemStack[] getItems(); + + /** + * Set the list of items. + * + * @return + */ + public void setItems(BaseItemStack[] items); +} diff --git a/src/com/sk89q/worldedit/blocks/DispenserBlock.java b/src/com/sk89q/worldedit/blocks/DispenserBlock.java new file mode 100644 index 000000000..f495983dc --- /dev/null +++ b/src/com/sk89q/worldedit/blocks/DispenserBlock.java @@ -0,0 +1,167 @@ +// $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.blocks; + +import com.sk89q.worldedit.data.*; +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; +import org.jnbt.*; + +/** + * Represents dispensers. + * + * @author sk89q + */ +public class DispenserBlock extends BaseBlock implements TileEntityBlock, ContainerBlock { + /** + * Store the list of items. + */ + private BaseItemStack[] items; + + /** + * Construct the chest block. + */ + public DispenserBlock() { + super(54); + items = new BaseItemStack[9]; + } + + /** + * Construct the chest block. + * + * @param data + */ + public DispenserBlock(int data) { + super(23, data); + items = new BaseItemStack[9]; + } + + /** + * Construct the chest block. + * + * @param data + * @param items + */ + public DispenserBlock(int data, BaseItemStack[] items) { + super(23, data); + this.items = items; + } + + /** + * Get the list of items. + * + * @return + */ + public BaseItemStack[] getItems() { + return items; + } + + /** + * Set the list of items. + * + * @return + */ + public void setItems(BaseItemStack[] items) { + this.items = items; + } + + /** + * Get the tile entity ID. + * + * @return + */ + public String getTileEntityID() { + return "Trap"; + } + + /** + * Store additional tile entity data. Returns true if the data is used. + * + * @return map of values + * @throws DataException + */ + public Map toTileEntityNBT() + throws DataException { + List itemsList = new ArrayList(); + for (int i = 0; i < items.length; i++) { + BaseItemStack item = items[i]; + if (item != null) { + Map data = new HashMap(); + CompoundTag itemTag = new CompoundTag("Items", data); + data.put("id", new ShortTag("id", (short)item.getType())); + data.put("Damage", new ShortTag("Damage", item.getDamage())); + data.put("Count", new ByteTag("Count", (byte)item.getAmount())); + data.put("Slot", new ByteTag("Slot", (byte)i)); + itemsList.add(itemTag); + } + } + Map values = new HashMap(); + values.put("Items", new ListTag("Items", CompoundTag.class, itemsList)); + return values; + } + + /** + * Get additional information from the title entity data. + * + * @param values + * @throws DataException + */ + public void fromTileEntityNBT(Map values) + throws DataException { + if (values == null) { + return; + } + + + Tag t = values.get("id"); + if (!(t instanceof StringTag) || !((StringTag)t).getValue().equals("Trap")) { + throw new DataException("'Trap' tile entity expected"); + } + + ListTag items = (ListTag)Chunk.getChildTag(values, "Items", ListTag.class); + BaseItemStack[] newItems = new BaseItemStack[27]; + + for (Tag tag : items.getValue()) { + if (!(tag instanceof CompoundTag)) { + throw new DataException("CompoundTag expected as child tag of Trap Items"); + } + + CompoundTag item = (CompoundTag)tag; + Map itemValues = item.getValue(); + + short id = (Short)((ShortTag)Chunk.getChildTag(itemValues, "id", ShortTag.class)) + .getValue(); + short damage = (Short)((ShortTag)Chunk.getChildTag(itemValues, "Damage", ShortTag.class)) + .getValue(); + byte count = (Byte)((ByteTag)Chunk.getChildTag(itemValues, "Count", ByteTag.class)) + .getValue(); + byte slot = (Byte)((ByteTag)Chunk.getChildTag(itemValues, "Slot", ByteTag.class)) + .getValue(); + + if (slot >= 0 && slot <= 26) { + newItems[slot] = new BaseItemStack(id, count, damage); + } + } + + this.items = newItems; + } +} diff --git a/src/com/sk89q/worldedit/blocks/FurnaceBlock.java b/src/com/sk89q/worldedit/blocks/FurnaceBlock.java new file mode 100644 index 000000000..6b132a9d9 --- /dev/null +++ b/src/com/sk89q/worldedit/blocks/FurnaceBlock.java @@ -0,0 +1,216 @@ +// $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.blocks; + +import com.sk89q.worldedit.data.*; +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; +import org.jnbt.*; + +/** + * Represents furnaces. + * + * @author sk89q + */ +public class FurnaceBlock extends BaseBlock implements TileEntityBlock, ContainerBlock { + /** + * Store the list of items. + */ + private BaseItemStack[] items; + + /** + * Fuel time. + */ + private short burnTime; + + /** + * Cook time. + */ + private short cookTime; + + /** + * Construct the chest block. + */ + public FurnaceBlock(int type) { + super(type); + items = new BaseItemStack[2]; + } + + /** + * Construct the chest block. + * + * @param data + */ + public FurnaceBlock(int type, int data) { + super(type, data); + items = new BaseItemStack[2]; + } + + /** + * Construct the chest block. + * + * @param data + * @param items + */ + public FurnaceBlock(int type, int data, BaseItemStack[] items) { + super(type, data); + this.items = items; + } + + /** + * Get the list of items. + * + * @return + */ + public BaseItemStack[] getItems() { + return items; + } + + /** + * Set the list of items. + * + * @return + */ + public void setItems(BaseItemStack[] items) { + this.items = items; + } + + /** + * @return the burnTime + */ + public short getBurnTime() { + return burnTime; + } + + /** + * @param burnTime the burnTime to set + */ + public void setBurnTime(short burnTime) { + this.burnTime = burnTime; + } + + /** + * @return the cookTime + */ + public short getCookTime() { + return cookTime; + } + + /** + * @param cookTime the cookTime to set + */ + public void setCookTime(short cookTime) { + this.cookTime = cookTime; + } + + /** + * Get the tile entity ID. + * + * @return + */ + public String getTileEntityID() { + return "Furnace"; + } + + /** + * Store additional tile entity data. Returns true if the data is used. + * + * @return map of values + * @throws DataException + */ + public Map toTileEntityNBT() + throws DataException { + List itemsList = new ArrayList(); + for (int i = 0; i < items.length; i++) { + BaseItemStack item = items[i]; + if (item != null) { + Map data = new HashMap(); + CompoundTag itemTag = new CompoundTag("Items", data); + data.put("id", new ShortTag("id", (short)item.getType())); + data.put("Damage", new ShortTag("Damage", item.getDamage())); + data.put("Count", new ByteTag("Count", (byte)item.getAmount())); + data.put("Slot", new ByteTag("Slot", (byte)i)); + itemsList.add(itemTag); + } + } + Map values = new HashMap(); + values.put("Items", new ListTag("Items", CompoundTag.class, itemsList)); + values.put("BurnTime", new ShortTag("BurnTime", burnTime)); + values.put("CookTime", new ShortTag("CookTime", cookTime)); + return values; + } + + /** + * Get additional information from the title entity data. + * + * @param values + * @throws DataException + */ + public void fromTileEntityNBT(Map values) + throws DataException { + if (values == null) { + return; + } + + Tag t = values.get("id"); + if (!(t instanceof StringTag) || !((StringTag)t).getValue().equals("Furnace")) { + throw new DataException("'Furnace' tile entity expected"); + } + + ListTag items = (ListTag)Chunk.getChildTag(values, "Items", ListTag.class); + BaseItemStack[] newItems = new BaseItemStack[27]; + + for (Tag tag : items.getValue()) { + if (!(tag instanceof CompoundTag)) { + throw new DataException("CompoundTag expected as child tag of Trap Items"); + } + + CompoundTag item = (CompoundTag)tag; + Map itemValues = item.getValue(); + + short id = (Short)((ShortTag)Chunk.getChildTag(itemValues, "id", ShortTag.class)) + .getValue(); + short damage = (Short)((ShortTag)Chunk.getChildTag(itemValues, "Damage", ShortTag.class)) + .getValue(); + byte count = (Byte)((ByteTag)Chunk.getChildTag(itemValues, "Count", ByteTag.class)) + .getValue(); + byte slot = (Byte)((ByteTag)Chunk.getChildTag(itemValues, "Slot", ByteTag.class)) + .getValue(); + + if (slot >= 0 && slot <= 26) { + newItems[slot] = new BaseItemStack(id, count, damage); + } + } + + this.items = newItems; + + t = values.get("BurnTime"); + if (t instanceof ShortTag) { + burnTime = ((ShortTag)t).getValue(); + } + + t = values.get("CookTime"); + if (t instanceof ShortTag) { + cookTime = ((ShortTag)t).getValue(); + } + } +} diff --git a/src/com/sk89q/worldedit/blocks/MobSpawnerBlock.java b/src/com/sk89q/worldedit/blocks/MobSpawnerBlock.java index 118b70ab1..45b8c5d82 100644 --- a/src/com/sk89q/worldedit/blocks/MobSpawnerBlock.java +++ b/src/com/sk89q/worldedit/blocks/MobSpawnerBlock.java @@ -51,7 +51,7 @@ public class MobSpawnerBlock extends BaseBlock implements TileEntityBlock { /** * Construct the mob spawner block. * - * @param items + * @param mobType */ public MobSpawnerBlock(String mobType) { super(52); @@ -62,7 +62,16 @@ public class MobSpawnerBlock extends BaseBlock implements TileEntityBlock { * Construct the mob spawner block. * * @param data - * @param items + */ + public MobSpawnerBlock(int data) { + super(52, data); + } + + /** + * Construct the mob spawner block. + * + * @param data + * @param mobType */ public MobSpawnerBlock(int data, String mobType) { super(52, data); @@ -120,7 +129,7 @@ public class MobSpawnerBlock extends BaseBlock implements TileEntityBlock { throws DataException { Map values = new HashMap(); values.put("EntityId", new StringTag("EntityId", mobType)); - values.put("Delay", new ShortTag("Delay", (short)0)); + values.put("Delay", new ShortTag("Delay", delay)); return values; } diff --git a/src/com/sk89q/worldedit/blocks/NoteBlock.java b/src/com/sk89q/worldedit/blocks/NoteBlock.java new file mode 100644 index 000000000..978917b53 --- /dev/null +++ b/src/com/sk89q/worldedit/blocks/NoteBlock.java @@ -0,0 +1,117 @@ +// $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.blocks; + +import com.sk89q.worldedit.data.*; +import java.util.Map; +import java.util.HashMap; +import org.jnbt.*; + +/** + * + * @author sk89q + */ +public class NoteBlock extends BaseBlock implements TileEntityBlock { + /** + * Stores the pitch. + */ + private byte note; + + /** + * Construct the sign without text. + * + * @param data + */ + public NoteBlock(int data) { + super(25, data); + this.note = 0; + } + + /** + * Construct the sign with text. + * + * @param note + */ + public NoteBlock(int data, byte note) { + super(25, data); + this.note = note; + } + + /** + * @return the note + */ + public byte getNote() { + return note; + } + + /** + * @param note the note to set + */ + public void setNote(byte note) { + this.note = note; + } + + /** + * Return the name of the title entity ID. + * + * @return title entity ID + */ + public String getTileEntityID() { + return "Music"; + } + + /** + * Store additional tile entity data. Returns true if the data is used. + * + * @return map of values + * @throws DataException + */ + public Map toTileEntityNBT() + throws DataException { + Map values = new HashMap(); + values.put("note", new ByteTag("note", note)); + return values; + } + + /** + * Get additional information from the title entity data. + * + * @param values + * @throws DataException + */ + public void fromTileEntityNBT(Map values) + throws DataException { + if (values == null) { + return; + } + + Tag t; + + t = values.get("id"); + if (!(t instanceof StringTag) || !((StringTag)t).getValue().equals("Music")) { + throw new DataException("'Music' tile entity expected"); + } + + t = values.get("note"); + if (t instanceof ByteTag) { + note = ((ByteTag)t).getValue(); + } + } +} diff --git a/src/com/sk89q/worldedit/bukkit/BukkitServerInterface.java b/src/com/sk89q/worldedit/bukkit/BukkitServerInterface.java index 8b90aeeed..7827082da 100644 --- a/src/com/sk89q/worldedit/bukkit/BukkitServerInterface.java +++ b/src/com/sk89q/worldedit/bukkit/BukkitServerInterface.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.bukkit; import org.bukkit.*; +import org.bukkit.entity.MobType; import com.sk89q.worldedit.ServerInterface; public class BukkitServerInterface extends ServerInterface { @@ -37,8 +38,7 @@ public class BukkitServerInterface extends ServerInterface { @Override public boolean isValidMobType(String type) { - // TODO Auto-generated method stub - return false; + return MobType.fromName(type) != null; } } diff --git a/src/com/sk89q/worldedit/bukkit/BukkitWorld.java b/src/com/sk89q/worldedit/bukkit/BukkitWorld.java index 88ed8b7f4..9e9c26f5d 100644 --- a/src/com/sk89q/worldedit/bukkit/BukkitWorld.java +++ b/src/com/sk89q/worldedit/bukkit/BukkitWorld.java @@ -23,14 +23,17 @@ 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; +import org.bukkit.block.MobSpawner; import org.bukkit.block.Sign; +import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.Location; import org.bukkit.World; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalWorld; import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.blocks.*; public class BukkitWorld extends LocalWorld { /** @@ -40,51 +43,302 @@ public class BukkitWorld extends LocalWorld { private World world; + /** + * Construct the object. + * @param world + */ public BukkitWorld(World world) { this.world = world; } + /** + * Get the world handle. + * + * @return + */ public World getWorld() { return world; } + /** + * Set block type. + * + * @param pt + * @param type + * @return + */ @Override public boolean setBlockType(Vector pt, int type) { return world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setTypeId(type); } + /** + * Get block type. + * + * @param pt + * @return + */ @Override public int getBlockType(Vector pt) { return world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).getTypeId(); } + /** + * Set block data. + * + * @param pt + * @param data + * @return + */ @Override public void setBlockData(Vector pt, int data) { world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setData((byte)data); } + /** + * Get block data. + * + * @param pt + * @return + */ @Override public int getBlockData(Vector pt) { return world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).getData(); } + /** + * Attempts to accurately copy a BaseBlock's extra data to the world. + * + * @param pt + * @param block + * @return + */ @Override - public void setSignText(Vector pt, String[] text) { + public boolean copyToWorld(Vector pt, BaseBlock block) { + // Signs + if (block instanceof SignBlock) { + setSignText(pt, ((SignBlock)block).getText()); + return true; + + // Furnaces + } else if (block instanceof FurnaceBlock) { + Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + if (bukkitBlock == null) return false; + BlockState state = bukkitBlock.getState(); + if (!(state instanceof Furnace)) return false; + Furnace bukkit = (Furnace)state; + FurnaceBlock we = (FurnaceBlock)block; + bukkit.setBurnTime(we.getBurnTime()); + bukkit.setCookTime(we.getCookTime()); + return setContainerBlockContents(pt, ((ContainerBlock)block).getItems()); + + // Chests/dispenser + } else if (block instanceof ContainerBlock) { + return setContainerBlockContents(pt, ((ContainerBlock)block).getItems()); + + // Mob spawners + } else if (block instanceof MobSpawnerBlock) { + Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + if (bukkitBlock == null) return false; + BlockState state = bukkitBlock.getState(); + if (!(state instanceof MobSpawner)) return false; + MobSpawner bukkit = (MobSpawner)state; + MobSpawnerBlock we = (MobSpawnerBlock)block; + bukkit.setMobTypeId(we.getMobType()); + bukkit.setDelay(we.getDelay()); + return true; + + // Note block + } else if (block instanceof NoteBlock) { + Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + if (bukkitBlock == null) return false; + BlockState state = bukkitBlock.getState(); + if (!(state instanceof org.bukkit.block.NoteBlock)) return false; + org.bukkit.block.NoteBlock bukkit = (org.bukkit.block.NoteBlock)state; + NoteBlock we = (NoteBlock)block; + bukkit.setNote(we.getNote()); + return true; + } + + return false; + } + + /** + * Attempts to read a BaseBlock's extra data from the world. + * + * @param pt + * @param block + * @return + */ + @Override + public boolean copyFromWorld(Vector pt, BaseBlock block) { + // Signs + if (block instanceof SignBlock) { + ((SignBlock)block).setText(getSignText(pt)); + return true; + + // Furnaces + } else if (block instanceof FurnaceBlock) { + Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + if (bukkitBlock == null) return false; + BlockState state = bukkitBlock.getState(); + if (!(state instanceof Furnace)) return false; + Furnace bukkit = (Furnace)state; + FurnaceBlock we = (FurnaceBlock)block; + we.setBurnTime(bukkit.getBurnTime()); + we.setCookTime(bukkit.getCookTime()); + ((ContainerBlock)block).setItems(getContainerBlockContents(pt)); + return true; + + // Chests/dispenser + } else if (block instanceof ContainerBlock) { + ((ContainerBlock)block).setItems(getContainerBlockContents(pt)); + return true; + + // Mob spawners + } else if (block instanceof MobSpawnerBlock) { + Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + if (bukkitBlock == null) return false; + BlockState state = bukkitBlock.getState(); + if (!(state instanceof MobSpawner)) return false; + MobSpawner bukkit = (MobSpawner)state; + MobSpawnerBlock we = (MobSpawnerBlock)block; + we.setMobType(bukkit.getMobTypeId()); + we.setDelay((short)bukkit.getDelay()); + return true; + + // Note block + } else if (block instanceof NoteBlock) { + Block bukkitBlock = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + if (bukkitBlock == null) return false; + BlockState state = bukkitBlock.getState(); + if (!(state instanceof org.bukkit.block.NoteBlock)) return false; + org.bukkit.block.NoteBlock bukkit = (org.bukkit.block.NoteBlock)state; + NoteBlock we = (NoteBlock)block; + we.setNote(bukkit.getNote()); + } + + return false; + } + + /** + * Clear a chest's contents. + * + * @param pt + */ + @Override + public boolean clearContainerBlockContents(Vector pt) { Block block = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - if (block == null) return; + if (block == null) { + return false; + } BlockState state = block.getState(); - if (state == null || !(state instanceof Sign)) return; + if (!(state instanceof org.bukkit.block.ContainerBlock)) { + return false; + } + + org.bukkit.block.ContainerBlock chest = (org.bukkit.block.ContainerBlock)state; + Inventory inven = chest.getInventory(); + inven.clear(); + return true; + } + + /** + * Generate a tree at a location. + * + * @param pt + * @return + */ + @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; + } + } + + /** + * Generate a big tree at a location. + * + * @param pt + * @return + */ + @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; + } + } + + /** + * Drop an item. + * + * @param pt + * @param item + */ + @Override + public void dropItem(Vector pt, BaseItemStack item) { + ItemStack bukkitItem = new ItemStack(item.getType(), item.getAmount(), + (byte)item.getDamage()); + world.dropItemNaturally(toLocation(pt), bukkitItem); + + } + + /** + * Kill mobs in an area. + * + * @param origin + * @param radius + * @return + */ + @Override + public int killMobs(Vector origin, int radius) { + // TODO Auto-generated method stub + return 0; + } + + private Location toLocation(Vector pt) { + return new Location(world, pt.getX(), pt.getY(), pt.getZ()); + } + + /** + * Set a sign's text. + * + * @param pt + * @param text + * @return + */ + private boolean setSignText(Vector pt, String[] text) { + Block block = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + if (block == null) return false; + BlockState state = block.getState(); + if (state == null || !(state instanceof Sign)) return false; Sign sign = (Sign)state; sign.setLine(0, text[0]); sign.setLine(1, text[1]); sign.setLine(2, text[2]); sign.setLine(3, text[3]); sign.update(); + return true; } - @Override - public String[] getSignText(Vector pt) { + /** + * Get a sign's text. + * + * @param pt + * @return + */ + private String[] getSignText(Vector pt) { Block block = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); if (block == null) return new String[] { "", "", "", "" }; BlockState state = block.getState(); @@ -102,76 +356,76 @@ public class BukkitWorld extends LocalWorld { }; } - @Override - public BaseItemStack[] getChestContents(Vector pt) { - // TODO Auto-generated method stub - return new BaseItemStack[0]; - } - - @Override - public boolean setChestContents(Vector pt, BaseItemStack[] contents) { - // TODO Auto-generated method stub - return false; - } - - @Override - public boolean clearChest(Vector pt) { - // TODO Auto-generated method stub - return false; - } - - @Override - public void setMobSpawnerType(Vector pt, String mobType) { - // TODO Auto-generated method stub + /** + * Get a container block's contents. + * + * @param pt + * @return + */ + private BaseItemStack[] getContainerBlockContents(Vector pt) { + Block block = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + if (block == null) { + return new BaseItemStack[0]; + } + BlockState state = block.getState(); + if (!(state instanceof org.bukkit.block.ContainerBlock)) { + return new BaseItemStack[0]; + } + org.bukkit.block.ContainerBlock container = (org.bukkit.block.ContainerBlock)state; + Inventory inven = container.getInventory(); + int size = inven.getSize(); + BaseItemStack[] contents = new BaseItemStack[size]; + + for (int i = 0; i < size; i++) { + ItemStack bukkitStack = inven.getItem(i); + if (bukkitStack.getTypeId() > 0) { + contents[i] = new BaseItemStack( + bukkitStack.getTypeId(), + bukkitStack.getAmount(), + bukkitStack.getDamage()); + } + } + + return contents; } - @Override - public String getMobSpawnerType(Vector pt) { - // TODO Auto-generated method stub - return ""; - } - - @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); + /** + * Set a container block's contents. + * + * @param pt + * @param contents + * @return + */ + private boolean setContainerBlockContents(Vector pt, BaseItemStack[] contents) { + Block block = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + if (block == null) { return false; } - } - - @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); + BlockState state = block.getState(); + if (!(state instanceof org.bukkit.block.ContainerBlock)) { return false; } - } - - @Override - public void dropItem(Vector pt, BaseItemStack item) { - ItemStack bukkitItem = new ItemStack(item.getType(), item.getAmount(), - (byte)item.getDamage()); - world.dropItemNaturally(toLocation(pt), bukkitItem); - } + org.bukkit.block.ContainerBlock chest = (org.bukkit.block.ContainerBlock)state; + Inventory inven = chest.getInventory(); + int size = inven.getSize(); + + for (int i = 0; i < size; i++) { + if (i >= contents.length + 1) { + break; + } - @Override - public int killMobs(Vector origin, int radius) { - // TODO Auto-generated method stub - return 0; - } - - private Location toLocation(Vector pt) { - return new Location(world, pt.getX(), pt.getY(), pt.getZ()); + if (contents[i] != null) { + inven.setItem(i, new ItemStack(contents[i].getType(), + contents[i].getAmount(), + (byte)contents[i].getDamage())); + } else { + inven.setItem(i, null); + } + } + + return true; } @Override