Archiviert
13
0

Fix AttributeSnapshot, rewrite ItemStack handling, add more tests

Fixes #85
Dieser Commit ist enthalten in:
Dan Mulloy 2015-06-02 14:57:30 -04:00
Ursprung a718cc9067
Commit 20247747b5
9 geänderte Dateien mit 145 neuen und 287 gelöschten Zeilen

Datei anzeigen

@ -21,14 +21,16 @@ import io.netty.buffer.ByteBuf;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@ -40,10 +42,6 @@ import java.util.regex.Pattern;
import javax.annotation.Nonnull;
import net.sf.cglib.asm.ClassReader;
import net.sf.cglib.asm.MethodVisitor;
import net.sf.cglib.asm.Opcodes;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.inventory.ItemStack;
@ -59,8 +57,6 @@ import com.comphenix.protocol.reflect.ClassAnalyser.AsmMethod;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
import com.comphenix.protocol.reflect.compiler.EmptyClassVisitor;
import com.comphenix.protocol.reflect.compiler.EmptyMethodVisitor;
import com.comphenix.protocol.reflect.fuzzy.AbstractFuzzyMatcher;
import com.comphenix.protocol.reflect.fuzzy.FuzzyClassContract;
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
@ -127,19 +123,9 @@ public class MinecraftReflection {
static CachedPackage craftbukkitPackage;
static CachedPackage libraryPackage;
// org.bukkit.craftbukkit
private static Constructor<?> craftNMSConstructor;
private static Constructor<?> craftBukkitConstructor;
// Matches classes
private static AbstractFuzzyMatcher<Class<?>> fuzzyMatcher;
// New in 1.4.5
private static Method craftNMSMethod;
private static Method craftBukkitNMS;
private static Method craftBukkitOBC;
private static boolean craftItemStackFailed;
// The NMS version
private static String packageVersion;
@ -783,7 +769,7 @@ public class MinecraftReflection {
*/
public static Class<?> getChatSerializerClass() {
try {
return getMinecraftClass("IChatBaseComponent$ChatSerializer", "ChatSerializer");
return getMinecraftClass("ChatSerializer", "IChatBaseComponent$ChatSerializer");
} catch (RuntimeException e) {
// TODO: Figure out a functional fallback
throw new IllegalStateException("Could not find ChatSerializer class.", e);
@ -825,18 +811,10 @@ public class MinecraftReflection {
throw new IllegalStateException("ServerPingServerData is only supported in 1.7.2.");
try {
return getMinecraftClass("ServerPing$ServerData", "ServerPingServerData");
return getMinecraftClass("ServerPingServerData", "ServerPing$ServerData");
} catch (RuntimeException e) {
Class<?> serverPing = getServerPingClass();
for (Field field : FuzzyReflection.fromClass(serverPing, true).getFields()) {
Class<?> clazz = field.getType();
if (clazz.getName().contains("ServerData")) {
return setMinecraftClass("ServerData", clazz);
}
}
throw new IllegalStateException("Could not find ServerData class.");
FuzzyReflection fuzzy = FuzzyReflection.fromClass(getServerPingClass(), true);
return setMinecraftClass("ServerPingServerData", fuzzy.getFieldByType("(.*)(ServerData)(.*)").getType());
}
}
@ -849,7 +827,7 @@ public class MinecraftReflection {
throw new IllegalStateException("ServerPingPlayerSample is only supported in 1.7.2.");
try {
return getMinecraftClass("ServerPing$ServerPingPlayerSample", "ServerPingPlayerSample");
return getMinecraftClass("ServerPingPlayerSample", "ServerPing$ServerPingPlayerSample");
} catch (RuntimeException e) {
Class<?> serverPing = getServerPingClass();
@ -1281,7 +1259,7 @@ public class MinecraftReflection {
*/
public static Class<?> getWatchableObjectClass() {
try {
return getMinecraftClass("DataWatcher$WatchableObject", "WatchableObject");
return getMinecraftClass("WatchableObject", "DataWatcher$WatchableObject");
} catch (RuntimeException e) {
Method selected = FuzzyReflection.fromClass(getDataWatcherClass(), true).
getMethod(FuzzyMethodContract.newBuilder().
@ -1498,46 +1476,17 @@ public class MinecraftReflection {
*/
public static Class<?> getAttributeSnapshotClass() {
try {
return getMinecraftClass("PacketPlayOutUpdateAttributes$AttributeSnapshot", "AttributeSnapshot");
} catch (RuntimeException e) {
final Class<?> packetUpdateAttributes = PacketRegistry.getPacketClassFromType(PacketType.Play.Server.UPDATE_ATTRIBUTES, true);
final String packetSignature = packetUpdateAttributes.getCanonicalName().replace('.', '/');
// HACK - class is found by inspecting code
return getMinecraftClass("AttributeSnapshot", "PacketPlayOutUpdateAttributes$AttributeSnapshot");
} catch (RuntimeException ex) {
try {
ClassReader reader = new ClassReader(packetUpdateAttributes.getCanonicalName());
reader.accept(new EmptyClassVisitor() {
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
// The read method
if (desc.startsWith("(Ljava/io/DataInput")) {
return new EmptyMethodVisitor() {
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
if (opcode == Opcodes.INVOKESPECIAL && isConstructor(name)) {
String className = owner.replace('/', '.');
// Use signature to distinguish between constructors
if (desc.startsWith("(L" + packetSignature)) {
setMinecraftClass("AttributeSnapshot", MinecraftReflection.getClass(className));
} else if (desc.startsWith("(Ljava/util/UUID;Ljava/lang/String")) {
setMinecraftClass("AttributeModifier", MinecraftReflection.getClass(className));
}
}
};
};
}
return null;
}
}, 0);
} catch (IOException e1) {
throw new RuntimeException("Unable to read the content of Packet44UpdateAttributes.", e1);
// It should be the parameter of a list in the update attributes packet
FuzzyReflection fuzzy = FuzzyReflection.fromClass(PacketType.Play.Server.UPDATE_ATTRIBUTES.getPacketClass(), true);
Field field = fuzzy.getFieldByType("attributes", Collection.class);
Type param = ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0];
return setMinecraftClass("AttributeSnapshot", (Class<?>) param);
} catch (Throwable ex1) {
return getMinecraftClass("AttributeSnapshot");
}
// If our dirty ASM trick failed, this will throw an exception
return getMinecraftClass("AttributeSnapshot");
}
}
@ -1700,15 +1649,6 @@ public class MinecraftReflection {
}
}
/**
* Determine if a given method retrieved by ASM is a constructor.
* @param name - the name of the method.
* @return TRUE if it is, FALSE otherwise.
*/
private static boolean isConstructor(String name) {
return "<init>".equals(name);
}
/**
* Retrieve the ItemStack[] class.
* @return The ItemStack[] class.
@ -1769,134 +1709,6 @@ public class MinecraftReflection {
return getCraftBukkitClass("util.CraftChatMessage");
}
/**
* Retrieve a CraftItemStack from a given ItemStack.
* @param bukkitItemStack - the Bukkit ItemStack to convert.
* @return A CraftItemStack as an ItemStack.
*/
public static ItemStack getBukkitItemStack(ItemStack bukkitItemStack) {
// Delegate this task to the method that can execute it
if (craftBukkitNMS != null)
return getBukkitItemByMethod(bukkitItemStack);
if (craftBukkitConstructor == null) {
try {
craftBukkitConstructor = getCraftItemStackClass().getConstructor(ItemStack.class);
} catch (Exception e) {
// See if this method works
if (!craftItemStackFailed)
return getBukkitItemByMethod(bukkitItemStack);
throw new RuntimeException("Cannot find CraftItemStack(org.bukkit.inventory.ItemStack).", e);
}
}
// Try to create the CraftItemStack
try {
return (ItemStack) craftBukkitConstructor.newInstance(bukkitItemStack);
} catch (Exception e) {
throw new RuntimeException("Cannot construct CraftItemStack.", e);
}
}
private static ItemStack getBukkitItemByMethod(ItemStack bukkitItemStack) {
if (craftBukkitNMS == null) {
try {
craftBukkitNMS = getCraftItemStackClass().getMethod("asNMSCopy", ItemStack.class);
craftBukkitOBC = getCraftItemStackClass().getMethod("asCraftMirror", MinecraftReflection.getItemStackClass());
} catch (Exception e) {
craftItemStackFailed = true;
throw new RuntimeException("Cannot find CraftItemStack.asCraftCopy(org.bukkit.inventory.ItemStack).", e);
}
}
// Next, construct it
try {
Object nmsItemStack = craftBukkitNMS.invoke(null, bukkitItemStack);
return (ItemStack) craftBukkitOBC.invoke(null, nmsItemStack);
} catch (Exception e) {
throw new RuntimeException("Cannot construct CraftItemStack.", e);
}
}
/**
* Retrieve the Bukkit ItemStack from a given net.minecraft.server ItemStack.
* @param minecraftItemStack - the NMS ItemStack to wrap.
* @return The wrapped ItemStack.
*/
public static ItemStack getBukkitItemStack(Object minecraftItemStack) {
// Delegate this task to the method that can execute it
if (craftNMSMethod != null)
return getBukkitItemByMethod(minecraftItemStack);
if (craftNMSConstructor == null) {
try {
craftNMSConstructor = getCraftItemStackClass().getConstructor(minecraftItemStack.getClass());
} catch (Exception e) {
// Give it a try
if (!craftItemStackFailed)
return getBukkitItemByMethod(minecraftItemStack);
throw new RuntimeException("Cannot find CraftItemStack(net.minecraft.server.ItemStack).", e);
}
}
// Try to create the CraftItemStack
try {
return (ItemStack) craftNMSConstructor.newInstance(minecraftItemStack);
} catch (Exception e) {
throw new RuntimeException("Cannot construct CraftItemStack.", e);
}
}
private static ItemStack getBukkitItemByMethod(Object minecraftItemStack) {
if (craftNMSMethod == null) {
try {
craftNMSMethod = getCraftItemStackClass().getMethod("asCraftMirror", minecraftItemStack.getClass());
} catch (Exception e) {
craftItemStackFailed = true;
throw new RuntimeException("Cannot find CraftItemStack.asCraftMirror(net.minecraft.server.ItemStack).", e);
}
}
// Next, construct it
try {
return (ItemStack) craftNMSMethod.invoke(null, minecraftItemStack);
} catch (Exception e) {
throw new RuntimeException("Cannot construct CraftItemStack.", e);
}
}
/**
* Retrieve the net.minecraft.server ItemStack from a Bukkit ItemStack.
* <p>
* By convention, item stacks that contain air are usually represented as NULL.
* @param stack - the Bukkit ItemStack to convert.
* @return The NMS ItemStack, or NULL if the stack represents air.
*/
public static Object getMinecraftItemStack(ItemStack stack) {
// Make sure this is a CraftItemStack
/* if (!isCraftItemStack(stack))
stack = getBukkitItemStack(stack);
BukkitUnwrapper unwrapper = new BukkitUnwrapper();
return unwrapper.unwrapItem(stack); */
if (craftBukkitNMS == null) {
try {
craftBukkitNMS = getCraftItemStackClass().getMethod("asNMSCopy", ItemStack.class);
} catch (Throwable ex) {
throw new RuntimeException("Could not find CraftItemStack.asNMSCopy.", ex);
}
}
try {
return craftBukkitNMS.invoke(null, stack);
} catch (Throwable ex) {
throw new RuntimeException("Could not obtain NMS ItemStack.", ex);
}
}
/**
* Retrieve the PlayerInfoData class in 1.8.
* @return The PlayerInfoData class
@ -1939,6 +1751,35 @@ public class MinecraftReflection {
return getArrayClass(getMultiBlockChangeInfoClass());
}
private static MethodAccessor asCraftMirror;
private static MethodAccessor asNMSCopy;
/**
* Retrieve a CraftItemStack from a given ItemStack.
* @param bukkitItemStack - the Bukkit ItemStack to convert.
* @return A CraftItemStack as an ItemStack.
*/
public static ItemStack getBukkitItemStack(Object nmsItem) {
if (asCraftMirror == null) {
asCraftMirror = Accessors.getMethodAccessor(getCraftItemStackClass(), "asCraftMirror", getItemStackClass());
}
return (ItemStack) asCraftMirror.invoke(null, nmsItem);
}
/**
* Retrieve the Bukkit ItemStack from a given net.minecraft.server ItemStack.
* @param minecraftItemStack - the NMS ItemStack to wrap.
* @return The wrapped ItemStack.
*/
public static Object getMinecraftItemStack(ItemStack stack) {
if (asNMSCopy == null) {
asNMSCopy = Accessors.getMethodAccessor(getCraftItemStackClass(), "asNMSCopy", ItemStack.class);
}
return asNMSCopy.invoke(null, stack);
}
/**
* Retrieve the given class by name.
* @param className - name of the class.
@ -2065,4 +1906,4 @@ public class MinecraftReflection {
public static String getNetLoginHandlerName() {
return getNetLoginHandlerClass().getSimpleName();
}
}
}

Datei anzeigen

@ -1,7 +1,7 @@
package com.comphenix.protocol;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.junit.Assert.assertFalse;
import java.util.Map;
import java.util.Map.Entry;
@ -33,9 +33,7 @@ public class PacketTypeTest {
PacketType type = entry.getKey();
Class<?> clazz = entry.getValue();
if (type.isDynamic()) {
fail("Packet " + clazz + " does not have a corresponding PacketType!");
}
assertFalse("Packet " + clazz + " does not have a corresponding PacketType!", type.isDynamic());
}
}
}

Datei anzeigen

@ -24,10 +24,14 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.List;
import java.util.UUID;
import net.minecraft.server.v1_8_R3.AttributeModifier;
import net.minecraft.server.v1_8_R3.MobEffect;
import net.minecraft.server.v1_8_R3.PacketPlayOutUpdateAttributes;
import net.minecraft.server.v1_8_R3.PacketPlayOutUpdateAttributes.AttributeSnapshot;
import org.apache.commons.lang.SerializationUtils;
import org.bukkit.ChatColor;
@ -368,8 +372,7 @@ public class PacketContainerTest {
assertEquals("Test", copy.getStrings().read(0));
}
// TODO Deal with inner classes
/* @Test
@Test
public void testAttributeList() {
PacketContainer attribute = new PacketContainer(PacketType.Play.Server.UPDATE_ATTRIBUTES);
attribute.getIntegers().write(0, 123); // Entity ID
@ -378,26 +381,33 @@ public class PacketContainerTest {
List<AttributeModifier> modifiers = Lists.newArrayList(
new AttributeModifier(UUID.randomUUID(), "Unknown synced attribute modifier", 10, 0));
// TODO This is hopefully just a temporary solution,
// but situations like this might be issues elsewhere
class PacketAccessor extends PacketPlayOutUpdateAttributes {
public AttributeSnapshot attributeSnapshot(String string, double d, Collection<AttributeModifier> coll) {
return new AttributeSnapshot(string, d, coll);
}
};
AttributeSnapshot snapshot = new PacketAccessor().attributeSnapshot("generic.Maxhealth", 20.0, modifiers);
// Obtain an AttributeSnapshot instance. This is complicated by the fact that AttributeSnapshots
// are inner classes (which is ultimately pointless because AttributeSnapshots don't access any
// members of the packet itself)
PacketPlayOutUpdateAttributes packet = (PacketPlayOutUpdateAttributes) attribute.getHandle();
AttributeSnapshot snapshot = packet.new AttributeSnapshot("generic.Maxhealth", 20.0D, modifiers);
attribute.getSpecificModifier(List.class).write(0, Lists.newArrayList(snapshot));
PacketContainer cloned = attribute.deepClone();
AttributeSnapshot clonedSnapshot = (AttributeSnapshot) cloned.getSpecificModifier(List.class).read(0).get(0);
assertEquals(
ToStringBuilder.reflectionToString(snapshot, ToStringStyle.SHORT_PREFIX_STYLE),
ToStringBuilder.reflectionToString(clonedSnapshot, ToStringStyle.SHORT_PREFIX_STYLE));
} */
// Compare the fields, because apparently the packet is a field in AttributeSnapshot
for (Field field : AttributeSnapshot.class.getDeclaredFields()) {
try {
// Skip the packet
if (field.getType().equals(packet.getClass())) {
continue;
}
field.setAccessible(true);
assertEquals(field.get(snapshot), field.get(clonedSnapshot));
} catch (AssertionError e) {
throw e;
} catch (Throwable ex) {
ex.printStackTrace();
}
}
}
@Test
public void testBlocks() {

Datei anzeigen

@ -1,6 +1,9 @@
package com.comphenix.protocol.utility;
import static org.junit.Assert.assertNotNull;
import org.junit.BeforeClass;
import org.junit.Test;
import com.comphenix.protocol.BukkitInitialization;
@ -10,8 +13,8 @@ public class MinecraftMethodsTest {
BukkitInitialization.initializePackage();
}
// @Test
// public void testSendPacketMethod() {
// assertNotNull(MinecraftMethods.getSendPacketMethod());
// }
@Test
public void testSendPacketMethod() {
assertNotNull(MinecraftMethods.getSendPacketMethod());
}
}

Datei anzeigen

@ -10,12 +10,15 @@ import net.minecraft.server.v1_8_R3.DataWatcher.WatchableObject;
import net.minecraft.server.v1_8_R3.IChatBaseComponent;
import net.minecraft.server.v1_8_R3.IChatBaseComponent.ChatSerializer;
import net.minecraft.server.v1_8_R3.NBTCompressedStreamTools;
import net.minecraft.server.v1_8_R3.PacketPlayOutUpdateAttributes.AttributeSnapshot;
import net.minecraft.server.v1_8_R3.ServerPing;
import net.minecraft.server.v1_8_R3.ServerPing.ServerData;
import net.minecraft.server.v1_8_R3.ServerPing.ServerPingPlayerSample;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.inventory.ItemStack;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
@ -67,8 +70,8 @@ public class MinecraftReflectionTest {
}
@Test
public void testNbtStreamTools() {
assertEquals(NBTCompressedStreamTools.class, MinecraftReflection.getNbtCompressedStreamToolsClass());
public void testAttributeSnapshot() {
assertEquals(AttributeSnapshot.class, MinecraftReflection.getAttributeSnapshotClass());
}
@Test
@ -86,6 +89,11 @@ public class MinecraftReflectionTest {
assertEquals(ChatSerializer.class, MinecraftReflection.getChatSerializerClass());
}
@Test
public void testChunkCoordIntPair() {
assertEquals(ChunkCoordIntPair.class, MinecraftReflection.getChunkCoordIntPair());
}
@Test
public void testServerPing() {
assertEquals(ServerPing.class, MinecraftReflection.getServerPingClass());
@ -102,12 +110,19 @@ public class MinecraftReflectionTest {
}
@Test
public void testChunkCoordIntPair() {
assertEquals(ChunkCoordIntPair.class, MinecraftReflection.getChunkCoordIntPair());
public void testNbtStreamTools() {
assertEquals(NBTCompressedStreamTools.class, MinecraftReflection.getNbtCompressedStreamToolsClass());
}
@Test
public void testWatchableObject() {
assertEquals(WatchableObject.class, MinecraftReflection.getWatchableObjectClass());
}
}
@Test
public void testItemStacks() {
ItemStack stack = new ItemStack(Material.GOLD_SWORD);
Object nmsStack = MinecraftReflection.getMinecraftItemStack(stack);
assertEquals(stack, MinecraftReflection.getBukkitItemStack(nmsStack));
}
}

Datei anzeigen

@ -61,7 +61,9 @@ public class StreamSerializerTest {
assertEquals(initial, deserialized);
}
// TODO This is an actual issue
// TODO This is an actual issue, probably need to fix the NBT API
// For future reference, items are saved in the ChunkRegionLoader and TileEntityChest
/* @Test
public void testCompound() throws IOException {
StreamSerializer serializer = new StreamSerializer();
@ -79,4 +81,4 @@ public class StreamSerializerTest {
assertEquals(initial, deserialized);
} */
}
}

Datei anzeigen

@ -1,22 +0,0 @@
package com.comphenix.protocol.wrappers;
import org.junit.BeforeClass;
import com.comphenix.protocol.BukkitInitialization;
public class WrappedChunkCoordinateTest {
@BeforeClass
public static void initializeBukkit() throws IllegalAccessException {
BukkitInitialization.initializePackage();
}
/* ChunkCoordinates don't exist anymore
@Test
public void test() {
WrappedChunkCoordinate coordinate = new WrappedChunkCoordinate(1, 2, 3);
assertEquals(1, coordinate.getX());
assertEquals(2, coordinate.getY());
assertEquals(3, coordinate.getZ());
} */
}

Datei anzeigen

@ -1,8 +1,17 @@
package com.comphenix.protocol.wrappers;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import org.junit.BeforeClass;
import org.junit.Test;
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
import com.comphenix.protocol.BukkitInitialization;
import com.comphenix.protocol.wrappers.WrappedServerPing.CompressedImage;
import com.google.common.io.Resources;
public class WrappedServerPingTest {
@BeforeClass
@ -10,28 +19,28 @@ public class WrappedServerPingTest {
BukkitInitialization.initializePackage();
}
// @Test
// public void test() throws IOException {
// CompressedImage tux = CompressedImage.fromPng(Resources.getResource("tux.png").openStream());
// byte[] original = tux.getDataCopy();
//
// WrappedServerPing serverPing = new WrappedServerPing();
// serverPing.setMotD("Hello, this is a test.");
// serverPing.setPlayersOnline(5);
// serverPing.setPlayersMaximum(10);
// serverPing.setVersionName("Minecraft 123");
// serverPing.setVersionProtocol(4);
// serverPing.setFavicon(tux);
//
// assertEquals(5, serverPing.getPlayersOnline());
// assertEquals(10, serverPing.getPlayersMaximum());
// assertEquals("Minecraft 123", serverPing.getVersionName());
// assertEquals(4, serverPing.getVersionProtocol());
//
// assertArrayEquals(original, serverPing.getFavicon().getData());
//
// CompressedImage copy = CompressedImage.fromBase64Png(Base64Coder.encodeLines(tux.getData()));
// assertArrayEquals(copy.getData(), serverPing.getFavicon().getData());
// }
@Test
public void test() throws IOException {
CompressedImage tux = CompressedImage.fromPng(Resources.getResource("tux.png").openStream());
byte[] original = tux.getDataCopy();
WrappedServerPing serverPing = new WrappedServerPing();
serverPing.setMotD("Hello, this is a test.");
serverPing.setPlayersOnline(5);
serverPing.setPlayersMaximum(10);
serverPing.setVersionName("Minecraft 123");
serverPing.setVersionProtocol(4);
serverPing.setFavicon(tux);
assertEquals(5, serverPing.getPlayersOnline());
assertEquals(10, serverPing.getPlayersMaximum());
assertEquals("Minecraft 123", serverPing.getVersionName());
assertEquals(4, serverPing.getVersionProtocol());
assertArrayEquals(original, serverPing.getFavicon().getData());
CompressedImage copy = CompressedImage.fromBase64Png(Base64Coder.encodeLines(tux.getData()));
assertArrayEquals(copy.getData(), serverPing.getFavicon().getData());
}
}

Datei anzeigen

@ -64,11 +64,13 @@ public class NbtFactoryTest {
assertEquals(compound.getInteger("age"), cloned.getInteger("age"));
assertEquals(compound.getList("nicknames"), cloned.getList("nicknames"));
}
// TODO See StreamSerializerTest
/* @Test
public void testItemTag() {
ItemStack test = new ItemStack(Material.GOLD_AXE);
ItemStack craftTest = MinecraftReflection.getBukkitItemStack(test);
ItemStack test = new ItemStack(Items.GOLDEN_AXE);
org.bukkit.inventory.ItemStack craftTest = MinecraftReflection.getBukkitItemStack(test);
NbtCompound compound = NbtFactory.ofCompound("tag");
compound.put("name", "Test Testerson");