1127 lines
40 KiB
Java
1127 lines
40 KiB
Java
package com.songoda.core.utils;
|
|
|
|
import com.songoda.core.compatibility.ClassMapping;
|
|
import com.songoda.core.compatibility.CompatibleMaterial;
|
|
import com.songoda.core.compatibility.MethodMapping;
|
|
import com.songoda.core.compatibility.ServerVersion;
|
|
import org.bukkit.Effect;
|
|
import org.bukkit.Location;
|
|
import org.bukkit.Material;
|
|
import org.bukkit.World;
|
|
import org.bukkit.block.Block;
|
|
import org.bukkit.block.BlockFace;
|
|
|
|
import java.lang.reflect.Constructor;
|
|
import java.lang.reflect.InvocationTargetException;
|
|
import java.lang.reflect.Method;
|
|
import java.util.EnumSet;
|
|
import java.util.Set;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
|
|
/**
|
|
* @deprecated This class will be removed in the future and replaced with a more maintainable system.
|
|
*/
|
|
@Deprecated
|
|
public class BlockUtils {
|
|
protected static final Set<Material> DOORS;
|
|
protected static final Set<Material> PRESSURE_PLATES;
|
|
protected static final Set<Material> FENCE_GATES;
|
|
protected static final Set<Material> TRAP_DOORS;
|
|
protected static final boolean useLegacy = Material.getMaterial("OAK_LOG") == null;
|
|
protected static Method legacySetBlockData = null;
|
|
protected static Method legacyUpdateBlockData = null;
|
|
|
|
static {
|
|
DOORS = EnumSet.noneOf(Material.class);
|
|
PRESSURE_PLATES = EnumSet.noneOf(Material.class);
|
|
FENCE_GATES = EnumSet.noneOf(Material.class);
|
|
TRAP_DOORS = EnumSet.noneOf(Material.class);
|
|
|
|
for (Material material : Material.values()) {
|
|
String name = material.name();
|
|
if (name.contains("DOOR") && !name.contains("ITEM")) {
|
|
if (name.contains("TRAP")) {
|
|
TRAP_DOORS.add(material);
|
|
} else {
|
|
DOORS.add(material);
|
|
}
|
|
} else if (name.contains("GATE") && !name.contains("END")) {
|
|
FENCE_GATES.add(material);
|
|
} else if (name.contains("_PLATE")) {
|
|
PRESSURE_PLATES.add(material);
|
|
}
|
|
}
|
|
|
|
if (useLegacy) {
|
|
try {
|
|
//legacyUpdateBlockData = Block.class.getDeclaredMethod("update");
|
|
legacySetBlockData = Block.class.getDeclaredMethod("setData", byte.class);
|
|
} catch (NoSuchMethodException ignore) {
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Interact with this block to either update redstone or open doors
|
|
*
|
|
* @param b block to update
|
|
*
|
|
* @return if this block's state was updated
|
|
*/
|
|
public static boolean tryInteract(Block b) {
|
|
final Material bType = b.getType();
|
|
|
|
if (isOpenable(bType)) {
|
|
toggleDoorStates(true, b);
|
|
return true;
|
|
} else if (bType == Material.LEVER) {
|
|
toggleLever(b);
|
|
return true;
|
|
} else if (bType.name().endsWith("_BUTTON")) {
|
|
pressButton(b);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Change a pressure plate's redstone state
|
|
*
|
|
* @param plate plate to update
|
|
* @param power power to set to 0-15 (wood plates are active if greater than 0)
|
|
*/
|
|
public static void updatePressurePlate(Block plate, int power) {
|
|
if (useLegacy && legacySetBlockData != null) {
|
|
_updatePressurePlateLegacy(plate, power);
|
|
} else {
|
|
BlockUtilsModern._updatePressurePlateModern(plate, power);
|
|
}
|
|
}
|
|
|
|
private static void _updatePressurePlateLegacy(Block plate, int power) {
|
|
final Material m = plate.getType();
|
|
|
|
try {
|
|
if (m.name().equals("GOLD_PLATE") || m.name().equals("IRON_PLATE")) {
|
|
legacySetBlockData.invoke(plate, (byte) (power & 0x15));
|
|
} else if (m.name().endsWith("_PLATE")) {
|
|
legacySetBlockData.invoke(plate, (byte) (power == 0 ? 0 : 1));
|
|
}
|
|
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
|
|
Logger.getLogger(BlockUtils.class.getName()).log(Level.SEVERE, "Unexpected method error", ex);
|
|
}
|
|
}
|
|
|
|
public static void pressButton(Block button) {
|
|
if (useLegacy && legacySetBlockData != null) {
|
|
_pressButtonLegacy(button);
|
|
} else {
|
|
BlockUtilsModern._pressButtonModern(button);
|
|
}
|
|
}
|
|
|
|
public static void releaseButton(Block button) {
|
|
if (useLegacy && legacySetBlockData != null) {
|
|
_releaseButtonLegacy(button);
|
|
} else {
|
|
BlockUtilsModern._releaseButtonModern(button);
|
|
}
|
|
}
|
|
|
|
private static void _pressButtonLegacy(Block button) {
|
|
final Material m = button.getType();
|
|
|
|
if (!m.name().endsWith("_BUTTON")) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
legacySetBlockData.invoke(button, (byte) (button.getData() | (31 & 0x8)));
|
|
button.getState().update();
|
|
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
|
|
Logger.getLogger(BlockUtils.class.getName()).log(Level.SEVERE, "Unexpected method error", ex);
|
|
}
|
|
}
|
|
|
|
private static void _releaseButtonLegacy(Block button) {
|
|
final Material m = button.getType();
|
|
|
|
if (!m.name().endsWith("_BUTTON")) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
legacySetBlockData.invoke(button, (byte) (button.getData() & ~0x8));
|
|
button.getState().update();
|
|
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
|
|
Logger.getLogger(BlockUtils.class.getName()).log(Level.SEVERE, "Unexpected method error", ex);
|
|
}
|
|
}
|
|
|
|
public static void toggleLever(Block lever) {
|
|
if (useLegacy && legacySetBlockData != null) {
|
|
_toggleLeverLegacy(lever);
|
|
} else {
|
|
BlockUtilsModern._toggleLeverModern(lever);
|
|
}
|
|
}
|
|
|
|
private static void _toggleLeverLegacy(Block lever) {
|
|
final Material m = lever.getType();
|
|
|
|
if (m != Material.LEVER) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
legacySetBlockData.invoke(lever, (byte) (lever.getData() ^ 0x8));
|
|
lever.getState().update();
|
|
//lever.getWorld().playEffect(lever.getLocation(), Effect.CLICK1, 0);
|
|
// now we need to update the redstone around it...
|
|
// int data = lever.getData() & ~0x8;
|
|
// Block attached;
|
|
// switch(data) {
|
|
// case 0:
|
|
// attached = lever.getRelative(BlockFace.UP);
|
|
// break;
|
|
// case 1:
|
|
// attached = lever.getRelative(BlockFace.WEST);
|
|
// break;
|
|
// case 2:
|
|
// attached = lever.getRelative(BlockFace.EAST);
|
|
// break;
|
|
// case 3:
|
|
// attached = lever.getRelative(BlockFace.NORTH);
|
|
// break;
|
|
// case 4:
|
|
// attached = lever.getRelative(BlockFace.SOUTH);
|
|
// break;
|
|
// case 5:
|
|
// attached = lever.getRelative(BlockFace.DOWN);
|
|
// break;
|
|
// default:
|
|
// return;
|
|
// }
|
|
//
|
|
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
|
|
Logger.getLogger(BlockUtils.class.getName()).log(Level.SEVERE, "Unexpected method error", ex);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Change all of the given door states to be inverse; that is, if a door is
|
|
* open, it will be closed afterwards. If the door is closed, it will become
|
|
* open.
|
|
* <p/>
|
|
* Note that the blocks given must be the bottom block of the door.
|
|
*
|
|
* @param allowDoorToOpen If FALSE, and the door is currently CLOSED, it
|
|
* will NOT be opened!
|
|
* @param doors Blocks given must be the bottom block of the door
|
|
*/
|
|
public static void toggleDoorStates(boolean allowDoorToOpen, Block... doors) {
|
|
if (useLegacy && legacySetBlockData != null) {
|
|
_toggleDoorStatesLegacy(allowDoorToOpen, doors);
|
|
} else {
|
|
BlockUtilsModern._toggleDoorStatesModern(allowDoorToOpen, doors);
|
|
}
|
|
}
|
|
|
|
private static void _toggleDoorStatesLegacy(boolean allowDoorToOpen, Block... doors) {
|
|
try {
|
|
for (Block door : doors) {
|
|
if (door == null) {
|
|
continue;
|
|
}
|
|
|
|
boolean isTop = (door.getData() & 0x8) != 0;
|
|
if (isTop) {
|
|
// The lower half of the door contains the direction & open/close state
|
|
door = door.getRelative(BlockFace.DOWN);
|
|
}
|
|
|
|
// If we aren't allowing the door to open, check if it's already closed
|
|
if (!allowDoorToOpen && (door.getData() & 0x4) == 0) {
|
|
// The door is already closed and we don't want to open it
|
|
// the bit 0x4 is set when the door is open
|
|
continue;
|
|
}
|
|
|
|
// Now xor both data values with 0x4, the flag that states if the door is open
|
|
legacySetBlockData.invoke(door, (byte) (door.getData() ^ 0x4));
|
|
|
|
// Play the door open/close sound
|
|
door.getWorld().playEffect(door.getLocation(), Effect.DOOR_TOGGLE, 0);
|
|
}
|
|
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
|
|
Logger.getLogger(BlockUtils.class.getName()).log(Level.SEVERE, "Unexpected method error", ex);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the double door for the given block
|
|
*/
|
|
public static Block getDoubleDoor(Block block) {
|
|
// TODO? if legacy, just search N/S/E/W to see if there's another door nearby
|
|
if (!isOpenable(block.getType())) {
|
|
return null;
|
|
}
|
|
|
|
return BlockUtilsModern._getDoubleDoorModern(block);
|
|
}
|
|
|
|
public static boolean isOpenable(Material m) {
|
|
return DOORS.contains(m) ||
|
|
FENCE_GATES.contains(m) ||
|
|
TRAP_DOORS.contains(m);
|
|
}
|
|
|
|
public static BlockFace getDoorClosedDirection(Block door) {
|
|
return useLegacy ? _getDoorClosedDirectionLegacy(door) : BlockUtilsModern._getDoorClosedDirectionModern(door);
|
|
}
|
|
|
|
private static BlockFace _getDoorClosedDirectionLegacy(Block door) {
|
|
final Material type = door.getType();
|
|
|
|
if (DOORS.contains(type)) {
|
|
boolean isTop = (door.getData() & 0x8) != 0;
|
|
|
|
if (isTop) {
|
|
// The lower half of the door contains the direction & open/close state
|
|
door = door.getRelative(BlockFace.DOWN);
|
|
if (door.getType() != type) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
boolean isOpen = (door.getData() & 0x4) != 0;
|
|
|
|
//int facing = (door.getData() & 0x3);
|
|
// [east, south, west, north]
|
|
boolean facingNS = (door.getData() & 0x1) != 0;
|
|
if (facingNS) {
|
|
return isOpen ? BlockFace.EAST : BlockFace.SOUTH;
|
|
} else {
|
|
return isOpen ? BlockFace.SOUTH : BlockFace.EAST;
|
|
}
|
|
} else if (FENCE_GATES.contains(door.getType())) {
|
|
boolean isOpen = (door.getData() & 0x4) != 0;
|
|
|
|
//int facing = (door.getData() & 0x3);
|
|
// so fence gate orientations are [south, west, north, east]
|
|
boolean facingNS = (door.getData() & 0x1) == 0;
|
|
if (facingNS) {
|
|
return isOpen ? BlockFace.EAST : BlockFace.SOUTH;
|
|
} else {
|
|
return isOpen ? BlockFace.SOUTH : BlockFace.EAST;
|
|
}
|
|
} else if (TRAP_DOORS.contains(door.getType())) {
|
|
boolean isOpen = (door.getData() & 0x4) != 0;
|
|
|
|
// [south, north, east, west]
|
|
boolean facingNS = (door.getData() & 0x3) <= 1;
|
|
if (facingNS) {
|
|
return isOpen ? BlockFace.EAST : BlockFace.SOUTH;
|
|
} else {
|
|
return isOpen ? BlockFace.SOUTH : BlockFace.EAST;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/* Only to be used by #updateAdjacentComparators */
|
|
private static Method chunkToNmsChunk, nmsChunkGetWorld, craftBlockGetPosition, craftBlockBlockDataGetter, blockDataGetBlock, craftMagicNumbersGetBlockByMaterial, nmsWorldUpdateAdjacentComparators;
|
|
/* Only to be used by #updateAdjacentComparators */
|
|
private static Constructor<?> blockPositionConstructor;
|
|
|
|
/**
|
|
* Manually trigger the updateAdjacentComparators method for containers
|
|
*
|
|
* @param loc The Location of the container
|
|
*
|
|
* @deprecated Use {@link com.songoda.core.nms.world.WorldCore#updateAdjacentComparators(Block)}
|
|
* via {@link com.songoda.core.nms.Nms#getImplementations()} instead.
|
|
*/
|
|
@Deprecated
|
|
public static void updateAdjacentComparators(Location loc) {
|
|
if (loc == null || loc.getWorld() == null) {
|
|
return;
|
|
}
|
|
|
|
Block craftBlock = loc.getBlock();
|
|
|
|
try {
|
|
if (chunkToNmsChunk == null) {
|
|
chunkToNmsChunk = MethodMapping.CB_GENERIC__GET_HANDLE.getMethod(ClassMapping.CRAFT_CHUNK.getClazz());
|
|
nmsChunkGetWorld = MethodMapping.MC_CHUNK__GET_WORLD.getMethod(chunkToNmsChunk.getReturnType());
|
|
|
|
craftBlockGetPosition = MethodMapping.CB_BLOCK__GET_POSITION.getMethod(ClassMapping.CRAFT_BLOCK.getClazz());
|
|
if (craftBlockGetPosition == null) {
|
|
blockPositionConstructor = ClassMapping.BLOCK_POSITION.getClazz().getConstructor(double.class, double.class, double.class);
|
|
}
|
|
|
|
nmsWorldUpdateAdjacentComparators = MethodMapping.WORLD__UPDATE_ADJACENT_COMPARATORS.getMethod(ClassMapping.WORLD.getClazz());
|
|
|
|
craftBlockBlockDataGetter = MethodMapping.CB_BLOCK__GET_NMS.getMethod(ClassMapping.CRAFT_BLOCK.getClazz());
|
|
blockDataGetBlock = MethodMapping.I_BLOCK_DATA__GET_BLOCK.getMethod(ClassMapping.I_BLOCK_DATA.getClazz());
|
|
if (craftBlockBlockDataGetter == null || blockDataGetBlock == null) {
|
|
craftMagicNumbersGetBlockByMaterial = MethodMapping.CRAFT_MAGIC_NUMBERS__GET_BLOCK__MATERIAL.getMethod(ClassMapping.CRAFT_MAGIC_NUMBERS.getClazz());
|
|
}
|
|
}
|
|
|
|
Object nmsChunk = chunkToNmsChunk.invoke(loc.getChunk());
|
|
Object nmsWorld = nmsChunkGetWorld.invoke(nmsChunk);
|
|
|
|
Object blockPosition;
|
|
if (craftBlockGetPosition != null) {
|
|
blockPosition = craftBlockGetPosition.invoke(craftBlock);
|
|
} else {
|
|
blockPosition = blockPositionConstructor.newInstance(loc.getX(), loc.getY(), loc.getZ());
|
|
}
|
|
|
|
Object nmsBlock;
|
|
if (craftBlockBlockDataGetter != null) {
|
|
nmsBlock = blockDataGetBlock.invoke(craftBlockBlockDataGetter.invoke(craftBlock));
|
|
} else {
|
|
nmsBlock = craftMagicNumbersGetBlockByMaterial.invoke(null, craftBlock.getType());
|
|
}
|
|
|
|
nmsWorldUpdateAdjacentComparators.invoke(nmsWorld, blockPosition, nmsBlock);
|
|
} catch (NullPointerException | ReflectiveOperationException ex) {
|
|
ex.printStackTrace();
|
|
}
|
|
}
|
|
|
|
/* Only to be used by #setBlockFast */
|
|
private static Class<?> clazzIBlockData, clazzBlocks, clazzCraftWorld, clazzBlockPosition;
|
|
/* Only to be used by #setBlockFast */
|
|
private static Method getHandle, getByCombinedId, setType, getChunkAt, getBlockData;
|
|
|
|
/**
|
|
* Set a block to a certain type by updating the block directly in the
|
|
* NMS chunk.
|
|
* <p>
|
|
* The chunk must be loaded and players must relog if they have the
|
|
* chunk loaded in order to use this method.
|
|
*
|
|
* @deprecated Use {@link com.songoda.core.nms.world.SWorld#setBlockFast(int, int, int, Material)}
|
|
* via {@link com.songoda.core.nms.Nms#getImplementations()} instead.
|
|
*/
|
|
@Deprecated
|
|
public static void setBlockFast(World world, int x, int y, int z, Material material, byte data) {
|
|
try {
|
|
// Cache reflection
|
|
if (clazzIBlockData == null) {
|
|
clazzIBlockData = ClassMapping.I_BLOCK_DATA.getClazz();
|
|
clazzBlockPosition = ClassMapping.BLOCK_POSITION.getClazz();
|
|
clazzCraftWorld = ClassMapping.CRAFT_WORLD.getClazz();
|
|
clazzBlocks = ClassMapping.BLOCKS.getClazz();
|
|
Class<?> clazzBlock = ClassMapping.BLOCK.getClazz();
|
|
Class<?> clazzWorld = ClassMapping.WORLD.getClazz();
|
|
Class<?> clazzChunk = ClassMapping.CHUNK.getClazz();
|
|
|
|
getHandle = clazzCraftWorld.getMethod("getHandle");
|
|
getChunkAt = MethodMapping.WORLD__GET_CHUNK_AT.getMethod(clazzWorld);
|
|
|
|
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)) {
|
|
getBlockData = MethodMapping.BLOCK__GET_BLOCK_DATA.getMethod(ClassMapping.BLOCK.getClazz());
|
|
setType = MethodMapping.CHUNK__SET_BLOCK_STATE.getMethod(ClassMapping.CHUNK.getClazz());
|
|
} else {
|
|
getByCombinedId = clazzBlock.getMethod("getByCombinedId", int.class);
|
|
setType = clazzChunk.getMethod("a", clazzBlockPosition, clazzIBlockData);
|
|
}
|
|
}
|
|
|
|
// invoke and cast objects.
|
|
Object craftWorld = clazzCraftWorld.cast(world);
|
|
Object nmsWorld = getHandle.invoke(craftWorld);
|
|
Object chunk = getChunkAt.invoke(nmsWorld, x >> 4, z >> 4);
|
|
Object blockPosition = clazzBlockPosition.getConstructor(int.class, int.class, int.class).newInstance(x & 0xF, y, z & 0xF);
|
|
|
|
// Invoke final method.
|
|
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)) {
|
|
Object block = clazzBlocks.getField(material.name()).get(null);
|
|
Object IBlockData = getBlockData.invoke(block);
|
|
setType.invoke(chunk, blockPosition, IBlockData, true);
|
|
} else {
|
|
Object IBlockData = getByCombinedId.invoke(null, material.getId() + (data << 12));
|
|
setType.invoke(chunk, blockPosition, IBlockData);
|
|
}
|
|
} catch (Exception ex) {
|
|
ex.printStackTrace();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @deprecated Use {@link com.songoda.core.nms.world.SWorld#setBlockFast(int, int, int, Material)}
|
|
* via {@link com.songoda.core.nms.Nms#getImplementations()} instead.
|
|
*/
|
|
@Deprecated
|
|
public static void setBlockFast(World world, int x, int y, int z, CompatibleMaterial material, byte data) {
|
|
setBlockFast(world, x, y, z, material.getBlockMaterial(), data);
|
|
}
|
|
|
|
/**
|
|
* Checks if a crop is at its max growth stage
|
|
*
|
|
* @param block The crop block to check
|
|
*
|
|
* @return true if the block is a crop and at its max growth stage
|
|
*/
|
|
public static boolean isCropFullyGrown(Block block) {
|
|
if (block == null) {
|
|
return false;
|
|
}
|
|
|
|
if (!useLegacy) {
|
|
return BlockUtilsModern._isCropFullyGrown(block);
|
|
}
|
|
|
|
CompatibleMaterial mat = CompatibleMaterial.getBlockMaterial(block.getType());
|
|
if (mat == null || !mat.isCrop()) {
|
|
return false;
|
|
}
|
|
|
|
return block.getData() >= (mat == CompatibleMaterial.BEETROOTS || mat == CompatibleMaterial.NETHER_WART ? 3 : 7);
|
|
}
|
|
|
|
/**
|
|
* Gets the max growth stage for the given block
|
|
*
|
|
* @param block The crop block to check
|
|
*
|
|
* @return The max growth stage of the given crop type, or -1 if not a crop
|
|
*/
|
|
public static int getMaxGrowthStage(Block block) {
|
|
if (block == null) {
|
|
return -1;
|
|
}
|
|
|
|
if (!useLegacy) {
|
|
return BlockUtilsModern._getMaxGrowthStage(block);
|
|
}
|
|
|
|
CompatibleMaterial mat = CompatibleMaterial.getBlockMaterial(block.getType());
|
|
if (mat == null || !mat.isCrop()) {
|
|
return -1;
|
|
}
|
|
|
|
return (mat == CompatibleMaterial.BEETROOTS
|
|
|| mat == CompatibleMaterial.NETHER_WART ? 3 : 7);
|
|
}
|
|
|
|
/**
|
|
* Gets the max growth stage for the given material
|
|
*
|
|
* @param material The material of the crop
|
|
*
|
|
* @return The max growth stage of the given crop type
|
|
*/
|
|
public static int getMaxGrowthStage(Material material) {
|
|
if (material == null) {
|
|
return -1;
|
|
}
|
|
|
|
if (!useLegacy) {
|
|
return BlockUtilsModern._getMaxGrowthStage(material);
|
|
}
|
|
|
|
CompatibleMaterial mat = CompatibleMaterial.getBlockMaterial(material);
|
|
if (mat == null || !mat.isCrop()) {
|
|
return -1;
|
|
}
|
|
|
|
return (mat == CompatibleMaterial.BEETROOTS || mat == CompatibleMaterial.NETHER_WART ? 3 : 7);
|
|
}
|
|
|
|
/**
|
|
* Sets the max growth stage for the given block
|
|
*
|
|
* @param block The crop block to change
|
|
* @param stage new growth stage to use
|
|
*/
|
|
public static void setGrowthStage(Block block, int stage) {
|
|
if (block == null) {
|
|
} else if (!useLegacy) {
|
|
BlockUtilsModern._setGrowthStage(block, stage);
|
|
} else {
|
|
CompatibleMaterial mat = CompatibleMaterial.getBlockMaterial(block.getType());
|
|
if (mat != null && mat.isCrop()) {
|
|
try {
|
|
legacySetBlockData.invoke(block, (byte) Math.max(0, Math.min(stage, (mat == CompatibleMaterial.BEETROOTS
|
|
|| mat == CompatibleMaterial.NETHER_WART ? 3 : 7))));
|
|
} catch (Exception ex) {
|
|
Logger.getLogger(BlockUtils.class.getName()).log(Level.SEVERE, "Unexpected method error", ex);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Increments the growth stage for the given block
|
|
*
|
|
* @param block The crop block to grow
|
|
*/
|
|
public static void incrementGrowthStage(Block block) {
|
|
if (block == null) {
|
|
} else if (!useLegacy) {
|
|
BlockUtilsModern._incrementGrowthStage(block);
|
|
} else {
|
|
CompatibleMaterial mat = CompatibleMaterial.getBlockMaterial(block.getType());
|
|
|
|
if (mat != null && mat.isCrop() &&
|
|
block.getData() < (mat == CompatibleMaterial.BEETROOTS || mat == CompatibleMaterial.NETHER_WART ? 3 : 7)) {
|
|
try {
|
|
legacySetBlockData.invoke(block, (byte) (block.getData() + 1));
|
|
} catch (Exception ex) {
|
|
Logger.getLogger(BlockUtils.class.getName()).log(Level.SEVERE, "Unexpected method error", ex);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets a crop's growth back to stage 0
|
|
*
|
|
* @param block The crop block to set
|
|
*/
|
|
public static void resetGrowthStage(Block block) {
|
|
if (block == null) {
|
|
} else if (!useLegacy) {
|
|
BlockUtilsModern._resetGrowthStage(block);
|
|
} else {
|
|
CompatibleMaterial mat = CompatibleMaterial.getBlockMaterial(block.getType());
|
|
|
|
if (mat != null && mat.isCrop()) {
|
|
try {
|
|
legacySetBlockData.invoke(block, (byte) 0);
|
|
} catch (Exception ex) {
|
|
Logger.getLogger(BlockUtils.class.getName()).log(Level.SEVERE, "Unexpected method error", ex);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check to see if this material does not impede player/mob movement at all.
|
|
*
|
|
* @param m material to check
|
|
*
|
|
* @return true if this material doesn't have a solid hitbox
|
|
*/
|
|
public static boolean canPassThrough(Material m) {
|
|
switch (m.name()) {
|
|
case "ACACIA_BUTTON":
|
|
case "ACACIA_PRESSURE_PLATE":
|
|
case "ACACIA_SAPLING":
|
|
case "ACACIA_SIGN":
|
|
case "ACACIA_WALL_SIGN":
|
|
case "ACTIVATOR_RAIL":
|
|
case "AIR":
|
|
case "ATTACHED_MELON_STEM":
|
|
case "ATTACHED_PUMPKIN_STEM":
|
|
case "AZURE_BLUET":
|
|
case "BEETROOTS":
|
|
case "BIRCH_BUTTON":
|
|
case "BIRCH_PRESSURE_PLATE":
|
|
case "BIRCH_SAPLING":
|
|
case "BIRCH_SIGN":
|
|
case "BIRCH_WALL_SIGN":
|
|
case "BLACK_WALL_BANNER":
|
|
case "BLUE_BANNER":
|
|
case "BLUE_ORCHID":
|
|
case "BLUE_WALL_BANNER":
|
|
case "BRAIN_CORAL_FAN":
|
|
case "BRAIN_CORAL_WALL_FAN":
|
|
case "BROWN_BANNER":
|
|
case "BROWN_MUSHROOM":
|
|
case "BROWN_WALL_BANNER":
|
|
case "BUBBLE_CORAL_FAN":
|
|
case "BUBBLE_CORAL_WALL_FAN":
|
|
case "CARROTS":
|
|
case "CAVE_AIR":
|
|
case "COBWEB":
|
|
case "CORNFLOWER":
|
|
case "CYAN_BANNER":
|
|
case "CYAN_WALL_BANNER":
|
|
case "DANDELION":
|
|
case "DARK_OAK_BUTTON":
|
|
case "DARK_OAK_PRESSURE_PLATE":
|
|
case "DARK_OAK_SAPLING":
|
|
case "DARK_OAK_SIGN":
|
|
case "DARK_OAK_WALL_SIGN":
|
|
case "DEAD_BRAIN_CORAL_FAN":
|
|
case "DEAD_BRAIN_CORAL_WALL_FAN":
|
|
case "DEAD_BUBBLE_CORAL_FAN":
|
|
case "DEAD_BUBBLE_CORAL_WALL_FAN":
|
|
case "DEAD_BUSH":
|
|
case "DEAD_FIRE_CORAL_FAN":
|
|
case "DEAD_FIRE_CORAL_WALL_FAN":
|
|
case "DEAD_HORN_CORAL_FAN":
|
|
case "DEAD_HORN_CORAL_WALL_FAN":
|
|
case "DEAD_TUBE_CORAL_FAN":
|
|
case "DEAD_TUBE_CORAL_WALL_FAN":
|
|
case "DETECTOR_RAIL":
|
|
case "END_PORTAL":
|
|
case "FERN":
|
|
case "FIRE":
|
|
case "FIRE_CORAL_FAN":
|
|
case "FIRE_CORAL_WALL_FAN":
|
|
case "GRASS":
|
|
case "GRAY_BANNER":
|
|
case "GRAY_WALL_BANNER":
|
|
case "GREEN_BANNER":
|
|
case "GREEN_WALL_BANNER":
|
|
case "HEAVY_WEIGHTED_PRESSURE_PLATE":
|
|
case "HORN_CORAL_FAN":
|
|
case "HORN_CORAL_WALL_FAN":
|
|
case "JUNGLE_BUTTON":
|
|
case "JUNGLE_PRESSURE_PLATE":
|
|
case "JUNGLE_SAPLING":
|
|
case "JUNGLE_SIGN":
|
|
case "JUNGLE_WALL_SIGN":
|
|
case "KELP":
|
|
case "LADDER":
|
|
case "LARGE_FERN":
|
|
case "LAVA":
|
|
case "LEVER":
|
|
case "LIGHT_BLUE_BANNER":
|
|
case "LIGHT_BLUE_WALL_BANNER":
|
|
case "LIGHT_GRAY_BANNER":
|
|
case "LIGHT_GRAY_WALL_BANNER":
|
|
case "LIGHT_WEIGHTED_PRESSURE_PLATE":
|
|
case "LILAC":
|
|
case "LILY_OF_THE_VALLEY":
|
|
case "LIME_BANNER":
|
|
case "MAGENTA_BANNER":
|
|
case "MAGENTA_WALL_BANNER":
|
|
case "MELON_STEM":
|
|
case "NETHER_PORTAL":
|
|
case "NETHER_WART":
|
|
case "OAK_BUTTON":
|
|
case "OAK_PRESSURE_PLATE":
|
|
case "OAK_SAPLING":
|
|
case "OAK_SIGN":
|
|
case "OAK_WALL_SIGN":
|
|
case "ORANGE_BANNER":
|
|
case "ORANGE_TULIP":
|
|
case "ORANGE_WALL_BANNER":
|
|
case "OXEYE_DAISY":
|
|
case "PEONY":
|
|
case "PINK_BANNER":
|
|
case "PINK_TULIP":
|
|
case "PINK_WALL_BANNER":
|
|
case "POTATOES":
|
|
case "POWERED_RAIL":
|
|
case "PUMPKIN_STEM":
|
|
case "PURPLE_BANNER":
|
|
case "PURPLE_WALL_BANNER":
|
|
case "RAIL":
|
|
case "REDSTONE_TORCH":
|
|
case "REDSTONE_WALL_TORCH":
|
|
case "REDSTONE_WIRE":
|
|
case "RED_BANNER":
|
|
case "RED_MUSHROOM":
|
|
case "RED_TULIP":
|
|
case "RED_WALL_BANNER":
|
|
case "ROSE_BUSH":
|
|
case "SCAFFOLDING":
|
|
case "SEAGRASS":
|
|
case "SPRUCE_BUTTON":
|
|
case "SPRUCE_PRESSURE_PLATE":
|
|
case "SPRUCE_SAPLING":
|
|
case "SPRUCE_SIGN":
|
|
case "SPRUCE_WALL_SIGN":
|
|
case "STONE_BUTTON":
|
|
case "STONE_PRESSURE_PLATE":
|
|
case "STRUCTURE_VOID":
|
|
case "SUGAR_CANE":
|
|
case "SUNFLOWER":
|
|
case "SWEET_BERRY_BUSH":
|
|
case "TALL_GRASS":
|
|
case "TALL_SEAGRASS":
|
|
case "TORCH":
|
|
case "TRIPWIRE":
|
|
case "TRIPWIRE_HOOK":
|
|
case "TUBE_CORAL_FAN":
|
|
case "TUBE_CORAL_WALL_FAN":
|
|
case "VINE":
|
|
case "VOID_AIR":
|
|
case "WALL_TORCH":
|
|
case "WATER":
|
|
case "WHEAT":
|
|
case "WHITE_BANNER":
|
|
case "WHITE_TULIP":
|
|
case "WHITE_WALL_BANNER":
|
|
case "WITHER_ROSE":
|
|
case "YELLOW_BANNER":
|
|
case "YELLOW_WALL_BANNER":
|
|
// Legacy values:
|
|
case "WEB":
|
|
case "LONG_GRASS":
|
|
case "YELLOW_FLOWER":
|
|
case "RED_ROSE":
|
|
case "CROPS":
|
|
case "SIGN_POST":
|
|
case "RAILS":
|
|
case "WALL_SIGN":
|
|
case "STONE_PLATE":
|
|
case "WOOD_PLATE":
|
|
case "REDSTONE_TORCH_OFF":
|
|
case "REDSTONE_TORCH_ON":
|
|
case "SUGAR_CANE_BLOCK":
|
|
case "PORTAL":
|
|
case "ENDER_PORTAL":
|
|
case "CARROT":
|
|
case "POTATO":
|
|
case "WOOD_BUTTON":
|
|
case "GOLD_PLATE":
|
|
case "IRON_PLATE":
|
|
case "DOUBLE_PLANT":
|
|
case "STANDING_BANNER":
|
|
case "WALL_BANNER":
|
|
case "BEETROOT_BLOCK":
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check to see if a player can walk into this material<br />
|
|
* This includes blocks like slabs and stairs
|
|
*
|
|
* @param m material to check
|
|
*
|
|
* @return true if this is a block that can be walked through or up
|
|
*/
|
|
public static boolean canWalkTo(Material m) {
|
|
switch (m.name()) {
|
|
case "ACACIA_BUTTON":
|
|
case "ACACIA_PRESSURE_PLATE":
|
|
case "ACACIA_SAPLING":
|
|
case "ACACIA_SIGN":
|
|
case "ACACIA_SLAB":
|
|
case "ACACIA_STAIRS":
|
|
case "ACACIA_TRAPDOOR":
|
|
case "ACACIA_WALL_SIGN":
|
|
case "ACTIVATOR_RAIL":
|
|
case "AIR":
|
|
case "ANDESITE_SLAB":
|
|
case "ANDESITE_STAIRS":
|
|
case "ATTACHED_MELON_STEM":
|
|
case "ATTACHED_PUMPKIN_STEM":
|
|
case "AZURE_BLUET":
|
|
case "BEETROOTS":
|
|
case "BIRCH_BUTTON":
|
|
case "BIRCH_DOOR":
|
|
case "BIRCH_FENCE_GATE":
|
|
case "BIRCH_PRESSURE_PLATE":
|
|
case "BIRCH_SAPLING":
|
|
case "BIRCH_SIGN":
|
|
case "BIRCH_SLAB":
|
|
case "BIRCH_STAIRS":
|
|
case "BIRCH_TRAPDOOR":
|
|
case "BIRCH_WALL_SIGN":
|
|
case "BLACK_CARPET":
|
|
case "BLACK_WALL_BANNER":
|
|
case "BLUE_BANNER":
|
|
case "BLUE_CARPET":
|
|
case "BLUE_ORCHID":
|
|
case "BLUE_WALL_BANNER":
|
|
case "BRAIN_CORAL_FAN":
|
|
case "BRAIN_CORAL_WALL_FAN":
|
|
case "BRICK_SLAB":
|
|
case "BRICK_STAIRS":
|
|
case "BROWN_BANNER":
|
|
case "BROWN_CARPET":
|
|
case "BROWN_MUSHROOM":
|
|
case "BROWN_WALL_BANNER":
|
|
case "BUBBLE_CORAL_FAN":
|
|
case "BUBBLE_CORAL_WALL_FAN":
|
|
case "CAKE":
|
|
case "CAMPFIRE":
|
|
case "CARROTS":
|
|
case "CAVE_AIR":
|
|
case "COBBLESTONE_SLAB":
|
|
case "COBBLESTONE_STAIRS":
|
|
case "COBWEB":
|
|
case "COMPARATOR":
|
|
case "CORNFLOWER":
|
|
case "CUT_RED_SANDSTONE_SLAB":
|
|
case "CUT_SANDSTONE_SLAB":
|
|
case "CYAN_BANNER":
|
|
case "CYAN_CARPET":
|
|
case "CYAN_WALL_BANNER":
|
|
case "DANDELION":
|
|
case "DARK_OAK_BUTTON":
|
|
case "DARK_OAK_DOOR":
|
|
case "DARK_OAK_FENCE_GATE":
|
|
case "DARK_OAK_PRESSURE_PLATE":
|
|
case "DARK_OAK_SAPLING":
|
|
case "DARK_OAK_SIGN":
|
|
case "DARK_OAK_SLAB":
|
|
case "DARK_OAK_STAIRS":
|
|
case "DARK_OAK_TRAPDOOR":
|
|
case "DARK_OAK_WALL_SIGN":
|
|
case "DARK_PRISMARINE_SLAB":
|
|
case "DARK_PRISMARINE_STAIRS":
|
|
case "DAYLIGHT_DETECTOR":
|
|
case "DEAD_BRAIN_CORAL_FAN":
|
|
case "DEAD_BRAIN_CORAL_WALL_FAN":
|
|
case "DEAD_BUBBLE_CORAL_FAN":
|
|
case "DEAD_BUBBLE_CORAL_WALL_FAN":
|
|
case "DEAD_BUSH":
|
|
case "DEAD_FIRE_CORAL_FAN":
|
|
case "DEAD_FIRE_CORAL_WALL_FAN":
|
|
case "DEAD_HORN_CORAL_FAN":
|
|
case "DEAD_HORN_CORAL_WALL_FAN":
|
|
case "DEAD_TUBE_CORAL_FAN":
|
|
case "DEAD_TUBE_CORAL_WALL_FAN":
|
|
case "DETECTOR_RAIL":
|
|
case "DIORITE_SLAB":
|
|
case "DIORITE_STAIRS":
|
|
case "END_PORTAL":
|
|
case "END_STONE_BRICK_SLAB":
|
|
case "END_STONE_BRICK_STAIRS":
|
|
case "FERN":
|
|
case "FIRE":
|
|
case "FIRE_CORAL_FAN":
|
|
case "FIRE_CORAL_WALL_FAN":
|
|
case "FLOWER_POT":
|
|
case "GRANITE_SLAB":
|
|
case "GRANITE_STAIRS":
|
|
case "GRASS":
|
|
case "GRAY_BANNER":
|
|
case "GRAY_CARPET":
|
|
case "GRAY_WALL_BANNER":
|
|
case "GREEN_BANNER":
|
|
case "GREEN_WALL_BANNER":
|
|
case "HEAVY_WEIGHTED_PRESSURE_PLATE":
|
|
case "HORN_CORAL_FAN":
|
|
case "HORN_CORAL_WALL_FAN":
|
|
case "IRON_DOOR":
|
|
case "JUNGLE_BUTTON":
|
|
case "JUNGLE_DOOR":
|
|
case "JUNGLE_FENCE_GATE":
|
|
case "JUNGLE_PRESSURE_PLATE":
|
|
case "JUNGLE_SAPLING":
|
|
case "JUNGLE_SIGN":
|
|
case "JUNGLE_SLAB":
|
|
case "JUNGLE_STAIRS":
|
|
case "JUNGLE_TRAPDOOR":
|
|
case "JUNGLE_WALL_SIGN":
|
|
case "KELP":
|
|
case "LADDER":
|
|
case "LARGE_FERN":
|
|
case "LAVA":
|
|
case "LEVER":
|
|
case "LIGHT_BLUE_BANNER":
|
|
case "LIGHT_BLUE_CARPET":
|
|
case "LIGHT_BLUE_WALL_BANNER":
|
|
case "LIGHT_GRAY_BANNER":
|
|
case "LIGHT_GRAY_CARPET":
|
|
case "LIGHT_GRAY_WALL_BANNER":
|
|
case "LIGHT_WEIGHTED_PRESSURE_PLATE":
|
|
case "LILAC":
|
|
case "LILY_OF_THE_VALLEY":
|
|
case "LILY_PAD":
|
|
case "LIME_BANNER":
|
|
case "LIME_CARPET":
|
|
case "MAGENTA_BANNER":
|
|
case "MAGENTA_CARPET":
|
|
case "MAGENTA_WALL_BANNER":
|
|
case "MELON_STEM":
|
|
case "MOSSY_COBBLESTONE_SLAB":
|
|
case "MOSSY_COBBLESTONE_STAIRS":
|
|
case "MOSSY_STONE_BRICK_SLAB":
|
|
case "MOSSY_STONE_BRICK_STAIRS":
|
|
case "NETHER_BRICK_SLAB":
|
|
case "NETHER_BRICK_STAIRS":
|
|
case "NETHER_PORTAL":
|
|
case "NETHER_WART":
|
|
case "OAK_BUTTON":
|
|
case "OAK_DOOR":
|
|
case "OAK_FENCE_GATE":
|
|
case "OAK_PRESSURE_PLATE":
|
|
case "OAK_SAPLING":
|
|
case "OAK_SIGN":
|
|
case "OAK_SLAB":
|
|
case "OAK_STAIRS":
|
|
case "OAK_TRAPDOOR":
|
|
case "OAK_WALL_SIGN":
|
|
case "ORANGE_BANNER":
|
|
case "ORANGE_CARPET":
|
|
case "ORANGE_TULIP":
|
|
case "ORANGE_WALL_BANNER":
|
|
case "OXEYE_DAISY":
|
|
case "PEONY":
|
|
case "PETRIFIED_OAK_SLAB":
|
|
case "PINK_BANNER":
|
|
case "PINK_CARPET":
|
|
case "PINK_TULIP":
|
|
case "PINK_WALL_BANNER":
|
|
case "POLISHED_ANDESITE_SLAB":
|
|
case "POLISHED_ANDESITE_STAIRS":
|
|
case "POLISHED_DIORITE_SLAB":
|
|
case "POLISHED_DIORITE_STAIRS":
|
|
case "POLISHED_GRANITE_SLAB":
|
|
case "POLISHED_GRANITE_STAIRS":
|
|
case "POTATOES":
|
|
case "POTTED_ACACIA_SAPLING":
|
|
case "POTTED_ALLIUM":
|
|
case "POTTED_AZURE_BLUET":
|
|
case "POTTED_BAMBOO":
|
|
case "POTTED_BIRCH_SAPLING":
|
|
case "POTTED_BLUE_ORCHID":
|
|
case "POTTED_BROWN_MUSHROOM":
|
|
case "POTTED_CACTUS":
|
|
case "POTTED_CORNFLOWER":
|
|
case "POTTED_DANDELION":
|
|
case "POTTED_DARK_OAK_SAPLING":
|
|
case "POTTED_DEAD_BUSH":
|
|
case "POTTED_FERN":
|
|
case "POTTED_JUNGLE_SAPLING":
|
|
case "POTTED_LILY_OF_THE_VALLEY":
|
|
case "POTTED_OAK_SAPLING":
|
|
case "POTTED_ORANGE_TULIP":
|
|
case "POTTED_OXEYE_DAISY":
|
|
case "POTTED_PINK_TULIP":
|
|
case "POTTED_POPPY":
|
|
case "POTTED_RED_MUSHROOM":
|
|
case "POTTED_RED_TULIP":
|
|
case "POTTED_SPRUCE_SAPLING":
|
|
case "POTTED_WHITE_TULIP":
|
|
case "POTTED_WITHER_ROSE":
|
|
case "POWERED_RAIL":
|
|
case "PRISMARINE_BRICK_SLAB":
|
|
case "PRISMARINE_BRICK_STAIRS":
|
|
case "PRISMARINE_SLAB":
|
|
case "PRISMARINE_STAIRS":
|
|
case "PUMPKIN_STEM":
|
|
case "PURPLE_BANNER":
|
|
case "PURPLE_CARPET":
|
|
case "PURPLE_WALL_BANNER":
|
|
case "PURPUR_SLAB":
|
|
case "PURPUR_STAIRS":
|
|
case "RAIL":
|
|
case "REDSTONE_TORCH":
|
|
case "REDSTONE_WALL_TORCH":
|
|
case "REDSTONE_WIRE":
|
|
case "RED_BANNER":
|
|
case "RED_CARPET":
|
|
case "RED_MUSHROOM":
|
|
case "RED_SANDSTONE_SLAB":
|
|
case "RED_SANDSTONE_STAIRS":
|
|
case "RED_TULIP":
|
|
case "RED_WALL_BANNER":
|
|
case "REPEATER":
|
|
case "ROSE_BUSH":
|
|
case "SANDSTONE_SLAB":
|
|
case "SANDSTONE_STAIRS":
|
|
case "SCAFFOLDING":
|
|
case "SEAGRASS":
|
|
case "SMOOTH_QUARTZ_SLAB":
|
|
case "SMOOTH_QUARTZ_STAIRS":
|
|
case "SMOOTH_RED_SANDSTONE_SLAB":
|
|
case "SMOOTH_RED_SANDSTONE_STAIRS":
|
|
case "SMOOTH_SANDSTONE_SLAB":
|
|
case "SMOOTH_SANDSTONE_STAIRS":
|
|
case "SMOOTH_STONE_SLAB":
|
|
case "SPRUCE_BUTTON":
|
|
case "SPRUCE_DOOR":
|
|
case "SPRUCE_FENCE_GATE":
|
|
case "SPRUCE_PRESSURE_PLATE":
|
|
case "SPRUCE_SAPLING":
|
|
case "SPRUCE_SIGN":
|
|
case "SPRUCE_SLAB":
|
|
case "SPRUCE_STAIRS":
|
|
case "SPRUCE_TRAPDOOR":
|
|
case "SPRUCE_WALL_SIGN":
|
|
case "STONECUTTER":
|
|
case "STONE_BRICK_SLAB":
|
|
case "STONE_BRICK_STAIRS":
|
|
case "STONE_BUTTON":
|
|
case "STONE_PRESSURE_PLATE":
|
|
case "STONE_SLAB":
|
|
case "STONE_STAIRS":
|
|
case "STRUCTURE_VOID":
|
|
case "SUGAR_CANE":
|
|
case "SUNFLOWER":
|
|
case "SWEET_BERRY_BUSH":
|
|
case "TALL_GRASS":
|
|
case "TALL_SEAGRASS":
|
|
case "TORCH":
|
|
case "TRIPWIRE":
|
|
case "TRIPWIRE_HOOK":
|
|
case "TUBE_CORAL_FAN":
|
|
case "TUBE_CORAL_WALL_FAN":
|
|
case "VINE":
|
|
case "VOID_AIR":
|
|
case "WALL_TORCH":
|
|
case "WATER":
|
|
case "WHEAT":
|
|
case "WHITE_BANNER":
|
|
case "WHITE_CARPET":
|
|
case "WHITE_TULIP":
|
|
case "WHITE_WALL_BANNER":
|
|
case "WITHER_ROSE":
|
|
case "YELLOW_BANNER":
|
|
case "YELLOW_CARPET":
|
|
case "YELLOW_WALL_BANNER":
|
|
// Legacy values:
|
|
case "WEB":
|
|
case "LONG_GRASS":
|
|
case "YELLOW_FLOWER":
|
|
case "RED_ROSE":
|
|
case "STEP":
|
|
case "WOOD_STAIRS":
|
|
case "CROPS":
|
|
case "SIGN_POST":
|
|
case "RAILS":
|
|
case "WOODEN_DOOR":
|
|
case "WALL_SIGN":
|
|
case "STONE_PLATE":
|
|
case "IRON_DOOR_BLOCK":
|
|
case "WOOD_PLATE":
|
|
case "REDSTONE_TORCH_OFF":
|
|
case "REDSTONE_TORCH_ON":
|
|
case "SNOW":
|
|
case "SUGAR_CANE_BLOCK":
|
|
case "PORTAL":
|
|
case "CAKE_BLOCK":
|
|
case "DIODE_BLOCK_OFF":
|
|
case "DIODE_BLOCK_ON":
|
|
case "TRAP_DOOR":
|
|
case "FENCE_GATE":
|
|
case "SMOOTH_STAIRS":
|
|
case "ENDER_PORTAL":
|
|
case "WOOD_STEP":
|
|
case "SPRUCE_WOOD_STAIRS":
|
|
case "BIRCH_WOOD_STAIRS":
|
|
case "JUNGLE_WOOD_STAIRS":
|
|
case "CARROT":
|
|
case "POTATO":
|
|
case "WOOD_BUTTON":
|
|
case "GOLD_PLATE":
|
|
case "IRON_PLATE":
|
|
case "REDSTONE_COMPARATOR_OFF":
|
|
case "REDSTONE_COMPARATOR_ON":
|
|
case "QUARTZ_STAIRS":
|
|
case "DOUBLE_PLANT":
|
|
case "STANDING_BANNER":
|
|
case "WALL_BANNER":
|
|
case "DAYLIGHT_DETECTOR_INVERTED":
|
|
case "DOUBLE_STONE_SLAB2":
|
|
case "STONE_SLAB2":
|
|
case "BEETROOT_BLOCK":
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
}
|