diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java b/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java index 609d00d9..0743c9d2 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java @@ -88,6 +88,7 @@ import com.comphenix.protocol.wrappers.EnumWrappers.TitleAction; import com.comphenix.protocol.wrappers.EnumWrappers.WorldBorderAction; import com.comphenix.protocol.wrappers.PlayerInfoData; import com.comphenix.protocol.wrappers.WrappedAttribute; +import com.comphenix.protocol.wrappers.WrappedBlockData; import com.comphenix.protocol.wrappers.WrappedChatComponent; import com.comphenix.protocol.wrappers.WrappedDataWatcher; import com.comphenix.protocol.wrappers.WrappedGameProfile; @@ -612,6 +613,19 @@ public class PacketContainer implements Serializable { GameProfile.class, BukkitConverters.getWrappedGameProfileConverter()); } + /** + * Retrieves a read/write structure for BlockData in Minecraft 1.8. + *

+ * This modifier will automatically marshall between WrappedBlockData and the + * internal Minecraft BlockData. + * @return A modifier for BlockData fields. + */ + public StructureModifier getBlockData() { + // Conver to and from our wrapper + return structureModifier.withType( + MinecraftReflection.getIBlockDataClass(), BukkitConverters.getWrappedBlockDataConverter()); + } + /** * Retrieves a read/write structure for chat components in Minecraft 1.7.2. *

diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java b/ProtocolLib/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java index fb5af3b9..06158db5 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java @@ -1915,6 +1915,24 @@ public class MinecraftReflection { return clazz != null && obj.getClass().equals(clazz); } + /** + * Retrieve the IBlockData class in 1.8. + * @return The IBlockData class + */ + public static Class getIBlockDataClass() { + return getMinecraftClass("IBlockData"); + } + + /** + * Determine if the given object is an IBlockData. + * @param obj - the given object. + * @return TRUE if it is, FALSE otherwise. + */ + public static boolean isIBlockData(Object obj) { + Class clazz = getIBlockDataClass(); + return clazz != null && obj.getClass().equals(clazz); + } + /** * Retrieve the given class by name. * @param className - name of the class. diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/BukkitConverters.java b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/BukkitConverters.java index 5dd1070d..578f9612 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/BukkitConverters.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/BukkitConverters.java @@ -395,7 +395,7 @@ public class BukkitConverters { /** * Retrieve a converter for wrapped chat components. - * @return Wrapped chat componetns. + * @return Wrapped chat component. */ public static EquivalentConverter getWrappedChatComponentConverter() { return new IgnoreNullConverter() { @@ -416,6 +416,29 @@ public class BukkitConverters { }; } + /** + * Retrieve a converter for wrapped block data. + * @return Wrapped block data. + */ + public static EquivalentConverter getWrappedBlockDataConverter() { + return new IgnoreNullConverter() { + @Override + protected Object getGenericValue(Class genericType, WrappedBlockData specific) { + return specific.getHandle(); + } + + @Override + protected WrappedBlockData getSpecificValue(Object generic) { + return new WrappedBlockData(generic); + } + + @Override + public Class getSpecificType() { + return WrappedBlockData.class; + } + }; + } + /** * Retrieve a converter for wrapped attribute snapshots. * @return Wrapped attribute snapshot converter. diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedBlockData.java b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedBlockData.java new file mode 100644 index 00000000..d72f05d7 --- /dev/null +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedBlockData.java @@ -0,0 +1,95 @@ +/** + * (c) 2015 dmulloy2 + */ +package com.comphenix.protocol.wrappers; + +import org.bukkit.Material; + +import com.comphenix.protocol.reflect.FuzzyReflection; +import com.comphenix.protocol.reflect.accessors.Accessors; +import com.comphenix.protocol.reflect.accessors.MethodAccessor; +import com.comphenix.protocol.utility.MinecraftReflection; + +/** + * Represents a wrapper around IBlockData. + * + * @author dmulloy2 + */ + +public class WrappedBlockData extends AbstractWrapper { + private static final Class MAGIC_NUMBERS = MinecraftReflection.getCraftBukkitClass("util.CraftMagicNumbers"); + private static final Class IBLOCK_DATA = MinecraftReflection.getIBlockDataClass(); + private static final Class BLOCK = MinecraftReflection.getBlockClass(); + + private static MethodAccessor FROM_LEGACY_DATA = null; + private static MethodAccessor GET_NMS_BLOCK = null; + private static MethodAccessor GET_BLOCK = null; + + static { + FuzzyReflection fuzzy = FuzzyReflection.fromClass(BLOCK); + FROM_LEGACY_DATA = Accessors.getMethodAccessor(fuzzy.getMethodByParameters("fromLegacyData", IBLOCK_DATA, + new Class[] { int.class })); + + fuzzy = FuzzyReflection.fromClass(MAGIC_NUMBERS); + GET_NMS_BLOCK = Accessors.getMethodAccessor(fuzzy.getMethodByParameters("getBlock", BLOCK, + new Class[] { int.class })); + + fuzzy = FuzzyReflection.fromClass(IBLOCK_DATA); + GET_BLOCK = Accessors.getMethodAccessor(fuzzy.getMethodByParameters("getBlock", BLOCK, + new Class[0])); + } + + public WrappedBlockData(Object handle) { + super(IBLOCK_DATA); + setHandle(handle); + } + + /** + * Retrieves the type of this BlockData. + * @return The type of this BlockData. + */ + public Material getType() { + Object block = GET_BLOCK.invoke(handle); + return BukkitConverters.getBlockConverter().getSpecific(block); + } + + /** + * Sets the type of this BlockData. + * @param type New type + */ + public void setType(Material type) { + setTypeAndData(type, 0); + } + + /** + * Sets the type and data of this BlockData. + * @param type New type + * @param data New data + */ + public void setTypeAndData(Material type, int data) { + Object nmsBlock = GET_NMS_BLOCK.invoke(null, type.getId()); + Object blockData = FROM_LEGACY_DATA.invoke(nmsBlock, data); + setHandle(blockData); + } + + /** + * Creates a new BlockData instance with the given type and no data. + * @param type Block type + * @return New BlockData + */ + public static WrappedBlockData createData(Material type) { + return createData(type, 0); + } + + /** + * Creates a new BlockData instance with the given type and data. + * @param type Block type + * @param data Block data + * @return New BlockData + */ + public static WrappedBlockData createData(Material type, int data) { + Object nmsBlock = GET_NMS_BLOCK.invoke(null, type.getId()); + Object blockData = FROM_LEGACY_DATA.invoke(nmsBlock, data); + return new WrappedBlockData(blockData); + } +} \ No newline at end of file