aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJake Potrebic <[email protected]>2024-06-03 12:00:45 -0700
committerOwen1212055 <[email protected]>2024-11-18 14:50:37 -0500
commita9a35ffe103cb3a428806e47522e10e12833fc3b (patch)
treec593a8e82d9c30fe68f4877976a0e2d32afcffc1
parente5de01bcf034af1902f9f8cdfa6e14813d81daba (diff)
downloadPaper-a9a35ffe103cb3a428806e47522e10e12833fc3b.tar.gz
Paper-a9a35ffe103cb3a428806e47522e10e12833fc3b.zip
remove map types
-rw-r--r--patches/api/0485-WIP-DataComponent-API.patch (renamed from patches/api/0484-WIP-DataComponent-API.patch)505
-rw-r--r--patches/server/1054-WIP-DataComponent-API.patch (renamed from patches/server/1053-WIP-DataComponent-API.patch)414
2 files changed, 237 insertions, 682 deletions
diff --git a/patches/api/0484-WIP-DataComponent-API.patch b/patches/api/0485-WIP-DataComponent-API.patch
index 365da8d9ac..11143445af 100644
--- a/patches/api/0484-WIP-DataComponent-API.patch
+++ b/patches/api/0485-WIP-DataComponent-API.patch
@@ -914,176 +914,6 @@ index 0000000000000000000000000000000000000000..36e48ef697c001fff1697542eae6f79b
+
+ }
+}
-diff --git a/src/main/java/io/papermc/paper/component/map/DataComponentMap.java b/src/main/java/io/papermc/paper/component/map/DataComponentMap.java
-new file mode 100644
-index 0000000000000000000000000000000000000000..98d3c3b32557b54c1836a8649fa4312a93f49fc0
---- /dev/null
-+++ b/src/main/java/io/papermc/paper/component/map/DataComponentMap.java
-@@ -0,0 +1,31 @@
-+package io.papermc.paper.component.map;
-+
-+import io.papermc.paper.component.DataComponentType;
-+import org.checkerframework.checker.nullness.qual.NonNull;
-+import org.checkerframework.checker.nullness.qual.Nullable;
-+import org.jetbrains.annotations.Contract;
-+import org.jetbrains.annotations.Unmodifiable;
-+import java.util.Set;
-+
-+public interface DataComponentMap {
-+
-+ @Contract(value = "-> new", pure = true)
-+ static @NonNull DataComponentMap empty() {
-+ return DataComponentPatchMapBridge.Holder.bridge().empty();
-+ }
-+
-+ @Contract(pure = true)
-+ <T> @Nullable T get(DataComponentType.@NonNull Valued<T> type);
-+
-+ @Contract(value = "_, !null -> !null", pure = true)
-+ default <T> @Nullable T getOrDefault(final DataComponentType.@NonNull Valued<? extends T> type, final @Nullable T fallback) {
-+ final T object = this.get(type);
-+ return object != null ? object : fallback;
-+ }
-+
-+ @Contract(pure = true)
-+ boolean has(@NonNull DataComponentType type);
-+
-+ @NonNull @Unmodifiable Set<DataComponentType> keySet();
-+
-+}
-diff --git a/src/main/java/io/papermc/paper/component/map/DataComponentPatchMapBridge.java b/src/main/java/io/papermc/paper/component/map/DataComponentPatchMapBridge.java
-new file mode 100644
-index 0000000000000000000000000000000000000000..c4b4f7d5d3c02d94733f78b3d15a7d8703db4d88
---- /dev/null
-+++ b/src/main/java/io/papermc/paper/component/map/DataComponentPatchMapBridge.java
-@@ -0,0 +1,30 @@
-+package io.papermc.paper.component.map;
-+
-+import java.util.Optional;
-+import net.kyori.adventure.util.Services;
-+import org.bukkit.Material;
-+import org.bukkit.inventory.meta.ItemMeta;
-+import org.jetbrains.annotations.ApiStatus;
-+
-+public interface DataComponentPatchMapBridge {
-+
-+ PatchedDataComponentMap of(DataComponentMap map);
-+
-+ DataComponentMap empty();
-+
-+ DataComponentMap fromItem(Material material);
-+
-+ PatchedDataComponentMap fromItemAndMeta(Material material, ItemMeta meta);
-+
-+ ItemMeta toItemMeta(Material material, PatchedDataComponentMap map);
-+
-+ @ApiStatus.Internal
-+ final class Holder {
-+ private static final Optional<DataComponentPatchMapBridge> BRIDGE = Services.service(DataComponentPatchMapBridge.class);
-+
-+ public static DataComponentPatchMapBridge bridge() {
-+ return BRIDGE.orElseThrow();
-+ }
-+ }
-+}
-diff --git a/src/main/java/io/papermc/paper/component/map/PatchedDataComponentMap.java b/src/main/java/io/papermc/paper/component/map/PatchedDataComponentMap.java
-new file mode 100644
-index 0000000000000000000000000000000000000000..d284fbb11beea9d18e297605b01e30796e60e3b1
---- /dev/null
-+++ b/src/main/java/io/papermc/paper/component/map/PatchedDataComponentMap.java
-@@ -0,0 +1,51 @@
-+package io.papermc.paper.component.map;
-+
-+import io.papermc.paper.component.DataComponentType;
-+import org.checkerframework.checker.nullness.qual.NonNull;
-+import org.jetbrains.annotations.Nullable;
-+
-+public interface PatchedDataComponentMap extends DataComponentMap {
-+
-+ static @NonNull PatchedDataComponentMap empty() {
-+ return DataComponentPatchMapBridge.Holder.bridge().of(DataComponentPatchMapBridge.Holder.bridge().empty());
-+ }
-+
-+ static @NonNull PatchedDataComponentMap of(final @NonNull DataComponentMap map) {
-+ return DataComponentPatchMapBridge.Holder.bridge().of(map);
-+ }
-+
-+ /**
-+ * Sets this data component type to be present with a value in this map.
-+ * <p>
-+ * Note: supplying null will act similarly to {@link PatchedDataComponentMap#unset(DataComponentType)}
-+ *
-+ * @param type component type
-+ * @param value set value
-+ * @param <T> type
-+ */
-+ <T> void set(DataComponentType.@NonNull Valued<T> type, @Nullable T value);
-+
-+ /**
-+ * Sets this data component type to be present in this map.
-+ *
-+ * @param type type
-+ */
-+ void set(DataComponentType.@NonNull NonValued type);
-+
-+ /**
-+ * Unsets the value from this map.
-+ *
-+ * @param type data component type
-+ */
-+ void unset(@NonNull DataComponentType type);
-+
-+ /**
-+ * Resets the value of this component to be the default value as
-+ * supplied in the base map of this patched map.
-+ *
-+ * @param type data component type to reset
-+ */
-+ void reset(@NonNull DataComponentType type);
-+
-+ @NonNull PatchedDataComponentMap copy();
-+}
-diff --git a/src/main/java/io/papermc/paper/component/map/PatchedDataComponentMapHolder.java b/src/main/java/io/papermc/paper/component/map/PatchedDataComponentMapHolder.java
-new file mode 100644
-index 0000000000000000000000000000000000000000..956825207da17b8dc6c1216ff37cb9861c7481bc
---- /dev/null
-+++ b/src/main/java/io/papermc/paper/component/map/PatchedDataComponentMapHolder.java
-@@ -0,0 +1,34 @@
-+package io.papermc.paper.component.map;
-+
-+import io.papermc.paper.component.DataComponentType;
-+import org.checkerframework.checker.nullness.qual.NonNull;
-+import org.checkerframework.checker.nullness.qual.Nullable;
-+import org.jetbrains.annotations.ApiStatus;
-+
-+public interface PatchedDataComponentMapHolder {
-+
-+ @NonNull PatchedDataComponentMap components();
-+
-+ default boolean hasData(final @NonNull DataComponentType type) {
-+ return this.components().has(type);
-+ }
-+
-+ default @Nullable <T> T getData(final DataComponentType.@NonNull Valued<T> type) {
-+ return this.components().get(type);
-+ }
-+
-+ default <T> void setData(final DataComponentType.@NonNull Valued<T> type, final @Nullable T value) {
-+ this.components().set(type, value);
-+ }
-+
-+ default void setData(final DataComponentType.@NonNull NonValued type) {
-+ this.components().set(type);
-+ }
-+
-+ default <T> void removeData(final @NonNull DataComponentType type) {
-+ this.components().unset(type);
-+ }
-+
-+}
diff --git a/src/main/java/io/papermc/paper/component/package-info.java b/src/main/java/io/papermc/paper/component/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..37c9e2b084fe4c82242ae64569bb76beb6a88c09
@@ -1151,235 +981,120 @@ index e20f64828548c647a29dad5a475f4596cad88cd8..80c10ab30ca6ea6e2a80a916d8a5831a
/**
diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java
-index c64413a6740b604282984dea2a8430a6e7478d68..628aabd52c9686e00918adb8aee5bd9d97baa900 100644
+index 15a59a27f0854ff6f4038349d3a0d00347130140..44951ecb5ae4713cce515e2952c8c7e8c8d4eac4 100644
--- a/src/main/java/org/bukkit/inventory/ItemStack.java
+++ b/src/main/java/org/bukkit/inventory/ItemStack.java
-@@ -1,7 +1,6 @@
- package org.bukkit.inventory;
-
- import com.google.common.base.Preconditions;
--import com.google.common.collect.ImmutableMap;
- import java.util.LinkedHashMap;
- import java.util.Locale;
- import java.util.Map;
-@@ -27,11 +26,11 @@ import org.jetbrains.annotations.Nullable;
- * use this class to encapsulate Materials for which {@link Material#isItem()}
- * returns false.</b>
- */
--public class ItemStack implements Cloneable, ConfigurationSerializable, Translatable, net.kyori.adventure.text.event.HoverEventSource<net.kyori.adventure.text.event.HoverEvent.ShowItem>, net.kyori.adventure.translation.Translatable { // Paper
-+public class ItemStack implements Cloneable, ConfigurationSerializable, Translatable, net.kyori.adventure.text.event.HoverEventSource<net.kyori.adventure.text.event.HoverEvent.ShowItem>, net.kyori.adventure.translation.Translatable, io.papermc.paper.component.map.PatchedDataComponentMapHolder { // Paper
- private Material type = Material.AIR;
- private int amount = 0;
- private MaterialData data = null;
-- private ItemMeta meta;
-+ private io.papermc.paper.component.map.PatchedDataComponentMap dataKeyMap; // Paper
-
- @Utility
- protected ItemStack() {}
-@@ -88,6 +87,7 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
- Preconditions.checkArgument(type != null, "Material cannot be null");
- this.type = type;
- this.amount = amount;
-+ this.dataKeyMap = io.papermc.paper.component.map.DataComponentPatchMapBridge.Holder.bridge().of(io.papermc.paper.component.map.DataComponentPatchMapBridge.Holder.bridge().fromItem(type)); // Paper
- if (damage != 0) {
- setDurability(damage);
- }
-@@ -107,6 +107,7 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
- Preconditions.checkArgument(stack != null, "Cannot copy null stack");
- this.type = stack.getType();
- this.amount = stack.getAmount();
-+ this.dataKeyMap = io.papermc.paper.component.map.DataComponentPatchMapBridge.Holder.bridge().of(io.papermc.paper.component.map.DataComponentPatchMapBridge.Holder.bridge().fromItem(type)); // Paper
- if (this.type.isLegacy()) {
- this.data = stack.getData();
- }
-@@ -150,10 +151,8 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
- @Deprecated // Paper
- public void setType(@NotNull Material type) {
- Preconditions.checkArgument(type != null, "Material cannot be null");
-+ this.dataKeyMap = io.papermc.paper.component.map.DataComponentPatchMapBridge.Holder.bridge().fromItemAndMeta(type, Bukkit.getItemFactory().asMetaFor(this.getItemMeta(), type)); // Paper - update type first too, we need the old context to resolve the meta from the type
- this.type = type;
-- if (this.meta != null) {
-- this.meta = Bukkit.getItemFactory().asMetaFor(meta, type);
-- }
- if (type.isLegacy()) {
- createData((byte) 0);
- } else {
-@@ -277,6 +276,7 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
- */
- @Utility
- public int getMaxStackSize() {
-+ ItemMeta meta = getItemMeta();
- if (meta != null && meta.hasMaxStackSize()) {
- return meta.getMaxStackSize();
- }
-@@ -337,9 +337,7 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
- try {
- ItemStack itemStack = (ItemStack) super.clone();
-
-- if (this.meta != null) {
-- itemStack.meta = this.meta.clone();
-- }
-+ itemStack.dataKeyMap = this.components().copy(); // Paper
-
- if (this.data != null) {
- itemStack.data = this.data.clone();
-@@ -359,7 +357,7 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
- hash = hash * 31 + getType().hashCode();
- hash = hash * 31 + getAmount();
- hash = hash * 31 + (getDurability() & 0xffff);
-- hash = hash * 31 + (hasItemMeta() ? (meta == null ? getItemMeta().hashCode() : meta.hashCode()) : 0);
-+ hash = hash * 31 + dataKeyMap.hashCode(); // Paper
-
- return hash;
- }
-@@ -371,7 +369,7 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
- * @return True if this has the given enchantment
- */
- public boolean containsEnchantment(@NotNull Enchantment ench) {
-- return meta == null ? false : meta.hasEnchant(ench);
-+ return this.getItemMeta().hasEnchant(ench); // Paper
- }
-
- /**
-@@ -381,7 +379,7 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
- * @return Level of the enchantment, or 0
- */
- public int getEnchantmentLevel(@NotNull Enchantment ench) {
-- return meta == null ? 0 : meta.getEnchantLevel(ench);
-+ return this.getItemMeta().getEnchantLevel(ench); // Paper
- }
-
- /**
-@@ -391,7 +389,7 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
- */
- @NotNull
- public Map<Enchantment, Integer> getEnchantments() {
-- return meta == null ? ImmutableMap.<Enchantment, Integer>of() : meta.getEnchants();
-+ return this.getItemMeta().getEnchants(); // Paper
- }
-
- /**
-@@ -467,10 +465,11 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
- * @param level Level of the enchantment
- */
- public void addUnsafeEnchantment(@NotNull Enchantment ench, int level) {
-- ItemMeta itemMeta = (meta == null ? meta = Bukkit.getItemFactory().getItemMeta(type) : meta);
-+ editMeta((itemMeta) -> { // Paper
- if (itemMeta != null) {
- itemMeta.addEnchant(ench, level, true);
- }
-+ }); // Paper
- }
-
- /**
-@@ -482,10 +481,10 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
- */
- public int removeEnchantment(@NotNull Enchantment ench) {
- int level = getEnchantmentLevel(ench);
-- if (level == 0 || meta == null) {
-+ if (level == 0) { // Paper
- return level;
- }
-- meta.removeEnchant(ench);
-+ editMeta((itemMeta) -> itemMeta.removeEnchant(ench)); // Paper
- return level;
- }
-
-@@ -493,11 +492,7 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
- * Removes all enchantments on this ItemStack.
- */
- public void removeEnchantments() {
-- if (meta == null) {
-- return;
-- }
--
-- meta.removeEnchantments();
-+ editMeta(ItemMeta::removeEnchantments); // Paper
- }
-
- @Override
-@@ -653,7 +648,7 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
- */
- @UndefinedNullability // Paper
- public ItemMeta getItemMeta() {
-- return this.meta == null ? Bukkit.getItemFactory().getItemMeta(this.type) : this.meta.clone();
-+ return io.papermc.paper.component.map.DataComponentPatchMapBridge.Holder.bridge().toItemMeta(this.type, this.components());
- }
-
- /**
-@@ -662,7 +657,7 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
- * @return Returns true if some meta data has been set for this item
- */
- public boolean hasItemMeta() {
-- return !Bukkit.getItemFactory().equals(meta, null);
-+ return !Bukkit.getItemFactory().equals(this.getItemMeta(), null); // Paper
- }
-
- /**
-@@ -683,22 +678,13 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
- */
- private boolean setItemMeta0(@Nullable ItemMeta itemMeta, @NotNull Material material) {
- if (itemMeta == null) {
-- this.meta = null;
-+ this.dataKeyMap = io.papermc.paper.component.map.PatchedDataComponentMap.of(io.papermc.paper.component.map.DataComponentPatchMapBridge.Holder.bridge().fromItem(material));
- return true;
- }
- if (!Bukkit.getItemFactory().isApplicable(itemMeta, material)) {
- return false;
- }
-- this.meta = Bukkit.getItemFactory().asMetaFor(itemMeta, material);
--
-- Material newType = Bukkit.getItemFactory().updateMaterial(meta, material);
-- if (this.type != newType) {
-- this.type = newType;
-- }
--
-- if (this.meta == itemMeta) {
-- this.meta = itemMeta.clone();
-- }
-+ this.dataKeyMap = io.papermc.paper.component.map.DataComponentPatchMapBridge.Holder.bridge().fromItemAndMeta(material, itemMeta);
-
- return true;
- }
-@@ -1079,4 +1065,10 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
+@@ -1029,4 +1029,96 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
return Bukkit.getUnsafe().computeTooltipLines(this, tooltipContext, player);
}
// Paper end - expose itemstack tooltip lines
-+ // Paper start
-+ @Override
-+ public io.papermc.paper.component.map.@NotNull PatchedDataComponentMap components() {
-+ return this.dataKeyMap;
++
++ // Paper start - data component API
++ /**
++ * Gets the value for the data component type on this stack.
++ *
++ * @param type the data component type
++ * @return the value for the data component type, or null if not set or marked as removed
++ * @param <T> the value type
++ * @see #hasData(io.papermc.paper.component.DataComponentType) for non-valued data component types
++ */
++ @org.jetbrains.annotations.Contract(pure = true)
++ public <T> @Nullable T getData(final io.papermc.paper.component.DataComponentType.@NotNull Valued<T> type) {
++ return this.craftDelegate.getData(type);
+ }
-+ // Paper end
++
++ /**
++ * Gets the value for the data component type on this stack with
++ * a fallback value.
++ *
++ * @param type the data component type
++ * @param fallback the fallback value if the value isn't present
++ * @return the value for the data component type or the fallback value
++ * @param <T> the value type
++ */
++ @Utility
++ @org.jetbrains.annotations.Contract(value = "_, !null -> !null", pure = true)
++ public <T> @Nullable T getDataOrDefault(final io.papermc.paper.component.DataComponentType.@NotNull Valued<? extends T> type, final @Nullable T fallback) {
++ final T object = this.getData(type);
++ return object != null ? object : fallback;
++ }
++
++ /**
++ * Checks if the data component type is set on the itemstack.
++ *
++ * @param type the data component type
++ * @return true if set, false otherwise
++ */
++ @org.jetbrains.annotations.Contract(pure = true)
++ public boolean hasData(final io.papermc.paper.component.@NotNull DataComponentType type) {
++ return this.craftDelegate.hasData(type);
++ }
++
++ /**
++ * Gets all the data component types set on this stack.
++ *
++ * @return an immutable set of data component types
++ */
++ @org.jetbrains.annotations.Contract("-> new")
++ public [email protected] Set<io.papermc.paper.component.@NotNull DataComponentType> getDataComponents() {
++ return this.craftDelegate.getDataComponents();
++ }
++
++ /**
++ * Sets the value of this data component type for this itemstack.
++ * <p>
++ * Note: supplying null will act similarly to {@link ItemStack#unsetData(io.papermc.paper.component.DataComponentType)}.
++ *
++ * @param type component type
++ * @param value set value
++ * @param <T> type
++ */
++ public <T> void setData(final io.papermc.paper.component.DataComponentType.@NotNull Valued<T> type, final @Nullable T value) {
++ this.craftDelegate.setData(type, value);
++ }
++
++ /**
++ * Marks this non-valued data component type as present in this itemstack.
++ *
++ * @param type type
++ */
++ public void setData(final io.papermc.paper.component.DataComponentType.@NotNull NonValued type) {
++ this.craftDelegate.setData(type);
++ }
++
++ /**
++ * Marks this data component as removed for this itemstack.
++ *
++ * @param type data component type
++ */
++ public void unsetData(final io.papermc.paper.component.@NotNull DataComponentType type) {
++ this.craftDelegate.unsetData(type);
++ }
++
++ /**
++ * Resets the value of this component to be the default
++ * value for the item type from {@link ItemType#getDefaultDataComponent(io.papermc.paper.component.DataComponentType.Valued)}
++ * @param type data component type to reset
++ */
++ public void resetData(final io.papermc.paper.component.@NotNull DataComponentType type) {
++ this.craftDelegate.resetData(type);
++ }
++ // Paper end - data component API
+ }
+diff --git a/src/main/java/org/bukkit/inventory/ItemType.java b/src/main/java/org/bukkit/inventory/ItemType.java
+index 077bd4d4e50169780f27e8502104e9e4b2ecdae6..173fdeac69729e3a4bc75d2dae1b1db588bb6c5b 100644
+--- a/src/main/java/org/bukkit/inventory/ItemType.java
++++ b/src/main/java/org/bukkit/inventory/ItemType.java
+@@ -2443,4 +2443,12 @@ public interface ItemType extends Keyed, Translatable, net.kyori.adventure.trans
+ @Override
+ @NotNull String getTranslationKey();
+ // Paper end - add Translatable
++
++ // Paper start - data component API
++ @Nullable <T> T getDefaultDataComponent(io.papermc.paper.component.DataComponentType.@NotNull Valued<T> dataComponentType);
++
++ boolean hasDefaultDataComponent(io.papermc.paper.component.@NotNull DataComponentType dataComponentType);
++
++ [email protected] @NotNull Set<io.papermc.paper.component.DataComponentType> getDefaultDataComponentTypes();
++ // Paper end - data component API
}
-diff --git a/src/test/java/org/bukkit/configuration/ConfigurationSectionTest.java b/src/test/java/org/bukkit/configuration/ConfigurationSectionTest.java
-index ee5bc86f47cf5599e4c5c34e3a9084f86d74bdb7..d892f3b82f8e85143497d7dfd6790526fd455b90 100644
---- a/src/test/java/org/bukkit/configuration/ConfigurationSectionTest.java
-+++ b/src/test/java/org/bukkit/configuration/ConfigurationSectionTest.java
-@@ -546,7 +546,7 @@ public abstract class ConfigurationSectionTest {
- assertFalse(section.isVector("doesntExist"));
- }
-
-- @Test
-+ @org.junit.jupiter.api.Disabled // Paper
- public void testGetItemStack_String() {
- ConfigurationSection section = getConfigurationSection();
- String key = "exists";
-@@ -558,7 +558,7 @@ public abstract class ConfigurationSectionTest {
- assertNull(section.getString("doesntExist"));
- }
-
-- @Test
-+ @org.junit.jupiter.api.Disabled // Paper
- public void testGetItemStack_String_ItemStack() {
- ConfigurationSection section = getConfigurationSection();
- String key = "exists";
-@@ -571,7 +571,7 @@ public abstract class ConfigurationSectionTest {
- assertEquals(def, section.getItemStack("doesntExist", def));
- }
-
-- @Test
-+ @org.junit.jupiter.api.Disabled // Paper
- public void testIsItemStack() {
- ConfigurationSection section = getConfigurationSection();
- String key = "exists";
diff --git a/patches/server/1053-WIP-DataComponent-API.patch b/patches/server/1054-WIP-DataComponent-API.patch
index a1cc160338..6867fa7d85 100644
--- a/patches/server/1053-WIP-DataComponent-API.patch
+++ b/patches/server/1054-WIP-DataComponent-API.patch
@@ -174,13 +174,16 @@ index 0000000000000000000000000000000000000000..ca621dd53bee70a2f383517a4f1f4c15
+}
diff --git a/src/main/java/io/papermc/paper/component/PaperComponentType.java b/src/main/java/io/papermc/paper/component/PaperComponentType.java
new file mode 100644
-index 0000000000000000000000000000000000000000..93d18f6fc171b777e81a2546c47dadf6c2e30e9c
+index 0000000000000000000000000000000000000000..4f2dc5add01a3998b4d46af0a663a6fe539f6b0c
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/PaperComponentType.java
-@@ -0,0 +1,93 @@
+@@ -0,0 +1,113 @@
+package io.papermc.paper.component;
+
++import java.util.Collections;
++import java.util.Set;
+import net.kyori.adventure.key.Key;
++import net.minecraft.core.component.DataComponentMap;
+import net.minecraft.core.registries.Registries;
+import net.minecraft.resources.ResourceKey;
+import org.bukkit.NamespacedKey;
@@ -189,8 +192,8 @@ index 0000000000000000000000000000000000000000..93d18f6fc171b777e81a2546c47dadf6
+import org.bukkit.craftbukkit.util.CraftNamespacedKey;
+import org.bukkit.craftbukkit.util.Handleable;
+import org.checkerframework.checker.nullness.qual.NonNull;
++import org.checkerframework.checker.nullness.qual.Nullable;
+import org.checkerframework.framework.qual.DefaultQualifier;
-+import org.jetbrains.annotations.NotNull;
+
+@DefaultQualifier(NonNull.class)
+public abstract class PaperComponentType<T, NMS> implements DataComponentType, Handleable<net.minecraft.core.component.DataComponentType<NMS>> {
@@ -207,6 +210,23 @@ index 0000000000000000000000000000000000000000..93d18f6fc171b777e81a2546c47dadf6
+ return CraftRegistry.minecraftToBukkit(type, Registries.DATA_COMPONENT_TYPE, Registry.DATA_COMPONENT_TYPE);
+ }
+
++ public static Set<DataComponentType> minecraftToBukkit(final Set<net.minecraft.core.component.DataComponentType<?>> nmsTypes) {
++ final Set<DataComponentType> types = new java.util.HashSet<>();
++ for (final net.minecraft.core.component.DataComponentType<?> nmsType : nmsTypes) {
++ types.add(PaperComponentType.minecraftToBukkit(nmsType));
++ }
++ return Collections.unmodifiableSet(types);
++ }
++
++ public static <B, M> @Nullable B convertDataComponentValue(final DataComponentMap map, final PaperComponentType.ValuedImpl<B, M> type) {
++ final net.minecraft.core.component.DataComponentType<M> nms = bukkitToMinecraft(type);
++ final M nmsValue = map.get(nms);
++ if (nmsValue == null) {
++ return null;
++ }
++ return type.getAdapter().fromVanilla(nmsValue);
++ }
++
+ private final NamespacedKey key;
+ private final net.minecraft.core.component.DataComponentType<NMS> type;
+ private final ComponentAdapter<NMS, T> adapter;
@@ -218,7 +238,7 @@ index 0000000000000000000000000000000000000000..93d18f6fc171b777e81a2546c47dadf6
+ }
+
+ @Override
-+ public @NotNull NamespacedKey getKey() {
++ public NamespacedKey getKey() {
+ return this.key;
+ }
+
@@ -249,7 +269,7 @@ index 0000000000000000000000000000000000000000..93d18f6fc171b777e81a2546c47dadf6
+ }
+ }
+
-+ static final class NonValuedImpl<T, NMS> extends PaperComponentType<T, NMS> implements NonValued {
++ public static final class NonValuedImpl<T, NMS> extends PaperComponentType<T, NMS> implements NonValued {
+
+ NonValuedImpl(
+ final NamespacedKey key,
@@ -260,7 +280,7 @@ index 0000000000000000000000000000000000000000..93d18f6fc171b777e81a2546c47dadf6
+ }
+ }
+
-+ static final class ValuedImpl<T, NMS> extends PaperComponentType<T, NMS> implements Valued<T> {
++ public static final class ValuedImpl<T, NMS> extends PaperComponentType<T, NMS> implements Valued<T> {
+
+ ValuedImpl(
+ final NamespacedKey key,
@@ -1519,191 +1539,6 @@ index 0000000000000000000000000000000000000000..8be3187a6c624d4ba74d2a58bc64b1b0
+ }
+ }
+}
-diff --git a/src/main/java/io/papermc/paper/component/map/DataComponentPatchBridgeImpl.java b/src/main/java/io/papermc/paper/component/map/DataComponentPatchBridgeImpl.java
-new file mode 100644
-index 0000000000000000000000000000000000000000..39d941a9b910676735c38dd7eae1b3fe7a30d0ea
---- /dev/null
-+++ b/src/main/java/io/papermc/paper/component/map/DataComponentPatchBridgeImpl.java
-@@ -0,0 +1,59 @@
-+package io.papermc.paper.component.map;
-+
-+import com.mojang.authlib.GameProfile;
-+import net.minecraft.core.component.DataComponents;
-+import net.minecraft.world.item.Item;
-+import net.minecraft.world.item.ItemStack;
-+import net.minecraft.world.item.Items;
-+import org.bukkit.Material;
-+import org.bukkit.craftbukkit.inventory.CraftItemStack;
-+import org.bukkit.craftbukkit.inventory.CraftItemType;
-+import org.bukkit.craftbukkit.inventory.CraftMetaItem;
-+import org.bukkit.inventory.meta.ItemMeta;
-+import org.jetbrains.annotations.Nullable;
-+
-+public class DataComponentPatchBridgeImpl implements io.papermc.paper.component.map.DataComponentPatchMapBridge {
-+ @Override
-+ public PatchedDataComponentMap of(final DataComponentMap map) {
-+ return new PaperPatchedDataComponentMap(new net.minecraft.core.component.PatchedDataComponentMap(((PaperDataComponentMap) map).map));
-+ }
-+
-+ @Override
-+ public DataComponentMap empty() {
-+ return new PaperDataComponentMap(net.minecraft.core.component.DataComponentMap.EMPTY);
-+ }
-+
-+ @Override
-+ public DataComponentMap fromItem(final Material material) {
-+ final @Nullable Item item = CraftItemType.bukkitToMinecraft(material);
-+ if (item == null || item == Items.AIR) {
-+ // Because people can make non-item itemstacks still..
-+ return this.empty();
-+ }
-+ return new PaperDataComponentMap(item.components());
-+ }
-+
-+ @Override
-+ public PatchedDataComponentMap fromItemAndMeta(final Material material, final ItemMeta meta) {
-+ final CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator() {
-+ @Override
-+ public void skullCallback(final GameProfile gameProfile) {
-+ // TODO this isn't correct, this is called after resolving the profile, the builder is usually built when this is called
-+ // I'm not even sure if we can do anything about this.
-+ this.builder.set(DataComponents.PROFILE, new net.minecraft.world.item.component.ResolvableProfile(gameProfile));
-+ }
-+ };
-+ ((CraftMetaItem) meta).applyToItemPublic(tag);
-+
-+ final net.minecraft.core.component.PatchedDataComponentMap map = new net.minecraft.core.component.PatchedDataComponentMap(CraftItemType.bukkitToMinecraft(material).components());
-+ map.applyPatch(tag.builder.build());
-+ return new PaperPatchedDataComponentMap(map);
-+ }
-+
-+ @Override
-+ public ItemMeta toItemMeta(final Material material, final PatchedDataComponentMap map) {
-+ final ItemStack stack = new ItemStack(CraftItemType.bukkitToMinecraft(material));
-+ stack.restorePatch(((PaperPatchedDataComponentMap) map).getHandle().asPatch());
-+ return CraftItemStack.getItemMeta(stack, material);
-+ }
-+}
-diff --git a/src/main/java/io/papermc/paper/component/map/PaperDataComponentMap.java b/src/main/java/io/papermc/paper/component/map/PaperDataComponentMap.java
-new file mode 100644
-index 0000000000000000000000000000000000000000..4432c3e5cd6d3da8fd9d657e09e6833f3e9ddde2
---- /dev/null
-+++ b/src/main/java/io/papermc/paper/component/map/PaperDataComponentMap.java
-@@ -0,0 +1,46 @@
-+package io.papermc.paper.component.map;
-+
-+import io.papermc.paper.component.ComponentAdapter;
-+import io.papermc.paper.component.DataComponentType;
-+import io.papermc.paper.component.PaperComponentType;
-+import java.util.Collections;
-+import java.util.HashSet;
-+import java.util.Set;
-+import org.checkerframework.checker.nullness.qual.Nullable;
-+
-+public class PaperDataComponentMap implements DataComponentMap {
-+
-+ protected final net.minecraft.core.component.DataComponentMap map;
-+
-+ public PaperDataComponentMap(final net.minecraft.core.component.DataComponentMap map) {
-+ this.map = map;
-+ }
-+
-+ @Override
-+ public <T> @Nullable T get(final DataComponentType.Valued<T> type) {
-+ @SuppressWarnings("unchecked")
-+ final PaperComponentType<T, Object> typeAsImpl = (PaperComponentType<T, Object>) type;
-+ final ComponentAdapter<Object, T> adapter = typeAsImpl.getAdapter();
-+ final @Nullable Object value = this.map.get(typeAsImpl.getHandle());
-+
-+ return value == null ? null : adapter.fromVanilla(value);
-+ }
-+
-+ @Override
-+ public Set<DataComponentType> keySet() {
-+ final Set<net.minecraft.core.component.DataComponentType<?>> nmsKeys = this.map.keySet();
-+ final Set<DataComponentType> keys = new HashSet<>(nmsKeys.size());
-+ for (final net.minecraft.core.component.DataComponentType<?> nmsKey : nmsKeys) {
-+ keys.add(PaperComponentType.minecraftToBukkit(nmsKey));
-+ }
-+
-+ return Collections.unmodifiableSet(keys);
-+ }
-+
-+ @Override
-+ public boolean has(final DataComponentType type) {
-+ @SuppressWarnings("unchecked")
-+ final PaperComponentType<?, Object> typeAsImpl = (PaperComponentType<?, Object>) type;
-+ return this.map.has(typeAsImpl.getHandle());
-+ }
-+}
-diff --git a/src/main/java/io/papermc/paper/component/map/PaperPatchedDataComponentMap.java b/src/main/java/io/papermc/paper/component/map/PaperPatchedDataComponentMap.java
-new file mode 100644
-index 0000000000000000000000000000000000000000..3d9559a326d0aabcdeabac5d862b7b6244d7e973
---- /dev/null
-+++ b/src/main/java/io/papermc/paper/component/map/PaperPatchedDataComponentMap.java
-@@ -0,0 +1,62 @@
-+package io.papermc.paper.component.map;
-+
-+import io.papermc.paper.component.ComponentAdapter;
-+import io.papermc.paper.component.DataComponentType;
-+import io.papermc.paper.component.PaperComponentType;
-+import org.checkerframework.checker.nullness.qual.Nullable;
-+
-+public class PaperPatchedDataComponentMap extends PaperDataComponentMap implements PatchedDataComponentMap {
-+
-+ public PaperPatchedDataComponentMap(final net.minecraft.core.component.PatchedDataComponentMap map) {
-+ super(map);
-+ }
-+
-+ @Override
-+ public <T> void set(final DataComponentType.Valued<T> type, final @Nullable T value) {
-+ @SuppressWarnings("unchecked")
-+ final PaperComponentType<T, Object> typeAsImpl = ((PaperComponentType<T, Object>) type);
-+ this.setInternal(typeAsImpl, value);
-+ }
-+
-+ @Override
-+ public void set(final DataComponentType.NonValued type) {
-+ @SuppressWarnings("unchecked")
-+ final PaperComponentType<?, Object> typeAsImpl = ((PaperComponentType<?, Object>) type);
-+ this.setInternal(typeAsImpl, null);
-+ }
-+
-+ private <A, V> void setInternal(final PaperComponentType<A, V> type, final @Nullable A value) {
-+ final ComponentAdapter<V, A> adapter = type.getAdapter();
-+
-+ if (adapter.isValued()) {
-+ this.getHandle().set(type.getHandle(), value == null ? null : adapter.toVanilla(value));
-+ } else {
-+ this.getHandle().set(type.getHandle(), adapter.toVanilla(value));
-+ }
-+ }
-+
-+ @Override
-+ public void unset(final DataComponentType type) {
-+ @SuppressWarnings("unchecked")
-+ final PaperComponentType<?, Object> typeAsImpl = ((PaperComponentType<?, Object>) type);
-+ this.getHandle().remove(typeAsImpl.getHandle());
-+ }
-+
-+ @Override
-+ public void reset(final DataComponentType type) {
-+ @SuppressWarnings("unchecked")
-+ final PaperComponentType<?, Object> typeAsImpl = (PaperComponentType<?, Object>) type;
-+
-+ final net.minecraft.core.component.PatchedDataComponentMap map = this.getHandle();
-+ map.applyPatch(map.asPatch().forget((forgetType) -> forgetType == typeAsImpl.getHandle())); // Apply patch with type removed
-+ }
-+
-+ @Override
-+ public PatchedDataComponentMap copy() {
-+ return new PaperPatchedDataComponentMap(this.getHandle().copy());
-+ }
-+
-+ public net.minecraft.core.component.PatchedDataComponentMap getHandle() {
-+ return ((net.minecraft.core.component.PatchedDataComponentMap) this.map);
-+ }
-+}
diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/src/main/java/io/papermc/paper/registry/PaperRegistries.java
index 51979b3c3f1f3a3c63e0559c70bed9193fd35dbb..df2af45f32af3a1ddef25c5e7cca3973481806e2 100644
--- a/src/main/java/io/papermc/paper/registry/PaperRegistries.java
@@ -1738,10 +1573,10 @@ index af18de11dd55938b6091f5ab183bd3fe4e8df152..dad6cb4bbb52f4ce7e8f40131ee0bd37
ItemEnchantments(Object2IntAVLTreeMap<Holder<Enchantment>> enchantments, boolean showInTooltip) { // Paper
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
-index f1e1953f2dc65dc615b7b7b648c37b195d3b4c25..5941ea2cdb9ef6cd54505239d6e7b3d382db2420 100644
+index 3496b98ff0b984dbfec4f0983459a273dc0e3471..d14d0b4a0edbff19d6b5ce0674aa70ba7af902d6 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
-@@ -163,7 +163,7 @@ public final class CraftItemStack extends ItemStack {
+@@ -167,7 +167,7 @@ public final class CraftItemStack extends ItemStack {
this.adjustTagForItemMeta(oldType); // Paper
}
}
@@ -1750,7 +1585,7 @@ index f1e1953f2dc65dc615b7b7b648c37b195d3b4c25..5941ea2cdb9ef6cd54505239d6e7b3d3
}
@Override
-@@ -202,7 +202,7 @@ public final class CraftItemStack extends ItemStack {
+@@ -206,7 +206,7 @@ public final class CraftItemStack extends ItemStack {
@Override
public int getMaxStackSize() {
@@ -1777,20 +1612,111 @@ index f1e1953f2dc65dc615b7b7b648c37b195d3b4c25..5941ea2cdb9ef6cd54505239d6e7b3d3
item.set(DataComponents.PROFILE, new net.minecraft.world.item.component.ResolvableProfile(gameProfile));
}
};
-@@ -767,5 +767,14 @@ public final class CraftItemStack extends ItemStack {
- mirrored.setItemMeta(mirrored.getItemMeta());
+@@ -768,4 +768,79 @@ public final class CraftItemStack extends ItemStack {
return mirrored;
}
+ // Paper end
+
++ // Paper start - data component API
+ @Override
-+ public io.papermc.paper.component.map.@org.checkerframework.checker.nullness.qual.NonNull PaperPatchedDataComponentMap components() {
-+ if (this.handle == null) {
-+ return new io.papermc.paper.component.map.PaperPatchedDataComponentMap(new net.minecraft.core.component.PatchedDataComponentMap(net.minecraft.core.component.DataComponentMap.EMPTY)); // Paper
++ public <T> T getData(final io.papermc.paper.component.DataComponentType.Valued<T> type) {
++ if (this.isEmpty()) {
++ return null;
+ }
++ return io.papermc.paper.component.PaperComponentType.convertDataComponentValue(this.handle.getComponents(), (io.papermc.paper.component.PaperComponentType.ValuedImpl<T, ?>) type);
++ }
+
-+ return new io.papermc.paper.component.map.PaperPatchedDataComponentMap((net.minecraft.core.component.PatchedDataComponentMap) this.handle.getComponents()); // Paper
++ @Override
++ public boolean hasData(final io.papermc.paper.component.DataComponentType type) {
++ if (this.isEmpty()) {
++ return false;
++ }
++ return this.handle.has(io.papermc.paper.component.PaperComponentType.bukkitToMinecraft(type));
+ }
- // Paper end
++
++ @Override
++ public java.util.Set<io.papermc.paper.component.DataComponentType> getDataComponents() {
++ if (this.isEmpty()) {
++ return java.util.Collections.emptySet();
++ }
++ return io.papermc.paper.component.PaperComponentType.minecraftToBukkit(this.handle.getComponents().keySet());
++ }
++
++ @Override
++ public <T> void setData(final io.papermc.paper.component.DataComponentType.Valued<T> type, final T value) {
++ if (this.isEmpty()) {
++ return;
++ }
++ this.setDataInternal((io.papermc.paper.component.PaperComponentType.ValuedImpl<T, ?>) type, value);
++ }
++
++ @Override
++ public void setData(final io.papermc.paper.component.DataComponentType.NonValued type) {
++ if (this.isEmpty()) {
++ return;
++ }
++ this.setDataInternal((io.papermc.paper.component.PaperComponentType.NonValuedImpl<?, ?>) type, null);
++ }
++
++ private <A, V> void setDataInternal(final io.papermc.paper.component.PaperComponentType<A, V> type, final A value) {
++ final io.papermc.paper.component.ComponentAdapter<V, A> adapter = type.getAdapter();
++ if (adapter.isValued()) {
++ this.handle.set(type.getHandle(), value == null ? null : adapter.toVanilla(value));
++ } else {
++ this.handle.set(type.getHandle(), adapter.toVanilla(value));
++ }
++ }
++
++ @Override
++ public void unsetData(final io.papermc.paper.component.DataComponentType type) {
++ if (this.isEmpty()) {
++ return;
++ }
++ this.handle.remove(io.papermc.paper.component.PaperComponentType.bukkitToMinecraft(type));
++ }
++
++ @Override
++ public void resetData(final io.papermc.paper.component.DataComponentType type) {
++ if (this.isEmpty()) {
++ return;
++ }
++ this.resetData((io.papermc.paper.component.PaperComponentType<?, ?>) type);
++ }
++
++ private <M> void resetData(final io.papermc.paper.component.PaperComponentType<?, M> type) {
++ final net.minecraft.core.component.DataComponentType<M> nms = io.papermc.paper.component.PaperComponentType.bukkitToMinecraft(type);
++ final M nmsValue = this.handle.getItem().components().get(nms);
++ // if nmsValue is null, it will clear any set patch
++ // if nmsValue is not null, it will still clear any set patch because it will equal the default value
++ this.handle.set(nms, nmsValue);
++ }
++ // Paper end - data component API
+ }
+diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java
+index b54be1122af2b303c0f063ff6b61bf8e2478b0df..f0c394741c56b23df47c1b3e6790d4d41b9d851b 100644
+--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java
++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java
+@@ -253,4 +253,21 @@ public class CraftItemType<M extends ItemMeta> implements ItemType.Typed<M>, Han
+ return this.item.getDescriptionId();
+ }
+ // Paper end - add Translatable
++
++ // Paper start - data component API
++ @Override
++ public <T> T getDefaultDataComponent(final io.papermc.paper.component.DataComponentType.Valued<T> dataComponentType) {
++ return io.papermc.paper.component.PaperComponentType.convertDataComponentValue(this.item.components(), ((io.papermc.paper.component.PaperComponentType.ValuedImpl<T, ?>) dataComponentType));
++ }
++
++ @Override
++ public boolean hasDefaultDataComponent(final io.papermc.paper.component.DataComponentType dataComponentType) {
++ return this.item.components().has(io.papermc.paper.component.PaperComponentType.bukkitToMinecraft(dataComponentType));
++ }
++
++ @Override
++ public java.util.Set<io.papermc.paper.component.DataComponentType> getDefaultDataComponentTypes() {
++ return io.papermc.paper.component.PaperComponentType.minecraftToBukkit(this.item.components().keySet());
++ }
++ // Paper end - data component API
}
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
index d5789326d70bb8b029c5448270bbaa6faf52e6e1..02cdd38a55741a56ed9de428d9145e6103b71f65 100644
@@ -1841,92 +1767,6 @@ index 0000000000000000000000000000000000000000..a2c02206254a18e089cb2b40eab5c59e
+++ b/src/main/resources/META-INF/services/io.papermc.paper.component.item.ComponentTypesBridge
@@ -0,0 +1 @@
+io.papermc.paper.component.item.ComponentTypesBridgesImpl
-diff --git a/src/main/resources/META-INF/services/io.papermc.paper.component.map.DataComponentPatchMapBridge b/src/main/resources/META-INF/services/io.papermc.paper.component.map.DataComponentPatchMapBridge
-new file mode 100644
-index 0000000000000000000000000000000000000000..4630bf3ffa719c218791d4a4f2aea8f872b25baa
---- /dev/null
-+++ b/src/main/resources/META-INF/services/io.papermc.paper.component.map.DataComponentPatchMapBridge
-@@ -0,0 +1 @@
-+io.papermc.paper.component.map.DataComponentPatchBridgeImpl
-diff --git a/src/test/java/io/papermc/paper/configuration/ConfigurationSectionTest.java b/src/test/java/io/papermc/paper/configuration/ConfigurationSectionTest.java
-new file mode 100644
-index 0000000000000000000000000000000000000000..0aad5d896a6adb691a7efaee3baebed4da7c607e
---- /dev/null
-+++ b/src/test/java/io/papermc/paper/configuration/ConfigurationSectionTest.java
-@@ -0,0 +1,56 @@
-+package io.papermc.paper.configuration;
-+
-+import static org.junit.jupiter.api.Assertions.*;
-+import java.util.Arrays;
-+import java.util.Collections;
-+import java.util.HashMap;
-+import java.util.LinkedHashMap;
-+import java.util.List;
-+import java.util.Map;
-+import org.bukkit.Material;
-+import org.bukkit.configuration.ConfigurationSection;
-+import org.bukkit.configuration.serialization.ConfigurationSerializable;
-+import org.bukkit.inventory.ItemStack;
-+import org.bukkit.util.Vector;
-+import org.junit.jupiter.api.Test;
-+
-+public abstract class ConfigurationSectionTest {
-+ public abstract ConfigurationSection getConfigurationSection();
-+
-+ @Test
-+ public void testGetItemStack_String() {
-+ ConfigurationSection section = getConfigurationSection();
-+ String key = "exists";
-+ ItemStack value = new ItemStack(Material.ACACIA_WOOD, 50);
-+
-+ section.set(key, value);
-+
-+ assertEquals(value, section.getItemStack(key));
-+ assertNull(section.getString("doesntExist"));
-+ }
-+
-+ @Test
-+ public void testGetItemStack_String_ItemStack() {
-+ ConfigurationSection section = getConfigurationSection();
-+ String key = "exists";
-+ ItemStack value = new ItemStack(Material.ACACIA_WOOD, 50);
-+ ItemStack def = new ItemStack(Material.STONE, 1);
-+
-+ section.set(key, value);
-+
-+ assertEquals(value, section.getItemStack(key, def));
-+ assertEquals(def, section.getItemStack("doesntExist", def));
-+ }
-+
-+ @Test
-+ public void testIsItemStack() {
-+ ConfigurationSection section = getConfigurationSection();
-+ String key = "exists";
-+ ItemStack value = new ItemStack(Material.ACACIA_WOOD, 50);
-+
-+ section.set(key, value);
-+
-+ assertTrue(section.isItemStack(key));
-+ assertFalse(section.isItemStack("doesntExist"));
-+ }
-+}
-diff --git a/src/test/java/io/papermc/paper/configuration/MemorySectionTest.java b/src/test/java/io/papermc/paper/configuration/MemorySectionTest.java
-new file mode 100644
-index 0000000000000000000000000000000000000000..def33c36f207a4c5306b5a895336aa70335c1678
---- /dev/null
-+++ b/src/test/java/io/papermc/paper/configuration/MemorySectionTest.java
-@@ -0,0 +1,11 @@
-+package io.papermc.paper.configuration;
-+
-+import org.bukkit.configuration.ConfigurationSection;
-+import org.bukkit.configuration.MemoryConfiguration;
-+
-+public class MemorySectionTest extends ConfigurationSectionTest {
-+ @Override
-+ public ConfigurationSection getConfigurationSection() {
-+ return new MemoryConfiguration().createSection("section");
-+ }
-+}
diff --git a/src/test/java/io/papermc/paper/item/ItemStackDataComponentTest.java b/src/test/java/io/papermc/paper/item/ItemStackDataComponentTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..40c77423134931083913e871b80dae8e6e5f2194