diff --git a/patches/api/0005-Adventure.patch b/patches/api/0005-Adventure.patch
index 560a56fd86..30c61b03b0 100644
--- a/patches/api/0005-Adventure.patch
+++ b/patches/api/0005-Adventure.patch
@@ -77,16 +77,15 @@ index 79bf95d5a19046b142d0162dd6b739b7f0f52e59..84432bf9dd99332098f952ea777ee97d
doLast {
diff --git a/src/main/java/io/papermc/paper/chat/ChatRenderer.java b/src/main/java/io/papermc/paper/chat/ChatRenderer.java
new file mode 100644
-index 0000000000000000000000000000000000000000..2fc47afbb233e6e5727a7b672f61b88ad3bab097
+index 0000000000000000000000000000000000000000..ffe0a921cc1ebbb95104f22b57e0e3af85e287a6
--- /dev/null
+++ b/src/main/java/io/papermc/paper/chat/ChatRenderer.java
-@@ -0,0 +1,78 @@
+@@ -0,0 +1,71 @@
+package io.papermc.paper.chat;
+
+import net.kyori.adventure.audience.Audience;
+import net.kyori.adventure.text.Component;
+import org.bukkit.entity.Player;
-+import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
@@ -115,7 +114,11 @@ index 0000000000000000000000000000000000000000..2fc47afbb233e6e5727a7b672f61b88a
+ */
+ @NotNull
+ static ChatRenderer defaultRenderer() {
-+ return viewerUnaware((source, sourceDisplayName, message) -> Component.translatable("chat.type.text", sourceDisplayName, message));
++ return new ViewerUnawareImpl.Default((source, sourceDisplayName, message) -> Component.translatable("chat.type.text", sourceDisplayName, message));
++ }
++
++ @ApiStatus.Internal
++ sealed interface Default extends ChatRenderer, ViewerUnaware permits ViewerUnawareImpl.Default {
+ }
+
+ /**
@@ -127,17 +130,7 @@ index 0000000000000000000000000000000000000000..2fc47afbb233e6e5727a7b672f61b88a
+ */
+ @NotNull
+ static ChatRenderer viewerUnaware(final @NotNull ViewerUnaware renderer) {
-+ return new ChatRenderer() {
-+ private @MonotonicNonNull Component message;
-+
-+ @Override
-+ public @NotNull Component render(final @NotNull Player source, final @NotNull Component sourceDisplayName, final @NotNull Component message, final @NotNull Audience viewer) {
-+ if (this.message == null) {
-+ this.message = renderer.render(source, sourceDisplayName, message);
-+ }
-+ return this.message;
-+ }
-+ };
++ return new ViewerUnawareImpl(renderer);
+ }
+
+ /**
@@ -159,6 +152,50 @@ index 0000000000000000000000000000000000000000..2fc47afbb233e6e5727a7b672f61b88a
+ Component render(@NotNull Player source, @NotNull Component sourceDisplayName, @NotNull Component message);
+ }
+}
+diff --git a/src/main/java/io/papermc/paper/chat/ViewerUnawareImpl.java b/src/main/java/io/papermc/paper/chat/ViewerUnawareImpl.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..9adeb880f7948f937891d83e256c808b5eb40a27
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/chat/ViewerUnawareImpl.java
+@@ -0,0 +1,38 @@
++package io.papermc.paper.chat;
++
++import net.kyori.adventure.audience.Audience;
++import net.kyori.adventure.text.Component;
++import org.bukkit.entity.Player;
++import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
++import org.jetbrains.annotations.NotNull;
++
++sealed class ViewerUnawareImpl implements ChatRenderer, ChatRenderer.ViewerUnaware permits ViewerUnawareImpl.Default {
++
++ private final ViewerUnaware unaware;
++
++ private @MonotonicNonNull Component message;
++
++ ViewerUnawareImpl(final ViewerUnaware unaware) {
++ this.unaware = unaware;
++ }
++
++ @Override
++ public @NotNull Component render(final @NotNull Player source, final @NotNull Component sourceDisplayName, final @NotNull Component message, final @NotNull Audience viewer) {
++ return this.render(source, sourceDisplayName, message);
++ }
++
++ @Override
++ public @NotNull Component render(final @NotNull Player source, final @NotNull Component sourceDisplayName, final @NotNull Component message) {
++ if (this.message == null) {
++ this.message = this.unaware.render(source, sourceDisplayName, message);
++ }
++ return this.message;
++ }
++
++ static final class Default extends ViewerUnawareImpl implements ChatRenderer.Default {
++
++ Default(final ViewerUnaware unaware) {
++ super(unaware);
++ }
++ }
++}
diff --git a/src/main/java/io/papermc/paper/event/player/AbstractChatEvent.java b/src/main/java/io/papermc/paper/event/player/AbstractChatEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..fa03a5cb2d3e3e0a60d84bacc911d96c454f81da
@@ -277,6 +314,164 @@ index 0000000000000000000000000000000000000000..fa03a5cb2d3e3e0a60d84bacc911d96c
+ this.cancelled = cancelled;
+ }
+}
+diff --git a/src/main/java/io/papermc/paper/event/player/AsyncChatCommandDecorateEvent.java b/src/main/java/io/papermc/paper/event/player/AsyncChatCommandDecorateEvent.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..bd216f7333795fc6bc5bec593f9cc0e3c2c1a27e
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/event/player/AsyncChatCommandDecorateEvent.java
+@@ -0,0 +1,27 @@
++package io.papermc.paper.event.player;
++
++import net.kyori.adventure.text.Component;
++import org.bukkit.entity.Player;
++import org.bukkit.event.HandlerList;
++import org.jetbrains.annotations.ApiStatus;
++import org.jetbrains.annotations.NotNull;
++import org.jetbrains.annotations.Nullable;
++
++@ApiStatus.Experimental
++public class AsyncChatCommandDecorateEvent extends AsyncChatDecorateEvent {
++
++ private static final HandlerList HANDLER_LIST = new HandlerList();
++
++ public AsyncChatCommandDecorateEvent(boolean async, @Nullable Player player, @NotNull Component originalMessage, boolean isPreview, @NotNull Component result) {
++ super(async, player, originalMessage, isPreview, result);
++ }
++
++ @Override
++ public @NotNull HandlerList getHandlers() {
++ return HANDLER_LIST;
++ }
++
++ public static @NotNull HandlerList getHandlerList() {
++ return HANDLER_LIST;
++ }
++}
+diff --git a/src/main/java/io/papermc/paper/event/player/AsyncChatDecorateEvent.java b/src/main/java/io/papermc/paper/event/player/AsyncChatDecorateEvent.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..347122b12ad98115133ef98db69b271ee0cec194
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/event/player/AsyncChatDecorateEvent.java
+@@ -0,0 +1,119 @@
++package io.papermc.paper.event.player;
++
++import net.kyori.adventure.text.Component;
++import org.bukkit.entity.Player;
++import org.bukkit.event.Cancellable;
++import org.bukkit.event.HandlerList;
++import org.bukkit.event.server.ServerEvent;
++import org.jetbrains.annotations.ApiStatus;
++import org.jetbrains.annotations.NotNull;
++import org.jetbrains.annotations.Nullable;
++
++/**
++ * This event is fired when the server decorates a component for chat purposes. It can be called
++ * under the following circumstances:
++ *
++ * - Previewing: If the client requests a preview response, this event is fired to decorate the component
++ * before it is sent back to the client for signing.
++ * - Chat: If the client sends a chat packet without having signed a preview (the client could have previews
++ * disabled or they sent the message too quickly) this event is fired to generated the decorated component. Note
++ * that when this is the case, the message will show up as modified as the decorated component wasn't signed
++ * by the client.
++ *
++ * @see AsyncChatCommandDecorateEvent for the decoration of messages sent via commands
++ */
++@ApiStatus.Experimental
++public class AsyncChatDecorateEvent extends ServerEvent implements Cancellable {
++
++ private static final HandlerList HANDLER_LIST = new HandlerList();
++
++ private final Player player;
++ private final Component originalMessage;
++ private final boolean isPreview;
++ private Component result;
++ private boolean cancelled;
++
++ @ApiStatus.Internal
++ public AsyncChatDecorateEvent(final boolean async, final @Nullable Player player, final @NotNull Component originalMessage, final boolean isPreview, final @NotNull Component result) {
++ super(async);
++ this.player = player;
++ this.originalMessage = originalMessage;
++ this.isPreview = isPreview;
++ this.result = result;
++ }
++
++ /**
++ * Gets the player (if available) associated with this event.
++ *
++ * Certain commands request decorations without a player context
++ * which is why this is possibly null.
++ *
++ * @return the player or null
++ */
++ public @Nullable Player player() {
++ return this.player;
++ }
++
++ /**
++ * Gets the original decoration input
++ *
++ * @return the input
++ */
++ public @NotNull Component originalMessage() {
++ return this.originalMessage;
++ }
++
++ /**
++ * Gets the decoration result. This may already be different from
++ * {@link #originalMessage()} if some other listener to this event
++ * OR the legacy preview event ({@link org.bukkit.event.player.AsyncPlayerChatPreviewEvent}
++ * changed the result.
++ *
++ * @return the result
++ */
++ public @NotNull Component result() {
++ return this.result;
++ }
++
++ /**
++ * Sets the resulting decorated component.
++ *
++ * @param result the result
++ */
++ public void result(@NotNull Component result) {
++ this.result = result;
++ }
++
++ /**
++ * If this decorating is part of a preview request/response.
++ *
++ * @return true if part of previewing
++ */
++ public boolean isPreview() {
++ return this.isPreview;
++ }
++
++ @Override
++ public boolean isCancelled() {
++ return this.cancelled;
++ }
++
++ /**
++ * A cancelled decorating event means that no changes to the result component
++ * will have any effect. The decorated component will be equal to the original
++ * component.
++ */
++ @Override
++ public void setCancelled(boolean cancel) {
++ this.cancelled = cancel;
++ }
++
++ @Override
++ public @NotNull HandlerList getHandlers() {
++ return HANDLER_LIST;
++ }
++
++ public static @NotNull HandlerList getHandlerList() {
++ return HANDLER_LIST;
++ }
++}
diff --git a/src/main/java/io/papermc/paper/event/player/AsyncChatEvent.java b/src/main/java/io/papermc/paper/event/player/AsyncChatEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..0d9e3c23027e3af90cb70e4bb6fb0ac1da35fc4d
diff --git a/patches/server/0008-Adventure.patch b/patches/server/0008-Adventure.patch
index f3571fcee4..6bc95235fe 100644
--- a/patches/server/0008-Adventure.patch
+++ b/patches/server/0008-Adventure.patch
@@ -98,30 +98,187 @@ index 0000000000000000000000000000000000000000..07cd02c6f9df00844b808218be2afd79
+ }
+ }
+}
-diff --git a/src/main/java/io/papermc/paper/adventure/ChatProcessor.java b/src/main/java/io/papermc/paper/adventure/ChatProcessor.java
+diff --git a/src/main/java/io/papermc/paper/adventure/ChatDecorationProcessor.java b/src/main/java/io/papermc/paper/adventure/ChatDecorationProcessor.java
new file mode 100644
-index 0000000000000000000000000000000000000000..3526bc0b6ad590776124966ea907fe2467cbbf5f
+index 0000000000000000000000000000000000000000..87e791801b624859477025df49824637eb347dec
--- /dev/null
-+++ b/src/main/java/io/papermc/paper/adventure/ChatProcessor.java
-@@ -0,0 +1,193 @@
++++ b/src/main/java/io/papermc/paper/adventure/ChatDecorationProcessor.java
+@@ -0,0 +1,141 @@
+package io.papermc.paper.adventure;
+
++import io.papermc.paper.event.player.AsyncChatCommandDecorateEvent;
++import io.papermc.paper.event.player.AsyncChatDecorateEvent;
++import java.util.ArrayList;
++import java.util.List;
++import java.util.concurrent.CompletableFuture;
++import java.util.regex.Pattern;
++import net.kyori.adventure.text.Component;
++import net.kyori.adventure.text.minimessage.MiniMessage;
++import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
++import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
++import net.minecraft.Util;
++import net.minecraft.commands.CommandSourceStack;
++import net.minecraft.network.chat.ChatDecorator;
++import net.minecraft.server.MinecraftServer;
++import net.minecraft.server.level.ServerPlayer;
++import org.bukkit.craftbukkit.entity.CraftPlayer;
++import org.bukkit.craftbukkit.util.LazyPlayerSet;
++import org.bukkit.event.Event;
++import org.bukkit.event.player.AsyncPlayerChatPreviewEvent;
++import org.checkerframework.checker.nullness.qual.NonNull;
++import org.checkerframework.checker.nullness.qual.Nullable;
++import org.checkerframework.framework.qual.DefaultQualifier;
++
++import static io.papermc.paper.adventure.ChatProcessor.DEFAULT_LEGACY_FORMAT;
++import static io.papermc.paper.adventure.ChatProcessor.canYouHearMe;
++import static io.papermc.paper.adventure.ChatProcessor.displayName;
++import static net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection;
++
++@DefaultQualifier(NonNull.class)
++public final class ChatDecorationProcessor {
++
++ private static final String DISPLAY_NAME_TAG = "---paper_dn---";
++ private static final Pattern DISPLAY_NAME_PATTERN = Pattern.compile("%(1\\$)?s");
++ private static final String CONTENT_TAG = "---paper_content---";
++ private static final Pattern CONTENT_PATTERN = Pattern.compile("%(2\\$)?s");
++
++ final MinecraftServer server;
++ final @Nullable ServerPlayer player;
++ final @Nullable CommandSourceStack commandSourceStack;
++ final Component originalMessage;
++ final boolean isPreview;
++
++ public ChatDecorationProcessor(final MinecraftServer server, final @Nullable ServerPlayer player, final @Nullable CommandSourceStack commandSourceStack, final net.minecraft.network.chat.Component originalMessage, final boolean isPreview) {
++ this.server = server;
++ this.player = player;
++ this.commandSourceStack = commandSourceStack;
++ this.originalMessage = PaperAdventure.asAdventure(originalMessage);
++ this.isPreview = isPreview;
++ }
++
++ public CompletableFuture process() {
++ return CompletableFuture.supplyAsync(() -> {
++ ChatDecorator.Result result = new ChatDecorator.ModernResult(this.originalMessage, true, false);
++ if (canYouHearMe(AsyncPlayerChatPreviewEvent.getHandlerList())) {
++ result = this.processLegacy(result);
++ }
++ return this.processModern(result);
++ }, this.server.chatExecutor);
++ }
++
++ private ChatDecorator.Result processLegacy(final ChatDecorator.Result input) {
++ if (this.player != null) {
++ final CraftPlayer player = this.player.getBukkitEntity();
++ final String originalMessage = legacySection().serialize(this.originalMessage);
++ final AsyncPlayerChatPreviewEvent event = new AsyncPlayerChatPreviewEvent(true, player, originalMessage, new LazyPlayerSet(this.server));
++ this.post(event);
++
++ final boolean isDefaultFormat = DEFAULT_LEGACY_FORMAT.equals(event.getFormat());
++ if (event.isCancelled() || (isDefaultFormat && originalMessage.equals(event.getMessage()))) {
++ return input;
++ } else {
++ final Component message = legacySection().deserialize(event.getMessage());
++ final Component component = isDefaultFormat ? message : legacyFormat(event.getFormat(), ((CraftPlayer) event.getPlayer()), legacySection().deserialize(event.getMessage()));
++ return legacy(component, event.getFormat(), new ChatDecorator.MessagePair(message, event.getMessage()), isDefaultFormat);
++ }
++ }
++ return input;
++ }
++
++ private ChatDecorator.Result processModern(final ChatDecorator.Result input) {
++ final @Nullable CraftPlayer player = Util.mapNullable(this.player, ServerPlayer::getBukkitEntity);
++
++ final Component initialResult = input.message().component();
++ final AsyncChatDecorateEvent event;
++ if (this.commandSourceStack != null) {
++ // TODO more command decorate context
++ event = new AsyncChatCommandDecorateEvent(true, player, this.originalMessage, this.isPreview, initialResult);
++ } else {
++ event = new AsyncChatDecorateEvent(true, player, this.originalMessage, this.isPreview, initialResult);
++ }
++ this.post(event);
++ if (!event.isCancelled() && !event.result().equals(initialResult)) {
++ if (input instanceof ChatDecorator.LegacyResult legacyResult) {
++ if (legacyResult.hasNoFormatting()) {
++ /*
++ The MessagePair in the decoration result may be different at this point. This is because the legacy
++ decoration system requires the same modifications be made to the message, so we can't have the initial
++ message value for the legacy chat events be changed by the modern decorate event.
++ */
++ return noFormatting(event.result(), legacyResult.format(), legacyResult.message().legacyMessage());
++ } else {
++ final Component formatted = legacyFormat(legacyResult.format(), player, event.result());
++ return withFormatting(formatted, legacyResult.format(), event.result(), legacyResult.message().legacyMessage());
++ }
++ } else {
++ return new ChatDecorator.ModernResult(event.result(), true, false);
++ }
++ }
++ return input;
++ }
++
++ private void post(final Event event) {
++ this.server.server.getPluginManager().callEvent(event);
++ }
++
++ private static Component legacyFormat(final String format, final @Nullable CraftPlayer player, final Component message) {
++ final List args = new ArrayList<>(player != null ? 2 : 1);
++ if (player != null) {
++ args.add(Placeholder.component(DISPLAY_NAME_TAG, displayName(player)));
++ }
++ args.add(Placeholder.component(CONTENT_TAG, message));
++ String miniMsg = MiniMessage.miniMessage().serialize(legacySection().deserialize(format));
++ miniMsg = DISPLAY_NAME_PATTERN.matcher(miniMsg).replaceFirst("<" + DISPLAY_NAME_TAG + ">");
++ miniMsg = CONTENT_PATTERN.matcher(miniMsg).replaceFirst("<" + CONTENT_TAG + ">");
++ return MiniMessage.miniMessage().deserialize(miniMsg, TagResolver.resolver(args));
++ }
++
++ public static ChatDecorator.LegacyResult legacy(final Component maybeFormatted, final String format, final ChatDecorator.MessagePair message, final boolean hasNoFormatting) {
++ return new ChatDecorator.LegacyResult(maybeFormatted, format, message, hasNoFormatting, false);
++ }
++
++ public static ChatDecorator.LegacyResult noFormatting(final Component component, final String format, final String legacyMessage) {
++ return new ChatDecorator.LegacyResult(component, format, new ChatDecorator.MessagePair(component, legacyMessage), true, true);
++ }
++
++ public static ChatDecorator.LegacyResult withFormatting(final Component formatted, final String format, final Component message, final String legacyMessage) {
++ return new ChatDecorator.LegacyResult(formatted, format, new ChatDecorator.MessagePair(message, legacyMessage), false, true);
++ }
++}
+diff --git a/src/main/java/io/papermc/paper/adventure/ChatProcessor.java b/src/main/java/io/papermc/paper/adventure/ChatProcessor.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..f8586ae7fe41cce772745bab2a1482c424d0b28f
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/adventure/ChatProcessor.java
+@@ -0,0 +1,376 @@
++package io.papermc.paper.adventure;
++
++import com.google.common.base.Suppliers;
+import io.papermc.paper.chat.ChatRenderer;
+import io.papermc.paper.event.player.AbstractChatEvent;
+import io.papermc.paper.event.player.AsyncChatEvent;
+import io.papermc.paper.event.player.ChatEvent;
++import java.util.BitSet;
++import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
-+import java.util.regex.Pattern;
++import java.util.function.Function;
++import java.util.function.Supplier;
+import net.kyori.adventure.audience.Audience;
+import net.kyori.adventure.audience.MessageType;
+import net.kyori.adventure.text.Component;
-+import net.kyori.adventure.text.TextReplacementConfig;
-+import net.kyori.adventure.text.event.ClickEvent;
-+import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
++import net.minecraft.Util;
++import net.minecraft.network.chat.ChatDecorator;
++import net.minecraft.network.chat.ChatMessageContent;
++import net.minecraft.network.chat.ChatType;
++import net.minecraft.network.chat.OutgoingPlayerChatMessage;
++import net.minecraft.network.chat.PlayerChatMessage;
++import net.minecraft.resources.ResourceKey;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.level.ServerPlayer;
++import org.bukkit.command.CommandSender;
++import org.bukkit.command.ConsoleCommandSender;
+import org.bukkit.craftbukkit.entity.CraftPlayer;
+import org.bukkit.craftbukkit.util.LazyPlayerSet;
+import org.bukkit.craftbukkit.util.Waitable;
@@ -130,35 +287,54 @@ index 0000000000000000000000000000000000000000..3526bc0b6ad590776124966ea907fe24
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.AsyncPlayerChatEvent;
+import org.bukkit.event.player.PlayerChatEvent;
++import org.checkerframework.checker.nullness.qual.NonNull;
++import org.checkerframework.checker.nullness.qual.Nullable;
++import org.checkerframework.framework.qual.DefaultQualifier;
+
++import static net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection;
++
++@DefaultQualifier(NonNull.class)
+public final class ChatProcessor {
-+ // <-- copied from adventure-text-serializer-legacy
-+ private static final Pattern DEFAULT_URL_PATTERN = Pattern.compile("(?:(https?)://)?([-\\w_.]+\\.\\w{2,})(/\\S*)?");
-+ private static final Pattern URL_SCHEME_PATTERN = Pattern.compile("^[a-z][a-z0-9+\\-.]*:");
-+ private static final TextReplacementConfig URL_REPLACEMENT_CONFIG = TextReplacementConfig.builder()
-+ .match(DEFAULT_URL_PATTERN)
-+ .replacement(url -> {
-+ String clickUrl = url.content();
-+ if (!URL_SCHEME_PATTERN.matcher(clickUrl).find()) {
-+ clickUrl = "http://" + clickUrl;
-+ }
-+ return url.clickEvent(ClickEvent.openUrl(clickUrl));
-+ })
-+ .build();
-+ // copied from adventure-text-serializer-legacy -->
-+ private static final String DEFAULT_LEGACY_FORMAT = "<%1$s> %2$s"; // copied from PlayerChatEvent/AsyncPlayerChatEvent
++ static final String DEFAULT_LEGACY_FORMAT = "<%1$s> %2$s"; // copied from PlayerChatEvent/AsyncPlayerChatEvent
+ final MinecraftServer server;
+ final ServerPlayer player;
-+ final String message;
++ final PlayerChatMessage message;
+ final boolean async;
-+ final Component originalMessage;
++ final String craftbukkit$originalMessage;
++ final Component paper$originalMessage;
++ final OutgoingPlayerChatMessage outgoing;
+
-+ public ChatProcessor(final MinecraftServer server, final ServerPlayer player, final String message, final boolean async) {
++ static final int MESSAGE_CHANGED = 1;
++ static final int FORMAT_CHANGED = 2;
++ static final int SENDER_CHANGED = 3; // Not used
++ // static final int FORCE_PREVIEW_USE = 4; // TODO (future, maybe?)
++ private final BitSet flags = new BitSet(3);
++
++ public ChatProcessor(final MinecraftServer server, final ServerPlayer player, final PlayerChatMessage message, final boolean async) {
+ this.server = server;
+ this.player = player;
++ /*
++ CraftBukkit's preview/decoration system relies on both the "decorate" and chat event making the same modifications. If
++ there is unsigned content in the legacyMessage, that is because the player sent the legacyMessage without it being
++ previewed (probably by sending it too quickly). We can just ignore that because the same changes will
++ happen in the chat event.
++
++ If unsigned content is present, it will be the same as `this.legacyMessage.signedContent().previewResult().component()`.
++ */
+ this.message = message;
+ this.async = async;
-+ this.originalMessage = Component.text(message);
++ if (this.message.signedContent().decorationResult().modernized()) {
++ this.craftbukkit$originalMessage = this.message.signedContent().decorationResult().message().legacyMessage();
++ } else {
++ this.craftbukkit$originalMessage = message.signedContent().plain();
++ }
++ /*
++ this.paper$originalMessage is the input to paper's chat events. This should be the decorated message component.
++ Even if the legacy preview event modified the format, and the client signed the formatted message, this should
++ still just be the message component.
++ */
++ this.paper$originalMessage = this.message.signedContent().decorationResult().message().component();
++ this.outgoing = OutgoingPlayerChatMessage.create(this.message);
+ }
+
+ @SuppressWarnings("deprecated")
@@ -167,7 +343,7 @@ index 0000000000000000000000000000000000000000..3526bc0b6ad590776124966ea907fe24
+ final boolean listenersOnSyncEvent = canYouHearMe(PlayerChatEvent.getHandlerList());
+ if (listenersOnAsyncEvent || listenersOnSyncEvent) {
+ final CraftPlayer player = this.player.getBukkitEntity();
-+ final AsyncPlayerChatEvent ae = new AsyncPlayerChatEvent(this.async, player, this.message, new LazyPlayerSet(this.server));
++ final AsyncPlayerChatEvent ae = new AsyncPlayerChatEvent(this.async, player, this.craftbukkit$originalMessage, new LazyPlayerSet(this.server));
+ this.post(ae);
+ if (listenersOnSyncEvent) {
+ final PlayerChatEvent se = new PlayerChatEvent(player, ae.getMessage(), ae.getFormat(), ae.getRecipients());
@@ -179,33 +355,73 @@ index 0000000000000000000000000000000000000000..3526bc0b6ad590776124966ea907fe24
+ return null;
+ }
+ });
++ this.readLegacyModifications(se.getMessage(), se.getFormat(), se.getPlayer());
+ this.processModern(
-+ legacyRenderer(se.getFormat()),
++ this.modernRenderer(se.getFormat()),
+ this.viewersFromLegacy(se.getRecipients()),
-+ LegacyComponentSerializer.legacySection().deserialize(se.getMessage()),
++ this.modernMessage(se.getMessage()),
++ se.getPlayer(),
+ se.isCancelled()
+ );
+ } else {
++ this.readLegacyModifications(ae.getMessage(), ae.getFormat(), ae.getPlayer());
+ this.processModern(
-+ legacyRenderer(ae.getFormat()),
++ this.modernRenderer(ae.getFormat()),
+ this.viewersFromLegacy(ae.getRecipients()),
-+ LegacyComponentSerializer.legacySection().deserialize(ae.getMessage()),
++ this.modernMessage(ae.getMessage()),
++ ae.getPlayer(),
+ ae.isCancelled()
+ );
+ }
+ } else {
+ this.processModern(
-+ ChatRenderer.defaultRenderer(),
++ defaultRenderer(),
+ new LazyChatAudienceSet(this.server),
-+ Component.text(this.message).replaceText(URL_REPLACEMENT_CONFIG),
++ this.paper$originalMessage,
++ this.player.getBukkitEntity(),
+ false
+ );
+ }
+ }
+
-+ private void processModern(final ChatRenderer renderer, final Set viewers, final Component message, final boolean cancelled) {
-+ final CraftPlayer player = this.player.getBukkitEntity();
-+ final AsyncChatEvent ae = new AsyncChatEvent(this.async, player, viewers, renderer, message, this.originalMessage);
++ private ChatRenderer modernRenderer(final String format) {
++ if (this.flags.get(FORMAT_CHANGED)) {
++ return legacyRenderer(format);
++ } else if (this.message.signedContent().decorationResult() instanceof ChatDecorator.LegacyResult legacyResult) {
++ return legacyRenderer(legacyResult.format());
++ } else {
++ return defaultRenderer();
++ }
++ }
++
++ private Component modernMessage(final String legacyMessage) {
++ if (this.flags.get(MESSAGE_CHANGED)) {
++ return legacySection().deserialize(legacyMessage);
++ } else if (this.message.unsignedContent().isEmpty() && this.message.signedContent().decorationResult() instanceof ChatDecorator.LegacyResult legacyResult) {
++ return legacyResult.message().component();
++ } else {
++ return this.paper$originalMessage;
++ }
++ }
++
++ private void readLegacyModifications(final String message, final String format, final Player playerSender) {
++ final ChatMessageContent content = this.message.signedContent();
++ if (content.decorationResult() instanceof ChatDecorator.LegacyResult result) {
++ if ((content.isDecorated() || this.message.unsignedContent().isPresent()) && !result.modernized()) {
++ this.flags.set(MESSAGE_CHANGED, !message.equals(result.message().legacyMessage()));
++ } else {
++ this.flags.set(MESSAGE_CHANGED, !message.equals(this.craftbukkit$originalMessage));
++ }
++ this.flags.set(FORMAT_CHANGED, !format.equals(result.format()));
++ } else {
++ this.flags.set(MESSAGE_CHANGED, !message.equals(this.craftbukkit$originalMessage));
++ this.flags.set(FORMAT_CHANGED, !format.equals(DEFAULT_LEGACY_FORMAT));
++ }
++ this.flags.set(SENDER_CHANGED, playerSender != this.player.getBukkitEntity());
++ }
++
++ private void processModern(final ChatRenderer renderer, final Set viewers, final Component message, final Player player, final boolean cancelled) {
++ final AsyncChatEvent ae = new AsyncChatEvent(this.async, player, viewers, renderer, message, this.paper$originalMessage);
+ ae.setCancelled(cancelled); // propagate cancelled state
+ this.post(ae);
+ final boolean listenersOnSyncEvent = canYouHearMe(ChatEvent.getHandlerList());
@@ -213,39 +429,145 @@ index 0000000000000000000000000000000000000000..3526bc0b6ad590776124966ea907fe24
+ this.queueIfAsyncOrRunImmediately(new Waitable() {
+ @Override
+ protected Void evaluate() {
-+ final ChatEvent se = new ChatEvent(player, ae.viewers(), ae.renderer(), ae.message(), ChatProcessor.this.originalMessage);
++ final ChatEvent se = new ChatEvent(player, ae.viewers(), ae.renderer(), ae.message(), ChatProcessor.this.paper$originalMessage/*, ae.usePreviewComponent()*/);
+ se.setCancelled(ae.isCancelled()); // propagate cancelled state
+ ChatProcessor.this.post(se);
++ ChatProcessor.this.readModernModifications(se, renderer);
+ ChatProcessor.this.complete(se);
+ return null;
+ }
+ });
+ } else {
++ this.readModernModifications(ae, renderer);
+ this.complete(ae);
+ }
+ }
+
++ private void readModernModifications(final AbstractChatEvent chatEvent, final ChatRenderer originalRenderer) {
++ if (this.message.signedContent().isDecorated()) {
++ this.flags.set(MESSAGE_CHANGED, !chatEvent.message().equals(this.message.signedContent().decorationResult().message().component()));
++ } else {
++ this.flags.set(MESSAGE_CHANGED, !chatEvent.message().equals(this.paper$originalMessage));
++ }
++ if (originalRenderer != chatEvent.renderer()) { // don't set to false if it hasn't changed
++ this.flags.set(FORMAT_CHANGED, true);
++ }
++ // this.flags.set(FORCE_PREVIEW_USE, chatEvent.usePreviewComponent()); // TODO (future, maybe?)
++ }
++
+ private void complete(final AbstractChatEvent event) {
+ if (event.isCancelled()) {
++ this.outgoing.sendHeadersToRemainingPlayers(this.server.getPlayerList());
+ return;
+ }
+
-+ final CraftPlayer player = this.player.getBukkitEntity();
++ final CraftPlayer player = ((CraftPlayer) event.getPlayer());
+ final Component displayName = displayName(player);
+ final Component message = event.message();
+ final ChatRenderer renderer = event.renderer();
+
+ final Set viewers = event.viewers();
++ final ResourceKey chatTypeKey = renderer instanceof ChatRenderer.Default ? ChatType.CHAT : ChatType.RAW;
++ final ChatType.Bound chatType = ChatType.bind(chatTypeKey, this.player.level.registryAccess(), PaperAdventure.asVanilla(displayName(player)));
+
-+ if (viewers instanceof LazyChatAudienceSet lazyAudienceSet && lazyAudienceSet.isLazy()) {
-+ this.server.console.sendMessage(player, renderer.render(player, displayName, message, this.server.console), MessageType.CHAT);
-+ for (final ServerPlayer viewer : this.server.getPlayerList().getPlayers()) {
-+ final Player bukkit = viewer.getBukkitEntity();
-+ bukkit.sendMessage(player, renderer.render(player, displayName, message, bukkit), MessageType.CHAT);
++ OutgoingChat outgoingChat = viewers instanceof LazyChatAudienceSet lazyAudienceSet && lazyAudienceSet.isLazy() ? new ServerOutgoingChat() : new ViewersOutgoingChat();
++ /* if (this.flags.get(FORCE_PREVIEW_USE)) { // TODO (future, maybe?)
++ outgoingChat.sendOriginal(player, viewers, chatType);
++ } else */
++ if (this.flags.get(FORMAT_CHANGED)) {
++ if (renderer instanceof ChatRenderer.ViewerUnaware unaware) {
++ outgoingChat.sendFormatChangedViewerUnaware(player, PaperAdventure.asVanilla(unaware.render(player, displayName, message)), viewers, chatType);
++ } else {
++ outgoingChat.sendFormatChangedViewerAware(player, displayName, message, renderer, viewers, chatType);
+ }
++ } else if (this.flags.get(MESSAGE_CHANGED)) {
++ if (!(renderer instanceof ChatRenderer.ViewerUnaware unaware)) {
++ throw new IllegalStateException("BUG: There should not be a non-legacy renderer at this point");
++ }
++ final Component renderedComponent = chatTypeKey == ChatType.CHAT ? message : unaware.render(player, displayName, message);
++ outgoingChat.sendMessageChanged(player, PaperAdventure.asVanilla(renderedComponent), viewers, chatType);
+ } else {
-+ for (final Audience viewer : viewers) {
-+ viewer.sendMessage(player, renderer.render(player, displayName, message, viewer), MessageType.CHAT);
++ outgoingChat.sendOriginal(player, viewers, chatType);
++ }
++ }
++
++ interface OutgoingChat {
++ default void sendFormatChangedViewerUnaware(CraftPlayer player, net.minecraft.network.chat.Component renderedMessage, Set viewers, ChatType.Bound chatType) {
++ this.sendMessageChanged(player, renderedMessage, viewers, chatType);
++ }
++
++ void sendFormatChangedViewerAware(CraftPlayer player, Component displayName, Component message, ChatRenderer renderer, Set viewers, ChatType.Bound chatType);
++
++ void sendMessageChanged(CraftPlayer player, net.minecraft.network.chat.Component renderedMessage, Set viewers, ChatType.Bound chatType);
++
++ void sendOriginal(CraftPlayer player, Set viewers, ChatType.Bound chatType);
++ }
++
++ final class ServerOutgoingChat implements OutgoingChat {
++ @Override
++ public void sendFormatChangedViewerAware(CraftPlayer player, Component displayName, Component message, ChatRenderer renderer, Set viewers, ChatType.Bound chatType) {
++ ChatProcessor.this.server.getPlayerList().broadcastChatMessage(ChatProcessor.this.message, ChatProcessor.this.player, chatType, viewer -> PaperAdventure.asVanilla(renderer.render(player, displayName, message, viewer)));
++ }
++
++ @Override
++ public void sendMessageChanged(CraftPlayer player, net.minecraft.network.chat.Component renderedMessage, Set viewers, ChatType.Bound chatType) {
++ ChatProcessor.this.server.getPlayerList().broadcastChatMessage(ChatProcessor.this.message.withUnsignedContent(renderedMessage), ChatProcessor.this.player, chatType);
++ }
++
++ @Override
++ public void sendOriginal(CraftPlayer player, Set viewers, ChatType.Bound chatType) {
++ ChatProcessor.this.server.getPlayerList().broadcastChatMessage(ChatProcessor.this.message, ChatProcessor.this.player, chatType);
++ }
++ }
++
++ final class ViewersOutgoingChat implements OutgoingChat {
++ @Override
++ public void sendFormatChangedViewerAware(CraftPlayer player, Component displayName, Component message, ChatRenderer renderer, Set viewers, ChatType.Bound chatType) {
++ this.broadcastToViewers(viewers, player, chatType, v -> PaperAdventure.asVanilla(renderer.render(player, displayName, message, v)));
++ }
++
++ @Override
++ public void sendMessageChanged(CraftPlayer player, net.minecraft.network.chat.Component renderedMessage, Set viewers, ChatType.Bound chatType) {
++ this.broadcastToViewers(viewers, player, chatType, new ConstantFunction(renderedMessage));
++ }
++
++ @Override
++ public void sendOriginal(CraftPlayer player, Set viewers, ChatType.Bound chatType) {
++ this.broadcastToViewers(viewers, player, chatType, null);
++ }
++
++ private void broadcastToViewers(Collection viewers, final Player source, final ChatType.Bound chatType, final @Nullable Function msgFunction) {
++ final Supplier fallbackSupplier = Suppliers.memoize(() -> PaperAdventure.asAdventure(msgFunction instanceof ConstantFunction constantFunction ? constantFunction.component : ChatProcessor.this.message.serverContent()));
++ final Function audienceMsgFunction = !(msgFunction instanceof ConstantFunction || msgFunction == null) ? msgFunction.andThen(PaperAdventure::asAdventure) : viewer -> fallbackSupplier.get();
++ for (Audience viewer : viewers) {
++ if (viewer instanceof Player || viewer instanceof ConsoleCommandSender) {
++ // players and console have builtin PlayerChatMessage sending support while other audiences do not
++ this.sendToViewer((CommandSender) viewer, chatType, msgFunction);
++ } else {
++ viewer.sendMessage(source, audienceMsgFunction.apply(viewer), MessageType.CHAT);
++ }
++ }
++ }
++
++ private void sendToViewer(final CommandSender viewer, final ChatType.Bound chatType, final @Nullable Function msgFunction) {
++ if (viewer instanceof ConsoleCommandSender) {
++ this.sendToServer(chatType, msgFunction);
++ } else if (viewer instanceof CraftPlayer craftPlayer) {
++ craftPlayer.getHandle().sendChatMessage(ChatProcessor.this.outgoing, ChatProcessor.this.player.shouldFilterMessageTo(craftPlayer.getHandle()), chatType, Util.mapNullable(msgFunction, f -> f.apply(viewer)));
++ } else {
++ throw new IllegalStateException("Should only be a Player or Console");
++ }
++ }
++
++ private void sendToServer(final ChatType.Bound chatType, final @Nullable Function msgFunction) {
++ final PlayerChatMessage toConsoleMessage = msgFunction == null ? ChatProcessor.this.message : ChatProcessor.this.message.withUnsignedContent(msgFunction.apply(ChatProcessor.this.server.console));
++ ChatProcessor.this.server.logChatMessage(toConsoleMessage.serverContent(), chatType, ChatProcessor.this.server.getPlayerList().verifyChatTrusted(toConsoleMessage, ChatProcessor.this.player.asChatSender()) ? null : "Not Secure");
++ }
++
++ record ConstantFunction(net.minecraft.network.chat.Component component) implements Function {
++ @Override
++ public net.minecraft.network.chat.Component apply(Audience audience) {
++ return this.component;
+ }
+ }
+ }
@@ -259,19 +581,27 @@ index 0000000000000000000000000000000000000000..3526bc0b6ad590776124966ea907fe24
+ return viewers;
+ }
+
-+ private static String legacyDisplayName(final CraftPlayer player) {
++ static String legacyDisplayName(final CraftPlayer player) {
+ return player.getDisplayName();
+ }
+
-+ private static Component displayName(final CraftPlayer player) {
++ static Component displayName(final CraftPlayer player) {
+ return player.displayName();
+ }
+
++ private static ChatRenderer.Default defaultRenderer() {
++ return (ChatRenderer.Default) ChatRenderer.defaultRenderer();
++ }
++
+ private static ChatRenderer legacyRenderer(final String format) {
+ if (DEFAULT_LEGACY_FORMAT.equals(format)) {
-+ return ChatRenderer.defaultRenderer();
++ return defaultRenderer();
+ }
-+ return ChatRenderer.viewerUnaware((player, displayName, message) -> LegacyComponentSerializer.legacySection().deserialize(String.format(format, legacyDisplayName((CraftPlayer) player), LegacyComponentSerializer.legacySection().serialize(message))).replaceText(URL_REPLACEMENT_CONFIG));
++ return ChatRenderer.viewerUnaware((player, sourceDisplayName, message) -> legacySection().deserialize(legacyFormat(format, player, legacySection().serialize(message))));
++ }
++
++ static String legacyFormat(final String format, Player player, String message) {
++ return String.format(format, legacyDisplayName((CraftPlayer) player), message);
+ }
+
+ private void queueIfAsyncOrRunImmediately(final Waitable waitable) {
@@ -293,7 +623,7 @@ index 0000000000000000000000000000000000000000..3526bc0b6ad590776124966ea907fe24
+ this.server.server.getPluginManager().callEvent(event);
+ }
+
-+ private static boolean canYouHearMe(final HandlerList handlers) {
++ static boolean canYouHearMe(final HandlerList handlers) {
+ return handlers.getRegisteredListeners().length > 0;
+ }
+}
@@ -361,7 +691,7 @@ index 0000000000000000000000000000000000000000..2fd6c3e65354071af71c7d8ebb97b559
+}
diff --git a/src/main/java/io/papermc/paper/adventure/PaperAdventure.java b/src/main/java/io/papermc/paper/adventure/PaperAdventure.java
new file mode 100644
-index 0000000000000000000000000000000000000000..3f25a9b1a74cfa0c9a4d0379ecda109d99f33db3
+index 0000000000000000000000000000000000000000..6679038054796b9bdfeb6fb4b29e50aa63052101
--- /dev/null
+++ b/src/main/java/io/papermc/paper/adventure/PaperAdventure.java
@@ -0,0 +1,331 @@
@@ -384,8 +714,8 @@ index 0000000000000000000000000000000000000000..3f25a9b1a74cfa0c9a4d0379ecda109d
+import net.kyori.adventure.text.TranslatableComponent;
+import net.kyori.adventure.text.flattener.ComponentFlattener;
+import net.kyori.adventure.text.format.TextColor;
++import net.kyori.adventure.text.serializer.ComponentSerializer;
+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;
@@ -474,7 +804,7 @@ index 0000000000000000000000000000000000000000..3f25a9b1a74cfa0c9a4d0379ecda109d
+ return decoded.toString();
+ }
+ };
-+ static final WrapperAwareSerializer WRAPPER_AWARE_SERIALIZER = new WrapperAwareSerializer();
++ public static final ComponentSerializer WRAPPER_AWARE_SERIALIZER = new WrapperAwareSerializer();
+
+ private PaperAdventure() {
+ }
@@ -1090,6 +1420,28 @@ index 98f2def9125d6faf5859572a004fa8d2fa066417..436f381c727cda72c04859c540dce471
@Nullable
public static ChatFormatting getById(int colorIndex) {
if (colorIndex < 0) {
+diff --git a/src/main/java/net/minecraft/commands/arguments/MessageArgument.java b/src/main/java/net/minecraft/commands/arguments/MessageArgument.java
+index 6f65ee8bb555dfbfa96363e0a4cf8aadfd92fde3..30a9ff0fd92a1de6c1bce46719549b7803d0c716 100644
+--- a/src/main/java/net/minecraft/commands/arguments/MessageArgument.java
++++ b/src/main/java/net/minecraft/commands/arguments/MessageArgument.java
+@@ -88,7 +88,7 @@ public class MessageArgument implements SignedArgument
+ MinecraftServer minecraftServer = source.getServer();
+ source.getChatMessageChainer().append(() -> {
+ CompletableFuture completableFuture = this.filterPlainText(source, this.signedArgument.signedContent().plain());
+- CompletableFuture completableFuture2 = minecraftServer.getChatDecorator().decorate(source.getPlayer(), this.signedArgument);
++ CompletableFuture completableFuture2 = minecraftServer.getChatDecorator().decorate(source.getPlayer(), source,this.signedArgument); // Paper
+ return CompletableFuture.allOf(completableFuture, completableFuture2).thenAcceptAsync((void_) -> {
+ PlayerChatMessage playerChatMessage = completableFuture2.join().filter(completableFuture.join().mask());
+ callback.accept(playerChatMessage);
+@@ -131,7 +131,7 @@ public class MessageArgument implements SignedArgument
+
+ CompletableFuture resolveDecoratedComponent(CommandSourceStack source) throws CommandSyntaxException {
+ Component component = this.resolveComponent(source);
+- CompletableFuture completableFuture = source.getServer().getChatDecorator().decorate(source.getPlayer(), component);
++ CompletableFuture completableFuture = source.getServer().getChatDecorator().decorate(source.getPlayer(), source, component, true).thenApply(net.minecraft.network.chat.ChatDecorator.Result::component); // Paper
+ MessageArgument.logResolutionFailure(source, completableFuture);
+ return completableFuture;
+ }
diff --git a/src/main/java/net/minecraft/network/FriendlyByteBuf.java b/src/main/java/net/minecraft/network/FriendlyByteBuf.java
index c4854debe11b8bb61fa49c76c1854f94c1e7777f..42514a0c7066dc79050c0496d6463528b593f9e4 100644
--- a/src/main/java/net/minecraft/network/FriendlyByteBuf.java
@@ -1147,6 +1499,168 @@ index 021a26a6b1c258deffc26c035ab52a4ea027d9a1..00d432bd395e7f7fb6ee24e371818d13
try {
int i = friendlyByteBuf.writerIndex();
+diff --git a/src/main/java/net/minecraft/network/chat/ChatDecorator.java b/src/main/java/net/minecraft/network/chat/ChatDecorator.java
+index b9cdd89a3871d934a0449ed70766c2e9d6369ab9..52307bdaed93de1c3ddb06477b3a5b434a8f7a68 100644
+--- a/src/main/java/net/minecraft/network/chat/ChatDecorator.java
++++ b/src/main/java/net/minecraft/network/chat/ChatDecorator.java
+@@ -10,10 +10,81 @@ public interface ChatDecorator {
+ return CompletableFuture.completedFuture(message);
+ };
+
++ @io.papermc.paper.annotation.DoNotUse // Paper
+ CompletableFuture decorate(@Nullable ServerPlayer sender, Component message);
+
++ // Paper start
++ default CompletableFuture decorate(@Nullable ServerPlayer sender, @Nullable net.minecraft.commands.CommandSourceStack commandSourceStack, Component message, boolean isPreview) {
++ throw new UnsupportedOperationException("Must override this implementation");
++ }
++
++ static ChatDecorator create(ImprovedChatDecorator delegate) {
++ return new ChatDecorator() {
++ @Override
++ public CompletableFuture decorate(@Nullable ServerPlayer sender, Component message) {
++ return this.decorate(sender, null, message, true).thenApply(Result::component);
++ }
++
++ @Override
++ public CompletableFuture decorate(@Nullable ServerPlayer sender, @Nullable net.minecraft.commands.CommandSourceStack commandSourceStack, Component message, boolean isPreview) {
++ return delegate.decorate(sender, commandSourceStack, message, isPreview);
++ }
++ };
++ }
++
++ @FunctionalInterface
++ interface ImprovedChatDecorator {
++ CompletableFuture decorate(@Nullable ServerPlayer sender, @Nullable net.minecraft.commands.CommandSourceStack commandSourceStack, Component message, boolean isPreview);
++ }
++
++ interface Result {
++ boolean hasNoFormatting();
++
++ Component component();
++
++ MessagePair message();
++
++ boolean modernized();
++ }
++
++ record MessagePair(net.kyori.adventure.text.Component component, String legacyMessage) { }
++
++ record LegacyResult(Component component, String format, MessagePair message, boolean hasNoFormatting, boolean modernized) implements Result {
++ public LegacyResult(net.kyori.adventure.text.Component component, String format, MessagePair message, boolean hasNoFormatting, boolean modernified) {
++ this(io.papermc.paper.adventure.PaperAdventure.asVanilla(component), format, message, hasNoFormatting, modernified);
++ }
++ public LegacyResult {
++ component = component instanceof io.papermc.paper.adventure.AdventureComponent adventureComponent ? adventureComponent.deepConverted() : component;
++ }
++ }
++
++ record ModernResult(Component maybeAdventureComponent, boolean hasNoFormatting, boolean modernized) implements Result {
++ public ModernResult(net.kyori.adventure.text.Component component, boolean hasNoFormatting, boolean modernized) {
++ this(io.papermc.paper.adventure.PaperAdventure.asVanilla(component), hasNoFormatting, modernized);
++ }
++
++ @Override
++ public Component component() {
++ return this.maybeAdventureComponent instanceof io.papermc.paper.adventure.AdventureComponent adventureComponent ? adventureComponent.deepConverted() : this.maybeAdventureComponent;
++ }
++
++ @Override
++ public MessagePair message() {
++ final net.kyori.adventure.text.Component adventureComponent = io.papermc.paper.adventure.PaperAdventure.WRAPPER_AWARE_SERIALIZER.deserialize(this.maybeAdventureComponent);
++ return new MessagePair(adventureComponent, net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(adventureComponent));
++ }
++ }
++ default CompletableFuture decorate(@Nullable ServerPlayer serverPlayer, @Nullable net.minecraft.commands.CommandSourceStack commandSourceStack, PlayerChatMessage playerChatMessage) {
++ return playerChatMessage.signedContent().isDecorated() ? CompletableFuture.completedFuture(playerChatMessage) : this.decorate(serverPlayer, commandSourceStack, playerChatMessage.serverContent(), false).thenApply(result -> {
++ return new PlayerChatMessage(playerChatMessage.signedHeader(), playerChatMessage.headerSignature(), playerChatMessage.signedBody().withContent(playerChatMessage.signedContent().withDecorationResult(result)), playerChatMessage.unsignedContent(), playerChatMessage.filterMask()).withUnsignedContent(result.component());
++ });
++ }
++
++ // Paper end
++
++ @io.papermc.paper.annotation.DoNotUse // Paper
+ default CompletableFuture decorate(@Nullable ServerPlayer serverPlayer, PlayerChatMessage playerChatMessage) {
+- return playerChatMessage.signedContent().isDecorated() ? CompletableFuture.completedFuture(playerChatMessage) : this.decorate(serverPlayer, playerChatMessage.serverContent()).thenApply(playerChatMessage::withUnsignedContent);
++ return this.decorate(serverPlayer, null, playerChatMessage); // Paper
+ }
+
+ static PlayerChatMessage attachIfNotDecorated(PlayerChatMessage playerChatMessage, Component component) {
+diff --git a/src/main/java/net/minecraft/network/chat/ChatMessageContent.java b/src/main/java/net/minecraft/network/chat/ChatMessageContent.java
+index b1c76ccfb4527337ac2c9ad2d2c7e34df0c4c660..e7caa6380b07f9bd34c2f8c821c0f6d3cb4e7649 100644
+--- a/src/main/java/net/minecraft/network/chat/ChatMessageContent.java
++++ b/src/main/java/net/minecraft/network/chat/ChatMessageContent.java
+@@ -3,7 +3,17 @@ package net.minecraft.network.chat;
+ import java.util.Objects;
+ import net.minecraft.network.FriendlyByteBuf;
+
+-public record ChatMessageContent(String plain, Component decorated) {
++// Paper start
++public record ChatMessageContent(String plain, Component decorated, ChatDecorator.Result decorationResult) {
++
++ public ChatMessageContent(String plain, Component decorated) {
++ this(plain, decorated, new ChatDecorator.ModernResult(decorated, true, false));
++ }
++
++ public ChatMessageContent withDecorationResult(ChatDecorator.Result result) {
++ return new ChatMessageContent(this.plain, this.decorated, result);
++ }
++ // Paper end
+ public ChatMessageContent(String content) {
+ this(content, Component.literal(content));
+ }
+diff --git a/src/main/java/net/minecraft/network/chat/ChatPreviewCache.java b/src/main/java/net/minecraft/network/chat/ChatPreviewCache.java
+index 85e75f3eb58be03b500e663a128663cbe9331605..487822cc8e491c38a276d0d78db6f5207de8a65b 100644
+--- a/src/main/java/net/minecraft/network/chat/ChatPreviewCache.java
++++ b/src/main/java/net/minecraft/network/chat/ChatPreviewCache.java
+@@ -1,27 +1,44 @@
+ package net.minecraft.network.chat;
+
+ import javax.annotation.Nullable;
++import net.minecraft.Util;
+
+ public class ChatPreviewCache {
+ @Nullable
+ private ChatPreviewCache.Result result;
+
+ public void set(String query, Component preview) {
+- this.result = new ChatPreviewCache.Result(query, preview);
++ // Paper start
++ this.set(query, new ChatDecorator.ModernResult(java.util.Objects.requireNonNull(preview), true, false));
++ }
++ public void set(String query, ChatDecorator.Result decoratorResult) {
++ this.result = new ChatPreviewCache.Result(query, java.util.Objects.requireNonNull(decoratorResult));
++ // Paper end
+ }
+
+ @Nullable
+ public Component pull(String query) {
++ // Paper start
++ return net.minecraft.Util.mapNullable(this.pullFull(query), Result::preview);
++ }
++ public @Nullable Result pullFull(String query) {
++ // Paper end
+ ChatPreviewCache.Result result = this.result;
+ if (result != null && result.matches(query)) {
+ this.result = null;
+- return result.preview();
++ return result; // Paper
+ } else {
+ return null;
+ }
+ }
+
+- static record Result(String query, Component preview) {
++ // Paper start
++ public record Result(String query, ChatDecorator.Result decoratorResult) {
++
++ public Component preview() {
++ return this.decoratorResult.component();
++ }
++ // Paper end
+ public boolean matches(String query) {
+ return this.query.equals(query);
+ }
diff --git a/src/main/java/net/minecraft/network/chat/Component.java b/src/main/java/net/minecraft/network/chat/Component.java
index 06736982f7625c1a532315afe94e5e0c45ec1331..e7d9e2d8c87ddf3658b1c2e0f2a3e98ef8080cec 100644
--- a/src/main/java/net/minecraft/network/chat/Component.java
@@ -1175,6 +1689,54 @@ index 06736982f7625c1a532315afe94e5e0c45ec1331..e7d9e2d8c87ddf3658b1c2e0f2a3e98e
JsonObject jsonobject = new JsonObject();
if (!ichatbasecomponent.getStyle().isEmpty()) {
+diff --git a/src/main/java/net/minecraft/network/chat/OutgoingPlayerChatMessage.java b/src/main/java/net/minecraft/network/chat/OutgoingPlayerChatMessage.java
+index 952dfc9ce81bc8ce2efb120884a5723145445f3c..fc43cc6f5bbb3485b9ddcc441a13399e57289586 100644
+--- a/src/main/java/net/minecraft/network/chat/OutgoingPlayerChatMessage.java
++++ b/src/main/java/net/minecraft/network/chat/OutgoingPlayerChatMessage.java
+@@ -13,6 +13,11 @@ public interface OutgoingPlayerChatMessage {
+ Component serverContent();
+
+ void sendToPlayer(ServerPlayer serverPlayer, boolean bl, ChatType.Bound bound);
++ // Paper start
++ default void sendToPlayer(ServerPlayer serverPlayer, boolean shouldFilter, ChatType.Bound bound, @javax.annotation.Nullable Component unsigned) {
++ this.sendToPlayer(serverPlayer, shouldFilter, bound);
++ }
++ // Paper end
+
+ void sendHeadersToRemainingPlayers(PlayerList playerManager);
+
+@@ -34,7 +39,15 @@ public interface OutgoingPlayerChatMessage {
+
+ @Override
+ public void sendToPlayer(ServerPlayer serverPlayer, boolean bl, ChatType.Bound bound) {
++ // Paper start
++ this.sendToPlayer(serverPlayer, bl, bound, null);
++ }
++
++ @Override
++ public void sendToPlayer(ServerPlayer serverPlayer, boolean bl, ChatType.Bound bound, @javax.annotation.Nullable Component unsigned) {
++ // Paper end
+ PlayerChatMessage playerChatMessage = this.message.filter(bl);
++ playerChatMessage = unsigned != null ? playerChatMessage.withUnsignedContent(unsigned) : playerChatMessage; // Paper
+ if (!playerChatMessage.isFullyFiltered()) {
+ RegistryAccess registryAccess = serverPlayer.level.registryAccess();
+ ChatType.BoundNetwork boundNetwork = bound.toNetwork(registryAccess);
+@@ -64,7 +77,15 @@ public interface OutgoingPlayerChatMessage {
+
+ @Override
+ public void sendToPlayer(ServerPlayer serverPlayer, boolean bl, ChatType.Bound bound) {
++ // Paper start
++ this.sendToPlayer(serverPlayer, bl, bound, null);
++ }
++
++ @Override
++ public void sendToPlayer(ServerPlayer serverPlayer, boolean bl, ChatType.Bound bound, @javax.annotation.Nullable Component unsigned) {
++ // Paper end
+ PlayerChatMessage playerChatMessage = this.message.filter(bl);
++ playerChatMessage = unsigned != null ? playerChatMessage.withUnsignedContent(unsigned) : playerChatMessage; // Paper
+ if (!playerChatMessage.isFullyFiltered()) {
+ this.playersWithFullMessage.add(serverPlayer);
+ RegistryAccess registryAccess = serverPlayer.level.registryAccess();
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetActionBarTextPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetActionBarTextPacket.java
index 02183c810f9968621b9b20c1f7b54258b620c507..32ef3edebe94a2014168b7e438752a80b2687e5f 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetActionBarTextPacket.java
@@ -1326,7 +1888,7 @@ index 762a9392ffac3042356709dddd15bb3516048bed..3544e2dc2522e9d6305d727d56e73490
buf.writeComponent(this.footer);
}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
-index 3aadba90ab32388b9e8ef96f182fa263c760f53b..acc5ce86ae8aa5ada21e6c97f7921caca4b0bd00 100644
+index 20a0a14f331ed891a64bd3ed69ade9cf2d917922..b9a6533afbfe07ff544f9f03f3c254890ee2e068 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -229,6 +229,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop {
+- // SPIGOT-7127: Console /say and similar
+- if (entityplayer == null) {
+- return CompletableFuture.completedFuture(ichatbasecomponent);
+- }
+-
+- return CompletableFuture.supplyAsync(() -> {
+- AsyncPlayerChatPreviewEvent event = new AsyncPlayerChatPreviewEvent(true, entityplayer.getBukkitEntity(), CraftChatMessage.fromComponent(ichatbasecomponent), new LazyPlayerSet(this));
+- String originalFormat = event.getFormat(), originalMessage = event.getMessage();
+- this.server.getPluginManager().callEvent(event);
+-
+- if (originalFormat.equals(event.getFormat()) && originalMessage.equals(event.getMessage()) && event.getPlayer().getName().equalsIgnoreCase(event.getPlayer().getDisplayName())) {
+- return ichatbasecomponent;
+- }
+-
+- return CraftChatMessage.fromStringOrNull(String.format(event.getFormat(), event.getPlayer().getDisplayName(), event.getMessage()));
+- }, chatExecutor);
+- };
++ // Paper start - moved to ChatPreviewProcessor
++ return ChatDecorator.create((sender, commandSourceStack, message, isPreview) -> {
++ final io.papermc.paper.adventure.ChatDecorationProcessor processor = new io.papermc.paper.adventure.ChatDecorationProcessor(this, sender, commandSourceStack, message, isPreview);
++ return processor.process();
++ });
++ // Paper end
+ // CraftBukkit end
+ }
+
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-index 4759a0eceeccf28b62cb8865b423235d47d07443..58aea845e8ce6e46e52fc3bdfa9c64153c32a750 100644
+index 4759a0eceeccf28b62cb8865b423235d47d07443..bee13e04481f57bf6778b66cd0bc2891e069547a 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -154,6 +154,7 @@ import net.minecraft.world.scores.Score;
@@ -1411,7 +2008,22 @@ index 4759a0eceeccf28b62cb8865b423235d47d07443..58aea845e8ce6e46e52fc3bdfa9c6415
this.connection.send(new ClientboundPlayerCombatKillPacket(this.getCombatTracker(), ichatbasecomponent), PacketSendListener.exceptionallySend(() -> {
boolean flag1 = true;
-@@ -1751,6 +1749,7 @@ public class ServerPlayer extends Player {
+@@ -1729,8 +1727,13 @@ public class ServerPlayer extends Player {
+ }
+
+ public void sendChatMessage(OutgoingPlayerChatMessage message, boolean flag, ChatType.Bound chatmessagetype_a) {
++ // Paper start
++ this.sendChatMessage(message, flag, chatmessagetype_a, null);
++ }
++ public void sendChatMessage(OutgoingPlayerChatMessage message, boolean flag, ChatType.Bound chatmessagetype_a, @Nullable Component unsigned) {
++ // Paper end
+ if (this.acceptsChatMessages()) {
+- message.sendToPlayer(this, flag, chatmessagetype_a);
++ message.sendToPlayer(this, flag, chatmessagetype_a, unsigned); // Paper
+ }
+
+ }
+@@ -1751,6 +1754,7 @@ public class ServerPlayer extends Player {
}
public String locale = "en_us"; // CraftBukkit - add, lowercase
@@ -1419,7 +2031,7 @@ index 4759a0eceeccf28b62cb8865b423235d47d07443..58aea845e8ce6e46e52fc3bdfa9c6415
public void updateOptions(ServerboundClientInformationPacket packet) {
// CraftBukkit start
if (getMainArm() != packet.mainHand()) {
-@@ -1762,6 +1761,10 @@ public class ServerPlayer extends Player {
+@@ -1762,6 +1766,10 @@ public class ServerPlayer extends Player {
this.server.server.getPluginManager().callEvent(event);
}
this.locale = packet.language;
@@ -1431,7 +2043,7 @@ index 4759a0eceeccf28b62cb8865b423235d47d07443..58aea845e8ce6e46e52fc3bdfa9c6415
// CraftBukkit end
this.chatVisibility = packet.chatVisibility();
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-index 13f996d163739f419b701854b5248a02edfc93c0..59932a4f83461280ab3c097add951e5a138eb53d 100644
+index 13f996d163739f419b701854b5248a02edfc93c0..0620ba3f5e26279e0165d86f589d73f423d633f0 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -187,6 +187,8 @@ import org.apache.commons.lang3.StringUtils;
@@ -1512,6 +2124,15 @@ index 13f996d163739f419b701854b5248a02edfc93c0..59932a4f83461280ab3c097add951e5a
}
// CraftBukkit end
this.player.getTextFilter().leave();
+@@ -1877,7 +1884,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+ if (this.verifyChatMessage(playerchatmessage)) {
+ this.chatMessageChain.append(() -> {
+ CompletableFuture completablefuture = this.filterTextPacket(playerchatmessage.signedContent().plain());
+- CompletableFuture completablefuture1 = this.server.getChatDecorator().decorate(this.player, playerchatmessage);
++ CompletableFuture completablefuture1 = this.server.getChatDecorator().decorate(this.player, null, playerchatmessage); // Paper
+
+ return CompletableFuture.allOf(completablefuture, completablefuture1).thenAcceptAsync((ovoid) -> {
+ FilterMask filtermask = ((FilteredText) completablefuture.join()).mask();
@@ -2039,7 +2046,12 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
this.handleCommand(s);
} else if (this.player.getChatVisibility() == ChatVisiblity.SYSTEM) {
@@ -1519,14 +2140,60 @@ index 13f996d163739f419b701854b5248a02edfc93c0..59932a4f83461280ab3c097add951e5a
- } else {
+ // Paper start
+ } else if (true) {
-+ final ChatProcessor cp = new ChatProcessor(this.server, this.player, s, async);
++ final ChatProcessor cp = new ChatProcessor(this.server, this.player, original, async);
+ cp.process();
+ // Paper end
+ } else if (false) { // Paper
Player player = this.getCraftPlayer();
AsyncPlayerChatEvent event = new AsyncPlayerChatEvent(async, player, s, new LazyPlayerSet(this.server));
String originalFormat = event.getFormat(), originalMessage = event.getMessage();
-@@ -3076,30 +3088,30 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -2172,9 +2184,12 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+ }
+
+ private ChatMessageContent getSignedContent(ServerboundChatPacket packet) {
+- Component ichatbasecomponent = this.chatPreviewCache.pull(packet.message());
++ // Paper start
++ final net.minecraft.network.chat.ChatPreviewCache.Result result = this.chatPreviewCache.pullFull(packet.message());
++ Component ichatbasecomponent = result != null ? result.preview() : null;
++ // Paper end
+
+- return packet.signedPreview() && ichatbasecomponent != null ? new ChatMessageContent(packet.message(), ichatbasecomponent) : new ChatMessageContent(packet.message());
++ return packet.signedPreview() && ichatbasecomponent != null ? new ChatMessageContent(packet.message(), ichatbasecomponent, result.decoratorResult()) : new ChatMessageContent(packet.message()); // Paper end
+ }
+
+ private void broadcastChatMessage(PlayerChatMessage playerchatmessage) {
+@@ -2269,14 +2284,17 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+
+ private CompletableFuture queryChatPreview(String query) {
+ MutableComponent ichatmutablecomponent = Component.literal(query);
+- CompletableFuture completablefuture = this.server.getChatDecorator().decorate(this.player, (Component) ichatmutablecomponent).thenApply((ichatbasecomponent) -> {
+- return !ichatmutablecomponent.equals(ichatbasecomponent) ? ichatbasecomponent : null;
++ // Paper start
++ final CompletableFuture result = this.server.getChatDecorator().decorate(this.player, null, ichatmutablecomponent, true);
++ CompletableFuture completablefuture = result.thenApply((res) -> {
++ return !ichatmutablecomponent.equals(res.component()) ? res : null;
++ // Paper end
+ });
+
+ completablefuture.thenAcceptAsync((ichatbasecomponent) -> {
+- this.chatPreviewCache.set(query, ichatbasecomponent);
++ if (ichatbasecomponent != null) this.chatPreviewCache.set(query, ichatbasecomponent); // Paper
+ }, this.server);
+- return completablefuture;
++ return completablefuture.thenApply(net.minecraft.network.chat.ChatDecorator.Result::component); // paper
+ }
+
+ private CompletableFuture queryCommandPreview(String query) {
+@@ -2285,7 +2303,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+ CompletableFuture completablefuture = this.getPreviewedArgument(commandlistenerwrapper, PreviewableCommand.of(parseresults));
+
+ completablefuture.thenAcceptAsync((ichatbasecomponent) -> {
+- this.chatPreviewCache.set(query, ichatbasecomponent);
++ if (ichatbasecomponent != null) this.chatPreviewCache.set(query, ichatbasecomponent); // Paper
+ }, this.server);
+ return completablefuture;
+ }
+@@ -3076,30 +3094,30 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
return;
}
@@ -1606,7 +2273,7 @@ index 3a587073dbe5e8a599d342c5f758d842b7b6cddb..a426adfba3fccf1815177e0b8065684c
@Override
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
-index ba6f4e9f74a524201390bd0e9106a6cf6afe0375..946b2b7341a10c25fae71d76f7b181b555fe38b6 100644
+index ba6f4e9f74a524201390bd0e9106a6cf6afe0375..68ea3623dedefbc695bbb53e163911d3dfbfbf7e 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -8,6 +8,7 @@ import com.mojang.logging.LogUtils;
@@ -1721,6 +2388,52 @@ index ba6f4e9f74a524201390bd0e9106a6cf6afe0375..946b2b7341a10c25fae71d76f7b181b5
}
// CraftBukkit end
+@@ -1169,14 +1169,25 @@ public abstract class PlayerList {
+ }
+
+ public void broadcastChatMessage(PlayerChatMessage playerchatmessage, ServerPlayer sender, ChatType.Bound params) {
++ // Paper start
++ this.broadcastChatMessage(playerchatmessage, sender, params, null);
++ }
++ public void broadcastChatMessage(PlayerChatMessage playerchatmessage, ServerPlayer sender, ChatType.Bound params, @Nullable Function unsignedFunction) {
++ // Paper end
+ Objects.requireNonNull(sender);
+- this.broadcastChatMessage(playerchatmessage, sender::shouldFilterMessageTo, sender, sender.asChatSender(), params);
++ this.broadcastChatMessage(playerchatmessage, sender::shouldFilterMessageTo, sender, sender.asChatSender(), params, unsignedFunction); // Paper
+ }
+
+ private void broadcastChatMessage(PlayerChatMessage playerchatmessage, Predicate shouldSendFiltered, @Nullable ServerPlayer entityplayer, ChatSender chatsender, ChatType.Bound chatmessagetype_a) {
++ // Paper start
++ this.broadcastChatMessage(playerchatmessage, shouldSendFiltered, entityplayer, chatsender, chatmessagetype_a, null);
++ }
++
++ private void broadcastChatMessage(PlayerChatMessage playerchatmessage, Predicate shouldSendFiltered, @Nullable ServerPlayer entityplayer, ChatSender chatsender, ChatType.Bound chatmessagetype_a, @Nullable Function unsignedFunction) {
++ // Paper end
+ boolean flag = this.verifyChatTrusted(playerchatmessage, chatsender);
+
+- this.server.logChatMessage(playerchatmessage.serverContent(), chatmessagetype_a, flag ? null : "Not Secure");
++ this.server.logChatMessage((unsignedFunction == null ? playerchatmessage : playerchatmessage.withUnsignedContent(unsignedFunction.apply(this.server.console))).serverContent(), chatmessagetype_a, flag ? null : "Not Secure"); // Paper
+ OutgoingPlayerChatMessage outgoingplayerchatmessage = OutgoingPlayerChatMessage.create(playerchatmessage);
+ boolean flag1 = playerchatmessage.isFullyFiltered();
+ boolean flag2 = false;
+@@ -1186,7 +1197,7 @@ public abstract class PlayerList {
+ ServerPlayer entityplayer1 = (ServerPlayer) iterator.next();
+ boolean flag3 = shouldSendFiltered.test(entityplayer1);
+
+- entityplayer1.sendChatMessage(outgoingplayerchatmessage, flag3, chatmessagetype_a);
++ entityplayer1.sendChatMessage(outgoingplayerchatmessage, flag3, chatmessagetype_a, unsignedFunction == null ? null : unsignedFunction.apply(entityplayer1.getBukkitEntity()));
+ if (entityplayer != entityplayer1) {
+ flag2 |= flag1 && flag3;
+ }
+@@ -1213,7 +1224,7 @@ public abstract class PlayerList {
+
+ }
+
+- private boolean verifyChatTrusted(PlayerChatMessage message, ChatSender profile) {
++ public boolean verifyChatTrusted(PlayerChatMessage message, ChatSender profile) { // Paper - private -> public
+ return !message.hasExpiredServer(Instant.now()) && message.verify(profile);
+ }
+
diff --git a/src/main/java/net/minecraft/world/BossEvent.java b/src/main/java/net/minecraft/world/BossEvent.java
index 4c62df5a3781ec9df4a5c5f1b528649e6e8a62d1..affd1b8c7589ba59330dc0b6fc803cce4ee57397 100644
--- a/src/main/java/net/minecraft/world/BossEvent.java
@@ -2004,7 +2717,7 @@ index 93308369f0bbd1e95569d9d573b8b6f42c8ae5a7..cf7762e76a2d35acdfc12627e9750fbe
+ // Paper end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
-index b05cea49219c6582bacc705f41e72ca7c7eb6a8c..c520e8e53356188ee00dc10a6a74c88b5e2f6e94 100644
+index e8d71985f2e96574081e4f609d62a3b8bded8249..681b58e6de48cccac82c7b6833f6fcea46d83dde 100644
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
@@ -19,6 +19,12 @@ public class Main {
@@ -2486,7 +3199,7 @@ index 446fdca49a5a6999626a7ee3a1d5c168b15a09dd..f9863e138994f6c7a7975a852f106faa
public boolean isOp() {
return true;
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
-index cadafdfd3469b6f813f5e0add116640313fb6209..ac6fd14f18f2fa2247db4d2d8c9233f862b85111 100644
+index e9036bbb2ec2862252c3a39a4022e195784291ca..ef5e29e0a66f8d4cb819c4383cf3f1317d4e5bb0 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -269,14 +269,39 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
diff --git a/patches/server/0039-Implement-PlayerLocaleChangeEvent.patch b/patches/server/0039-Implement-PlayerLocaleChangeEvent.patch
index b9a9162157..41fbaec734 100644
--- a/patches/server/0039-Implement-PlayerLocaleChangeEvent.patch
+++ b/patches/server/0039-Implement-PlayerLocaleChangeEvent.patch
@@ -5,10 +5,10 @@ Subject: [PATCH] Implement PlayerLocaleChangeEvent
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-index 5ff3bf1c436fd69e6129e59c205f626df9d61e8d..a3410c8f89c4b7f68999aafb090555c7e7513316 100644
+index 16c4df6bd5b84b5e7a820ba14f2b2ee80b5b401c..48ffa3fce91ad98d9e4c099aacf6c0a84b2093e4 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-@@ -1749,7 +1749,7 @@ public class ServerPlayer extends Player {
+@@ -1754,7 +1754,7 @@ public class ServerPlayer extends Player {
return s;
}
@@ -17,7 +17,7 @@ index 5ff3bf1c436fd69e6129e59c205f626df9d61e8d..a3410c8f89c4b7f68999aafb090555c7
public java.util.Locale adventure$locale = java.util.Locale.US; // Paper
public void updateOptions(ServerboundClientInformationPacket packet) {
// CraftBukkit start
-@@ -1757,9 +1757,10 @@ public class ServerPlayer extends Player {
+@@ -1762,9 +1762,10 @@ public class ServerPlayer extends Player {
PlayerChangedMainHandEvent event = new PlayerChangedMainHandEvent(this.getBukkitEntity(), getMainArm() == HumanoidArm.LEFT ? MainHand.LEFT : MainHand.RIGHT);
this.server.server.getPluginManager().callEvent(event);
}
@@ -30,7 +30,7 @@ index 5ff3bf1c436fd69e6129e59c205f626df9d61e8d..a3410c8f89c4b7f68999aafb090555c7
this.locale = packet.language;
// Paper start
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
-index 46abb31a5330662f46949466e01c404ba2922027..b6d03bdd161da73492fb947cc4ca4f6c1ba172f1 100644
+index 6d2609222afa3cd5f99118281c20281f8c2f792f..9bcffda912e3cc7322043e705dddfe052f4b1273 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -1965,8 +1965,10 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
diff --git a/patches/server/0040-Per-Player-View-Distance-API-placeholders.patch b/patches/server/0040-Per-Player-View-Distance-API-placeholders.patch
index 221d8dcfd0..ccdb2bf31b 100644
--- a/patches/server/0040-Per-Player-View-Distance-API-placeholders.patch
+++ b/patches/server/0040-Per-Player-View-Distance-API-placeholders.patch
@@ -7,10 +7,10 @@ I hope to look at this more in-depth soon. It appears doable.
However this should not block the update.
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-index a3410c8f89c4b7f68999aafb090555c7e7513316..b6a19cd2cfd8acfac6dde77033bbb82ef20586d0 100644
+index 48ffa3fce91ad98d9e4c099aacf6c0a84b2093e4..28d8ba2f421245ab6707ea982e76d543916a1e51 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-@@ -2232,4 +2232,6 @@ public class ServerPlayer extends Player {
+@@ -2237,4 +2237,6 @@ public class ServerPlayer extends Player {
return (CraftPlayer) super.getBukkitEntity();
}
// CraftBukkit end
@@ -60,7 +60,7 @@ index cf7762e76a2d35acdfc12627e9750fbec766d555..40d6b00fb40db167c6c80b6a3f79eb82
// Spigot start
private final org.bukkit.World.Spigot spigot = new org.bukkit.World.Spigot()
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
-index b6d03bdd161da73492fb947cc4ca4f6c1ba172f1..b73b202a3c68ba559b65245186a97025bda25134 100644
+index 9bcffda912e3cc7322043e705dddfe052f4b1273..62a4ae1ee2a0784787b6f45bff6393630e1d4219 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -402,6 +402,46 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
diff --git a/patches/server/0079-Add-PlayerUseUnknownEntityEvent.patch b/patches/server/0079-Add-PlayerUseUnknownEntityEvent.patch
index 6e717ab751..d4da1e88e3 100644
--- a/patches/server/0079-Add-PlayerUseUnknownEntityEvent.patch
+++ b/patches/server/0079-Add-PlayerUseUnknownEntityEvent.patch
@@ -20,10 +20,10 @@ index 8834ed411a7db86b4d2b88183a1315317107d719..c45b5ab6776f3ac79f856c3a6467c510
static final ServerboundInteractPacket.Action ATTACK_ACTION = new ServerboundInteractPacket.Action() {
@Override
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-index 2e9aa7bcdaf86165190d16098d7f6363bfa2f837..680193185185972d3b9112c7b59565bce1b1729a 100644
+index 101dde32d7ad708d4826f0dbf81263f07c31085b..ce3b68275ca399b5900012d5170e70fb35602695 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-@@ -2613,8 +2613,37 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -2619,8 +2619,37 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
});
}
}
diff --git a/patches/server/0083-Option-to-use-vanilla-per-world-scoreboard-coloring-.patch b/patches/server/0083-Option-to-use-vanilla-per-world-scoreboard-coloring-.patch
index 4b02783b1c..04ed9957ea 100644
--- a/patches/server/0083-Option-to-use-vanilla-per-world-scoreboard-coloring-.patch
+++ b/patches/server/0083-Option-to-use-vanilla-per-world-scoreboard-coloring-.patch
@@ -12,29 +12,31 @@ for this on CB at one point but I can't find it. We may need to do this
ourselves at some point in the future.
diff --git a/src/main/java/io/papermc/paper/adventure/ChatProcessor.java b/src/main/java/io/papermc/paper/adventure/ChatProcessor.java
-index 3526bc0b6ad590776124966ea907fe2467cbbf5f..b13d516d91788713768b5c336537ffe31653b074 100644
+index bc37199f1d181f572da518d9b93b2980504024b1..d5e0ed2adba4e22b9842110ddf009f47187840e4 100644
--- a/src/main/java/io/papermc/paper/adventure/ChatProcessor.java
+++ b/src/main/java/io/papermc/paper/adventure/ChatProcessor.java
-@@ -16,6 +16,8 @@ import net.kyori.adventure.text.event.ClickEvent;
- import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
+@@ -24,8 +24,10 @@ import net.minecraft.network.chat.PlayerChatMessage;
+ import net.minecraft.resources.ResourceKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
+import org.bukkit.ChatColor;
+ import org.bukkit.command.CommandSender;
+ import org.bukkit.command.ConsoleCommandSender;
+import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.util.LazyPlayerSet;
import org.bukkit.craftbukkit.util.Waitable;
-@@ -154,10 +156,16 @@ public final class ChatProcessor {
+@@ -329,10 +331,16 @@ public final class ChatProcessor {
}
- private static String legacyDisplayName(final CraftPlayer player) {
+ static String legacyDisplayName(final CraftPlayer player) {
+ if (((org.bukkit.craftbukkit.CraftWorld) player.getWorld()).getHandle().paperConfig().scoreboards.useVanillaWorldScoreboardNameColoring) {
-+ return LegacyComponentSerializer.legacySection().serialize(player.teamDisplayName()) + ChatColor.RESET;
++ return legacySection().serialize(player.teamDisplayName()) + ChatColor.RESET;
+ }
return player.getDisplayName();
}
- private static Component displayName(final CraftPlayer player) {
+ static Component displayName(final CraftPlayer player) {
+ if (((CraftWorld) player.getWorld()).getHandle().paperConfig().scoreboards.useVanillaWorldScoreboardNameColoring) {
+ return player.teamDisplayName();
+ }
diff --git a/patches/server/0119-Properly-fix-item-duplication-bug.patch b/patches/server/0119-Properly-fix-item-duplication-bug.patch
index aaf16b075f..4a25d9c776 100644
--- a/patches/server/0119-Properly-fix-item-duplication-bug.patch
+++ b/patches/server/0119-Properly-fix-item-duplication-bug.patch
@@ -6,10 +6,10 @@ Subject: [PATCH] Properly fix item duplication bug
Credit to prplz for figuring out the real issue
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-index b117a98dea77755bee33f8a141f8df16b587beeb..8f4b8e4911d5c3bb82c9ac246c041c0eb51a3123 100644
+index 9cd5bf2890fbb0bdb8eb79b1659fe7058dbe08e9..b239654eb92f95cb855cd3d750c79f98893f9980 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-@@ -2189,7 +2189,7 @@ public class ServerPlayer extends Player {
+@@ -2194,7 +2194,7 @@ public class ServerPlayer extends Player {
@Override
public boolean isImmobile() {
@@ -19,10 +19,10 @@ index b117a98dea77755bee33f8a141f8df16b587beeb..8f4b8e4911d5c3bb82c9ac246c041c0e
@Override
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-index 50759c53b46b913ac7ff56476d2a49163e54fff4..44daf6210786748f44275a97ecebbd191837b5e5 100644
+index 26e10d245adbac49f9c30ada74729444fe0fedaf..21e1520e30a4655c679b3f3b4f8f8e053f245aca 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-@@ -3252,7 +3252,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -3258,7 +3258,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
}
public final boolean isDisconnected() {
diff --git a/patches/server/0131-Add-option-to-make-parrots-stay-on-shoulders-despite.patch b/patches/server/0131-Add-option-to-make-parrots-stay-on-shoulders-despite.patch
index c18bd20fc5..95f44c6c77 100644
--- a/patches/server/0131-Add-option-to-make-parrots-stay-on-shoulders-despite.patch
+++ b/patches/server/0131-Add-option-to-make-parrots-stay-on-shoulders-despite.patch
@@ -11,10 +11,10 @@ I suspect Mojang may switch to this behavior before full release.
To be converted into a Paper-API event at some point in the future?
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-index 44daf6210786748f44275a97ecebbd191837b5e5..7bf555082539dc6cc4151df875b048b85fdba020 100644
+index 21e1520e30a4655c679b3f3b4f8f8e053f245aca..7a55caac4bf216484780e243ae2b58798ceea520 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-@@ -2438,6 +2438,13 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -2444,6 +2444,13 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
switch (packet.getAction()) {
case PRESS_SHIFT_KEY:
this.player.setShiftKeyDown(true);
diff --git a/patches/server/0157-handle-ServerboundKeepAlivePacket-async.patch b/patches/server/0157-handle-ServerboundKeepAlivePacket-async.patch
index 18988ee1e2..7d5c9f0cac 100644
--- a/patches/server/0157-handle-ServerboundKeepAlivePacket-async.patch
+++ b/patches/server/0157-handle-ServerboundKeepAlivePacket-async.patch
@@ -15,10 +15,10 @@ also adding some additional logging in order to help work out what is causing
random disconnections for clients.
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-index f7da31103f75e6bdc06f28a35e3341ec360bd245..49f7840a04f12ae6a28f3e0282d3e4529496c736 100644
+index 12325f4eafb7c7f4fd273464c1244d8c4f99fce7..d2641f1aad42f9e3930e5fe106a3a40f833e3945 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-@@ -3211,14 +3211,18 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -3217,14 +3217,18 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
@Override
public void handleKeepAlive(ServerboundKeepAlivePacket packet) {
diff --git a/patches/server/0189-Fix-exploit-that-allowed-colored-signs-to-be-created.patch b/patches/server/0189-Fix-exploit-that-allowed-colored-signs-to-be-created.patch
index 22d93ebb58..856af4a308 100644
--- a/patches/server/0189-Fix-exploit-that-allowed-colored-signs-to-be-created.patch
+++ b/patches/server/0189-Fix-exploit-that-allowed-colored-signs-to-be-created.patch
@@ -5,10 +5,10 @@ Subject: [PATCH] Fix exploit that allowed colored signs to be created
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-index dc3725622f8ae2832ff4329aa78395c5cc67c02f..5bd5cde911520eb0da695b961867a52845ad416f 100644
+index b465bf1a3ffa9fd164592967c6ebbab85f374a73..a0b52f23170cc7b75b556dd8223c16881abd7f3b 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-@@ -3217,9 +3217,9 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -3223,9 +3223,9 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
FilteredText filteredtext = (FilteredText) signText.get(i);
if (this.player.isTextFilteringEnabled()) {
diff --git a/patches/server/0215-InventoryCloseEvent-Reason-API.patch b/patches/server/0215-InventoryCloseEvent-Reason-API.patch
index d92c40acec..bb5e6bb71f 100644
--- a/patches/server/0215-InventoryCloseEvent-Reason-API.patch
+++ b/patches/server/0215-InventoryCloseEvent-Reason-API.patch
@@ -29,7 +29,7 @@ index 3d3926a14229d922fb7b7e76c9babb031bf7d9ab..5029436157fe7279a2a583f06b7d02a0
}
// Spigot End
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-index a9497e21c87e785631788968bc4922f6261169f9..522c8791edd87feb6cb32ef8e621ae35e53c9cb1 100644
+index dac7d458f161bc7449fee7142ac6cc95bf92388d..c14854f653342a6c4c8e520c3821866472d3c8af 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -610,7 +610,7 @@ public class ServerPlayer extends Player {
@@ -75,7 +75,7 @@ index a9497e21c87e785631788968bc4922f6261169f9..522c8791edd87feb6cb32ef8e621ae35
this.doCloseContainer();
}
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-index 5bd5cde911520eb0da695b961867a52845ad416f..57e3301e5b18d90d6f499fa6a544866a5eca01a9 100644
+index a0b52f23170cc7b75b556dd8223c16881abd7f3b..231e3dfecbc2fee1889f29821201a574f22d73e5 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -216,6 +216,7 @@ import org.bukkit.event.inventory.ClickType;
@@ -86,7 +86,7 @@ index 5bd5cde911520eb0da695b961867a52845ad416f..57e3301e5b18d90d6f499fa6a544866a
import org.bukkit.event.inventory.InventoryCreativeEvent;
import org.bukkit.event.inventory.InventoryType.SlotType;
import org.bukkit.event.inventory.SmithItemEvent;
-@@ -2743,10 +2744,15 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -2749,10 +2750,15 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
@Override
public void handleContainerClose(ServerboundContainerClosePacket packet) {
@@ -104,7 +104,7 @@ index 5bd5cde911520eb0da695b961867a52845ad416f..57e3301e5b18d90d6f499fa6a544866a
this.player.doCloseContainer();
}
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
-index 29f761432be28b5089caab9338b3bff41f4f8f07..2ad88d72a9d14c7e73a824544a1ebcb6bb74a127 100644
+index 861f736c32d85abbce8dfade503ec0976aa7a275..a7d7882652c9361f37dfcbaec3872a50e048b4b9 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -507,7 +507,7 @@ public abstract class PlayerList {
@@ -173,7 +173,7 @@ index 4ff81744b7c9113f57cf1fa89bb943902711b2dc..404ed5e8f54d70a50de4232c6ea0f616
@Override
public boolean isBlocking() {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
-index c63831b9ec29ea1589cc87fbe4615f6dfddce473..f5259ada3e21b036fd3e3b96d727f1c8c4a042b8 100644
+index 3ff83fcee396b220cc1977f85ce3af399a4c2802..0c6226292f1928f657ea77529992123ad6f7bc9b 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -1079,7 +1079,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
diff --git a/patches/server/0217-Refresh-player-inventory-when-cancelling-PlayerInter.patch b/patches/server/0217-Refresh-player-inventory-when-cancelling-PlayerInter.patch
index 3bb306582c..94dfab8113 100644
--- a/patches/server/0217-Refresh-player-inventory-when-cancelling-PlayerInter.patch
+++ b/patches/server/0217-Refresh-player-inventory-when-cancelling-PlayerInter.patch
@@ -16,10 +16,10 @@ Refresh the player inventory when PlayerInteractEntityEvent is
cancelled to avoid this problem.
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-index 57e3301e5b18d90d6f499fa6a544866a5eca01a9..15e69839cb1da5f0402e9abd155fb67d323b8f5d 100644
+index 231e3dfecbc2fee1889f29821201a574f22d73e5..b3570e63957efea26e1538f1cb44304c22b84040 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-@@ -2628,6 +2628,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -2634,6 +2634,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
}
if (event.isCancelled()) {
diff --git a/patches/server/0271-Call-player-spectator-target-events-and-improve-impl.patch b/patches/server/0271-Call-player-spectator-target-events-and-improve-impl.patch
index b3d594b2dd..bc8632e576 100644
--- a/patches/server/0271-Call-player-spectator-target-events-and-improve-impl.patch
+++ b/patches/server/0271-Call-player-spectator-target-events-and-improve-impl.patch
@@ -19,10 +19,10 @@ spectate the target entity.
Co-authored-by: Spottedleaf
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-index 1b3188837069622baaba90c80fe387abfbfad10a..f9cd8040f0782c0c0543c8a9f52727ba838f987f 100644
+index 56b1c585d1c330bf9b904ebf8ef0b8be47102aa3..e4f991578d4ee581e65f2edb7d32640ff36a01bd 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-@@ -1870,14 +1870,58 @@ public class ServerPlayer extends Player {
+@@ -1875,14 +1875,58 @@ public class ServerPlayer extends Player {
}
public void setCamera(@Nullable Entity entity) {
diff --git a/patches/server/0277-Reset-players-airTicks-on-respawn.patch b/patches/server/0277-Reset-players-airTicks-on-respawn.patch
index 4263234b5a..604f55e563 100644
--- a/patches/server/0277-Reset-players-airTicks-on-respawn.patch
+++ b/patches/server/0277-Reset-players-airTicks-on-respawn.patch
@@ -5,10 +5,10 @@ Subject: [PATCH] Reset players airTicks on respawn
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-index f9cd8040f0782c0c0543c8a9f52727ba838f987f..ca3206ad7c6e4acf31eda406c439fc7c70e47c01 100644
+index e4f991578d4ee581e65f2edb7d32640ff36a01bd..c5120e5e7414a6b870eab877605e9bb52db3e8cb 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-@@ -2283,6 +2283,7 @@ public class ServerPlayer extends Player {
+@@ -2288,6 +2288,7 @@ public class ServerPlayer extends Player {
this.setHealth(this.getMaxHealth());
this.stopUsingItem(); // CraftBukkit - SPIGOT-6682: Clear active item on reset
diff --git a/patches/server/0300-Limit-Client-Sign-length-more.patch b/patches/server/0300-Limit-Client-Sign-length-more.patch
index 798d1e7df2..f85faa474d 100644
--- a/patches/server/0300-Limit-Client-Sign-length-more.patch
+++ b/patches/server/0300-Limit-Client-Sign-length-more.patch
@@ -22,7 +22,7 @@ it only impacts data sent from the client.
Set -DPaper.maxSignLength=XX to change limit or -1 to disable
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-index ed272499b40a96efd83f1a09a063e4d65dbe48e8..32c89f89fc9dbcdc9528acf46415b4d7c6475ff3 100644
+index 9c0d8f6cb9e447d33f04535d96f2fc8d11d66cf7..fff1873ee166d9fae98474ee81f6509c561b3b64 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -293,6 +293,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
@@ -33,7 +33,7 @@ index ed272499b40a96efd83f1a09a063e4d65dbe48e8..32c89f89fc9dbcdc9528acf46415b4d7
public ServerGamePacketListenerImpl(MinecraftServer server, Connection connection, ServerPlayer player) {
this.lastChatTimeStamp = new AtomicReference(Instant.EPOCH);
-@@ -3262,7 +3263,19 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -3268,7 +3269,19 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
@Override
public void handleSignUpdate(ServerboundSignUpdatePacket packet) {
diff --git a/patches/server/0307-Update-entity-Metadata-for-all-tracked-players.patch b/patches/server/0307-Update-entity-Metadata-for-all-tracked-players.patch
index 2558096b58..a716efd34e 100644
--- a/patches/server/0307-Update-entity-Metadata-for-all-tracked-players.patch
+++ b/patches/server/0307-Update-entity-Metadata-for-all-tracked-players.patch
@@ -22,10 +22,10 @@ index d6f34adbdf45bbef4a39e629dd7cb6d7fcb5db0f..7881176a900daa3306c691454f688c1f
this.broadcast.accept(packet);
if (this.entity instanceof ServerPlayer) {
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-index 32c89f89fc9dbcdc9528acf46415b4d7c6475ff3..30b65246eacf2955a52bbf46856ca82ae9e1d5cb 100644
+index fff1873ee166d9fae98474ee81f6509c561b3b64..29e6f4726016a62b22588f0efd0284e49fe5a33b 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-@@ -2703,7 +2703,14 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -2709,7 +2709,14 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
if (event.isCancelled() || ServerGamePacketListenerImpl.this.player.getInventory().getSelected() == null || ServerGamePacketListenerImpl.this.player.getInventory().getSelected().getItem() != origItem) {
// Refresh the current entity metadata
diff --git a/patches/server/0332-Dont-send-unnecessary-sign-update.patch b/patches/server/0332-Dont-send-unnecessary-sign-update.patch
index 8eeda30cd5..f4756b4270 100644
--- a/patches/server/0332-Dont-send-unnecessary-sign-update.patch
+++ b/patches/server/0332-Dont-send-unnecessary-sign-update.patch
@@ -5,10 +5,10 @@ Subject: [PATCH] Dont send unnecessary sign update
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-index 83d9eac28a08bc075904d274effed54de77be6bf..00f9b6213a7289ea8d48fcf41d701bde5497006d 100644
+index 4e4af6e79c126a8b21dea16cb0311e80e23f1d66..ae42daea9aaca1f0c19c26232e51e185353fe717 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-@@ -3307,6 +3307,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -3313,6 +3313,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
if (!tileentitysign.isEditable() || !this.player.getUUID().equals(tileentitysign.getPlayerWhoMayEdit())) {
ServerGamePacketListenerImpl.LOGGER.warn("Player {} just tried to change non-editable sign", this.player.getName().getString());
diff --git a/patches/server/0373-Add-tick-times-API-and-mspt-command.patch b/patches/server/0373-Add-tick-times-API-and-mspt-command.patch
index 2206f80a2f..6f4253e903 100644
--- a/patches/server/0373-Add-tick-times-API-and-mspt-command.patch
+++ b/patches/server/0373-Add-tick-times-API-and-mspt-command.patch
@@ -125,7 +125,7 @@ index 6a00f3d38da8107825ab1d405f337fd077b09f72..d31b5ed47cffc61c90c926a0cd2005b7
public static void registerCommands(final MinecraftServer server) {
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
-index 19f38a8d66846d859dd46fb53f3224fe0d7f2eb8..f5fc952e119723d7761408d8ffb95e869d01cb81 100644
+index e8b826e431229b80fbba2bcdaed2105e6a9bcbdd..7b646a46d561c3cdb03a488d691e811d40684417 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -237,6 +237,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop queue = Queues.newConcurrentLinkedQueue();
-diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
-index af2d703fe3cb74ced502ca89c5bf6ca1f47474bb..7ca8941ade15c073939c198334bfba78dfcc3c08 100644
---- a/src/main/java/net/minecraft/server/MinecraftServer.java
-+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
-@@ -2527,7 +2527,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop {
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
index 648bc209938364a387c3f81dcd073db398e9f864..e42df2956e2d852a5a4c8fdeda395a3efd32c44c 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
diff --git a/patches/server/0438-Add-and-implement-PlayerRecipeBookClickEvent.patch b/patches/server/0438-Add-and-implement-PlayerRecipeBookClickEvent.patch
index 3afe5c911a..58f445f747 100644
--- a/patches/server/0438-Add-and-implement-PlayerRecipeBookClickEvent.patch
+++ b/patches/server/0438-Add-and-implement-PlayerRecipeBookClickEvent.patch
@@ -5,10 +5,10 @@ Subject: [PATCH] Add and implement PlayerRecipeBookClickEvent
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-index a42d153d861134a1255e302b44b291f6f36132ce..38f514320de5a2b3c09e288f7fb1b88c1662e9f8 100644
+index 6d4923a8a563918cf9db73f1f6e1ef5699d10a79..651bf74a4d09e2d0611f86a8e865c065cb0e9327 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-@@ -3204,9 +3204,15 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -3210,9 +3210,15 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
if (!this.player.containerMenu.stillValid(this.player)) {
ServerGamePacketListenerImpl.LOGGER.debug("Player {} interacted with invalid menu {}", this.player, this.player.containerMenu);
} else {
diff --git a/patches/server/0442-Fix-Per-World-Difficulty-Remembering-Difficulty.patch b/patches/server/0442-Fix-Per-World-Difficulty-Remembering-Difficulty.patch
index ddd5e571ee..6b5d169a95 100644
--- a/patches/server/0442-Fix-Per-World-Difficulty-Remembering-Difficulty.patch
+++ b/patches/server/0442-Fix-Per-World-Difficulty-Remembering-Difficulty.patch
@@ -8,7 +8,7 @@ makes it so that the server keeps the last difficulty used instead
of restoring the server.properties every single load.
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
-index e2ba646cf628c3791e8a5b1195f985cb1b3e6916..546ee711f3a11789647b021383841a332cc9c72f 100644
+index aeaa34a17e7d0240a87a62a8a7cc5ca620b16d2b..db490f74834715c8382a9c5ff076d7e89fd4dec3 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -791,7 +791,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0) {
--this.chatSpamTickCount;
-@@ -3223,6 +3225,14 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -3229,6 +3231,14 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
@Override
public void handlePlaceRecipe(ServerboundPlaceRecipePacket packet) {
diff --git a/patches/server/0537-Player-Chunk-Load-Unload-Events.patch b/patches/server/0537-Player-Chunk-Load-Unload-Events.patch
index fcd60beef6..f00bed613a 100644
--- a/patches/server/0537-Player-Chunk-Load-Unload-Events.patch
+++ b/patches/server/0537-Player-Chunk-Load-Unload-Events.patch
@@ -5,10 +5,10 @@ Subject: [PATCH] Player Chunk Load/Unload Events
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-index 8c6f55efb555c9ca7253ccc1cd9ba615cfb1171c..345091d6ba617c26ac7acfd88eb023f2ec8fae11 100644
+index 6cb4cda5235ca6c54158d6980526e3d5fceae829..5f1ec63ae45cf3f53cb6c5b55ccdb3962b1ebd72 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-@@ -2129,11 +2129,21 @@ public class ServerPlayer extends Player {
+@@ -2134,11 +2134,21 @@ public class ServerPlayer extends Player {
public void trackChunk(ChunkPos chunkPos, Packet> chunkDataPacket) {
this.connection.send(chunkDataPacket);
diff --git a/patches/server/0552-Fix-interact-event-not-being-called-in-adventure.patch b/patches/server/0552-Fix-interact-event-not-being-called-in-adventure.patch
index 81fb0381c6..a517033341 100644
--- a/patches/server/0552-Fix-interact-event-not-being-called-in-adventure.patch
+++ b/patches/server/0552-Fix-interact-event-not-being-called-in-adventure.patch
@@ -6,7 +6,7 @@ Subject: [PATCH] Fix interact event not being called in adventure
Call PlayerInteractEvent when left-clicking on a block in adventure mode
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-index 7f91a1129a7702a4cff001de791514a37f9def09..6525d8cee86928158dfd121ff11d18b088898a67 100644
+index a514912127a6a353b98d29c336e9b8d2c0c0ec8b..52e928b0ca0e3b0c31a80cc2b3d3deba07d41da8 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -1845,7 +1845,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
@@ -18,7 +18,7 @@ index 7f91a1129a7702a4cff001de791514a37f9def09..6525d8cee86928158dfd121ff11d18b0
this.player.swing(enumhand, true);
}
}
-@@ -2591,7 +2591,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -2597,7 +2597,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
Vec3 vec3d1 = vec3d.add((double) f7 * d3, (double) f6 * d3, (double) f8 * d3);
HitResult movingobjectposition = this.player.level.clip(new ClipContext(vec3d, vec3d1, ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, this.player));
diff --git a/patches/server/0631-add-RespawnFlags-to-PlayerRespawnEvent.patch b/patches/server/0631-add-RespawnFlags-to-PlayerRespawnEvent.patch
index b31b543aa1..460c5868ea 100644
--- a/patches/server/0631-add-RespawnFlags-to-PlayerRespawnEvent.patch
+++ b/patches/server/0631-add-RespawnFlags-to-PlayerRespawnEvent.patch
@@ -5,10 +5,10 @@ Subject: [PATCH] add RespawnFlags to PlayerRespawnEvent
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-index 125cc1951c785fd1a75569f57f779626a1fbe586..035b8a49c3647be3c2e6478767078d6dd14e6208 100644
+index e23c6bad7e0b83c4eae581ac638f2e7b2a32458e..5e8f6f36d259526e97d926ed83ef0e6d7b618021 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-@@ -2876,7 +2876,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -2882,7 +2882,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
case PERFORM_RESPAWN:
if (this.player.wonGame) {
this.player.wonGame = false;
@@ -18,7 +18,7 @@ index 125cc1951c785fd1a75569f57f779626a1fbe586..035b8a49c3647be3c2e6478767078d6d
} else {
if (this.player.getHealth() > 0.0F) {
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
-index f58f35cdab48066688cf4cf16fc4819229d2191d..bdb37391b9df7ec4983728de8324aa3f1ed20f4b 100644
+index 9f50af39555a90fd4e3b9131286107b9ef971270..3adc2fcded1d7bb7cb892eccc96f43facd404045 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -811,6 +811,12 @@ public abstract class PlayerList {
diff --git a/patches/server/0644-additions-to-PlayerGameModeChangeEvent.patch b/patches/server/0644-additions-to-PlayerGameModeChangeEvent.patch
index a08c959134..e6ee25d000 100644
--- a/patches/server/0644-additions-to-PlayerGameModeChangeEvent.patch
+++ b/patches/server/0644-additions-to-PlayerGameModeChangeEvent.patch
@@ -45,7 +45,7 @@ index 65089c0e78c9913a92ae9c66d664f48e2112ad92..7882ee2b7813d437d3b7580f046f38e7
}
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-index d8bbab6af9625cdb411df0099261f97f59daacb4..607a44d2db927e579d8be7c52021d7bb205a379c 100644
+index ec46dda11b527e2e31d8025416c83d11153edc8c..705201ced84717180b9b6cfc2111f0557cca56ab 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -1810,8 +1810,15 @@ public class ServerPlayer extends Player {
@@ -75,7 +75,7 @@ index d8bbab6af9625cdb411df0099261f97f59daacb4..607a44d2db927e579d8be7c52021d7bb
}
}
-@@ -2220,6 +2227,16 @@ public class ServerPlayer extends Player {
+@@ -2225,6 +2232,16 @@ public class ServerPlayer extends Player {
}
public void loadGameTypes(@Nullable CompoundTag nbt) {
@@ -126,10 +126,10 @@ index 32746dfbc2fdfc150583676b1bf0762398b76d75..1ad1f958a9b6e1bc21f1c505aa7ea549
}
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-index 035b8a49c3647be3c2e6478767078d6dd14e6208..9ad786bb2fd516e167c3ec55e854155d64dd73a5 100644
+index 5e8f6f36d259526e97d926ed83ef0e6d7b618021..2ee76d9c5fb22e792618d8c865e7fb9a335202a6 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-@@ -2885,7 +2885,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -2891,7 +2891,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
this.player = this.server.getPlayerList().respawn(this.player, false);
if (this.server.isHardcore()) {
@@ -139,7 +139,7 @@ index 035b8a49c3647be3c2e6478767078d6dd14e6208..9ad786bb2fd516e167c3ec55e854155d
}
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
-index c6019b688eed5426e21f2950065363268f8285a5..60024a387429a13593f7f709004282d27678cbbe 100644
+index f2af098691d3e6951e17645c3eee019000fb4882..c65621c97f05ee5c7be0fd485b6fb9c703d00406 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -1396,7 +1396,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
diff --git a/patches/server/0656-Add-PlayerKickEvent-causes.patch b/patches/server/0656-Add-PlayerKickEvent-causes.patch
index f19ccd3c47..c19226712e 100644
--- a/patches/server/0656-Add-PlayerKickEvent-causes.patch
+++ b/patches/server/0656-Add-PlayerKickEvent-causes.patch
@@ -5,7 +5,7 @@ Subject: [PATCH] Add PlayerKickEvent causes
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
-index db60b41f7da9caebfb798ed39ccac51d15bd1324..1376f0aa4ec2c37a64d208168c0160255aa4899b 100644
+index 2ea4e4ecae33ba42d559133453fea064b8359d46..2fb7bdb18f1528fd496971b5f9445339b4239720 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -2101,7 +2101,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 200 && !this.server.getPlayerList().isOp(this.player.getGameProfile())) {
// CraftBukkit end
@@ -285,7 +285,7 @@ index 2217d9b3bb589278da5b421ffce9e00261d08469..26b0bc810b4b09df9c910e3b8b49c18d
}
}
-@@ -2577,7 +2587,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -2583,7 +2593,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
private void handleValidationFailure(Set reasons) {
ServerGamePacketListenerImpl.LOGGER.warn("Failed to validate message from {}, reasons: {}", this.player.getName().getString(), reasons.stream().map(LastSeenMessagesValidator.ErrorCondition::message).collect(Collectors.joining(",")));
@@ -294,7 +294,7 @@ index 2217d9b3bb589278da5b421ffce9e00261d08469..26b0bc810b4b09df9c910e3b8b49c18d
}
@Override
-@@ -2724,7 +2734,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -2730,7 +2740,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
}
if (i > 4096) {
@@ -303,7 +303,7 @@ index 2217d9b3bb589278da5b421ffce9e00261d08469..26b0bc810b4b09df9c910e3b8b49c18d
}
}
-@@ -2739,7 +2749,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -2745,7 +2755,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
// Spigot Start
if ( entity == this.player && !this.player.isSpectator() )
{
@@ -312,7 +312,7 @@ index 2217d9b3bb589278da5b421ffce9e00261d08469..26b0bc810b4b09df9c910e3b8b49c18d
return;
}
// Spigot End
-@@ -2832,7 +2842,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -2838,7 +2848,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
}
// CraftBukkit end
} else {
@@ -321,7 +321,7 @@ index 2217d9b3bb589278da5b421ffce9e00261d08469..26b0bc810b4b09df9c910e3b8b49c18d
ServerGamePacketListenerImpl.LOGGER.warn("Player {} tried to attack an invalid entity", ServerGamePacketListenerImpl.this.player.getName().getString());
}
}
-@@ -3240,7 +3250,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -3246,7 +3256,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
// Paper start
if (!org.bukkit.Bukkit.isPrimaryThread()) {
if (recipeSpamPackets.addAndGet(io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.recipeSpamIncrement) > io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.recipeSpamLimit) {
@@ -330,7 +330,7 @@ index 2217d9b3bb589278da5b421ffce9e00261d08469..26b0bc810b4b09df9c910e3b8b49c18d
return;
}
}
-@@ -3443,7 +3453,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -3449,7 +3459,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
} else if (!this.isSingleplayerOwner()) {
// Paper start - This needs to be handled on the main thread for plugins
server.submit(() -> {
@@ -339,7 +339,7 @@ index 2217d9b3bb589278da5b421ffce9e00261d08469..26b0bc810b4b09df9c910e3b8b49c18d
});
// Paper end
}
-@@ -3489,7 +3499,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -3495,7 +3505,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
}
} catch (Exception ex) {
ServerGamePacketListenerImpl.LOGGER.error("Couldn\'t register custom payload", ex);
@@ -348,7 +348,7 @@ index 2217d9b3bb589278da5b421ffce9e00261d08469..26b0bc810b4b09df9c910e3b8b49c18d
}
} else if (packet.identifier.equals(CUSTOM_UNREGISTER)) {
try {
-@@ -3499,7 +3509,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -3505,7 +3515,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
}
} catch (Exception ex) {
ServerGamePacketListenerImpl.LOGGER.error("Couldn\'t unregister custom payload", ex);
@@ -357,7 +357,7 @@ index 2217d9b3bb589278da5b421ffce9e00261d08469..26b0bc810b4b09df9c910e3b8b49c18d
}
} else {
try {
-@@ -3517,7 +3527,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -3523,7 +3533,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
this.cserver.getMessenger().dispatchIncomingMessage(this.player.getBukkitEntity(), packet.identifier.toString(), data);
} catch (Exception ex) {
ServerGamePacketListenerImpl.LOGGER.error("Couldn\'t dispatch custom payload", ex);
@@ -367,7 +367,7 @@ index 2217d9b3bb589278da5b421ffce9e00261d08469..26b0bc810b4b09df9c910e3b8b49c18d
}
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
-index bdb37391b9df7ec4983728de8324aa3f1ed20f4b..ca0ad4fd5f4aafacd197494970f2aec3b2a6c4d0 100644
+index 3adc2fcded1d7bb7cb892eccc96f43facd404045..e6a5c5da58403ca5498d8741bc520b8e68c56310 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -720,7 +720,7 @@ public abstract class PlayerList {
diff --git a/patches/server/0671-Fix-PlayerDropItemEvent-using-wrong-item.patch b/patches/server/0671-Fix-PlayerDropItemEvent-using-wrong-item.patch
index c053f7f56a..fb4745c873 100644
--- a/patches/server/0671-Fix-PlayerDropItemEvent-using-wrong-item.patch
+++ b/patches/server/0671-Fix-PlayerDropItemEvent-using-wrong-item.patch
@@ -5,10 +5,10 @@ Subject: [PATCH] Fix PlayerDropItemEvent using wrong item
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-index 607a44d2db927e579d8be7c52021d7bb205a379c..6e53214042ab515d9c66fb24f6aa1c07d6c3539d 100644
+index 705201ced84717180b9b6cfc2111f0557cca56ab..af1aedd970778e69845f093581ad401da5e99adb 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-@@ -2196,7 +2196,7 @@ public class ServerPlayer extends Player {
+@@ -2201,7 +2201,7 @@ public class ServerPlayer extends Player {
if (retainOwnership) {
if (!itemstack1.isEmpty()) {
diff --git a/patches/server/0677-Adds-PlayerArmSwingEvent.patch b/patches/server/0677-Adds-PlayerArmSwingEvent.patch
index c3c42ead1c..d4afb0ed5b 100644
--- a/patches/server/0677-Adds-PlayerArmSwingEvent.patch
+++ b/patches/server/0677-Adds-PlayerArmSwingEvent.patch
@@ -5,10 +5,10 @@ Subject: [PATCH] Adds PlayerArmSwingEvent
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-index 685745b853f86fa2eda031ad20317ad321b1379a..c65c72a2dd3c87621c1369c52770b912057eafd2 100644
+index 87cdc22491da7deb4d61809bed6aea8bf44a6fbb..302f7ee99460efba88eabfa661ad6f6a46e92d17 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-@@ -2618,7 +2618,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -2624,7 +2624,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
}
// Arm swing animation
diff --git a/patches/server/0692-Add-PlayerSetSpawnEvent.patch b/patches/server/0692-Add-PlayerSetSpawnEvent.patch
index b1aa1739f5..878b72133b 100644
--- a/patches/server/0692-Add-PlayerSetSpawnEvent.patch
+++ b/patches/server/0692-Add-PlayerSetSpawnEvent.patch
@@ -32,7 +32,7 @@ index ce1c7512cc368e196ae94ee22c6a228c975b4980..1e41de9523c5fa3b9cfced798a5c35a2
String string = resourceKey.location().toString();
if (targets.size() == 1) {
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-index f523311e822af9cbef571338fd8fef177b9fc73d..ec713ffb7c4cba53dc983ebde5596e4749107493 100644
+index 5ef42e8e69169995f2c36ec332500f0307e84337..17f7ecafb2b0877b140353323b5972fb90e558e0 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -1287,7 +1287,7 @@ public class ServerPlayer extends Player {
@@ -44,7 +44,7 @@ index f523311e822af9cbef571338fd8fef177b9fc73d..ec713ffb7c4cba53dc983ebde5596e47
if (this.level.isDay()) {
return Either.left(Player.BedSleepingProblem.NOT_POSSIBLE_NOW);
} else {
-@@ -2123,12 +2123,33 @@ public class ServerPlayer extends Player {
+@@ -2128,12 +2128,33 @@ public class ServerPlayer extends Player {
return this.respawnForced;
}
@@ -80,7 +80,7 @@ index f523311e822af9cbef571338fd8fef177b9fc73d..ec713ffb7c4cba53dc983ebde5596e47
}
this.respawnPosition = pos;
-@@ -2142,6 +2163,7 @@ public class ServerPlayer extends Player {
+@@ -2147,6 +2168,7 @@ public class ServerPlayer extends Player {
this.respawnForced = false;
}
@@ -89,7 +89,7 @@ index f523311e822af9cbef571338fd8fef177b9fc73d..ec713ffb7c4cba53dc983ebde5596e47
public void trackChunk(ChunkPos chunkPos, Packet> chunkDataPacket) {
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
-index 0354b7e20bbc9f888cf85d6db42ce2b64a25b4c2..76fa5e31701bc0e504d8e7b6ebfa737f3a10dc3b 100644
+index 10231f5a811a8b4510ef063a9de2f8b386570cbe..84b3a86b5fd77dbdedbe4b45f5a67f113e2c8e48 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -896,13 +896,13 @@ public abstract class PlayerList {
@@ -129,7 +129,7 @@ index c3e49a781f838e6a46cb89744f3f1846de182275..c2f3d3a09327e7cb7d3167609eb3ce68
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
-index d72e5c06ab4f34742ec74448d1cad892048f159b..fa85a7be4a131b7ae8a5d2aae78a82fcd53e5967 100644
+index aaa50b04ae3dc49fa93ca408442abd540a4e4b7a..05529f795672636ce43c6fbab73f9ada459cdcb9 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -1216,9 +1216,9 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
diff --git a/patches/server/0737-Execute-chunk-tasks-mid-tick.patch b/patches/server/0737-Execute-chunk-tasks-mid-tick.patch
index ac2df1c4ad..9602f9b1f5 100644
--- a/patches/server/0737-Execute-chunk-tasks-mid-tick.patch
+++ b/patches/server/0737-Execute-chunk-tasks-mid-tick.patch
@@ -19,7 +19,7 @@ index 23e564b05ba438924180c91f9b19a60731eedd1b..5ec241d49ff5e3a161a39006f05823a5
private MinecraftTimings() {}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
-index a7610894e05c763ce405c0a2d91665b83d02980a..097eb29a9fd94d49ff5df71110d250a03d6e4c45 100644
+index 660e1b6955115d67cb37161ef556f90acc53bdfa..621956c024d64bcaa868e0bb01c485fe4ac11df3 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1303,6 +1303,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { // Paper - push to main
this.disconnect(Component.translatable("multiplayer.disconnect.out_of_order_chat"), org.bukkit.event.player.PlayerKickEvent.Cause.OUT_OF_ORDER_CHAT); // Paper - kick event cause
}); // Paper - push to main
-@@ -2552,7 +2552,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -2555,7 +2555,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
return false;
} else {
if (message.hasExpiredServer(Instant.now())) {
diff --git a/patches/server/0919-Fix-Spigot-Config-not-using-commands.spam-exclusions.patch b/patches/server/0919-Fix-Spigot-Config-not-using-commands.spam-exclusions.patch
index 9d90007654..ff5e37f8fc 100644
--- a/patches/server/0919-Fix-Spigot-Config-not-using-commands.spam-exclusions.patch
+++ b/patches/server/0919-Fix-Spigot-Config-not-using-commands.spam-exclusions.patch
@@ -5,10 +5,10 @@ Subject: [PATCH] Fix Spigot Config not using commands.spam-exclusions
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-index cdf7ed204cf6216337ab9667158b33143c82a819..72864ca3f0fa94512d7f57b4e05929be7d2912cd 100644
+index c384e715a54248e3bf2e1dc02acc118ec9fcfa1d..736ef6024285866fd372e5449b5eb55633e7ddf9 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-@@ -2573,7 +2573,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+@@ -2576,7 +2576,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
}
// Spigot end
// this.chatSpamTickCount += 20;
diff --git a/patches/server/0924-Send-block-entities-after-destroy-prediction.patch b/patches/server/0924-Send-block-entities-after-destroy-prediction.patch
index c5f9f02261..d83705065c 100644
--- a/patches/server/0924-Send-block-entities-after-destroy-prediction.patch
+++ b/patches/server/0924-Send-block-entities-after-destroy-prediction.patch
@@ -57,7 +57,7 @@ index 9378e83a67a70dbb1fb4f05b33f1e553d008e62b..5a60f5dc202c44b06ca34e9a19d45cb7
}
}
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-index adb9cde74295830e74241e522ae5766d436aadb1..ff7df8026f85b7ad51458a0b720a8baf71cd9bd1 100644
+index 8e32bf0deacd966a1bfeef7c57455be4ccfdadda..01a498536497db7ab0f3ebac80fb022b356385c8 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -1873,8 +1873,28 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic