Skip to content

Commit

Permalink
Fix serializing and deserializing of ItemStack on 1.21 (#3217)
Browse files Browse the repository at this point in the history
  • Loading branch information
JustRed23 authored Sep 23, 2024
1 parent 7f61537 commit c9ee2f1
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 11 deletions.
62 changes: 53 additions & 9 deletions src/main/java/com/comphenix/protocol/utility/StreamSerializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
import com.comphenix.protocol.injector.netty.NettyByteBufAdapter;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
Expand All @@ -31,6 +33,7 @@ public class StreamSerializer {
private static final StreamSerializer DEFAULT = new StreamSerializer();

// Cached methods
private static FieldAccessor STREAM_CODEC;
private static MethodAccessor READ_ITEM_METHOD;
private static MethodAccessor WRITE_ITEM_METHOD;

Expand Down Expand Up @@ -235,14 +238,35 @@ public ItemStack deserializeItemStackFromByteArray(byte[] input) {
Object serializer = MinecraftReflection.getPacketDataSerializer(buf);

if (READ_ITEM_METHOD == null) {
READ_ITEM_METHOD = Accessors.getMethodAccessor(FuzzyReflection
.fromClass(serializer.getClass(), false)
.getMethodByReturnTypeAndParameters("readItemStack", MinecraftReflection.getItemStackClass()));
if (MinecraftVersion.v1_21_0.atOrAbove()) {
if (STREAM_CODEC == null) {
STREAM_CODEC = Accessors.getFieldAccessor(FuzzyReflection
.fromClass(MinecraftReflection.getItemStackClass())
.getFieldList(FuzzyFieldContract.newBuilder()
.typeExact(MinecraftReflection.getStreamCodecClass())
.build()).get(1)); //skip OPTIONAL_STREAM_CODEC
}

READ_ITEM_METHOD = Accessors.getMethodAccessor(FuzzyReflection.fromObject(STREAM_CODEC.get(null), true)
.getMethod(FuzzyMethodContract.newBuilder()
.parameterExactType(MinecraftReflection.getRegistryFriendlyByteBufClass().get())
.returnTypeExact(MinecraftReflection.getItemStackClass())
.build()));
} else {
READ_ITEM_METHOD = Accessors.getMethodAccessor(FuzzyReflection
.fromClass(serializer.getClass(), false)
.getMethodByReturnTypeAndParameters("readItemStack", MinecraftReflection.getItemStackClass()));
}
}

try {
// unwrap the item
Object nmsItem = READ_ITEM_METHOD.invoke(serializer);
Object nmsItem;
if (MinecraftVersion.v1_21_0.atOrAbove()) {
nmsItem = READ_ITEM_METHOD.invoke(STREAM_CODEC.get(null), serializer);
} else {
nmsItem = READ_ITEM_METHOD.invoke(serializer);
}
return nmsItem != null ? MinecraftReflection.getBukkitItemStack(nmsItem) : null;
} finally {
ReferenceCountUtil.safeRelease(buf);
Expand All @@ -262,19 +286,39 @@ public ItemStack deserializeItemStackFromByteArray(byte[] input) {
* @throws IOException If the operation fails due to reflection problems.
*/
public void serializeItemStack(DataOutputStream output, ItemStack stack) throws IOException {
// TODO this functionality was replaced by the CODEC field in the nms ItemStack
if (WRITE_ITEM_METHOD == null) {
WRITE_ITEM_METHOD = Accessors.getMethodAccessor(FuzzyReflection
.fromClass(MinecraftReflection.getPacketDataSerializerClass(), true)
.getMethodByParameters("writeStack", MinecraftReflection.getItemStackClass()));
if (MinecraftVersion.v1_21_0.atOrAbove()) {
if (STREAM_CODEC == null) {
STREAM_CODEC = Accessors.getFieldAccessor(FuzzyReflection
.fromClass(MinecraftReflection.getItemStackClass())
.getFieldList(FuzzyFieldContract.newBuilder()
.typeExact(MinecraftReflection.getStreamCodecClass())
.build()).get(1)); //skip OPTIONAL_STREAM_CODEC
}

WRITE_ITEM_METHOD = Accessors.getMethodAccessor(FuzzyReflection.fromObject(STREAM_CODEC.get(null), true)
.getMethod(FuzzyMethodContract.newBuilder()
.parameterExactArray(MinecraftReflection.getRegistryFriendlyByteBufClass().get(), MinecraftReflection.getItemStackClass())
.returnTypeExact(void.class)
.build()));
} else {
WRITE_ITEM_METHOD = Accessors.getMethodAccessor(FuzzyReflection
.fromClass(MinecraftReflection.getPacketDataSerializerClass(), true)
.getMethodByParameters("writeStack", MinecraftReflection.getItemStackClass()));
}
}

ByteBuf buf = Unpooled.buffer();
Object serializer = MinecraftReflection.getPacketDataSerializer(buf);

// Get the NMS version of the ItemStack and write it into the buffer
Object nmsItem = MinecraftReflection.getMinecraftItemStack(stack);
WRITE_ITEM_METHOD.invoke(serializer, nmsItem);

if (MinecraftVersion.v1_21_0.atOrAbove()) {
WRITE_ITEM_METHOD.invoke(STREAM_CODEC.get(null), serializer, nmsItem);
} else {
WRITE_ITEM_METHOD.invoke(serializer, nmsItem);
}

// write the serialized content to the stream
output.write(this.getBytesAndRelease(buf));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ public void testCompound() throws IOException {
}

@Test
@Disabled // TODO -- replaced with registry friendly bytebuf
public void testItems() throws IOException {
StreamSerializer serializer = new StreamSerializer();
ItemStack initial = new ItemStack(Material.STRING);
Expand All @@ -72,7 +71,6 @@ public void testItems() throws IOException {
}

@Test
@Disabled // TODO -- replaced with registry friendly bytebuf
public void testItemMeta() throws IOException {
StreamSerializer serializer = new StreamSerializer();
ItemStack initial = new ItemStack(Material.BLUE_WOOL, 2);
Expand Down

0 comments on commit c9ee2f1

Please sign in to comment.