From ca1e522499207fb4602c61e980bae25fc1dd97fe Mon Sep 17 00:00:00 2001 From: sk89q Date: Sun, 24 Oct 2010 23:42:56 -0700 Subject: [PATCH] Added chest support. Double-width chests don't work too well yet. --- src/CuboidClipboard.java | 8 +- src/EditSession.java | 26 ++- src/SMServerInterface.java | 54 ++++++ src/com/sk89q/worldedit/Countable.java | 74 ++++++++ src/com/sk89q/worldedit/ServerInterface.java | 21 +++ src/com/sk89q/worldedit/blocks/BaseItem.java | 84 +++++++++ .../sk89q/worldedit/blocks/ChestBlock.java | 164 ++++++++++++++++++ src/com/sk89q/worldedit/data/Chunk.java | 13 +- 8 files changed, 435 insertions(+), 9 deletions(-) create mode 100644 src/com/sk89q/worldedit/Countable.java create mode 100644 src/com/sk89q/worldedit/blocks/BaseItem.java create mode 100644 src/com/sk89q/worldedit/blocks/ChestBlock.java diff --git a/src/CuboidClipboard.java b/src/CuboidClipboard.java index 2ec613243..bb76f72bf 100644 --- a/src/CuboidClipboard.java +++ b/src/CuboidClipboard.java @@ -359,13 +359,19 @@ public class CuboidClipboard { int index = y * width * length + z * width + x; BlockVector pt = new BlockVector(x, y, z); BaseBlock block; - + if (blocks[index] == 63 || blocks[index] == 68) { block = new SignBlock(blocks[index], blockData[index]); if (tileEntitiesMap.containsKey(pt)) { ((TileEntityBlock)block).fromTileEntityNBT( tileEntitiesMap.get(pt)); } + } else if(blocks[index] == 54) { + block = new ChestBlock(); + if (tileEntitiesMap.containsKey(pt)) { + ((TileEntityBlock)block).fromTileEntityNBT( + tileEntitiesMap.get(pt)); + } } else { block = new BaseBlock(blocks[index], blockData[index]); } diff --git a/src/EditSession.java b/src/EditSession.java index 570b739de..975c5beec 100644 --- a/src/EditSession.java +++ b/src/EditSession.java @@ -116,19 +116,27 @@ public class EditSession { private boolean rawSetBlock(Vector pt, BaseBlock block) { boolean result = server.setBlockType(pt, block.getID()); if (block.getID() != 0) { - // Changes in block data don't take effect if the block type doesn't - // change, so here's a hack! - /*if (!result) { - server.setBlockType(pt, 0); - result = server.setBlockType(pt, block.getID()); - } - server.setBlockData(pt, block.getData());*/ + server.setBlockData(pt, block.getData()); // Signs if (block instanceof SignBlock) { SignBlock signBlock = (SignBlock)block; String[] text = signBlock.getText(); server.setSignText(pt, text); + // Chests + } else if (block instanceof ChestBlock) { + ChestBlock chestBlock = (ChestBlock)block; + BaseItem blankItem = new BaseItem((short)1); + Map> items = chestBlock.getItems(); + for (byte i = 0; i <= 26; i++) { + Countable item = items.get(i); + if (item != null) { + server.setChestSlot(pt, i, item.getID(), + item.getAmount()); + } else { + server.setChestSlot(pt, i, blankItem, 0); + } + } } } @@ -234,6 +242,10 @@ public class EditSession { if (type == 63 || type == 68) { String[] text = server.getSignText(pt); return new SignBlock(type, data, text); + // Chest + } else if (type == 54) { + Map> items = server.getChestContents(pt); + return new ChestBlock(data, items); } else { return new BaseBlock(type, data); } diff --git a/src/SMServerInterface.java b/src/SMServerInterface.java index 50276b7c0..34b7b12d3 100644 --- a/src/SMServerInterface.java +++ b/src/SMServerInterface.java @@ -18,6 +18,9 @@ */ import com.sk89q.worldedit.*; +import com.sk89q.worldedit.blocks.BaseItem; +import java.util.Map; +import java.util.HashMap; /** * @@ -108,4 +111,55 @@ public class SMServerInterface implements ServerInterface { } return text; } + + /** + * Gets the contents of chests. + * + * @param pt + * @return + */ + public Map> getChestContents(Vector pt) { + ComplexBlock cblock = etc.getServer().getComplexBlock( + pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + + if (!(cblock instanceof Chest)) { + return null; + } + + Chest chest = (Chest)cblock; + Map> items = + new HashMap>(); + + for (byte i = 0; i <= 26; i++) { + Item item = chest.getItemFromSlot(i); + if (item != null) { + items.put(i, new Countable(new BaseItem((short)item.getItemId()), item.getAmount())); + } + } + + return items; + } + + /** + * Sets a chest slot. + * + * @param pt + * @param slot + * @param item + * @param amount + * @return + */ + public boolean setChestSlot(Vector pt, byte slot, BaseItem item, int amount) { + ComplexBlock cblock = etc.getServer().getComplexBlock( + pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + + if (!(cblock instanceof Chest)) { + return false; + } + + Chest chest = (Chest)cblock; + chest.addItem(new Item(item.getID(), amount, slot)); + chest.update(); + return true; + } } diff --git a/src/com/sk89q/worldedit/Countable.java b/src/com/sk89q/worldedit/Countable.java new file mode 100644 index 000000000..91918aed8 --- /dev/null +++ b/src/com/sk89q/worldedit/Countable.java @@ -0,0 +1,74 @@ +// $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; + +/** + * + * @author sk89q + */ +public class Countable { + /** + * ID. + */ + private T id; + /** + * Amount. + */ + private int amount; + + /** + * Construct the object. + * + * @param id + * @param amount + */ + public Countable(T id, int amount) { + this.id = id; + this.amount = amount; + } + + /** + * @return the id + */ + public T getID() { + return id; + } + + /** + * @param id the id to set + */ + public void setID(T id) { + this.id = id; + } + + /** + * @return the amount + */ + public int getAmount() { + return amount; + } + + /** + * @param amount the amount to set + */ + public void setAmount(int amount) { + this.amount = amount; + } +} diff --git a/src/com/sk89q/worldedit/ServerInterface.java b/src/com/sk89q/worldedit/ServerInterface.java index 7ebeffd96..63f48d6bf 100644 --- a/src/com/sk89q/worldedit/ServerInterface.java +++ b/src/com/sk89q/worldedit/ServerInterface.java @@ -19,6 +19,10 @@ package com.sk89q.worldedit; +import java.util.Map; +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.blocks.BaseItem; + /** * * @author sk89q @@ -68,4 +72,21 @@ public interface ServerInterface { * @return */ public String[] getSignText(Vector pt); + /** + * Gets the contents of chests. + * + * @param pt + * @return + */ + public Map> getChestContents(Vector pt); + /** + * Sets a chest slot. + * + * @param pt + * @param slot + * @param item + * @param amount + * @return + */ + public boolean setChestSlot(Vector pt, byte slot, BaseItem item, int amount); } diff --git a/src/com/sk89q/worldedit/blocks/BaseItem.java b/src/com/sk89q/worldedit/blocks/BaseItem.java new file mode 100644 index 000000000..20d2abc79 --- /dev/null +++ b/src/com/sk89q/worldedit/blocks/BaseItem.java @@ -0,0 +1,84 @@ +// $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 an item. + * + * @author sk89q + */ +public class BaseItem { + /** + * Item ID. + */ + private short id; + /** + * Item damage. + */ + private short damage; + + /** + * Construct the object. + * + * @param id + */ + public BaseItem(short id) { + this.id = id; + this.damage = 0; + } + + /** + * Construct the object. + * + * @param id + */ + public BaseItem(short id, short damage) { + this.id = id; + this.damage = damage; + } + + /** + * @return the id + */ + public short getID() { + return id; + } + + /** + * @param id the id to set + */ + public void setID(short id) { + this.id = id; + } + + /** + * @return the damage + */ + public short getDamage() { + return damage; + } + + /** + * @param damage the damage to set + */ + public void setDamage(short damage) { + this.damage = damage; + } +} diff --git a/src/com/sk89q/worldedit/blocks/ChestBlock.java b/src/com/sk89q/worldedit/blocks/ChestBlock.java new file mode 100644 index 000000000..785aa1e64 --- /dev/null +++ b/src/com/sk89q/worldedit/blocks/ChestBlock.java @@ -0,0 +1,164 @@ +// $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.*; +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 chests. + * + * @author sk89q + */ +public class ChestBlock extends BaseBlock implements TileEntityBlock { + /** + * Store the list of items. + */ + private Map> items; + + /** + * Construct the chest block. + */ + public ChestBlock() { + super(54); + items = new HashMap>(); + } + + /** + * Construct the chest block. + * + * @param data + */ + public ChestBlock(int data) { + super(54, data); + items = new HashMap>(); + } + + /** + * Construct the chest block. + * + * @param data + * @param items + */ + public ChestBlock(int data, Map> items) { + super(54, data); + this.items = items; + } + + /** + * Get the list of items. + * + * @return + */ + public Map> getItems() { + return items; + } + + /** + * Set the list of items. + * + * @return + */ + public void setItems(Map> items) { + this.items = items; + } + + /** + * Get the tile entity ID. + * + * @return + */ + public String getTileEntityID() { + return "Chest"; + } + + /** + * 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 (Map.Entry> entry : items.entrySet()) { + Map data = new HashMap(); + CompoundTag item = new CompoundTag("Items", data); + BaseItem i = entry.getValue().getID(); + data.put("id", new ShortTag("id", i.getID())); + data.put("Damage", new ShortTag("Damage", i.getDamage())); + data.put("Count", new ByteTag("Count", (byte)entry.getValue().getAmount())); + data.put("Slot", new ByteTag("Slot", entry.getKey())); + itemsList.add(item); + } + 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; + } + + Map> newItems = new HashMap>(); + + Tag t = values.get("id"); + if (!(t instanceof StringTag) || !((StringTag)t).getValue().equals("Chest")) { + throw new DataException("'Chest' tile entity expected"); + } + + ListTag items = (ListTag)Chunk.getChildTag(values, "Items", ListTag.class); + + for (Tag tag : items.getValue()) { + if (!(tag instanceof CompoundTag)) { + throw new DataException("CompoundTag expected as child tag of Chest's 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(); + + newItems.put(slot, new Countable(new BaseItem(id, damage), count)); + } + + this.items = newItems; + } +} diff --git a/src/com/sk89q/worldedit/data/Chunk.java b/src/com/sk89q/worldedit/data/Chunk.java index a4e8972d2..c50e9f856 100644 --- a/src/com/sk89q/worldedit/data/Chunk.java +++ b/src/com/sk89q/worldedit/data/Chunk.java @@ -199,6 +199,17 @@ public class Chunk { ((TileEntityBlock)block).fromTileEntityNBT(tileEntity); } + return block; + // Chests + } else if (id == 54) { + ChestBlock block = new ChestBlock(); + + Map tileEntity = getBlockTileEntity(pos); + + if (tileEntity != null) { + ((TileEntityBlock)block).fromTileEntityNBT(tileEntity); + } + return block; } else { return new BaseBlock(id, data); @@ -214,7 +225,7 @@ public class Chunk { * @return child tag * @throws InvalidFormatException */ - private static Tag getChildTag(Map items, String key, Class expected) + public static Tag getChildTag(Map items, String key, Class expected) throws InvalidFormatException { if (!items.containsKey(key)) { throw new InvalidFormatException("Missing a \"" + key + "\" tag");