From 36313eabb1b71b2eac6b9f6a2133fd6bc2b535aa Mon Sep 17 00:00:00 2001 From: Dan Mulloy Date: Sun, 10 May 2015 14:04:08 -0400 Subject: [PATCH] Add wrapper for MultiBlockChangeInfo --- .../protocol/events/PacketContainer.java | 23 +- .../protocol/utility/MinecraftReflection.java | 18 +- .../wrappers/MultiBlockChangeInfo.java | 223 ++++++++++++++++++ 3 files changed, 253 insertions(+), 11 deletions(-) create mode 100644 ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/MultiBlockChangeInfo.java 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 30971fe3..b7275b48 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java @@ -87,6 +87,7 @@ import com.comphenix.protocol.wrappers.EnumWrappers.ResourcePackStatus; import com.comphenix.protocol.wrappers.EnumWrappers.ScoreboardAction; import com.comphenix.protocol.wrappers.EnumWrappers.TitleAction; import com.comphenix.protocol.wrappers.EnumWrappers.WorldBorderAction; +import com.comphenix.protocol.wrappers.MultiBlockChangeInfo; import com.comphenix.protocol.wrappers.PlayerInfoData; import com.comphenix.protocol.wrappers.WrappedAttribute; import com.comphenix.protocol.wrappers.WrappedBlockData; @@ -459,11 +460,8 @@ public class PacketContainer implements Serializable { /** * Retrieves a read/write structure for chunk positions. - * - * @deprecated ChunkPosition no longer exists. * @return A modifier for a ChunkPosition. */ - @Deprecated public StructureModifier getPositionModifier() { // Convert to and from the Bukkit wrapper return structureModifier.withType( @@ -616,14 +614,29 @@ public class PacketContainer implements Serializable { * Retrieves a read/write structure for BlockData in Minecraft 1.8. *

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

+ * This modifier will automatically marshall between MultiBlockChangeInfo and the + * internal Minecraft MultiBlockChangeInfo. + * @return A modifier for BlockData fields. + */ + public StructureModifier getMultiBlockChangeInfoArrays() { + ChunkCoordIntPair chunk = getChunkCoordIntPairs().read(0); + + // Convert to and from our wrapper + return structureModifier.withType( + MinecraftReflection.getMultiBlockChangeInfoArrayClass(), MultiBlockChangeInfo.getArrayConverter(chunk)); + } /** * 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 43f1c69a..26880d6e 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java @@ -1924,13 +1924,19 @@ public class MinecraftReflection { } /** - * Determine if the given object is an IBlockData. - * @param obj - the given object. - * @return TRUE if it is, FALSE otherwise. + * Retrieve the MultiBlockChangeInfo class in 1.8. + * @return The MultiBlockChangeInfo class */ - public static boolean isIBlockData(Object obj) { - Class clazz = getIBlockDataClass(); - return clazz != null && obj.getClass().equals(clazz); + public static Class getMultiBlockChangeInfoClass() { + return getMinecraftClass("PacketPlayOutMultiBlockChange$MultiBlockChangeInfo"); + } + + /** + * Retrieve the MultiBlockChangeInfo array class in 1.8. + * @return The MultiBlockChangeInfo array class + */ + public static Class getMultiBlockChangeInfoArrayClass() { + return getArrayClass(getMultiBlockChangeInfoClass()); } /** diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/MultiBlockChangeInfo.java b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/MultiBlockChangeInfo.java new file mode 100644 index 00000000..aad75998 --- /dev/null +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/MultiBlockChangeInfo.java @@ -0,0 +1,223 @@ +/** + * (c) 2015 dmulloy2 + */ +package com.comphenix.protocol.wrappers; + +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; + +import org.bukkit.Location; +import org.bukkit.World; + +import com.comphenix.protocol.reflect.EquivalentConverter; +import com.comphenix.protocol.reflect.StructureModifier; +import com.comphenix.protocol.utility.MinecraftReflection; + +/** + * Represents a single block change. + * + * @author dmulloy2 + */ + +public class MultiBlockChangeInfo { + private short location; + private WrappedBlockData data; + private ChunkCoordIntPair chunk; + + public MultiBlockChangeInfo(short location, WrappedBlockData data, ChunkCoordIntPair chunk) { + this.location = location; + this.data = data; + this.chunk = chunk; + } + + /** + * Returns this block change's absolute Location in a given World. + * + * @param world World for the location + * @return This block change's absolute Location + */ + public Location getLocation(World world) { + return new Location(world, getX(), getY(), getZ()); + } + + /** + * Sets this block change's absolute Location. + * + * @param location This block change's new location + */ + public void setLocation(Location location) { + int x = location.getBlockX() - getChunkX() << 4; + int y = location.getBlockY(); + int z = location.getBlockZ() - getChunkZ() << 4; + + this.location = (short) (x << 12 | z << 8 | y); + } + + /** + * Gets this block change's absolute x coordinate + * + * @return X coordinate + */ + public int getX() { + return getChunkX() + (location >> 12 & 15); + } + + /** + * Sets this block change's absolute x coordinate + * + * @param x New x coordinate + */ + public void setX(int x) { + x -= getChunkX() << 4; + this.location = (short) (x << 12 | getZ() << 8 | getY()); + } + + /** + * Gets this block change's y coordinate. + * + * @return Y coordinate + */ + public int getY() { + return location & 255; + } + + /** + * Sets this block change's y coordinate + * + * @param y New y coordinate + */ + public void setY(int y) { + this.location = (short) (getX() << 12 | getZ() << 8 | y); + } + + /** + * Gets this block change's absolute z coordinate. + * + * @return Z coordinate + */ + public int getZ() { + return getChunkZ() + (location >> 8 & 15); + } + + /** + * Sets this block change's absolute z coordinate. + * + * @param z New z coordinate + */ + public void setZ(int z) { + z -= getChunkZ() << 4; + this.location = (short) (getX() << 12 | getZ() << 8 | getY()); + } + + private int getChunkX() { + return chunk.getChunkX() << 4; + } + + private int getChunkZ() { + return chunk.getChunkZ() << 4; + } + + /** + * Gets this block change's block data. + * + * @return The block data + */ + public WrappedBlockData getData() { + return data; + } + + /** + * Sets this block change's block data. + * + * @param data New block data + */ + public void setData(WrappedBlockData data) { + this.data = data; + } + + /** + * Gets the chunk this block change occured in. + * + * @return The chunk + */ + public ChunkCoordIntPair getChunk() { + return chunk; + } + + public static EquivalentConverter getConverter(final ChunkCoordIntPair chunk) { + return new EquivalentConverter() { + + @Override + public MultiBlockChangeInfo getSpecific(Object generic) { + StructureModifier modifier = new StructureModifier(generic.getClass(), null, false).withTarget(generic); + + StructureModifier shorts = modifier.withType(short.class); + short location = shorts.read(0); + + StructureModifier dataModifier = modifier.withType(MinecraftReflection.getIBlockDataClass(), + BukkitConverters.getWrappedBlockDataConverter()); + WrappedBlockData data = dataModifier.read(0); + + return new MultiBlockChangeInfo(location, data, chunk); + } + + @Override + public Object getGeneric(Class genericType, MultiBlockChangeInfo specific) { + try { + Constructor constructor = MinecraftReflection.getMultiBlockChangeInfoClass().getConstructor( + short.class, + MinecraftReflection.getIBlockDataClass() + ); + + return constructor.newInstance( + specific.location, + BukkitConverters.getWrappedBlockDataConverter().getGeneric(MinecraftReflection.getIBlockDataClass(), specific.data) + ); + } catch (Throwable ex) { + throw new RuntimeException("Failed to construct MultiBlockChangeInfo instance.", ex); + } + } + + @Override + public Class getSpecificType() { + return MultiBlockChangeInfo.class; + } + }; + } + + public static EquivalentConverter getArrayConverter(final ChunkCoordIntPair chunk) { + return new EquivalentConverter() { + private final EquivalentConverter converter = MultiBlockChangeInfo.getConverter(chunk); + + @Override + public MultiBlockChangeInfo[] getSpecific(Object generic) { + Object[] array = (Object[]) generic; + MultiBlockChangeInfo[] result = new MultiBlockChangeInfo[array.length]; + + // Unwrap every item + for (int i = 0; i < result.length; i++) { + result[i] = converter.getSpecific(array[i]); + } + + return result; + } + + @Override + public Object getGeneric(Class genericType, MultiBlockChangeInfo[] specific) { + Object[] result = (Object[]) Array.newInstance(genericType, specific.length); + + // Wrap every item + for (int i = 0; i < result.length; i++) { + result[i] = converter.getGeneric(genericType, specific[i]); + } + + return result; + } + + @Override + public Class getSpecificType() { + return MultiBlockChangeInfo[].class; + } + }; + } +} \ No newline at end of file