From 6996db9e63040fbdfd5afca8b701506082e75a5b Mon Sep 17 00:00:00 2001 From: "Kristian S. Stangeland" Date: Wed, 2 Jan 2013 20:37:24 +0100 Subject: [PATCH] Add a serializer for reading and writing ItemStacks to byte arrays. To aid discoverability, we add a short-cut to this serializer in PacketContainer, next to the getByteArrays() method. --- .../protocol/events/PacketContainer.java | 9 +++ .../protocol/utility/StreamSerializer.java | 73 +++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 ProtocolLib/src/main/java/com/comphenix/protocol/utility/StreamSerializer.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 c724a266..b819ee04 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketContainer.java @@ -51,6 +51,7 @@ import com.comphenix.protocol.reflect.cloning.ImmutableDetector; import com.comphenix.protocol.reflect.cloning.AggregateCloner.BuilderParameters; import com.comphenix.protocol.reflect.instances.DefaultInstances; import com.comphenix.protocol.utility.MinecraftReflection; +import com.comphenix.protocol.utility.StreamSerializer; import com.comphenix.protocol.wrappers.BukkitConverters; import com.comphenix.protocol.wrappers.ChunkPosition; import com.comphenix.protocol.wrappers.WrappedDataWatcher; @@ -235,6 +236,14 @@ public class PacketContainer implements Serializable { public StructureModifier getByteArrays() { return structureModifier.withType(byte[].class); } + + /** + * Retrieve a serializer for reading and writing ItemStacks stored in a byte array. + * @return A instance of the serializer. + */ + public StreamSerializer getByteArraySerializer() { + return new StreamSerializer(); + } /** * Retrieves a read/write structure for every int array field. diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/utility/StreamSerializer.java b/ProtocolLib/src/main/java/com/comphenix/protocol/utility/StreamSerializer.java new file mode 100644 index 00000000..2edbb3cf --- /dev/null +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/utility/StreamSerializer.java @@ -0,0 +1,73 @@ +package com.comphenix.protocol.utility; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.lang.reflect.Method; + +import org.bukkit.inventory.ItemStack; + +import com.comphenix.protocol.reflect.FuzzyReflection; + +/** + * Utility methods for reading and writing Minecraft objects to streams. + * + * @author Kristian + */ +public class StreamSerializer { + // Cached methods + private static Method readItemMethod; + private static Method writeItemMethod; + + /** + * Read or deserialize an item stack from an underlying input stream. + *

+ * To supply a byte array, wrap it in a {@link java.io.ByteArrayInputStream ByteArrayInputStream} + * and {@link java.io.DataInputStream DataInputStream}. + * + * @param input - the target input stream. + * @return The resulting item stack. + * @throws IOException If the operation failed due to reflection or corrupt data. + */ + public ItemStack deserializeItemStack(DataInputStream input) throws IOException { + if (readItemMethod == null) + readItemMethod = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()). + getMethodByParameters("readPacket", + MinecraftReflection.getItemStackClass(), + new Class[] {DataInputStream.class}); + try { + Object nmsItem = readItemMethod.invoke(null, input); + + // Convert back to a Bukkit item stack + return MinecraftReflection.getBukkitItemStack(nmsItem); + + } catch (Exception e) { + throw new IOException("Cannot read item stack.", e); + } + } + + /** + * Write or serialize an item stack to the given output stream. + *

+ * To supply a byte array, wrap it in a {@link java.io.ByteArrayOutputStream ByteArrayOutputStream} + * and {@link java.io.DataOutputStream DataOutputStream}. + * + * @param output - the target output stream. + * @param stack - the item stack that will be written. + * @throws IOException If the operation fails due to reflection problems. + */ + public void serializeItemStack(DataOutputStream output, ItemStack stack) throws IOException { + Object nmsItem = MinecraftReflection.getMinecraftItemStack(stack); + + if (writeItemMethod == null) + writeItemMethod = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()). + getMethodByParameters("writePacket", new Class[] { + MinecraftReflection.getItemStackClass(), + DataOutputStream.class }); + try { + writeItemMethod.invoke(null, nmsItem, output); + } catch (Exception e) { + throw new IOException("Cannot write item stack " + stack, e); + } + } +}