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.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>
|
||||||
|
@ -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.
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
In neuem Issue referenzieren
Einen Benutzer sperren