diff options
author | Owen1212055 <[email protected]> | 2024-10-31 13:35:26 -0400 |
---|---|---|
committer | Owen1212055 <[email protected]> | 2024-11-18 14:50:38 -0500 |
commit | eaddf6ab8c4cb57e61b7ca150f0e2f272cfa717c (patch) | |
tree | b3d1b6b149cf256f9a2853cbf412d2fd46895a0b | |
parent | 2bd5eee1a03fa51e5fca3dd931da84efa32eb0de (diff) | |
download | Paper-eaddf6ab8c4cb57e61b7ca150f0e2f272cfa717c.tar.gz Paper-eaddf6ab8c4cb57e61b7ca150f0e2f272cfa717c.zip |
Update Data component api
-rw-r--r-- | patches/api/0497-WIP-DataComponent-API.patch (renamed from patches/api/0482-WIP-DataComponent-API.patch) | 1130 | ||||
-rw-r--r-- | patches/server/1058-WIP-DataComponent-API.patch (renamed from patches/server/1044-WIP-DataComponent-API.patch) | 1276 |
2 files changed, 2109 insertions, 297 deletions
diff --git a/patches/api/0482-WIP-DataComponent-API.patch b/patches/api/0497-WIP-DataComponent-API.patch index 289497f7a9..77e6b14804 100644 --- a/patches/api/0482-WIP-DataComponent-API.patch +++ b/patches/api/0497-WIP-DataComponent-API.patch @@ -148,18 +148,23 @@ index 0000000000000000000000000000000000000000..3a0bca9f95d6f1ad2e160620bb47f702 +} diff --git a/src/main/java/io/papermc/paper/datacomponent/DataComponentTypes.java b/src/main/java/io/papermc/paper/datacomponent/DataComponentTypes.java new file mode 100644 -index 0000000000000000000000000000000000000000..4a99e023e4593dc0ccc05b9af292b44d056f534e +index 0000000000000000000000000000000000000000..a40b95ce0de70365bf1a1d339df96a483128abe1 --- /dev/null +++ b/src/main/java/io/papermc/paper/datacomponent/DataComponentTypes.java -@@ -0,0 +1,324 @@ +@@ -0,0 +1,342 @@ +package io.papermc.paper.datacomponent; + +import io.papermc.paper.datacomponent.item.BannerPatternLayers; +import io.papermc.paper.datacomponent.item.BlockItemDataProperties; +import io.papermc.paper.datacomponent.item.BundleContents; +import io.papermc.paper.datacomponent.item.ChargedProjectiles; ++import io.papermc.paper.datacomponent.item.Consumable; +import io.papermc.paper.datacomponent.item.CustomModelData; ++import io.papermc.paper.datacomponent.item.DamageResistant; ++import io.papermc.paper.datacomponent.item.DeathProtection; +import io.papermc.paper.datacomponent.item.DyedItemColor; ++import io.papermc.paper.datacomponent.item.Enchantable; ++import io.papermc.paper.datacomponent.item.Equippable; +import io.papermc.paper.datacomponent.item.Fireworks; +import io.papermc.paper.datacomponent.item.FoodProperties; +import io.papermc.paper.datacomponent.item.ItemAdventurePredicate; @@ -174,6 +179,8 @@ index 0000000000000000000000000000000000000000..4a99e023e4593dc0ccc05b9af292b44d +import io.papermc.paper.datacomponent.item.MapDecorations; +import io.papermc.paper.datacomponent.item.MapId; +import io.papermc.paper.datacomponent.item.MapItemColor; ++import io.papermc.paper.datacomponent.item.UseCooldown; ++import io.papermc.paper.datacomponent.item.UseRemainder; +import io.papermc.paper.item.MapPostProcessing; +import io.papermc.paper.datacomponent.item.PotDecorations; +import io.papermc.paper.datacomponent.item.PotionContents; @@ -193,6 +200,7 @@ index 0000000000000000000000000000000000000000..4a99e023e4593dc0ccc05b9af292b44d +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.inventory.ItemRarity; ++import org.bukkit.inventory.meta.Repairable; +import org.checkerframework.checker.index.qual.NonNegative; +import org.checkerframework.checker.index.qual.Positive; +import org.checkerframework.common.value.qual.IntRange; @@ -254,6 +262,7 @@ index 0000000000000000000000000000000000000000..4a99e023e4593dc0ccc05b9af292b44d + * @see #CUSTOM_NAME + */ + public static final DataComponentType.Valued<Component> ITEM_NAME = valued("item_name"); ++ public static final DataComponentType.Valued<Key> ITEM_MODEL = valued("item_model"); + /** + * Additional lines to include in an item's tooltip. + */ @@ -320,14 +329,23 @@ index 0000000000000000000000000000000000000000..4a99e023e4593dc0ccc05b9af292b44d + * When present, this item will behave as if a food (can be eaten). + */ + public static final DataComponentType.Valued<FoodProperties> FOOD = valued("food"); ++ public static final DataComponentType.Valued<Consumable> CONSUMABLE = valued("consumable"); ++ public static final DataComponentType.Valued<UseRemainder> USE_REMAINDER = valued("use_remainder"); ++ public static final DataComponentType.Valued<UseCooldown> USE_COOLDOWN = valued("use_cooldown"); + /** + * If present, this item will not burn in fire. + */ -+ public static final DataComponentType.NonValued FIRE_RESISTANT = unvalued("fire_resistant"); ++ public static final DataComponentType.Valued<DamageResistant> DAMAGE_RESISTANT = valued("damage_resistant"); + /** + * Controls the behavior of the item as a tool. + */ + public static final DataComponentType.Valued<Tool> TOOL = valued("tool"); ++ public static final DataComponentType.Valued<Enchantable> ENCHANTABLE = valued("enchantable"); ++ public static final DataComponentType.Valued<Equippable> EQUIPPABLE = valued("equippable"); ++ public static final DataComponentType.Valued<Repairable> REPAIRABLE = valued("repairable"); ++ public static final DataComponentType.NonValued GLIDER = unvalued("glider"); ++ public static final DataComponentType.Valued<Key> TOOLTIP_STYLE = valued("tooltip_style"); ++ public static final DataComponentType.Valued<DeathProtection> DEATH_PROTECTION = valued("death_protection"); + /** + * Stores list of enchantments and their levels for an Enchanted Book. + * Unlike {@link #ENCHANTMENTS}, the effects provided by enchantments @@ -760,6 +778,96 @@ index 0000000000000000000000000000000000000000..df663aeeb1ebe547fff956bdda4455bd + @NonNull Builder addAll(@NonNull List<@NonNull ItemStack> stacks); + } +} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/Consumable.java b/src/main/java/io/papermc/paper/datacomponent/item/Consumable.java +new file mode 100644 +index 0000000000000000000000000000000000000000..01d25b7c618926284c517e4fa67600416b8ef532 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/Consumable.java +@@ -0,0 +1,84 @@ ++package io.papermc.paper.datacomponent.item; ++ ++import io.papermc.paper.datacomponent.BuildableDataComponent; ++import io.papermc.paper.datacomponent.DataComponentBuilder; ++import java.util.Collection; ++import java.util.List; ++import io.papermc.paper.datacomponent.item.consumable.ConsumeEffect; ++import io.papermc.paper.datacomponent.item.consumable.ItemUseAnimation; ++import net.kyori.adventure.key.Key; ++import org.bukkit.inventory.ItemStack; ++import org.checkerframework.checker.index.qual.NonNegative; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.Contract; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Unmodifiable; ++ ++/** ++ * Holds the properties for this item for when it is consumed. ++ * @see io.papermc.paper.datacomponent.DataComponentTypes#CONSUMABLE ++ */ ++public interface Consumable extends BuildableDataComponent<Consumable, Consumable.Builder> { ++ ++ @Contract(value = "-> new", pure = true) ++ static Consumable.@NonNull Builder consumable() { ++ return ItemComponentTypesBridge.bridge().consumable(); ++ } ++ ++ @Contract(pure = true) ++ @NonNegative ++ float consumeSeconds(); ++ ++ @Contract(pure = true) ++ ItemUseAnimation animation(); ++ ++ @Contract(pure = true) ++ @NonNull ++ Key sound(); ++ ++ @Contract(pure = true) ++ boolean hasConsumeParticles(); ++ ++ @Contract(pure = true) ++ @Unmodifiable ++ @NonNull ++ List<ConsumeEffect> consumeEffects(); ++ ++ /** ++ * Builder for {@link Consumable}. ++ */ ++ @ApiStatus.Experimental ++ @ApiStatus.NonExtendable ++ interface Builder extends DataComponentBuilder<Consumable> { ++ ++ @Contract(value = "_ -> this", mutates = "this") ++ @NonNull ++ Builder consumeSeconds(@NonNegative float consumeSeconds); ++ ++ @Contract(value = "_ -> this", mutates = "this") ++ @NonNull ++ Builder animation(@NotNull ItemUseAnimation animation); ++ ++ @Contract(value = "_ -> this", mutates = "this") ++ @NonNull ++ Builder sound(@NonNull Key sound); ++ ++ @Contract(value = "_ -> this", mutates = "this") ++ @NonNull ++ Builder hasConsumeParticles(boolean hasConsumeParticles); ++ ++ @Contract(value = "_ -> this", mutates = "this") ++ @NonNull ++ Builder addEffect(@NonNull ConsumeEffect effect); ++ ++ @Contract(value = "_ -> this", mutates = "this") ++ @NonNull ++ Builder addEffects(@NonNull Collection<@NonNull ConsumeEffect> effects); ++ } ++ ++ ++} diff --git a/src/main/java/io/papermc/paper/datacomponent/item/CustomModelData.java b/src/main/java/io/papermc/paper/datacomponent/item/CustomModelData.java new file mode 100644 index 0000000000000000000000000000000000000000..998eb257bf88f313a812802fd7dd45320893d224 @@ -793,6 +901,106 @@ index 0000000000000000000000000000000000000000..998eb257bf88f313a812802fd7dd4532 + @Contract(pure = true) + int id(); +} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/DamageResistant.java b/src/main/java/io/papermc/paper/datacomponent/item/DamageResistant.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a6fd5b513b119bbf4e998a533bb36185d5cdfa92 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/DamageResistant.java +@@ -0,0 +1,35 @@ ++package io.papermc.paper.datacomponent.item; ++ ++import io.papermc.paper.datacomponent.DataComponentBuilder; ++import io.papermc.paper.registry.set.RegistryKeySet; ++import io.papermc.paper.registry.tag.TagKey; ++import org.bukkit.damage.DamageType; ++import org.bukkit.inventory.ItemStack; ++import org.bukkit.potion.PotionEffectType; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.Contract; ++ ++/** ++ * Holds the contents of damage types that the item entity containing this item is invincible to. ++ * @see io.papermc.paper.datacomponent.DataComponentTypes#DAMAGE_RESISTANT ++ */ ++public interface DamageResistant { ++ ++ @Contract(value = "_ -> new", pure = true) ++ static @NonNull DamageResistant damageResistant(final @NonNull TagKey<DamageType> types) { ++ return ItemComponentTypesBridge.bridge().damageResistant(types); ++ } ++ ++ /** ++ * The types that this damage type is invincible tp. ++ * ++ * @return item ++ */ ++ @Contract(value = "-> new", pure = true) ++ @NonNull ++ TagKey<DamageType> types(); ++ ++} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/DeathProtection.java b/src/main/java/io/papermc/paper/datacomponent/item/DeathProtection.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2ab52d15420122f6b8c05131a4fc0ccb25d8906c +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/DeathProtection.java +@@ -0,0 +1,53 @@ ++package io.papermc.paper.datacomponent.item; ++ ++import io.papermc.paper.datacomponent.DataComponentBuilder; ++import java.util.Arrays; ++import java.util.Collection; ++import java.util.List; ++import io.papermc.paper.datacomponent.item.consumable.ConsumeEffect; ++import org.bukkit.inventory.ItemStack; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.Contract; ++import org.jetbrains.annotations.Unmodifiable; ++ ++/** ++ * Sets whether this item should protect the entity upon death, and what effects should be played. ++ * @see io.papermc.paper.datacomponent.DataComponentTypes#DEATH_PROTECTION ++ */ ++public interface DeathProtection { ++ ++ @Contract(value = "_ -> new", pure = true) ++ static @NonNull DeathProtection deathProtection(final @NonNull ConsumeEffect @NonNull... deathEffects) { ++ return deathProtection(Arrays.asList(deathEffects)); ++ } ++ ++ @Contract(value = "_ -> new", pure = true) ++ static @NonNull DeathProtection deathProtection(final @NonNull List<@NonNull ConsumeEffect> deathEffects) { ++ return deathProtection().addEffects(deathEffects).build(); ++ } ++ ++ @Contract(value = "-> new", pure = true) ++ static DeathProtection.@NonNull Builder deathProtection() { ++ return ItemComponentTypesBridge.bridge().deathProtection(); ++ } ++ ++ @Contract(value = "-> new", pure = true) ++ @NonNull @Unmodifiable List<@NonNull ConsumeEffect> deathEffects(); ++ ++ /** ++ * Builder for {@link DeathProtection}. ++ */ ++ @ApiStatus.Experimental ++ @ApiStatus.NonExtendable ++ interface Builder extends DataComponentBuilder<DeathProtection> { ++ ++ @Contract(value = "_ -> this", mutates = "this") ++ @NonNull Builder addEffect(@NonNull ConsumeEffect effect); ++ ++ @Contract(value = "_ -> this", mutates = "this") ++ @NonNull Builder addEffects(@NonNull Collection<@NonNull ConsumeEffect> effects); ++ } ++} diff --git a/src/main/java/io/papermc/paper/datacomponent/item/DyedItemColor.java b/src/main/java/io/papermc/paper/datacomponent/item/DyedItemColor.java new file mode 100644 index 0000000000000000000000000000000000000000..78afe5d6f3796e2c1ee945c8bcac167ce847c1f4 @@ -851,6 +1059,218 @@ index 0000000000000000000000000000000000000000..78afe5d6f3796e2c1ee945c8bcac167c + @NonNull Builder color(@NonNull Color color); + } +} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/Enchantable.java b/src/main/java/io/papermc/paper/datacomponent/item/Enchantable.java +new file mode 100644 +index 0000000000000000000000000000000000000000..feced7acdac5219b6f5d6a7eab825c6e23db3899 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/Enchantable.java +@@ -0,0 +1,28 @@ ++package io.papermc.paper.datacomponent.item; ++ ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.Contract; ++ ++/** ++ * Holds if an item is enchantable, allowing for enchantments of the type to be seen in an enchanting table. ++ * @see io.papermc.paper.datacomponent.DataComponentTypes#ENCHANTABLE ++ */ ++public interface Enchantable { ++ ++ @Contract(value = "_ -> new", pure = true) ++ static @NonNull Enchantable enchantable(final int level) { ++ return ItemComponentTypesBridge.bridge().enchantable(level); ++ } ++ ++ /** ++ * Gets the current enchantment value level allowed, ++ * a higher value allows enchantments with a higher cost to be picked. ++ * ++ * @return the value ++ */ ++ @Contract(pure = true) ++ int value(); ++} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/Equippable.java b/src/main/java/io/papermc/paper/datacomponent/item/Equippable.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ec6a408f858241cd96ef2c73db7b14914fab800e +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/Equippable.java +@@ -0,0 +1,172 @@ ++package io.papermc.paper.datacomponent.item; ++ ++import io.papermc.paper.datacomponent.BuildableDataComponent; ++import io.papermc.paper.datacomponent.DataComponentBuilder; ++import io.papermc.paper.registry.set.RegistryKeySet; ++import net.kyori.adventure.key.Key; ++import org.bukkit.entity.EntityType; ++import org.bukkit.inventory.EquipmentSlot; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.Contract; ++ ++ ++/** ++ * Holds the equippable properties of an item. ++ * @see io.papermc.paper.datacomponent.DataComponentTypes#EQUIPPABLE ++ */ ++public interface Equippable extends BuildableDataComponent<Equippable, Equippable.Builder> { ++ ++ /** ++ * Creates a new {@link Equippable.Builder} instance. ++ * @param slot The slot for the new equppable to be equippable in. ++ * ++ * @return a new builder ++ */ ++ @Contract(value = "_ -> new", pure = true) ++ static Equippable.@NonNull Builder equippable(@NonNull EquipmentSlot slot) { ++ return ItemComponentTypesBridge.bridge().equippable(slot); ++ } ++ ++ /** ++ * Gets the equipment slot this item can be equipped in. ++ * ++ * @return the equipment slot ++ */ ++ @Contract(pure = true) ++ @NonNull ++ EquipmentSlot slot(); ++ ++ /** ++ * Gets the equip sound key. ++ * ++ * @return the equip sound key ++ */ ++ @Contract(pure = true) ++ @NonNull ++ Key equipSound(); ++ ++ /** ++ * Gets the model key if present. ++ * ++ * @return the model key or null ++ */ ++ @Contract(pure = true) ++ @Nullable Key model(); ++ ++ /** ++ * Gets the camera overlay key if present. ++ * ++ * @return the camera overlay key or null ++ */ ++ @Contract(pure = true) ++ @Nullable Key cameraOverlay(); ++ ++ /** ++ * Gets the set of allowed entities that can equip this item. ++ * May be null if all entities are allowed. ++ * ++ * @return the set of allowed entities ++ */ ++ @Contract(pure = true) ++ @Nullable ++ RegistryKeySet<EntityType> allowedEntities(); ++ ++ /** ++ * Checks if the item is dispensable. ++ * ++ * @return true if dispensable, false otherwise ++ */ ++ @Contract(pure = true) ++ boolean dispensable(); ++ ++ /** ++ * Checks if the item is swappable. ++ * ++ * @return true if swappable, false otherwise ++ */ ++ @Contract(pure = true) ++ boolean swappable(); ++ ++ /** ++ * Checks if the item takes damage when the wearer is hurt. ++ * ++ * @return true if it damages on hurt, false otherwise ++ */ ++ @Contract(pure = true) ++ boolean damageOnHurt(); ++ ++ /** ++ * Builder for {@link Equippable}. ++ */ ++ @ApiStatus.Experimental ++ @ApiStatus.NonExtendable ++ interface Builder extends DataComponentBuilder<Equippable> { ++ ++ /** ++ * Sets the equip sound key for this item. ++ * ++ * @param equipSound the equip sound key ++ * @return the builder for chaining ++ */ ++ @Contract(value = "_ -> this", mutates = "this") ++ @NonNull Builder equipSound(@NonNull Key equipSound); ++ ++ /** ++ * Sets the model key for this item. ++ * ++ * @param model the model key, nullable ++ * @return the builder for chaining ++ */ ++ @Contract(value = "_ -> this", mutates = "this") ++ @NonNull Builder model(@Nullable Key model); ++ ++ /** ++ * Sets the camera overlay key for this item. ++ * ++ * @param cameraOverlay the camera overlay key, nullable ++ * @return the builder for chaining ++ */ ++ @Contract(value = "_ -> this", mutates = "this") ++ @NonNull Builder cameraOverlay(@Nullable Key cameraOverlay); ++ ++ /** ++ * Sets the allowed entities that can equip this item. ++ * ++ * @param allowedEntities the set of allowed entity types, or null if any ++ * @return the builder for chaining ++ */ ++ @Contract(value = "_ -> this", mutates = "this") ++ @NonNull Builder allowedEntities(@Nullable RegistryKeySet<EntityType> allowedEntities); ++ ++ /** ++ * Sets whether the item is dispensable. ++ * ++ * @param dispensable true if dispensable ++ * @return the builder for chaining ++ */ ++ @Contract(value = "_ -> this", mutates = "this") ++ @NonNull Builder dispensable(boolean dispensable); ++ ++ /** ++ * Sets whether the item is swappable. ++ * ++ * @param swappable true if swappable ++ * @return the builder for chaining ++ */ ++ @Contract(value = "_ -> this", mutates = "this") ++ @NonNull Builder swappable(boolean swappable); ++ ++ /** ++ * Sets whether the item takes damage when the wearer is hurt. ++ * ++ * @param damageOnHurt true if it damages on hurt ++ * @return the builder for chaining ++ */ ++ @Contract(value = "_ -> this", mutates = "this") ++ @NonNull Builder damageOnHurt(boolean damageOnHurt); ++ } ++} diff --git a/src/main/java/io/papermc/paper/datacomponent/item/Fireworks.java b/src/main/java/io/papermc/paper/datacomponent/item/Fireworks.java new file mode 100644 index 0000000000000000000000000000000000000000..127ee7a9a89783df9eee78aa94ede7390f606fdc @@ -942,10 +1362,10 @@ index 0000000000000000000000000000000000000000..127ee7a9a89783df9eee78aa94ede739 +} diff --git a/src/main/java/io/papermc/paper/datacomponent/item/FoodProperties.java b/src/main/java/io/papermc/paper/datacomponent/item/FoodProperties.java new file mode 100644 -index 0000000000000000000000000000000000000000..b28bdb326f6579840813c4c390c0fb65fa3f0cb5 +index 0000000000000000000000000000000000000000..d8aa7a006044324763bf27a074ecfaaad93b3628 --- /dev/null +++ b/src/main/java/io/papermc/paper/datacomponent/item/FoodProperties.java -@@ -0,0 +1,161 @@ +@@ -0,0 +1,92 @@ +package io.papermc.paper.datacomponent.item; + +import io.papermc.paper.datacomponent.BuildableDataComponent; @@ -999,57 +1419,6 @@ index 0000000000000000000000000000000000000000..b28bdb326f6579840813c4c390c0fb65 + boolean canAlwaysEat(); + + /** -+ * The number of seconds that it takes to eat this food item. -+ * -+ * @return the number seconds to eat that food -+ */ -+ @Contract(pure = true) -+ float eatSeconds(); -+ -+ @Contract(pure = true) -+ @Nullable ItemStack usingConvertsTo(); -+ -+ /** -+ * List of effects to apply when eaten. -+ * -+ * @return effects -+ */ -+ @NonNull @Unmodifiable List<@NonNull PossibleEffect> effects(); -+ -+ /** -+ * Effect to possibly be applied when eaten. -+ */ -+ @ApiStatus.NonExtendable -+ interface PossibleEffect { -+ -+ /** -+ * Create a possible effect. -+ * -+ * @param effect the potion effect -+ * @param probability the probability of this effect being applied, between 0 and 1 inclusive. -+ * @return the possible effect -+ */ -+ @Contract(value = "_, _ -> new", pure = true) -+ static @NonNull PossibleEffect of(final @NonNull PotionEffect effect, final float probability) { -+ return ItemComponentTypesBridge.bridge().foodEffect(effect, probability); -+ } -+ -+ /** -+ * Effect instance. -+ * -+ * @return effect -+ */ -+ @NonNull PotionEffect effect(); -+ -+ /** -+ * Float between 0 and 1, chance for the effect to be applied. -+ * -+ * @return chance -+ */ -+ float probability(); -+ } -+ -+ /** + * Builder for {@link FoodProperties}. + */ + @ApiStatus.Experimental @@ -1068,16 +1437,6 @@ index 0000000000000000000000000000000000000000..b28bdb326f6579840813c4c390c0fb65 + @NonNull Builder canAlwaysEat(boolean canAlwaysEat); + + /** -+ * Set the seconds it takes to eat this food. -+ * -+ * @param eatSeconds the seconds, must be non-negative -+ * @return the builder for chaining -+ * @see #eatSeconds() -+ */ -+ @Contract(value = "_ -> this", mutates = "this") -+ @NonNull Builder eatSeconds(@NonNegative float eatSeconds); -+ -+ /** + * Sets the saturation of the food. + * + * @param saturation the saturation @@ -1097,14 +1456,6 @@ index 0000000000000000000000000000000000000000..b28bdb326f6579840813c4c390c0fb65 + @Contract(value = "_ -> this", mutates = "this") + @NonNull Builder nutrition(@NonNegative int nutrition); + -+ @Contract(value = "_ -> this", mutates = "this") -+ @NonNull Builder usingConvertsTo(@Nullable ItemStack stack); -+ -+ @Contract(value = "_ -> this", mutates = "this") -+ @NonNull Builder addEffect(@NonNull PossibleEffect effect); -+ -+ @Contract(value = "_ -> this", mutates = "this") -+ @NonNull Builder addEffects(@NonNull Collection<@NonNull PossibleEffect> effects); + } +} diff --git a/src/main/java/io/papermc/paper/datacomponent/item/ItemAdventurePredicate.java b/src/main/java/io/papermc/paper/datacomponent/item/ItemAdventurePredicate.java @@ -1320,14 +1671,15 @@ index 0000000000000000000000000000000000000000..79a7f5387142aa267655f6243a8f9291 +} diff --git a/src/main/java/io/papermc/paper/datacomponent/item/ItemComponentTypesBridge.java b/src/main/java/io/papermc/paper/datacomponent/item/ItemComponentTypesBridge.java new file mode 100644 -index 0000000000000000000000000000000000000000..9ecd83fdc364700ef5aaf3ac63f41818f4a91a07 +index 0000000000000000000000000000000000000000..8e2c70fca8f28996bacde186057fc6ad4eb429bb --- /dev/null +++ b/src/main/java/io/papermc/paper/datacomponent/item/ItemComponentTypesBridge.java -@@ -0,0 +1,92 @@ +@@ -0,0 +1,110 @@ +package io.papermc.paper.datacomponent.item; + +import com.destroystokyo.paper.profile.PlayerProfile; +import io.papermc.paper.registry.set.RegistryKeySet; ++import io.papermc.paper.registry.tag.TagKey; +import io.papermc.paper.util.Filtered; +import java.util.Optional; +import java.util.ServiceLoader; @@ -1335,9 +1687,12 @@ index 0000000000000000000000000000000000000000..9ecd83fdc364700ef5aaf3ac63f41818 +import net.kyori.adventure.util.TriState; +import org.bukkit.JukeboxSong; +import org.bukkit.block.BlockType; ++import org.bukkit.damage.DamageType; ++import org.bukkit.inventory.EquipmentSlot; ++import org.bukkit.inventory.ItemStack; ++import org.bukkit.inventory.ItemType; +import org.bukkit.inventory.meta.trim.ArmorTrim; +import org.bukkit.map.MapCursor; -+import org.bukkit.potion.PotionEffect; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.jetbrains.annotations.ApiStatus; + @@ -1364,8 +1719,6 @@ index 0000000000000000000000000000000000000000..9ecd83fdc364700ef5aaf3ac63f41818 + + FoodProperties.Builder food(); + -+ FoodProperties.PossibleEffect foodEffect(PotionEffect effect, float probability); -+ + DyedItemColor.Builder dyedItemColor(); + + PotionContents.Builder potionContents(); @@ -1414,7 +1767,23 @@ index 0000000000000000000000000000000000000000..9ecd83fdc364700ef5aaf3ac63f41818 + + MapId mapId(int id); + -+ LockCode lockCode(String code); ++ UseRemainder useRemainder(ItemStack itemStack); ++ ++ Consumable.Builder consumable(); ++ ++ UseCooldown.Builder useCooldown(final float seconds); ++ ++ DamageResistant damageResistant(TagKey<DamageType> types); ++ ++ Enchantable enchantable(int level); ++ ++ Repairable repairable(RegistryKeySet<ItemType> types); ++ ++ Equippable.Builder equippable(EquipmentSlot slot); ++ ++ DeathProtection.Builder deathProtection(); ++ ++ OminiousBottleAmplifier ominiousBottleAmplifier(int amplifier); +} diff --git a/src/main/java/io/papermc/paper/datacomponent/item/ItemContainerContents.java b/src/main/java/io/papermc/paper/datacomponent/item/ItemContainerContents.java new file mode 100644 @@ -1701,7 +2070,7 @@ index 0000000000000000000000000000000000000000..26ca1143b74d4b0c4e48865dc94128ec +} diff --git a/src/main/java/io/papermc/paper/datacomponent/item/LockCode.java b/src/main/java/io/papermc/paper/datacomponent/item/LockCode.java new file mode 100644 -index 0000000000000000000000000000000000000000..6386d859ec06ffd23553767d8f87d85ed1e6a4df +index 0000000000000000000000000000000000000000..e32e18010a3f3ed436547cfae86679ef00b21daa --- /dev/null +++ b/src/main/java/io/papermc/paper/datacomponent/item/LockCode.java @@ -0,0 +1,22 @@ @@ -1719,13 +2088,13 @@ index 0000000000000000000000000000000000000000..6386d859ec06ffd23553767d8f87d85e +public interface LockCode { + -+ @Contract(value = "_ -> new", pure = true) -+ static @NonNull LockCode lockCode(final @NonNull String code) { -+ return ItemComponentTypesBridge.bridge().lockCode(code); -+ } -+ -+ @Contract(pure = true) -+ @NonNull String key(); ++ // @Contract(value = "_ -> new", pure = true) ++ // static @NonNull LockCode lockCode(final @NonNull String code) { ++ // return ItemComponentTypesBridge.bridge().lockCode(code); ++ // } ++ // ++ // @Contract(pure = true) ++ // @NonNull String key(); +} diff --git a/src/main/java/io/papermc/paper/datacomponent/item/LodestoneTracker.java b/src/main/java/io/papermc/paper/datacomponent/item/LodestoneTracker.java new file mode 100644 @@ -2010,6 +2379,39 @@ index 0000000000000000000000000000000000000000..b385132b23c3f52f327f8a699fdb8cba + @NonNull Builder color(@NonNull Color color); + } +} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/OminiousBottleAmplifier.java b/src/main/java/io/papermc/paper/datacomponent/item/OminiousBottleAmplifier.java +new file mode 100644 +index 0000000000000000000000000000000000000000..73a14a0f9bf98bed1611eeb0285d9f89b76b401f +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/OminiousBottleAmplifier.java +@@ -0,0 +1,27 @@ ++package io.papermc.paper.datacomponent.item; ++ ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.Contract; ++ ++/** ++ * Holds the custom model data. ++ * @see io.papermc.paper.datacomponent.DataComponentTypes#CUSTOM_MODEL_DATA ++ */ ++public interface OminiousBottleAmplifier { ++ ++ @Contract(value = "_ -> new", pure = true) ++ static @NonNull OminiousBottleAmplifier amplifier(final int amplifier) { ++ return ItemComponentTypesBridge.bridge().ominiousBottleAmplifier(amplifier); ++ } ++ ++ /** ++ * Gets the bottle amplifier. ++ * ++ * @return the amplifier ++ */ ++ @Contract(pure = true) ++ int amplifier(); ++} diff --git a/src/main/java/io/papermc/paper/datacomponent/item/PotDecorations.java b/src/main/java/io/papermc/paper/datacomponent/item/PotDecorations.java new file mode 100644 index 0000000000000000000000000000000000000000..35958f84bf93270c53ad8b09483bab503d85aae3 @@ -2126,10 +2528,10 @@ index 0000000000000000000000000000000000000000..35958f84bf93270c53ad8b09483bab50 +} diff --git a/src/main/java/io/papermc/paper/datacomponent/item/PotionContents.java b/src/main/java/io/papermc/paper/datacomponent/item/PotionContents.java new file mode 100644 -index 0000000000000000000000000000000000000000..e212f5401312c64c6c25af19ba9dc8e511157409 +index 0000000000000000000000000000000000000000..8e16affd83ad0cb94b275246e0da621fbb5fb787 --- /dev/null +++ b/src/main/java/io/papermc/paper/datacomponent/item/PotionContents.java -@@ -0,0 +1,100 @@ +@@ -0,0 +1,118 @@ +package io.papermc.paper.datacomponent.item; + +import io.papermc.paper.datacomponent.DataComponentBuilder; @@ -2182,6 +2584,14 @@ index 0000000000000000000000000000000000000000..e212f5401312c64c6c25af19ba9dc8e5 + @Contract(pure = true) + @NonNull @Unmodifiable List<@NonNull PotionEffect> customEffects(); + ++ /** ++ * Overrides the visual name of the potion. ++ * ++ * @return name override, or {@code null} if not present ++ * @apiNote This is used in the display of tipped arrow and potion items. ++ */ ++ @Contract(pure = true) @Nullable String customName(); ++ + @ApiStatus.Experimental + @ApiStatus.NonExtendable + interface Builder extends DataComponentBuilder<PotionContents> { @@ -2208,6 +2618,16 @@ index 0000000000000000000000000000000000000000..e212f5401312c64c6c25af19ba9dc8e5 + @NonNull Builder customColor(@Nullable Color color); + + /** ++ * Sets the name override for this builder. ++ * ++ * @param name name ++ * @return the builder for chaining ++ * @see #customName() ++ */ ++ @Contract(value = "_ -> this", mutates = "this") ++ @NonNull Builder customName(@Nullable String name); ++ ++ /** + * Adds a custom effect instance to this builder. + * + * @param effect effect @@ -2230,6 +2650,45 @@ index 0000000000000000000000000000000000000000..e212f5401312c64c6c25af19ba9dc8e5 + @NonNull Builder addCustomEffects(@NonNull List<@NonNull PotionEffect> effects); + } +} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/Repairable.java b/src/main/java/io/papermc/paper/datacomponent/item/Repairable.java +new file mode 100644 +index 0000000000000000000000000000000000000000..928e61eef3f33af0d76e258661a163557fdf40f8 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/Repairable.java +@@ -0,0 +1,33 @@ ++package io.papermc.paper.datacomponent.item; ++ ++import io.papermc.paper.datacomponent.DataComponentBuilder; ++import io.papermc.paper.registry.set.RegistryKeySet; ++import org.bukkit.damage.DamageType; ++import org.bukkit.inventory.ItemType; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.Contract; ++ ++/** ++ * Holds if this item is repairable, and what item types it can be repaired with. ++ * @see io.papermc.paper.datacomponent.DataComponentTypes#REPAIRABLE ++ */ ++public interface Repairable { ++ ++ @Contract(value = "_ -> new", pure = true) ++ static @NonNull Repairable repairable(final @NonNull RegistryKeySet<ItemType> types) { ++ return ItemComponentTypesBridge.bridge().repairable(types); ++ } ++ ++ /** ++ * The types that this item is repairable to. ++ * ++ * @return item ++ */ ++ @Contract(value = "-> new", pure = true) ++ @NonNull ++ RegistryKeySet<ItemType> types(); ++ ++} diff --git a/src/main/java/io/papermc/paper/datacomponent/item/ResolvableProfile.java b/src/main/java/io/papermc/paper/datacomponent/item/ResolvableProfile.java new file mode 100644 index 0000000000000000000000000000000000000000..85d9a14b3f8abf99793118e5d66cbf3eca66616a @@ -2729,6 +3188,137 @@ index 0000000000000000000000000000000000000000..a8ddecde35b427f594395a5df5420a20 + interface Builder extends ShownInTooltip.Builder<Builder>, DataComponentBuilder<Unbreakable> { + } +} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/UseCooldown.java b/src/main/java/io/papermc/paper/datacomponent/item/UseCooldown.java +new file mode 100644 +index 0000000000000000000000000000000000000000..84ac174f53dfc84f9c20783b70c7fb5a679b1752 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/UseCooldown.java +@@ -0,0 +1,71 @@ ++package io.papermc.paper.datacomponent.item; ++ ++import io.papermc.paper.datacomponent.DataComponentBuilder; ++import java.util.List; ++import net.kyori.adventure.key.Key; ++import org.bukkit.Color; ++import org.bukkit.NamespacedKey; ++import org.bukkit.potion.PotionEffect; ++import org.bukkit.potion.PotionType; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.Contract; ++import org.jetbrains.annotations.Unmodifiable; ++ ++/** ++ * Holds the contents of cooldown information when an item is used. ++ * @see io.papermc.paper.datacomponent.DataComponentTypes#USE_COOLDOWN ++ */ ++public interface UseCooldown { ++ ++ /** ++ * Creates a new builder for use cooldown. ++ * ++ * @param seconds the duration in seconds; must be positive ++ * @return builder ++ */ ++ @Contract(value = "_ -> new", pure = true) ++ static UseCooldown.@NonNull Builder useCooldown(float seconds) { ++ return ItemComponentTypesBridge.bridge().useCooldown(seconds); ++ } ++ ++ /** ++ * The amount of seconds the cooldown will be active for. ++ * ++ * @return cooldown seconds ++ */ ++ @Contract(pure = true) ++ float seconds(); ++ ++ /** ++ * The unique resource location to identify this cooldown group. ++ * <p> ++ * This allows items to share cooldowns with other items in the same cooldown group, if present. ++ * ++ * @return cooldown group, or null if not present ++ */ ++ @Contract(pure = true) ++ @Nullable ++ Key cooldownGroup(); ++ ++ @ApiStatus.Experimental ++ @ApiStatus.NonExtendable ++ interface Builder extends DataComponentBuilder<UseCooldown> { ++ ++ /** ++ * Sets a unique resource location for this cooldown group. ++ * <p> ++ * This allows items to share cooldowns with other items in the same cooldown group. ++ * </p> ++ * ++ * @param key the unique resource location; can be null ++ * @return the builder for chaining ++ * @see #cooldownGroup() ++ */ ++ @Contract(value = "_ -> this", mutates = "this") ++ @NonNull Builder cooldownGroup(@Nullable Key key); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/UseRemainder.java b/src/main/java/io/papermc/paper/datacomponent/item/UseRemainder.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c80d5bf7ddaa24de0c7d2f812f1538b020d3ad69 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/UseRemainder.java +@@ -0,0 +1,48 @@ ++package io.papermc.paper.datacomponent.item; ++ ++import io.papermc.paper.datacomponent.DataComponentBuilder; ++import org.bukkit.Color; ++import org.bukkit.inventory.ItemStack; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.Contract; ++ ++/** ++ * Holds the contents of item transformation information when an item is used. ++ * @see io.papermc.paper.datacomponent.DataComponentTypes#USE_REMAINDER ++ */ ++public interface UseRemainder { ++ ++ @Contract(value = "_ -> new", pure = true) ++ static @NonNull UseRemainder useRemainder(final @NonNull ItemStack itemStack) { ++ return ItemComponentTypesBridge.bridge().useRemainder(itemStack); ++ } ++ ++ /** ++ * The item that the item that is consumed is transformed into. ++ * ++ * @return item ++ */ ++ @Contract(value = "-> new", pure = true) ++ @NonNull ItemStack transformInto(); ++ ++ /** ++ * Builder for {@link UseRemainder}. ++ */ ++ @ApiStatus.Experimental ++ @ApiStatus.NonExtendable ++ interface Builder extends ShownInTooltip.Builder<Builder>, DataComponentBuilder<UseRemainder> { ++ ++ /** ++ * Sets the transform item of this builder. ++ * ++ * @param itemStack item ++ * @return the builder for chaining ++ * @see #transformInto() ++ */ ++ @Contract(value = "_ -> this", mutates = "this") ++ @NonNull Builder transformInto(@NonNull ItemStack itemStack); ++ } ++} diff --git a/src/main/java/io/papermc/paper/datacomponent/item/WritableBookContent.java b/src/main/java/io/papermc/paper/datacomponent/item/WritableBookContent.java new file mode 100644 index 0000000000000000000000000000000000000000..eb6042af2d5d0c63f1adc56576a4e6b80bb31463 @@ -2993,6 +3583,289 @@ index 0000000000000000000000000000000000000000..a8f86b9ec871857106903715749bbbe4 + @NonNull Builder addFilteredPages(@NonNull Collection<@NonNull Filtered<@NonNull ? extends ComponentLike>> pages); + } +} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/consumable/ApplyStatusEffectsConsumeEffect.java b/src/main/java/io/papermc/paper/datacomponent/item/consumable/ApplyStatusEffectsConsumeEffect.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d11d4563e20916000d2d4cb754e7c1e386386bfb +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/consumable/ApplyStatusEffectsConsumeEffect.java +@@ -0,0 +1,39 @@ ++package io.papermc.paper.datacomponent.item.consumable; ++ ++import org.bukkit.potion.PotionEffect; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.jetbrains.annotations.Contract; ++import java.util.List; ++ ++/** ++ * Represents a consumable effect that applies effects based on a probability on consumption. ++ */ ++public interface ApplyStatusEffectsConsumeEffect extends ConsumeEffect { ++ ++ /** ++ * Creates a consume effect that gives status effects on consumption. ++ * ++ * @param effects the potion effects to apply ++ * @param probability the probability of these effects being applied, between 0 and 1 inclusive. ++ * @return the effect ++ */ ++ @Contract(value = "_, _ -> new", pure = true) ++ static @NonNull ApplyStatusEffectsConsumeEffect applyStatusEffects(final @NonNull List<PotionEffect> effects, final float probability) { ++ return ConsumableTypesBridge.bridge().applyStatusEffects(effects, probability); ++ } ++ ++ /** ++ * Effect instances to grant ++ * ++ * @return effect ++ */ ++ @NonNull List<PotionEffect> effects(); ++ ++ /** ++ * Float between 0 and 1, chance for the effect to be applied. ++ * ++ * @return chance ++ */ ++ float probability(); ++ ++} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/consumable/ClearAllStatusEffectsConsumeEffect.java b/src/main/java/io/papermc/paper/datacomponent/item/consumable/ClearAllStatusEffectsConsumeEffect.java +new file mode 100644 +index 0000000000000000000000000000000000000000..97208df2e8ffbb653a96da34534fd6a08e5a141c +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/consumable/ClearAllStatusEffectsConsumeEffect.java +@@ -0,0 +1,22 @@ ++package io.papermc.paper.datacomponent.item.consumable; ++ ++import org.bukkit.potion.PotionEffect; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.jetbrains.annotations.Contract; ++import java.util.List; ++ ++/** ++ * Represents a consumable effect that clears all effects on consumption. ++ */ ++public interface ClearAllStatusEffectsConsumeEffect extends ConsumeEffect { ++ ++ /** ++ * Creates a consume effect that clears all status effects. ++ * ++ * @return effect instance ++ */ ++ @Contract(value = "-> new", pure = true) ++ static @NonNull ClearAllStatusEffectsConsumeEffect clearAllStatusEffects() { ++ return ConsumableTypesBridge.bridge().clearAllStatusEffects(); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/consumable/ConsumableTypesBridge.java b/src/main/java/io/papermc/paper/datacomponent/item/consumable/ConsumableTypesBridge.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e11b697e93126fa1b7342a4a872220130184374c +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/consumable/ConsumableTypesBridge.java +@@ -0,0 +1,40 @@ ++package io.papermc.paper.datacomponent.item.consumable; ++ ++import com.destroystokyo.paper.profile.PlayerProfile; ++import io.papermc.paper.registry.set.RegistryKeySet; ++import io.papermc.paper.registry.tag.TagKey; ++import io.papermc.paper.util.Filtered; ++import net.kyori.adventure.key.Key; ++import net.kyori.adventure.util.TriState; ++import org.bukkit.JukeboxSong; ++import org.bukkit.block.BlockType; ++import org.bukkit.inventory.meta.trim.ArmorTrim; ++import org.bukkit.map.MapCursor; ++import org.bukkit.potion.PotionEffect; ++import org.bukkit.potion.PotionEffectType; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.jetbrains.annotations.ApiStatus; ++import java.util.List; ++import java.util.Optional; ++import java.util.ServiceLoader; ++ ++interface ConsumableTypesBridge { ++ ++ Optional<ConsumableTypesBridge> BRIDGE = ServiceLoader.load(ConsumableTypesBridge.class).findFirst(); ++ ++ static ConsumableTypesBridge bridge() { ++ return BRIDGE.orElseThrow(); ++ } ++ ++ ApplyStatusEffectsConsumeEffect applyStatusEffects(List<PotionEffect> effectList, float probability); ++ ++ RemoveStatusEffectsConsumeEffect removeStatusEffects(RegistryKeySet<PotionEffectType> potionEffectTypeTagKey); ++ ++ ClearAllStatusEffectsConsumeEffect clearAllStatusEffects(); ++ ++ PlaySoundConsumeEffect playSoundEffect(Key sound); ++ ++ TeleportRandomlyConsumeEffect teleportRandomlyEffect(float diameter); ++ ++} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/consumable/ConsumeEffect.java b/src/main/java/io/papermc/paper/datacomponent/item/consumable/ConsumeEffect.java +new file mode 100644 +index 0000000000000000000000000000000000000000..50b06f14d611fc189873f652d4769484ceea4703 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/consumable/ConsumeEffect.java +@@ -0,0 +1,18 @@ ++package io.papermc.paper.datacomponent.item.consumable; ++ ++import io.papermc.paper.datacomponent.item.Consumable; ++import org.bukkit.potion.PotionEffect; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.Contract; ++ ++import java.util.List; ++ ++/** ++ * Effect that occurs when consuming an item. ++ */ ++public ++interface ConsumeEffect { ++ ++} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/consumable/ItemUseAnimation.java b/src/main/java/io/papermc/paper/datacomponent/item/consumable/ItemUseAnimation.java +new file mode 100644 +index 0000000000000000000000000000000000000000..8cd6dbe4ea5ee3270b9428a9c29cbd88823d9f6c +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/consumable/ItemUseAnimation.java +@@ -0,0 +1,17 @@ ++package io.papermc.paper.datacomponent.item.consumable; ++ ++/** ++ * Represents the hand animation that is used when a player is consuming this item. ++ */ ++public enum ItemUseAnimation { ++ NONE, ++ EAT, ++ DRINK, ++ BLOCK, ++ BOW, ++ SPEAR, ++ CROSSBOW, ++ SPYGLASS, ++ TOOT_HORN, ++ BRUSH ++} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/consumable/PlaySoundConsumeEffect.java b/src/main/java/io/papermc/paper/datacomponent/item/consumable/PlaySoundConsumeEffect.java +new file mode 100644 +index 0000000000000000000000000000000000000000..82c232a1acc1ec93303cc03c40dc855bd8c36284 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/consumable/PlaySoundConsumeEffect.java +@@ -0,0 +1,35 @@ ++package io.papermc.paper.datacomponent.item.consumable; ++ ++import net.kyori.adventure.key.Key; ++import org.bukkit.potion.PotionEffect; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.jetbrains.annotations.Contract; ++import org.jetbrains.annotations.NotNull; ++import java.util.List; ++ ++/** ++ * Represents a consumable effect that plays a sound on consumption. ++ */ ++public interface PlaySoundConsumeEffect extends ConsumeEffect { ++ ++ /** ++ * Creates a consume effect that plays a sound on consumption. ++ * ++ * @param key the sound effect to play ++ * @return the effect ++ */ ++ @Contract(value = "_ -> new", pure = true) ++ static @NonNull PlaySoundConsumeEffect playSoundConsumeEffect(final @NotNull Key key) { ++ return ConsumableTypesBridge.bridge().playSoundEffect(key); ++ } ++ ++ /** ++ * Sound effect to play in the world ++ * ++ * @return sound effect ++ */ ++ @NonNull ++ Key sound(); ++ ++ ++} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/consumable/RemoveStatusEffectsConsumeEffect.java b/src/main/java/io/papermc/paper/datacomponent/item/consumable/RemoveStatusEffectsConsumeEffect.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9190034759052ef643181df12fdbf94d971cc07e +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/consumable/RemoveStatusEffectsConsumeEffect.java +@@ -0,0 +1,36 @@ ++package io.papermc.paper.datacomponent.item.consumable; ++ ++ ++import io.papermc.paper.registry.set.RegistryKeySet; ++import net.kyori.adventure.key.Key; ++import org.bukkit.inventory.ItemType; ++import org.bukkit.potion.PotionEffectType; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.jetbrains.annotations.Contract; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * Represents a consumable effect that removes status effects on consumption ++ */ ++public interface RemoveStatusEffectsConsumeEffect extends ConsumeEffect { ++ ++ /** ++ * Creates a consume effect that gives status effects on consumption. ++ * ++ * @param key the sound effect to play ++ * @return the effect ++ */ ++ @Contract(value = "_ -> new", pure = true) ++ static @NonNull RemoveStatusEffectsConsumeEffect removeEffects(final @NotNull RegistryKeySet<PotionEffectType> key) { ++ return ConsumableTypesBridge.bridge().removeStatusEffects(key); ++ } ++ ++ /** ++ * Potion effects to remove ++ * ++ * @return effects ++ */ ++ @NonNull ++ RegistryKeySet<PotionEffectType> removeEffects(); ++ ++} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/consumable/TeleportRandomlyConsumeEffect.java b/src/main/java/io/papermc/paper/datacomponent/item/consumable/TeleportRandomlyConsumeEffect.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4f765f322a6ba69978411e453f772fc786b5cdf7 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/consumable/TeleportRandomlyConsumeEffect.java +@@ -0,0 +1,28 @@ ++package io.papermc.paper.datacomponent.item.consumable; ++ ++import io.papermc.paper.registry.set.RegistryKeySet; ++import org.bukkit.potion.PotionEffectType; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.jetbrains.annotations.Contract; ++ ++public interface TeleportRandomlyConsumeEffect extends ConsumeEffect { ++ ++ /** ++ * Creates a consume effect that randomly teleports the entity on consumption. ++ * ++ * @param diameter diameter of random teleportation ++ * @return the effect ++ */ ++ @Contract(value = "_ -> new", pure = true) ++ static @NonNull TeleportRandomlyConsumeEffect teleportRandomlyEffect(final float diameter) { ++ return ConsumableTypesBridge.bridge().teleportRandomlyEffect(diameter); ++ } ++ ++ /** ++ * The max range that the entity can be teleported to. ++ * ++ * @return teleportation diameter ++ */ ++ float diameter(); ++ ++} diff --git a/src/main/java/io/papermc/paper/datacomponent/package-info.java b/src/main/java/io/papermc/paper/datacomponent/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..3ddd1f787e97c22eee3e32bb2a9660a8e300d7f9 @@ -3017,7 +3890,7 @@ index 0000000000000000000000000000000000000000..5843768d0be2ae4a0219636ed7640727 + SCALE +} diff --git a/src/main/java/io/papermc/paper/registry/RegistryKey.java b/src/main/java/io/papermc/paper/registry/RegistryKey.java -index 2945dde566682f977e84fde5d473a6c69be24df1..530cbadc8b4871113dc9ebb24bc565a95a61fdae 100644 +index d8716f855806471728c35b3ec34efb808a5146cf..cf8a28a6e41fadeeffe358e5bcdc25bf6c351aea 100644 --- a/src/main/java/io/papermc/paper/registry/RegistryKey.java +++ b/src/main/java/io/papermc/paper/registry/RegistryKey.java @@ -1,5 +1,6 @@ @@ -3027,13 +3900,10 @@ index 2945dde566682f977e84fde5d473a6c69be24df1..530cbadc8b4871113dc9ebb24bc565a9 import net.kyori.adventure.key.Keyed; import org.bukkit.Art; import org.bukkit.Fluid; -@@ -81,6 +82,10 @@ public sealed interface RegistryKey<T> extends Keyed permits RegistryKeyImpl { +@@ -114,6 +115,7 @@ public sealed interface RegistryKey<T> extends Keyed permits RegistryKeyImpl { + * @see io.papermc.paper.registry.keys.MenuTypeKeys */ - @ApiStatus.Experimental // Paper - already required for registry builders - RegistryKey<ItemType> ITEM = create("item"); -+ /** -+ * Built-in registry for data component types. -+ */ + RegistryKey<MenuType> MENU = create("menu"); + RegistryKey<DataComponentType> DATA_COMPONENT_TYPE = create("data_component_type"); @@ -3075,10 +3945,10 @@ index 0000000000000000000000000000000000000000..6919f01a18bc0ab375d2e05412065243 + @Nullable T filtered(); +} diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java -index 54704da43cf9c429f3914f0580246dde99aa93c0..87bc4ce78350d95b9337262ba585b44c77213722 100644 +index 615eb24ffdd8f6d55ccd4f21760b809c1098bc68..1b3e120bb9b10b65eb6225af8f08caed5973007d 100644 --- a/src/main/java/org/bukkit/Material.java +++ b/src/main/java/org/bukkit/Material.java -@@ -130,7 +130,7 @@ import org.jetbrains.annotations.Nullable; +@@ -137,7 +137,7 @@ import org.jetbrains.annotations.Nullable; @SuppressWarnings({"DeprecatedIsStillUsed", "deprecation"}) // Paper public enum Material implements Keyed, Translatable, net.kyori.adventure.translation.Translatable { // Paper //<editor-fold desc="Materials" defaultstate="collapsed"> @@ -3087,25 +3957,21 @@ index 54704da43cf9c429f3914f0580246dde99aa93c0..87bc4ce78350d95b9337262ba585b44c STONE(22948), GRANITE(21091), POLISHED_GRANITE(5477), -@@ -5599,6 +5599,7 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla +@@ -5784,6 +5784,7 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla */ @ApiStatus.Internal @Nullable + @org.jetbrains.annotations.Contract(pure = true) // Paper public ItemType asItemType() { - Material material = this; - if (isLegacy()) { -@@ -5615,6 +5616,7 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla + return itemType.get(); + } +@@ -5796,7 +5797,47 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla */ @ApiStatus.Internal @Nullable + @org.jetbrains.annotations.Contract(pure = true) // Paper public BlockType asBlockType() { - Material material = this; - if (isLegacy()) { -@@ -5622,4 +5624,43 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla - } - return Registry.BLOCK.get(material.key); + return blockType.get(); } + + // Paper start - data component API @@ -3148,23 +4014,22 @@ index 54704da43cf9c429f3914f0580246dde99aa93c0..87bc4ce78350d95b9337262ba585b44c + // Paper end - data component API } diff --git a/src/main/java/org/bukkit/Registry.java b/src/main/java/org/bukkit/Registry.java -index 20015393f91af405c99db2635a471fb6ff19e4bf..7ab29c3d0471d5eb2152ff749efc15ac9d24acf8 100644 +index b4ef3133fdd9d79a3381cf8f659ff561ab2b4fad..d3c9fb2fd625ed6ae4882c3b16b86f324f236161 100644 --- a/src/main/java/org/bukkit/Registry.java +++ b/src/main/java/org/bukkit/Registry.java -@@ -349,6 +349,8 @@ public interface Registry<T extends Keyed> extends Iterable<T> { - return StreamSupport.stream(this.spliterator(), false); - } - }; -+ -+ Registry<io.papermc.paper.datacomponent.DataComponentType> DATA_COMPONENT_TYPE = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.DATA_COMPONENT_TYPE); // Paper +@@ -370,6 +370,7 @@ public interface Registry<T extends Keyed> extends Iterable<T> { + */ + Registry<org.bukkit.potion.PotionEffectType> POTION_EFFECT_TYPE = EFFECT; // Paper end - potion effect type registry ++ Registry<io.papermc.paper.datacomponent.DataComponentType> DATA_COMPONENT_TYPE = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.DATA_COMPONENT_TYPE); // Paper /** * Get the object by its key. + * diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java -index b3abe3bde05d4a360e31e490bff8a859dc2bd4a6..794b3cf36f6ce4fb2c7957a4b259f8adf63090f3 100644 +index b59222b8c262545d100a9fd28b3bf1d2a4cf4eb0..ef254ecf202e85afec2919baf6075ad44dbcab53 100644 --- a/src/main/java/org/bukkit/inventory/ItemStack.java +++ b/src/main/java/org/bukkit/inventory/ItemStack.java -@@ -1,10 +1,10 @@ +@@ -1,10 +1,11 @@ package org.bukkit.inventory; import com.google.common.base.Preconditions; @@ -3173,10 +4038,11 @@ index b3abe3bde05d4a360e31e490bff8a859dc2bd4a6..794b3cf36f6ce4fb2c7957a4b259f8ad import java.util.Locale; import java.util.Map; +import io.papermc.paper.datacomponent.DataComponentBuilder; ++import io.papermc.paper.datacomponent.DataComponentType; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.NamespacedKey; -@@ -1033,4 +1033,149 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat +@@ -1137,4 +1138,173 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat return Bukkit.getUnsafe().computeTooltipLines(this, tooltipContext, player); } // Paper end - expose itemstack tooltip lines @@ -3248,6 +4114,30 @@ index b3abe3bde05d4a360e31e490bff8a859dc2bd4a6..794b3cf36f6ce4fb2c7957a4b259f8ad + } + + /** ++ * Modifies the value of the specified data component type for this item stack based on the result ++ * of applying a given function to the current value. ++ * ++ * <p>If the function returns {@code null}, the data component type will be reset using ++ * {@link #unsetData(DataComponentType)}. Otherwise, the ++ * component value will be updated with the new result using {@link #setData(DataComponentType.Valued, Object)}.</p> ++ * ++ * @param <T> the type of the data component's value ++ * @param type the data component type to be modified ++ * @param consumer a function that takes the current component value (can be {@code null}) and ++ * returns the modified value (or {@code null} to unset) ++ */ ++ @Utility ++ public <T> void editData(final io.papermc.paper.datacomponent.DataComponentType.@NotNull Valued<T> type, final @NotNull java.util.function.Function<@Nullable T, @Nullable T> consumer) { ++ T value = getData(type); ++ T newType = consumer.apply(value); ++ if (newType == null) { ++ unsetData(type); ++ } else { ++ setData(type, newType); ++ } ++ } ++ ++ /** + * Sets the value of the data component type for this itemstack. To + * reset the value to the default for the {@link #getType() item type}, use + * {@link #resetData(io.papermc.paper.datacomponent.DataComponentType)}. To mark the data component type @@ -3327,10 +4217,10 @@ index b3abe3bde05d4a360e31e490bff8a859dc2bd4a6..794b3cf36f6ce4fb2c7957a4b259f8ad + // 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 0168f0a14a3e899e84c5e36963ff79950ab580fb..6d0466a8a54531eaf51521b10047a27ef83d47b7 100644 +index 72803c00e4af576f286d2af34bf300ee554a7f3c..9769726ec1e227606a79ccab1e8e439ef9ec16c1 100644 --- a/src/main/java/org/bukkit/inventory/ItemType.java +++ b/src/main/java/org/bukkit/inventory/ItemType.java -@@ -2336,4 +2336,30 @@ public interface ItemType extends Keyed, Translatable, net.kyori.adventure.trans +@@ -2483,4 +2483,30 @@ public interface ItemType extends Keyed, Translatable, net.kyori.adventure.trans */ @Nullable ItemRarity getItemRarity(); // Paper end - expand ItemRarity API diff --git a/patches/server/1044-WIP-DataComponent-API.patch b/patches/server/1058-WIP-DataComponent-API.patch index 99c2f3ddaa..6e42b123d4 100644 --- a/patches/server/1044-WIP-DataComponent-API.patch +++ b/patches/server/1058-WIP-DataComponent-API.patch @@ -8,7 +8,7 @@ public net/minecraft/world/item/component/ItemContainerContents MAX_SIZE public net/minecraft/world/item/component/ItemContainerContents items diff --git a/src/main/java/io/papermc/paper/adventure/PaperAdventure.java b/src/main/java/io/papermc/paper/adventure/PaperAdventure.java -index 22fe529890f34f66534c01248f654dc911b44c3b..6a1908d0eca04af885171cde44f419478048064e 100644 +index cfcaf215c4a901dd2938c7ce41db502c57b42bbf..e735cc98c53b62defa02d80f4b185641b5e27ae8 100644 --- a/src/main/java/io/papermc/paper/adventure/PaperAdventure.java +++ b/src/main/java/io/papermc/paper/adventure/PaperAdventure.java @@ -149,6 +149,10 @@ public final class PaperAdventure { @@ -66,10 +66,10 @@ index 0000000000000000000000000000000000000000..08c717590a34584c359408c49c69379c +} diff --git a/src/main/java/io/papermc/paper/datacomponent/ComponentAdapters.java b/src/main/java/io/papermc/paper/datacomponent/ComponentAdapters.java new file mode 100644 -index 0000000000000000000000000000000000000000..04742f12afc523aa1748f94b4bad8536074fff87 +index 0000000000000000000000000000000000000000..1c861bd7773cbfce8c74403b9308c327580232cc --- /dev/null +++ b/src/main/java/io/papermc/paper/datacomponent/ComponentAdapters.java -@@ -0,0 +1,172 @@ +@@ -0,0 +1,195 @@ +package io.papermc.paper.datacomponent; + +import com.mojang.brigadier.exceptions.CommandSyntaxException; @@ -78,8 +78,13 @@ index 0000000000000000000000000000000000000000..04742f12afc523aa1748f94b4bad8536 +import io.papermc.paper.datacomponent.item.PaperBlockItemDataProperties; +import io.papermc.paper.datacomponent.item.PaperBundleContents; +import io.papermc.paper.datacomponent.item.PaperChargedProjectiles; ++import io.papermc.paper.datacomponent.item.PaperConsumable; +import io.papermc.paper.datacomponent.item.PaperCustomModelData; ++import io.papermc.paper.datacomponent.item.PaperDamageResistant; ++import io.papermc.paper.datacomponent.item.PaperDeathProtection; +import io.papermc.paper.datacomponent.item.PaperDyedItemColor; ++import io.papermc.paper.datacomponent.item.PaperEnchantable; ++import io.papermc.paper.datacomponent.item.PaperEquippable; +import io.papermc.paper.datacomponent.item.PaperFireworks; +import io.papermc.paper.datacomponent.item.PaperFoodProperties; +import io.papermc.paper.datacomponent.item.PaperItemAdventurePredicate; @@ -95,23 +100,29 @@ index 0000000000000000000000000000000000000000..04742f12afc523aa1748f94b4bad8536 +import io.papermc.paper.datacomponent.item.PaperMapDecorations; +import io.papermc.paper.datacomponent.item.PaperMapId; +import io.papermc.paper.datacomponent.item.PaperMapItemColor; ++import io.papermc.paper.datacomponent.item.PaperOminousBottleAmplifier; +import io.papermc.paper.datacomponent.item.PaperPotDecorations; +import io.papermc.paper.datacomponent.item.PaperPotionContents; ++import io.papermc.paper.datacomponent.item.PaperRepairable; +import io.papermc.paper.datacomponent.item.PaperResolvableProfile; +import io.papermc.paper.datacomponent.item.PaperSeededContainerLoot; +import io.papermc.paper.datacomponent.item.PaperSuspiciousStewEffects; +import io.papermc.paper.datacomponent.item.PaperUnbreakable; ++import io.papermc.paper.datacomponent.item.PaperUseCooldown; ++import io.papermc.paper.datacomponent.item.PaperUseRemainder; +import io.papermc.paper.datacomponent.item.PaperWritableBookContent; +import io.papermc.paper.datacomponent.item.PaperWrittenBookContent; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; ++import io.papermc.paper.registry.PaperRegistries; +import net.minecraft.core.component.DataComponentType; +import net.minecraft.core.component.DataComponents; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; +import net.minecraft.resources.ResourceKey; ++import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Unit; +import net.minecraft.world.LockCode; +import net.minecraft.world.item.Rarity; @@ -124,6 +135,7 @@ index 0000000000000000000000000000000000000000..04742f12afc523aa1748f94b4bad8536 +import org.bukkit.DyeColor; +import org.bukkit.craftbukkit.CraftMusicInstrument; +import org.bukkit.craftbukkit.inventory.CraftMetaFirework; ++import org.bukkit.craftbukkit.util.CraftNamespacedKey; +import org.bukkit.craftbukkit.util.Handleable; +import org.bukkit.inventory.ItemRarity; +import org.checkerframework.checker.nullness.qual.NonNull; @@ -159,6 +171,8 @@ index 0000000000000000000000000000000000000000..04742f12afc523aa1748f94b4bad8536 + register(DataComponents.UNBREAKABLE, PaperUnbreakable::new); + register(DataComponents.CUSTOM_NAME, PaperAdventure::asAdventure, PaperAdventure::asVanilla); + register(DataComponents.ITEM_NAME, PaperAdventure::asAdventure, PaperAdventure::asVanilla); ++ register(DataComponents.ITEM_MODEL, CraftNamespacedKey::fromMinecraft, CraftNamespacedKey::toMinecraft); ++ + register(DataComponents.LORE, PaperItemLore::new); + register(DataComponents.RARITY, nms -> ItemRarity.valueOf(nms.name()), api -> Rarity.valueOf(api.name())); + register(DataComponents.ENCHANTMENTS, PaperItemEnchantments::new); @@ -173,8 +187,17 @@ index 0000000000000000000000000000000000000000..04742f12afc523aa1748f94b4bad8536 + registerIdentity(DataComponents.ENCHANTMENT_GLINT_OVERRIDE); + registerUntyped(DataComponents.INTANGIBLE_PROJECTILE); + register(DataComponents.FOOD, PaperFoodProperties::new); -+ registerUntyped(DataComponents.FIRE_RESISTANT); ++ register(DataComponents.CONSUMABLE, PaperConsumable::new); ++ register(DataComponents.USE_REMAINDER, PaperUseRemainder::new); ++ register(DataComponents.USE_COOLDOWN, PaperUseCooldown::new); ++ register(DataComponents.DAMAGE_RESISTANT, PaperDamageResistant::new); + register(DataComponents.TOOL, PaperItemTool::new); ++ register(DataComponents.ENCHANTABLE, PaperEnchantable::new); ++ register(DataComponents.EQUIPPABLE, PaperEquippable::new); ++ register(DataComponents.REPAIRABLE, PaperRepairable::new); ++ registerUntyped(DataComponents.GLIDER); ++ register(DataComponents.TOOLTIP_STYLE, PaperAdventure::asAdventure, PaperAdventure::asVanilla); ++ register(DataComponents.DEATH_PROTECTION, PaperDeathProtection::new); + register(DataComponents.STORED_ENCHANTMENTS, PaperItemEnchantments::new); + register(DataComponents.DYED_COLOR, PaperDyedItemColor::new); + register(DataComponents.MAP_COLOR, PaperMapItemColor::new); @@ -193,9 +216,9 @@ index 0000000000000000000000000000000000000000..04742f12afc523aa1748f94b4bad8536 + // bucket entity data + // block entity data + register(DataComponents.INSTRUMENT, CraftMusicInstrument::minecraftHolderToBukkit, CraftMusicInstrument::bukkitToMinecraftHolder); -+ registerIdentity(DataComponents.OMINOUS_BOTTLE_AMPLIFIER); ++ register(DataComponents.OMINOUS_BOTTLE_AMPLIFIER, PaperOminousBottleAmplifier::new); + register(DataComponents.JUKEBOX_PLAYABLE, PaperJukeboxPlayable::new); -+ register(DataComponents.RECIPES, nms -> transform(nms, PaperAdventure::asAdventure), api -> transform(api, PaperAdventure::asVanilla)); ++ register(DataComponents.RECIPES, nms -> transform(nms, PaperRegistries::fromNms), api -> transform(api, PaperRegistries::toNms)); + register(DataComponents.LODESTONE_TRACKER, PaperLodestoneTracker::new); + register(DataComponents.FIREWORK_EXPLOSION, CraftMetaFirework::getEffect, CraftMetaFirework::getExplosion); + register(DataComponents.FIREWORKS, PaperFireworks::new); @@ -244,10 +267,10 @@ index 0000000000000000000000000000000000000000..04742f12afc523aa1748f94b4bad8536 +} diff --git a/src/main/java/io/papermc/paper/datacomponent/ComponentUtils.java b/src/main/java/io/papermc/paper/datacomponent/ComponentUtils.java new file mode 100644 -index 0000000000000000000000000000000000000000..07e268941d95c315592e3464c3ea08023205813e +index 0000000000000000000000000000000000000000..b169ea527559cfb3608037c71dedd366a14f5790 --- /dev/null +++ b/src/main/java/io/papermc/paper/datacomponent/ComponentUtils.java -@@ -0,0 +1,31 @@ +@@ -0,0 +1,42 @@ +package io.papermc.paper.datacomponent; + +import com.google.common.collect.Collections2; @@ -256,6 +279,12 @@ index 0000000000000000000000000000000000000000..07e268941d95c315592e3464c3ea0802 +import java.util.Collections; +import java.util.List; +import java.util.function.Function; ++import io.papermc.paper.adventure.PaperAdventure; ++import net.kyori.adventure.key.Key; ++import net.minecraft.core.Holder; ++import net.minecraft.core.registries.BuiltInRegistries; ++import net.minecraft.resources.ResourceLocation; ++import net.minecraft.sounds.SoundEvent; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.framework.qual.DefaultQualifier; + @@ -265,6 +294,11 @@ index 0000000000000000000000000000000000000000..07e268941d95c315592e3464c3ea0802 + private ComponentUtils() { + } + ++ public static Holder<SoundEvent> keyToSound(Key key) { ++ ResourceLocation soundId = PaperAdventure.asVanilla(key); ++ return BuiltInRegistries.SOUND_EVENT.wrapAsHolder(BuiltInRegistries.SOUND_EVENT.getOptional(soundId).orElse(SoundEvent.createVariableRangeEvent(soundId))); ++ } ++ + public static <A, M> List<A> transform(final List<? extends M> nms, final Function<? super M, ? extends A> converter) { + return Collections.unmodifiableList(Lists.transform(nms, converter::apply)); + } @@ -399,22 +433,32 @@ index 0000000000000000000000000000000000000000..74e883d50477b3b4dabdcb674d95e92e +} diff --git a/src/main/java/io/papermc/paper/datacomponent/item/ItemComponentTypesBridgesImpl.java b/src/main/java/io/papermc/paper/datacomponent/item/ItemComponentTypesBridgesImpl.java new file mode 100644 -index 0000000000000000000000000000000000000000..10da83e8c871ba464e124ff011497d5de37b8d8a +index 0000000000000000000000000000000000000000..32266842261fe62ff50925782e69b2ec4f48a653 --- /dev/null +++ b/src/main/java/io/papermc/paper/datacomponent/item/ItemComponentTypesBridgesImpl.java -@@ -0,0 +1,184 @@ +@@ -0,0 +1,235 @@ +package io.papermc.paper.datacomponent.item; + +import com.destroystokyo.paper.profile.PlayerProfile; ++import io.papermc.paper.registry.PaperRegistries; ++import io.papermc.paper.registry.set.PaperRegistrySets; +import io.papermc.paper.registry.set.RegistryKeySet; ++import io.papermc.paper.registry.tag.TagKey; +import io.papermc.paper.util.Filtered; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.util.TriState; ++import net.minecraft.core.registries.BuiltInRegistries; ++import net.minecraft.core.registries.Registries; ++import net.minecraft.world.item.component.OminousBottleAmplifier; +import org.bukkit.JukeboxSong; +import org.bukkit.block.BlockType; ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.damage.DamageType; ++import org.bukkit.inventory.EquipmentSlot; ++import org.bukkit.inventory.ItemStack; ++import org.bukkit.inventory.ItemType; +import org.bukkit.inventory.meta.trim.ArmorTrim; +import org.bukkit.map.MapCursor; -+import org.bukkit.potion.PotionEffect; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.DefaultQualifier; @@ -458,11 +502,6 @@ index 0000000000000000000000000000000000000000..10da83e8c871ba464e124ff011497d5d + } + + @Override -+ public FoodProperties.PossibleEffect foodEffect(final PotionEffect effect, final float probability) { -+ return PaperFoodProperties.PossibleEffectImpl.toApi(effect, probability); -+ } -+ -+ @Override + public DyedItemColor.Builder dyedItemColor() { + return new PaperDyedItemColor.BuilderImpl(); + } @@ -578,14 +617,60 @@ index 0000000000000000000000000000000000000000..10da83e8c871ba464e124ff011497d5d + } + + @Override -+ public LockCode lockCode(final String code) { -+ return new PaperLockCode(new net.minecraft.world.LockCode(code)); ++ public UseRemainder useRemainder(final ItemStack itemStack) { ++ return new PaperUseRemainder( ++ new net.minecraft.world.item.component.UseRemainder(CraftItemStack.asNMSCopy(itemStack)) ++ ); ++ } ++ ++ @Override ++ public Consumable.Builder consumable() { ++ return new PaperConsumable.BuilderImpl(); ++ } ++ ++ @Override ++ public UseCooldown.Builder useCooldown(final float seconds) { ++ return new PaperUseCooldown.BuilderImpl(seconds); ++ } ++ ++ @Override ++ public DamageResistant damageResistant(final TagKey<DamageType> types) { ++ return new PaperDamageResistant(new net.minecraft.world.item.component.DamageResistant(PaperRegistries.toNms(types))); ++ } ++ ++ @Override ++ public Enchantable enchantable(final int level) { ++ return new PaperEnchantable(new net.minecraft.world.item.enchantment.Enchantable(level)); ++ } ++ ++ @Override ++ public Repairable repairable(final RegistryKeySet<ItemType> types) { ++ return new PaperRepairable(new net.minecraft.world.item.enchantment.Repairable( ++ PaperRegistrySets.convertToNms(Registries.ITEM, BuiltInRegistries.BUILT_IN_CONVERSIONS.lookup(), types) ++ )); ++ } ++ ++ @Override ++ public Equippable.Builder equippable(EquipmentSlot slot) { ++ return new PaperEquippable.BuilderImpl(slot); ++ } ++ ++ @Override ++ public DeathProtection.Builder deathProtection() { ++ return new PaperDeathProtection.BuilderImpl(); + } + + @Override + public CustomModelData customModelData(final int id) { + return new PaperCustomModelData(new net.minecraft.world.item.component.CustomModelData(id)); + } ++ ++ @Override ++ public OminiousBottleAmplifier ominiousBottleAmplifier(final int amplifier) { ++ return new PaperOminousBottleAmplifier( ++ new OminousBottleAmplifier(amplifier) ++ ); ++ } +} diff --git a/src/main/java/io/papermc/paper/datacomponent/item/PaperBannerPatternLayers.java b/src/main/java/io/papermc/paper/datacomponent/item/PaperBannerPatternLayers.java new file mode 100644 @@ -839,6 +924,165 @@ index 0000000000000000000000000000000000000000..db00e0d68dba2b844377248c8e70b5e2 + } + } +} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/PaperConsumable.java b/src/main/java/io/papermc/paper/datacomponent/item/PaperConsumable.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ddcd650d2f4d71ba8f602d2562ecb9b716a61fc9 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/PaperConsumable.java +@@ -0,0 +1,153 @@ ++package io.papermc.paper.datacomponent.item; ++ ++import io.papermc.paper.adventure.PaperAdventure; ++import io.papermc.paper.block.BlockPredicate; ++import io.papermc.paper.datacomponent.item.consumable.ConsumeEffect; ++import io.papermc.paper.datacomponent.item.consumable.ItemUseAnimation; ++import io.papermc.paper.datacomponent.item.consumable.PaperConsumableEffects; ++import io.papermc.paper.registry.RegistryKey; ++import io.papermc.paper.registry.set.PaperRegistrySets; ++import java.util.ArrayList; ++import java.util.Collection; ++import java.util.Collections; ++import java.util.List; ++import java.util.Optional; ++import net.kyori.adventure.key.Key; ++import net.minecraft.core.Holder; ++import net.minecraft.core.registries.BuiltInRegistries; ++import net.minecraft.core.registries.Registries; ++import net.minecraft.resources.ResourceLocation; ++import net.minecraft.sounds.SoundEvent; ++import net.minecraft.sounds.SoundEvents; ++import net.minecraft.world.item.component.Consumables; ++import org.bukkit.craftbukkit.util.Handleable; ++import org.checkerframework.checker.index.qual.NonNegative; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Unmodifiable; ++ ++import static io.papermc.paper.datacomponent.ComponentUtils.transform; ++ ++@DefaultQualifier(NonNull.class) ++public record PaperConsumable( ++ net.minecraft.world.item.component.Consumable impl, ++ List<ConsumeEffect> consumeEffects ++) implements Consumable, Handleable<net.minecraft.world.item.component.Consumable> { ++ ++ public PaperConsumable(final net.minecraft.world.item.component.Consumable impl) { ++ this( ++ impl, ++ transform(impl.onConsumeEffects(), PaperConsumableEffects::fromNms) ++ ); ++ } ++ ++ private static final ItemUseAnimation[] VALUES = ItemUseAnimation.values(); ++ ++ @Override ++ public net.minecraft.world.item.component.Consumable getHandle() { ++ return this.impl; ++ } ++ ++ @Override ++ public @NonNegative float consumeSeconds() { ++ return this.impl.consumeSeconds(); ++ } ++ ++ @Override ++ public ItemUseAnimation animation() { ++ return VALUES[impl.animation().ordinal()]; ++ } ++ ++ @Override ++ public @NonNull Key sound() { ++ return PaperAdventure.asAdventure(this.impl.sound().value().location()); ++ } ++ ++ @Override ++ public boolean hasConsumeParticles() { ++ return this.impl.hasConsumeParticles(); ++ } ++ ++ @Override ++ public @Unmodifiable @NonNull List<ConsumeEffect> consumeEffects() { ++ return this.consumeEffects; ++ } ++ ++ @Override ++ public Consumable.Builder toBuilder() { ++ return new BuilderImpl() ++ .consumeSeconds(this.consumeSeconds()) ++ .animation(this.animation()) ++ .sound(this.sound()) ++ .addEffects(this.consumeEffects()); ++ } ++ ++ static final class BuilderImpl implements Builder { ++ ++ private static final net.minecraft.world.item.ItemUseAnimation[] VALUES = net.minecraft.world.item.ItemUseAnimation.values(); ++ ++ private float consumeSeconds = net.minecraft.world.item.component.Consumable.DEFAULT_CONSUME_SECONDS; ++ private net.minecraft.world.item.ItemUseAnimation consumeAnimation = net.minecraft.world.item.ItemUseAnimation.EAT; ++ private Holder<SoundEvent> eatSound = SoundEvents.GENERIC_EAT; ++ private boolean hasConsumeParticles = true; ++ private final List<net.minecraft.world.item.consume_effects.ConsumeEffect> effects = new ArrayList<>(); ++ ++ @Override ++ public @NonNull Builder consumeSeconds(@NonNegative final float consumeSeconds) { ++ this.consumeSeconds = consumeSeconds; ++ return this; ++ } ++ ++ @Override ++ public @NonNull Builder animation(@NotNull final ItemUseAnimation animation) { ++ this.consumeAnimation = VALUES[animation.ordinal()]; ++ return this; ++ } ++ ++ @Override ++ public @NonNull Builder sound(@NonNull final Key sound) { ++ ResourceLocation keySound = PaperAdventure.asVanilla(sound); ++ this.eatSound = BuiltInRegistries.SOUND_EVENT.wrapAsHolder( ++ BuiltInRegistries.SOUND_EVENT.getOptional(keySound).orElse( ++ SoundEvent.createVariableRangeEvent(keySound) ++ ) ++ ); ++ ++ return this; ++ } ++ ++ @Override ++ public @NonNull Builder hasConsumeParticles(final boolean hasConsumeParticles) { ++ this.hasConsumeParticles = hasConsumeParticles; ++ return this; ++ } ++ ++ @Override ++ public @NonNull Builder addEffect(@NonNull final ConsumeEffect effect) { ++ this.effects.add(PaperConsumableEffects.toNms(effect)); ++ return this; ++ } ++ ++ @Override ++ public @NonNull Builder addEffects(@NonNull final Collection<@NonNull ConsumeEffect> effects) { ++ for (ConsumeEffect effect : effects) { ++ this.effects.add(PaperConsumableEffects.toNms(effect)); ++ } ++ return this; ++ } ++ ++ @Override ++ public @NonNull Consumable build() { ++ return new PaperConsumable( ++ new net.minecraft.world.item.component.Consumable( ++ this.consumeSeconds, ++ this.consumeAnimation, ++ this.eatSound, ++ this.hasConsumeParticles, ++ this.effects ++ ) ++ ); ++ } ++ } ++} diff --git a/src/main/java/io/papermc/paper/datacomponent/item/PaperCustomModelData.java b/src/main/java/io/papermc/paper/datacomponent/item/PaperCustomModelData.java new file mode 100644 index 0000000000000000000000000000000000000000..a68ae7a3c31094a579a8c307d275847c311e3f86 @@ -866,6 +1110,113 @@ index 0000000000000000000000000000000000000000..a68ae7a3c31094a579a8c307d275847c + return this.impl.value(); + } +} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/PaperDamageResistant.java b/src/main/java/io/papermc/paper/datacomponent/item/PaperDamageResistant.java +new file mode 100644 +index 0000000000000000000000000000000000000000..461461d3ad0f2c7f3d8d0267804fbe23dbefce64 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/PaperDamageResistant.java +@@ -0,0 +1,27 @@ ++package io.papermc.paper.datacomponent.item; ++ ++import io.papermc.paper.registry.PaperRegistries; ++import io.papermc.paper.registry.RegistryKey; ++import io.papermc.paper.registry.set.PaperRegistrySets; ++import io.papermc.paper.registry.set.RegistryKeySet; ++import io.papermc.paper.registry.tag.TagKey; ++import org.bukkit.craftbukkit.util.Handleable; ++import org.bukkit.damage.DamageType; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++@DefaultQualifier(NonNull.class) ++public record PaperDamageResistant( ++ net.minecraft.world.item.component.DamageResistant impl ++) implements DamageResistant, Handleable<net.minecraft.world.item.component.DamageResistant> { ++ ++ @Override ++ public net.minecraft.world.item.component.DamageResistant getHandle() { ++ return this.impl; ++ } ++ ++ @Override ++ public @NonNull TagKey<DamageType> types() { ++ return PaperRegistries.fromNms(this.impl.types()); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/PaperDeathProtection.java b/src/main/java/io/papermc/paper/datacomponent/item/PaperDeathProtection.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9e9ec0257c30f323ab9b10135b7b76be95a836d3 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/PaperDeathProtection.java +@@ -0,0 +1,68 @@ ++package io.papermc.paper.datacomponent.item; ++ ++import io.papermc.paper.adventure.PaperAdventure; ++import io.papermc.paper.datacomponent.item.consumable.ConsumeEffect; ++import io.papermc.paper.datacomponent.item.consumable.ItemUseAnimation; ++import io.papermc.paper.datacomponent.item.consumable.PaperConsumableEffects; ++import java.util.ArrayList; ++import java.util.Collection; ++import java.util.List; ++import net.kyori.adventure.key.Key; ++import net.minecraft.core.Holder; ++import net.minecraft.core.registries.BuiltInRegistries; ++import net.minecraft.resources.ResourceLocation; ++import net.minecraft.sounds.SoundEvent; ++import net.minecraft.sounds.SoundEvents; ++import org.bukkit.craftbukkit.util.Handleable; ++import org.checkerframework.checker.index.qual.NonNegative; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Unmodifiable; ++ ++import static io.papermc.paper.datacomponent.ComponentUtils.transform; ++ ++@DefaultQualifier(NonNull.class) ++public record PaperDeathProtection( ++ net.minecraft.world.item.component.DeathProtection impl, ++ List<ConsumeEffect> deathEffects ++) implements DeathProtection, Handleable<net.minecraft.world.item.component.DeathProtection> { ++ ++ public PaperDeathProtection(final net.minecraft.world.item.component.DeathProtection impl) { ++ this( ++ impl, ++ transform(impl.deathEffects(), PaperConsumableEffects::fromNms) ++ ); ++ } ++ ++ @Override ++ public net.minecraft.world.item.component.DeathProtection getHandle() { ++ return this.impl; ++ } ++ ++ static final class BuilderImpl implements Builder { ++ ++ private final List<net.minecraft.world.item.consume_effects.ConsumeEffect> effects = new ArrayList<>(); ++ ++ @Override ++ public @NonNull Builder addEffect(@NonNull final ConsumeEffect effect) { ++ this.effects.add(PaperConsumableEffects.toNms(effect)); ++ return this; ++ } ++ ++ @Override ++ public @NonNull Builder addEffects(@NonNull final Collection<@NonNull ConsumeEffect> effects) { ++ for (ConsumeEffect effect : effects) { ++ this.effects.add(PaperConsumableEffects.toNms(effect)); ++ } ++ return this; ++ } ++ ++ @Override ++ public @NonNull DeathProtection build() { ++ return new PaperDeathProtection( ++ new net.minecraft.world.item.component.DeathProtection(this.effects) ++ ); ++ } ++ } ++} diff --git a/src/main/java/io/papermc/paper/datacomponent/item/PaperDyedItemColor.java b/src/main/java/io/papermc/paper/datacomponent/item/PaperDyedItemColor.java new file mode 100644 index 0000000000000000000000000000000000000000..ff2a81366fcd554451e9b2aa438e9277fa70248b @@ -927,6 +1278,205 @@ index 0000000000000000000000000000000000000000..ff2a81366fcd554451e9b2aa438e9277 + } + } +} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/PaperEnchantable.java b/src/main/java/io/papermc/paper/datacomponent/item/PaperEnchantable.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a9de03513e371c049375a7b87d9905371061a95f +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/PaperEnchantable.java +@@ -0,0 +1,22 @@ ++package io.papermc.paper.datacomponent.item; ++ ++import org.bukkit.craftbukkit.util.Handleable; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++@DefaultQualifier(NonNull.class) ++public record PaperEnchantable( ++ net.minecraft.world.item.enchantment.Enchantable impl ++) implements Enchantable, Handleable<net.minecraft.world.item.enchantment.Enchantable> { ++ ++ @Override ++ public net.minecraft.world.item.enchantment.Enchantable getHandle() { ++ return this.impl; ++ } ++ ++ ++ @Override ++ public int value() { ++ return this.impl.value(); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/PaperEquippable.java b/src/main/java/io/papermc/paper/datacomponent/item/PaperEquippable.java +new file mode 100644 +index 0000000000000000000000000000000000000000..dfa2e7a6bd5152b225fa563347c093bc95b9c4ea +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/PaperEquippable.java +@@ -0,0 +1,165 @@ ++package io.papermc.paper.datacomponent.item; ++ ++import io.papermc.paper.adventure.PaperAdventure; ++import io.papermc.paper.datacomponent.ComponentUtils; ++import io.papermc.paper.registry.RegistryKey; ++import io.papermc.paper.registry.set.PaperRegistrySets; ++import io.papermc.paper.registry.set.RegistryKeySet; ++import net.kyori.adventure.key.Key; ++import net.minecraft.core.Holder; ++import net.minecraft.core.HolderSet; ++import net.minecraft.core.registries.BuiltInRegistries; ++import net.minecraft.core.registries.Registries; ++import net.minecraft.resources.ResourceLocation; ++import net.minecraft.sounds.SoundEvent; ++import net.minecraft.sounds.SoundEvents; ++import org.bukkit.craftbukkit.CraftEquipmentSlot; ++import org.bukkit.craftbukkit.util.Handleable; ++import org.bukkit.entity.EntityType; ++import org.bukkit.inventory.EquipmentSlot; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.checkerframework.framework.qual.DefaultQualifier; ++import java.util.Optional; ++ ++@DefaultQualifier(NonNull.class) ++public record PaperEquippable( ++ net.minecraft.world.item.equipment.Equippable impl ++) implements Equippable, Handleable<net.minecraft.world.item.equipment.Equippable> { ++ ++ @Override ++ public net.minecraft.world.item.equipment.Equippable getHandle() { ++ return this.impl; ++ } ++ ++ @Override ++ public @NonNull EquipmentSlot slot() { ++ return CraftEquipmentSlot.getSlot(this.impl.slot()); ++ } ++ ++ @Override ++ public @NonNull Key equipSound() { ++ return PaperAdventure.asAdventure(this.impl.equipSound().value().location()); ++ } ++ ++ @Override ++ public @Nullable Key model() { ++ return this.impl.model() ++ .map(PaperAdventure::asAdventure) ++ .orElse(null); ++ } ++ ++ @Override ++ public @Nullable Key cameraOverlay() { ++ return this.impl.cameraOverlay() ++ .map(PaperAdventure::asAdventure) ++ .orElse(null); ++ } ++ ++ @Override ++ public @Nullable RegistryKeySet<EntityType> allowedEntities() { ++ return this.impl.allowedEntities() ++ .map((set) -> PaperRegistrySets.convertToApi(RegistryKey.ENTITY_TYPE, set)) ++ .orElse(null); ++ } ++ ++ @Override ++ public boolean dispensable() { ++ return this.impl.dispensable(); ++ } ++ ++ @Override ++ public boolean swappable() { ++ return this.impl.swappable(); ++ } ++ ++ @Override ++ public boolean damageOnHurt() { ++ return this.impl.damageOnHurt(); ++ } ++ ++ @Override ++ public Builder toBuilder() { ++ return new BuilderImpl(this.slot()) ++ .equipSound(this.equipSound()) ++ .model(this.model()) ++ .cameraOverlay(this.cameraOverlay()) ++ .allowedEntities(this.allowedEntities()) ++ .dispensable(this.dispensable()) ++ .swappable(this.swappable()) ++ .damageOnHurt(this.damageOnHurt()); ++ } ++ ++ ++ static final class BuilderImpl implements Builder { ++ ++ private final net.minecraft.world.entity.EquipmentSlot equipmentSlot; ++ private Holder<SoundEvent> equipSound = SoundEvents.ARMOR_EQUIP_GENERIC; ++ private Optional<ResourceLocation> model = Optional.empty(); ++ private Optional<ResourceLocation> cameraOverlay = Optional.empty(); ++ private Optional<HolderSet<net.minecraft.world.entity.EntityType<?>>> allowedEntities = Optional.empty(); ++ private boolean dispensable = true; ++ private boolean swappable = true; ++ private boolean damageOnHurt = true; ++ ++ BuilderImpl(final EquipmentSlot equipmentSlot) { ++ this.equipmentSlot = CraftEquipmentSlot.getNMS(equipmentSlot); ++ } ++ ++ @Override ++ public @NonNull Builder equipSound(final @NonNull Key equipSound) { ++ this.equipSound = ComponentUtils.keyToSound(equipSound); ++ return this; ++ } ++ ++ @Override ++ public @NonNull Builder model(final @Nullable Key model) { ++ this.model = Optional.ofNullable(model) ++ .map(PaperAdventure::asVanilla); ++ ++ return this; ++ } ++ ++ @Override ++ public @NonNull Builder cameraOverlay(@Nullable final Key cameraOverlay) { ++ this.cameraOverlay = Optional.ofNullable(cameraOverlay) ++ .map(PaperAdventure::asVanilla); ++ ++ return this; ++ } ++ ++ @Override ++ public @NonNull Builder allowedEntities(final @Nullable RegistryKeySet<EntityType> allowedEntities) { ++ this.allowedEntities = Optional.ofNullable(allowedEntities) ++ .map((set) -> PaperRegistrySets.convertToNms(Registries.ENTITY_TYPE, BuiltInRegistries.BUILT_IN_CONVERSIONS.lookup(), set)); ++ return this; ++ } ++ ++ @Override ++ public @NonNull Builder dispensable(final boolean dispensable) { ++ this.dispensable = dispensable; ++ return this; ++ } ++ ++ @Override ++ public @NonNull Builder swappable(final boolean swappable) { ++ this.swappable = swappable; ++ return this; ++ } ++ ++ @Override ++ public @NonNull Builder damageOnHurt(final boolean damageOnHurt) { ++ this.damageOnHurt = damageOnHurt; ++ return this; ++ } ++ ++ @Override ++ public @NonNull Equippable build() { ++ return new PaperEquippable( ++ new net.minecraft.world.item.equipment.Equippable( ++ this.equipmentSlot, this.equipSound, this.model, this.cameraOverlay, this.allowedEntities, this.dispensable, this.swappable, this.damageOnHurt ++ ) ++ ); ++ } ++ } ++} diff --git a/src/main/java/io/papermc/paper/datacomponent/item/PaperFireworks.java b/src/main/java/io/papermc/paper/datacomponent/item/PaperFireworks.java new file mode 100644 index 0000000000000000000000000000000000000000..d61720f6316b2f7dee05fdb60640dbc600db3210 @@ -1016,10 +1566,10 @@ index 0000000000000000000000000000000000000000..d61720f6316b2f7dee05fdb60640dbc6 +} diff --git a/src/main/java/io/papermc/paper/datacomponent/item/PaperFoodProperties.java b/src/main/java/io/papermc/paper/datacomponent/item/PaperFoodProperties.java new file mode 100644 -index 0000000000000000000000000000000000000000..3a1e6dbc09794d9bc4aad53fb05ebd7810223ec9 +index 0000000000000000000000000000000000000000..d6add9e4917f887cda2197895e2b9f045dce8bb3 --- /dev/null +++ b/src/main/java/io/papermc/paper/datacomponent/item/PaperFoodProperties.java -@@ -0,0 +1,166 @@ +@@ -0,0 +1,89 @@ +package io.papermc.paper.datacomponent.item; + +import com.google.common.base.Preconditions; @@ -1042,16 +1592,9 @@ index 0000000000000000000000000000000000000000..3a1e6dbc09794d9bc4aad53fb05ebd78 + +@DefaultQualifier(NonNull.class) +public record PaperFoodProperties( -+ net.minecraft.world.food.FoodProperties impl, -+ List<PossibleEffect> effects ++ net.minecraft.world.food.FoodProperties impl +) implements FoodProperties, Handleable<net.minecraft.world.food.FoodProperties> { + -+ public PaperFoodProperties(final net.minecraft.world.food.FoodProperties impl) { -+ this( -+ impl, -+ transform(impl.effects(), PossibleEffectImpl::new) -+ ); -+ } + + @Override + public int nutrition() { @@ -1069,24 +1612,11 @@ index 0000000000000000000000000000000000000000..3a1e6dbc09794d9bc4aad53fb05ebd78 + } + + @Override -+ public float eatSeconds() { -+ return this.impl.eatSeconds(); -+ } -+ -+ @Override -+ public @Nullable ItemStack usingConvertsTo() { -+ return this.impl.usingConvertsTo().map(item -> CraftItemStack.asCraftMirror(item.copy())).orElse(null); -+ } -+ -+ @Override + public FoodProperties.Builder toBuilder() { + return new BuilderImpl() -+ .addEffects(this.effects()) + .nutrition(this.nutrition()) + .saturation(this.saturation()) -+ .canAlwaysEat(this.canAlwaysEat()) -+ .eatSeconds(this.eatSeconds()) -+ .usingConvertsTo(this.usingConvertsTo()); ++ .canAlwaysEat(this.canAlwaysEat()); + } + + @Override @@ -1094,53 +1624,18 @@ index 0000000000000000000000000000000000000000..3a1e6dbc09794d9bc4aad53fb05ebd78 + return this.impl; + } + -+ record PossibleEffectImpl( -+ net.minecraft.world.food.FoodProperties.PossibleEffect possibleEffect -+ ) implements PossibleEffect, Handleable<net.minecraft.world.food.FoodProperties.PossibleEffect> { -+ -+ public static PossibleEffect toApi(final PotionEffect effect, final float probability) { -+ Preconditions.checkArgument(probability >= 0.0F && probability <= 1.0F, "probability must be [0.0f, 1.0f], was %s", probability); -+ return new PossibleEffectImpl(new net.minecraft.world.food.FoodProperties.PossibleEffect(CraftPotionUtil.fromBukkit(effect), probability)); -+ } -+ -+ @Override -+ public PotionEffect effect() { -+ return CraftPotionUtil.toBukkit(this.possibleEffect.effect()); -+ } -+ -+ @Override -+ public float probability() { -+ return this.possibleEffect.probability(); -+ } -+ -+ @Override -+ public net.minecraft.world.food.FoodProperties.PossibleEffect getHandle() { -+ return this.possibleEffect; -+ } -+ } + + static final class BuilderImpl implements FoodProperties.Builder { + -+ private final List<net.minecraft.world.food.FoodProperties.PossibleEffect> possibleEffects = new ArrayList<>(); + private boolean canAlwaysEat = false; -+ private float eatSeconds = net.minecraft.world.food.FoodProperties.DEFAULT_EAT_SECONDS; + private float saturation = 0; + private int nutrition = 0; -+ private @Nullable ItemStack convertedStack; + + @Override + public FoodProperties.Builder canAlwaysEat(final boolean canAlwaysEat) { + this.canAlwaysEat = canAlwaysEat; + return this; + } -+ -+ @Override -+ public FoodProperties.Builder eatSeconds(final float eatSeconds) { -+ Preconditions.checkArgument(eatSeconds > 0, "eatSeconds must be positive, was %s", eatSeconds); -+ this.eatSeconds = eatSeconds; -+ return this; -+ } -+ + @Override + public FoodProperties.Builder saturation(final float saturation) { + this.saturation = saturation; @@ -1155,43 +1650,21 @@ index 0000000000000000000000000000000000000000..3a1e6dbc09794d9bc4aad53fb05ebd78 + } + + @Override -+ public FoodProperties.Builder usingConvertsTo(final @Nullable ItemStack stack) { -+ Preconditions.checkArgument(stack == null || !stack.isEmpty(), "stack cannot be empty"); -+ this.convertedStack = stack; -+ return this; -+ } -+ -+ @Override -+ public FoodProperties.Builder addEffect(final PossibleEffect effect) { -+ this.possibleEffects.add(((PossibleEffectImpl) effect).possibleEffect()); -+ return this; -+ } -+ -+ @Override -+ public FoodProperties.Builder addEffects(final Collection<PossibleEffect> effects) { -+ addAndConvert(this.possibleEffects, effects, effect -> ((PossibleEffectImpl) effect).possibleEffect()); -+ return this; -+ } -+ -+ @Override + public FoodProperties build() { + return new PaperFoodProperties(new net.minecraft.world.food.FoodProperties( + this.nutrition, + this.saturation, -+ this.canAlwaysEat, -+ this.eatSeconds, -+ Optional.ofNullable(this.convertedStack).map(CraftItemStack::asNMSCopy), -+ Collections.unmodifiableList(this.possibleEffects) ++ this.canAlwaysEat + )); + } + } +} diff --git a/src/main/java/io/papermc/paper/datacomponent/item/PaperItemAdventurePredicate.java b/src/main/java/io/papermc/paper/datacomponent/item/PaperItemAdventurePredicate.java new file mode 100644 -index 0000000000000000000000000000000000000000..2984b9026b3c4b5a254fe9db0e829bfb0b69d13c +index 0000000000000000000000000000000000000000..d6e97b964070e08cb59c81a760293301a6f00030 --- /dev/null +++ b/src/main/java/io/papermc/paper/datacomponent/item/PaperItemAdventurePredicate.java -@@ -0,0 +1,77 @@ +@@ -0,0 +1,85 @@ +package io.papermc.paper.datacomponent.item; + +import java.util.ArrayList; @@ -1258,6 +1731,14 @@ index 0000000000000000000000000000000000000000..2984b9026b3c4b5a254fe9db0e829bfb + } + + @Override ++ public @NonNull Builder addPredicates(@NonNull final List<@NonNull BlockPredicate> predicates) { ++ for (BlockPredicate predicate : predicates) { ++ this.addPredicate(predicate); ++ } ++ return this; ++ } ++ ++ @Override + public ItemAdventurePredicate.Builder showInTooltip(final boolean showInTooltip) { + this.showInTooltip = showInTooltip; + return this; @@ -1271,7 +1752,7 @@ index 0000000000000000000000000000000000000000..2984b9026b3c4b5a254fe9db0e829bfb +} diff --git a/src/main/java/io/papermc/paper/datacomponent/item/PaperItemArmorTrim.java b/src/main/java/io/papermc/paper/datacomponent/item/PaperItemArmorTrim.java new file mode 100644 -index 0000000000000000000000000000000000000000..765c79f85f9a2c8009b0525a940f36bd05c0c929 +index 0000000000000000000000000000000000000000..cfcce96da5dc8fe25fd646a51cd00df6a3ed089a --- /dev/null +++ b/src/main/java/io/papermc/paper/datacomponent/item/PaperItemArmorTrim.java @@ -0,0 +1,65 @@ @@ -1286,17 +1767,17 @@ index 0000000000000000000000000000000000000000..765c79f85f9a2c8009b0525a940f36bd + +@DefaultQualifier(NonNull.class) +public record PaperItemArmorTrim( -+ net.minecraft.world.item.armortrim.ArmorTrim impl -+) implements ItemArmorTrim, Handleable<net.minecraft.world.item.armortrim.ArmorTrim> { ++ net.minecraft.world.item.equipment.trim.ArmorTrim impl ++) implements ItemArmorTrim, Handleable<net.minecraft.world.item.equipment.trim.ArmorTrim> { + + @Override -+ public net.minecraft.world.item.armortrim.ArmorTrim getHandle() { ++ public net.minecraft.world.item.equipment.trim.ArmorTrim getHandle() { + return this.impl; + } + + @Override + public boolean showInTooltip() { -+ return this.impl.showInTooltip; ++ return this.impl.showInTooltip(); + } + + @Override @@ -1332,7 +1813,7 @@ index 0000000000000000000000000000000000000000..765c79f85f9a2c8009b0525a940f36bd + + @Override + public ItemArmorTrim build() { -+ return new PaperItemArmorTrim(new net.minecraft.world.item.armortrim.ArmorTrim( ++ return new PaperItemArmorTrim(new net.minecraft.world.item.equipment.trim.ArmorTrim( + CraftTrimMaterial.bukkitToMinecraftHolder(this.armorTrim.getMaterial()), + CraftTrimPattern.bukkitToMinecraftHolder(this.armorTrim.getPattern()), + this.showInTooltip @@ -1879,10 +2360,10 @@ index 0000000000000000000000000000000000000000..1afafbc43cbf1a0ce07b43ceeefdeaf9 +} diff --git a/src/main/java/io/papermc/paper/datacomponent/item/PaperLockCode.java b/src/main/java/io/papermc/paper/datacomponent/item/PaperLockCode.java new file mode 100644 -index 0000000000000000000000000000000000000000..485bf8e0c7a24cc5714815f95e9818143ae226db +index 0000000000000000000000000000000000000000..42bd5d5bd739f3dcfd8f2945c53ca3cc34cd11c9 --- /dev/null +++ b/src/main/java/io/papermc/paper/datacomponent/item/PaperLockCode.java -@@ -0,0 +1,22 @@ +@@ -0,0 +1,17 @@ +package io.papermc.paper.datacomponent.item; + +import org.bukkit.craftbukkit.util.Handleable; @@ -1899,11 +2380,6 @@ index 0000000000000000000000000000000000000000..485bf8e0c7a24cc5714815f95e981814 + return this.impl; + } + -+ @Override -+ public String key() { -+ return this.impl.key(); -+ } -+ +} diff --git a/src/main/java/io/papermc/paper/datacomponent/item/PaperLodestoneTracker.java b/src/main/java/io/papermc/paper/datacomponent/item/PaperLodestoneTracker.java new file mode 100644 @@ -2145,6 +2621,34 @@ index 0000000000000000000000000000000000000000..20a9652f9a1ab18df8e1581fea1ca363 + } + } +} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/PaperOminousBottleAmplifier.java b/src/main/java/io/papermc/paper/datacomponent/item/PaperOminousBottleAmplifier.java +new file mode 100644 +index 0000000000000000000000000000000000000000..94c43ecb85c7193baa8c78bc90fa119c5ce877c0 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/PaperOminousBottleAmplifier.java +@@ -0,0 +1,22 @@ ++package io.papermc.paper.datacomponent.item; ++ ++import net.minecraft.world.item.component.OminousBottleAmplifier; ++import org.bukkit.craftbukkit.util.Handleable; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++@DefaultQualifier(NonNull.class) ++public record PaperOminousBottleAmplifier( ++ net.minecraft.world.item.component.OminousBottleAmplifier impl ++) implements OminiousBottleAmplifier, Handleable<net.minecraft.world.item.component.OminousBottleAmplifier> { ++ ++ @Override ++ public net.minecraft.world.item.component.OminousBottleAmplifier getHandle() { ++ return this.impl; ++ } ++ ++ @Override ++ public int amplifier() { ++ return this.impl.value(); ++ } ++} diff --git a/src/main/java/io/papermc/paper/datacomponent/item/PaperPotDecorations.java b/src/main/java/io/papermc/paper/datacomponent/item/PaperPotDecorations.java new file mode 100644 index 0000000000000000000000000000000000000000..cb19491e0f43e075d76415cad2b8a441f292f2d3 @@ -2245,10 +2749,10 @@ index 0000000000000000000000000000000000000000..cb19491e0f43e075d76415cad2b8a441 +} diff --git a/src/main/java/io/papermc/paper/datacomponent/item/PaperPotionContents.java b/src/main/java/io/papermc/paper/datacomponent/item/PaperPotionContents.java new file mode 100644 -index 0000000000000000000000000000000000000000..81ecae8a916e07630a3fab76345542f81e62e099 +index 0000000000000000000000000000000000000000..53a57ff74c501a313f1f973eb7c60e8fc09d309c --- /dev/null +++ b/src/main/java/io/papermc/paper/datacomponent/item/PaperPotionContents.java -@@ -0,0 +1,95 @@ +@@ -0,0 +1,109 @@ +package io.papermc.paper.datacomponent.item; + +import java.util.ArrayList; @@ -2300,11 +2804,18 @@ index 0000000000000000000000000000000000000000..81ecae8a916e07630a3fab76345542f8 + .orElse(null); + } + ++ @Override ++ public @Nullable String customName() { ++ return this.impl.customName() ++ .orElse(null); ++ } ++ + static final class BuilderImpl implements PotionContents.Builder { + + private final List<MobEffectInstance> customEffects = new ArrayList<>(); + private @Nullable PotionType type; + private @Nullable Color color; ++ private @Nullable String customName; + + @Override + public PotionContents.Builder potion(final @Nullable PotionType type) { @@ -2319,6 +2830,12 @@ index 0000000000000000000000000000000000000000..81ecae8a916e07630a3fab76345542f8 + } + + @Override ++ public @NonNull Builder customName(@Nullable final String name) { ++ this.customName = customName; ++ return this; ++ } ++ ++ @Override + public PotionContents.Builder addCustomEffect(final PotionEffect effect) { + this.customEffects.add(CraftPotionUtil.fromBukkit(effect)); + return this; @@ -2339,11 +2856,46 @@ index 0000000000000000000000000000000000000000..81ecae8a916e07630a3fab76345542f8 + return new PaperPotionContents(new net.minecraft.world.item.alchemy.PotionContents( + Optional.ofNullable(this.type).map(CraftPotionType::bukkitToMinecraftHolder), + Optional.ofNullable(this.color).map(Color::asARGB), -+ Collections.unmodifiableList(this.customEffects) ++ Collections.unmodifiableList(this.customEffects), ++ Optional.ofNullable(this.customName) + )); + } + } +} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/PaperRepairable.java b/src/main/java/io/papermc/paper/datacomponent/item/PaperRepairable.java +new file mode 100644 +index 0000000000000000000000000000000000000000..90f524f5c203d04cfa2593c439c7d9a8e987d355 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/PaperRepairable.java +@@ -0,0 +1,28 @@ ++package io.papermc.paper.datacomponent.item; ++ ++import io.papermc.paper.registry.PaperRegistries; ++import io.papermc.paper.registry.RegistryKey; ++import io.papermc.paper.registry.set.PaperRegistrySets; ++import io.papermc.paper.registry.set.RegistryKeySet; ++import io.papermc.paper.registry.tag.TagKey; ++import org.bukkit.craftbukkit.util.Handleable; ++import org.bukkit.damage.DamageType; ++import org.bukkit.inventory.ItemType; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++@DefaultQualifier(NonNull.class) ++public record PaperRepairable( ++ net.minecraft.world.item.enchantment.Repairable impl ++) implements Repairable, Handleable<net.minecraft.world.item.enchantment.Repairable> { ++ ++ @Override ++ public net.minecraft.world.item.enchantment.Repairable getHandle() { ++ return this.impl; ++ } ++ ++ @Override ++ public @NonNull RegistryKeySet<ItemType> types() { ++ return PaperRegistrySets.convertToApi(RegistryKey.ITEM, this.impl.items()); ++ } ++} diff --git a/src/main/java/io/papermc/paper/datacomponent/item/PaperResolvableProfile.java b/src/main/java/io/papermc/paper/datacomponent/item/PaperResolvableProfile.java new file mode 100644 index 0000000000000000000000000000000000000000..c5e2f645d05c73f2a6a7902c8c3aaa92816bcca3 @@ -2644,6 +3196,102 @@ index 0000000000000000000000000000000000000000..2ff5004427766b0034595ddad04aac6b + } + } +} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/PaperUseCooldown.java b/src/main/java/io/papermc/paper/datacomponent/item/PaperUseCooldown.java +new file mode 100644 +index 0000000000000000000000000000000000000000..587755c3ab532662b1cb9a6f662832e77dd7d0e2 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/PaperUseCooldown.java +@@ -0,0 +1,60 @@ ++package io.papermc.paper.datacomponent.item; ++ ++import com.google.common.base.Preconditions; ++import io.papermc.paper.adventure.PaperAdventure; ++import net.kyori.adventure.key.Key; ++import net.minecraft.resources.ResourceLocation; ++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 java.util.Optional; ++ ++@DefaultQualifier(NonNull.class) ++public record PaperUseCooldown( ++ net.minecraft.world.item.component.UseCooldown impl ++) implements UseCooldown, Handleable<net.minecraft.world.item.component.UseCooldown> { ++ ++ @Override ++ public net.minecraft.world.item.component.UseCooldown getHandle() { ++ return this.impl; ++ } ++ ++ @Override ++ public float seconds() { ++ return this.impl.seconds(); ++ } ++ ++ @Override ++ public @Nullable Key cooldownGroup() { ++ return this.impl.cooldownGroup() ++ .map(PaperAdventure::asAdventure) ++ .orElse(null); ++ } ++ ++ ++ static final class BuilderImpl implements Builder { ++ ++ private final float seconds; ++ private Optional<ResourceLocation> cooldownGroup = Optional.empty(); ++ ++ BuilderImpl(final float seconds) { ++ this.seconds = seconds; ++ } ++ ++ @Override ++ public @NonNull Builder cooldownGroup(@Nullable final Key key) { ++ this.cooldownGroup = Optional.ofNullable(key) ++ .map(PaperAdventure::asVanilla); ++ ++ return this; ++ } ++ ++ @Override ++ public @NonNull UseCooldown build() { ++ return new PaperUseCooldown( ++ new net.minecraft.world.item.component.UseCooldown(this.seconds, this.cooldownGroup) ++ ); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/PaperUseRemainder.java b/src/main/java/io/papermc/paper/datacomponent/item/PaperUseRemainder.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ae908c3a2edc4ed79686a2b26e775c8850ae7b86 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/PaperUseRemainder.java +@@ -0,0 +1,24 @@ ++package io.papermc.paper.datacomponent.item; ++ ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.craftbukkit.util.Handleable; ++import org.bukkit.inventory.ItemStack; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++@DefaultQualifier(NonNull.class) ++public record PaperUseRemainder( ++ net.minecraft.world.item.component.UseRemainder impl ++) implements UseRemainder, Handleable<net.minecraft.world.item.component.UseRemainder> { ++ ++ @Override ++ public net.minecraft.world.item.component.UseRemainder getHandle() { ++ return this.impl; ++ } ++ ++ ++ @Override ++ public @NonNull ItemStack transformInto() { ++ return CraftItemStack.asBukkitCopy(this.impl.convertInto()); ++ } ++} diff --git a/src/main/java/io/papermc/paper/datacomponent/item/PaperWritableBookContent.java b/src/main/java/io/papermc/paper/datacomponent/item/PaperWritableBookContent.java new file mode 100644 index 0000000000000000000000000000000000000000..964e819110825321e06da532c9d94f8fec4eb4b0 @@ -2959,32 +3607,304 @@ index 0000000000000000000000000000000000000000..fdfc10c9b5993d098f0ad8f4772ac7e5 + } + } +} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/consumable/ConsumableTypesBridgeImpl.java b/src/main/java/io/papermc/paper/datacomponent/item/consumable/ConsumableTypesBridgeImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..207bcdf0079163037c03e4cb5f419237d9b70e21 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/consumable/ConsumableTypesBridgeImpl.java +@@ -0,0 +1,68 @@ ++package io.papermc.paper.datacomponent.item.consumable; ++ ++import java.util.ArrayList; ++import java.util.List; ++import java.util.Optional; ++import java.util.ServiceLoader; ++import com.google.common.collect.Lists; ++import io.papermc.paper.adventure.PaperAdventure; ++import io.papermc.paper.datacomponent.ComponentUtils; ++import io.papermc.paper.registry.set.PaperRegistrySets; ++import io.papermc.paper.registry.set.RegistryKeySet; ++import net.kyori.adventure.key.Key; ++import net.minecraft.core.registries.BuiltInRegistries; ++import net.minecraft.core.registries.Registries; ++import net.minecraft.resources.ResourceLocation; ++import net.minecraft.sounds.SoundEvent; ++import org.bukkit.craftbukkit.potion.CraftPotionUtil; ++import org.bukkit.potion.PotionEffect; ++import org.bukkit.potion.PotionEffectType; ++import org.jetbrains.annotations.ApiStatus; ++ ++public class ConsumableTypesBridgeImpl implements ConsumableTypesBridge { ++ ++ @Override ++ public ApplyStatusEffectsConsumeEffect applyStatusEffects(final List<PotionEffect> effectList, final float probability) { ++ return new PaperApplyStatusEffectsConsumeEffect( ++ new net.minecraft.world.item.consume_effects.ApplyStatusEffectsConsumeEffect( ++ new ArrayList<>(Lists.transform(effectList, CraftPotionUtil::fromBukkit)), ++ probability ++ ) ++ ); ++ } ++ ++ @Override ++ public RemoveStatusEffectsConsumeEffect removeStatusEffects(final RegistryKeySet<PotionEffectType> potionEffectTypeTagKey) { ++ return new PaperRemoveStatusEffectsConsumeEffect( ++ new net.minecraft.world.item.consume_effects.RemoveStatusEffectsConsumeEffect( ++ PaperRegistrySets.convertToNms(Registries.MOB_EFFECT, BuiltInRegistries.BUILT_IN_CONVERSIONS.lookup(), potionEffectTypeTagKey) ++ ) ++ ); ++ } ++ ++ @Override ++ public ClearAllStatusEffectsConsumeEffect clearAllStatusEffects() { ++ return new PaperClearAllStatusEffectsConsumeEffect( ++ new net.minecraft.world.item.consume_effects.ClearAllStatusEffectsConsumeEffect() ++ ); ++ } ++ ++ @Override ++ public PlaySoundConsumeEffect playSoundEffect(final Key sound) { ++ return new PaperPlaySoundConsumeEffect( ++ new net.minecraft.world.item.consume_effects.PlaySoundConsumeEffect( ++ ComponentUtils.keyToSound(sound) ++ ) ++ ); ++ } ++ ++ @Override ++ public TeleportRandomlyConsumeEffect teleportRandomlyEffect(final float diameter) { ++ return new PaperTeleportRandomlyConsumeEffect( ++ new net.minecraft.world.item.consume_effects.TeleportRandomlyConsumeEffect(diameter) ++ ); ++ } ++ ++ ++} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/consumable/PaperApplyStatusEffectsConsumeEffect.java b/src/main/java/io/papermc/paper/datacomponent/item/consumable/PaperApplyStatusEffectsConsumeEffect.java +new file mode 100644 +index 0000000000000000000000000000000000000000..61888e17d7e66012cdb196cb26162e39b0f25588 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/consumable/PaperApplyStatusEffectsConsumeEffect.java +@@ -0,0 +1,30 @@ ++package io.papermc.paper.datacomponent.item.consumable; ++ ++import java.util.List; ++import net.minecraft.world.item.consume_effects.ApplyStatusEffectsConsumeEffect; ++import org.bukkit.craftbukkit.potion.CraftPotionUtil; ++import org.bukkit.craftbukkit.util.Handleable; ++import org.bukkit.potion.PotionEffect; ++import org.checkerframework.checker.nullness.qual.NonNull; ++ ++import static io.papermc.paper.datacomponent.ComponentUtils.transform; ++ ++public record PaperApplyStatusEffectsConsumeEffect( ++ ApplyStatusEffectsConsumeEffect impl ++) implements io.papermc.paper.datacomponent.item.consumable.ApplyStatusEffectsConsumeEffect, PaperConsumableEffectImpl<ApplyStatusEffectsConsumeEffect> { ++ ++ @Override ++ public @NonNull List<PotionEffect> effects() { ++ return transform(this.impl().effects(), CraftPotionUtil::toBukkit); ++ } ++ ++ @Override ++ public float probability() { ++ return this.impl.probability(); ++ } ++ ++ @Override ++ public ApplyStatusEffectsConsumeEffect getHandle() { ++ return this.impl; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/consumable/PaperClearAllStatusEffectsConsumeEffect.java b/src/main/java/io/papermc/paper/datacomponent/item/consumable/PaperClearAllStatusEffectsConsumeEffect.java +new file mode 100644 +index 0000000000000000000000000000000000000000..adcaa40e0b3d61ba2b7a563704fce0a5b180038e +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/consumable/PaperClearAllStatusEffectsConsumeEffect.java +@@ -0,0 +1,15 @@ ++package io.papermc.paper.datacomponent.item.consumable; ++ ++import org.bukkit.craftbukkit.util.Handleable; ++ ++import static io.papermc.paper.datacomponent.ComponentUtils.transform; ++ ++public record PaperClearAllStatusEffectsConsumeEffect( ++ net.minecraft.world.item.consume_effects.ClearAllStatusEffectsConsumeEffect impl ++) implements io.papermc.paper.datacomponent.item.consumable.ClearAllStatusEffectsConsumeEffect, PaperConsumableEffectImpl<net.minecraft.world.item.consume_effects.ClearAllStatusEffectsConsumeEffect> { ++ ++ @Override ++ public net.minecraft.world.item.consume_effects.ClearAllStatusEffectsConsumeEffect getHandle() { ++ return this.impl; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/consumable/PaperConsumableEffectImpl.java b/src/main/java/io/papermc/paper/datacomponent/item/consumable/PaperConsumableEffectImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..05ede1d3f5b0b5ea3a5004cb4a7a153ed7714a55 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/consumable/PaperConsumableEffectImpl.java +@@ -0,0 +1,7 @@ ++package io.papermc.paper.datacomponent.item.consumable; ++ ++import net.minecraft.world.item.consume_effects.ConsumeEffect; ++import org.bukkit.craftbukkit.util.Handleable; ++ ++public interface PaperConsumableEffectImpl<T extends ConsumeEffect> extends Handleable<T> { ++} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/consumable/PaperConsumableEffects.java b/src/main/java/io/papermc/paper/datacomponent/item/consumable/PaperConsumableEffects.java +new file mode 100644 +index 0000000000000000000000000000000000000000..006fc44b489e25658355da7d9303174c2a8fff19 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/consumable/PaperConsumableEffects.java +@@ -0,0 +1,32 @@ ++package io.papermc.paper.datacomponent.item.consumable; ++ ++import io.papermc.paper.datacomponent.item.Consumable; ++import net.minecraft.world.item.consume_effects.ApplyStatusEffectsConsumeEffect; ++import net.minecraft.world.item.consume_effects.ClearAllStatusEffectsConsumeEffect; ++import net.minecraft.world.item.consume_effects.PlaySoundConsumeEffect; ++import net.minecraft.world.item.consume_effects.RemoveStatusEffectsConsumeEffect; ++import net.minecraft.world.item.consume_effects.TeleportRandomlyConsumeEffect; ++import org.bukkit.craftbukkit.util.Handleable; ++ ++public class PaperConsumableEffects { ++ ++ ++ public static ConsumeEffect fromNms(net.minecraft.world.item.consume_effects.ConsumeEffect consumable) { ++ return switch (consumable) { ++ case ApplyStatusEffectsConsumeEffect effect -> new PaperApplyStatusEffectsConsumeEffect(effect); ++ case ClearAllStatusEffectsConsumeEffect effect -> new PaperClearAllStatusEffectsConsumeEffect(effect); ++ case PlaySoundConsumeEffect effect -> new PaperPlaySoundConsumeEffect(effect); ++ case RemoveStatusEffectsConsumeEffect effect -> new PaperRemoveStatusEffectsConsumeEffect(effect); ++ case TeleportRandomlyConsumeEffect effect -> new PaperTeleportRandomlyConsumeEffect(effect); ++ default -> throw new UnsupportedOperationException("Dont know how to convert " + consumable.getClass()); ++ }; ++ } ++ ++ public static net.minecraft.world.item.consume_effects.ConsumeEffect toNms(ConsumeEffect effect) { ++ if (effect instanceof PaperConsumableEffectImpl<?> consumableEffect) { ++ return consumableEffect.getHandle(); ++ } else { ++ throw new UnsupportedOperationException("Must implement handleable!"); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/consumable/PaperPlaySoundConsumeEffect.java b/src/main/java/io/papermc/paper/datacomponent/item/consumable/PaperPlaySoundConsumeEffect.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6667a5dfd3de7f27dc6c35f95f3c3211f77a78fe +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/consumable/PaperPlaySoundConsumeEffect.java +@@ -0,0 +1,25 @@ ++package io.papermc.paper.datacomponent.item.consumable; ++ ++import io.papermc.paper.adventure.PaperAdventure; ++import net.kyori.adventure.key.Key; ++import net.minecraft.world.item.consume_effects.PlaySoundConsumeEffect; ++import org.bukkit.craftbukkit.util.Handleable; ++import org.checkerframework.checker.nullness.qual.NonNull; ++ ++import static io.papermc.paper.datacomponent.ComponentUtils.transform; ++ ++public record PaperPlaySoundConsumeEffect( ++ PlaySoundConsumeEffect impl ++) implements io.papermc.paper.datacomponent.item.consumable.PlaySoundConsumeEffect, PaperConsumableEffectImpl<PlaySoundConsumeEffect> { ++ ++ @NonNull ++ @Override ++ public Key sound() { ++ return PaperAdventure.asAdventure(this.impl.sound().value().location()); ++ } ++ ++ @Override ++ public PlaySoundConsumeEffect getHandle() { ++ return this.impl; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/consumable/PaperRemoveStatusEffectsConsumeEffect.java b/src/main/java/io/papermc/paper/datacomponent/item/consumable/PaperRemoveStatusEffectsConsumeEffect.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3d52af596a2ded9d5e9bc7e8acaaddd511490dcf +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/consumable/PaperRemoveStatusEffectsConsumeEffect.java +@@ -0,0 +1,30 @@ ++package io.papermc.paper.datacomponent.item.consumable; ++ ++import java.util.List; ++import io.papermc.paper.registry.PaperRegistries; ++import io.papermc.paper.registry.RegistryKey; ++import io.papermc.paper.registry.set.PaperRegistrySets; ++import io.papermc.paper.registry.set.RegistryKeySet; ++import net.minecraft.world.item.consume_effects.ApplyStatusEffectsConsumeEffect; ++import org.bukkit.craftbukkit.potion.CraftPotionUtil; ++import org.bukkit.craftbukkit.util.Handleable; ++import org.bukkit.potion.PotionEffect; ++import org.bukkit.potion.PotionEffectType; ++import org.checkerframework.checker.nullness.qual.NonNull; ++ ++import static io.papermc.paper.datacomponent.ComponentUtils.transform; ++ ++public record PaperRemoveStatusEffectsConsumeEffect( ++ net.minecraft.world.item.consume_effects.RemoveStatusEffectsConsumeEffect impl ++) implements RemoveStatusEffectsConsumeEffect, PaperConsumableEffectImpl<net.minecraft.world.item.consume_effects.RemoveStatusEffectsConsumeEffect> { ++ ++ @Override ++ public @NonNull RegistryKeySet<PotionEffectType> removeEffects() { ++ return PaperRegistrySets.convertToApi(RegistryKey.MOB_EFFECT, this.impl.effects()); ++ } ++ ++ @Override ++ public net.minecraft.world.item.consume_effects.RemoveStatusEffectsConsumeEffect getHandle() { ++ return this.impl; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/datacomponent/item/consumable/PaperTeleportRandomlyConsumeEffect.java b/src/main/java/io/papermc/paper/datacomponent/item/consumable/PaperTeleportRandomlyConsumeEffect.java +new file mode 100644 +index 0000000000000000000000000000000000000000..5985308cac8f9409eea478fb68f64e8cfd4855c9 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/datacomponent/item/consumable/PaperTeleportRandomlyConsumeEffect.java +@@ -0,0 +1,17 @@ ++package io.papermc.paper.datacomponent.item.consumable; ++ ++import org.bukkit.craftbukkit.util.Handleable; ++ ++public record PaperTeleportRandomlyConsumeEffect( ++ net.minecraft.world.item.consume_effects.TeleportRandomlyConsumeEffect impl ++) implements TeleportRandomlyConsumeEffect, PaperConsumableEffectImpl<net.minecraft.world.item.consume_effects.TeleportRandomlyConsumeEffect> { ++ @Override ++ public float diameter() { ++ return this.impl.diameter(); ++ } ++ ++ @Override ++ public net.minecraft.world.item.consume_effects.TeleportRandomlyConsumeEffect getHandle() { ++ return this.impl; ++ } ++} diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/src/main/java/io/papermc/paper/registry/PaperRegistries.java -index 6ec9d9b9acf557aa2ebf39d38a14225b0205fae1..3a10a72cf6c5f91297a2d2980929f5484b3965be 100644 +index 12220f78ffaf06433ada72fd0c7f22b97d55287d..e1c6f514f45a02d7401b5390aefd0a4946b8e4b9 100644 --- a/src/main/java/io/papermc/paper/registry/PaperRegistries.java +++ b/src/main/java/io/papermc/paper/registry/PaperRegistries.java -@@ -3,6 +3,8 @@ package io.papermc.paper.registry; +@@ -1,6 +1,8 @@ + package io.papermc.paper.registry; + import io.papermc.paper.adventure.PaperAdventure; - import io.papermc.paper.registry.data.PaperEnchantmentRegistryEntry; - import io.papermc.paper.registry.data.PaperGameEventRegistryEntry; +import io.papermc.paper.datacomponent.DataComponentType; +import io.papermc.paper.datacomponent.PaperComponentType; + import io.papermc.paper.registry.data.PaperEnchantmentRegistryEntry; + import io.papermc.paper.registry.data.PaperGameEventRegistryEntry; import io.papermc.paper.registry.entry.RegistryEntry; - import io.papermc.paper.registry.tag.TagKey; - import java.util.Collections; -@@ -81,6 +83,7 @@ public final class PaperRegistries { - entry(Registries.VILLAGER_PROFESSION, RegistryKey.VILLAGER_PROFESSION, Villager.Profession.class, CraftVillager.CraftProfession::new), +@@ -84,6 +86,7 @@ public final class PaperRegistries { entry(Registries.VILLAGER_TYPE, RegistryKey.VILLAGER_TYPE, Villager.Type.class, CraftVillager.CraftType::new), entry(Registries.MAP_DECORATION_TYPE, RegistryKey.MAP_DECORATION_TYPE, MapCursor.Type.class, CraftMapCursor.CraftType::new), + entry(Registries.MENU, RegistryKey.MENU, MenuType.class, CraftMenuType::new), + entry(Registries.DATA_COMPONENT_TYPE, RegistryKey.DATA_COMPONENT_TYPE, DataComponentType.class, PaperComponentType::of), // data-drivens entry(Registries.STRUCTURE, RegistryKey.STRUCTURE, Structure.class, CraftStructure::new).delayed(), diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -index 40fb5b5e00f6bc82e67d318b8b3d1e7606973f52..15b2b43e718e7ea8a982e072ce9c8bc9baef119a 100644 +index 756c73a401437566258813946fa10c7caa8f2469..1222918237c3bc30a984f34cda99728499da069b 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -@@ -194,7 +194,7 @@ public final class CraftItemStack extends ItemStack { +@@ -206,7 +206,7 @@ public final class CraftItemStack extends ItemStack { this.adjustTagForItemMeta(oldType); // Paper } } @@ -2993,7 +3913,7 @@ index 40fb5b5e00f6bc82e67d318b8b3d1e7606973f52..15b2b43e718e7ea8a982e072ce9c8bc9 } @Override -@@ -233,7 +233,7 @@ public final class CraftItemStack extends ItemStack { +@@ -245,7 +245,7 @@ public final class CraftItemStack extends ItemStack { @Override public int getMaxStackSize() { @@ -3002,7 +3922,7 @@ index 40fb5b5e00f6bc82e67d318b8b3d1e7606973f52..15b2b43e718e7ea8a982e072ce9c8bc9 } // Paper start -@@ -255,12 +255,14 @@ public final class CraftItemStack extends ItemStack { +@@ -267,12 +267,14 @@ public final class CraftItemStack extends ItemStack { public void addUnsafeEnchantment(Enchantment ench, int level) { Preconditions.checkArgument(ench != null, "Enchantment cannot be null"); @@ -3022,7 +3942,7 @@ index 40fb5b5e00f6bc82e67d318b8b3d1e7606973f52..15b2b43e718e7ea8a982e072ce9c8bc9 // Paper end } -@@ -290,17 +292,28 @@ public final class CraftItemStack extends ItemStack { +@@ -302,17 +304,28 @@ public final class CraftItemStack extends ItemStack { public int removeEnchantment(Enchantment ench) { Preconditions.checkArgument(ench != null, "Enchantment cannot be null"); @@ -3060,7 +3980,7 @@ index 40fb5b5e00f6bc82e67d318b8b3d1e7606973f52..15b2b43e718e7ea8a982e072ce9c8bc9 } @Override -@@ -312,7 +325,13 @@ public final class CraftItemStack extends ItemStack { +@@ -324,7 +337,13 @@ public final class CraftItemStack extends ItemStack { @Override public Map<Enchantment, Integer> getEnchantments() { @@ -3075,7 +3995,7 @@ index 40fb5b5e00f6bc82e67d318b8b3d1e7606973f52..15b2b43e718e7ea8a982e072ce9c8bc9 } static Map<Enchantment, Integer> getEnchantments(net.minecraft.world.item.ItemStack item) { -@@ -543,4 +562,130 @@ public final class CraftItemStack extends ItemStack { +@@ -526,4 +545,130 @@ public final class CraftItemStack extends ItemStack { return this.pdcView; } // Paper end - pdc @@ -3207,10 +4127,10 @@ index 40fb5b5e00f6bc82e67d318b8b3d1e7606973f52..15b2b43e718e7ea8a982e072ce9c8bc9 + // 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 450c63c31d2f5d056d989aa00452231f50c8224d..65446258661b31c4efb47d3aa7548e991adc0c56 100644 +index 1b57649d0d3db24ed32c78cf3d5ce1d9fb1353e0..ce1287edd7db00279ec8569d767ab6272c8ae3fb 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java -@@ -273,4 +273,20 @@ public class CraftItemType<M extends ItemMeta> implements ItemType.Typed<M>, Han +@@ -270,4 +270,20 @@ public class CraftItemType<M extends ItemMeta> implements ItemType.Typed<M>, Han return rarity == null ? null : org.bukkit.inventory.ItemRarity.valueOf(rarity.name()); } // Paper end - expand ItemRarity API @@ -3232,11 +4152,11 @@ index 450c63c31d2f5d056d989aa00452231f50c8224d..65446258661b31c4efb47d3aa7548e99 + // Paper end - data component API } diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java -index 0eceacbb096481d3bd31f5f99e964c88aea2e3fb..acd80ad00caefe07232fc179cfbf4e7f56450859 100644 +index a944803771d514572f94b4e98a6d4435a009c078..82cb8cd1635c279326cec8454f1906ce35021dec 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java -@@ -78,7 +78,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { - }); +@@ -91,7 +91,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { + this.safelyAddEffects(effects, false); // Paper - limit firework effects } - static FireworkEffect getEffect(FireworkExplosion explosion) { @@ -3244,7 +4164,7 @@ index 0eceacbb096481d3bd31f5f99e964c88aea2e3fb..acd80ad00caefe07232fc179cfbf4e7f FireworkEffect.Builder effect = FireworkEffect.builder() .flicker(explosion.hasTwinkle()) .trail(explosion.hasTrail()) -@@ -98,7 +98,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { +@@ -111,7 +111,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { return effect.build(); } @@ -3274,31 +4194,39 @@ index 097996d3955ab5126b71f7bff1dd2c62becb5ffd..2e75620e803868ad3c254d11e6265062 public static Vec3 toVec3D(Location location) { return new Vec3(location.getX(), location.getY(), location.getZ()); } -diff --git a/src/main/resources/META-INF/services/io.papermc.paper.datacomponent.item.ComponentTypesBridge b/src/main/resources/META-INF/services/io.papermc.paper.datacomponent.item.ComponentTypesBridge +diff --git a/src/main/resources/META-INF/services/io.papermc.paper.datacomponent.item.ItemComponentTypesBridge b/src/main/resources/META-INF/services/io.papermc.paper.datacomponent.item.ItemComponentTypesBridge new file mode 100644 index 0000000000000000000000000000000000000000..0fd276c2fdbba784c1cd95105553996b4ba2460e --- /dev/null -+++ b/src/main/resources/META-INF/services/io.papermc.paper.datacomponent.item.ComponentTypesBridge ++++ b/src/main/resources/META-INF/services/io.papermc.paper.datacomponent.item.ItemComponentTypesBridge @@ -0,0 +1 @@ +io.papermc.paper.datacomponent.item.ItemComponentTypesBridgesImpl +diff --git a/src/main/resources/META-INF/services/io.papermc.paper.datacomponent.item.consumable.ConsumableTypesBridge b/src/main/resources/META-INF/services/io.papermc.paper.datacomponent.item.consumable.ConsumableTypesBridge +new file mode 100644 +index 0000000000000000000000000000000000000000..852ab097181491735fb9ee5ee4f70e4ceeb32e6d +--- /dev/null ++++ b/src/main/resources/META-INF/services/io.papermc.paper.datacomponent.item.consumable.ConsumableTypesBridge +@@ -0,0 +1 @@ ++io.papermc.paper.datacomponent.item.consumable.ConsumableTypesBridgeImpl diff --git a/src/test/java/io/papermc/paper/item/ItemStackDataComponentEqualsTest.java b/src/test/java/io/papermc/paper/item/ItemStackDataComponentEqualsTest.java new file mode 100644 -index 0000000000000000000000000000000000000000..06476cdd7f8290846e86bdd3837488ca900a7ddc +index 0000000000000000000000000000000000000000..9fc9756aff2248d7684e20f37e9202375b5ac71d --- /dev/null +++ b/src/test/java/io/papermc/paper/item/ItemStackDataComponentEqualsTest.java -@@ -0,0 +1,70 @@ +@@ -0,0 +1,71 @@ +package io.papermc.paper.item; + +import io.papermc.paper.datacomponent.DataComponentTypes; +import net.kyori.adventure.text.Component; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; -+import org.bukkit.support.AbstractTestingBase; ++import org.bukkit.support.environment.Normal; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import java.util.Set; + -+class ItemStackDataComponentEqualsTest extends AbstractTestingBase { ++@Normal ++class ItemStackDataComponentEqualsTest { + + @Test + public void testEqual() { @@ -3359,15 +4287,16 @@ index 0000000000000000000000000000000000000000..06476cdd7f8290846e86bdd3837488ca +} 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..0769c462ca0defbe31c10fc7a6d3ba901b382fad +index 0000000000000000000000000000000000000000..586f88b5bd5a7ce84d0dbd5e5bfa6a67d72089f6 --- /dev/null +++ b/src/test/java/io/papermc/paper/item/ItemStackDataComponentTest.java -@@ -0,0 +1,387 @@ +@@ -0,0 +1,380 @@ +package io.papermc.paper.item; + +import io.papermc.paper.datacomponent.DataComponentType; +import io.papermc.paper.datacomponent.DataComponentTypes; +import io.papermc.paper.datacomponent.item.ChargedProjectiles; ++import io.papermc.paper.datacomponent.item.Consumable; +import io.papermc.paper.datacomponent.item.CustomModelData; +import io.papermc.paper.datacomponent.item.DyedItemColor; +import io.papermc.paper.datacomponent.item.Fireworks; @@ -3382,6 +4311,9 @@ index 0000000000000000000000000000000000000000..0769c462ca0defbe31c10fc7a6d3ba90 +import io.papermc.paper.datacomponent.item.PotDecorations; +import io.papermc.paper.datacomponent.item.Tool; +import io.papermc.paper.datacomponent.item.Unbreakable; ++import io.papermc.paper.datacomponent.item.consumable.ApplyStatusEffectsConsumeEffect; ++import io.papermc.paper.datacomponent.item.consumable.ConsumeEffect; ++import io.papermc.paper.datacomponent.item.consumable.ItemUseAnimation; +import io.papermc.paper.registry.RegistryAccess; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.set.RegistrySet; @@ -3422,7 +4354,7 @@ index 0000000000000000000000000000000000000000..0769c462ca0defbe31c10fc7a6d3ba90 +import org.bukkit.inventory.meta.trim.TrimPattern; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; -+import org.bukkit.support.AbstractTestingBase; ++import org.bukkit.support.environment.Normal; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import java.util.List; @@ -3430,7 +4362,8 @@ index 0000000000000000000000000000000000000000..0769c462ca0defbe31c10fc7a6d3ba90 +import java.util.function.BiConsumer; +import java.util.function.Function; + -+class ItemStackDataComponentTest extends AbstractTestingBase { ++@Normal ++class ItemStackDataComponentTest { + + @Test + void testMaxStackSize() { @@ -3550,10 +4483,8 @@ index 0000000000000000000000000000000000000000..0769c462ca0defbe31c10fc7a6d3ba90 + void testFood() { + FoodProperties properties = FoodProperties.food() + .canAlwaysEat(true) -+ .eatSeconds(1.3F) ++ .saturation(1.3F) + .nutrition(1) -+ .addEffects(List.of(FoodProperties.PossibleEffect.possibleEffect(new PotionEffect(PotionEffectType.SLOWNESS, 5, 10), 1F))) -+ .usingConvertsTo(new ItemStack(Material.STONE)) + .build(); + + final ItemStack stack = new ItemStack(Material.CROSSBOW); @@ -3562,22 +4493,15 @@ index 0000000000000000000000000000000000000000..0769c462ca0defbe31c10fc7a6d3ba90 + ItemMeta meta = stack.getItemMeta(); + FoodComponent component = meta.getFood(); + Assertions.assertEquals(properties.canAlwaysEat(), component.canAlwaysEat()); -+ Assertions.assertEquals(properties.eatSeconds(), component.getEatSeconds()); ++ Assertions.assertEquals(properties.saturation(), component.getSaturation()); + Assertions.assertEquals(properties.nutrition(), component.getNutrition()); + -+ int idx = 0; -+ for (FoodComponent.FoodEffect effect : component.getEffects()) { -+ Assertions.assertEquals(properties.effects().get(idx).effect(), effect.getEffect()); -+ Assertions.assertEquals(properties.effects().get(idx).probability(), effect.getProbability()); -+ idx++; -+ } -+ Assertions.assertEquals(properties.usingConvertsTo(), component.getUsingConvertsTo()); -+ + stack.unsetData(DataComponentTypes.FOOD); + meta = stack.getItemMeta(); + Assertions.assertFalse(meta.hasFood()); + } + ++ + @Test + void testTool() { + Tool properties = Tool.tool() @@ -3634,10 +4558,7 @@ index 0000000000000000000000000000000000000000..0769c462ca0defbe31c10fc7a6d3ba90 + Assertions.assertFalse(meta.hasJukeboxPlayable()); + } + -+ @Test -+ void testFireResistant() { -+ testWithMeta(new ItemStack(Material.STONE), DataComponentTypes.FIRE_RESISTANT, true, ItemMeta.class, ItemMeta::isFireResistant, ItemMeta::setFireResistant); -+ } ++ + + @Test + void testDyedColor() { @@ -3752,10 +4673,10 @@ index 0000000000000000000000000000000000000000..0769c462ca0defbe31c10fc7a6d3ba90 +} diff --git a/src/test/java/io/papermc/paper/item/MetaComparisonTest.java b/src/test/java/io/papermc/paper/item/MetaComparisonTest.java new file mode 100644 -index 0000000000000000000000000000000000000000..5a61ad9f3517b6cbf52e03c40b935900330da4d0 +index 0000000000000000000000000000000000000000..957b08ec2d44cb05a9eff33d4529d016fb7af2ed --- /dev/null +++ b/src/test/java/io/papermc/paper/item/MetaComparisonTest.java -@@ -0,0 +1,283 @@ +@@ -0,0 +1,284 @@ +package io.papermc.paper.item; + +import com.destroystokyo.paper.profile.CraftPlayerProfile; @@ -3778,7 +4699,7 @@ index 0000000000000000000000000000000000000000..5a61ad9f3517b6cbf52e03c40b935900 +import org.bukkit.inventory.meta.SkullMeta; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; -+import org.bukkit.support.AbstractTestingBase; ++import org.bukkit.support.environment.Normal; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; @@ -3787,7 +4708,8 @@ index 0000000000000000000000000000000000000000..5a61ad9f3517b6cbf52e03c40b935900 +import java.util.function.Consumer; + +// TODO: This should technically be used to compare legacy meta vs the newly implemented -+public class MetaComparisonTest extends AbstractTestingBase { ++@Normal ++public class MetaComparisonTest { + + private static final ItemFactory FACTORY = CraftItemFactory.instance(); + @@ -4040,10 +4962,10 @@ index 0000000000000000000000000000000000000000..5a61ad9f3517b6cbf52e03c40b935900 + } +} diff --git a/src/test/java/org/bukkit/PerMaterialTest.java b/src/test/java/org/bukkit/PerMaterialTest.java -index 7787e399c6432120fb5a1826799cd229bbb28fe2..c06b409f3dce00bce846ae30852fe0cb33830684 100644 +index 629fccec144b5d66addc0e8258cde90e81904e1c..6961730365da9083e8963200ecc5f85dbc654f35 100644 --- a/src/test/java/org/bukkit/PerMaterialTest.java +++ b/src/test/java/org/bukkit/PerMaterialTest.java -@@ -100,17 +100,13 @@ public class PerMaterialTest extends AbstractTestingBase { +@@ -101,17 +101,13 @@ public class PerMaterialTest { final ItemStack bukkit = new ItemStack(material); final CraftItemStack craft = CraftItemStack.asCraftCopy(bukkit); @@ -4065,10 +4987,10 @@ index 7787e399c6432120fb5a1826799cd229bbb28fe2..c06b409f3dce00bce846ae30852fe0cb @ParameterizedTest diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java -index 1a582ee78334835df79f93cc9fd3669c347d8b3a..83a11c0eeecaf6aeb65f386a777b495231be8dc4 100644 +index ba5c958f322dc34baff3c9d1b99741a4ffeee135..13614672db233c3fb96bde7c4f6c52a583e6e341 100644 --- a/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java +++ b/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java -@@ -452,7 +452,7 @@ public class ItemMetaTest extends AbstractTestingBase { +@@ -453,7 +453,7 @@ public class ItemMetaTest { assertThat(providers, hasSize(ItemStackTest.COMPOUND_MATERIALS.length - 4/* Normal item meta, skulls, eggs and tile entities */), "Forgotten test?"); for (final StackProvider provider : providers) { @@ -4077,7 +4999,7 @@ index 1a582ee78334835df79f93cc9fd3669c347d8b3a..83a11c0eeecaf6aeb65f386a777b4952 this.downCastTest(new CraftWrapper(provider)); } } -@@ -512,13 +512,6 @@ public class ItemMetaTest extends AbstractTestingBase { +@@ -513,13 +513,6 @@ public class ItemMetaTest { final ItemStack blank = new ItemStack(Material.STONE); final ItemStack craftBlank = CraftItemStack.asCraftCopy(blank); @@ -4092,13 +5014,13 @@ index 1a582ee78334835df79f93cc9fd3669c347d8b3a..83a11c0eeecaf6aeb65f386a777b4952 this.downCastTest(name, provider.stack(), craftBlank); craftBlank.setItemMeta(craftBlank.getItemMeta()); diff --git a/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java b/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java -index c1f886c906a9f9313d97a223f719095fa2624c57..115a12d3d33abe70388f9fa20da2c3c6fca19849 100644 +index eb3974690fb12ffe678522ed47e0f730712db016..1843b89c8616acc1fca7757f938c6b62e8b6c2a8 100644 --- a/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java +++ b/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java -@@ -80,6 +80,7 @@ public class RegistriesArgumentProvider implements ArgumentsProvider { - register(RegistryKey.CAT_VARIANT, Cat.Type.class, Registries.CAT_VARIANT, CraftCat.CraftType.class, CatVariant.class); +@@ -83,6 +83,7 @@ public class RegistriesArgumentProvider implements ArgumentsProvider { register(RegistryKey.MAP_DECORATION_TYPE, MapCursor.Type.class, Registries.MAP_DECORATION_TYPE, CraftMapCursor.CraftType.class, MapDecorationType.class); register(RegistryKey.BANNER_PATTERN, PatternType.class, Registries.BANNER_PATTERN, CraftPatternType.class, BannerPattern.class); + register(RegistryKey.MENU, MenuType.class, Registries.MENU, CraftMenuType.class, net.minecraft.world.inventory.MenuType.class); + register(RegistryKey.DATA_COMPONENT_TYPE, io.papermc.paper.datacomponent.DataComponentType.class, Registries.DATA_COMPONENT_TYPE, io.papermc.paper.datacomponent.PaperComponentType.class, net.minecraft.core.component.DataComponentType.class); } |