Fix the StreamSerializer

String-based methods will still work, but deserializing from a data
input stream has been deprecated since it depends on hacky code

Fixes #31, Fixes #125
This commit is contained in:
Dan Mulloy 2015-11-02 23:56:41 -05:00
parent 4bb917e596
commit 7dff86cb48
10 changed files with 293 additions and 191 deletions

View File

@ -61,10 +61,6 @@ public class Netty {
return getCompat().createPacketBuffer(); return getCompat().createPacketBuffer();
} }
public static WrappedByteBuf allocateUnpooled() {
return getCompat().allocateUnpooled();
}
public static Class<?> getGenericFutureListenerArray() { public static Class<?> getGenericFutureListenerArray() {
return getCompat().getGenericFutureListenerArray(); return getCompat().getGenericFutureListenerArray();
} }
@ -92,4 +88,12 @@ public class Netty {
public static WrappedByteBuf packetWriter(DataOutputStream output) { public static WrappedByteBuf packetWriter(DataOutputStream output) {
return getCompat().packetWriter(output); return getCompat().packetWriter(output);
} }
public static WrappedByteBuf copiedBuffer(byte[] array) {
return getCompat().copiedBuffer(array);
}
public static WrappedByteBuf buffer() {
return getCompat().buffer();
}
} }

View File

@ -30,11 +30,14 @@ import com.comphenix.protocol.wrappers.WrappedServerPing.CompressedImage;
* @author dmulloy2 * @author dmulloy2
*/ */
// TODO: Sort out packet readers/writers
public interface NettyCompat { public interface NettyCompat {
WrappedByteBuf createPacketBuffer(); WrappedByteBuf createPacketBuffer();
WrappedByteBuf allocateUnpooled(); WrappedByteBuf copiedBuffer(byte[] array);
WrappedByteBuf buffer();
Class<?> getGenericFutureListenerArray(); Class<?> getGenericFutureListenerArray();

View File

@ -41,4 +41,6 @@ public interface WrappedByteBuf {
void writeByte(int i); void writeByte(int i);
void writeBytes(byte[] bytes); void writeBytes(byte[] bytes);
byte[] array();
} }

View File

@ -55,11 +55,6 @@ public class IndependentNetty implements NettyCompat {
} }
} }
@Override
public WrappedByteBuf allocateUnpooled() {
return new NettyByteBuf(UnpooledByteBufAllocator.DEFAULT.buffer());
}
@Override @Override
public Class<?> getGenericFutureListenerArray() { public Class<?> getGenericFutureListenerArray() {
return GenericFutureListener[].class; return GenericFutureListener[].class;
@ -97,4 +92,14 @@ public class IndependentNetty implements NettyCompat {
public WrappedByteBuf packetWriter(DataOutputStream output) { public WrappedByteBuf packetWriter(DataOutputStream output) {
return new NettyByteBuf(NettyByteBufAdapter.packetWriter(output)); return new NettyByteBuf(NettyByteBufAdapter.packetWriter(output));
} }
@Override
public WrappedByteBuf copiedBuffer(byte[] array) {
return new NettyByteBuf(Unpooled.copiedBuffer(array));
}
@Override
public WrappedByteBuf buffer() {
return new NettyByteBuf(Unpooled.buffer());
}
} }

View File

@ -75,4 +75,9 @@ public class NettyByteBuf implements WrappedByteBuf {
public void writeBytes(byte[] bytes) { public void writeBytes(byte[] bytes) {
handle.get().writeBytes(bytes); handle.get().writeBytes(bytes);
} }
@Override
public byte[] array() {
return handle.get().array();
}
} }

View File

@ -174,7 +174,7 @@ public class MinecraftMethods {
// Create our proxy object // Create our proxy object
Object javaProxy = enhancer.create( Object javaProxy = enhancer.create(
new Class<?>[] { MinecraftReflection.getByteBufClass() }, new Class<?>[] { MinecraftReflection.getByteBufClass() },
new Object[] { Netty.allocateUnpooled().getHandle() } new Object[] { Netty.buffer().getHandle() }
); );
Object lookPacket = new PacketContainer(PacketType.Play.Client.CLOSE_WINDOW).getHandle(); Object lookPacket = new PacketContainer(PacketType.Play.Client.CLOSE_WINDOW).getHandle();

View File

@ -10,6 +10,7 @@ import java.io.IOException;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import org.apache.commons.lang.Validate;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder; import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
@ -50,6 +51,22 @@ public class StreamSerializer {
return DEFAULT; return DEFAULT;
} }
/**
* Write a variable integer to an output stream.
* @param destination - the destination.
* @param value - the value to write.
* @throws IOException The destination stream threw an exception.
*/
public void serializeVarInt(@Nonnull DataOutputStream destination, int value) throws IOException {
Preconditions.checkNotNull(destination, "source cannot be NULL");
while ((value & 0xFFFFFF80) != 0) {
destination.writeByte(value & 0x7F | 0x80);
value >>>= 7;
}
destination.writeByte(value);
}
/** /**
* Read a variable integer from an input stream. * Read a variable integer from an input stream.
* @param source - the source. * @param source - the source.
@ -73,66 +90,49 @@ public class StreamSerializer {
} }
/** /**
* Write a variable integer to an output stream. * Write or serialize a NBT compound to the given output stream.
* @param destination - the destination.
* @param value - the value to write.
* @throws IOException The destination stream threw an exception.
*/
public void serializeVarInt(@Nonnull DataOutputStream destination, int value) throws IOException {
Preconditions.checkNotNull(destination, "source cannot be NULL");
while ((value & 0xFFFFFF80) != 0) {
destination.writeByte(value & 0x7F | 0x80);
value >>>= 7;
}
destination.writeByte(value);
}
/**
* Read or deserialize an item stack from an underlying input stream.
* <p> * <p>
* To supply a byte array, wrap it in a {@link java.io.ByteArrayInputStream ByteArrayInputStream} * Note: An NBT compound can be written to a stream even if it's NULL.
* and {@link java.io.DataInputStream DataInputStream}.
* *
* @param input - the target input stream. * @param output - the target output stream.
* @return The resulting item stack, or NULL if the serialized item stack was NULL. * @param compound - the NBT compound to be serialized, or NULL to represent nothing.
* @throws IOException If the operation failed due to reflection or corrupt data. * @throws IOException If the operation fails due to reflection problems.
*/ */
public ItemStack deserializeItemStack(@Nonnull DataInputStream input) throws IOException { public void serializeCompound(@Nonnull DataOutputStream output, NbtCompound compound) throws IOException {
if (input == null) if (output == null)
throw new IllegalArgumentException("Input stream cannot be NULL."); throw new IllegalArgumentException("Output stream cannot be NULL.");
Object nmsItem = null;
// Get the NMS version of the compound
Object handle = compound != null ? NbtFactory.fromBase(compound).getHandle() : null;
if (MinecraftReflection.isUsingNetty()) { if (MinecraftReflection.isUsingNetty()) {
if (READ_ITEM_METHOD == null) { if (WRITE_NBT_METHOD == null) {
READ_ITEM_METHOD = Accessors.getMethodAccessor( WRITE_NBT_METHOD = Accessors.getMethodAccessor(
FuzzyReflection.fromClass(MinecraftReflection.getPacketDataSerializerClass(), true). FuzzyReflection.fromClass(MinecraftReflection.getPacketDataSerializerClass(), true).
getMethodByParameters("readItemStack", /* i */ getMethodByParameters("writeNbtCompound", /* a */
MinecraftReflection.getItemStackClass(), new Class<?>[0]) MinecraftReflection.getNBTCompoundClass())
); );
} }
nmsItem = READ_ITEM_METHOD.invoke(Netty.packetReader(input).getHandle()); WrappedByteBuf buf = Netty.packetWriter(output);
buf.writeByte(NbtType.TAG_COMPOUND.getRawID());
WRITE_NBT_METHOD.invoke(buf.getHandle(), handle);
} else { } else {
if (READ_ITEM_METHOD == null) { if (WRITE_NBT_METHOD == null) {
READ_ITEM_METHOD = Accessors.getMethodAccessor( WRITE_NBT_METHOD = Accessors.getMethodAccessor(
FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()).getMethod( FuzzyReflection.fromClass(MinecraftReflection.getPacketClass(), true).getMethod(
FuzzyMethodContract.newBuilder(). FuzzyMethodContract.newBuilder().
parameterCount(1). parameterCount(2).
parameterDerivedOf(DataInput.class). parameterDerivedOf(MinecraftReflection.getNBTBaseClass(), 0).
returnDerivedOf(MinecraftReflection.getItemStackClass()). parameterDerivedOf(DataOutput.class, 1).
returnTypeVoid().
build()) build())
); );
} }
nmsItem = READ_ITEM_METHOD.invoke(null, input); WRITE_NBT_METHOD.invoke(null, handle, output);
} }
// Convert back to a Bukkit item stack
if (nmsItem != null)
return MinecraftReflection.getBukkitItemStack(nmsItem);
else
return null;
} }
/** /**
@ -183,6 +183,47 @@ public class StreamSerializer {
return null; return null;
} }
/**
* Serialize a string using the standard Minecraft UTF-16 encoding.
* <p>
* Note that strings cannot exceed 32767 characters, regardless if maximum lenght.
* @param output - the output stream.
* @param text - the string to serialize.
* @throws IOException If the data in the string cannot be written.
*/
public void serializeString(@Nonnull DataOutputStream output, String text) throws IOException {
if (output == null)
throw new IllegalArgumentException("output stream cannot be NULL.");
if (text == null)
throw new IllegalArgumentException("text cannot be NULL.");
if (MinecraftReflection.isUsingNetty()) {
if (WRITE_STRING_METHOD == null) {
WRITE_STRING_METHOD = Accessors.getMethodAccessor(
FuzzyReflection.fromClass(MinecraftReflection.getPacketDataSerializerClass(), true).
getMethodByParameters("writeString", /* a */
String.class)
);
}
WRITE_STRING_METHOD.invoke(Netty.packetWriter(output).getHandle(), text);
} else {
if (WRITE_STRING_METHOD == null) {
WRITE_STRING_METHOD = Accessors.getMethodAccessor(
FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()).getMethod(
FuzzyMethodContract.newBuilder().
parameterCount(2).
parameterExactType(String.class, 0).
parameterDerivedOf(DataOutput.class, 1).
returnTypeVoid().
build())
);
}
WRITE_STRING_METHOD.invoke(null, text, output);
}
}
/** /**
* Deserialize a string using the standard Minecraft UTF-16 encoding. * Deserialize a string using the standard Minecraft UTF-16 encoding.
* <p> * <p>
@ -227,18 +268,98 @@ public class StreamSerializer {
} }
} }
/**
* Serialize an item stack as a base-64 encoded string.
* <p>
* Note: An ItemStack can be written to the serialized text even if it's NULL.
*
* @param stack - the item stack to serialize, or NULL to represent air/nothing.
* @return A base-64 representation of the given item stack.
* @throws IOException If the operation fails due to reflection problems.
*/
public String serializeItemStack(ItemStack stack) throws IOException {
Object nmsItem = MinecraftReflection.getMinecraftItemStack(stack);
byte[] bytes = null;
if (MinecraftReflection.isUsingNetty()) {
WrappedByteBuf buf = Netty.buffer();
Object serializer = MinecraftReflection.getPacketDataSerializer(buf.getHandle());
if (WRITE_ITEM_METHOD == null) {
WRITE_ITEM_METHOD = Accessors.getMethodAccessor(
FuzzyReflection.fromClass(MinecraftReflection.getPacketDataSerializerClass(), true).
getMethodByParameters("writeStack", // a()
MinecraftReflection.getItemStackClass()));
}
WRITE_ITEM_METHOD.invoke(serializer, nmsItem);
bytes = buf.array();
} else {
if (WRITE_ITEM_METHOD == null) {
WRITE_ITEM_METHOD = Accessors.getMethodAccessor(
FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()).getMethod(
FuzzyMethodContract.newBuilder().
parameterCount(2).
parameterDerivedOf(MinecraftReflection.getItemStackClass(), 0).
parameterDerivedOf(DataOutput.class, 1).
build())
);
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
DataOutputStream dataOutput = new DataOutputStream(outputStream);
WRITE_ITEM_METHOD.invoke(null, nmsItem, dataOutput);
bytes = outputStream.toByteArray();
}
return Base64Coder.encodeLines(bytes);
}
/** /**
* Deserialize an item stack from a base-64 encoded string. * Deserialize an item stack from a base-64 encoded string.
* @param input - base-64 encoded string. * @param input - base-64 encoded string.
* @return A deserialized item stack, or NULL if the serialized ItemStack was also NULL. * @return A deserialized item stack, or NULL if the serialized ItemStack was also NULL.
* @throws IOException If the operation failed due to reflection or corrupt data. * @throws IOException If the operation failed due to reflection or corrupt data.
*/ */
public ItemStack deserializeItemStack(@Nonnull String input) throws IOException { public ItemStack deserializeItemStack(String input) throws IOException {
if (input == null) Validate.notNull(input, "input cannot be null!");
throw new IllegalArgumentException("Input text cannot be NULL.");
ByteArrayInputStream inputStream = new ByteArrayInputStream(Base64Coder.decodeLines(input));
return deserializeItemStack(new DataInputStream(inputStream)); Object nmsItem = null;
byte[] bytes = Base64Coder.decodeLines(input);
if (MinecraftReflection.isUsingNetty()) {
WrappedByteBuf buf = Netty.copiedBuffer(bytes);
Object serializer = MinecraftReflection.getPacketDataSerializer(buf.getHandle());
if (READ_ITEM_METHOD == null) {
READ_ITEM_METHOD = Accessors.getMethodAccessor(FuzzyReflection.fromClass(MinecraftReflection.getPacketDataSerializerClass(), true).
getMethodByParameters("readItemStack", // i(ItemStack)
MinecraftReflection.getItemStackClass(), new Class<?>[0]));
}
nmsItem = READ_ITEM_METHOD.invoke(serializer);
} else {
if (READ_ITEM_METHOD == null) {
READ_ITEM_METHOD = Accessors.getMethodAccessor(
FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()).getMethod(
FuzzyMethodContract.newBuilder().
parameterCount(1).
parameterDerivedOf(DataInput.class).
returnDerivedOf(MinecraftReflection.getItemStackClass()).
build())
);
}
ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes);
DataInputStream inputStream = new DataInputStream(byteStream);
nmsItem = READ_ITEM_METHOD.invoke(null, inputStream);
}
return nmsItem != null ? MinecraftReflection.getBukkitItemStack(nmsItem) : null;
} }
/** /**
@ -253,9 +374,8 @@ public class StreamSerializer {
* @param stack - the item stack that will be written, or NULL to represent air/nothing. * @param stack - the item stack that will be written, or NULL to represent air/nothing.
* @throws IOException If the operation fails due to reflection problems. * @throws IOException If the operation fails due to reflection problems.
*/ */
public void serializeItemStack(@Nonnull DataOutputStream output, ItemStack stack) throws IOException { public void serializeItemStack(DataOutputStream output, ItemStack stack) throws IOException {
if (output == null) Validate.notNull("output cannot be null!");
throw new IllegalArgumentException("Output stream cannot be NULL.");
// Get the NMS version of the ItemStack // Get the NMS version of the ItemStack
Object nmsItem = MinecraftReflection.getMinecraftItemStack(stack); Object nmsItem = MinecraftReflection.getMinecraftItemStack(stack);
@ -269,7 +389,12 @@ public class StreamSerializer {
); );
} }
WRITE_ITEM_METHOD.invoke(Netty.packetWriter(output).getHandle(), nmsItem); WrappedByteBuf buf = Netty.buffer();
Object serializer = MinecraftReflection.getPacketDataSerializer(buf.getHandle());
WRITE_ITEM_METHOD.invoke(serializer, nmsItem);
output.write(buf.array());
} else { } else {
if (WRITE_ITEM_METHOD == null) if (WRITE_ITEM_METHOD == null)
WRITE_ITEM_METHOD = Accessors.getMethodAccessor( WRITE_ITEM_METHOD = Accessors.getMethodAccessor(
@ -286,108 +411,56 @@ public class StreamSerializer {
} }
/** /**
* Write or serialize a NBT compound to the given output stream. * Read or deserialize an item stack from an underlying input stream.
* <p> * <p>
* Note: An NBT compound can be written to a stream even if it's NULL. * To supply a byte array, wrap it in a {@link java.io.ByteArrayInputStream ByteArrayInputStream}
* and {@link java.io.DataInputStream DataInputStream}.
* *
* @param output - the target output stream. * @param input - the target input stream.
* @param compound - the NBT compound to be serialized, or NULL to represent nothing. * @return The resulting item stack, or NULL if the serialized item stack was NULL.
* @throws IOException If the operation fails due to reflection problems. * @throws IOException If the operation failed due to reflection or corrupt data.
* @deprecated This is a pretty hacky solution for backwards compatibility. See {@link #deserializeItemStack(DataInputStream)}
*/ */
public void serializeCompound(@Nonnull DataOutputStream output, NbtCompound compound) throws IOException { @Deprecated
if (output == null) public ItemStack deserializeItemStack(DataInputStream input) throws IOException {
throw new IllegalArgumentException("Output stream cannot be NULL."); Validate.notNull(input, "input cannot be null!");
Object nmsItem = null;
// Get the NMS version of the compound
Object handle = compound != null ? NbtFactory.fromBase(compound).getHandle() : null;
if (MinecraftReflection.isUsingNetty()) { if (MinecraftReflection.isUsingNetty()) {
if (WRITE_NBT_METHOD == null) { if (READ_ITEM_METHOD == null) {
WRITE_NBT_METHOD = Accessors.getMethodAccessor( READ_ITEM_METHOD = Accessors.getMethodAccessor(
FuzzyReflection.fromClass(MinecraftReflection.getPacketDataSerializerClass(), true). FuzzyReflection.fromClass(MinecraftReflection.getPacketDataSerializerClass(), true).
getMethodByParameters("writeNbtCompound", /* a */ getMethodByParameters("readItemStack", /* i */
MinecraftReflection.getNBTCompoundClass()) MinecraftReflection.getItemStackClass(), new Class<?>[0])
); );
} }
WrappedByteBuf buf = Netty.packetWriter(output); byte[] bytes = new byte[8192];
buf.writeByte(NbtType.TAG_COMPOUND.getRawID()); input.read(bytes);
WRITE_NBT_METHOD.invoke(buf.getHandle(), handle); WrappedByteBuf buf = Netty.copiedBuffer(bytes);
Object serializer = MinecraftReflection.getPacketDataSerializer(buf.getHandle());
nmsItem = READ_ITEM_METHOD.invoke(serializer);
} else { } else {
if (WRITE_NBT_METHOD == null) { if (READ_ITEM_METHOD == null) {
WRITE_NBT_METHOD = Accessors.getMethodAccessor( READ_ITEM_METHOD = Accessors.getMethodAccessor(
FuzzyReflection.fromClass(MinecraftReflection.getPacketClass(), true).getMethod(
FuzzyMethodContract.newBuilder().
parameterCount(2).
parameterDerivedOf(MinecraftReflection.getNBTBaseClass(), 0).
parameterDerivedOf(DataOutput.class, 1).
returnTypeVoid().
build())
);
}
WRITE_NBT_METHOD.invoke(null, handle, output);
}
}
/**
* Serialize a string using the standard Minecraft UTF-16 encoding.
* <p>
* Note that strings cannot exceed 32767 characters, regardless if maximum lenght.
* @param output - the output stream.
* @param text - the string to serialize.
* @throws IOException If the data in the string cannot be written.
*/
public void serializeString(@Nonnull DataOutputStream output, String text) throws IOException {
if (output == null)
throw new IllegalArgumentException("output stream cannot be NULL.");
if (text == null)
throw new IllegalArgumentException("text cannot be NULL.");
if (MinecraftReflection.isUsingNetty()) {
if (WRITE_STRING_METHOD == null) {
WRITE_STRING_METHOD = Accessors.getMethodAccessor(
FuzzyReflection.fromClass(MinecraftReflection.getPacketDataSerializerClass(), true).
getMethodByParameters("writeString", /* a */
String.class)
);
}
WRITE_STRING_METHOD.invoke(Netty.packetWriter(output).getHandle(), text);
} else {
if (WRITE_STRING_METHOD == null) {
WRITE_STRING_METHOD = Accessors.getMethodAccessor(
FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()).getMethod( FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()).getMethod(
FuzzyMethodContract.newBuilder(). FuzzyMethodContract.newBuilder().
parameterCount(2). parameterCount(1).
parameterExactType(String.class, 0). parameterDerivedOf(DataInput.class).
parameterDerivedOf(DataOutput.class, 1). returnDerivedOf(MinecraftReflection.getItemStackClass()).
returnTypeVoid().
build()) build())
); );
} }
WRITE_STRING_METHOD.invoke(null, text, output); nmsItem = READ_ITEM_METHOD.invoke(null, input);
}
} }
/** // Convert back to a Bukkit item stack
* Serialize an item stack as a base-64 encoded string. if (nmsItem != null)
* <p> return MinecraftReflection.getBukkitItemStack(nmsItem);
* Note: An ItemStack can be written to the serialized text even if it's NULL. else
* return null;
* @param stack - the item stack to serialize, or NULL to represent air/nothing.
* @return A base-64 representation of the given item stack.
* @throws IOException If the operation fails due to reflection problems.
*/
public String serializeItemStack(ItemStack stack) throws IOException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
DataOutputStream dataOutput = new DataOutputStream(outputStream);
serializeItemStack(dataOutput, stack);
// Serialize that array
return Base64Coder.encodeLines(outputStream.toByteArray());
} }
} }

View File

@ -10,8 +10,11 @@ import java.io.IOException;
import net.minecraft.server.v1_8_R3.IntHashMap; import net.minecraft.server.v1_8_R3.IntHashMap;
import org.bukkit.ChatColor;
import org.bukkit.DyeColor;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -36,18 +39,6 @@ public class StreamSerializerTest {
assertEquals(IntHashMap.class, MinecraftReflection.getIntHashMapClass()); assertEquals(IntHashMap.class, MinecraftReflection.getIntHashMapClass());
} }
@Test
public void testSerializer() throws IOException {
ItemStack before = new ItemStack(Material.GOLD_AXE);
StreamSerializer serializer = new StreamSerializer();
String data = serializer.serializeItemStack(before);
ItemStack after = serializer.deserializeItemStack(data);
assertEquals(before.getType(), after.getType());
assertEquals(before.getAmount(), after.getAmount());
}
@Test @Test
public void testStrings() throws IOException { public void testStrings() throws IOException {
StreamSerializer serializer = new StreamSerializer(); StreamSerializer serializer = new StreamSerializer();
@ -57,8 +48,7 @@ public class StreamSerializerTest {
ByteArrayOutputStream buffer = new ByteArrayOutputStream(); ByteArrayOutputStream buffer = new ByteArrayOutputStream();
serializer.serializeString(new DataOutputStream(buffer), initial); serializer.serializeString(new DataOutputStream(buffer), initial);
DataInputStream input = new DataInputStream( DataInputStream input = new DataInputStream(new ByteArrayInputStream(buffer.toByteArray()));
new ByteArrayInputStream(buffer.toByteArray()));
String deserialized = serializer.deserializeString(input, 50); String deserialized = serializer.deserializeString(input, 50);
assertEquals(initial, deserialized); assertEquals(initial, deserialized);
@ -76,8 +66,7 @@ public class StreamSerializerTest {
ByteArrayOutputStream buffer = new ByteArrayOutputStream(); ByteArrayOutputStream buffer = new ByteArrayOutputStream();
serializer.serializeCompound(new DataOutputStream(buffer), initial); serializer.serializeCompound(new DataOutputStream(buffer), initial);
DataInputStream input = new DataInputStream( DataInputStream input = new DataInputStream(new ByteArrayInputStream(buffer.toByteArray()));
new ByteArrayInputStream(buffer.toByteArray()));
NbtCompound deserialized = serializer.deserializeCompound(input); NbtCompound deserialized = serializer.deserializeCompound(input);
assertEquals(initial, deserialized); assertEquals(initial, deserialized);
@ -88,12 +77,23 @@ public class StreamSerializerTest {
StreamSerializer serializer = new StreamSerializer(); StreamSerializer serializer = new StreamSerializer();
ItemStack initial = new ItemStack(Material.STRING); ItemStack initial = new ItemStack(Material.STRING);
ByteArrayOutputStream buffer = new ByteArrayOutputStream(); String serialized = serializer.serializeItemStack(initial);
serializer.serializeItemStack(new DataOutputStream(buffer), initial); ItemStack deserialized = serializer.deserializeItemStack(serialized);
DataInputStream input = new DataInputStream( assertEquals(initial, deserialized);
new ByteArrayInputStream(buffer.toByteArray())); }
ItemStack deserialized = serializer.deserializeItemStack(input);
@Test
public void testItemMeta() throws IOException {
StreamSerializer serializer = new StreamSerializer();
ItemStack initial = new ItemStack(Material.WOOL, 2, DyeColor.BLUE.getWoolData());
ItemMeta meta = initial.getItemMeta();
meta.setDisplayName(ChatColor.BLUE + "Blue Wool");
initial.setItemMeta(meta);
String serialized = serializer.serializeItemStack(initial);
ItemStack deserialized = serializer.deserializeItemStack(serialized);
assertEquals(initial, deserialized); assertEquals(initial, deserialized);
} }

View File

@ -75,4 +75,9 @@ public class ShadedByteBuf implements WrappedByteBuf {
public void writeBytes(byte[] bytes) { public void writeBytes(byte[] bytes) {
handle.get().writeBytes(bytes); handle.get().writeBytes(bytes);
} }
@Override
public byte[] array() {
return handle.get().array();
}
} }

View File

@ -55,11 +55,6 @@ public class ShadedNetty implements NettyCompat {
} }
} }
@Override
public WrappedByteBuf allocateUnpooled() {
return new ShadedByteBuf(UnpooledByteBufAllocator.DEFAULT.buffer());
}
@Override @Override
public Class<?> getGenericFutureListenerArray() { public Class<?> getGenericFutureListenerArray() {
return GenericFutureListener[].class; return GenericFutureListener[].class;
@ -97,4 +92,14 @@ public class ShadedNetty implements NettyCompat {
public WrappedByteBuf packetWriter(DataOutputStream output) { public WrappedByteBuf packetWriter(DataOutputStream output) {
return new ShadedByteBuf(ShadedByteBufAdapter.packetWriter(output)); return new ShadedByteBuf(ShadedByteBufAdapter.packetWriter(output));
} }
@Override
public WrappedByteBuf copiedBuffer(byte[] array) {
return new ShadedByteBuf(Unpooled.copiedBuffer(array));
}
@Override
public WrappedByteBuf buffer() {
return new ShadedByteBuf(Unpooled.buffer());
}
} }