diff --git a/patches/api/Add-Raw-Byte-ItemStack-Serialization.patch b/patches/api/Add-Raw-Byte-ItemStack-Serialization.patch
index d30beb0b77..012bca23dd 100644
--- a/patches/api/Add-Raw-Byte-ItemStack-Serialization.patch
+++ b/patches/api/Add-Raw-Byte-ItemStack-Serialization.patch
@@ -5,6 +5,8 @@ Subject: [PATCH] Add Raw Byte ItemStack Serialization
 
 Serializes using NBT which is safer for server data migrations than bukkits format.
 
+Co-authored-by: Nassim Jahnke <nassim@njahnke.dev>
+
 diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/org/bukkit/UnsafeValues.java
@@ -50,7 +52,126 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    public byte[] serializeAsBytes() {
 +        return org.bukkit.Bukkit.getUnsafe().serializeItem(this);
 +    }
++
++    /**
++     * The current version byte of the item array format used in {@link #serializeItemsAsBytes(java.util.Collection)}
++     * and {@link #deserializeItemsFromBytes(byte[])} respectively.
++     */
++    private static final byte ARRAY_SERIALIZATION_VERSION = 1;
++
++    /**
++     * Serializes a collection of items to raw bytes in NBT. Serializes empty items as null.
++     * <p>
++     * If you need a string representation to put into a file, you can for example use {@link java.util.Base64} encoding.
++     *
++     * @param items items to serialize
++     * @return bytes representing the items in NBT
++     * @see #serializeAsBytes()
++     */
++    public static byte @NotNull [] serializeItemsAsBytes(java.util.@NotNull Collection<ItemStack> items) {
++        try (final java.io.ByteArrayOutputStream outputStream = new java.io.ByteArrayOutputStream()) {
++            final java.io.DataOutput output = new java.io.DataOutputStream(outputStream);
++            output.writeByte(ARRAY_SERIALIZATION_VERSION);
++            output.writeInt(items.size());
++            for (final ItemStack item : items) {
++                if (item == null || item.isEmpty()) {
++                    // Ensure the correct order by including empty/null items
++                    output.writeInt(0);
++                    continue;
++                }
++
++                final byte[] itemBytes = item.serializeAsBytes();
++                output.writeInt(itemBytes.length);
++                output.write(itemBytes);
++            }
++            return outputStream.toByteArray();
++        } catch (final java.io.IOException e) {
++            throw new RuntimeException("Error while writing itemstack", e);
++        }
++    }
++
++    /**
++     * Serializes a collection of items to raw bytes in NBT. Serializes empty items as null.
++     * <p>
++     * If you need a string representation to put into a file, you can for example use {@link java.util.Base64} encoding.
++     *
++     * @param items items to serialize
++     * @return bytes representing the items in NBT
++     * @see #serializeAsBytes()
++     */
++    public static byte @NotNull [] serializeItemsAsBytes(@Nullable ItemStack @NotNull [] items) {
++        return serializeItemsAsBytes(java.util.Arrays.asList(items));
++    }
++
++    /**
++     * Deserializes this itemstack from raw NBT bytes.
++     * <p>
++     * If you need a string representation to put into a file, you can for example use {@link java.util.Base64} encoding.
++     *
++     * @param bytes bytes representing an item in NBT
++     * @return ItemStack array migrated to this version of Minecraft if needed
++     * @see #deserializeBytes(byte[])
++     */
++    public static @NotNull ItemStack @NotNull [] deserializeItemsFromBytes(final byte @NotNull [] bytes) {
++        try (final java.io.ByteArrayInputStream inputStream = new java.io.ByteArrayInputStream(bytes)) {
++            final java.io.DataInputStream input = new java.io.DataInputStream(inputStream);
++            final byte version = input.readByte();
++            if (version != ARRAY_SERIALIZATION_VERSION) {
++                throw new IllegalArgumentException("Unsupported version or bad data: " + version);
++            }
++
++            final int count = input.readInt();
++            final ItemStack[] items = new ItemStack[count];
++            for (int i = 0; i < count; i++) {
++                final int length = input.readInt();
++                if (length == 0) {
++                    // Empty item, keep entry as empty
++                    items[i] = ItemStack.empty();
++                    continue;
++                }
++
++                final byte[] itemBytes = new byte[length];
++                input.read(itemBytes);
++                items[i] = ItemStack.deserializeBytes(itemBytes);
++            }
++            return items;
++        } catch (final java.io.IOException e) {
++            throw new RuntimeException("Error while reading itemstack", e);
++        }
++    }
 +
      /**
       * Gets the Display name as seen in the Client.
       * Currently the server only supports the English language. To override this,
+diff --git a/src/main/java/org/bukkit/util/io/BukkitObjectInputStream.java b/src/main/java/org/bukkit/util/io/BukkitObjectInputStream.java
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/src/main/java/org/bukkit/util/io/BukkitObjectInputStream.java
++++ b/src/main/java/org/bukkit/util/io/BukkitObjectInputStream.java
+@@ -0,0 +0,0 @@ import org.bukkit.configuration.serialization.ConfigurationSerialization;
+  * <p>
+  * Behavior of implementations extending this class is not guaranteed across
+  * future versions.
++ * @deprecated Object streams on their own are not safe. For safer and more consistent serialization of items,
++ * use {@link org.bukkit.inventory.ItemStack#serializeAsBytes()} or
++ * {@link org.bukkit.inventory.ItemStack#serializeItemsAsBytes(java.util.Collection)}.
+  */
++@Deprecated(since = "1.21") // Paper
+ public class BukkitObjectInputStream extends ObjectInputStream {
+ 
+     /**
+diff --git a/src/main/java/org/bukkit/util/io/BukkitObjectOutputStream.java b/src/main/java/org/bukkit/util/io/BukkitObjectOutputStream.java
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/src/main/java/org/bukkit/util/io/BukkitObjectOutputStream.java
++++ b/src/main/java/org/bukkit/util/io/BukkitObjectOutputStream.java
+@@ -0,0 +0,0 @@ import org.bukkit.configuration.serialization.ConfigurationSerializable;
+  * <p>
+  * Behavior of implementations extending this class is not guaranteed across
+  * future versions.
++ * @deprecated Object streams on their own are not safe. For safer and more consistent serialization of items,
++ * use {@link org.bukkit.inventory.ItemStack#serializeAsBytes()} or
++ * {@link org.bukkit.inventory.ItemStack#serializeItemsAsBytes(java.util.Collection)}.
+  */
++@Deprecated(since = "1.21") // Paper
+ public class BukkitObjectOutputStream extends ObjectOutputStream {
+ 
+     /**