package org.bukkit.craftbukkit.inventory; import com.google.common.base.Objects; import com.google.common.collect.ImmutableMap; import java.util.Map; import net.minecraft.server.BlockJukeBox; import net.minecraft.server.NBTBase; import net.minecraft.server.NBTTagCompound; import net.minecraft.server.TileEntity; import net.minecraft.server.TileEntityBanner; import net.minecraft.server.TileEntityBeacon; import net.minecraft.server.TileEntityBrewingStand; import net.minecraft.server.TileEntityChest; import net.minecraft.server.TileEntityCommand; import net.minecraft.server.TileEntityComparator; import net.minecraft.server.TileEntityDispenser; import net.minecraft.server.TileEntityDropper; import net.minecraft.server.TileEntityEnchantTable; import net.minecraft.server.TileEntityEndGateway; import net.minecraft.server.TileEntityEnderChest; import net.minecraft.server.TileEntityFlowerPot; import net.minecraft.server.TileEntityFurnace; import net.minecraft.server.TileEntityHopper; import net.minecraft.server.TileEntityLightDetector; import net.minecraft.server.TileEntityMobSpawner; import net.minecraft.server.TileEntityNote; import net.minecraft.server.TileEntityShulkerBox; import net.minecraft.server.TileEntitySign; import net.minecraft.server.TileEntitySkull; import net.minecraft.server.TileEntityStructure; import org.apache.commons.lang3.Validate; import org.bukkit.Material; import org.bukkit.block.BlockState; import org.bukkit.configuration.serialization.DelegateDeserialization; import org.bukkit.craftbukkit.block.CraftBanner; import org.bukkit.craftbukkit.block.CraftBeacon; import org.bukkit.craftbukkit.block.CraftBlockState; import org.bukkit.craftbukkit.block.CraftBrewingStand; import org.bukkit.craftbukkit.block.CraftChest; import org.bukkit.craftbukkit.block.CraftCommandBlock; import org.bukkit.craftbukkit.block.CraftComparator; import org.bukkit.craftbukkit.block.CraftCreatureSpawner; import org.bukkit.craftbukkit.block.CraftDaylightDetector; import org.bukkit.craftbukkit.block.CraftDispenser; import org.bukkit.craftbukkit.block.CraftDropper; import org.bukkit.craftbukkit.block.CraftEnchantingTable; import org.bukkit.craftbukkit.block.CraftEndGateway; import org.bukkit.craftbukkit.block.CraftEnderChest; import org.bukkit.craftbukkit.block.CraftFlowerPot; import org.bukkit.craftbukkit.block.CraftFurnace; import org.bukkit.craftbukkit.block.CraftHopper; import org.bukkit.craftbukkit.block.CraftJukebox; import org.bukkit.craftbukkit.block.CraftNoteBlock; import org.bukkit.craftbukkit.block.CraftShulkerBox; import org.bukkit.craftbukkit.block.CraftSign; import org.bukkit.craftbukkit.block.CraftSkull; import org.bukkit.craftbukkit.block.CraftStructureBlock; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.inventory.meta.BlockStateMeta; @DelegateDeserialization(CraftMetaItem.SerializableMeta.class) public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta { @ItemMetaKey.Specific(ItemMetaKey.Specific.To.NBT) static final ItemMetaKey BLOCK_ENTITY_TAG = new ItemMetaKey("BlockEntityTag"); final Material material; NBTTagCompound blockEntityTag; CraftMetaBlockState(CraftMetaItem meta, Material material) { super(meta); this.material = material; if (!(meta instanceof CraftMetaBlockState) || ((CraftMetaBlockState) meta).material != material) { blockEntityTag = null; return; } CraftMetaBlockState te = (CraftMetaBlockState) meta; this.blockEntityTag = te.blockEntityTag; } CraftMetaBlockState(NBTTagCompound tag, Material material) { super(tag); this.material = material; if (tag.hasKeyOfType(BLOCK_ENTITY_TAG.NBT, CraftMagicNumbers.NBT.TAG_COMPOUND)) { blockEntityTag = tag.getCompound(BLOCK_ENTITY_TAG.NBT); } else { blockEntityTag = null; } } CraftMetaBlockState(Map<String, Object> map) { super(map); String matName = SerializableMeta.getString(map, "blockMaterial", true); Material m = Material.getMaterial(matName); if (m != null) { material = m; } else { material = Material.AIR; } } @Override void applyToItem(NBTTagCompound tag) { super.applyToItem(tag); if (blockEntityTag != null) { tag.set(BLOCK_ENTITY_TAG.NBT, blockEntityTag); } } @Override void deserializeInternal(NBTTagCompound tag) { if (tag.hasKeyOfType(BLOCK_ENTITY_TAG.NBT, CraftMagicNumbers.NBT.TAG_COMPOUND)) { blockEntityTag = tag.getCompound(BLOCK_ENTITY_TAG.NBT); } } @Override void serializeInternal(final Map<String, NBTBase> internalTags) { if (blockEntityTag != null) { internalTags.put(BLOCK_ENTITY_TAG.NBT, blockEntityTag); } } @Override ImmutableMap.Builder<String, Object> serialize(ImmutableMap.Builder<String, Object> builder) { super.serialize(builder); builder.put("blockMaterial", material.name()); return builder; } @Override int applyHash() { final int original; int hash = original = super.applyHash(); if (blockEntityTag != null) { hash = 61 * hash + this.blockEntityTag.hashCode(); } return original != hash ? CraftMetaBlockState.class.hashCode() ^ hash : hash; } @Override public boolean equalsCommon(CraftMetaItem meta) { if (!super.equalsCommon(meta)) { return false; } if (meta instanceof CraftMetaBlockState) { CraftMetaBlockState that = (CraftMetaBlockState) meta; return Objects.equal(this.blockEntityTag, that.blockEntityTag); } return true; } @Override boolean notUncommon(CraftMetaItem meta) { return super.notUncommon(meta) && (meta instanceof CraftMetaBlockState || blockEntityTag == null); } @Override boolean isEmpty() { return super.isEmpty() && blockEntityTag == null; } @Override boolean applicableTo(Material type) { switch(type){ case FURNACE: case CHEST: case TRAPPED_CHEST: case JUKEBOX: case DISPENSER: case DROPPER: case SIGN: case MOB_SPAWNER: case NOTE_BLOCK: case PISTON_BASE: case BREWING_STAND_ITEM: case ENCHANTMENT_TABLE: case COMMAND: case COMMAND_REPEATING: case COMMAND_CHAIN: case BEACON: case DAYLIGHT_DETECTOR: case DAYLIGHT_DETECTOR_INVERTED: case HOPPER: case REDSTONE_COMPARATOR: case FLOWER_POT_ITEM: case SHIELD: case STRUCTURE_BLOCK: case WHITE_SHULKER_BOX: case ORANGE_SHULKER_BOX: case MAGENTA_SHULKER_BOX: case LIGHT_BLUE_SHULKER_BOX: case YELLOW_SHULKER_BOX: case LIME_SHULKER_BOX: case PINK_SHULKER_BOX: case GRAY_SHULKER_BOX: case SILVER_SHULKER_BOX: case CYAN_SHULKER_BOX: case PURPLE_SHULKER_BOX: case BLUE_SHULKER_BOX: case BROWN_SHULKER_BOX: case GREEN_SHULKER_BOX: case RED_SHULKER_BOX: case BLACK_SHULKER_BOX: case ENDER_CHEST: return true; } return false; } @Override public boolean hasBlockState() { return blockEntityTag != null; } @Override public BlockState getBlockState() { if (blockEntityTag != null) { switch (material) { case SHIELD: blockEntityTag.setString("id", "banner"); break; case WHITE_SHULKER_BOX: case ORANGE_SHULKER_BOX: case MAGENTA_SHULKER_BOX: case LIGHT_BLUE_SHULKER_BOX: case YELLOW_SHULKER_BOX: case LIME_SHULKER_BOX: case PINK_SHULKER_BOX: case GRAY_SHULKER_BOX: case SILVER_SHULKER_BOX: case CYAN_SHULKER_BOX: case PURPLE_SHULKER_BOX: case BLUE_SHULKER_BOX: case BROWN_SHULKER_BOX: case GREEN_SHULKER_BOX: case RED_SHULKER_BOX: case BLACK_SHULKER_BOX: blockEntityTag.setString("id", "shulker_box"); break; } } TileEntity te = (blockEntityTag == null) ? null : TileEntity.a(null, blockEntityTag); switch (material) { case SIGN: case SIGN_POST: case WALL_SIGN: if (te == null) { te = new TileEntitySign(); } return new CraftSign(material, (TileEntitySign) te); case CHEST: case TRAPPED_CHEST: if (te == null) { te = new TileEntityChest(); } return new CraftChest(material, (TileEntityChest) te); case BURNING_FURNACE: case FURNACE: if (te == null) { te = new TileEntityFurnace(); } return new CraftFurnace(material, (TileEntityFurnace) te); case DISPENSER: if (te == null) { te = new TileEntityDispenser(); } return new CraftDispenser(material, (TileEntityDispenser) te); case DROPPER: if (te == null) { te = new TileEntityDropper(); } return new CraftDropper(material, (TileEntityDropper) te); case END_GATEWAY: if (te == null) { te = new TileEntityEndGateway(); } return new CraftEndGateway(material, (TileEntityEndGateway) te); case HOPPER: if (te == null) { te = new TileEntityHopper(); } return new CraftHopper(material, (TileEntityHopper) te); case MOB_SPAWNER: if (te == null) { te = new TileEntityMobSpawner(); } return new CraftCreatureSpawner(material, (TileEntityMobSpawner) te); case NOTE_BLOCK: if (te == null) { te = new TileEntityNote(); } return new CraftNoteBlock(material, (TileEntityNote) te); case JUKEBOX: if (te == null) { te = new BlockJukeBox.TileEntityRecordPlayer(); } return new CraftJukebox(material, (BlockJukeBox.TileEntityRecordPlayer) te); case BREWING_STAND_ITEM: if (te == null) { te = new TileEntityBrewingStand(); } return new CraftBrewingStand(material, (TileEntityBrewingStand) te); case SKULL: if (te == null) { te = new TileEntitySkull(); } return new CraftSkull(material, (TileEntitySkull) te); case COMMAND: case COMMAND_REPEATING: case COMMAND_CHAIN: if (te == null) { te = new TileEntityCommand(); } return new CraftCommandBlock(material, (TileEntityCommand) te); case BEACON: if (te == null) { te = new TileEntityBeacon(); } return new CraftBeacon(material, (TileEntityBeacon) te); case SHIELD: case BANNER: case WALL_BANNER: case STANDING_BANNER: if (te == null) { te = new TileEntityBanner(); } return new CraftBanner(material, (TileEntityBanner) te); case FLOWER_POT_ITEM: if (te == null) { te = new TileEntityFlowerPot(); } return new CraftFlowerPot(material, (TileEntityFlowerPot) te); case STRUCTURE_BLOCK: if (te == null) { te = new TileEntityStructure(); } return new CraftStructureBlock(material, (TileEntityStructure) te); case WHITE_SHULKER_BOX: case ORANGE_SHULKER_BOX: case MAGENTA_SHULKER_BOX: case LIGHT_BLUE_SHULKER_BOX: case YELLOW_SHULKER_BOX: case LIME_SHULKER_BOX: case PINK_SHULKER_BOX: case GRAY_SHULKER_BOX: case SILVER_SHULKER_BOX: case CYAN_SHULKER_BOX: case PURPLE_SHULKER_BOX: case BLUE_SHULKER_BOX: case BROWN_SHULKER_BOX: case GREEN_SHULKER_BOX: case RED_SHULKER_BOX: case BLACK_SHULKER_BOX: if (te == null) { te = new TileEntityShulkerBox(); } return new CraftShulkerBox(material, (TileEntityShulkerBox) te); case ENCHANTMENT_TABLE: if (te == null) { te = new TileEntityEnchantTable(); } return new CraftEnchantingTable(material, (TileEntityEnchantTable) te); case ENDER_CHEST: if (te == null){ te = new TileEntityEnderChest(); } return new CraftEnderChest(material, (TileEntityEnderChest) te); case DAYLIGHT_DETECTOR: case DAYLIGHT_DETECTOR_INVERTED: if (te == null){ te = new TileEntityLightDetector(); } return new CraftDaylightDetector(material, (TileEntityLightDetector) te); case REDSTONE_COMPARATOR: if (te == null){ te = new TileEntityComparator(); } return new CraftComparator(material, (TileEntityComparator) te); default: throw new IllegalStateException("Missing blockState for " + material); } } @Override public void setBlockState(BlockState blockState) { Validate.notNull(blockState, "blockState must not be null"); TileEntity te = ((CraftBlockState) blockState).getTileEntity(); Validate.notNull(te, "Invalid tile for " + blockState); boolean valid; switch (material) { case SIGN: case SIGN_POST: case WALL_SIGN: valid = te instanceof TileEntitySign; break; case CHEST: case TRAPPED_CHEST: valid = te instanceof TileEntityChest; break; case BURNING_FURNACE: case FURNACE: valid = te instanceof TileEntityFurnace; break; case DISPENSER: valid = te instanceof TileEntityDispenser; break; case DROPPER: valid = te instanceof TileEntityDropper; break; case END_GATEWAY: valid = te instanceof TileEntityEndGateway; break; case HOPPER: valid = te instanceof TileEntityHopper; break; case MOB_SPAWNER: valid = te instanceof TileEntityMobSpawner; break; case NOTE_BLOCK: valid = te instanceof TileEntityNote; break; case JUKEBOX: valid = te instanceof BlockJukeBox.TileEntityRecordPlayer; break; case BREWING_STAND_ITEM: valid = te instanceof TileEntityBrewingStand; break; case SKULL: valid = te instanceof TileEntitySkull; break; case COMMAND: case COMMAND_REPEATING: case COMMAND_CHAIN: valid = te instanceof TileEntityCommand; break; case BEACON: valid = te instanceof TileEntityBeacon; break; case SHIELD: case BANNER: case WALL_BANNER: case STANDING_BANNER: valid = te instanceof TileEntityBanner; break; case FLOWER_POT_ITEM: valid = te instanceof TileEntityFlowerPot; break; case STRUCTURE_BLOCK: valid = te instanceof TileEntityStructure; break; case WHITE_SHULKER_BOX: case ORANGE_SHULKER_BOX: case MAGENTA_SHULKER_BOX: case LIGHT_BLUE_SHULKER_BOX: case YELLOW_SHULKER_BOX: case LIME_SHULKER_BOX: case PINK_SHULKER_BOX: case GRAY_SHULKER_BOX: case SILVER_SHULKER_BOX: case CYAN_SHULKER_BOX: case PURPLE_SHULKER_BOX: case BLUE_SHULKER_BOX: case BROWN_SHULKER_BOX: case GREEN_SHULKER_BOX: case RED_SHULKER_BOX: case BLACK_SHULKER_BOX: valid = te instanceof TileEntityShulkerBox; break; case ENCHANTMENT_TABLE: valid = te instanceof TileEntityEnchantTable; break; case ENDER_CHEST: valid = te instanceof TileEntityEnderChest; break; case DAYLIGHT_DETECTOR: case DAYLIGHT_DETECTOR_INVERTED: valid = te instanceof TileEntityLightDetector; break; case REDSTONE_COMPARATOR: valid = te instanceof TileEntityComparator; break; default: valid = false; break; } Validate.isTrue(valid, "Invalid blockState for " + material); blockEntityTag = new NBTTagCompound(); te.save(blockEntityTag); } }