aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOwen1212055 <[email protected]>2024-06-03 17:31:29 -0400
committerOwen1212055 <[email protected]>2024-11-18 14:50:37 -0500
commit5666bdb82517948937c7425fe0f081a280fb11ec (patch)
treefca5d980953b7c322cb18cc7ba39488adb7f9066
parent6dbbd90b5db39e13e0279f9209608a6dfb5f22a8 (diff)
downloadPaper-5666bdb82517948937c7425fe0f081a280fb11ec.tar.gz
Paper-5666bdb82517948937c7425fe0f081a280fb11ec.zip
Added writable_book_content, written_book_content, trim, instrument,lodestone_tracker, firework_explosion, fireworks, profile, note_block_sound, banner_patterns, container, lock
-rw-r--r--patches/api/0485-WIP-DataComponent-API.patch514
-rw-r--r--patches/server/1054-WIP-DataComponent-API.patch851
2 files changed, 1334 insertions, 31 deletions
diff --git a/patches/api/0485-WIP-DataComponent-API.patch b/patches/api/0485-WIP-DataComponent-API.patch
index d3de7b1237..660b3e2e14 100644
--- a/patches/api/0485-WIP-DataComponent-API.patch
+++ b/patches/api/0485-WIP-DataComponent-API.patch
@@ -39,34 +39,46 @@ 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..ea1a789086ba3f853cc0ac91cbe603fc3c416592
+index 0000000000000000000000000000000000000000..e094dbc6919ee7fe08270e8865f80375b4dc7f8a
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/DataComponentTypes.java
-@@ -0,0 +1,99 @@
+@@ -0,0 +1,111 @@
+package io.papermc.paper.component;
+
++import io.papermc.paper.component.item.BannerPatternLayers;
+import io.papermc.paper.component.item.BundleContents;
+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.ItemArmorTrim;
+import io.papermc.paper.component.item.ItemAttributeModifiers;
++import io.papermc.paper.component.item.ItemContainerContents;
+import io.papermc.paper.component.item.ItemEnchantments;
+import io.papermc.paper.component.item.ItemLore;
++import io.papermc.paper.component.item.LockCode;
++import io.papermc.paper.component.item.LodestoneTracker;
+import io.papermc.paper.component.item.MapDecorations;
+import io.papermc.paper.component.item.MapID;
+import io.papermc.paper.component.item.MapItemColor;
+import io.papermc.paper.component.item.MapPostProcessing;
+import io.papermc.paper.component.item.PotDecorations;
+import io.papermc.paper.component.item.PotionContents;
++import io.papermc.paper.component.item.ResolvableProfile;
+import io.papermc.paper.component.item.SeededContainerLoot;
+import io.papermc.paper.component.item.SuspiciousStewEffects;
+import io.papermc.paper.component.item.Unbreakable;
++import io.papermc.paper.component.item.WritableBookContent;
++import io.papermc.paper.component.item.WrittenBookContent;
+import net.kyori.adventure.text.Component;
+import org.bukkit.DyeColor;
++import org.bukkit.FireworkEffect;
++import org.bukkit.MusicInstrument;
+import org.bukkit.NamespacedKey;
+import org.bukkit.Registry;
+import org.bukkit.inventory.ItemRarity;
++import org.bukkit.inventory.meta.WritableBookMeta;
+import java.security.Key;
+import java.util.List;
+
@@ -106,28 +118,28 @@ index 0000000000000000000000000000000000000000..ea1a789086ba3f853cc0ac91cbe603fc
+ public static final DataComponentType.Valued<BundleContents> BUNDLE_CONTENTS = valued("bundle_contents");
+ public static final DataComponentType.Valued<PotionContents> POTION_CONTENTS = valued("potion_contents");
+ public static final DataComponentType.Valued<SuspiciousStewEffects> SUSPICIOUS_STEW_EFFECTS = valued("suspicious_stew_effects");
-+ // writable_book_content
-+ // written_book_content
-+ // trim
++ public static final DataComponentType.Valued<WritableBookContent> WRITABLE_BOOK_CONTENT = valued("writable_book_content");
++ public static final DataComponentType.Valued<WrittenBookContent> WRITTEN_BOOK_CONTENT = valued("written_book_content");
++ public static final DataComponentType.Valued<ItemArmorTrim> TRIM = valued("trim");
+ // debug_stick_state - Block Property API
+ // entity_data
+ // bucket_entity_data
+ // block_entity_data
-+ // instrument
++ public static final DataComponentType.Valued<MusicInstrument> INSTRUMENT = valued("instrument");
+ public static final DataComponentType.Valued<Integer> OMINOUS_BOTTLE_AMPLIFIER = valued("ominous_bottle_amplifier");
+ public static final DataComponentType.Valued<List<Key>> RECIPES = valued("recipes");
-+ // lodestone_tracker
-+ // firework_explosion
-+ // fireworks
-+ // profile
-+ // note_block_sound
-+ // banner_patterns
++ public static final DataComponentType.Valued<LodestoneTracker> LODESTONE_TRACKER = valued("lodestone_tracker");
++ public static final DataComponentType.Valued<FireworkEffect> FIREWORK_EXPLOSION = valued("firework_explosion");
++ public static final DataComponentType.Valued<Fireworks> FIREWORKS = valued("fireworks");
++ public static final DataComponentType.Valued<ResolvableProfile> PROFILE = valued("profile");
++ public static final DataComponentType.Valued<NamespacedKey> NOTE_BLOCK_SOUND = valued("note_block_sound");
++ public static final DataComponentType.Valued<BannerPatternLayers> BANNER_PATTERNS = valued("banner_patterns");
+ public static final DataComponentType.Valued<DyeColor> BASE_COLOR = valued("base_color");
+ public static final DataComponentType.Valued<PotDecorations> POT_DECORATIONS = valued("pot_decorations");
-+ // container
++ public static final DataComponentType.Valued<ItemContainerContents> CONTAINER = valued("container");
+ // block_state
+ // bees
-+ // lock
++ public static final DataComponentType.Valued<LockCode> LOCK = valued("lock");
+ public static final DataComponentType.Valued<SeededContainerLoot> CONTAINER_LOOT = valued("container_loot");
+
+ private static DataComponentType.NonValued unvalued(final String name) {
@@ -142,6 +154,46 @@ index 0000000000000000000000000000000000000000..ea1a789086ba3f853cc0ac91cbe603fc
+ private DataComponentTypes() {
+ }
+}
+diff --git a/src/main/java/io/papermc/paper/component/item/BannerPatternLayers.java b/src/main/java/io/papermc/paper/component/item/BannerPatternLayers.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..a6afa95840ba6dce2f7cd08451c385e04e629520
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/component/item/BannerPatternLayers.java
+@@ -0,0 +1,34 @@
++package io.papermc.paper.component.item;
++
++import org.bukkit.block.banner.Pattern;
++import org.checkerframework.checker.nullness.qual.NonNull;
++import org.jetbrains.annotations.ApiStatus;
++import org.jetbrains.annotations.Contract;
++import org.jetbrains.annotations.Unmodifiable;
++import java.util.List;
++
++public interface BannerPatternLayers {
++
++ @Contract(value = "-> new", pure = true)
++ static BannerPatternLayers.@NonNull Builder bannerPatternLayers() {
++ return ComponentTypesBridge.Holder.bridge().bannerPatternLayers();
++ }
++
++ @Contract(value = "-> new", pure = true)
++ @NonNull @Unmodifiable List<Pattern> getPatterns();
++
++ @ApiStatus.NonExtendable
++ interface Builder {
++
++ @Contract(value = "_ -> this", mutates = "this")
++ @NonNull Builder add(@NonNull Pattern pattern);
++
++ @Contract(value = "_ -> this", mutates = "this")
++ @NonNull Builder addAll(@NonNull List<Pattern> patterns);
++
++ @Contract(value = "-> new", pure = true)
++ @NonNull
++ BannerPatternLayers build();
++ }
++}
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..8686f4022395d3cd64a077b388e6f48595dac6f7
@@ -222,10 +274,10 @@ index 0000000000000000000000000000000000000000..dcf759607fd49aefd2abce280e0f3f43
+}
diff --git a/src/main/java/io/papermc/paper/component/item/ComponentTypesBridge.java b/src/main/java/io/papermc/paper/component/item/ComponentTypesBridge.java
new file mode 100644
-index 0000000000000000000000000000000000000000..0173820bd80354e4af215398db9308d38c6e59ab
+index 0000000000000000000000000000000000000000..62395ea2f1f63ecb64e712840b561f099eee877e
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/item/ComponentTypesBridge.java
-@@ -0,0 +1,58 @@
+@@ -0,0 +1,76 @@
+package io.papermc.paper.component.item;
+
+import java.util.Optional;
@@ -274,6 +326,24 @@ index 0000000000000000000000000000000000000000..0173820bd80354e4af215398db9308d3
+
+ SeededContainerLoot.Builder seededContainerLoot(final Key lootTableKey);
+
++ WrittenBookContent.Builder writtenBookContent();
++
++ WritableBookContent.Builder writeableBookContent();
++
++ ItemArmorTrim.Builder itemArmorTrim();
++
++ LodestoneTracker.Builder lodestoneTracker();
++
++ Fireworks.Builder fireworks();
++
++ ResolvableProfile.Builder resolvableProfile();
++
++ BannerPatternLayers.Builder bannerPatternLayers();
++
++ LockCode.Builder lockCode();
++
++ ItemContainerContents.Builder itemContainerContents();
++
+ @ApiStatus.Internal
+ final class Holder {
+
@@ -350,6 +420,52 @@ index 0000000000000000000000000000000000000000..825ec454ad412ecacce8da8c2a8dcc35
+ @NonNull DyedItemColor build();
+ }
+}
+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..1e698ab0ce40d4cf1b9f8386f3a06115db531415
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/component/item/Fireworks.java
+@@ -0,0 +1,40 @@
++package io.papermc.paper.component.item;
++
++import java.util.List;
++import org.bukkit.FireworkEffect;
++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;
++
++public interface Fireworks {
++
++ @Contract(value = "-> new", pure = true)
++ static Fireworks.@NonNull Builder fireworks() {
++ return ComponentTypesBridge.Holder.bridge().fireworks();
++ }
++
++ @Contract(value = "-> new", pure = true)
++ @NonNull @Unmodifiable List<FireworkEffect> effects();
++
++ int flightDuration();
++
++ @ApiStatus.NonExtendable
++ interface Builder {
++
++ @Contract(value = "_ -> this", mutates = "this")
++ @NonNull Builder flightDuration(@NonNull int duration);
++
++ @Contract(value = "_ -> this", mutates = "this")
++ @NonNull Builder add(@NonNull FireworkEffect effect);
++
++ @Contract(value = "_ -> this", mutates = "this")
++ @NonNull Builder addAll(@NonNull List<FireworkEffect> effects);
++
++ @Contract(value = "-> new", pure = true)
++ @NonNull
++ Fireworks build();
++ }
++}
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..fd8a2c011c214fe667938c22fdbe0c54db676e6f
@@ -417,6 +533,42 @@ index 0000000000000000000000000000000000000000..fd8a2c011c214fe667938c22fdbe0c54
+ @NonNull FoodProperties build();
+ }
+}
+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..98c916092a30550308a03a0030d7b08693374b28
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/component/item/ItemArmorTrim.java
+@@ -0,0 +1,30 @@
++package io.papermc.paper.component.item;
++
++import org.bukkit.inventory.meta.trim.ArmorTrim;
++import org.checkerframework.checker.nullness.qual.NonNull;
++import org.jetbrains.annotations.ApiStatus;
++import org.jetbrains.annotations.Contract;
++import org.jetbrains.annotations.NotNull;
++
++public interface ItemArmorTrim extends ShownInTooltip<ItemArmorTrim> {
++
++ @Contract(value = "-> new", pure = true)
++ static ItemArmorTrim.@NonNull Builder itemArmorTrim() {
++ return ComponentTypesBridge.Holder.bridge().itemArmorTrim();
++ }
++
++ @NotNull
++ ArmorTrim armorTrim();
++
++ @ApiStatus.NonExtendable
++ interface Builder extends ShownInTooltip.Builder<Builder> {
++
++ @Contract(value = "_, _, _ -> this", mutates = "this")
++ @NonNull Builder armorTrim(@NonNull ArmorTrim armorTrim);
++
++ @Contract(value = "-> new", pure = true)
++ @NonNull
++ ItemArmorTrim build();
++ }
++}
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..ab1ed5e705256855dc35300161bc922f02e8227a
@@ -459,6 +611,46 @@ index 0000000000000000000000000000000000000000..ab1ed5e705256855dc35300161bc922f
+ @NonNull ItemAttributeModifiers build();
+ }
+}
+diff --git a/src/main/java/io/papermc/paper/component/item/ItemContainerContents.java b/src/main/java/io/papermc/paper/component/item/ItemContainerContents.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..fd297e9ec49a78adc34e39eb6ee446a8b2840513
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/component/item/ItemContainerContents.java
+@@ -0,0 +1,34 @@
++package io.papermc.paper.component.item;
++
++import java.util.List;
++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;
++
++public interface ItemContainerContents {
++
++ @Contract(value = "-> new", pure = true)
++ static ItemContainerContents.@NonNull Builder bundleContents() {
++ return ComponentTypesBridge.Holder.bridge().itemContainerContents();
++ }
++
++ @Contract(value = "-> new", pure = true)
++ @NonNull @Unmodifiable List<ItemStack> getItems();
++
++ @ApiStatus.NonExtendable
++ interface Builder {
++
++ @Contract(value = "_ -> this", mutates = "this")
++ @NonNull Builder add(@NonNull ItemStack itemStack);
++
++ @Contract(value = "_ -> this", mutates = "this")
++ @NonNull Builder addAll(@NonNull List<ItemStack> itemStack);
++
++ @Contract(value = "-> new", pure = true)
++ @NonNull
++ ItemContainerContents build();
++ }
++}
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..ee1b18269cbc1b71f753d9eea2dfe59ffbc69e2c
@@ -551,6 +743,85 @@ index 0000000000000000000000000000000000000000..0f9f645ad2fbffb26636dfb702295fb3
+
+ }
+}
+diff --git a/src/main/java/io/papermc/paper/component/item/LockCode.java b/src/main/java/io/papermc/paper/component/item/LockCode.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..08e4b46ec6c0be076eeeb91153365b1f0c815e52
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/component/item/LockCode.java
+@@ -0,0 +1,28 @@
++package io.papermc.paper.component.item;
++
++import org.checkerframework.checker.nullness.qual.NonNull;
++import org.jetbrains.annotations.ApiStatus;
++import org.jetbrains.annotations.Contract;
++import org.jetbrains.annotations.NotNull;
++
++public interface LockCode {
++
++ @Contract(value = "-> new", pure = true)
++ static LockCode.@NonNull Builder lockCode() {
++ return ComponentTypesBridge.Holder.bridge().lockCode();
++ }
++
++ String lock();
++
++ @ApiStatus.NonExtendable
++ interface Builder {
++
++ @Contract(value = "_ -> this", mutates = "this")
++ @NonNull Builder lock(@NotNull String code);
++
++ @Contract(value = "-> new", pure = true)
++ @NonNull
++ LockCode build();
++ }
++}
+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..c931a9aed26334888ac982e6373c0fe6047d54b0
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/component/item/LodestoneTracker.java
+@@ -0,0 +1,39 @@
++package io.papermc.paper.component.item;
++
++import io.papermc.paper.util.Filtered;
++import java.util.Collection;
++import java.util.List;
++import org.bukkit.Location;
++import org.checkerframework.checker.nullness.qual.NonNull;
++import org.jetbrains.annotations.ApiStatus;
++import org.jetbrains.annotations.Contract;
++import org.jetbrains.annotations.NotNull;
++import org.jetbrains.annotations.Nullable;
++import org.jetbrains.annotations.Unmodifiable;
++
++public interface LodestoneTracker {
++
++ @Contract(value = "-> new", pure = true)
++ static LodestoneTracker.@NonNull Builder lodestoneTracker() {
++ return ComponentTypesBridge.Holder.bridge().lodestoneTracker();
++ }
++
++ @Nullable Location location();
++
++ boolean tracked();
++
++ @ApiStatus.NonExtendable
++ interface Builder {
++
++ @Contract(value = "_ -> this", mutates = "this")
++ @NonNull Builder location(@Nullable Location page);
++
++ @Contract(value = "_ -> this", mutates = "this")
++ @NonNull Builder tracked(boolean tracked);
++
++ @Contract(value = "-> new", pure = true)
++ @NonNull
++ LodestoneTracker build();
++ }
++}
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..d22f08c08c209facd31c14c44c52221f0105b35b
@@ -783,6 +1054,63 @@ index 0000000000000000000000000000000000000000..2fea9c373b4a86f98510bcf85979e35e
+ @NonNull PotionContents build();
+ }
+}
+diff --git a/src/main/java/io/papermc/paper/component/item/ResolvableProfile.java b/src/main/java/io/papermc/paper/component/item/ResolvableProfile.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..56489fc38cfa180463799e902a3d3fbaf67ed84d
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/component/item/ResolvableProfile.java
+@@ -0,0 +1,51 @@
++package io.papermc.paper.component.item;
++
++import java.util.Collection;
++import java.util.List;
++import java.util.UUID;
++import java.util.concurrent.CompletableFuture;
++import com.destroystokyo.paper.profile.PlayerProfile;
++import com.destroystokyo.paper.profile.ProfileProperty;
++import org.checkerframework.checker.nullness.qual.NonNull;
++import org.jetbrains.annotations.ApiStatus;
++import org.jetbrains.annotations.Contract;
++import org.jetbrains.annotations.NotNull;
++import org.jetbrains.annotations.Nullable;
++import org.jetbrains.annotations.Unmodifiable;
++
++public interface ResolvableProfile {
++
++ @Contract(value = "-> new", pure = true)
++ static ResolvableProfile.@NonNull Builder resolvableProfile() {
++ return ComponentTypesBridge.Holder.bridge().resolvableProfile();
++ }
++
++ @Nullable UUID uuid();
++
++ @Nullable String name();
++
++ @Unmodifiable @NonNull Collection<ProfileProperty> properties();
++
++ @NotNull CompletableFuture<PlayerProfile> resolve();
++
++ @ApiStatus.NonExtendable
++ interface Builder {
++
++ @Contract(value = "_ -> this", mutates = "this")
++ @NonNull Builder name(@Nullable String name);
++
++ @Contract(value = "_ -> this", mutates = "this")
++ @NonNull Builder uuid(@Nullable UUID uuid);
++
++ @Contract(value = "_ -> this", mutates = "this")
++ @NonNull Builder addAllProperties(@NonNull List<ProfileProperty> properties);
++
++ @Contract(value = "_ -> this", mutates = "this")
++ @NonNull Builder addProperty(@NonNull ProfileProperty property);
++
++ @Contract(value = "-> new", pure = true)
++ @NonNull
++ ResolvableProfile build();
++ }
++}
diff --git a/src/main/java/io/papermc/paper/component/item/SeededContainerLoot.java b/src/main/java/io/papermc/paper/component/item/SeededContainerLoot.java
new file mode 100644
index 0000000000000000000000000000000000000000..eb89ff28b773f3fe24b0073513d5fc2abf4c370e
@@ -922,6 +1250,128 @@ index 0000000000000000000000000000000000000000..36e48ef697c001fff1697542eae6f79b
+
+ }
+}
+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..919b81435247986177c17f1c6e4424b2c61dbdd9
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/component/item/WritableBookContent.java
+@@ -0,0 +1,42 @@
++package io.papermc.paper.component.item;
++
++import io.papermc.paper.util.Filtered;
++import java.util.Collection;
++import java.util.List;
++import net.kyori.adventure.text.Component;
++import org.checkerframework.checker.nullness.qual.NonNull;
++import org.jetbrains.annotations.ApiStatus;
++import org.jetbrains.annotations.Contract;
++import org.jetbrains.annotations.NotNull;
++import org.jetbrains.annotations.Unmodifiable;
++
++public interface WritableBookContent {
++
++ @Contract(value = "-> new", pure = true)
++ static WritableBookContent.@NonNull Builder writeableBookContent() {
++ return ComponentTypesBridge.Holder.bridge().writeableBookContent();
++ }
++
++ @NotNull @Unmodifiable List<Filtered<String>> pages();
++
++ @ApiStatus.NonExtendable
++ interface Builder {
++
++ @Contract(value = "_ -> this", mutates = "this")
++ @NonNull Builder addPage(@NonNull String page);
++
++ @Contract(value = "_ -> this", mutates = "this")
++ @NonNull Builder addPages(@NonNull Collection<String> page);
++
++ @Contract(value = "_ -> this", mutates = "this")
++ @NonNull Builder addPageFiltered(@NonNull Filtered<String> page);
++
++ @Contract(value = "_ -> this", mutates = "this")
++ @NonNull Builder addPagesFiltered(@NonNull Collection<Filtered<String>> pages);
++
++ @Contract(value = "-> new", pure = true)
++ @NonNull
++ WritableBookContent build();
++ }
++}
+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..ed3969d9bd0332d845c655da3c271aff08f1b752
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/component/item/WrittenBookContent.java
+@@ -0,0 +1,68 @@
++package io.papermc.paper.component.item;
++
++import java.util.Collection;
++import java.util.List;
++import java.util.logging.Filter;
++import io.papermc.paper.util.Filtered;
++import net.kyori.adventure.text.Component;
++import org.bukkit.potion.PotionEffect;
++import org.checkerframework.checker.nullness.qual.NonNull;
++import org.jetbrains.annotations.ApiStatus;
++import org.jetbrains.annotations.Contract;
++import org.jetbrains.annotations.NotNull;
++import org.jetbrains.annotations.Nullable;
++import org.jetbrains.annotations.Unmodifiable;
++
++public interface WrittenBookContent {
++
++ @Contract(value = "-> new", pure = true)
++ static WrittenBookContent.@NonNull Builder writtenBookContent() {
++ return ComponentTypesBridge.Holder.bridge().writtenBookContent();
++ }
++
++ @NotNull Filtered<String> title();
++
++ @NotNull String author();
++
++ int generation();
++
++ @NotNull @Unmodifiable List<Filtered<Component>> pages();
++
++ boolean resolved();
++
++ @ApiStatus.NonExtendable
++ interface Builder {
++
++ @Contract(value = "_ -> this", mutates = "this")
++ @NonNull Builder title(@NonNull String title);
++
++ @Contract(value = "_ -> this", mutates = "this")
++ @NonNull Builder titleFiltered(@NonNull Filtered<String> title);
++
++ @Contract(value = "_ -> this", mutates = "this")
++ @NonNull Builder author(@NonNull String author);
++
++ @Contract(value = "_ -> this", mutates = "this")
++ @NonNull Builder generation(int generation);
++
++ @Contract(value = "_ -> this", mutates = "this")
++ @NonNull Builder resolved(boolean resolved);
++
++ @Contract(value = "_ -> this", mutates = "this")
++ @NonNull Builder addPage(@NonNull Component page);
++
++ @Contract(value = "_ -> this", mutates = "this")
++ @NonNull Builder addPages(@NonNull Collection<Component> page);
++
++ @Contract(value = "_ -> this", mutates = "this")
++ @NonNull Builder addPageFiltered(@NonNull Filtered<Component> page);
++
++ @Contract(value = "_ -> this", mutates = "this")
++ @NonNull Builder addPagesFiltered(@NonNull Collection<Filtered<Component>> pages);
++
++ @Contract(value = "-> new", pure = true)
++ @NonNull
++ WrittenBookContent build();
++ }
++}
diff --git a/src/main/java/io/papermc/paper/component/package-info.java b/src/main/java/io/papermc/paper/component/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..37c9e2b084fe4c82242ae64569bb76beb6a88c09
@@ -950,6 +1400,38 @@ index 7b79bf33074355020e0b3b5ef40c7f2e6ba644b4..5cf3aa4641822c91adfbd70a847ca529
RegistryKey<MapCursor.Type> MAP_DECORATION_TYPE = create("map_decoration_type");
+ RegistryKey<DataComponentType> DATA_COMPONENT_TYPE = create("data_component_type");
}
+diff --git a/src/main/java/io/papermc/paper/util/Filtered.java b/src/main/java/io/papermc/paper/util/Filtered.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..c3355a59d008920ab4afb910925f433548e2f956
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/util/Filtered.java
+@@ -0,0 +1,26 @@
++package io.papermc.paper.util;
++
++import org.checkerframework.checker.nullness.qual.NonNull;
++import org.jetbrains.annotations.ApiStatus;
++import org.jetbrains.annotations.NotNull;
++import org.jetbrains.annotations.Nullable;
++
++/**
++ * Denotes that this type is filterable by the client, and may be shown differently
++ * depending on the player's set configuration.
++ * @param <T> type of value
++ */
++public interface Filtered<T> {
++
++ static <T> Filtered<T> of(@NonNull T raw, @Nullable T filtered) {
++ record Instance<T>(T raw, T filtered) implements Filtered<T> { }
++
++ return new Instance<>(raw, filtered);
++ }
++
++ T raw();
++
++ @Nullable
++ T filtered();
++}
diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java
index 7509b61dfdc0a6675256970cb850b08f9e814580..28e2628d8d0a6af742b2fa89e5581e6b0d1a38a4 100644
--- a/src/main/java/org/bukkit/Material.java
diff --git a/patches/server/1054-WIP-DataComponent-API.patch b/patches/server/1054-WIP-DataComponent-API.patch
index 16317fd188..10a6b4746c 100644
--- a/patches/server/1054-WIP-DataComponent-API.patch
+++ b/patches/server/1054-WIP-DataComponent-API.patch
@@ -37,26 +37,33 @@ index 0000000000000000000000000000000000000000..e538819c873a324c58bcd8e73f89510e
+}
diff --git a/src/main/java/io/papermc/paper/component/ComponentAdapters.java b/src/main/java/io/papermc/paper/component/ComponentAdapters.java
new file mode 100644
-index 0000000000000000000000000000000000000000..e6a57e276cfa8be5943302edafbbdeb3f5aff404
+index 0000000000000000000000000000000000000000..08e04fb9ecd9be1c3b13d114d07040bb36fec4c1
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/ComponentAdapters.java
-@@ -0,0 +1,151 @@
+@@ -0,0 +1,162 @@
+package io.papermc.paper.component;
+
+import io.papermc.paper.adventure.PaperAdventure;
++import io.papermc.paper.component.item.PaperBannerPatternLayers;
+import io.papermc.paper.component.item.PaperBundleContents;
+import io.papermc.paper.component.item.PaperChargedProjectiles;
+import io.papermc.paper.component.item.PaperCustomModelData;
+import io.papermc.paper.component.item.PaperDyedItemColor;
++import io.papermc.paper.component.item.PaperFireworks;
+import io.papermc.paper.component.item.PaperFoodProperties;
++import io.papermc.paper.component.item.PaperItemArmorTrim;
+import io.papermc.paper.component.item.PaperItemAttributeModifiers;
++import io.papermc.paper.component.item.PaperItemContainerContents;
+import io.papermc.paper.component.item.PaperItemEnchantments;
+import io.papermc.paper.component.item.PaperItemLore;
++import io.papermc.paper.component.item.PaperLockCode;
++import io.papermc.paper.component.item.PaperLodestoneTracker;
+import io.papermc.paper.component.item.PaperMapDecorations;
+import io.papermc.paper.component.item.PaperMapID;
+import io.papermc.paper.component.item.PaperMapItemColor;
+import io.papermc.paper.component.item.PaperPotDecorations;
+import io.papermc.paper.component.item.PaperPotionContents;
++import io.papermc.paper.component.item.PaperResolvableProfile;
+import io.papermc.paper.component.item.PaperSeededContainerLoot;
+import io.papermc.paper.component.item.PaperSuspiciousStewEffects;
+import io.papermc.paper.component.item.PaperUnbreakable;
@@ -66,6 +73,8 @@ index 0000000000000000000000000000000000000000..e6a57e276cfa8be5943302edafbbdeb3
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
++import io.papermc.paper.component.item.PaperWritableBookContent;
++import io.papermc.paper.component.item.PaperWrittenBookContent;
+import net.kyori.adventure.key.Key;
+import net.minecraft.core.component.DataComponentType;
+import net.minecraft.core.component.DataComponents;
@@ -76,6 +85,8 @@ index 0000000000000000000000000000000000000000..e6a57e276cfa8be5943302edafbbdeb3
+import net.minecraft.world.item.Rarity;
+import net.minecraft.world.item.component.MapPostProcessing;
+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;
@@ -125,9 +136,9 @@ index 0000000000000000000000000000000000000000..e6a57e276cfa8be5943302edafbbdeb3
+ register(DataComponents.BUNDLE_CONTENTS, PaperBundleContents::new);
+ register(DataComponents.POTION_CONTENTS, PaperPotionContents::new);
+ register(DataComponents.SUSPICIOUS_STEW_EFFECTS, PaperSuspiciousStewEffects::new);
-+ // writable book content
-+ // written book content
-+ // trim
++ register(DataComponents.WRITTEN_BOOK_CONTENT, PaperWrittenBookContent::new);
++ register(DataComponents.WRITABLE_BOOK_CONTENT, PaperWritableBookContent::new);
++ register(DataComponents.TRIM, PaperItemArmorTrim::new);
+ // debug stick state
+ // entity data
+ // bucket entity data
@@ -148,16 +159,16 @@ index 0000000000000000000000000000000000000000..e6a57e276cfa8be5943302edafbbdeb3
+
+ return Collections.unmodifiableList(nms);
+ });
-+ // lodestone tracker
-+ // firework explosion
-+ // fireworks
-+ // profile
-+ // note block sound
++ register(DataComponents.LODESTONE_TRACKER, PaperLodestoneTracker::new);
++ register(DataComponents.FIREWORK_EXPLOSION, CraftMetaFirework::getEffect, CraftMetaFirework::getExplosion);
++ register(DataComponents.FIREWORKS, PaperFireworks::new);
++ register(DataComponents.PROFILE, PaperResolvableProfile::new);
++ register(DataComponents.NOTE_BLOCK_SOUND, CraftNamespacedKey::fromMinecraft, CraftNamespacedKey::toMinecraft);
+ register(DataComponents.BASE_COLOR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData()));
+ register(DataComponents.POT_DECORATIONS, PaperPotDecorations::new);
+ // block state (block data)
+ // bees
-+ // lock
++ register(DataComponents.LOCK, PaperLockCode::new);
+ register(DataComponents.CONTAINER_LOOT, PaperSeededContainerLoot::new);
+
+ // TODO: REMOVE THIS... we want to build the PR... so lets just make things UNTYPED!
@@ -318,10 +329,10 @@ index 0000000000000000000000000000000000000000..5639559368e6866e9b0afa6688f3b12c
+}
diff --git a/src/main/java/io/papermc/paper/component/item/ComponentTypesBridgesImpl.java b/src/main/java/io/papermc/paper/component/item/ComponentTypesBridgesImpl.java
new file mode 100644
-index 0000000000000000000000000000000000000000..c6583b428491d5d523a40ef42a94d4c1184b8ed9
+index 0000000000000000000000000000000000000000..548c392e045fd8ca6ebdbb3e6ee871cabceab707
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/item/ComponentTypesBridgesImpl.java
-@@ -0,0 +1,99 @@
+@@ -0,0 +1,139 @@
+package io.papermc.paper.component.item;
+
+import net.kyori.adventure.key.Key;
@@ -420,6 +431,120 @@ index 0000000000000000000000000000000000000000..c6583b428491d5d523a40ef42a94d4c1
+ public SeededContainerLoot.Builder seededContainerLoot(final Key lootTableKey) {
+ return new PaperSeededContainerLoot.BuilderImpl(new NamespacedKey(lootTableKey.namespace(), lootTableKey.value()));
+ }
++
++ @Override
++ public WrittenBookContent.Builder writtenBookContent() {
++ return new PaperWrittenBookContent.BuilderImpl();
++ }
++
++ @Override
++ public WritableBookContent.Builder writeableBookContent() {
++ return new PaperWritableBookContent.BuilderImpl();
++ }
++
++ @Override
++ public ItemArmorTrim.Builder itemArmorTrim() {
++ return new PaperItemArmorTrim.BuilderImpl();
++ }
++
++ @Override
++ public LodestoneTracker.Builder lodestoneTracker() {
++ return new PaperLodestoneTracker.BuilderImpl();
++ }
++
++ @Override
++ public Fireworks.Builder fireworks() {
++ return new PaperFireworks.BuilderImpl();
++ }
++
++ @Override
++ public ResolvableProfile.Builder resolvableProfile() {
++ return new PaperResolvableProfile.BuilderImpl();
++ }
++
++ @Override
++ public BannerPatternLayers.Builder bannerPatternLayers() {
++ return new PaperBannerPatternLayers.BuilderImpl();
++ }
++
++ @Override
++ public LockCode.Builder lockCode() {
++ return new PaperLockCode.BuilderImpl();
++ }
++}
+diff --git a/src/main/java/io/papermc/paper/component/item/PaperBannerPatternLayers.java b/src/main/java/io/papermc/paper/component/item/PaperBannerPatternLayers.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..fa1d453538d9fa1e0efa6bfffdf0ae9dd1c616e5
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/component/item/PaperBannerPatternLayers.java
+@@ -0,0 +1,68 @@
++package io.papermc.paper.component.item;
++
++import com.google.common.base.Function;
++import com.google.common.collect.Lists;
++import java.util.ArrayList;
++import java.util.Collections;
++import java.util.List;
++import java.util.Optional;
++import org.bukkit.DyeColor;
++import org.bukkit.block.banner.Pattern;
++import org.bukkit.block.banner.PatternType;
++import org.bukkit.craftbukkit.CraftRegistry;
++import org.bukkit.craftbukkit.block.banner.CraftPatternType;
++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;
++import org.jetbrains.annotations.Unmodifiable;
++
++@DefaultQualifier(NonNull.class)
++public record PaperBannerPatternLayers(
++ net.minecraft.world.level.block.entity.BannerPatternLayers impl
++) implements BannerPatternLayers, Handleable<net.minecraft.world.level.block.entity.BannerPatternLayers> {
++
++ @Override
++ public net.minecraft.world.level.block.entity.BannerPatternLayers getHandle() {
++ return this.impl;
++ }
++
++ @Override
++ public @NonNull @Unmodifiable List<Pattern> getPatterns() {
++ return Collections.unmodifiableList(
++ Lists.transform(
++ this.impl.layers(), // this already copies the itemstacks to maintain immutability
++ input -> {
++ Optional<PatternType> type = CraftRegistry.unwrapAndConvertHolder(org.bukkit.Registry.BANNER_PATTERN, input.pattern());
++ return new Pattern(DyeColor.getByWoolData((byte) input.color().getId()), type.orElseThrow());
++ }
++ )
++ );
++ }
++
++ static final class BuilderImpl implements Builder {
++
++ private final net.minecraft.world.level.block.entity.BannerPatternLayers.Builder builder = new net.minecraft.world.level.block.entity.BannerPatternLayers.Builder();
++
++ @Override
++ public @NonNull Builder add(@NonNull final Pattern pattern) {
++ this.builder.add(
++ CraftPatternType.bukkitToMinecraftHolder(pattern.getPattern()),
++ net.minecraft.world.item.DyeColor.byId(pattern.getColor().getWoolData())
++ );
++ return this;
++ }
++
++ @Override
++ public @NonNull Builder addAll(@NonNull final List<Pattern> patterns) {
++ patterns.forEach(this::add);
++ return this;
++ }
++
++ @Override
++ public @NonNull BannerPatternLayers build() {
++ return new PaperBannerPatternLayers(this.builder.build());
++ }
++ }
+}
diff --git a/src/main/java/io/papermc/paper/component/item/PaperBundleContents.java b/src/main/java/io/papermc/paper/component/item/PaperBundleContents.java
new file mode 100644
@@ -650,6 +775,82 @@ index 0000000000000000000000000000000000000000..1e2b03f7de79a2b2559bb896f2ea8286
+ }
+ }
+}
+diff --git a/src/main/java/io/papermc/paper/component/item/PaperFireworks.java b/src/main/java/io/papermc/paper/component/item/PaperFireworks.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..3c32b35ed56eb238ff6562a6512aa1d7d007fb2f
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/component/item/PaperFireworks.java
+@@ -0,0 +1,70 @@
++package io.papermc.paper.component.item;
++
++import com.google.common.collect.Lists;
++import java.util.ArrayList;
++import java.util.Collections;
++import java.util.List;
++import net.minecraft.world.item.component.FireworkExplosion;
++import org.bukkit.FireworkEffect;
++import org.bukkit.craftbukkit.inventory.CraftItemStack;
++import org.bukkit.craftbukkit.inventory.CraftMetaFirework;
++import org.bukkit.craftbukkit.util.Handleable;
++import org.bukkit.inventory.ItemStack;
++import org.checkerframework.checker.nullness.qual.NonNull;
++import org.checkerframework.framework.qual.DefaultQualifier;
++import org.jetbrains.annotations.Unmodifiable;
++
++@DefaultQualifier(NonNull.class)
++public record PaperFireworks(
++ net.minecraft.world.item.component.Fireworks impl
++) implements Fireworks, Handleable<net.minecraft.world.item.component.Fireworks> {
++
++ @Override
++ public net.minecraft.world.item.component.Fireworks getHandle() {
++ return this.impl;
++ }
++
++ @Override
++ public @NonNull @Unmodifiable List<FireworkEffect> effects() {
++ return Collections.unmodifiableList(
++ Lists.transform(
++ this.impl.explosions(),
++ CraftMetaFirework::getEffect
++ )
++ );
++ }
++
++ @Override
++ public int flightDuration() {
++ return this.impl.flightDuration();
++ }
++
++ static final class BuilderImpl implements Builder {
++
++ private final List<FireworkExplosion> effects = new ArrayList<>();
++ private int duration;
++
++ @Override
++ public @NonNull Builder flightDuration(@NonNull final int duration) {
++ this.duration = duration;
++ return this;
++ }
++
++ @Override
++ public @NonNull Builder add(@NonNull final FireworkEffect effect) {
++ this.effects.add(CraftMetaFirework.getExplosion(effect));
++ return this;
++ }
++
++ @Override
++ public @NonNull Builder addAll(@NonNull final List<FireworkEffect> effects) {
++ effects.forEach(this::add);
++ return this;
++ }
++
++ @Override
++ public @NonNull Fireworks build() {
++ return new PaperFireworks(new net.minecraft.world.item.component.Fireworks(this.duration, this.effects));
++ }
++ }
++}
diff --git a/src/main/java/io/papermc/paper/component/item/PaperFoodProperties.java b/src/main/java/io/papermc/paper/component/item/PaperFoodProperties.java
new file mode 100644
index 0000000000000000000000000000000000000000..cb19f766943ac3aabddf03b958d151c25f8a9a16
@@ -777,6 +978,83 @@ index 0000000000000000000000000000000000000000..cb19f766943ac3aabddf03b958d151c2
+ }
+ }
+}
+diff --git a/src/main/java/io/papermc/paper/component/item/PaperItemArmorTrim.java b/src/main/java/io/papermc/paper/component/item/PaperItemArmorTrim.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..3f1c41aa799e02fff1af787d63c9e5efa8f851e8
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/component/item/PaperItemArmorTrim.java
+@@ -0,0 +1,71 @@
++package io.papermc.paper.component.item;
++
++import com.google.common.collect.Lists;
++import java.util.ArrayList;
++import java.util.Collections;
++import java.util.List;
++import org.bukkit.attribute.Attribute;
++import org.bukkit.attribute.AttributeModifier;
++import org.bukkit.craftbukkit.CraftEquipmentSlot;
++import org.bukkit.craftbukkit.attribute.CraftAttribute;
++import org.bukkit.craftbukkit.attribute.CraftAttributeInstance;
++import org.bukkit.craftbukkit.inventory.trim.CraftTrimMaterial;
++import org.bukkit.craftbukkit.inventory.trim.CraftTrimPattern;
++import org.bukkit.craftbukkit.util.Handleable;
++import org.bukkit.inventory.EquipmentSlotGroup;
++import org.bukkit.inventory.meta.trim.ArmorTrim;
++import org.checkerframework.checker.nullness.qual.NonNull;
++import org.checkerframework.framework.qual.DefaultQualifier;
++import org.jetbrains.annotations.NotNull;
++
++@DefaultQualifier(NonNull.class)
++public record PaperItemArmorTrim(
++ net.minecraft.world.item.armortrim.ArmorTrim impl
++) implements ItemArmorTrim, Handleable<net.minecraft.world.item.armortrim.ArmorTrim> {
++
++ @Override
++ public net.minecraft.world.item.armortrim.ArmorTrim getHandle() {
++ return this.impl;
++ }
++
++ @Override
++ public boolean showInTooltip() {
++ return this.impl.showInTooltip;
++ }
++
++ @Override
++ public ItemArmorTrim showInTooltip(final boolean showInTooltip) {
++ return new PaperItemArmorTrim(this.impl.withTooltip(showInTooltip));
++ }
++
++ @Override
++ public @NotNull ArmorTrim armorTrim() {
++ return new ArmorTrim(CraftTrimMaterial.minecraftHolderToBukkit(this.impl.material()), CraftTrimPattern.minecraftHolderToBukkit(this.impl.pattern()));
++ }
++
++ static final class BuilderImpl implements Builder {
++
++ private net.minecraft.world.item.armortrim.ArmorTrim armorTrim;
++ private boolean showInTooltip = true;
++
++ @Override
++ public Builder showInTooltip(final boolean showInTooltip) {
++ this.showInTooltip = showInTooltip;
++ return this;
++ }
++
++ @Override
++ public @NonNull Builder armorTrim(@NonNull final ArmorTrim armorTrim) {
++ this.armorTrim = new net.minecraft.world.item.armortrim.ArmorTrim(
++ CraftTrimMaterial.bukkitToMinecraftHolder(armorTrim.getMaterial()),
++ CraftTrimPattern.bukkitToMinecraftHolder(armorTrim.getPattern())
++ );
++ return this;
++ }
++
++ @Override
++ public @NonNull ItemArmorTrim build() {
++ return new PaperItemArmorTrim(this.armorTrim.withTooltip(this.showInTooltip));
++ }
++ }
++}
diff --git a/src/main/java/io/papermc/paper/component/item/PaperItemAttributeModifiers.java b/src/main/java/io/papermc/paper/component/item/PaperItemAttributeModifiers.java
new file mode 100644
index 0000000000000000000000000000000000000000..26b195f590025406232fde513f602fd3ff536405
@@ -872,6 +1150,64 @@ index 0000000000000000000000000000000000000000..26b195f590025406232fde513f602fd3
+ }
+ }
+}
+diff --git a/src/main/java/io/papermc/paper/component/item/PaperItemContainerContents.java b/src/main/java/io/papermc/paper/component/item/PaperItemContainerContents.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..4227aa0b63ac4041b0ddc9821e4573ca791158b1
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/component/item/PaperItemContainerContents.java
+@@ -0,0 +1,52 @@
++package io.papermc.paper.component.item;
++
++import com.google.common.collect.Lists;
++import java.util.ArrayList;
++import java.util.Collections;
++import java.util.List;
++import java.util.stream.Collectors;
++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 PaperItemContainerContents(
++ net.minecraft.world.item.component.ItemContainerContents impl
++) implements ItemContainerContents, Handleable<net.minecraft.world.item.component.ItemContainerContents> {
++
++ @Override
++ public net.minecraft.world.item.component.ItemContainerContents getHandle() {
++ return this.impl;
++ }
++
++ @Override
++ public List<ItemStack> getItems() {
++ return this.impl.stream().map(CraftItemStack::asCraftMirror).collect(Collectors.toUnmodifiableList());
++ }
++
++ static final class BuilderImpl implements Builder {
++
++ private final List<net.minecraft.world.item.ItemStack> items = new ArrayList<>();
++
++ @Override
++ public Builder add(final ItemStack itemStack) {
++ this.items.add(CraftItemStack.asNMSCopy(itemStack));
++ return this;
++ }
++
++ @Override
++ public Builder addAll(final List<ItemStack> itemStack) {
++ for (final ItemStack item : itemStack) {
++ this.items.add(CraftItemStack.asNMSCopy(item));
++ }
++ return this;
++ }
++
++ @Override
++ public ItemContainerContents build() {
++ return new PaperItemContainerContents(net.minecraft.world.item.component.ItemContainerContents.fromItems(this.items));
++ }
++ }
++}
diff --git a/src/main/java/io/papermc/paper/component/item/PaperItemEnchantments.java b/src/main/java/io/papermc/paper/component/item/PaperItemEnchantments.java
new file mode 100644
index 0000000000000000000000000000000000000000..ed99ed52fe47b231dae2b78bd1bc363389f9c11f
@@ -1030,6 +1366,123 @@ index 0000000000000000000000000000000000000000..b972ceebd3d5965d4926262b752c33a0
+ }
+ }
+}
+diff --git a/src/main/java/io/papermc/paper/component/item/PaperLockCode.java b/src/main/java/io/papermc/paper/component/item/PaperLockCode.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..2b544947f9fac0f4945f428b43071498b48b69c3
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/component/item/PaperLockCode.java
+@@ -0,0 +1,38 @@
++package io.papermc.paper.component.item;
++
++import org.bukkit.craftbukkit.util.Handleable;
++import org.checkerframework.checker.nullness.qual.NonNull;
++import org.checkerframework.framework.qual.DefaultQualifier;
++import org.jetbrains.annotations.NotNull;
++
++@DefaultQualifier(NonNull.class)
++public record PaperLockCode(
++ net.minecraft.world.LockCode impl
++) implements LockCode, Handleable<net.minecraft.world.LockCode> {
++
++ @Override
++ public net.minecraft.world.LockCode getHandle() {
++ return this.impl;
++ }
++
++ @Override
++ public String lock() {
++ return this.impl.key();
++ }
++
++ static final class BuilderImpl implements Builder {
++
++ private String lock = "";
++
++ @Override
++ public @NonNull Builder lock(@NotNull final String code) {
++ this.lock = lock;
++ return this;
++ }
++
++ @Override
++ public LockCode build() {
++ return new PaperLockCode(new net.minecraft.world.LockCode(this.lock));
++ }
++ }
++}
+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..547561acf87d34244a44548432521c82f0af7684
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/component/item/PaperLodestoneTracker.java
+@@ -0,0 +1,67 @@
++package io.papermc.paper.component.item;
++
++import com.google.common.base.Preconditions;
++import com.google.common.collect.Lists;
++import io.papermc.paper.util.Filtered;
++import java.util.ArrayList;
++import java.util.Collection;
++import java.util.Collections;
++import java.util.List;
++import java.util.Optional;
++import java.util.function.Function;
++import net.minecraft.core.GlobalPos;
++import net.minecraft.server.network.Filterable;
++import org.bukkit.Location;
++import org.bukkit.craftbukkit.entity.memory.CraftMemoryMapper;
++import org.bukkit.craftbukkit.util.Handleable;
++import org.checkerframework.checker.nullness.qual.NonNull;
++import org.checkerframework.framework.qual.DefaultQualifier;
++import org.jetbrains.annotations.NotNull;
++import org.jetbrains.annotations.Nullable;
++import org.jetbrains.annotations.Unmodifiable;
++
++@DefaultQualifier(NonNull.class)
++public record PaperLodestoneTracker(
++ net.minecraft.world.item.component.LodestoneTracker impl
++) implements LodestoneTracker, Handleable<net.minecraft.world.item.component.LodestoneTracker> {
++
++ @Override
++ public net.minecraft.world.item.component.LodestoneTracker getHandle() {
++ return this.impl;
++ }
++
++ @Override
++ public @Nullable Location location() {
++ return this.impl.target().map(CraftMemoryMapper::fromNms).orElse(null);
++ }
++
++ @Override
++ public boolean tracked() {
++ return this.impl.tracked();
++ }
++
++ static final class BuilderImpl implements Builder {
++
++ private Optional<GlobalPos> pos = Optional.empty();
++ private boolean tracked = true;
++
++ @Override
++ public @NonNull Builder location(@Nullable final Location page) {
++ this.pos = Optional.ofNullable(page).map(CraftMemoryMapper::toNms);
++ return this;
++ }
++
++ @Override
++ public @NonNull Builder tracked(final boolean tracked) {
++ this.tracked = tracked;
++ return this;
++ }
++
++ @Override
++ public @NonNull LodestoneTracker build() {
++ return new PaperLodestoneTracker(
++ new net.minecraft.world.item.component.LodestoneTracker(this.pos, this.tracked)
++ );
++ }
++ }
++}
diff --git a/src/main/java/io/papermc/paper/component/item/PaperMapDecorations.java b/src/main/java/io/papermc/paper/component/item/PaperMapDecorations.java
new file mode 100644
index 0000000000000000000000000000000000000000..2d97d20e0b16558a61ef21d2595b920e528d9879
@@ -1157,7 +1610,7 @@ index 0000000000000000000000000000000000000000..805a86b4da99e82b3fa4254b62c0e265
+}
diff --git a/src/main/java/io/papermc/paper/component/item/PaperMapItemColor.java b/src/main/java/io/papermc/paper/component/item/PaperMapItemColor.java
new file mode 100644
-index 0000000000000000000000000000000000000000..307fdefe165380c31e51b81c431b88709efbc494
+index 0000000000000000000000000000000000000000..5f4833a78aff61e6ae1a1568cf58f4c5e66823d5
--- /dev/null
+++ b/src/main/java/io/papermc/paper/component/item/PaperMapItemColor.java
@@ -0,0 +1,38 @@
@@ -1185,7 +1638,7 @@ index 0000000000000000000000000000000000000000..307fdefe165380c31e51b81c431b8870
+
+ static final class BuilderImpl implements Builder {
+
-+ private Color color = Color.WHITE;
++ private Color color = Color.fromRGB(net.minecraft.world.item.component.MapItemColor.DEFAULT.rgb());
+
+ @Override
+ public Builder mapColor(final Color color) {
@@ -1385,6 +1838,117 @@ index 0000000000000000000000000000000000000000..b98bd15e9d0d32102a6213b4107f85bf
+ }
+ }
+}
+diff --git a/src/main/java/io/papermc/paper/component/item/PaperResolvableProfile.java b/src/main/java/io/papermc/paper/component/item/PaperResolvableProfile.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..b1e189c52b494670cf138ca67d1418620a00e3eb
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/component/item/PaperResolvableProfile.java
+@@ -0,0 +1,105 @@
++package io.papermc.paper.component.item;
++
++import com.destroystokyo.paper.profile.CraftPlayerProfile;
++import com.destroystokyo.paper.profile.PlayerProfile;
++import com.destroystokyo.paper.profile.ProfileProperty;
++import com.google.common.base.Preconditions;
++import com.google.common.collect.Collections2;
++import com.google.common.collect.Lists;
++import com.mojang.authlib.properties.Property;
++import com.mojang.authlib.properties.PropertyMap;
++import io.papermc.paper.adventure.PaperAdventure;
++import io.papermc.paper.util.Filtered;
++import java.util.ArrayList;
++import java.util.Collection;
++import java.util.Collections;
++import java.util.List;
++import java.util.Optional;
++import java.util.UUID;
++import java.util.concurrent.CompletableFuture;
++import java.util.function.Function;
++import net.kyori.adventure.text.Component;
++import net.minecraft.server.network.Filterable;
++import org.bukkit.craftbukkit.util.Handleable;
++import org.checkerframework.checker.nullness.qual.NonNull;
++import org.checkerframework.framework.qual.DefaultQualifier;
++import org.jetbrains.annotations.NotNull;
++import org.jetbrains.annotations.Nullable;
++import org.jetbrains.annotations.Unmodifiable;
++
++@DefaultQualifier(NonNull.class)
++public record PaperResolvableProfile(
++ net.minecraft.world.item.component.ResolvableProfile impl
++) implements ResolvableProfile, Handleable<net.minecraft.world.item.component.ResolvableProfile> {
++
++ @Override
++ public net.minecraft.world.item.component.ResolvableProfile getHandle() {
++ return this.impl;
++ }
++
++ @Override
++ public @Nullable UUID uuid() {
++ return this.impl.id().orElse(null);
++ }
++
++ @Override
++ public @Nullable String name() {
++ return this.impl.name().orElse(null);
++ }
++
++ @Override
++ public @Unmodifiable @NonNull Collection<ProfileProperty> properties() {
++ return Collections.unmodifiableCollection(
++ Collections2.transform(
++ this.impl.properties().values(),
++ input -> new ProfileProperty(input.name(), input.value(), input.signature())
++ )
++ );
++ }
++
++ @Override
++ public @NotNull CompletableFuture<PlayerProfile> resolve() {
++ return this.impl.resolve().thenApply(resolvableProfile -> CraftPlayerProfile.asBukkitCopy(resolvableProfile.gameProfile()));
++ }
++
++ static final class BuilderImpl implements Builder {
++
++ private Optional<String> name = Optional.empty();
++ private Optional<UUID> uuid = Optional.empty();
++ private PropertyMap propertyMap = new PropertyMap();
++
++ @Override
++ public @NonNull Builder name(@Nullable final String name) {
++ this.name = Optional.ofNullable(name);
++ return this;
++ }
++
++ @Override
++ public @NonNull Builder uuid(@Nullable final UUID uuid) {
++ this.uuid = Optional.ofNullable(uuid);
++ return this;
++ }
++
++ @Override
++ public @NonNull Builder addProperty(@NonNull final ProfileProperty property) {
++ this.propertyMap.put(property.getName(), new Property(property.getName(), property.getValue(), property.getSignature()));
++ return this;
++ }
++
++
++ @Override
++ public @NonNull Builder addAllProperties(@NonNull final List<ProfileProperty> properties) {
++ properties.forEach(this::addProperty);
++ return this;
++ }
++
++ @Override
++ public ResolvableProfile build() {
++ return new PaperResolvableProfile(new net.minecraft.world.item.component.ResolvableProfile(
++ this.name,
++ this.uuid,
++ this.propertyMap
++ ));
++ }
++ }
++}
diff --git a/src/main/java/io/papermc/paper/component/item/PaperSeededContainerLoot.java b/src/main/java/io/papermc/paper/component/item/PaperSeededContainerLoot.java
new file mode 100644
index 0000000000000000000000000000000000000000..fc6169ea30df1d91363adcb48556afba30ac34a5
@@ -1564,6 +2128,241 @@ index 0000000000000000000000000000000000000000..8be3187a6c624d4ba74d2a58bc64b1b0
+ }
+ }
+}
+diff --git a/src/main/java/io/papermc/paper/component/item/PaperWritableBookContent.java b/src/main/java/io/papermc/paper/component/item/PaperWritableBookContent.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..6b4ccc782352290aa3647032e07955b8c96d4467
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/component/item/PaperWritableBookContent.java
+@@ -0,0 +1,79 @@
++package io.papermc.paper.component.item;
++
++import com.google.common.base.Preconditions;
++import com.google.common.collect.Lists;
++import io.papermc.paper.adventure.PaperAdventure;
++import io.papermc.paper.util.Filtered;
++import net.kyori.adventure.text.Component;
++import net.minecraft.server.network.Filterable;
++import org.bukkit.craftbukkit.util.Handleable;
++import org.checkerframework.checker.nullness.qual.NonNull;
++import org.checkerframework.framework.qual.DefaultQualifier;
++import org.jetbrains.annotations.NotNull;
++import org.jetbrains.annotations.Unmodifiable;
++import java.util.*;
++
++@DefaultQualifier(NonNull.class)
++public record PaperWritableBookContent(
++ net.minecraft.world.item.component.WritableBookContent impl
++) implements WritableBookContent, Handleable<net.minecraft.world.item.component.WritableBookContent> {
++
++ @Override
++ public net.minecraft.world.item.component.WritableBookContent getHandle() {
++ return this.impl;
++ }
++
++ @Override
++ public @NotNull @Unmodifiable List<Filtered<String>> pages() {
++ return Collections.unmodifiableList(
++ Lists.transform(
++ this.impl.pages(),
++ input -> Filtered.of(input.raw(), input.filtered().orElse(null))
++ )
++ );
++ }
++
++ static final class BuilderImpl implements Builder {
++
++ private final List<Filterable<String>> pages = new ArrayList<>();
++
++ @Override
++ public @NonNull Builder addPage(@NonNull final String page) {
++ Preconditions.checkArgument(page.length() <= net.minecraft.world.item.component.WritableBookContent.PAGE_EDIT_LENGTH, "String is too big!");
++ Preconditions.checkArgument(this.pages.size() < net.minecraft.world.item.component.WritableBookContent.MAX_PAGES, "Too many pages!");
++ this.pages.add(Filterable.passThrough(page));
++ return this;
++ }
++
++ @Override
++ public @NonNull Builder addPages(@NonNull final Collection<String> pages) {
++ pages.forEach(this::addPage);
++ return this;
++ }
++
++ @Override
++ public @NonNull Builder addPageFiltered(@NonNull final Filtered<String> page) {
++ Preconditions.checkArgument(page.raw().length() <= net.minecraft.world.item.component.WritableBookContent.PAGE_EDIT_LENGTH, "Page is too big!");
++ if (page.filtered() != null) {
++ Preconditions.checkArgument(page.filtered().length() <= net.minecraft.world.item.component.WritableBookContent.PAGE_EDIT_LENGTH, "Filtered page is too big!");
++ }
++ Preconditions.checkArgument(this.pages.size() < net.minecraft.world.item.component.WritableBookContent.MAX_PAGES, "Too many pages!");
++
++ this.pages.add(new Filterable<>(page.raw(), Optional.ofNullable(page.filtered())));
++ return this;
++ }
++
++ @Override
++ public @NonNull Builder addPagesFiltered(@NonNull final Collection<Filtered<String>> pages) {
++ pages.forEach(this::addPageFiltered);
++ return this;
++ }
++
++ @Override
++ public @NonNull WritableBookContent build() {
++ return new PaperWritableBookContent(
++ new net.minecraft.world.item.component.WritableBookContent(this.pages)
++ );
++ }
++ }
++}
+diff --git a/src/main/java/io/papermc/paper/component/item/PaperWrittenBookContent.java b/src/main/java/io/papermc/paper/component/item/PaperWrittenBookContent.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..a87bb09c06c5d3558114f76c97fe347b4b4bf0d6
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/component/item/PaperWrittenBookContent.java
+@@ -0,0 +1,144 @@
++package io.papermc.paper.component.item;
++
++import com.google.common.base.Function;
++import com.google.common.base.Preconditions;
++import com.google.common.collect.Lists;
++import java.util.ArrayList;
++import java.util.Collection;
++import java.util.Collections;
++import java.util.List;
++import java.util.Optional;
++import io.papermc.paper.adventure.PaperAdventure;
++import io.papermc.paper.util.Filtered;
++import net.kyori.adventure.text.Component;
++import net.minecraft.server.network.Filterable;
++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;
++import org.jetbrains.annotations.NotNull;
++import org.jetbrains.annotations.Unmodifiable;
++
++@DefaultQualifier(NonNull.class)
++public record PaperWrittenBookContent(
++ net.minecraft.world.item.component.WrittenBookContent impl
++) implements WrittenBookContent, Handleable<net.minecraft.world.item.component.WrittenBookContent> {
++
++ @Override
++ public net.minecraft.world.item.component.WrittenBookContent getHandle() {
++ return this.impl;
++ }
++
++ @Override
++ public @NotNull Filtered<String> title() {
++ return Filtered.of(this.impl.title().raw(), this.impl.title().filtered().orElse(null));
++ }
++
++ @Override
++ public @NotNull String author() {
++ return this.impl.author();
++ }
++
++ @Override
++ public int generation() {
++ return this.impl.generation();
++ }
++
++ @Override
++ public @NotNull @Unmodifiable List<Filtered<Component>> pages() {
++ return Collections.unmodifiableList(
++ Lists.transform(
++ this.impl.pages(),
++ input -> Filtered.of(PaperAdventure.asAdventure(input.raw()), input.filtered().map(PaperAdventure::asAdventure).orElse(null))
++ )
++ );
++ }
++
++ @Override
++ public boolean resolved() {
++ return this.impl.resolved();
++ }
++
++ static final class BuilderImpl implements Builder {
++
++ private static final net.minecraft.world.item.component.WrittenBookContent EMPTY = net.minecraft.world.item.component.WrittenBookContent.EMPTY;
++
++ private final List<Filterable<net.minecraft.network.chat.Component>> pages = new ArrayList<>();
++ private Filterable<String> title = EMPTY.title();
++ private String author = EMPTY.author();
++ private int generation = EMPTY.generation();
++ private boolean resolved = EMPTY.resolved();
++
++ @Override
++ public @NonNull Builder title(@NonNull final String title) {
++ Preconditions.checkArgument(title.length() <= net.minecraft.world.item.component.WrittenBookContent.TITLE_MAX_LENGTH, "Title is too big!");
++ this.title = Filterable.passThrough(title);
++ return this;
++ }
++
++ @Override
++ public @NonNull Builder titleFiltered(@NonNull final Filtered<String> title) {
++ Preconditions.checkArgument(title.raw().length() <= net.minecraft.world.item.component.WrittenBookContent.TITLE_MAX_LENGTH, "Title is too big!");
++ if (title.filtered() != null) {
++ Preconditions.checkArgument(title.filtered().length() <= net.minecraft.world.item.component.WrittenBookContent.TITLE_MAX_LENGTH, "Filtered title is too big!");
++ }
++ this.title = new Filterable<>(title.raw(), Optional.ofNullable(title.filtered()));
++ return this;
++ }
++
++ @Override
++ public @NonNull Builder author(@NonNull final String author) {
++ this.author = author;
++ return this;
++ }
++
++ @Override
++ public @NonNull Builder generation(final int generation) {
++ Preconditions.checkArgument(generation <= net.minecraft.world.item.component.WrittenBookContent.MAX_GENERATION, "Generation is too big!");
++ this.generation = generation;
++ return this;
++ }
++
++ @Override
++ public @NonNull Builder resolved(final boolean resolved) {
++ this.resolved = resolved;
++ return this;
++ }
++
++ @Override
++ public @NonNull Builder addPage(@NonNull final Component page) {
++ this.pages.add(Filterable.passThrough(PaperAdventure.asVanilla(page)));
++ return this;
++ }
++
++ @Override
++ public @NonNull Builder addPages(@NonNull final Collection<Component> pages) {
++ pages.forEach(this::addPage);
++ return this;
++ }
++
++ @Override
++ public @NonNull Builder addPageFiltered(@NonNull final Filtered<Component> page) {
++ this.pages.add(new Filterable<>(PaperAdventure.asVanilla(page.raw()), Optional.ofNullable(page.filtered()).map(PaperAdventure::asVanilla)));
++ return this;
++ }
++
++ @Override
++ public @NonNull Builder addPagesFiltered(@NonNull final Collection<Filtered<Component>> pages) {
++ pages.forEach(this::addPageFiltered);
++ return this;
++ }
++
++ @Override
++ public WrittenBookContent build() {
++ return new PaperWrittenBookContent(new net.minecraft.world.item.component.WrittenBookContent(
++ this.title,
++ this.author,
++ this.generation,
++ this.pages,
++ this.resolved
++ ));
++ }
++ }
++}
diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/src/main/java/io/papermc/paper/registry/PaperRegistries.java
index 51979b3c3f1f3a3c63e0559c70bed9193fd35dbb..df2af45f32af3a1ddef25c5e7cca3973481806e2 100644
--- a/src/main/java/io/papermc/paper/registry/PaperRegistries.java
@@ -1753,6 +2552,28 @@ index b54be1122af2b303c0f063ff6b61bf8e2478b0df..a66775b21e829f76de9cf234b702f5f0
+ }
+ // 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 77489c3ffaa3a72d4cf105499a77150fca6d8526..e91c8a7c7c62909a3adc29e13c7b6ff83e13cbf8 100644
+--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java
++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java
+@@ -79,7 +79,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta {
+ });
+ }
+
+- static FireworkEffect getEffect(FireworkExplosion explosion) {
++ public static FireworkEffect getEffect(FireworkExplosion explosion) { // Paper
+ FireworkEffect.Builder effect = FireworkEffect.builder()
+ .flicker(explosion.hasTwinkle())
+ .trail(explosion.hasTrail())
+@@ -99,7 +99,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta {
+ return effect.build();
+ }
+
+- static FireworkExplosion getExplosion(FireworkEffect effect) {
++ public static FireworkExplosion getExplosion(FireworkEffect effect) { // Paper
+ IntList colors = CraftMetaFirework.addColors(effect.getColors());
+ IntList fadeColors = CraftMetaFirework.addColors(effect.getFadeColors());
+
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
index d5789326d70bb8b029c5448270bbaa6faf52e6e1..02cdd38a55741a56ed9de428d9145e6103b71f65 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java