diff --git a/patches/api/Adventure.patch b/patches/api/Adventure.patch
index 28bbf09cd3..5613f8de20 100644
--- a/patches/api/Adventure.patch
+++ b/patches/api/Adventure.patch
@@ -4361,6 +4361,178 @@ diff --git a/src/main/java/org/bukkit/inventory/meta/BookMeta.java b/src/main/ja
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/inventory/meta/BookMeta.java
+++ b/src/main/java/org/bukkit/inventory/meta/BookMeta.java
+@@ -0,0 +0,0 @@ import org.jetbrains.annotations.NotNull;
+ import org.jetbrains.annotations.Nullable;
+
+ /**
+- * Represents a {@link Material#WRITTEN_BOOK}) that can have a title, an author,
++ * Represents a {@link Material#WRITTEN_BOOK} that can have a title, an author,
+ * and pages.
++ *
++ * Before using this type, make sure to check the itemstack's material with
++ * {@link org.bukkit.inventory.ItemStack#getType()}. {@code instanceof} on
++ * the meta instance is not sufficient due to unusual inheritance
++ * with relation to {@link WritableBookMeta}.
+ */
+-public interface BookMeta extends WritableBookMeta {
++public interface BookMeta extends WritableBookMeta, net.kyori.adventure.inventory.Book { // Paper - adventure
+
+ /**
+ * Represents the generation (or level of copying) of a written book
+@@ -0,0 +0,0 @@ public interface BookMeta extends WritableBookMeta {
+ @NotNull
+ BookMeta clone();
+
++ // Paper start - adventure
++ //
++ /**
++ * @deprecated use {@link #page(int)}
++ */
++ @Deprecated
++ @Override
++ @NotNull String getPage(int page);
++
++ /**
++ * @deprecated use {@link #page(int, net.kyori.adventure.text.Component)}
++ */
++ @Deprecated
++ @Override
++ void setPage(int page, @NotNull String data);
++
++ /**
++ * @deprecated use {@link #pages()}
++ */
++ @Deprecated
++ @Override
++ @NotNull List getPages();
++
++ /**
++ * @deprecated use {@link #pages(List)}
++ */
++ @Deprecated
++ @Override
++ void setPages(@NotNull List pages);
++
++ /**
++ * @deprecated use {@link #pages(net.kyori.adventure.text.Component...)}
++ */
++ @Deprecated
++ @Override
++ void setPages(@NotNull String... pages);
++
++ /**
++ * @deprecated use {@link #addPages(net.kyori.adventure.text.Component...)}
++ */
++ @Deprecated
++ @Override
++ void addPage(@NotNull String... pages);
++ //
++
++ /**
++ * Gets the title of the book.
++ *
++ * Plugins should check that hasTitle() returns true before calling this
++ * method.
++ *
++ * @return the title of the book
++ */
++ @Override
++ net.kyori.adventure.text.@Nullable Component title();
++
++ /**
++ * Sets the title of the book.
++ *
++ * Limited to 32 characters. Removes title when given null.
++ *
++ * @param title the title to set
++ * @return the same {@link BookMeta} instance
++ */
++ @org.jetbrains.annotations.Contract(value = "_ -> this", pure = false)
++ @Override
++ @NotNull BookMeta title(net.kyori.adventure.text.@Nullable Component title);
++
++ /**
++ * Gets the author of the book.
++ *
++ * Plugins should check that hasAuthor() returns true before calling this
++ * method.
++ *
++ * @return the author of the book
++ */
++ @Override
++ net.kyori.adventure.text.@Nullable Component author();
++
++ /**
++ * Sets the author of the book. Removes author when given null.
++ *
++ * @param author the author to set
++ * @return the same {@link BookMeta} instance
++ */
++ @org.jetbrains.annotations.Contract(value = "_ -> this", pure = false)
++ @Override
++ @NotNull BookMeta author(net.kyori.adventure.text.@Nullable Component author);
++
++
++ /**
++ * Gets the specified page in the book. The page must exist.
++ *
++ * Pages are 1-indexed.
++ *
++ * @param page the page number to get, in range [1, getPageCount()]
++ * @return the page from the book
++ */
++ net.kyori.adventure.text.@NotNull Component page(int page);
++
++ /**
++ * Sets the specified page in the book. Pages of the book must be
++ * contiguous.
++ *
++ * The data can be up to 1024 characters in length, additional characters
++ * are truncated.
++ *
++ * Pages are 1-indexed.
++ *
++ * @param page the page number to set, in range [1, getPageCount()]
++ * @param data the data to set for that page
++ */
++ void page(int page, net.kyori.adventure.text.@NotNull Component data);
++
++ /**
++ * Adds new pages to the end of the book. Up to a maximum of 100 pages with
++ * 1024 characters per page.
++ *
++ * @param pages A list of strings, each being a page
++ */
++ void addPages(net.kyori.adventure.text.@NotNull Component @NotNull ... pages);
++
++ interface BookMetaBuilder extends net.kyori.adventure.inventory.Book.Builder {
++
++ @Override
++ @NotNull BookMetaBuilder title(net.kyori.adventure.text.@Nullable Component title);
++
++ @Override
++ @NotNull BookMetaBuilder author(net.kyori.adventure.text.@Nullable Component author);
++
++ @Override
++ @NotNull BookMetaBuilder addPage(net.kyori.adventure.text.@NotNull Component page);
++
++ @Override
++ @NotNull BookMetaBuilder pages(net.kyori.adventure.text.@NotNull Component @NotNull ... pages);
++
++ @Override
++ @NotNull BookMetaBuilder pages(java.util.@NotNull Collection pages);
++
++ @Override
++ @NotNull BookMeta build();
++ }
++
++ @Override
++ @NotNull BookMetaBuilder toBuilder();
++ // Paper end
++
+ // Spigot start
+ public class Spigot {
+
@@ -0,0 +0,0 @@ public interface BookMeta extends WritableBookMeta {
*
* @param page the page number to get
@@ -4521,185 +4693,23 @@ diff --git a/src/main/java/org/bukkit/inventory/meta/WritableBookMeta.java b/src
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/inventory/meta/WritableBookMeta.java
+++ b/src/main/java/org/bukkit/inventory/meta/WritableBookMeta.java
-@@ -0,0 +0,0 @@ import org.jetbrains.annotations.NotNull;
- * Represents a book ({@link Material#WRITABLE_BOOK} or {@link
- * Material#WRITTEN_BOOK}) that can have pages.
+@@ -0,0 +0,0 @@ import org.bukkit.Material;
+ import org.jetbrains.annotations.NotNull;
+
+ /**
+- * Represents a book ({@link Material#WRITABLE_BOOK} or {@link
+- * Material#WRITTEN_BOOK}) that can have pages.
++ * Represents a book ({@link Material#WRITABLE_BOOK}) that can have pages.
++ *
++ * For {@link Material#WRITTEN_BOOK}, use {@link BookMeta}.
++ *
++ * Before using this type, make sure to check the itemstack's material with
++ * {@link org.bukkit.inventory.ItemStack#getType()}. {@code instanceof} on
++ * the meta instance is not sufficient due to unusual inheritance
++ * with relation to {@link BookMeta}.
*/
--public interface WritableBookMeta extends ItemMeta {
-+public interface WritableBookMeta extends ItemMeta, net.kyori.adventure.inventory.Book { // Paper
+ public interface WritableBookMeta extends ItemMeta {
- /**
- * Checks for the existence of pages in the book.
-@@ -0,0 +0,0 @@ public interface WritableBookMeta extends ItemMeta {
- */
- boolean hasPages();
-
-+ // Paper start
-+ /**
-+ * Gets the title of the book.
-+ *
-+ * Plugins should check that hasTitle() returns true before calling this
-+ * method.
-+ *
-+ * @return the title of the book
-+ */
-+ @Override
-+ net.kyori.adventure.text.@org.jetbrains.annotations.Nullable Component title();
-+
-+ /**
-+ * Sets the title of the book.
-+ *
-+ * Limited to 32 characters. Removes title when given null.
-+ *
-+ * @param title the title to set
-+ * @return the same {@link BookMeta} instance
-+ */
-+ @org.jetbrains.annotations.Contract(value = "_ -> this", pure = false)
-+ @Override
-+ @NotNull BookMeta title(net.kyori.adventure.text.@org.jetbrains.annotations.Nullable Component title);
-+
-+ /**
-+ * Gets the author of the book.
-+ *
-+ * Plugins should check that hasAuthor() returns true before calling this
-+ * method.
-+ *
-+ * @return the author of the book
-+ */
-+ @Override
-+ net.kyori.adventure.text.@org.jetbrains.annotations.Nullable Component author();
-+
-+ /**
-+ * Sets the author of the book. Removes author when given null.
-+ *
-+ * @param author the author to set
-+ * @return the same {@link BookMeta} instance
-+ */
-+ @org.jetbrains.annotations.Contract(value = "_ -> this", pure = false)
-+ @Override
-+ @NotNull BookMeta author(net.kyori.adventure.text.@org.jetbrains.annotations.Nullable Component author);
-+
-+ /**
-+ * Gets the specified page in the book. The page must exist.
-+ *
-+ * Pages are 1-indexed.
-+ *
-+ * @param page the page number to get, in range [1, getPageCount()]
-+ * @return the page from the book
-+ */
-+ net.kyori.adventure.text.@NotNull Component page(int page);
-+
-+ /**
-+ * Sets the specified page in the book. Pages of the book must be
-+ * contiguous.
-+ *
-+ * The data can be up to 1024 characters in length, additional characters
-+ * are truncated.
-+ *
-+ * Pages are 1-indexed.
-+ *
-+ * @param page the page number to set, in range [1, getPageCount()]
-+ * @param data the data to set for that page
-+ */
-+ void page(int page, net.kyori.adventure.text.@NotNull Component data);
-+
-+ /**
-+ * Adds new pages to the end of the book. Up to a maximum of 100 pages with
-+ * 1024 characters per page.
-+ *
-+ * @param pages A list of strings, each being a page
-+ */
-+ void addPages(net.kyori.adventure.text.@NotNull Component @NotNull ... pages);
-+
-+ interface BookMetaBuilder extends net.kyori.adventure.inventory.Book.Builder {
-+
-+ @Override
-+ @NotNull BookMetaBuilder title(net.kyori.adventure.text.@org.jetbrains.annotations.Nullable Component title);
-+
-+ @Override
-+ @NotNull BookMetaBuilder author(net.kyori.adventure.text.@org.jetbrains.annotations.Nullable Component author);
-+
-+ @Override
-+ @NotNull BookMetaBuilder addPage(net.kyori.adventure.text.@NotNull Component page);
-+
-+ @Override
-+ @NotNull BookMetaBuilder pages(net.kyori.adventure.text.@NotNull Component @NotNull ... pages);
-+
-+ @Override
-+ @NotNull BookMetaBuilder pages(java.util.@NotNull Collection pages);
-+
-+ @Override
-+ @NotNull BookMeta build();
-+ }
-+
-+ @Override
-+ @NotNull BookMetaBuilder toBuilder();
-+ // Paper end
-+
- /**
- * Gets the specified page in the book. The given page must exist.
- *
-@@ -0,0 +0,0 @@ public interface WritableBookMeta extends ItemMeta {
- *
- * @param page the page number to get, in range [1, getPageCount()]
- * @return the page from the book
-+ * @deprecated in favour of {@link #page(int)}
- */
- @NotNull
-+ @Deprecated // Paper
- String getPage(int page);
-
- /**
-@@ -0,0 +0,0 @@ public interface WritableBookMeta extends ItemMeta {
- *
- * @param page the page number to set, in range [1, getPageCount()]
- * @param data the data to set for that page
-+ * @deprecated in favour of {@link #page(int, net.kyori.adventure.text.Component)}
- */
-+ @Deprecated // Paper
- void setPage(int page, @NotNull String data);
-
- /**
- * Gets all the pages in the book.
- *
- * @return list of all the pages in the book
-+ * @deprecated in favour of {@link #pages()}
- */
- @NotNull
-+ @Deprecated // Paper
- List getPages();
-
- /**
-@@ -0,0 +0,0 @@ public interface WritableBookMeta extends ItemMeta {
- * pages. Maximum 100 pages with 1024 characters per page.
- *
- * @param pages A list of pages to set the book to use
-+ * @deprecated in favour of {@link #pages(List)}
- */
-+ @Deprecated // Paper
- void setPages(@NotNull List pages);
-
- /**
-@@ -0,0 +0,0 @@ public interface WritableBookMeta extends ItemMeta {
- * pages. Maximum 100 pages with 1024 characters per page.
- *
- * @param pages A list of strings, each being a page
-+ * @deprecated in favour of {@link #pages(net.kyori.adventure.text.Component...)}
- */
-+ @Deprecated // Paper
- void setPages(@NotNull String... pages);
-
- /**
-@@ -0,0 +0,0 @@ public interface WritableBookMeta extends ItemMeta {
- * 1024 characters per page.
- *
- * @param pages A list of strings, each being a page
-+ * @deprecated in favour of {@link #addPages(net.kyori.adventure.text.Component...)}
- */
-+ @Deprecated // Paper
- void addPage(@NotNull String... pages);
-
- /**
diff --git a/src/main/java/org/bukkit/inventory/meta/trim/TrimMaterial.java b/src/main/java/org/bukkit/inventory/meta/trim/TrimMaterial.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/inventory/meta/trim/TrimMaterial.java
@@ -5112,10 +5122,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
*/
@Deprecated
@NotNull
-+ @Deprecated // Paper
- Objective registerNewObjective(@NotNull String name, @NotNull String criteria, @NotNull String displayName);
-
- /**
@@ -0,0 +0,0 @@ public interface Scoreboard {
* characters.
* @throws IllegalArgumentException if an objective by that name already
@@ -5125,10 +5131,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
*/
@Deprecated
@NotNull
-+ @Deprecated // Paper
- Objective registerNewObjective(@NotNull String name, @NotNull String criteria, @NotNull String displayName, @NotNull RenderType renderType);
-
- /**
@@ -0,0 +0,0 @@ public interface Scoreboard {
* characters.
* @throws IllegalArgumentException if an objective by that name already
diff --git a/patches/api/Fix-Spigot-annotation-mistakes.patch b/patches/api/Fix-Spigot-annotation-mistakes.patch
index e782e537a3..ffbb5e6e09 100644
--- a/patches/api/Fix-Spigot-annotation-mistakes.patch
+++ b/patches/api/Fix-Spigot-annotation-mistakes.patch
@@ -980,14 +980,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
super(view);
this.enchanter = enchanter;
this.table = table;
-@@ -0,0 +0,0 @@ public class PrepareItemEnchantEvent extends InventoryEvent implements Cancellab
- * @return experience level costs offered
- * @deprecated Use {@link #getOffers()} instead of this method
- */
-+ @Deprecated // Paper
- @NotNull
- @Deprecated
- public int[] getExpLevelCostsOffered() {
@@ -0,0 +0,0 @@ public class PrepareItemEnchantEvent extends InventoryEvent implements Cancellab
*
* @return list of available enchantment offers
@@ -1851,18 +1843,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
public interface Redstone {
/**
-diff --git a/src/main/java/org/bukkit/material/Step.java b/src/main/java/org/bukkit/material/Step.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/org/bukkit/material/Step.java
-+++ b/src/main/java/org/bukkit/material/Step.java
-@@ -0,0 +0,0 @@ public class Step extends TexturedMaterial {
- *
- * @deprecated Magic value
- */
-+ @Deprecated // Paper
- @Override
- @Deprecated
- protected int getTextureIndex() {
diff --git a/src/main/java/org/bukkit/material/types/MushroomBlockTexture.java b/src/main/java/org/bukkit/material/types/MushroomBlockTexture.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/material/types/MushroomBlockTexture.java
diff --git a/patches/server/Adventure.patch b/patches/server/Adventure.patch
index ab998b46d1..eb5260a3c1 100644
--- a/patches/server/Adventure.patch
+++ b/patches/server/Adventure.patch
@@ -4827,57 +4827,52 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // Paper start
+ @Override
+ public net.kyori.adventure.text.Component title() {
-+ return this.title == null ? null : LEGACY_DOWNSAMPLING_COMPONENT_SERIALIZER.deserialize(this.title);
++ return null;
+ }
+
+ @Override
+ public org.bukkit.inventory.meta.BookMeta title(net.kyori.adventure.text.Component title) {
-+ this.setTitle(title == null ? null : LEGACY_DOWNSAMPLING_COMPONENT_SERIALIZER.serialize(title));
+ return this;
+ }
+
+ @Override
+ public net.kyori.adventure.text.Component author() {
-+ return this.author == null ? null : LEGACY_DOWNSAMPLING_COMPONENT_SERIALIZER.deserialize(this.author);
++ return null;
+ }
+
+ @Override
+ public org.bukkit.inventory.meta.BookMeta author(net.kyori.adventure.text.Component author) {
-+ this.setAuthor(author == null ? null : LEGACY_DOWNSAMPLING_COMPONENT_SERIALIZER.serialize(author));
+ return this;
+ }
+
+ @Override
+ public net.kyori.adventure.text.Component page(final int page) {
-+ Preconditions.checkArgument(isValidPage(page), "Invalid page number");
-+ return this instanceof CraftMetaBookSigned ? net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().deserialize(pages.get(page - 1)) : net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(pages.get(page - 1));
++ Preconditions.checkArgument(this.isValidPage(page), "Invalid page number");
++ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(this.pages.get(page - 1));
+ }
+
+ @Override
+ public void page(final int page, net.kyori.adventure.text.Component data) {
-+ if (!isValidPage(page)) {
-+ throw new IllegalArgumentException("Invalid page number " + page + "/" + pages.size());
++ if (!this.isValidPage(page)) {
++ throw new IllegalArgumentException("Invalid page number " + page + "/" + this.pages.size());
+ }
+ if (data == null) {
+ data = net.kyori.adventure.text.Component.empty();
+ }
-+ pages.set(page - 1, this instanceof CraftMetaBookSigned ? net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().serialize(data) : net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(data));
++ this.pages.set(page - 1, net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(data));
+ }
+
+ @Override
+ public List pages() {
+ if (this.pages == null) return ImmutableList.of();
-+ if (this instanceof CraftMetaBookSigned)
-+ return pages.stream().map(net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson()::deserialize).collect(ImmutableList.toImmutableList());
-+ else
-+ return pages.stream().map(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection()::deserialize).collect(ImmutableList.toImmutableList());
++ return this.pages.stream().map(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection()::deserialize).collect(ImmutableList.toImmutableList());
+ }
+
+ @Override
+ public BookMeta pages(List pages) {
+ if (this.pages != null) this.pages.clear();
+ for (net.kyori.adventure.text.Component page : pages) {
-+ addPages(page);
++ this.addPages(page);
+ }
+ return this;
+ }
@@ -4885,7 +4880,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ @Override
+ public BookMeta pages(net.kyori.adventure.text.Component... pages) {
+ if (this.pages != null) this.pages.clear();
-+ addPages(pages);
++ this.addPages(pages);
+ return this;
+ }
+
@@ -4901,34 +4896,25 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ page = net.kyori.adventure.text.Component.empty();
+ }
+
-+ this.pages.add(this instanceof CraftMetaBookSigned ? net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().serialize(page) : net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(page));
++ this.pages.add(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(page));
+ }
+ }
+
-+ public static final net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer LEGACY_DOWNSAMPLING_COMPONENT_SERIALIZER = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.builder()
-+ .character(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.SECTION_CHAR)
-+ .build();
-+ private CraftMetaBook(net.kyori.adventure.text.Component title, net.kyori.adventure.text.Component author, List pages) {
++ private CraftMetaBook(List pages) {
+ super((org.bukkit.craftbukkit.inventory.CraftMetaItem) org.bukkit.Bukkit.getItemFactory().getItemMeta(org.bukkit.Material.WRITABLE_BOOK));
-+ this.title = title == null ? null : LEGACY_DOWNSAMPLING_COMPONENT_SERIALIZER.serialize(title);
-+ this.author = author == null ? null : LEGACY_DOWNSAMPLING_COMPONENT_SERIALIZER.serialize(author);
+ this.pages = pages.subList(0, Math.min(MAX_PAGES, pages.size())).stream().map(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection()::serialize).collect(java.util.stream.Collectors.toList());
+ }
+
+ static class CraftMetaBookBuilder implements BookMetaBuilder {
-+ private net.kyori.adventure.text.Component title = null;
-+ private net.kyori.adventure.text.Component author = null;
-+ private final List pages = new java.util.ArrayList<>();
++ protected final List pages = new java.util.ArrayList<>();
+
+ @Override
+ public BookMetaBuilder title(net.kyori.adventure.text.Component title) {
-+ this.title = title;
+ return this;
+ }
+
+ @Override
+ public BookMetaBuilder author(net.kyori.adventure.text.Component author) {
-+ this.author = author;
+ return this;
+ }
+
@@ -4952,11 +4938,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+ @Override
+ public BookMeta build() {
-+ return this.build(title, author, pages);
-+ }
-+
-+ protected BookMeta build(net.kyori.adventure.text.Component title, net.kyori.adventure.text.Component author, java.util.List pages) {
-+ return new CraftMetaBook(title, author, pages);
++ return new CraftMetaBook(this.pages);
+ }
+ }
+
@@ -5006,17 +4988,35 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
// Spigot end
+
+ // Paper start - adventure
++ public static final net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer LEGACY_DOWNSAMPLING_COMPONENT_SERIALIZER = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.builder()
++ .character(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.SECTION_CHAR)
++ .build();
+ private CraftMetaBookSigned(net.kyori.adventure.text.Component title, net.kyori.adventure.text.Component author, java.util.List pages) {
+ super((org.bukkit.craftbukkit.inventory.CraftMetaItem) org.bukkit.Bukkit.getItemFactory().getItemMeta(Material.WRITABLE_BOOK));
-+ this.title = title == null ? null : CraftMetaBook.LEGACY_DOWNSAMPLING_COMPONENT_SERIALIZER.serialize(title);
-+ this.author = author == null ? null : CraftMetaBook.LEGACY_DOWNSAMPLING_COMPONENT_SERIALIZER.serialize(author);
++ this.title = title == null ? null : LEGACY_DOWNSAMPLING_COMPONENT_SERIALIZER.serialize(title);
++ this.author = author == null ? null : LEGACY_DOWNSAMPLING_COMPONENT_SERIALIZER.serialize(author);
+ this.pages = io.papermc.paper.adventure.PaperAdventure.asVanilla(pages.subList(0, Math.min(MAX_PAGES, pages.size())));
+ }
+
+ static final class CraftMetaBookSignedBuilder extends CraftMetaBook.CraftMetaBookBuilder {
++ private net.kyori.adventure.text.Component title;
++ private net.kyori.adventure.text.Component author;
++
+ @Override
-+ protected BookMeta build(net.kyori.adventure.text.Component title, net.kyori.adventure.text.Component author, java.util.List pages) {
-+ return new CraftMetaBookSigned(title, author, pages);
++ public org.bukkit.inventory.meta.BookMeta.BookMetaBuilder title(final net.kyori.adventure.text.Component title) {
++ this.title = title;
++ return this;
++ }
++
++ @Override
++ public org.bukkit.inventory.meta.BookMeta.BookMetaBuilder author(final net.kyori.adventure.text.Component author) {
++ this.author = author;
++ return this;
++ }
++
++ @Override
++ public org.bukkit.inventory.meta.BookMeta build() {
++ return new CraftMetaBookSigned(this.title, this.author, this.pages);
+ }
+ }
+
@@ -5024,6 +5024,76 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ public BookMetaBuilder toBuilder() {
+ return new CraftMetaBookSignedBuilder();
+ }
++
++ @Override
++ public net.kyori.adventure.text.Component title() {
++ return this.title == null ? null : LEGACY_DOWNSAMPLING_COMPONENT_SERIALIZER.deserialize(this.title);
++ }
++
++ @Override
++ public org.bukkit.inventory.meta.BookMeta title(net.kyori.adventure.text.Component title) {
++ this.setTitle(title == null ? null : LEGACY_DOWNSAMPLING_COMPONENT_SERIALIZER.serialize(title));
++ return this;
++ }
++
++ @Override
++ public net.kyori.adventure.text.Component author() {
++ return this.author == null ? null : LEGACY_DOWNSAMPLING_COMPONENT_SERIALIZER.deserialize(this.author);
++ }
++
++ @Override
++ public org.bukkit.inventory.meta.BookMeta author(net.kyori.adventure.text.Component author) {
++ this.setAuthor(author == null ? null : LEGACY_DOWNSAMPLING_COMPONENT_SERIALIZER.serialize(author));
++ return this;
++ }
++
++ @Override
++ public net.kyori.adventure.text.Component page(final int page) {
++ Preconditions.checkArgument(this.isValidPage(page), "Invalid page number");
++ return io.papermc.paper.adventure.PaperAdventure.asAdventure(this.pages.get(page - 1));
++ }
++
++ @Override
++ public void page(final int page, net.kyori.adventure.text.Component data) {
++ if (!this.isValidPage(page)) {
++ throw new IllegalArgumentException("Invalid page number " + page + "/" + this.pages.size());
++ }
++ this.pages.set(page - 1, io.papermc.paper.adventure.PaperAdventure.asVanillaNullToEmpty(data));
++ }
++
++ @Override
++ public List pages() {
++ if (this.pages == null) return ImmutableList.of();
++ return this.pages.stream().map(io.papermc.paper.adventure.PaperAdventure::asAdventure).collect(ImmutableList.toImmutableList());
++ }
++
++ @Override
++ public BookMeta pages(List pages) {
++ if (this.pages != null) this.pages.clear();
++ for (net.kyori.adventure.text.Component page : pages) {
++ this.addPages(page);
++ }
++ return this;
++ }
++
++ @Override
++ public BookMeta pages(net.kyori.adventure.text.Component... pages) {
++ if (this.pages != null) this.pages.clear();
++ this.addPages(pages);
++ return this;
++ }
++
++ @Override
++ public void addPages(net.kyori.adventure.text.Component... pages) {
++ if (this.pages == null) this.pages = new ArrayList<>();
++ for (net.kyori.adventure.text.Component page : pages) {
++ if (this.pages.size() >= MAX_PAGES) {
++ return;
++ }
++
++ this.pages.add(io.papermc.paper.adventure.PaperAdventure.asVanillaNullToEmpty(page));
++ }
++ }
+ // Paper end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java