aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOwen1212055 <[email protected]>2024-06-18 20:53:44 -0400
committerOwen1212055 <[email protected]>2024-11-18 14:50:38 -0500
commitd34d823291c19c9efe70a1a150b46869986aaa53 (patch)
tree1e96901fe0e19cd8ba1a768bdf01eab356769d93
parentf911f47f249fae79c52c7d6aa770d4ec91c4ec94 (diff)
downloadPaper-d34d823291c19c9efe70a1a150b46869986aaa53.tar.gz
Paper-d34d823291c19c9efe70a1a150b46869986aaa53.zip
So many tests, alot of javadocs
-rw-r--r--patches/api/0480-WIP-DataComponent-API.patch522
-rw-r--r--patches/server/1026-WIP-DataComponent-API.patch282
2 files changed, 747 insertions, 57 deletions
diff --git a/patches/api/0480-WIP-DataComponent-API.patch b/patches/api/0480-WIP-DataComponent-API.patch
index 62d9a052ec..46a7596471 100644
--- a/patches/api/0480-WIP-DataComponent-API.patch
+++ b/patches/api/0480-WIP-DataComponent-API.patch
@@ -138,7 +138,7 @@ index 0000000000000000000000000000000000000000..50d15b4e0ed5cd17fdc95476ee4650ef
+}
diff --git a/src/main/java/io/papermc/paper/component/DataComponentTypes.java b/src/main/java/io/papermc/paper/component/DataComponentTypes.java
new file mode 100644
-index 0000000000000000000000000000000000000000..5c76b3e09be7c6b525ff71aae5fd9233ed567876
+index 0000000000000000000000000000000000000000..40274b25355e351c796d51a2077e87f382b0adb8
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/DataComponentTypes.java
@@ -0,0 +1,311 @@
@@ -274,7 +274,7 @@ index 0000000000000000000000000000000000000000..5c76b3e09be7c6b525ff71aae5fd9233
+ /**
+ * If set, it will completely hide whole item tooltip (that includes item name)
+ */
-+ public static final DataComponentType.NonValued HIDE_TOOLTIP = unvalued("hide_tooltip");
++ public static final DataComponentType.NonValued HIDE_TOOLTIP = unvalued("hide_tooltip");
+ /**
+ * The additional experience cost required to modify an item in an Anvil.
+ * If not present, has an implicit default value of: {@code 0}
@@ -537,10 +537,10 @@ index 0000000000000000000000000000000000000000..1c4859bcabcc2a4a2e3b52253a984960
+}
diff --git a/src/main/java/io/papermc/paper/component/item/BundleContents.java b/src/main/java/io/papermc/paper/component/item/BundleContents.java
new file mode 100644
-index 0000000000000000000000000000000000000000..2f0ca3360ec033d335b80f269a0d9253d76a190c
+index 0000000000000000000000000000000000000000..e9efe98121d45890824d624a8cf66d3342ae84a3
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/item/BundleContents.java
-@@ -0,0 +1,42 @@
+@@ -0,0 +1,59 @@
+package io.papermc.paper.component.item;
+
+import io.papermc.paper.component.ComponentBuilder;
@@ -552,6 +552,9 @@ index 0000000000000000000000000000000000000000..2f0ca3360ec033d335b80f269a0d9253
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.Unmodifiable;
+
++/**
++ * Holds all items stored inside of a Bundle.
++ */
+public interface BundleContents {
+
@@ -570,25 +573,39 @@ index 0000000000000000000000000000000000000000..2f0ca3360ec033d335b80f269a0d9253
+ return ComponentTypesBridge.bridge().bundleContents();
+ }
+
++ /**
++ * Lists the items that are currently stored inside of this component.
++ * @return items
++ */
+ @Contract(value = "-> new", pure = true)
+ @NonNull @Unmodifiable List<@NonNull ItemStack> contents();
+
+ @ApiStatus.NonExtendable
+ interface Builder extends ComponentBuilder<BundleContents> {
+
++ /**
++ * Adds an item to this builder.
++ * @param stack item
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ @NonNull Builder add(@NonNull ItemStack stack);
+
++ /**
++ * Adds items to this builder.
++ * @param stacks items
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ @NonNull Builder addAll(@NonNull List<@NonNull ItemStack> stacks);
+ }
+}
diff --git a/src/main/java/io/papermc/paper/component/item/ChargedProjectiles.java b/src/main/java/io/papermc/paper/component/item/ChargedProjectiles.java
new file mode 100644
-index 0000000000000000000000000000000000000000..48f5b0a3bceb4312a5a2e10ee27811ce9036c4ff
+index 0000000000000000000000000000000000000000..13e7303189c38c79b4b0726841a2fd6fd8e720a6
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/item/ChargedProjectiles.java
-@@ -0,0 +1,42 @@
+@@ -0,0 +1,59 @@
+package io.papermc.paper.component.item;
+
+import io.papermc.paper.component.ComponentBuilder;
@@ -600,6 +617,9 @@ index 0000000000000000000000000000000000000000..48f5b0a3bceb4312a5a2e10ee27811ce
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.Unmodifiable;
+
++/**
++ * Holds all projectiles that have been loaded into a Crossbow.
++ */
+public interface ChargedProjectiles {
+
@@ -618,17 +638,31 @@ index 0000000000000000000000000000000000000000..48f5b0a3bceb4312a5a2e10ee27811ce
+ return ComponentTypesBridge.bridge().chargedProjectiles();
+ }
+
++ /**
++ * Lists the projectiles that are currently loaded into this component.
++ * @return
++ */
+ @Contract(value = "-> new", pure = true)
+ @NonNull @Unmodifiable List<@NonNull ItemStack> projectiles();
+
+ @ApiStatus.NonExtendable
+ interface Builder extends ComponentBuilder<ChargedProjectiles> {
+
++ /**
++ * Adds a projectile to be loaded in this builder.
++ * @param itemStack projectile
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ @NonNull Builder add(@NonNull ItemStack itemStack);
+
++ /**
++ * Adds projectiles to be loaded in this builder.
++ * @param itemStacks projectiles
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
-+ @NonNull Builder addAll(@NonNull List<@NonNull ItemStack> itemStack);
++ @NonNull Builder addAll(@NonNull List<@NonNull ItemStack> itemStacks);
+ }
+}
diff --git a/src/main/java/io/papermc/paper/component/item/ComponentTypesBridge.java b/src/main/java/io/papermc/paper/component/item/ComponentTypesBridge.java
@@ -759,10 +793,10 @@ index 0000000000000000000000000000000000000000..d8919127e181573ef5afe857cbc777a6
+}
diff --git a/src/main/java/io/papermc/paper/component/item/DyedItemColor.java b/src/main/java/io/papermc/paper/component/item/DyedItemColor.java
new file mode 100644
-index 0000000000000000000000000000000000000000..51ab59571e7c75cfc72d0d40bd5ed18d2f5014c2
+index 0000000000000000000000000000000000000000..ade9b048dd56f397278717fefc10a3c369603d30
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/item/DyedItemColor.java
-@@ -0,0 +1,31 @@
+@@ -0,0 +1,43 @@
+package io.papermc.paper.component.item;
+
+import io.papermc.paper.component.ComponentBuilder;
@@ -771,6 +805,9 @@ index 0000000000000000000000000000000000000000..51ab59571e7c75cfc72d0d40bd5ed18d
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Contract;
+
++/**
++ * Represents a color applied to a dyeable item.
++ */
+public interface DyedItemColor extends ShownInTooltip<DyedItemColor> {
+
@@ -784,22 +821,31 @@ index 0000000000000000000000000000000000000000..51ab59571e7c75cfc72d0d40bd5ed18d
+ return ComponentTypesBridge.bridge().dyedItemColor();
+ }
+
++ /**
++ * Color of the item.
++ * @return color
++ */
+ @Contract(value = "-> new", pure = true)
+ @NonNull Color color();
+
+ @ApiStatus.NonExtendable
+ interface Builder extends ShownInTooltip.Builder<Builder>, ComponentBuilder<DyedItemColor> {
+
++ /**
++ * Sets the color of this builder.
++ * @param color color
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ @NonNull Builder color(@NonNull Color color);
+ }
+}
diff --git a/src/main/java/io/papermc/paper/component/item/Fireworks.java b/src/main/java/io/papermc/paper/component/item/Fireworks.java
new file mode 100644
-index 0000000000000000000000000000000000000000..8e6b91f994b5790886f5da908bbee6f3867b4736
+index 0000000000000000000000000000000000000000..720ba84a3f7c426e6bb533e47ce4546725cc7136
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/item/Fireworks.java
-@@ -0,0 +1,42 @@
+@@ -0,0 +1,68 @@
+package io.papermc.paper.component.item;
+
+import io.papermc.paper.component.ComponentBuilder;
@@ -810,6 +856,9 @@ index 0000000000000000000000000000000000000000..8e6b91f994b5790886f5da908bbee6f3
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.Unmodifiable;
+
++/**
++ * Stores all explosions crafted into a Firework Rocket, as well as flight duration.
++ */
+public interface Fireworks {
+
@@ -823,41 +872,66 @@ index 0000000000000000000000000000000000000000..8e6b91f994b5790886f5da908bbee6f3
+ return ComponentTypesBridge.bridge().fireworks();
+ }
+
++ /**
++ * Lists the effects stored in this component.
++ * @return
++ */
+ @Contract(pure = true)
+ @NonNull @Unmodifiable List<@NonNull FireworkEffect> effects();
+
++ /**
++ * Number of gunpowder in this component.
++ * @return
++ */
+ @Contract(pure = true)
+ int flightDuration();
+
+ @ApiStatus.NonExtendable
+ interface Builder extends ComponentBuilder<Fireworks> {
+
++ /**
++ * Sets the number of gunpowder used in this builder.
++ * @param duration duration
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ @NonNull Builder flightDuration(int duration);
+
++ /**
++ * Adds an explosion to this builder.
++ * @param effect effect
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ @NonNull Builder add(@NonNull FireworkEffect effect);
+
++ /**
++ * Adds explosions to this builder.
++ * @param effects effects
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ @NonNull Builder addAll(@NonNull List<@NonNull FireworkEffect> effects);
+ }
+}
diff --git a/src/main/java/io/papermc/paper/component/item/FoodProperties.java b/src/main/java/io/papermc/paper/component/item/FoodProperties.java
new file mode 100644
-index 0000000000000000000000000000000000000000..fec96d323477fdf8fb410629ac2d23cd8f0a2ecb
+index 0000000000000000000000000000000000000000..18acee6c417e477770535e9c85a8efdf3700696d
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/item/FoodProperties.java
-@@ -0,0 +1,75 @@
+@@ -0,0 +1,109 @@
+package io.papermc.paper.component.item;
+
+import io.papermc.paper.component.ComponentBuilder;
+import java.util.List;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.potion.PotionEffect;
++import org.checkerframework.checker.index.qual.NonNegative;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.Nullable;
++import org.jetbrains.annotations.Range;
+import org.jetbrains.annotations.Unmodifiable;
+
@@ -868,15 +942,32 @@ index 0000000000000000000000000000000000000000..fec96d323477fdf8fb410629ac2d23cd
+ return ComponentTypesBridge.bridge().food();
+ }
+
++ /**
++ * Number of food points to restore when eaten
++ * @return non-negative integer
++ */
+ @Contract(pure = true)
++ @NonNegative
+ int nutrition();
+
++ /**
++ * Amount of saturation to restore when eaten
++ * @return saturation
++ */
+ @Contract(pure = true)
+ float saturation();
+
++ /**
++ * If true, this food can be eaten even if not hungry.
++ * @return can be eaten
++ */
+ @Contract(pure = true)
+ boolean canAlwaysEat();
+
++ /**
++ * The number of seconds that it takes to eat this food item.
++ * @return seconds
++ */
+ @Contract(pure = true)
+ float eatSeconds();
+
@@ -884,8 +975,15 @@ index 0000000000000000000000000000000000000000..fec96d323477fdf8fb410629ac2d23cd
+ @Contract(pure = true)
+ ItemStack usingConvertsTo();
+
++ /**
++ * List of effects to apply when eaten.
++ * @return effects
++ */
+ @Unmodifiable @NonNull List<@NonNull PossibleEffect> effects();
+
++ /**
++ * Effect to be applied when eaten.
++ */
+ @ApiStatus.NonExtendable
+ interface PossibleEffect {
+
@@ -893,8 +991,16 @@ index 0000000000000000000000000000000000000000..fec96d323477fdf8fb410629ac2d23cd
+ return ComponentTypesBridge.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();
+ }
+
@@ -925,10 +1031,10 @@ index 0000000000000000000000000000000000000000..fec96d323477fdf8fb410629ac2d23cd
+}
diff --git a/src/main/java/io/papermc/paper/component/item/ItemAdventurePredicate.java b/src/main/java/io/papermc/paper/component/item/ItemAdventurePredicate.java
new file mode 100644
-index 0000000000000000000000000000000000000000..65a2267ef0b0d8958ea54454f55a7c6d01fc0f33
+index 0000000000000000000000000000000000000000..3a16423dc37c6a56d86c1f07518c601ef6fbcbbc
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/item/ItemAdventurePredicate.java
-@@ -0,0 +1,31 @@
+@@ -0,0 +1,42 @@
+package io.papermc.paper.component.item;
+
+import io.papermc.paper.block.BlockPredicate;
@@ -941,6 +1047,9 @@ index 0000000000000000000000000000000000000000..65a2267ef0b0d8958ea54454f55a7c6d
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.Unmodifiable;
+
++/**
++ * Controls which blocks a player in Adventure mode can do a certain action with this item.
++ */
+public interface ItemAdventurePredicate extends ShownInTooltip<ItemAdventurePredicate> {
+
@@ -949,23 +1058,31 @@ index 0000000000000000000000000000000000000000..65a2267ef0b0d8958ea54454f55a7c6d
+ return ComponentTypesBridge.bridge().itemAdventurePredicate();
+ }
+
++ /**
++ * List of block predicates that control if the action is allowed.
++ * @return predicates
++ */
+ @Contract(pure = true)
+ @NonNull @Unmodifiable List<@NonNull BlockPredicate> modifiers();
+
-+
+ @ApiStatus.NonExtendable
+ interface Builder extends ShownInTooltip.Builder<Builder>, ComponentBuilder<ItemAdventurePredicate> {
-+
++ /**
++ * Adds a block predicate to this builder.
++ * @param predicate predicate
++ * @return self
++ * @see #modifiers()
++ */
+ @Contract(value = "_, _ -> this", mutates = "this")
+ @NonNull Builder addPredicate(@NonNull BlockPredicate predicate);
+ }
+}
diff --git a/src/main/java/io/papermc/paper/component/item/ItemArmorTrim.java b/src/main/java/io/papermc/paper/component/item/ItemArmorTrim.java
new file mode 100644
-index 0000000000000000000000000000000000000000..0d1ecd1e33a423df2ef07f1bf73334b06224b199
+index 0000000000000000000000000000000000000000..5a288237162c75fb0e969b894b719ba09a0c4a02
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/item/ItemArmorTrim.java
-@@ -0,0 +1,31 @@
+@@ -0,0 +1,43 @@
+package io.papermc.paper.component.item;
+
+import io.papermc.paper.component.ComponentBuilder;
@@ -974,6 +1091,9 @@ index 0000000000000000000000000000000000000000..0d1ecd1e33a423df2ef07f1bf73334b0
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Contract;
+
++/**
++ * Holds the trims applied to an item.
++ */
+public interface ItemArmorTrim extends ShownInTooltip<ItemArmorTrim> {
+
@@ -987,22 +1107,31 @@ index 0000000000000000000000000000000000000000..0d1ecd1e33a423df2ef07f1bf73334b0
+ return ComponentTypesBridge.bridge().itemArmorTrim(armorTrim);
+ }
+
++ /**
++ * Armor trim present on this item.
++ * @return trim
++ */
+ @Contract(pure = true)
+ @NonNull ArmorTrim armorTrim();
+
+ @ApiStatus.NonExtendable
+ interface Builder extends ShownInTooltip.Builder<Builder>, ComponentBuilder<ItemArmorTrim> {
+
++ /**
++ * Sets the item trim for this builder.
++ * @param armorTrim trim
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ @NonNull Builder armorTrim(@NonNull ArmorTrim armorTrim);
+ }
+}
diff --git a/src/main/java/io/papermc/paper/component/item/ItemAttributeModifiers.java b/src/main/java/io/papermc/paper/component/item/ItemAttributeModifiers.java
new file mode 100644
-index 0000000000000000000000000000000000000000..e0940c24da8c7f0480cf1bcb5c4600aa21cba170
+index 0000000000000000000000000000000000000000..3faf44b7864119f8bd14cfb835d91d29b6d48bbf
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/item/ItemAttributeModifiers.java
-@@ -0,0 +1,38 @@
+@@ -0,0 +1,55 @@
+package io.papermc.paper.component.item;
+
+import io.papermc.paper.component.ComponentBuilder;
@@ -1014,6 +1143,9 @@ index 0000000000000000000000000000000000000000..e0940c24da8c7f0480cf1bcb5c4600aa
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.Unmodifiable;
+
++/**
++ * Holds attribute modifiers applied to any item
++ */
+public interface ItemAttributeModifiers extends ShownInTooltip<ItemAttributeModifiers> {
+
@@ -1022,9 +1154,17 @@ index 0000000000000000000000000000000000000000..e0940c24da8c7f0480cf1bcb5c4600aa
+ return ComponentTypesBridge.bridge().modifiers();
+ }
+
++ /**
++ * Lists the attribute modifiers that are present on this item.
++ * @return modifiers
++ */
+ @Contract(pure = true)
+ @NonNull @Unmodifiable List<@NonNull Entry> modifiers();
+
++ /**
++ * Holds an attribute entry.
++ */
++ @ApiStatus.NonExtendable
+ interface Entry {
+
+ @Contract(pure = true)
@@ -1037,6 +1177,12 @@ index 0000000000000000000000000000000000000000..e0940c24da8c7f0480cf1bcb5c4600aa
+ @ApiStatus.NonExtendable
+ interface Builder extends ShownInTooltip.Builder<Builder>, ComponentBuilder<ItemAttributeModifiers> {
+
++ /**
++ * Adds a modifier to this builder.
++ * @param attribute attribute
++ * @param attributeModifier modifier
++ * @return self
++ */
+ @Contract(value = "_, _ -> this", mutates = "this")
+ @NonNull Builder addModifier(@NonNull Attribute attribute, @NonNull AttributeModifier attributeModifier);
+ }
@@ -1091,10 +1237,10 @@ index 0000000000000000000000000000000000000000..41c91487c3e60c744dba7cf0be86adce
+}
diff --git a/src/main/java/io/papermc/paper/component/item/ItemEnchantments.java b/src/main/java/io/papermc/paper/component/item/ItemEnchantments.java
new file mode 100644
-index 0000000000000000000000000000000000000000..7787de27d3931e9c305916228517fa3bbea83971
+index 0000000000000000000000000000000000000000..bc4773e8cac7a06dd92923486aa58615d6c0eb41
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/item/ItemEnchantments.java
-@@ -0,0 +1,37 @@
+@@ -0,0 +1,55 @@
+package io.papermc.paper.component.item;
+
+import io.papermc.paper.component.ComponentBuilder;
@@ -1106,6 +1252,9 @@ index 0000000000000000000000000000000000000000..7787de27d3931e9c305916228517fa3b
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.Unmodifiable;
+
++/**
++ * Stores a list of enchantments and their levels on an item.
++ */
+public interface ItemEnchantments extends ShownInTooltip<ItemEnchantments> {
+
@@ -1119,25 +1268,40 @@ index 0000000000000000000000000000000000000000..7787de27d3931e9c305916228517fa3b
+ return ComponentTypesBridge.bridge().enchantments();
+ }
+
++ /**
++ * Enchantments currently present on this item.
++ * @return enchantments
++ */
+ @Contract(pure = true)
+ @NonNull @Unmodifiable Map<@NonNull Enchantment, @NonNull @IntRange(from = 0, to = 255) Integer> enchantments();
+
+ @ApiStatus.NonExtendable
+ interface Builder extends ShownInTooltip.Builder<Builder>, ComponentBuilder<ItemEnchantments> {
+
++ /**
++ * Adds an enchantment with the given level to this component.
++ * @param enchantment enchantment
++ * @param level level
++ * @return self
++ */
+ @Contract(value = "_, _ -> this", mutates = "this")
+ @NonNull Builder add(@NonNull Enchantment enchantment, int level);
+
++ /**
++ * Adds enchantments with the given level to this component.
++ * @param enchantments enchantments
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ @NonNull Builder addAll(@NonNull Map<@NonNull Enchantment, @NonNull @IntRange(from = 0, to = 255) Integer> enchantments);
+ }
+}
diff --git a/src/main/java/io/papermc/paper/component/item/ItemLore.java b/src/main/java/io/papermc/paper/component/item/ItemLore.java
new file mode 100644
-index 0000000000000000000000000000000000000000..f2db3054e16bcdd615b98cc728d17f96b5e64582
+index 0000000000000000000000000000000000000000..35ae4f276be7edfd293a1ba3b4bebb99972f3e0d
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/item/ItemLore.java
-@@ -0,0 +1,43 @@
+@@ -0,0 +1,69 @@
+package io.papermc.paper.component.item;
+
+import io.papermc.paper.component.ComponentBuilder;
@@ -1149,6 +1313,9 @@ index 0000000000000000000000000000000000000000..f2db3054e16bcdd615b98cc728d17f96
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.Unmodifiable;
+
++/**
++ * Additional lines to include in an item's tooltip.
++ */
+public interface ItemLore {
+
@@ -1162,21 +1329,44 @@ index 0000000000000000000000000000000000000000..f2db3054e16bcdd615b98cc728d17f96
+ return ComponentTypesBridge.bridge().lore();
+ }
+
++ /**
++ * Lists the components that are added to an item's tooltip.
++ * @return component list
++ */
+ @Contract(pure = true)
+ @NonNull @Unmodifiable List<@NonNull Component> lines();
+
++ /**
++ * Lists the styled components (example: italicized and purple) that are added to an item's tooltip.
++ * @return component list
++ */
+ @Contract(pure = true)
+ @NonNull @Unmodifiable List<@NonNull Component> styledLines();
+
+ @ApiStatus.NonExtendable
+ interface Builder extends ComponentBuilder<ItemLore> {
+
++ /**
++ * Sets the components of this lore.
++ * @param lines components
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ Builder lines(@NonNull List<@NonNull ? extends ComponentLike> lines);
+
++ /**
++ * Adds a component to the lore.
++ * @param line component
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ @NonNull Builder addLine(@NonNull ComponentLike line);
+
++ /**
++ * Adds components to the lore.
++ * @param lines components
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ @NonNull Builder addAllLines(@NonNull List<@NonNull ? extends ComponentLike> lines);
+ }
@@ -1252,10 +1442,10 @@ index 0000000000000000000000000000000000000000..dfcd12fe3fed01ff93bce6eca732bd6f
+}
diff --git a/src/main/java/io/papermc/paper/component/item/LodestoneTracker.java b/src/main/java/io/papermc/paper/component/item/LodestoneTracker.java
new file mode 100644
-index 0000000000000000000000000000000000000000..2835c0ac093ce9b46b9a68228b61cf12187e6788
+index 0000000000000000000000000000000000000000..316e3e0894c0d5cc0a7b304a815803f90eb2c766
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/item/LodestoneTracker.java
-@@ -0,0 +1,38 @@
+@@ -0,0 +1,59 @@
+package io.papermc.paper.component.item;
+
+import io.papermc.paper.component.ComponentBuilder;
@@ -1265,6 +1455,9 @@ index 0000000000000000000000000000000000000000..2835c0ac093ce9b46b9a68228b61cf12
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Contract;
+
++/**
++ * If present, specifies the target Lodestone that a Compass should point towards.
++ */
+public interface LodestoneTracker {
+
@@ -1278,28 +1471,46 @@ index 0000000000000000000000000000000000000000..2835c0ac093ce9b46b9a68228b61cf12
+ return ComponentTypesBridge.bridge().lodestoneTracker();
+ }
+
++ /**
++ * The location that the compass should point towards.
++ * @return location
++ */
+ @Contract(value = "-> new", pure = true)
+ @Nullable Location location();
+
++ /**
++ * If true, when the Lodestone at the target position is removed, the component will be removed.
++ * @return tracked
++ */
+ @Contract(pure = true)
+ boolean tracked();
+
+ @ApiStatus.NonExtendable
+ interface Builder extends ComponentBuilder<LodestoneTracker> {
+
++ /**
++ * Sets the location to point towards for this builder.
++ * @param location location to point towards
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
-+ @NonNull Builder location(@Nullable Location page);
++ @NonNull Builder location(@Nullable Location location);
+
++ /**
++ * Sets if this location lodestone is tracked for this builder.
++ * @param tracked is tracked
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ @NonNull Builder tracked(boolean tracked);
+ }
+}
diff --git a/src/main/java/io/papermc/paper/component/item/MapDecorations.java b/src/main/java/io/papermc/paper/component/item/MapDecorations.java
new file mode 100644
-index 0000000000000000000000000000000000000000..3bca9c5b46d595b33535b538d1f4f625d349fda4
+index 0000000000000000000000000000000000000000..723f65d502a94617174203da02fda55f78621e2a
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/item/MapDecorations.java
-@@ -0,0 +1,57 @@
+@@ -0,0 +1,95 @@
+package io.papermc.paper.component.item;
+
+import io.papermc.paper.component.ComponentBuilder;
@@ -1310,6 +1521,9 @@ index 0000000000000000000000000000000000000000..3bca9c5b46d595b33535b538d1f4f625
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Contract;
+
++/**
++ * Holds a list of markers to be placed on a Filled Map (used for Explorer Maps)
++ */
+public interface MapDecorations {
+
@@ -1323,9 +1537,17 @@ index 0000000000000000000000000000000000000000..3bca9c5b46d595b33535b538d1f4f625
+ return ComponentTypesBridge.bridge().mapDecorations();
+ }
+
++ /**
++ * Gets the decoration entry with the given id.
++ * @param id id
++ * @return decoration entry, or null if not present
++ */
+ @Contract(pure = true)
+ @Nullable DecorationEntry getDecoration(@NonNull String id);
+
++ /**
++ * Decoration present on the map.
++ */
+ @ApiStatus.NonExtendable
+ interface DecorationEntry {
+
@@ -1334,15 +1556,31 @@ index 0000000000000000000000000000000000000000..3bca9c5b46d595b33535b538d1f4f625
+ return ComponentTypesBridge.bridge().decorationEntry(type, x, z, rotation);
+ }
+
++ /**
++ * Type of decoration.
++ * @return type
++ */
+ @Contract(pure = true)
+ MapCursor.@NonNull Type type();
+
++ /**
++ * X world coordinate of the decoration.
++ * @return x
++ */
+ @Contract(pure = true)
+ double x();
+
++ /**
++ * Z world coordinate of the decoration.
++ * @return z
++ */
+ @Contract(pure = true)
+ double z();
+
++ /**
++ * Clockwise rotation from north in degrees
++ * @return rotation
++ */
+ @Contract(pure = true)
+ float rotation();
+ }
@@ -1350,25 +1588,39 @@ index 0000000000000000000000000000000000000000..3bca9c5b46d595b33535b538d1f4f625
+ @ApiStatus.NonExtendable
+ interface Builder extends ComponentBuilder<MapDecorations> {
+
++ /**
++ * Puts the decoration with the given id in this builder.
++ * @param id id
++ * @param entry decoration
++ * @return self
++ */
+ @Contract(value = "_, _ -> this", mutates = "this")
+ MapDecorations.@NonNull Builder put(@NonNull String id, @NonNull DecorationEntry entry);
+
++ /**
++ * Puts all the decoration with the given id in this builder.
++ * @param entries decorations
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ MapDecorations.@NonNull Builder putAll(@NonNull Map<@NonNull String, @NonNull DecorationEntry> entries);
+ }
+}
diff --git a/src/main/java/io/papermc/paper/component/item/MapID.java b/src/main/java/io/papermc/paper/component/item/MapID.java
new file mode 100644
-index 0000000000000000000000000000000000000000..fb895caa1c5acc8116b9c52021835e186fdbacd5
+index 0000000000000000000000000000000000000000..d4a8ff6c9f82b35bf339f4cfa171a95c74327c7e
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/item/MapID.java
-@@ -0,0 +1,27 @@
+@@ -0,0 +1,39 @@
+package io.papermc.paper.component.item;
+
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Contract;
+
++/**
++ * References the shared map state holding map contents and markers for a Filled Map.
++ */
+public interface MapID {
+
@@ -1377,12 +1629,21 @@ index 0000000000000000000000000000000000000000..fb895caa1c5acc8116b9c52021835e18
+ return ComponentTypesBridge.bridge().mapId();
+ }
+
++ /**
++ * The map id.
++ * @return id
++ */
+ @Contract(pure = true)
+ int id();
+
+ @ApiStatus.NonExtendable
+ interface Builder {
+
++ /**
++ * Sets the map id of this builder
++ * @param id id
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ @NonNull Builder mapId(int id);
+
@@ -1392,10 +1653,10 @@ index 0000000000000000000000000000000000000000..fb895caa1c5acc8116b9c52021835e18
+}
diff --git a/src/main/java/io/papermc/paper/component/item/MapItemColor.java b/src/main/java/io/papermc/paper/component/item/MapItemColor.java
new file mode 100644
-index 0000000000000000000000000000000000000000..025e2edd791db72b87f4e43bdda6647cfe6b3d7e
+index 0000000000000000000000000000000000000000..fdcf1f092fe52d9f111b47651a5f7eba6d28692d
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/item/MapItemColor.java
-@@ -0,0 +1,27 @@
+@@ -0,0 +1,39 @@
+package io.papermc.paper.component.item;
+
+import org.bukkit.Color;
@@ -1403,6 +1664,9 @@ index 0000000000000000000000000000000000000000..025e2edd791db72b87f4e43bdda6647c
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Contract;
+
++/**
++ * Represents the tint of the decorations on the Filled Map item.
++ */
+public interface MapItemColor {
+
@@ -1411,11 +1675,20 @@ index 0000000000000000000000000000000000000000..025e2edd791db72b87f4e43bdda6647c
+ return ComponentTypesBridge.bridge().mapItemColor();
+ }
+
++ /**
++ * The tint to apply.
++ * @return color
++ */
+ @NonNull Color mapColor();
+
+ @ApiStatus.NonExtendable
+ interface Builder {
+
++ /**
++ * Sets the map color of this builder.
++ * @param color color
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ @NonNull Builder mapColor(@NonNull Color color);
+
@@ -1493,10 +1766,10 @@ index 0000000000000000000000000000000000000000..fb2f3d705102cf67c847b2b2d38cc239
+}
diff --git a/src/main/java/io/papermc/paper/component/item/PotionContents.java b/src/main/java/io/papermc/paper/component/item/PotionContents.java
new file mode 100644
-index 0000000000000000000000000000000000000000..902d93544b686440442d2e29f6df3ce85f5a996f
+index 0000000000000000000000000000000000000000..d25430f52d95f90875f4052b39e652282275c8e7
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/item/PotionContents.java
-@@ -0,0 +1,46 @@
+@@ -0,0 +1,85 @@
+package io.papermc.paper.component.item;
+
+import io.papermc.paper.component.ComponentBuilder;
@@ -1510,6 +1783,9 @@ index 0000000000000000000000000000000000000000..902d93544b686440442d2e29f6df3ce8
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.Unmodifiable;
+
++/**
++ * Holds the contents of a potion (Potion, Splash Potion, Lingering Potion), or potion applied to an item (Tipped Arrow)
++ */
+public interface PotionContents {
+
@@ -1518,27 +1794,63 @@ index 0000000000000000000000000000000000000000..902d93544b686440442d2e29f6df3ce8
+ return ComponentTypesBridge.bridge().potionContents();
+ }
+
++ /**
++ * The potion type in this item: the item will inherit all effects from this.
++ * @return potion type, or null if not present
++ */
+ @Contract(pure = true)
+ @Nullable PotionType potion();
+
++ /**
++ * Overrides the visual color of the potion
++ * @return color override, or null if not present
++ */
+ @Contract(pure = true)
+ @Nullable Color customColor();
+
++ /**
++ * Additional list of effect instances that this item should apply.
++ * @return effects
++ */
+ @Contract(pure = true)
+ @Unmodifiable @NonNull List<@NonNull PotionEffect> customEffects();
+
+ @ApiStatus.NonExtendable
+ interface Builder extends ComponentBuilder<PotionContents> {
+
++ /**
++ * Sets the potion type for this builder
++ * @param potionType builder
++ * @see #potion()
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ @NonNull Builder potion(@Nullable PotionType potionType);
+
++ /**
++ * Sets the color override for this builder.
++ * @param color color
++ * @see #customColor()
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ @NonNull Builder customColor(@Nullable Color color);
+
++ /**
++ * Adds a custom effect instance to this builder.
++ * @param potionEffect effect
++ * @see #customEffects()
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ @NonNull Builder add(@NonNull PotionEffect potionEffect);
+
++ /**
++ * Adds custom effect instances to this builder.
++ * @param potionEffects effects
++ * @see #customEffects()
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ @NonNull Builder addAll(@NonNull List<@NonNull PotionEffect> potionEffects);
+ }
@@ -1672,10 +1984,10 @@ index 0000000000000000000000000000000000000000..75c4ede2e9a2913a2bd542935b0bcaba
+}
diff --git a/src/main/java/io/papermc/paper/component/item/SuspiciousStewEffects.java b/src/main/java/io/papermc/paper/component/item/SuspiciousStewEffects.java
new file mode 100644
-index 0000000000000000000000000000000000000000..59c559fc0c139a6b688ef69a484e24c1d3543007
+index 0000000000000000000000000000000000000000..84e1c430acb5f488dc6835c1269586873dae5026
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/item/SuspiciousStewEffects.java
-@@ -0,0 +1,42 @@
+@@ -0,0 +1,59 @@
+package io.papermc.paper.component.item;
+
+import io.papermc.paper.component.ComponentBuilder;
@@ -1687,6 +1999,9 @@ index 0000000000000000000000000000000000000000..59c559fc0c139a6b688ef69a484e24c1
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.Unmodifiable;
+
++/**
++ * Holds the effects that will be applied when consuming Suspicious Stew
++ */
+public interface SuspiciousStewEffects {
+
@@ -1705,25 +2020,39 @@ index 0000000000000000000000000000000000000000..59c559fc0c139a6b688ef69a484e24c1
+ return ComponentTypesBridge.bridge().suspiciousStewEffects();
+ }
+
++ /**
++ * Effects that will be applied when consuming Suspicious Stew.
++ * @return effects
++ */
+ @Contract(pure = true)
+ @NonNull @Unmodifiable List<@NonNull SuspiciousEffectEntry> effects();
+
+ @ApiStatus.NonExtendable
+ interface Builder extends ComponentBuilder<SuspiciousStewEffects> {
+
++ /**
++ * Adds an effect applied to this builder.
++ * @param entry effect
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ @NonNull Builder add(@NonNull SuspiciousEffectEntry entry);
+
++ /**
++ * Adds effects applied to this builder.
++ * @param entries effect
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ @NonNull Builder addAll(@NonNull List<@NonNull SuspiciousEffectEntry> entries);
+ }
+}
diff --git a/src/main/java/io/papermc/paper/component/item/Tool.java b/src/main/java/io/papermc/paper/component/item/Tool.java
new file mode 100644
-index 0000000000000000000000000000000000000000..13ac8404c63ffdd08392c07915a07ebff57efae3
+index 0000000000000000000000000000000000000000..848cf03f35e2fe07373d8281082c1d8d633ad3f7
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/item/Tool.java
-@@ -0,0 +1,78 @@
+@@ -0,0 +1,128 @@
+package io.papermc.paper.component.item;
+
+import io.papermc.paper.component.ComponentBuilder;
@@ -1734,6 +2063,7 @@ index 0000000000000000000000000000000000000000..13ac8404c63ffdd08392c07915a07ebf
+import org.bukkit.block.BlockType;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.potion.PotionEffect;
++import org.checkerframework.checker.index.qual.NonNegative;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Contract;
@@ -1741,6 +2071,9 @@ index 0000000000000000000000000000000000000000..13ac8404c63ffdd08392c07915a07ebf
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.Unmodifiable;
+
++/**
++ * Controls the behavior of the item as a tool.
++ */
+public interface Tool {
+
@@ -1749,12 +2082,24 @@ index 0000000000000000000000000000000000000000..13ac8404c63ffdd08392c07915a07ebf
+ return ComponentTypesBridge.bridge().tool();
+ }
+
++ /**
++ * Mining speed to use if no rules match and don't override mining speed
++ * @return default mining speed
++ */
+ @Contract(pure = true)
+ float defaultMiningSpeed();
+
++ /**
++ * Amount of durability to remove each time a block is mined with this tool
++ * @return durability
++ */
+ @Contract(pure = true)
-+ int damagePerBlock();
++ @NonNegative int damagePerBlock();
+
++ /**
++ * List of rule entries
++ * @return rules
++ */
+ @Contract(pure = true)
+ @NonNull @Unmodifiable List<Tool.@NonNull Rule> rules();
+
@@ -1777,11 +2122,25 @@ index 0000000000000000000000000000000000000000..13ac8404c63ffdd08392c07915a07ebf
+ return of(tag, speed, TriState.NOT_SET);
+ }
+
++ /**
++ * Blocks to match.
++ * @return blocks
++ */
+ @NonNull RegistryKeySet<BlockType> blockTypes();
+
++ /**
++ * Overrides the mining speed if present and matched.
++ * <p>
++ * {@code true} will cause the block to mine at its most efficient speed, and drop items if the targeted block requires that.
++ * @return speed override
++ */
+ @Nullable
+ Float speed();
+
++ /**
++ * Overrides whether this tool is considered 'correct' if present and matched.
++ * @return
++ */
+ @NotNull
+ TriState correctForDrops();
+ }
@@ -1789,25 +2148,45 @@ index 0000000000000000000000000000000000000000..13ac8404c63ffdd08392c07915a07ebf
+ @ApiStatus.NonExtendable
+ interface Builder extends ComponentBuilder<Tool> {
+
++ /**
++ * Controls the amount of durability to remove each time a block is mined with this tool.
++ * @param damage durability to remove
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ @NonNull Builder damagePerBlock(@NonNull int damage);
+
++ /**
++ * Controls mining speed to use if no rules match and don't override mining speed.
++ * @param speed mining speed
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ @NonNull Builder defaultMiningSpeed(float speed);
+
++ /**
++ * Adds a rule to the tool that controls the breaking speed / damage per block if matched.
++ * @param rule rule
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ @NonNull Builder addRule(@NonNull Rule rule);
+
++ /**
++ * Adds rules to the tool that control the breaking speed / damage per block if matched.
++ * @param rules rules
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ @NonNull Builder addRules(@NonNull List<@NonNull Rule> rules);
+ }
+}
diff --git a/src/main/java/io/papermc/paper/component/item/Unbreakable.java b/src/main/java/io/papermc/paper/component/item/Unbreakable.java
new file mode 100644
-index 0000000000000000000000000000000000000000..fb0e8598ea179b180aa8513271b8aaf020ce46ee
+index 0000000000000000000000000000000000000000..bae28273ffa8017fecb24328f21b6a4622326273
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/item/Unbreakable.java
-@@ -0,0 +1,24 @@
+@@ -0,0 +1,27 @@
+package io.papermc.paper.component.item;
+
+import io.papermc.paper.component.ComponentBuilder;
@@ -1815,6 +2194,9 @@ index 0000000000000000000000000000000000000000..fb0e8598ea179b180aa8513271b8aaf0
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Contract;
+
++/**
++ * If set, the item will not lose any durability when used.
++ */
+public interface Unbreakable extends ShownInTooltip<Unbreakable> {
+
@@ -1834,10 +2216,10 @@ index 0000000000000000000000000000000000000000..fb0e8598ea179b180aa8513271b8aaf0
+}
diff --git a/src/main/java/io/papermc/paper/component/item/WritableBookContent.java b/src/main/java/io/papermc/paper/component/item/WritableBookContent.java
new file mode 100644
-index 0000000000000000000000000000000000000000..e59a79339b31a914d8063a1aa6949a598f852a8c
+index 0000000000000000000000000000000000000000..368662920dda88a35d61c9f98d41e4a84626999d
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/item/WritableBookContent.java
-@@ -0,0 +1,38 @@
+@@ -0,0 +1,62 @@
+package io.papermc.paper.component.item;
+
+import io.papermc.paper.component.ComponentBuilder;
@@ -1857,31 +2239,55 @@ index 0000000000000000000000000000000000000000..e59a79339b31a914d8063a1aa6949a59
+ return ComponentTypesBridge.bridge().writeableBookContent();
+ }
+
++ /**
++ * Holds the pages that can be written to for this component.
++ * @return pages, as filtered objects
++ */
+ @Contract(pure = true)
+ @NonNull @Unmodifiable List<@NonNull Filtered<String>> pages();
+
+ @ApiStatus.NonExtendable
+ interface Builder extends ComponentBuilder<WritableBookContent> {
+
++ /**
++ * Adds a page that can be written to for this builder.
++ * @param page page
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ @NonNull Builder addPage(@NonNull String page);
+
++ /**
++ * Adds pages that can be written to for this builder.
++ * @param pages pages
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
-+ @NonNull Builder addPages(@NonNull Collection<@NonNull String> page);
++ @NonNull Builder addPages(@NonNull Collection<@NonNull String> pages);
+
++ /**
++ * Adds a filterable page that can be written to for this builder.
++ * @param page page
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ @NonNull Builder addPageFiltered(@NonNull Filtered<@NonNull String> page);
+
++ /**
++ * Adds filterable pages that can be written to for this builder.
++ * @param pages pages
++ * @return self
++ */
+ @Contract(value = "_ -> this", mutates = "this")
+ @NonNull Builder addPagesFiltered(@NonNull Collection<@NonNull Filtered<@NonNull String>> pages);
+ }
+}
diff --git a/src/main/java/io/papermc/paper/component/item/WrittenBookContent.java b/src/main/java/io/papermc/paper/component/item/WrittenBookContent.java
new file mode 100644
-index 0000000000000000000000000000000000000000..671b0e9b35863b2137fcf778fbba1fdd7dea58e6
+index 0000000000000000000000000000000000000000..f33aa2d9528b96df98b40cd9d0b052cfcebe20de
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/item/WrittenBookContent.java
-@@ -0,0 +1,72 @@
+@@ -0,0 +1,92 @@
+package io.papermc.paper.component.item;
+
+import io.papermc.paper.component.ComponentBuilder;
@@ -1895,6 +2301,9 @@ index 0000000000000000000000000000000000000000..671b0e9b35863b2137fcf778fbba1fdd
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.Unmodifiable;
+
++/**
++ * Holds the contents and metadata of a Written Book.
++ */
+public interface WrittenBookContent {
+
@@ -1908,18 +2317,35 @@ index 0000000000000000000000000000000000000000..671b0e9b35863b2137fcf778fbba1fdd
+ return ComponentTypesBridge.bridge().writtenBookContent(title, author);
+ }
+
++ /**
++ * Title of this book.
++ * @return title
++ */
+ @Contract(pure = true)
+ @NonNull Filtered<@NonNull String> title();
+
++ /**
++ * Player name of the author of this book.
++ * @return author
++ */
+ @Contract(pure = true)
+ @NonNull String author();
+
++ /**
++ * The number of times this book has been copied (0 = original)
++ * @return generation
++ */
+ @Contract(pure = true)
+ int generation();
+
+ @Contract(pure = true)
+ @NonNull @Unmodifiable List<@NonNull Filtered<@NonNull Component>> pages();
+
++ /**
++ * If the chat components in this book have already been resolved (entity selectors, scores substituted)
++ * If false, will be resolved when opened by a player
++ * @return resolved
++ */
+ @Contract(pure = true)
+ boolean resolved();
+
diff --git a/patches/server/1026-WIP-DataComponent-API.patch b/patches/server/1026-WIP-DataComponent-API.patch
index f43fbcfb27..d1fccc8973 100644
--- a/patches/server/1026-WIP-DataComponent-API.patch
+++ b/patches/server/1026-WIP-DataComponent-API.patch
@@ -765,7 +765,7 @@ index 0000000000000000000000000000000000000000..fbd9a0a1eb447d1a5ab0e898d9dc80b6
+}
diff --git a/src/main/java/io/papermc/paper/component/item/PaperChargedProjectiles.java b/src/main/java/io/papermc/paper/component/item/PaperChargedProjectiles.java
new file mode 100644
-index 0000000000000000000000000000000000000000..6a3d6541d1d009a882f717f3d10920f49b627519
+index 0000000000000000000000000000000000000000..862eb057c156117b5856cd9bc453a6e378c972e6
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/item/PaperChargedProjectiles.java
@@ -0,0 +1,51 @@
@@ -807,8 +807,8 @@ index 0000000000000000000000000000000000000000..6a3d6541d1d009a882f717f3d10920f4
+ }
+
+ @Override
-+ public ChargedProjectiles.Builder addAll(final List<ItemStack> itemStack) {
-+ for (final ItemStack item : itemStack) {
++ public ChargedProjectiles.Builder addAll(final List<ItemStack> itemStacks) {
++ for (final ItemStack item : itemStacks) {
+ this.items.add(CraftItemStack.asNMSCopy(item));
+ }
+ return this;
@@ -1917,7 +1917,7 @@ index 0000000000000000000000000000000000000000..0e6320385a3eaea265bd3ffd2a9ee831
+}
diff --git a/src/main/java/io/papermc/paper/component/item/PaperLodestoneTracker.java b/src/main/java/io/papermc/paper/component/item/PaperLodestoneTracker.java
new file mode 100644
-index 0000000000000000000000000000000000000000..eb9bf45b5599d72be4f54452437cce565a1140ec
+index 0000000000000000000000000000000000000000..5611a001165a32f39a26ce171142420ed704430b
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/item/PaperLodestoneTracker.java
@@ -0,0 +1,56 @@
@@ -1958,8 +1958,8 @@ index 0000000000000000000000000000000000000000..eb9bf45b5599d72be4f54452437cce56
+ private boolean tracked = true;
+
+ @Override
-+ public LodestoneTracker.Builder location(final @Nullable Location page) {
-+ this.pos = Optional.ofNullable(page).map(CraftMemoryMapper::toNms);
++ public LodestoneTracker.Builder location(final @Nullable Location location) {
++ this.pos = Optional.ofNullable(location).map(CraftMemoryMapper::toNms);
+ return this;
+ }
+
@@ -3204,33 +3204,84 @@ index 0000000000000000000000000000000000000000..a2c02206254a18e089cb2b40eab5c59e
+io.papermc.paper.component.item.ComponentTypesBridgesImpl
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..3ee8696686d4e91de57e2dbb2772c9313dc4c21b
+index 0000000000000000000000000000000000000000..f53fb0732aa3a90ebc75dc786cc61d0037fa5648
--- /dev/null
+++ b/src/test/java/io/papermc/paper/item/ItemStackDataComponentTest.java
-@@ -0,0 +1,127 @@
+@@ -0,0 +1,391 @@
+package io.papermc.paper.item;
+
++import ca.spottedleaf.concurrentutil.util.CollectionUtil;
++import com.google.common.collect.HashMultiset;
++import com.google.common.collect.Iterators;
++import com.google.common.collect.Lists;
++import io.papermc.paper.block.BlockPredicate;
+import io.papermc.paper.component.DataComponentType;
+import io.papermc.paper.component.DataComponentTypes;
+import io.papermc.paper.component.item.ChargedProjectiles;
++import io.papermc.paper.component.item.CustomModelData;
++import io.papermc.paper.component.item.DyedItemColor;
++import io.papermc.paper.component.item.Fireworks;
++import io.papermc.paper.component.item.FoodProperties;
++import io.papermc.paper.component.item.ItemAdventurePredicate;
++import io.papermc.paper.component.item.ItemArmorTrim;
++import io.papermc.paper.component.item.ItemAttributeModifiers;
++import io.papermc.paper.component.item.ItemEnchantments;
++import io.papermc.paper.component.item.ItemLore;
++import io.papermc.paper.component.item.MapID;
++import io.papermc.paper.component.item.MapItemColor;
+import io.papermc.paper.component.item.PotDecorations;
++import io.papermc.paper.component.item.Tool;
+import io.papermc.paper.component.item.Unbreakable;
++import io.papermc.paper.registry.RegistryAccess;
++import io.papermc.paper.registry.RegistryKey;
++import io.papermc.paper.registry.set.RegistrySet;
++import io.papermc.paper.registry.tag.TagKey;
++import net.kyori.adventure.text.Component;
++import net.kyori.adventure.util.TriState;
++import net.minecraft.world.item.enchantment.Enchantments;
++import net.minecraft.world.level.saveddata.maps.MapId;
++import org.bukkit.Color;
++import org.bukkit.FireworkEffect;
+import org.bukkit.Material;
++import org.bukkit.NamespacedKey;
++import org.bukkit.Registry;
++import org.bukkit.Tag;
++import org.bukkit.attribute.Attribute;
++import org.bukkit.attribute.AttributeModifier;
+import org.bukkit.block.BlockState;
++import org.bukkit.block.BlockType;
+import org.bukkit.block.DecoratedPot;
++import org.bukkit.enchantments.Enchantment;
++import org.bukkit.inventory.EquipmentSlotGroup;
+import org.bukkit.inventory.ItemFlag;
++import org.bukkit.inventory.ItemRarity;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.ItemType;
++import org.bukkit.inventory.meta.ArmorMeta;
+import org.bukkit.inventory.meta.BlockStateMeta;
+import org.bukkit.inventory.meta.CrossbowMeta;
+import org.bukkit.inventory.meta.Damageable;
++import org.bukkit.inventory.meta.FireworkMeta;
+import org.bukkit.inventory.meta.ItemMeta;
++import org.bukkit.inventory.meta.LeatherArmorMeta;
++import org.bukkit.inventory.meta.MapMeta;
+import org.bukkit.inventory.meta.Repairable;
++import org.bukkit.inventory.meta.components.FoodComponent;
++import org.bukkit.inventory.meta.components.ToolComponent;
++import org.bukkit.inventory.meta.trim.ArmorTrim;
++import org.bukkit.inventory.meta.trim.TrimMaterial;
++import org.bukkit.inventory.meta.trim.TrimPattern;
++import org.bukkit.potion.PotionEffect;
++import org.bukkit.potion.PotionEffectType;
+import org.bukkit.support.AbstractTestingBase;
++import org.codehaus.plexus.util.CollectionUtils;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
++import java.util.List;
++import java.util.Map;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
++import java.util.stream.Collectors;
+
+class ItemStackDataComponentTest extends AbstractTestingBase {
+
@@ -3259,7 +3310,7 @@ index 0000000000000000000000000000000000000000..3ee8696686d4e91de57e2dbb2772c931
+
+ Assertions.assertTrue(stack.getItemMeta().isUnbreakable());
+ Assertions.assertTrue(stack.getItemMeta().getItemFlags().contains(ItemFlag.HIDE_UNBREAKABLE));
-+ stack.setData(DataComponentTypes.UNBREAKABLE, null);
++ stack.unsetData(DataComponentTypes.UNBREAKABLE);
+ Assertions.assertFalse(stack.getItemMeta().isUnbreakable());
+ }
+
@@ -3296,6 +3347,195 @@ index 0000000000000000000000000000000000000000..3ee8696686d4e91de57e2dbb2772c931
+ }
+
+ @Test
++ void testCustomName() {
++ testWithMeta(new ItemStack(Material.STONE), DataComponentTypes.CUSTOM_NAME, Component.text("HELLO!!!!!!"), ItemMeta.class, ItemMeta::displayName, ItemMeta::displayName);
++ }
++
++ @Test
++ void testItemName() {
++ testWithMeta(new ItemStack(Material.STONE), DataComponentTypes.ITEM_NAME, Component.text("HELLO!!!!!! ITEM NAME"), ItemMeta.class, ItemMeta::itemName, ItemMeta::itemName);
++ }
++
++ @Test
++ void testItemLore() {
++ List<Component> list = List.of(Component.text("1"), Component.text("2"));
++ testWithMeta(new ItemStack(Material.STONE), DataComponentTypes.LORE, ItemLore.lore().lines(list).build(), ItemLore::lines, ItemMeta.class, ItemMeta::lore, ItemMeta::lore);
++ }
++
++ @Test
++ void testItemRarity() {
++ testWithMeta(new ItemStack(Material.STONE), DataComponentTypes.RARITY, ItemRarity.RARE, ItemMeta.class, ItemMeta::getRarity, ItemMeta::setRarity);
++ }
++
++ @Test
++ void testItemEnchantments() {
++ final ItemStack stack = new ItemStack(Material.STONE);
++ Map<Enchantment, Integer> enchantmentIntegerMap = Map.of(Enchantment.SOUL_SPEED, 1);
++ stack.setData(DataComponentTypes.ENCHANTMENTS, ItemEnchantments.itemEnchantments(enchantmentIntegerMap, false));
++
++ Assertions.assertTrue(stack.getItemMeta().hasItemFlag(ItemFlag.HIDE_ENCHANTS));
++ Assertions.assertEquals(1, stack.getItemMeta().getEnchantLevel(Enchantment.SOUL_SPEED));
++ Assertions.assertEquals(stack.getItemMeta().getEnchants(), enchantmentIntegerMap);
++ stack.unsetData(DataComponentTypes.ENCHANTMENTS);
++ Assertions.assertTrue(stack.getItemMeta().getEnchants().isEmpty());
++ }
++
++
++ @Test
++ void testItemAttributes() {
++ final ItemStack stack = new ItemStack(Material.STONE);
++ AttributeModifier modifier = new AttributeModifier(NamespacedKey.minecraft("test"), 5, AttributeModifier.Operation.ADD_NUMBER, EquipmentSlotGroup.ANY);
++ stack.setData(DataComponentTypes.ATTRIBUTE_MODIFIERS, ItemAttributeModifiers.itemAttributes().showInTooltip(false).addModifier(Attribute.GENERIC_ATTACK_DAMAGE, modifier).build());
++
++
++ Assertions.assertTrue(stack.getItemMeta().hasItemFlag(ItemFlag.HIDE_ATTRIBUTES));
++ Assertions.assertEquals(modifier, Iterators.get(stack.getItemMeta().getAttributeModifiers(Attribute.GENERIC_ATTACK_DAMAGE).iterator(), 0));
++ stack.unsetData(DataComponentTypes.ATTRIBUTE_MODIFIERS);
++ Assertions.assertNull(stack.getItemMeta().getAttributeModifiers());
++ }
++
++
++ @Test
++ void testCustomModelData() {
++ testWithMeta(new ItemStack(Material.STONE), DataComponentTypes.CUSTOM_MODEL_DATA, CustomModelData.customModelData().customModelData(1).build(), CustomModelData::data, ItemMeta.class, ItemMeta::getCustomModelData, ItemMeta::setCustomModelData);
++ }
++
++ @Test
++ void testEnchantmentGlintOverride() {
++ testWithMeta(new ItemStack(Material.STONE), DataComponentTypes.ENCHANTMENT_GLINT_OVERRIDE, true, ItemMeta.class, ItemMeta::getEnchantmentGlintOverride, ItemMeta::setEnchantmentGlintOverride);
++ }
++
++ @Test
++ void testFood() {
++ FoodProperties properties = FoodProperties.food()
++ .canAlwaysEat(true)
++ .eatSeconds(1.3F)
++ .nutrition(1)
++ .addAllEffects(List.of(FoodProperties.PossibleEffect.of(new PotionEffect(PotionEffectType.SLOWNESS, 5, 255), 1F)))
++ .usingConvertsTo(new ItemStack(Material.STONE))
++ .build();
++
++ final ItemStack stack = new ItemStack(Material.CROSSBOW);
++ stack.setData(DataComponentTypes.FOOD, properties);
++
++ ItemMeta meta = stack.getItemMeta();
++ FoodComponent component = meta.getFood();
++ Assertions.assertEquals(properties.canAlwaysEat(), component.canAlwaysEat());
++ Assertions.assertEquals(properties.eatSeconds(), component.getEatSeconds());
++ 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 = (CrossbowMeta) stack.getItemMeta();
++ Assertions.assertFalse(meta.hasFood());
++ }
++
++ @Test
++ void testTool() {
++ Tool properties = Tool.tool()
++ .damagePerBlock(1)
++ .defaultMiningSpeed(2F)
++ .addRules(List.of(
++ Tool.Rule.of(
++ RegistrySet.keySetFromValues(RegistryKey.BLOCK, List.of(BlockType.STONE, BlockType.GRAVEL)),
++ 2F,
++ TriState.TRUE
++
++ ),
++ Tool.Rule.of(
++ RegistryAccess.registryAccess().getRegistry(RegistryKey.BLOCK).getTag(TagKey.create(RegistryKey.BLOCK, NamespacedKey.minecraft("bamboo_blocks"))),
++ 2F,
++ TriState.TRUE
++
++ )
++
++
++ ))
++ .build();
++
++ final ItemStack stack = new ItemStack(Material.CROSSBOW);
++ stack.setData(DataComponentTypes.TOOL, properties);
++
++ ItemMeta meta = stack.getItemMeta();
++ ToolComponent component = meta.getTool();
++ Assertions.assertEquals(properties.damagePerBlock(), component.getDamagePerBlock());
++ Assertions.assertEquals(properties.defaultMiningSpeed(), component.getDefaultMiningSpeed());
++
++ int idx = 0;
++ for (ToolComponent.ToolRule effect : component.getRules()) {
++ Assertions.assertEquals(properties.rules().get(idx).speed(), effect.getSpeed());
++ Assertions.assertEquals(properties.rules().get(idx).correctForDrops().toBoolean(), effect.isCorrectForDrops());
++ Assertions.assertEquals(properties.rules().get(idx).blockTypes().resolve(Registry.BLOCK), effect.getBlocks().stream().map(Material::asBlockType).toList());
++ idx++;
++ }
++
++
++ stack.unsetData(DataComponentTypes.TOOL);
++ meta = stack.getItemMeta();
++ Assertions.assertFalse(meta.hasTool());
++ }
++
++
++ @Test
++ void testFireResistant() {
++ testWithMeta(new ItemStack(Material.STONE), DataComponentTypes.FIRE_RESISTANT, true, ItemMeta.class, ItemMeta::isFireResistant, ItemMeta::setFireResistant);
++ }
++
++ @Test
++ void testDyedColor() {
++ final ItemStack stack = new ItemStack(Material.LEATHER_CHESTPLATE);
++ Color color = Color.BLUE;
++ stack.setData(DataComponentTypes.DYED_COLOR, DyedItemColor.dyedItemColor(color, false));
++
++ Assertions.assertTrue(stack.getItemMeta().hasItemFlag(ItemFlag.HIDE_DYE));
++ Assertions.assertEquals(color, ((LeatherArmorMeta) stack.getItemMeta()).getColor());
++ stack.unsetData(DataComponentTypes.DYED_COLOR);
++ Assertions.assertFalse(((LeatherArmorMeta) stack.getItemMeta()).isDyed());
++ }
++
++ @Test
++ void testMapColor() {
++ testWithMeta(new ItemStack(Material.FILLED_MAP), DataComponentTypes.MAP_COLOR, MapItemColor.mapItemColor().mapColor(Color.BLUE).build(), MapItemColor::mapColor, MapMeta.class, MapMeta::getColor, MapMeta::setColor);
++ }
++
++ @Test
++ void testMapId() {
++ testWithMeta(new ItemStack(Material.FILLED_MAP), DataComponentTypes.MAP_ID, MapID.mapId().mapId(1).build(), MapID::id, MapMeta.class, MapMeta::getMapId, MapMeta::setMapId);
++ }
++
++ @Test
++ void testFireworks() {
++ testWithMeta(new ItemStack(Material.FIREWORK_ROCKET), DataComponentTypes.FIREWORKS, Fireworks.fireworks(List.of(FireworkEffect.builder().build()), 1), Fireworks::effects, FireworkMeta.class, FireworkMeta::getEffects, (fireworkMeta, o) -> {
++ fireworkMeta.clearEffects();
++ fireworkMeta.addEffects(o);
++ });
++
++ testWithMeta(new ItemStack(Material.FIREWORK_ROCKET), DataComponentTypes.FIREWORKS, Fireworks.fireworks(List.of(FireworkEffect.builder().build()), 1), Fireworks::flightDuration, FireworkMeta.class, FireworkMeta::getPower, FireworkMeta::setPower);
++ }
++
++ @Test
++ void testTrim() {
++ final ItemStack stack = new ItemStack(Material.LEATHER_CHESTPLATE);
++ ItemArmorTrim armorTrim = ItemArmorTrim.itemArmorTrim(new ArmorTrim(TrimMaterial.AMETHYST, TrimPattern.BOLT), false);
++ stack.setData(DataComponentTypes.TRIM, armorTrim);
++
++ Assertions.assertTrue(stack.getItemMeta().hasItemFlag(ItemFlag.HIDE_ARMOR_TRIM));
++ Assertions.assertEquals(armorTrim.armorTrim(), ((ArmorMeta) stack.getItemMeta()).getTrim());
++ stack.unsetData(DataComponentTypes.TRIM);
++ Assertions.assertFalse(stack.getItemMeta().hasItemFlag(ItemFlag.HIDE_ARMOR_TRIM));
++ Assertions.assertFalse(((ArmorMeta) stack.getItemMeta()).hasTrim());
++ }
++
++
++ @Test
+ void testChargedProjectiles() {
+ final ItemStack stack = new ItemStack(Material.CROSSBOW);
+ ItemStack projectile = new ItemStack(Material.FIREWORK_ROCKET);
@@ -3334,6 +3574,30 @@ index 0000000000000000000000000000000000000000..3ee8696686d4e91de57e2dbb2772c931
+
+ Assertions.assertEquals(metaGetter.apply(typedMeta), value);
+ }
++
++ @SuppressWarnings("unchecked")
++ private static <T, M, R> void testWithMeta(final ItemStack stack, final DataComponentType.Valued<T> type, final T value, Function<T, R> mapper, final Class<M> metaType, final Function<M, R> metaGetter, final BiConsumer<M, R> metaSetter) {
++ stack.setData(type, value);
++
++ Assertions.assertEquals(value, stack.getData(type));
++
++ final ItemMeta meta = stack.getItemMeta();
++ final M typedMeta = Assertions.assertInstanceOf(metaType, meta);
++
++ Assertions.assertEquals(metaGetter.apply(typedMeta), mapper.apply(value));
++ }
++
++ @SuppressWarnings("unchecked")
++ private static <M> void testWithMeta(final ItemStack stack, final DataComponentType.NonValued type, final boolean value, final Class<M> metaType, final Function<M, Boolean> metaGetter, final BiConsumer<M, Boolean> metaSetter) {
++ stack.setData(type);
++
++ Assertions.assertEquals(value, stack.hasData(type));
++
++ final ItemMeta meta = stack.getItemMeta();
++ final M typedMeta = Assertions.assertInstanceOf(metaType, meta);
++
++ Assertions.assertEquals(metaGetter.apply(typedMeta), value);
++ }
+}
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