Archiviert
13
0

Added the ability to serialize and deserialize NbtCompounds.

Dieser Commit ist enthalten in:
Kristian S. Stangeland 2013-07-17 20:31:25 +02:00
Ursprung b0cec61d66
Commit aa9d84c639
3 geänderte Dateien mit 98 neuen und 2 gelöschten Zeilen

Datei anzeigen

@ -8,7 +8,6 @@ import java.io.DataOutput;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
@ -16,6 +15,8 @@ import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract; import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
/** /**
* Utility methods for reading and writing Minecraft objects to streams. * Utility methods for reading and writing Minecraft objects to streams.
@ -27,6 +28,9 @@ public class StreamSerializer {
private static Method READ_ITEM_METHOD; private static Method READ_ITEM_METHOD;
private static Method WRITE_ITEM_METHOD; private static Method WRITE_ITEM_METHOD;
private static Method READ_NBT_METHOD;
private static Method WRITE_NBT_METHOD;
private static Method READ_STRING_METHOD; private static Method READ_STRING_METHOD;
private static Method WRITE_STRING_METHOD; private static Method WRITE_STRING_METHOD;
@ -62,13 +66,38 @@ public class StreamSerializer {
} }
} }
/**
* Read or deserialize an NBT compound from a input stream.
* @param input - the target input stream.
* @return The resulting compound, or NULL.
* @throws IOException If the operation failed due to reflection or corrupt data.
*/
public NbtCompound deserializeCompound(@Nonnull DataInputStream input) throws IOException {
if (input == null)
throw new IllegalArgumentException("Input stream cannot be NULL.");
if (READ_NBT_METHOD == null) {
READ_NBT_METHOD = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()).getMethod(
FuzzyMethodContract.newBuilder().
parameterCount(1).
parameterDerivedOf(DataInput.class).
returnDerivedOf(MinecraftReflection.getNBTBaseClass()).
build());
}
try {
// Convert back to an NBT Compound
return NbtFactory.fromNMSCompound(READ_NBT_METHOD.invoke(null, input));
} catch (Exception e) {
throw new IOException("Cannot read item stack.", e);
}
}
/** /**
* Deserialize a string using the standard Minecraft UTF-16 encoding. * Deserialize a string using the standard Minecraft UTF-16 encoding.
* <p> * <p>
* Note that strings cannot exceed 32767 characters, regardless if maximum lenght. * Note that strings cannot exceed 32767 characters, regardless if maximum lenght.
* @param input - the input stream. * @param input - the input stream.
* @param maximumLength - the maximum lenght of the string. * @param maximumLength - the maximum lenght of the string.
* @return * @return The deserialized string.
* @throws IOException * @throws IOException
*/ */
public String deserializeString(@Nonnull DataInputStream input, int maximumLength) throws IOException { public String deserializeString(@Nonnull DataInputStream input, int maximumLength) throws IOException {
@ -144,6 +173,40 @@ public class StreamSerializer {
} }
} }
/**
* Write or serialize a NBT compound to the given output stream.
* <p>
* Note: An NBT compound can be written to a stream even if it's NULL.
*
* @param output - the target output stream.
* @param stack - the NBT compound to be serialized, or NULL to represent nothing.
* @throws IOException If the operation fails due to reflection problems.
*/
public void serializeCompound(@Nonnull DataOutputStream output, NbtCompound compound) throws IOException {
if (output == null)
throw new IllegalArgumentException("Output stream cannot be NULL.");
// Get the NMS version of the compound
Object handle = compound != null ? NbtFactory.fromBase(compound).getHandle() : null;
if (WRITE_NBT_METHOD == null) {
WRITE_NBT_METHOD = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass(), true).getMethod(
FuzzyMethodContract.newBuilder().
parameterCount(2).
parameterDerivedOf(MinecraftReflection.getNBTBaseClass(), 0).
parameterDerivedOf(DataOutput.class, 1).
returnTypeVoid().
build());
WRITE_NBT_METHOD.setAccessible(true);
}
try {
WRITE_NBT_METHOD.invoke(null, handle, output);
} catch (Exception e) {
throw new IOException("Cannot write compound " + compound, e);
}
}
/** /**
* Deserialize a string using the standard Minecraft UTF-16 encoding. * Deserialize a string using the standard Minecraft UTF-16 encoding.
* <p> * <p>

Datei anzeigen

@ -22,6 +22,8 @@ import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.annotation.Nonnull;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import com.comphenix.protocol.reflect.FieldAccessException; import com.comphenix.protocol.reflect.FieldAccessException;
@ -163,6 +165,17 @@ public class NbtFactory {
return partial; return partial;
} }
/**
* Retrieve the NBT compound from a given NMS handle.
* @param handle - the underlying net.minecraft.server object to wrap.
* @return A NBT compound wrapper
*/
public static NbtCompound fromNMSCompound(@Nonnull Object handle) {
if (handle == null)
throw new IllegalArgumentException("handle cannot be NULL.");
return (NbtCompound) NbtFactory.<Map<String, NbtBase<?>>>fromNMS(handle);
}
/** /**
* Constructs a NBT tag of type string. * Constructs a NBT tag of type string.
* @param name - name of the tag. * @param name - name of the tag.

Datei anzeigen

@ -17,6 +17,8 @@ import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.core.classloader.annotations.PrepareForTest;
import com.comphenix.protocol.BukkitInitialization; import com.comphenix.protocol.BukkitInitialization;
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
@RunWith(org.powermock.modules.junit4.PowerMockRunner.class) @RunWith(org.powermock.modules.junit4.PowerMockRunner.class)
@PrepareForTest(CraftItemFactory.class) @PrepareForTest(CraftItemFactory.class)
@ -53,4 +55,22 @@ public class StreamSerializerTest {
assertEquals(initial, deserialized); assertEquals(initial, deserialized);
} }
@Test
public void testCompound() throws IOException {
StreamSerializer serializer = new StreamSerializer();
NbtCompound initial = NbtFactory.ofCompound("tag");
initial.put("name", "Ole");
initial.put("age", 20);
// Buffer
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
serializer.serializeCompound(new DataOutputStream(buffer), initial);
DataInputStream input = new DataInputStream(
new ByteArrayInputStream(buffer.toByteArray()));
NbtCompound deserialized = serializer.deserializeCompound(input);
assertEquals(initial, deserialized);
}
} }