diff --git a/Spigot-API-Patches/0222-Brand-support.patch b/Spigot-API-Patches/0221-Brand-support.patch similarity index 100% rename from Spigot-API-Patches/0222-Brand-support.patch rename to Spigot-API-Patches/0221-Brand-support.patch diff --git a/Spigot-API-Patches/Adventure.patch b/Spigot-API-Patches/Adventure.patch index ef67b894d2..43d9b63a44 100644 --- a/Spigot-API-Patches/Adventure.patch +++ b/Spigot-API-Patches/Adventure.patch @@ -20,7 +20,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + net.kyori + adventure-bom -+ 4.5.1 ++ 4.6.0 + pom + import + @@ -55,10 +55,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 https://javadoc.io/doc/org.jetbrains/annotations-java5/20.1.0/ https://javadoc.io/doc/net.md-5/bungeecord-chat/1.16-R0.4/ + -+ https://jd.adventure.kyori.net/api/4.5.1/ -+ https://jd.adventure.kyori.net/text-serializer-gson/4.5.1/ -+ https://jd.adventure.kyori.net/text-serializer-legacy/4.5.1/ -+ https://jd.adventure.kyori.net/text-serializer-plain/4.5.1/ ++ https://jd.adventure.kyori.net/api/4.6.0/ ++ https://jd.adventure.kyori.net/text-serializer-gson/4.6.0/ ++ https://jd.adventure.kyori.net/text-serializer-legacy/4.6.0/ ++ https://jd.adventure.kyori.net/text-serializer-plain/4.6.0/ + @@ -94,6 +94,214 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end } +diff --git a/src/main/java/io/papermc/paper/chat/ChatFormatter.java b/src/main/java/io/papermc/paper/chat/ChatFormatter.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/chat/ChatFormatter.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.chat; ++ ++import net.kyori.adventure.text.Component; ++import org.bukkit.entity.Player; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * A chat formatter is responsible for the formatting of chat messages sent by {@link Player}s to the server. ++ */ ++@FunctionalInterface ++public interface ChatFormatter { ++ // This format might be different than the CraftBukkit one? ++ ChatFormatter DEFAULT = (displayName, message) -> Component.translatable("chat.type.text", displayName, message); ++ ++ /** ++ * Formats a chat message. ++ * ++ * @param displayName the display name of the {@link Player} sending the message ++ * @param message the chat message ++ * @return a formatted chat message ++ */ ++ @NotNull ++ Component chat(final @NotNull Component displayName, final @NotNull Component message); ++} +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..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/AbstractChatEvent.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.event.player; ++ ++import io.papermc.paper.chat.ChatFormatter; ++import java.util.Objects; ++import java.util.Set; ++import net.kyori.adventure.text.Component; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.player.PlayerEvent; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * An abstract implementation of a chat event, handling shared logic. ++ */ ++public abstract class AbstractChatEvent extends PlayerEvent implements Cancellable { ++ private final Set recipients; ++ private boolean cancelled = false; ++ private ChatFormatter formatter; ++ private Component message; ++ ++ AbstractChatEvent(final boolean async, final @NotNull Player player, final @NotNull Set recipients, final @NotNull ChatFormatter formatter, final @NotNull Component message) { ++ super(player, async); ++ this.recipients = recipients; ++ this.formatter = formatter; ++ this.message = message; ++ } ++ ++ /** ++ * Gets a set of recipients that this chat message will be displayed to. ++ * ++ *

The set returned is not guaranteed to be mutable and may auto-populate ++ * on access. Any listener accessing the returned set should be aware that ++ * it may reduce performance for a lazy set implementation.

++ * ++ *

Listeners should be aware that modifying the list may throw {@link ++ * UnsupportedOperationException} if the event caller provides an ++ * unmodifiable set.

++ * ++ * @return a set of players who will receive the chat message ++ */ ++ @NotNull ++ public final Set recipients() { ++ return this.recipients; ++ } ++ ++ /** ++ * Gets the chat formatter. ++ * ++ * @return the chat formatter ++ */ ++ @NotNull ++ public final ChatFormatter formatter() { ++ return this.formatter; ++ } ++ ++ /** ++ * Sets the chat formatter. ++ * ++ * @param formatter the chat formatter ++ * @throws NullPointerException if {@code formatter} is {@code null} ++ */ ++ public final void formatter(final @NotNull ChatFormatter formatter) { ++ this.formatter = Objects.requireNonNull(formatter, "formatter"); ++ } ++ ++ /** ++ * Gets the user-supplied message. ++ * ++ * @return the user-supplied message ++ */ ++ @NotNull ++ public final Component message() { ++ return this.message; ++ } ++ ++ /** ++ * Sets the user-supplied message. ++ * ++ * @param message the user-supplied message ++ * @throws NullPointerException if {@code message} is {@code null} ++ */ ++ public final void message(final @NotNull Component message) { ++ this.message = Objects.requireNonNull(message, "message"); ++ } ++ ++ @Override ++ public final boolean isCancelled() { ++ return this.cancelled; ++ } ++ ++ @Override ++ public final void setCancelled(final boolean cancelled) { ++ this.cancelled = cancelled; ++ } ++} +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..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/AsyncChatEvent.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.event.player; ++ ++import io.papermc.paper.chat.ChatFormatter; ++import java.util.Set; ++import net.kyori.adventure.text.Component; ++import org.bukkit.entity.Player; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * An event fired when a {@link Player} sends a chat message to the server. ++ */ ++public final class AsyncChatEvent extends AbstractChatEvent { ++ private static final HandlerList HANDLERS = new HandlerList(); ++ ++ public AsyncChatEvent(final boolean async, final @NotNull Player player, final @NotNull Set recipients, final @NotNull ChatFormatter formatter, final @NotNull Component message) { ++ super(async, player, recipients, formatter, message); ++ } ++ ++ @NotNull ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLERS; ++ } ++ ++ @NotNull ++ public static HandlerList getHandlerList() { ++ return HANDLERS; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/event/player/ChatEvent.java b/src/main/java/io/papermc/paper/event/player/ChatEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/player/ChatEvent.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.event.player; ++ ++import io.papermc.paper.chat.ChatFormatter; ++import java.util.Set; ++import net.kyori.adventure.text.Component; ++import org.bukkit.Warning; ++import org.bukkit.entity.Player; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * An event fired when a {@link Player} sends a chat message to the server. ++ * ++ * @deprecated Listening to this event forces chat to wait for the main thread, delaying chat messages. It is recommended to use {@link AsyncChatEvent} instead, wherever possible. ++ */ ++@Deprecated ++@Warning(reason = "Listening to this event forces chat to wait for the main thread, delaying chat messages.") ++public final class ChatEvent extends AbstractChatEvent { ++ private static final HandlerList HANDLERS = new HandlerList(); ++ ++ public ChatEvent(final @NotNull Player player, final @NotNull Set recipients, final @NotNull ChatFormatter formatter, final @NotNull Component message) { ++ super(false, player, recipients, formatter, message); ++ } ++ ++ @NotNull ++ @Override ++ public HandlerList getHandlers() { ++ return HANDLERS; ++ } ++ ++ @NotNull ++ public static HandlerList getHandlerList() { ++ return HANDLERS; ++ } ++} diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/Bukkit.java @@ -601,6 +809,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end } +diff --git a/src/main/java/org/bukkit/Warning.java b/src/main/java/org/bukkit/Warning.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/org/bukkit/Warning.java ++++ b/src/main/java/org/bukkit/Warning.java +@@ -0,0 +0,0 @@ public @interface Warning { + * + */ + public boolean printFor(@Nullable Warning warning) { ++ if (Boolean.getBoolean("paper.alwaysPrintWarningState")) return true; // Paper + if (this == DEFAULT) { + return warning == null || warning.value(); + } diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/World.java @@ -1502,6 +1722,22 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public String getDefaultTitle() { return title; } +diff --git a/src/main/java/org/bukkit/event/player/AsyncPlayerChatEvent.java b/src/main/java/org/bukkit/event/player/AsyncPlayerChatEvent.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/org/bukkit/event/player/AsyncPlayerChatEvent.java ++++ b/src/main/java/org/bukkit/event/player/AsyncPlayerChatEvent.java +@@ -0,0 +0,0 @@ import org.jetbrains.annotations.NotNull; + *

+ * Care should be taken to check {@link #isAsynchronous()} and treat the event + * appropriately. ++ * ++ * @deprecated use {@link io.papermc.paper.event.player.AsyncChatEvent} instead + */ ++@Deprecated // Paper ++@org.bukkit.Warning(value = false, reason = "Don't nag on old event yet") // Paper + public class AsyncPlayerChatEvent extends PlayerEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + private boolean cancel = false; diff --git a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java @@ -1633,6 +1869,31 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } /** +diff --git a/src/main/java/org/bukkit/event/player/PlayerChatEvent.java b/src/main/java/org/bukkit/event/player/PlayerChatEvent.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerChatEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerChatEvent.java +@@ -0,0 +0,0 @@ import org.jetbrains.annotations.NotNull; + * Listening to this event forces chat to wait for the main thread which + * causes delays for chat. {@link AsyncPlayerChatEvent} is the encouraged + * alternative for thread safe implementations. ++ * @deprecated use {@link io.papermc.paper.event.player.ChatEvent} instead + */ + @Deprecated + @Warning(reason = "Listening to this event forces chat to wait for the main thread, delaying chat messages.") +diff --git a/src/main/java/org/bukkit/event/player/PlayerEvent.java b/src/main/java/org/bukkit/event/player/PlayerEvent.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerEvent.java +@@ -0,0 +0,0 @@ public abstract class PlayerEvent extends Event { + player = who; + } + +- PlayerEvent(@NotNull final Player who, boolean async) { ++ public PlayerEvent(@NotNull final Player who, boolean async) { // Paper - public + super(async); + player = who; + diff --git a/src/main/java/org/bukkit/event/player/PlayerJoinEvent.java b/src/main/java/org/bukkit/event/player/PlayerJoinEvent.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/event/player/PlayerJoinEvent.java diff --git a/Spigot-API-Patches/Make-PlayerEvent-public.patch b/Spigot-API-Patches/Make-PlayerEvent-public.patch deleted file mode 100644 index 766005e22a..0000000000 --- a/Spigot-API-Patches/Make-PlayerEvent-public.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Mon, 27 Apr 2020 02:40:34 -0400 -Subject: [PATCH] Make PlayerEvent public - - -diff --git a/src/main/java/org/bukkit/event/player/PlayerEvent.java b/src/main/java/org/bukkit/event/player/PlayerEvent.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/org/bukkit/event/player/PlayerEvent.java -+++ b/src/main/java/org/bukkit/event/player/PlayerEvent.java -@@ -0,0 +0,0 @@ public abstract class PlayerEvent extends Event { - player = who; - } - -- PlayerEvent(@NotNull final Player who, boolean async) { -+ public PlayerEvent(@NotNull final Player who, boolean async) { // Paper - wtf? - super(async); - player = who; - diff --git a/Spigot-Server-Patches/Add-option-for-console-having-all-permissions.patch b/Spigot-Server-Patches/Add-option-for-console-having-all-permissions.patch index 0c9027cd49..04bfb9f787 100644 --- a/Spigot-Server-Patches/Add-option-for-console-having-all-permissions.patch +++ b/Spigot-Server-Patches/Add-option-for-console-having-all-permissions.patch @@ -24,7 +24,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +++ b/src/main/java/org/bukkit/craftbukkit/command/CraftConsoleCommandSender.java @@ -0,0 +0,0 @@ public class CraftConsoleCommandSender extends ServerCommandSender implements Co public void sendMessage(final net.kyori.adventure.identity.Identity identity, final net.kyori.adventure.text.Component message, final net.kyori.adventure.audience.MessageType type) { - this.sendRawMessage(io.papermc.paper.adventure.PaperAdventure.LEGACY_SECTION_UXRC.serialize(message)); + this.sendRawMessage(org.bukkit.craftbukkit.util.CraftChatMessage.fromComponent(io.papermc.paper.adventure.PaperAdventure.asVanilla(message))); } + + @Override diff --git a/Spigot-Server-Patches/Adventure.patch b/Spigot-Server-Patches/Adventure.patch index ff8d2a01ea..b626e9a1f1 100644 --- a/Spigot-Server-Patches/Adventure.patch +++ b/Spigot-Server-Patches/Adventure.patch @@ -104,6 +104,221 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + } +} +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..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/adventure/ChatProcessor.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.adventure; ++ ++import io.papermc.paper.chat.ChatFormatter; ++import io.papermc.paper.event.player.AbstractChatEvent; ++import io.papermc.paper.event.player.AsyncChatEvent; ++import io.papermc.paper.event.player.ChatEvent; ++import java.util.concurrent.ExecutionException; ++import java.util.function.Consumer; ++import java.util.regex.Pattern; ++import net.kyori.adventure.text.Component; ++import net.kyori.adventure.text.TextReplacementConfig; ++import net.kyori.adventure.text.event.ClickEvent; ++import net.minecraft.server.EntityPlayer; ++import net.minecraft.server.IChatBaseComponent; ++import net.minecraft.server.MinecraftServer; ++import org.bukkit.Bukkit; ++import org.bukkit.craftbukkit.entity.CraftPlayer; ++import org.bukkit.craftbukkit.util.LazyPlayerSet; ++import org.bukkit.craftbukkit.util.Waitable; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Event; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.AsyncPlayerChatEvent; ++import org.bukkit.event.player.PlayerChatEvent; ++ ++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 --> ++ final MinecraftServer server; ++ final EntityPlayer player; ++ final String message; ++ final boolean async; ++ ++ public ChatProcessor(final MinecraftServer server, final EntityPlayer player, final String message, final boolean async) { ++ this.server = server; ++ this.player = player; ++ this.message = message; ++ this.async = async; ++ } ++ ++ @SuppressWarnings("deprecation") ++ public void process() { ++ final boolean listenersOnSyncEvent = anyListeners(ChatEvent.getHandlerList()); ++ ++ this.processLegacy( ++ // continuing from AsyncPlayerChatEvent (without PlayerChatEvent) ++ event -> { ++ final AsyncChatEvent ae = this.createAsync( ++ legacyFormatter(event.getFormat(), event.getPlayer().getDisplayName(), event.getMessage()), ++ PaperAdventure.LEGACY_SECTION_UXRC.deserialize(event.getMessage()) ++ ); ++ ae.setCancelled(event.isCancelled()); // propagate cancelled state ++ post(ae); ++ if (listenersOnSyncEvent) { ++ this.continueWithSyncFromWhereAsyncLeftOff(ae); ++ } else { ++ this.complete(ae); ++ } ++ }, ++ // continuing from AsyncPlayerChatEvent and PlayerChatEvent ++ event -> { ++ this.queueIfAsyncOrRunImmediately(new Waitable() { ++ @Override ++ protected Void evaluate() { ++ final ChatEvent se = ChatProcessor.this.createSync( ++ legacyFormatter(event.getFormat(), event.getPlayer().getDisplayName(), event.getMessage()), ++ PaperAdventure.LEGACY_SECTION_UXRC.deserialize(event.getMessage()) ++ ); ++ se.setCancelled(event.isCancelled()); // propagate cancelled state ++ post(se); ++ ChatProcessor.this.complete(se); ++ return null; ++ } ++ }); ++ }, ++ // no legacy events called, all nice and fresh! ++ () -> { ++ final AsyncChatEvent ae = this.createAsync(ChatFormatter.DEFAULT, Component.text(this.message).replaceText(URL_REPLACEMENT_CONFIG)); ++ post(ae); ++ if (listenersOnSyncEvent) { ++ this.continueWithSyncFromWhereAsyncLeftOff(ae); ++ } else { ++ this.complete(ae); ++ } ++ } ++ ); ++ } ++ ++ private static Component displayName(final CraftPlayer player) { ++ return player.displayName(); ++ } ++ ++ private static ChatFormatter legacyFormatter(final String format, final String legacyDisplayName, final String legacyMessage) { ++ return (displayName, message) -> PaperAdventure.LEGACY_SECTION_UXRC.deserialize(String.format(format, legacyDisplayName, legacyMessage)).replaceText(URL_REPLACEMENT_CONFIG); ++ } ++ ++ private void continueWithSyncFromWhereAsyncLeftOff(final AsyncChatEvent ae) { ++ this.queueIfAsyncOrRunImmediately(new Waitable() { ++ @Override ++ protected Void evaluate() { ++ final ChatEvent se = ChatProcessor.this.createSync(ae.formatter(), ae.message()); ++ se.setCancelled(ae.isCancelled()); // propagate cancelled state ++ post(se); ++ ChatProcessor.this.complete(se); ++ return null; ++ } ++ }); ++ } ++ ++ private void complete(final AbstractChatEvent event) { ++ if (event.isCancelled()) { ++ return; ++ } ++ ++ final CraftPlayer player = this.player.getBukkitEntity(); ++ ++ final Component message = event.formatter().chat( ++ displayName(player), ++ event.message() ++ ); ++ ++ this.server.console.sendMessage(message); ++ ++ if (((LazyPlayerSet) event.recipients()).isLazy()) { ++ final IChatBaseComponent vanilla = PaperAdventure.asVanilla(message); ++ for(final EntityPlayer recipient : this.server.getPlayerList().players) { ++ recipient.sendMessage(vanilla, this.player.getUniqueID()); ++ } ++ } else { ++ for(final Player recipient : event.recipients()) { ++ recipient.sendMessage(player, message); ++ } ++ } ++ } ++ ++ private AsyncChatEvent createAsync(final ChatFormatter formatter, final Component message) { ++ return new AsyncChatEvent(this.async, this.player.getBukkitEntity(), new LazyPlayerSet(this.server), formatter, message); ++ } ++ ++ private ChatEvent createSync(final ChatFormatter formatter, final Component message) { ++ return new ChatEvent(this.player.getBukkitEntity(), new LazyPlayerSet(this.server), formatter, message); ++ } ++ ++ @SuppressWarnings("deprecation") ++ public void processLegacy( ++ final Consumer continueAfterAsync, ++ final Consumer continueAfterAsyncAndSync, ++ final Runnable modernOnly ++ ) { ++ final boolean listenersOnAsyncEvent = anyListeners(AsyncPlayerChatEvent.getHandlerList()); ++ final boolean listenersOnSyncEvent = anyListeners(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)); ++ post(ae); ++ if (listenersOnSyncEvent) { ++ final PlayerChatEvent se = new PlayerChatEvent(player, ae.getMessage(), ae.getFormat(), ae.getRecipients()); ++ se.setCancelled(ae.isCancelled()); // propagate cancelled state ++ this.queueIfAsyncOrRunImmediately(new Waitable() { ++ @Override ++ protected Void evaluate() { ++ post(se); ++ return null; ++ } ++ }); ++ continueAfterAsyncAndSync.accept(se); ++ } else if (!ae.isCancelled()) { ++ continueAfterAsync.accept(ae); ++ } ++ } else { ++ modernOnly.run(); ++ } ++ } ++ ++ private void queueIfAsyncOrRunImmediately(final Waitable waitable) { ++ if (this.async) { ++ this.server.processQueue.add(waitable); ++ } else { ++ waitable.run(); ++ } ++ try { ++ waitable.get(); ++ } catch (final InterruptedException e) { ++ Thread.currentThread().interrupt(); // tag, you're it ++ } catch (final ExecutionException e) { ++ throw new RuntimeException("Exception processing chat", e.getCause()); ++ } ++ } ++ ++ private static void post(final Event event) { ++ Bukkit.getPluginManager().callEvent(event); ++ } ++ ++ private static boolean anyListeners(final HandlerList handlers) { ++ return handlers.getRegisteredListeners().length > 0; ++ } ++} diff --git a/src/main/java/io/papermc/paper/adventure/NBTLegacyHoverEventSerializer.java b/src/main/java/io/papermc/paper/adventure/NBTLegacyHoverEventSerializer.java new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 @@ -537,73 +752,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.action.accept(PacketPlayOutBoss.Action.UPDATE_PROPERTIES); + } +} -diff --git a/src/main/java/io/papermc/paper/adventure/VanillaChatMessageLogic.java b/src/main/java/io/papermc/paper/adventure/VanillaChatMessageLogic.java -new file mode 100644 -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/adventure/VanillaChatMessageLogic.java -@@ -0,0 +0,0 @@ -+package io.papermc.paper.adventure; -+ -+import java.util.function.BiFunction; -+import java.util.regex.MatchResult; -+import java.util.regex.Pattern; -+import net.kyori.adventure.text.Component; -+import net.kyori.adventure.text.ComponentLike; -+import net.kyori.adventure.text.TextComponent; -+import net.kyori.adventure.text.TextReplacementConfig; -+import net.kyori.adventure.text.event.ClickEvent; -+import org.bukkit.craftbukkit.entity.CraftPlayer; -+ -+public class VanillaChatMessageLogic { -+ // <-- 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 --> -+ -+ public static Component displayNameForChat(final CraftPlayer player) { -+ return player.displayName(); -+ } -+ -+ public static Component formatChat(final Component displayName, final String format, final String message) { -+ final class Replacement implements BiFunction { -+ private int index = 0; -+ -+ @Override -+ public ComponentLike apply(final MatchResult result, final TextComponent.Builder builder) { -+ if (this.index == 0) { -+ this.index++; -+ return displayName; -+ } else if (this.index == 1) { -+ this.index++; -+ return PaperAdventure.LEGACY_SECTION_UXRC.deserialize(message).mergeStyle(builder.asComponent()).replaceText(URL_REPLACEMENT_CONFIG); -+ } else { -+ return builder; -+ } -+ } -+ } -+ final Replacement replacement = new Replacement(); -+ if (format.contains("%2$s") && !format.contains("%1$s")) { -+ replacement.index = 1; -+ } -+ return PaperAdventure.LEGACY_SECTION_UXRC.deserialize(format) -+ .replaceText(config -> { -+ config.times(2); -+ config.match("%(\\d+\\$)?s"); -+ config.replacement(replacement); -+ }); -+ } -+} diff --git a/src/main/java/io/papermc/paper/adventure/WrapperAwareSerializer.java b/src/main/java/io/papermc/paper/adventure/WrapperAwareSerializer.java new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 @@ -1136,8 +1284,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import org.apache.logging.log4j.Logger; // CraftBukkit start ++import io.papermc.paper.adventure.ChatProcessor; // Paper +import io.papermc.paper.adventure.PaperAdventure; // Paper -+import io.papermc.paper.adventure.VanillaChatMessageLogic; // Paper import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import org.bukkit.Location; @@ -1200,55 +1348,21 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // CraftBukkit end ITextFilter itextfilter = this.player.Q(); @@ -0,0 +0,0 @@ public class PlayerConnection implements PacketListenerPlayIn { - return null; - } + this.handleCommand(s); + } else if (this.player.getChatFlags() == EnumChatVisibility.SYSTEM) { + // Do nothing, this is coming from a plugin +- } else { +- Player player = this.getPlayer(); ++ // Paper start ++ } else if (true) { ++ final ChatProcessor cp = new ChatProcessor(this.minecraftServer, this.player, s, async); ++ cp.process(); ++ // Paper end ++ } else if (false) { // Paper ++ Player player = this.getPlayer(); // Paper + AsyncPlayerChatEvent event = new AsyncPlayerChatEvent(async, player, s, new LazyPlayerSet(minecraftServer)); + this.server.getPluginManager().callEvent(event); -- String message = String.format(queueEvent.getFormat(), queueEvent.getPlayer().getDisplayName(), queueEvent.getMessage()); -- PlayerConnection.this.minecraftServer.console.sendMessage(message); -+ final net.kyori.adventure.text.Component adventure$msg = VanillaChatMessageLogic.formatChat(VanillaChatMessageLogic.displayNameForChat((CraftPlayer) player), queueEvent.getFormat(), queueEvent.getMessage()); // Paper -+ //String message = String.format(queueEvent.getFormat(), queueEvent.getPlayer().getDisplayName(), queueEvent.getMessage()); // Paper - comment -+ //PlayerConnection.this.minecraftServer.console.sendMessage(message); // Paper - comment -+ PlayerConnection.this.minecraftServer.console.sendMessage(adventure$msg); // Paper - if (((LazyPlayerSet) queueEvent.getRecipients()).isLazy()) { -+ final IChatBaseComponent vanilla$msg = PaperAdventure.asVanilla(adventure$msg); // Paper - for (Object player : PlayerConnection.this.minecraftServer.getPlayerList().players) { -- ((EntityPlayer) player).sendMessage(PlayerConnection.this.player.getUniqueID(), CraftChatMessage.fromString(message)); -+ //((EntityPlayer) player).sendMessage(PlayerConnection.this.player.getUniqueID(), CraftChatMessage.fromString(message)); // Paper - comment -+ ((EntityPlayer) player).sendMessage(vanilla$msg, PlayerConnection.this.player.getUniqueID()); - } - } else { - for (Player player : queueEvent.getRecipients()) { -- player.sendMessage(PlayerConnection.this.player.getUniqueID(), message); -+ //player.sendMessage(PlayerConnection.this.player.getUniqueID(), message); // Paper - comment -+ player.sendMessage(PlayerConnection.this.player.getBukkitEntity(), adventure$msg); // Paper - } - } - return null; -@@ -0,0 +0,0 @@ public class PlayerConnection implements PacketListenerPlayIn { - return; - } - -- s = String.format(event.getFormat(), event.getPlayer().getDisplayName(), event.getMessage()); -- minecraftServer.console.sendMessage(s); -+ final net.kyori.adventure.text.Component adventure$msg = VanillaChatMessageLogic.formatChat(VanillaChatMessageLogic.displayNameForChat((CraftPlayer) player), event.getFormat(), event.getMessage()); // Paper -+ //s = String.format(event.getFormat(), event.getPlayer().getDisplayName(), event.getMessage()); // Paper - comment -+ //minecraftServer.console.sendMessage(s); // Paper - comment -+ minecraftServer.console.sendMessage(adventure$msg); // Paper - if (((LazyPlayerSet) event.getRecipients()).isLazy()) { -+ final IChatBaseComponent vanilla$msg = PaperAdventure.asVanilla(adventure$msg); // Paper - for (Object recipient : minecraftServer.getPlayerList().players) { -- ((EntityPlayer) recipient).sendMessage(PlayerConnection.this.player.getUniqueID(), CraftChatMessage.fromString(s)); -+ //((EntityPlayer) recipient).sendMessage(PlayerConnection.this.player.getUniqueID(), CraftChatMessage.fromString(s)); // Paper - comment -+ ((EntityPlayer) recipient).sendMessage(vanilla$msg, PlayerConnection.this.player.getUniqueID()); // Paper - } - } else { - for (Player recipient : event.getRecipients()) { -- recipient.sendMessage(PlayerConnection.this.player.getUniqueID(), s); -+ //recipient.sendMessage(PlayerConnection.this.player.getUniqueID(), s); // Paper - comment -+ recipient.sendMessage(PlayerConnection.this.player.getBukkitEntity(), adventure$msg); // Paper - } - } - } @@ -0,0 +0,0 @@ public class PlayerConnection implements PacketListenerPlayIn { return; } @@ -1773,7 +1887,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start + @Override + public void sendMessage(final net.kyori.adventure.identity.Identity identity, final net.kyori.adventure.text.Component message, final net.kyori.adventure.audience.MessageType type) { -+ this.sendRawMessage(io.papermc.paper.adventure.PaperAdventure.LEGACY_SECTION_UXRC.serialize(message)); ++ this.sendRawMessage(org.bukkit.craftbukkit.util.CraftChatMessage.fromComponent(io.papermc.paper.adventure.PaperAdventure.asVanilla(message))); + } + // Paper end } diff --git a/Spigot-Server-Patches/Limit-recipe-packets.patch b/Spigot-Server-Patches/Limit-recipe-packets.patch index d497287268..2444a150ec 100644 --- a/Spigot-Server-Patches/Limit-recipe-packets.patch +++ b/Spigot-Server-Patches/Limit-recipe-packets.patch @@ -42,8 +42,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -@@ -0,0 +0,0 @@ import io.papermc.paper.adventure.PaperAdventure; // Paper - import io.papermc.paper.adventure.VanillaChatMessageLogic; // Paper +@@ -0,0 +0,0 @@ import io.papermc.paper.adventure.ChatProcessor; // Paper + import io.papermc.paper.adventure.PaperAdventure; // Paper import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; + diff --git a/Spigot-Server-Patches/Option-to-use-vanilla-per-world-scoreboard-coloring-.patch b/Spigot-Server-Patches/Option-to-use-vanilla-per-world-scoreboard-coloring-.patch index 99c5ba80f4..07b2e77e22 100644 --- a/Spigot-Server-Patches/Option-to-use-vanilla-per-world-scoreboard-coloring-.patch +++ b/Spigot-Server-Patches/Option-to-use-vanilla-per-world-scoreboard-coloring-.patch @@ -25,48 +25,27 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + useVanillaScoreboardColoring = getBoolean("use-vanilla-world-scoreboard-name-coloring", false); + } } -diff --git a/src/main/java/io/papermc/paper/adventure/VanillaChatMessageLogic.java b/src/main/java/io/papermc/paper/adventure/VanillaChatMessageLogic.java +diff --git a/src/main/java/io/papermc/paper/adventure/ChatProcessor.java b/src/main/java/io/papermc/paper/adventure/ChatProcessor.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/io/papermc/paper/adventure/VanillaChatMessageLogic.java -+++ b/src/main/java/io/papermc/paper/adventure/VanillaChatMessageLogic.java -@@ -0,0 +0,0 @@ import net.kyori.adventure.text.ComponentLike; - import net.kyori.adventure.text.TextComponent; - import net.kyori.adventure.text.TextReplacementConfig; - import net.kyori.adventure.text.event.ClickEvent; +--- a/src/main/java/io/papermc/paper/adventure/ChatProcessor.java ++++ b/src/main/java/io/papermc/paper/adventure/ChatProcessor.java +@@ -0,0 +0,0 @@ import net.kyori.adventure.text.event.ClickEvent; + import net.minecraft.server.EntityPlayer; + import net.minecraft.server.IChatBaseComponent; + import net.minecraft.server.MinecraftServer; +import net.minecraft.server.ScoreboardTeam; + import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.entity.CraftPlayer; + import org.bukkit.craftbukkit.util.LazyPlayerSet; + import org.bukkit.craftbukkit.util.Waitable; +@@ -0,0 +0,0 @@ public final class ChatProcessor { + } - public class VanillaChatMessageLogic { -@@ -0,0 +0,0 @@ public class VanillaChatMessageLogic { - // copied from adventure-text-serializer-legacy --> - - public static Component displayNameForChat(final CraftPlayer player) { + private static Component displayName(final CraftPlayer player) { + if (((CraftWorld) player.getWorld()).getHandle().paperConfig.useVanillaScoreboardColoring) { + return PaperAdventure.asAdventure(ScoreboardTeam.a(player.getHandle().getScoreboardTeam(), player.getHandle().getDisplayName())); + } return player.displayName(); } -diff --git a/src/main/java/net/minecraft/server/PlayerConnection.java b/src/main/java/net/minecraft/server/PlayerConnection.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/PlayerConnection.java -+++ b/src/main/java/net/minecraft/server/PlayerConnection.java -@@ -0,0 +0,0 @@ public class PlayerConnection implements PacketListenerPlayIn { - } else if (this.player.getChatFlags() == EnumChatVisibility.SYSTEM) { - // Do nothing, this is coming from a plugin - } else { -- Player player = this.getPlayer(); -+ CraftPlayer player = this.getPlayer(); // Paper - AsyncPlayerChatEvent event = new AsyncPlayerChatEvent(async, player, s, new LazyPlayerSet(minecraftServer)); - this.server.getPluginManager().callEvent(event); - -@@ -0,0 +0,0 @@ public class PlayerConnection implements PacketListenerPlayIn { - return null; - } - -- final net.kyori.adventure.text.Component adventure$msg = VanillaChatMessageLogic.formatChat(VanillaChatMessageLogic.displayNameForChat((CraftPlayer) player), queueEvent.getFormat(), queueEvent.getMessage()); // Paper -+ final net.kyori.adventure.text.Component adventure$msg = VanillaChatMessageLogic.formatChat(VanillaChatMessageLogic.displayNameForChat(player), queueEvent.getFormat(), queueEvent.getMessage()); // Paper - //String message = String.format(queueEvent.getFormat(), queueEvent.getPlayer().getDisplayName(), queueEvent.getMessage()); // Paper - comment - //PlayerConnection.this.minecraftServer.console.sendMessage(message); // Paper - comment - PlayerConnection.this.minecraftServer.console.sendMessage(adventure$msg); // Paper