diff --git a/patches/api/Adventure.patch b/patches/api/Adventure.patch
index 4fb579bcdf..6766221f3f 100644
--- a/patches/api/Adventure.patch
+++ b/patches/api/Adventure.patch
@@ -390,9 +390,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import net.kyori.adventure.text.format.NamedTextColor;
 +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
 +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
-+import net.kyori.adventure.text.serializer.plain.PlainComponentSerializer;
++import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
 +import org.bukkit.Bukkit;
-+import org.checkerframework.checker.nullness.qual.NonNull;
++import org.jetbrains.annotations.NotNull;
 +
 +/**
 + * Paper API-specific methods for working with {@link Component}s and related.
@@ -407,7 +407,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +     *
 +     * @return a component flattener
 +     */
-+    public static @NonNull ComponentFlattener flattener() {
++    public static @NotNull ComponentFlattener flattener() {
 +        return Bukkit.getUnsafe().componentFlattener();
 +    }
 +
@@ -420,7 +420,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +     *
 +     * @return a serializer to plain text
 +     */
-+    public static @NonNull PlainComponentSerializer plainSerializer() {
++    public static @NotNull PlainTextComponentSerializer plainSerializer() {
 +        return Bukkit.getUnsafe().plainComponentSerializer();
 +    }
 +
@@ -434,7 +434,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +     *
 +     * @return a json component serializer
 +     */
-+    public static @NonNull GsonComponentSerializer gsonSerializer() {
++    public static @NotNull GsonComponentSerializer gsonSerializer() {
 +        return Bukkit.getUnsafe().gsonComponentSerializer();
 +    }
 +
@@ -449,7 +449,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +     *
 +     * @return a json component serializer
 +     */
-+    public static @NonNull GsonComponentSerializer colorDownsamplingGsonSerializer() {
++    public static @NotNull GsonComponentSerializer colorDownsamplingGsonSerializer() {
 +        return Bukkit.getUnsafe().colorDownsamplingGsonComponentSerializer();
 +    }
 +
@@ -467,7 +467,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +     *
 +     * @return a section serializer
 +     */
-+    public static @NonNull LegacyComponentSerializer legacySectionSerializer() {
++    public static @NotNull LegacyComponentSerializer legacySectionSerializer() {
 +        return Bukkit.getUnsafe().legacyComponentSerializer();
 +    }
 +}
@@ -1095,7 +1095,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
  public interface UnsafeValues {
 +    // Paper start
 +    net.kyori.adventure.text.flattener.ComponentFlattener componentFlattener();
-+    net.kyori.adventure.text.serializer.plain.PlainComponentSerializer plainComponentSerializer();
++    net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer plainComponentSerializer();
 +    net.kyori.adventure.text.serializer.gson.GsonComponentSerializer gsonComponentSerializer();
 +    net.kyori.adventure.text.serializer.gson.GsonComponentSerializer colorDownsamplingGsonComponentSerializer();
 +    net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer legacyComponentSerializer();
@@ -1776,18 +1776,23 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        this.sendSignChange(loc, lines, DyeColor.BLACK);
 +    }
 +
-     /**
-      * Send a sign change. This fakes a sign change packet for a user at
-      * a certain location. This will not actually change the world in any way.
-@@ -0,0 +0,0 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM
-      *
-      * @param loc the location of the sign
-      * @param lines the new text on the sign or null to clear it
++    /**
++     * Send a sign change. This fakes a sign change packet for a user at
++     * a certain location. This will not actually change the world in any way.
++     * This method will use a sign at the location's block or a faked sign
++     * sent via
++     * {@link #sendBlockChange(org.bukkit.Location, org.bukkit.Material, byte)}.
++     * <p>
++     * If the client does not have a sign at the given location it will
++     * display an error message to the user.
++     *
++     * @param loc the location of the sign
++     * @param lines the new text on the sign or null to clear it
 +     * @param dyeColor the color of the sign
-      * @throws IllegalArgumentException if location is null
++     * @throws IllegalArgumentException if location is null
 +     * @throws IllegalArgumentException if dyeColor is null
-      * @throws IllegalArgumentException if lines is non-null and has a length less than 4
-      */
++     * @throws IllegalArgumentException if lines is non-null and has a length less than 4
++     */
 +    default void sendSignChange(@NotNull Location loc, @Nullable java.util.List<net.kyori.adventure.text.Component> lines, @NotNull DyeColor dyeColor) throws IllegalArgumentException {
 +        this.sendSignChange(loc, lines, dyeColor, false);
 +    }
@@ -1835,22 +1840,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        throws IllegalArgumentException;
 +    // Paper end
 +
-+    /**
-+     * Send a sign change. This fakes a sign change packet for a user at
-+     * a certain location. This will not actually change the world in any way.
-+     * This method will use a sign at the location's block or a faked sign
-+     * sent via
-+     * {@link #sendBlockChange(org.bukkit.Location, org.bukkit.Material, byte)}.
-+     * <p>
-+     * If the client does not have a sign at the given location it will
-+     * display an error message to the user.
-+     *
-+     * @param loc the location of the sign
-+     * @param lines the new text on the sign or null to clear it
-+     * @throws IllegalArgumentException if location is null
-+     * @throws IllegalArgumentException if lines is non-null and has a length less than 4
+     /**
+      * Send a sign change. This fakes a sign change packet for a user at
+      * a certain location. This will not actually change the world in any way.
+@@ -0,0 +0,0 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM
+      * @param lines the new text on the sign or null to clear it
+      * @throws IllegalArgumentException if location is null
+      * @throws IllegalArgumentException if lines is non-null and has a length less than 4
 +     * @deprecated in favour of {@link #sendSignChange(org.bukkit.Location, java.util.List)}
-+     */
+      */
 +    @Deprecated // Paper
      public void sendSignChange(@NotNull Location loc, @Nullable String[] lines) throws IllegalArgumentException;
  
@@ -1875,6 +1873,116 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
      public void sendSignChange(@NotNull Location loc, @Nullable String[] lines, @NotNull DyeColor dyeColor, boolean hasGlowingText) throws IllegalArgumentException;
  
      /**
+@@ -0,0 +0,0 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM
+      */
+     public void setResourcePack(@NotNull String url, @Nullable byte[] hash, @Nullable String prompt);
+ 
++    // Paper start
++    /**
++     * Request that the player's client download and switch resource packs.
++     * <p>
++     * The player's client will download the new resource pack asynchronously
++     * in the background, and will automatically switch to it once the
++     * download is complete. If the client has downloaded and cached a
++     * resource pack with the same hash in the past it will not download but
++     * directly apply the cached pack. If the hash is null and the client has
++     * downloaded and cached the same resource pack in the past, it will
++     * perform a file size check against the response content to determine if
++     * the resource pack has changed and needs to be downloaded again. When
++     * this request is sent for the very first time from a given server, the
++     * client will first display a confirmation GUI to the player before
++     * proceeding with the download.
++     * <p>
++     * Notes:
++     * <ul>
++     * <li>Players can disable server resources on their client, in which
++     *     case this method will have no affect on them. Use the
++     *     {@link PlayerResourcePackStatusEvent} to figure out whether or not
++     *     the player loaded the pack!
++     * <li>There is no concept of resetting resource packs back to default
++     *     within Minecraft, so players will have to relog to do so or you
++     *     have to send an empty pack.
++     * <li>The request is sent with empty string as the hash when the hash is
++     *     not provided. This might result in newer versions not loading the
++     *     pack correctly.
++     * </ul>
++     *
++     * @param url The URL from which the client will download the resource
++     *     pack. The string must contain only US-ASCII characters and should
++     *     be encoded as per RFC 1738.
++     * @param hash The sha1 hash sum of the resource pack file which is used
++     *     to apply a cached version of the pack directly without downloading
++     *     if it is available. Hast to be 20 bytes long!
++     * @param prompt The optional custom prompt message to be shown to client.
++     * @throws IllegalArgumentException Thrown if the URL is null.
++     * @throws IllegalArgumentException Thrown if the URL is too long. The
++     *     length restriction is an implementation specific arbitrary value.
++     * @throws IllegalArgumentException Thrown if the hash is not 20 bytes
++     *     long.
++     */
++    default void setResourcePack(@NotNull String url, byte @Nullable [] hash, net.kyori.adventure.text.@Nullable Component prompt) {
++        this.setResourcePack(url, hash, prompt, false);
++    }
++    // Paper end
++
+     /**
+      * Request that the player's client download and switch resource packs.
+      * <p>
+@@ -0,0 +0,0 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM
+      */
+     public void setResourcePack(@NotNull String url, @Nullable byte[] hash, @Nullable String prompt, boolean force);
+ 
++    // Paper end
++    /**
++     * Request that the player's client download and switch resource packs.
++     * <p>
++     * The player's client will download the new resource pack asynchronously
++     * in the background, and will automatically switch to it once the
++     * download is complete. If the client has downloaded and cached a
++     * resource pack with the same hash in the past it will not download but
++     * directly apply the cached pack. If the hash is null and the client has
++     * downloaded and cached the same resource pack in the past, it will
++     * perform a file size check against the response content to determine if
++     * the resource pack has changed and needs to be downloaded again. When
++     * this request is sent for the very first time from a given server, the
++     * client will first display a confirmation GUI to the player before
++     * proceeding with the download.
++     * <p>
++     * Notes:
++     * <ul>
++     * <li>Players can disable server resources on their client, in which
++     *     case this method will have no affect on them. Use the
++     *     {@link PlayerResourcePackStatusEvent} to figure out whether or not
++     *     the player loaded the pack!
++     * <li>There is no concept of resetting resource packs back to default
++     *     within Minecraft, so players will have to relog to do so or you
++     *     have to send an empty pack.
++     * <li>The request is sent with empty string as the hash when the hash is
++     *     not provided. This might result in newer versions not loading the
++     *     pack correctly.
++     * </ul>
++     *
++     * @param url The URL from which the client will download the resource
++     *     pack. The string must contain only US-ASCII characters and should
++     *     be encoded as per RFC 1738.
++     * @param hash The sha1 hash sum of the resource pack file which is used
++     *     to apply a cached version of the pack directly without downloading
++     *     if it is available. Hast to be 20 bytes long!
++     * @param prompt The optional custom prompt message to be shown to client.
++     * @param force If true, the client will be disconnected from the server
++     *     when it declines to use the resource pack.
++     * @throws IllegalArgumentException Thrown if the URL is null.
++     * @throws IllegalArgumentException Thrown if the URL is too long. The
++     *     length restriction is an implementation specific arbitrary value.
++     * @throws IllegalArgumentException Thrown if the hash is not 20 bytes
++     *     long.
++     */
++    public void setResourcePack(@NotNull String url, byte @Nullable [] hash, net.kyori.adventure.text.@Nullable Component prompt, boolean force);
++    // Paper end
++
+     /**
+      * Gets the Scoreboard displayed to this player
+      *
 @@ -0,0 +0,0 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM
       *
       * @param title Title text
@@ -4122,3 +4230,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
          "Lorg/jetbrains/annotations/Nullable;",
          "Lorg/jetbrains/annotations/NotNull;",
          "Lorg/jetbrains/annotations/Contract;",
+@@ -0,0 +0,0 @@ public class AnnotationTest {
+                         if (method.invisibleTypeAnnotations != null) {
+                             for (final org.objectweb.asm.tree.TypeAnnotationNode invisibleTypeAnnotation : method.invisibleTypeAnnotations) {
+                                 final org.objectweb.asm.TypeReference ref = new org.objectweb.asm.TypeReference(invisibleTypeAnnotation.typeRef);
+-                                if (ref.getSort() == org.objectweb.asm.TypeReference.METHOD_FORMAL_PARAMETER && ref.getTypeParameterIndex() == i && java.util.Arrays.binarySearch(ACCEPTED_ANNOTATIONS, invisibleTypeAnnotation.desc) >= 0) {
++                                if (ref.getSort() == org.objectweb.asm.TypeReference.METHOD_FORMAL_PARAMETER && ref.getTypeParameterIndex() == i && org.apache.commons.lang.ArrayUtils.contains(ACCEPTED_ANNOTATIONS, invisibleTypeAnnotation.desc)) {
+                                     continue dancing;
+                                 }
+                             }
diff --git a/patches/server/Adventure.patch b/patches/server/Adventure.patch
index bf5280f2ba..beb1d4ed54 100644
--- a/patches/server/Adventure.patch
+++ b/patches/server/Adventure.patch
@@ -43,27 +43,27 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import net.minecraft.network.chat.Style;
 +import net.minecraft.util.FormattedCharSequence;
 +import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
-+import org.checkerframework.checker.nullness.qual.Nullable;
++import org.jetbrains.annotations.Nullable;
 +
 +public final class AdventureComponent implements net.minecraft.network.chat.Component {
-+    final Component wrapped;
-+    private net.minecraft.network.chat.@MonotonicNonNull Component converted;
++    final Component adventure;
++    private net.minecraft.network.chat.@MonotonicNonNull Component vanilla;
 +
-+    public AdventureComponent(final Component wrapped) {
-+        this.wrapped = wrapped;
++    public AdventureComponent(final Component adventure) {
++        this.adventure = adventure;
 +    }
 +
 +    public net.minecraft.network.chat.Component deepConverted() {
-+        net.minecraft.network.chat.Component converted = this.converted;
-+        if (converted == null) {
-+            converted = PaperAdventure.WRAPPER_AWARE_SERIALIZER.serialize(this.wrapped);
-+            this.converted = converted;
++        net.minecraft.network.chat.Component vanilla = this.vanilla;
++        if (vanilla == null) {
++            vanilla = PaperAdventure.WRAPPER_AWARE_SERIALIZER.serialize(this.adventure);
++            this.vanilla = vanilla;
 +        }
-+        return converted;
++        return vanilla;
 +    }
 +
 +    public net.minecraft.network.chat.@Nullable Component deepConvertedIfPresent() {
-+        return this.converted;
++        return this.vanilla;
 +    }
 +
 +    @Override
@@ -73,8 +73,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +
 +    @Override
 +    public String getContents() {
-+        if (this.wrapped instanceof TextComponent) {
-+            return ((TextComponent) this.wrapped).content();
++        if (this.adventure instanceof TextComponent) {
++            return ((TextComponent) this.adventure).content();
 +        } else {
 +            return this.deepConverted().getContents();
 +        }
@@ -82,7 +82,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +
 +    @Override
 +    public String getString() {
-+        return PaperAdventure.PLAIN.serialize(this.wrapped);
++        return PaperAdventure.PLAIN.serialize(this.adventure);
 +    }
 +
 +    @Override
@@ -108,7 +108,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    public static class Serializer implements JsonSerializer<AdventureComponent> {
 +        @Override
 +        public JsonElement serialize(final AdventureComponent src, final Type type, final JsonSerializationContext context) {
-+            return PaperAdventure.GSON.serializer().toJsonTree(src.wrapped, Component.class);
++            return PaperAdventure.GSON.serializer().toJsonTree(src.adventure, Component.class);
 +        }
 +    }
 +}
@@ -527,7 +527,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import net.kyori.adventure.text.format.TextColor;
 +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
 +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
-+import net.kyori.adventure.text.serializer.plain.PlainComponentSerializer;
++import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
 +import net.kyori.adventure.translation.GlobalTranslator;
 +import net.kyori.adventure.translation.TranslationRegistry;
 +import net.kyori.adventure.translation.Translator;
@@ -544,8 +544,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import net.minecraft.world.item.ItemStack;
 +import net.minecraft.world.item.WrittenBookItem;
 +import org.bukkit.ChatColor;
-+import org.checkerframework.checker.nullness.qual.NonNull;
-+import org.checkerframework.checker.nullness.qual.Nullable;
++import org.jetbrains.annotations.NotNull;
++import org.jetbrains.annotations.Nullable;
 +
 +public final class PaperAdventure {
 +    public static final AttributeKey<Locale> LOCALE_ATTRIBUTE = AttributeKey.valueOf("adventure:locale");
@@ -560,7 +560,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +                    }
 +                }
 +            }
-+            final @NonNull String translated = Language.getInstance().getOrDefault(translatable.key());
++            final @NotNull String translated = Language.getInstance().getOrDefault(translatable.key());
 +
 +            final Matcher matcher = LOCALIZATION_PATTERN.matcher(translated);
 +            final List<Component> args = translatable.args();
@@ -599,7 +599,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        })
 +        .build();
 +    public static final LegacyComponentSerializer LEGACY_SECTION_UXRC = LegacyComponentSerializer.builder().flattener(FLATTENER).hexColors().useUnusualXRepeatedCharacterHexFormat().build();
-+    public static final PlainComponentSerializer PLAIN = PlainComponentSerializer.builder().flattener(FLATTENER).build();
++    public static final PlainTextComponentSerializer PLAIN = PlainTextComponentSerializer.builder().flattener(FLATTENER).build();
 +    public static final GsonComponentSerializer GSON = GsonComponentSerializer.builder()
 +        .legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.INSTANCE)
 +        .build();
@@ -609,7 +609,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        .build();
 +    private static final Codec<CompoundTag, String, IOException, IOException> NBT_CODEC = new Codec<CompoundTag, String, IOException, IOException>() {
 +        @Override
-+        public @NonNull CompoundTag decode(final @NonNull String encoded) throws IOException {
++        public @NotNull CompoundTag decode(final @NotNull String encoded) throws IOException {
 +            try {
 +                return TagParser.parseTag(encoded);
 +            } catch (final CommandSyntaxException e) {
@@ -618,7 +618,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        }
 +
 +        @Override
-+        public @NonNull String encode(final @NonNull CompoundTag decoded) {
++        public @NotNull String encode(final @NotNull CompoundTag decoded) {
 +            return decoded.toString();
 +        }
 +    };
@@ -671,6 +671,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    }
 +
 +    public static net.minecraft.network.chat.Component asVanilla(final Component component) {
++        if (component == null) return null;
 +        if (true) return new AdventureComponent(component);
 +        return net.minecraft.network.chat.Component.Serializer.fromJson(GSON.serializer().toJsonTree(component));
 +    }
@@ -697,7 +698,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +
 +    public static String asJsonString(final net.minecraft.network.chat.Component component, final Locale locale) {
 +        if (component instanceof AdventureComponent) {
-+            return asJsonString(((AdventureComponent) component).wrapped, locale);
++            return asJsonString(((AdventureComponent) component).adventure, locale);
 +        }
 +        return net.minecraft.network.chat.Component.Serializer.toJson(component);
 +    }
@@ -722,71 +723,47 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    // BossBar
 +
 +    public static BossEvent.BossBarColor asVanilla(final BossBar.Color color) {
-+        if (color == BossBar.Color.PINK) {
-+            return BossEvent.BossBarColor.PINK;
-+        } else if (color == BossBar.Color.BLUE) {
-+            return BossEvent.BossBarColor.BLUE;
-+        } else if (color == BossBar.Color.RED) {
-+            return BossEvent.BossBarColor.RED;
-+        } else if (color == BossBar.Color.GREEN) {
-+            return BossEvent.BossBarColor.GREEN;
-+        } else if (color == BossBar.Color.YELLOW) {
-+            return BossEvent.BossBarColor.YELLOW;
-+        } else if (color == BossBar.Color.PURPLE) {
-+            return BossEvent.BossBarColor.PURPLE;
-+        } else if (color == BossBar.Color.WHITE) {
-+            return BossEvent.BossBarColor.WHITE;
-+        }
-+        throw new IllegalArgumentException(color.name());
++        return switch (color) {
++            case PINK -> BossEvent.BossBarColor.PINK;
++            case BLUE -> BossEvent.BossBarColor.BLUE;
++            case RED -> BossEvent.BossBarColor.RED;
++            case GREEN -> BossEvent.BossBarColor.GREEN;
++            case YELLOW -> BossEvent.BossBarColor.YELLOW;
++            case PURPLE -> BossEvent.BossBarColor.PURPLE;
++            case WHITE -> BossEvent.BossBarColor.WHITE;
++        };
 +    }
 +
 +    public static BossBar.Color asAdventure(final BossEvent.BossBarColor color) {
-+        if(color == BossEvent.BossBarColor.PINK) {
-+            return BossBar.Color.PINK;
-+        } else if(color == BossEvent.BossBarColor.BLUE) {
-+            return BossBar.Color.BLUE;
-+        } else if(color == BossEvent.BossBarColor.RED) {
-+            return BossBar.Color.RED;
-+        } else if(color == BossEvent.BossBarColor.GREEN) {
-+            return BossBar.Color.GREEN;
-+        } else if(color == BossEvent.BossBarColor.YELLOW) {
-+            return BossBar.Color.YELLOW;
-+        } else if(color == BossEvent.BossBarColor.PURPLE) {
-+            return BossBar.Color.PURPLE;
-+        } else if(color == BossEvent.BossBarColor.WHITE) {
-+            return BossBar.Color.WHITE;
-+        }
-+        throw new IllegalArgumentException(color.name());
++        return switch (color) {
++            case PINK -> BossBar.Color.PINK;
++            case BLUE -> BossBar.Color.BLUE;
++            case RED -> BossBar.Color.RED;
++            case GREEN -> BossBar.Color.GREEN;
++            case YELLOW -> BossBar.Color.YELLOW;
++            case PURPLE -> BossBar.Color.PURPLE;
++            case WHITE -> BossBar.Color.WHITE;
++        };
 +    }
 +
 +    public static BossEvent.BossBarOverlay asVanilla(final BossBar.Overlay overlay) {
-+        if (overlay == BossBar.Overlay.PROGRESS) {
-+            return BossEvent.BossBarOverlay.PROGRESS;
-+        } else if (overlay == BossBar.Overlay.NOTCHED_6) {
-+            return BossEvent.BossBarOverlay.NOTCHED_6;
-+        } else if (overlay == BossBar.Overlay.NOTCHED_10) {
-+            return BossEvent.BossBarOverlay.NOTCHED_10;
-+        } else if (overlay == BossBar.Overlay.NOTCHED_12) {
-+            return BossEvent.BossBarOverlay.NOTCHED_12;
-+        } else if (overlay == BossBar.Overlay.NOTCHED_20) {
-+            return BossEvent.BossBarOverlay.NOTCHED_20;
-+        }
-+        throw new IllegalArgumentException(overlay.name());
++        return switch (overlay) {
++            case PROGRESS -> BossEvent.BossBarOverlay.PROGRESS;
++            case NOTCHED_6 -> BossEvent.BossBarOverlay.NOTCHED_6;
++            case NOTCHED_10 -> BossEvent.BossBarOverlay.NOTCHED_10;
++            case NOTCHED_12 -> BossEvent.BossBarOverlay.NOTCHED_12;
++            case NOTCHED_20 -> BossEvent.BossBarOverlay.NOTCHED_20;
++        };
 +    }
 +
 +    public static BossBar.Overlay asAdventure(final BossEvent.BossBarOverlay overlay) {
-+        if (overlay == BossEvent.BossBarOverlay.PROGRESS) {
-+            return BossBar.Overlay.PROGRESS;
-+        } else if (overlay == BossEvent.BossBarOverlay.NOTCHED_6) {
-+            return BossBar.Overlay.NOTCHED_6;
-+        } else if (overlay == BossEvent.BossBarOverlay.NOTCHED_10) {
-+            return BossBar.Overlay.NOTCHED_10;
-+        } else if (overlay == BossEvent.BossBarOverlay.NOTCHED_12) {
-+            return BossBar.Overlay.NOTCHED_12;
-+        } else if (overlay == BossEvent.BossBarOverlay.NOTCHED_20) {
-+            return BossBar.Overlay.NOTCHED_20;
-+        }
-+        throw new IllegalArgumentException(overlay.name());
++        return switch (overlay) {
++            case PROGRESS -> BossBar.Overlay.PROGRESS;
++            case NOTCHED_6 -> BossBar.Overlay.NOTCHED_6;
++            case NOTCHED_10 -> BossBar.Overlay.NOTCHED_10;
++            case NOTCHED_12 -> BossBar.Overlay.NOTCHED_12;
++            case NOTCHED_20 -> BossBar.Overlay.NOTCHED_20;
++        };
 +    }
 +
 +    public static void setFlag(final BossBar bar, final BossBar.Flag flag, final boolean value) {
@@ -876,14 +853,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +
 +    // Colors
 +
-+    public static @NonNull TextColor asAdventure(ChatFormatting minecraftColor) {
-+        if (minecraftColor.getColor() == null) {
++    public static @NotNull TextColor asAdventure(final ChatFormatting formatting) {
++        final Integer color = formatting.getColor();
++        if (color == null) {
 +            throw new IllegalArgumentException("Not a valid color");
 +        }
-+        return TextColor.color(minecraftColor.getColor());
++        return TextColor.color(color);
 +    }
 +
-+    public static @Nullable ChatFormatting asVanilla(TextColor color) {
++    public static @Nullable ChatFormatting asVanilla(final TextColor color) {
 +        return ChatFormatting.getByHexValue(color.value());
 +    }
 +}
@@ -952,7 +930,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    @Override
 +    public Component deserialize(final net.minecraft.network.chat.Component input) {
 +        if (input instanceof AdventureComponent) {
-+            return ((AdventureComponent) input).wrapped;
++            return ((AdventureComponent) input).adventure;
 +        }
 +        return PaperAdventure.GSON.serializer().fromJson(net.minecraft.network.chat.Component.Serializer.toJsonTree(input), Component.class);
 +    }
@@ -2534,6 +2512,46 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
  
      @Override
 @@ -0,0 +0,0 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
+ 
+     @Override
+     public void setResourcePack(String url) {
+-        this.setResourcePack(url, null);
++        this.setResourcePack(url, (byte[]) null);
+     }
+ 
+     @Override
+@@ -0,0 +0,0 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
+ 
+     @Override
+     public void setResourcePack(String url, byte[] hash, boolean force) {
+-        this.setResourcePack(url, hash, null, force);
++        this.setResourcePack(url, hash, (String) null, force);
+     }
+ 
+     @Override
+@@ -0,0 +0,0 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
+         }
+     }
+ 
++    // Paper start
++    @Override
++    public void setResourcePack(String url, byte[] hashBytes, net.kyori.adventure.text.Component prompt, boolean force) {
++        Validate.notNull(url, "Resource pack URL cannot be null");
++        final String hash;
++        if (hashBytes != null) {
++            Validate.isTrue(hashBytes.length == 20, "Resource pack hash should be 20 bytes long but was " + hashBytes.length);
++            hash = BaseEncoding.base16().lowerCase().encode(hashBytes);
++        } else {
++            hash = "";
++        }
++        this.getHandle().sendTexturePack(url, hash, force, io.papermc.paper.adventure.PaperAdventure.asVanilla(prompt));
++    }
++    // Paper end
++
+     public void addChannel(String channel) {
+         Preconditions.checkState(this.channels.size() < 128, "Cannot register channel '%s'. Too many channels registered!", channel);
+         channel = StandardMessenger.validateAndCorrectChannel(channel);
+@@ -0,0 +0,0 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
          return (this.getHandle().clientViewDistance == null) ? Bukkit.getViewDistance() : this.getHandle().clientViewDistance;
      }
  
@@ -3529,7 +3547,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    }
 +
 +    @Override
-+    public net.kyori.adventure.text.serializer.plain.PlainComponentSerializer plainComponentSerializer() {
++    public net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer plainComponentSerializer() {
 +        return io.papermc.paper.adventure.PaperAdventure.PLAIN;
 +    }
 +
diff --git a/patches/server/Complete-resource-pack-API.patch b/patches/server/Complete-resource-pack-API.patch
index 2261bab9f1..0d986f72d3 100644
--- a/patches/server/Complete-resource-pack-API.patch
+++ b/patches/server/Complete-resource-pack-API.patch
@@ -46,15 +46,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
      public CraftPlayer(CraftServer server, ServerPlayer entity) {
          super(server, entity);
 @@ -0,0 +0,0 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
- 
-     @Override
-     public void setResourcePack(String url) {
--        this.setResourcePack(url, null);
-+        this.setResourcePack(url, (byte[]) null);
-     }
- 
-     @Override
-@@ -0,0 +0,0 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
      public boolean getAffectsSpawning() {
          return this.getHandle().affectsSpawning;
      }
diff --git a/patches/server/Flag-to-disable-the-channel-limit.patch b/patches/server/Flag-to-disable-the-channel-limit.patch
index e73ce09e34..28a4e04765 100644
--- a/patches/server/Flag-to-disable-the-channel-limit.patch
+++ b/patches/server/Flag-to-disable-the-channel-limit.patch
@@ -21,7 +21,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
  
      public CraftPlayer(CraftServer server, ServerPlayer entity) {
 @@ -0,0 +0,0 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
-     }
+     // Paper end
  
      public void addChannel(String channel) {
 -        Preconditions.checkState(this.channels.size() < 128, "Cannot register channel '%s'. Too many channels registered!", channel);