From 996146280e6e9fb4cc6f43235f22f4e568431597 Mon Sep 17 00:00:00 2001 From: ryanbennitt Date: Sat, 26 Mar 2016 09:26:20 +1100 Subject: SPIGOT-1682: Fixed block data for Beetroot --- src/main/java/org/bukkit/Material.java | 4 +- src/main/java/org/bukkit/material/Crops.java | 84 ++++++++++++++++++++-- .../org/bukkit/materials/MaterialDataTest.java | 62 ++++++++++++++++ 3 files changed, 142 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java index 295ffa85..6de16317 100644 --- a/src/main/java/org/bukkit/Material.java +++ b/src/main/java/org/bukkit/Material.java @@ -208,8 +208,8 @@ public enum Material { BEACON(138), COBBLE_WALL(139), FLOWER_POT(140, FlowerPot.class), - CARROT(141), - POTATO(142), + CARROT(141, Crops.class), + POTATO(142, Crops.class), WOOD_BUTTON(143, Button.class), SKULL(144, Skull.class), ANVIL(145), diff --git a/src/main/java/org/bukkit/material/Crops.java b/src/main/java/org/bukkit/material/Crops.java index 0a4f8f17..f48637d0 100644 --- a/src/main/java/org/bukkit/material/Crops.java +++ b/src/main/java/org/bukkit/material/Crops.java @@ -4,15 +4,43 @@ import org.bukkit.CropState; import org.bukkit.Material; /** - * Represents the different types of crops. + * Represents the different types of crops in different states of growth. + * + * @see Material#CROPS + * @see Material#CARROT + * @see Material#POTATO + * @see Material#BEETROOT_BLOCK + * @see Material#NETHER_WARTS */ public class Crops extends MaterialData { + protected static final Material DEFAULT_TYPE = Material.CROPS; + protected static final CropState DEFAULT_STATE = CropState.SEEDED; + + /** + * Constructs a wheat crop block in the seeded state. + */ public Crops() { - super(Material.CROPS); + this(DEFAULT_TYPE, DEFAULT_STATE); } + /** + * Constructs a wheat crop block in the given growth state + * + * @param state The growth state of the crops + */ public Crops(CropState state) { - this(); + this(DEFAULT_TYPE, state); + setState(state); + } + + /** + * Constructs a crop block of the given type and in the given growth state + * + * @param type The type of crops + * @param state The growth state of the crops + */ + public Crops(final Material type, final CropState state) { + super(type); setState(state); } @@ -25,8 +53,13 @@ public class Crops extends MaterialData { super(type); } + /** + * Constructs a crop block of the given type and in the seeded state + * + * @param type The type of crops + */ public Crops(final Material type) { - super(type); + this(type, DEFAULT_STATE); } /** @@ -52,19 +85,58 @@ public class Crops extends MaterialData { /** * Gets the current growth state of this crop * + * For crops with only four growth states such as beetroot, only the values SEEDED, SMALL, TALL and RIPE will be + * returned. + * * @return CropState of this crop */ public CropState getState() { - return CropState.getByData(getData()); + switch (getItemType()) { + case CROPS: + case CARROT: + case POTATO: + // Mask the data just in case top bit set + return CropState.getByData((byte)(getData() & 0x7)); + case BEETROOT_BLOCK: + case NETHER_WARTS: + // Mask the data just in case top bits are set + // Will return SEEDED, SMALL, TALL, RIPE for the three growth data values + return CropState.getByData((byte)(((getData() & 0x3)*7+2)/3)) ; + default: + throw new IllegalArgumentException("Block type is not a crop"); + } } /** * Sets the growth state of this crop * + * For crops with only four growth states such as beetroot, the 8 CropStates are mapped into four states: + * + * SEEDED, SMALL, TALL and RIPE + * + * GERMINATED will change to SEEDED + * VERY_SMALL will change to SMALL + * MEDIUM will change to TALL + * VERY_TALL will change to RIPE + * * @param state New growth state of this crop */ public void setState(CropState state) { - setData(state.getData()); + switch (getItemType()) { + case CROPS: + case CARROT: + case POTATO: + // Preserve the top bit in case it is set + setData((byte)((getData() & 0x8)|state.getData())); + break; + case NETHER_WARTS: + case BEETROOT_BLOCK: + // Preserve the top bits in case they are set + setData((byte)((getData() & 0xC)|(state.getData() >> 1))); + break; + default: + throw new IllegalArgumentException("Block type is not a crop"); + } } @Override diff --git a/src/test/java/org/bukkit/materials/MaterialDataTest.java b/src/test/java/org/bukkit/materials/MaterialDataTest.java index 3eaede3c..2be3ddc9 100644 --- a/src/test/java/org/bukkit/materials/MaterialDataTest.java +++ b/src/test/java/org/bukkit/materials/MaterialDataTest.java @@ -3,12 +3,16 @@ package org.bukkit.materials; import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; +import org.bukkit.CropState; import org.bukkit.Material; +import org.bukkit.NetherWartsState; import org.bukkit.TreeSpecies; import org.bukkit.block.BlockFace; +import org.bukkit.material.Crops; import org.bukkit.material.Door; import org.bukkit.material.Leaves; import org.bukkit.material.Mushroom; +import org.bukkit.material.NetherWarts; import org.bukkit.material.Sapling; import org.bukkit.material.Tree; import org.bukkit.material.Wood; @@ -259,4 +263,62 @@ public class MaterialDataTest { } } } + + @Test + public void testCrops() { + Crops crops = new Crops(); + assertThat("Constructed with default crops type", crops.getItemType(), equalTo(Material.CROPS)); + assertThat("Constructed with default crop state", crops.getState(), equalTo(CropState.SEEDED)); + + CropState[] allStates = CropState.values(); + for (CropState state : allStates) { + crops = new Crops(state); + assertThat("Constructed with default crops type", crops.getItemType(), equalTo(Material.CROPS)); + assertThat("Constructed with correct crop state", crops.getState(), equalTo(state)); + } + + // The crops which fully implement all crop states + Material[] allCrops = new Material[] {Material.CROPS, Material.CARROT, Material.POTATO}; + for (Material crop : allCrops) { + crops = new Crops(crop); + assertThat("Constructed with correct crops type", crops.getItemType(), equalTo(crop)); + assertThat("Constructed with default crop state", crops.getState(), equalTo(CropState.SEEDED)); + + for (CropState state : allStates) { + crops = new Crops(crop, state); + assertThat("Constructed with correct crops type", crops.getItemType(), equalTo(crop)); + assertThat("Constructed with correct crop state", crops.getState(), equalTo(state)); + } + } + + // Beetroot are crops too, but they only have four states + // Setting different crop states for beetroot will return the following when retrieved back + CropState[] beetrootStates = new CropState[] {CropState.SEEDED, CropState.SEEDED, CropState.SMALL, CropState.SMALL, CropState.TALL, CropState.TALL, CropState.RIPE, CropState.RIPE}; + assertThat("Beetroot state translations match size", beetrootStates.length, equalTo(allStates.length)); + crops = new Crops(Material.BEETROOT_BLOCK); + assertThat("Constructed with correct crops type", crops.getItemType(), equalTo(Material.BEETROOT_BLOCK)); + assertThat("Constructed with default crop state", crops.getState(), equalTo(CropState.SEEDED)); + for (int s = 0; s < beetrootStates.length; s++) { + crops = new Crops(Material.BEETROOT_BLOCK, allStates[s]); + assertThat("Constructed with correct crops type", crops.getItemType(), equalTo(Material.BEETROOT_BLOCK)); + assertThat("Constructed with correct crop state", crops.getState(), equalTo(beetrootStates[s])); + } + + // In case you want to treat NetherWarts as Crops, although they really aren't + crops = new Crops(Material.NETHER_WARTS); + NetherWarts warts = new NetherWarts(); + assertThat("Constructed with correct crops type", crops.getItemType(), equalTo(warts.getItemType())); + assertThat("Constructed with default crop state", crops.getState(), equalTo(CropState.SEEDED)); + assertThat("Constructed with default wart state", warts.getState(), equalTo(NetherWartsState.SEEDED)); + allStates = new CropState[] {CropState.SEEDED, CropState.SMALL, CropState.TALL, CropState.RIPE}; + NetherWartsState[] allWartStates = NetherWartsState.values(); + assertThat("Nether Warts state translations match size", allWartStates.length, equalTo(allStates.length)); + for (int s = 0; s < allStates.length; s++) { + crops = new Crops(Material.NETHER_WARTS, allStates[s]); + warts = new NetherWarts(allWartStates[s]); + assertThat("Constructed with correct crops type", crops.getItemType(), equalTo(warts.getItemType())); + assertThat("Constructed with correct crop state", crops.getState(), equalTo(allStates[s])); + assertThat("Constructed with correct wart state", warts.getState(), equalTo(allWartStates[s])); + } + } } -- cgit v1.2.3