From 24f43ae5a64a8b0ae0d3e3211d6bee7f3d6b7f0e Mon Sep 17 00:00:00 2001 From: Celtic Minstrel Date: Sun, 26 Feb 2012 22:07:26 -0500 Subject: [Bleeding] MaterialData fixes. Addresses BUKKIT-842 --- src/main/java/org/bukkit/Material.java | 36 +++-- src/main/java/org/bukkit/material/Cauldron.java | 51 +++++++ src/main/java/org/bukkit/material/Door.java | 12 +- src/main/java/org/bukkit/material/Gate.java | 91 ++++++++++++ src/main/java/org/bukkit/material/Mushroom.java | 182 +++++++++++++++++++++++ src/main/java/org/bukkit/material/Openable.java | 17 +++ src/main/java/org/bukkit/material/SpawnEgg.java | 52 +++++++ src/main/java/org/bukkit/material/TrapDoor.java | 53 ++++--- src/main/java/org/bukkit/material/Vine.java | 185 ++++++++++++++++++++++++ 9 files changed, 631 insertions(+), 48 deletions(-) create mode 100644 src/main/java/org/bukkit/material/Cauldron.java create mode 100644 src/main/java/org/bukkit/material/Gate.java create mode 100644 src/main/java/org/bukkit/material/Mushroom.java create mode 100644 src/main/java/org/bukkit/material/Openable.java create mode 100644 src/main/java/org/bukkit/material/SpawnEgg.java create mode 100644 src/main/java/org/bukkit/material/Vine.java diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java index 69963a1c..942957c7 100644 --- a/src/main/java/org/bukkit/Material.java +++ b/src/main/java/org/bukkit/Material.java @@ -7,7 +7,9 @@ import java.util.logging.Level; import java.util.logging.Logger; import org.apache.commons.lang.Validate; +import org.bukkit.map.MapView; import org.bukkit.material.*; +import org.bukkit.potion.Potion; import org.bukkit.util.Java15Compat; import com.google.common.collect.Maps; @@ -115,26 +117,26 @@ public enum Material { TRAP_DOOR(96, TrapDoor.class), MONSTER_EGGS(97, MonsterEggs.class), SMOOTH_BRICK(98, SmoothBrick.class), - HUGE_MUSHROOM_1(99), - HUGE_MUSHROOM_2(100), + HUGE_MUSHROOM_1(99, Mushroom.class), + HUGE_MUSHROOM_2(100, Mushroom.class), IRON_FENCE(101), THIN_GLASS(102), MELON_BLOCK(103), - PUMPKIN_STEM(104), - MELON_STEM(105), - VINE(106), - FENCE_GATE(107), - BRICK_STAIRS(108), - SMOOTH_STAIRS(109), + PUMPKIN_STEM(104, MaterialData.class), + MELON_STEM(105, MaterialData.class), + VINE(106, Vine.class), + FENCE_GATE(107, Gate.class), + BRICK_STAIRS(108, Stairs.class), + SMOOTH_STAIRS(109, Stairs.class), MYCEL(110), WATER_LILY(111), NETHER_BRICK(112), NETHER_FENCE(113), - NETHER_BRICK_STAIRS(114), - NETHER_WARTS(115), + NETHER_BRICK_STAIRS(114, Stairs.class), + NETHER_WARTS(115, MaterialData.class), ENCHANTMENT_TABLE(116), - BREWING_STAND(117), - CAULDRON(118), + BREWING_STAND(117, MaterialData.class), + CAULDRON(118, Cauldron.class), ENDER_PORTAL(119), ENDER_PORTAL_FRAME(120), ENDER_STONE(121), @@ -242,6 +244,9 @@ public enum Material { BED(355, 1), DIODE(356), COOKIE(357), + /** + * @see MapView + */ MAP(358, 1, MaterialData.class), SHEARS(359, 1, 238), MELON(360), @@ -257,7 +262,10 @@ public enum Material { GHAST_TEAR(370), GOLD_NUGGET(371), NETHER_STALK(372), - POTION(373, 1), + /** + * @see Potion + */ + POTION(373, 1, MaterialData.class), GLASS_BOTTLE(374), SPIDER_EYE(375), FERMENTED_SPIDER_EYE(376), @@ -267,7 +275,7 @@ public enum Material { CAULDRON_ITEM(380), EYE_OF_ENDER(381), SPECKLED_MELON(382), - MONSTER_EGG(383, 1), + MONSTER_EGG(383, 1, SpawnEgg.class), GOLD_RECORD(2256, 1), GREEN_RECORD(2257, 1), RECORD_3(2258, 1), diff --git a/src/main/java/org/bukkit/material/Cauldron.java b/src/main/java/org/bukkit/material/Cauldron.java new file mode 100644 index 00000000..3a923cba --- /dev/null +++ b/src/main/java/org/bukkit/material/Cauldron.java @@ -0,0 +1,51 @@ +package org.bukkit.material; + +import org.bukkit.Material; + +/** + * Represents a cauldron + */ +public class Cauldron extends MaterialData { + private static final int CAULDRON_FULL = 3; + private static final int CAULDRON_EMPTY = 0; + + public Cauldron() { + super(Material.CAULDRON); + } + + public Cauldron(int type, byte data){ + super(type, data); + } + + public Cauldron(byte data) { + super(Material.CAULDRON, data); + } + + /** + * Check if the cauldron is full. + * + * @return True if it is full. + */ + public boolean isFull() { + return getData() >= CAULDRON_FULL; + } + + /** + * Check if the cauldron is empty. + * + * @return True if it is empty. + */ + public boolean isEmpty() { + return getData() <= CAULDRON_EMPTY; + } + + @Override + public String toString() { + return (isEmpty() ? "EMPTY" : (isFull() ? "FULL" : getData() + "/3 FULL")) + " CAULDRON"; + } + + @Override + public Cauldron clone() { + return (Cauldron) super.clone(); + } +} diff --git a/src/main/java/org/bukkit/material/Door.java b/src/main/java/org/bukkit/material/Door.java index 14226790..e992c28e 100644 --- a/src/main/java/org/bukkit/material/Door.java +++ b/src/main/java/org/bukkit/material/Door.java @@ -6,7 +6,7 @@ import org.bukkit.block.BlockFace; /** * Represents a door. */ -public class Door extends MaterialData implements Directional { +public class Door extends MaterialData implements Directional, Openable { public Door() { super(Material.WOODEN_DOOR); } @@ -27,20 +27,10 @@ public class Door extends MaterialData implements Directional { super(type, data); } - /** - * Check to see if the door is open. - * - * @return true if the door has swung counterclockwise around its hinge. - */ public boolean isOpen() { return ((getData() & 0x4) == 0x4); } - /** - * Configure this door to be either open or closed; - * - * @param isOpen True to open the door. - */ public void setOpen(boolean isOpen) { setData((byte) (isOpen ? (getData() | 0x4) : (getData() & ~0x4))); } diff --git a/src/main/java/org/bukkit/material/Gate.java b/src/main/java/org/bukkit/material/Gate.java new file mode 100644 index 00000000..e80abe7a --- /dev/null +++ b/src/main/java/org/bukkit/material/Gate.java @@ -0,0 +1,91 @@ +package org.bukkit.material; + +import org.bukkit.Material; +import org.bukkit.block.BlockFace; + +/** + * Represents a fence gate + */ +public class Gate extends MaterialData implements Directional, Openable { + private static final byte OPEN_BIT = 0x4; + private static final byte DIR_BIT = 0x3; + private static final byte GATE_SOUTH = 0x0; + private static final byte GATE_WEST = 0x1; + private static final byte GATE_NORTH = 0x2; + private static final byte GATE_EAST = 0x3; + + public Gate() { + super(Material.FENCE_GATE); + } + + public Gate(int type, byte data){ + super(type, data); + } + + public Gate(byte data) { + super(Material.FENCE_GATE, data); + } + + public void setFacingDirection(BlockFace face) { + byte data = (byte) (getData() &~ DIR_BIT); + + switch (face) { + default: + case SOUTH: + data |= GATE_SOUTH; + break; + case WEST: + data |= GATE_WEST; + break; + case NORTH: + data |= GATE_NORTH; + break; + case EAST: + data |= GATE_EAST; + break; + } + + setData(data); + } + + public BlockFace getFacing() { + switch (getData() & DIR_BIT) { + case GATE_SOUTH: + return BlockFace.SOUTH; + case GATE_WEST: + return BlockFace.WEST; + case GATE_NORTH: + return BlockFace.NORTH; + case GATE_EAST: + return BlockFace.EAST; + } + + return BlockFace.SOUTH; + } + + public boolean isOpen() { + return (getData() & OPEN_BIT) > 0; + } + + public void setOpen(boolean isOpen) { + byte data = getData(); + + if (isOpen) { + data |= OPEN_BIT; + } else { + data &= ~OPEN_BIT; + } + + setData(data); + } + + @Override + public String toString() { + return (isOpen() ? "OPEN " : "CLOSED ") + " facing and opening " + getFacing(); + } + + @Override + public Gate clone() { + return (Gate) super.clone(); + } +} \ No newline at end of file diff --git a/src/main/java/org/bukkit/material/Mushroom.java b/src/main/java/org/bukkit/material/Mushroom.java new file mode 100644 index 00000000..237a17a5 --- /dev/null +++ b/src/main/java/org/bukkit/material/Mushroom.java @@ -0,0 +1,182 @@ +package org.bukkit.material; + +import java.util.EnumSet; +import java.util.Set; + +import org.apache.commons.lang.Validate; +import org.bukkit.Material; +import org.bukkit.block.BlockFace; + +/** + * Represents a huge mushroom block + */ +public class Mushroom extends MaterialData { + private static final byte SHROOM_NONE = 0; + private static final byte SHROOM_STEM = 10; + private static final byte NORTH_LIMIT = 4; + private static final byte SOUTH_LIMIT = 6; + private static final byte EAST_WEST_LIMIT = 3; + private static final byte EAST_REMAINDER = 0; + private static final byte WEST_REMAINDER = 1; + private static final byte NORTH_SOUTH_MOD = 3; + private static final byte EAST_WEST_MOD = 1; + + public Mushroom(Material shroom) { + super(shroom); + Validate.isTrue(shroom == Material.HUGE_MUSHROOM_1 || shroom == Material.HUGE_MUSHROOM_2, "Not a mushroom!"); + } + + public Mushroom(Material shroom, byte data) { + super(shroom, data); + Validate.isTrue(shroom == Material.HUGE_MUSHROOM_1 || shroom == Material.HUGE_MUSHROOM_2, "Not a mushroom!"); + } + + public Mushroom(int type, byte data){ + super(type, data); + Validate.isTrue(type == Material.HUGE_MUSHROOM_1.getId() || type == Material.HUGE_MUSHROOM_2.getId(), "Not a mushroom!"); + } + + /** + * @return Whether this is a mushroom stem. + */ + public boolean isStem() { + return getData() == SHROOM_STEM; + } + + /** + * Sets this to be a mushroom stem. + */ + public void setStem() { + setData((byte) 10); + } + + /** + * Checks whether a face of the block is painted. + * @param face The face to check. + * @return True if it is painted. + */ + public boolean isFacePainted(BlockFace face) { + byte data = getData(); + + if (data == SHROOM_NONE || data == SHROOM_STEM) { + return false; + } + + switch (face) { + case NORTH: + return data < NORTH_LIMIT; + case SOUTH: + return data > SOUTH_LIMIT; + case EAST: + return data % EAST_WEST_LIMIT == EAST_REMAINDER; + case WEST: + return data % EAST_WEST_LIMIT == WEST_REMAINDER; + case UP: + return true; + default: + return false; + } + } + + /** + * Set a face of the block to be painted or not. Note that due to the nature of how the data is stored, + * setting a face painted or not is not guaranteed to leave the other faces unchanged. + * @param face The face to paint or unpaint. + * @param painted True if you want to paint it, false if you want the pores to show. + */ + public void setFacePainted(BlockFace face, boolean painted) { + if (painted == isFacePainted(face)) { + return; + } + + byte data = getData(); + + if (data == SHROOM_STEM) { + data = 5; + } + + switch (face) { + case NORTH: + if (painted) { + data -= NORTH_SOUTH_MOD; + } else { + data += NORTH_SOUTH_MOD; + } + + break; + case SOUTH: + if (painted) { + data += NORTH_SOUTH_MOD; + } else { + data -= NORTH_SOUTH_MOD; + } + + break; + case EAST: + if (painted) { + data += EAST_WEST_MOD; + } else { + data -= EAST_WEST_MOD; + } + + break; + case WEST: + if (painted) { + data -= EAST_WEST_MOD; + } else { + data += EAST_WEST_MOD; + } + + break; + case UP: + if (!painted) { + data = 0; + } + + break; + default: + throw new IllegalArgumentException("Can't paint that face of a mushroom!"); + } + + setData(data); + } + + /** + * @return A set of all faces that are currently painted (an empty set if it is a stem) + */ + public Set getPaintedFaces() { + EnumSet faces = EnumSet.noneOf(BlockFace.class); + + if (isFacePainted(BlockFace.NORTH)) { + faces.add(BlockFace.NORTH); + } + + if (isFacePainted(BlockFace.EAST)) { + faces.add(BlockFace.EAST); + } + + if (isFacePainted(BlockFace.WEST)) { + faces.add(BlockFace.WEST); + } + + if (isFacePainted(BlockFace.SOUTH)) { + faces.add(BlockFace.SOUTH); + } + + if (isFacePainted(BlockFace.UP)) { + faces.add(BlockFace.UP); + } + + return faces; + } + + @Override + public String toString() { + return Material.getMaterial(getItemTypeId()).toString() + (isStem() ? "{STEM}" : getPaintedFaces()); + } + + @Override + public Mushroom clone() { + return (Mushroom) super.clone(); + } +} diff --git a/src/main/java/org/bukkit/material/Openable.java b/src/main/java/org/bukkit/material/Openable.java new file mode 100644 index 00000000..17e5f022 --- /dev/null +++ b/src/main/java/org/bukkit/material/Openable.java @@ -0,0 +1,17 @@ +package org.bukkit.material; + +public interface Openable { + /** + * Check to see if the door is open. + * + * @return true if the door has swung counterclockwise around its hinge. + */ + boolean isOpen(); + + /** + * Configure this door to be either open or closed; + * + * @param isOpen True to open the door. + */ + void setOpen(boolean isOpen); +} diff --git a/src/main/java/org/bukkit/material/SpawnEgg.java b/src/main/java/org/bukkit/material/SpawnEgg.java new file mode 100644 index 00000000..7ee0f1bd --- /dev/null +++ b/src/main/java/org/bukkit/material/SpawnEgg.java @@ -0,0 +1,52 @@ +package org.bukkit.material; + +import org.bukkit.Material; +import org.bukkit.entity.EntityType; + +/** + * Represents a spawn egg that can be used to spawn mobs + */ +public class SpawnEgg extends MaterialData { + public SpawnEgg() { + super(Material.MONSTER_EGG); + } + + public SpawnEgg(int type, byte data){ + super(type, data); + } + + public SpawnEgg(byte data) { + super(Material.MONSTER_EGG, data); + } + + public SpawnEgg(EntityType type) { + this(); + setSpawnedType(type); + } + + /** + * Get the type of entity this egg will spawn. + * @return The entity type. + */ + public EntityType getSpawnedType() { + return EntityType.fromId(getData()); + } + + /** + * Set the type of entity this egg will spawn. + * @param type The entity type. + */ + public void setSpawnedType(EntityType type) { + setData((byte) type.getTypeId()); + } + + @Override + public String toString() { + return "SPAWN EGG{" + getSpawnedType() + "}"; + } + + @Override + public SpawnEgg clone() { + return (SpawnEgg) super.clone(); + } +} diff --git a/src/main/java/org/bukkit/material/TrapDoor.java b/src/main/java/org/bukkit/material/TrapDoor.java index f709fcf9..c280c78f 100644 --- a/src/main/java/org/bukkit/material/TrapDoor.java +++ b/src/main/java/org/bukkit/material/TrapDoor.java @@ -6,7 +6,7 @@ import org.bukkit.block.BlockFace; /** * Represents a trap door */ -public class TrapDoor extends SimpleAttachableMaterialData { +public class TrapDoor extends SimpleAttachableMaterialData implements Openable { public TrapDoor() { super(Material.TRAP_DOOR); } @@ -27,30 +27,37 @@ public class TrapDoor extends SimpleAttachableMaterialData { super(type, data); } - /** - * Check to see if the trap door is open. - * - * @return true if the trap door is open. - */ public boolean isOpen() { return ((getData() & 0x4) == 0x4); } + public void setOpen(boolean isOpen) { + byte data = getData(); + + if (isOpen) { + data |= 0x4; + } else { + data &= ~0x4; + } + + setData(data); + } + public BlockFace getAttachedFace() { byte data = (byte) (getData() & 0x3); switch (data) { - case 0x0: - return BlockFace.WEST; + case 0x0: + return BlockFace.WEST; - case 0x1: - return BlockFace.EAST; + case 0x1: + return BlockFace.EAST; - case 0x2: - return BlockFace.SOUTH; + case 0x2: + return BlockFace.SOUTH; - case 0x3: - return BlockFace.NORTH; + case 0x3: + return BlockFace.NORTH; } return null; @@ -61,15 +68,15 @@ public class TrapDoor extends SimpleAttachableMaterialData { byte data = (byte) (getData() & 0x4); switch (face) { - case WEST: - data |= 0x1; - break; - case NORTH: - data |= 0x2; - break; - case SOUTH: - data |= 0x3; - break; + case WEST: + data |= 0x1; + break; + case NORTH: + data |= 0x2; + break; + case SOUTH: + data |= 0x3; + break; } setData(data); diff --git a/src/main/java/org/bukkit/material/Vine.java b/src/main/java/org/bukkit/material/Vine.java new file mode 100644 index 00000000..beb92480 --- /dev/null +++ b/src/main/java/org/bukkit/material/Vine.java @@ -0,0 +1,185 @@ +package org.bukkit.material; + +import java.util.Arrays; +import java.util.EnumSet; + +import org.bukkit.Material; +import org.bukkit.block.BlockFace; + +/** + * Represents a vine + */ +public class Vine extends MaterialData { + private static final int VINE_NORTH = 0x4; + private static final int VINE_EAST = 0x8; + private static final int VINE_WEST = 0x2; + private static final int VINE_SOUTH = 0x1; + EnumSet possibleFaces = EnumSet.of(BlockFace.NORTH, BlockFace.EAST, BlockFace.WEST, BlockFace.SOUTH); + + public Vine() { + super(Material.VINE); + } + + public Vine(int type, byte data){ + super(type, data); + } + + public Vine(byte data) { + super(Material.VINE, data); + } + + public Vine(BlockFace... faces) { + this(EnumSet.copyOf(Arrays.asList(faces))); + } + + public Vine(EnumSet faces) { + this((byte) 0); + faces.retainAll(possibleFaces); + + byte data = 0; + + if (faces.contains(BlockFace.NORTH)) { + data |= VINE_NORTH; + } + + if (faces.contains(BlockFace.EAST)) { + data |= VINE_EAST; + } + + if (faces.contains(BlockFace.WEST)) { + data |= VINE_WEST; + } + + if (faces.contains(BlockFace.SOUTH)) { + data |= VINE_SOUTH; + } + + setData(data); + } + + /** + * Check if the vine is attached to the specified face of an adjacent block. You can + * check two faces at once by passing eg {@link BlockFace#NORTH_EAST}. + * + * @param face The face to check. + * @return Whether it is attached to that face. + */ + public boolean isOnFace(BlockFace face) { + switch (face) { + case NORTH: + return (getData() & VINE_NORTH) > 0; + case EAST: + return (getData() & VINE_EAST) > 0; + case WEST: + return (getData() & VINE_WEST) > 0; + case SOUTH: + return (getData() & VINE_SOUTH) > 0; + case NORTH_EAST: + return isOnFace(BlockFace.NORTH) && isOnFace(BlockFace.EAST); + case NORTH_WEST: + return isOnFace(BlockFace.NORTH) && isOnFace(BlockFace.WEST); + case SOUTH_EAST: + return isOnFace(BlockFace.SOUTH) && isOnFace(BlockFace.EAST); + case SOUTH_WEST: + return isOnFace(BlockFace.SOUTH) && isOnFace(BlockFace.WEST); + case UP: // It's impossible to be accurate with this since it's contextual + return true; + default: + return false; + } + } + + /** + * Attach the vine to the specified face of an adjacent block. + * + * @param face The face to attach. + */ + public void putOnFace(BlockFace face) { + switch(face) { + case NORTH: + setData((byte) (getData() | VINE_NORTH)); + break; + case EAST: + setData((byte) (getData() | VINE_EAST)); + break; + case WEST: + setData((byte) (getData() | VINE_WEST)); + break; + case SOUTH: + setData((byte) (getData() | VINE_SOUTH)); + break; + case NORTH_EAST: + putOnFace(BlockFace.NORTH); + putOnFace(BlockFace.EAST); + break; + case NORTH_WEST: + putOnFace(BlockFace.NORTH); + putOnFace(BlockFace.WEST); + break; + case SOUTH_EAST: + putOnFace(BlockFace.SOUTH); + putOnFace(BlockFace.EAST); + break; + case SOUTH_WEST: + putOnFace(BlockFace.SOUTH); + putOnFace(BlockFace.WEST); + break; + case UP: + break; + default: + throw new IllegalArgumentException("Vines can't go on face " + face.toString()); + } + } + + /** + * Detach the vine from the specified face of an adjacent block. + * + * @param face The face to detach. + */ + public void removeFromFace(BlockFace face) { + switch(face) { + case NORTH: + setData((byte) (getData() &~ VINE_NORTH)); + break; + case EAST: + setData((byte) (getData() &~ VINE_EAST)); + break; + case WEST: + setData((byte) (getData() &~ VINE_WEST)); + break; + case SOUTH: + setData((byte) (getData() &~ VINE_SOUTH)); + break; + case NORTH_EAST: + removeFromFace(BlockFace.NORTH); + removeFromFace(BlockFace.EAST); + break; + case NORTH_WEST: + removeFromFace(BlockFace.NORTH); + removeFromFace(BlockFace.WEST); + break; + case SOUTH_EAST: + removeFromFace(BlockFace.SOUTH); + removeFromFace(BlockFace.EAST); + break; + case SOUTH_WEST: + removeFromFace(BlockFace.SOUTH); + removeFromFace(BlockFace.WEST); + break; + case UP: + break; + default: + throw new IllegalArgumentException("Vines can't go on face " + face.toString()); + } + } + + @Override + public String toString() { + return "VINE"; + } + + @Override + public Vine clone() { + return (Vine) super.clone(); + } +} -- cgit v1.2.3