Added the ability to serialize and deserialize NbtCompounds.
Dieser Commit ist enthalten in:
Ursprung
b0cec61d66
Commit
aa9d84c639
@ -8,7 +8,6 @@ import java.io.DataOutput;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
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.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.
|
||||
@ -27,6 +28,9 @@ public class StreamSerializer {
|
||||
private static Method READ_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 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.
|
||||
* <p>
|
||||
* Note that strings cannot exceed 32767 characters, regardless if maximum lenght.
|
||||
* @param input - the input stream.
|
||||
* @param maximumLength - the maximum lenght of the string.
|
||||
* @return
|
||||
* @return The deserialized string.
|
||||
* @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.
|
||||
* <p>
|
||||
|
@ -22,6 +22,8 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||
@ -163,6 +165,17 @@ public class NbtFactory {
|
||||
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.
|
||||
* @param name - name of the tag.
|
||||
|
@ -17,6 +17,8 @@ import org.junit.runner.RunWith;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
|
||||
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)
|
||||
@PrepareForTest(CraftItemFactory.class)
|
||||
@ -53,4 +55,22 @@ public class StreamSerializerTest {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
In neuem Issue referenzieren
Einen Benutzer sperren