diff --git a/patches/server/Adventure.patch b/patches/server/Adventure.patch index 89c8d0c1b5..3380915a16 100644 --- a/patches/server/Adventure.patch +++ b/patches/server/Adventure.patch @@ -257,22 +257,27 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ +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.lang.reflect.Field; ++import java.lang.reflect.Modifier; +import java.util.BitSet; +import java.util.Collection; ++import java.util.HashMap; +import java.util.HashSet; ++import java.util.Map; ++import java.util.Objects; +import java.util.Set; +import java.util.concurrent.ExecutionException; +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.audience.ForwardingAudience; ++import net.kyori.adventure.key.Key; +import net.kyori.adventure.text.Component; +import net.minecraft.Util; ++import net.minecraft.core.registries.Registries; +import net.minecraft.network.chat.ChatDecorator; +import net.minecraft.network.chat.ChatType; +import net.minecraft.network.chat.OutgoingChatMessage; @@ -280,7 +285,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +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; @@ -524,39 +528,79 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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))); ++ this.broadcastToViewers(viewers, 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)); ++ this.broadcastToViewers(viewers, chatType, $ -> renderedMessage); + } + + @Override + public void sendOriginal(CraftPlayer player, Set viewers, ChatType.Bound chatType) { -+ this.broadcastToViewers(viewers, player, chatType, null); ++ this.broadcastToViewers(viewers, 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.decoratedContent())); -+ final Function audienceMsgFunction = !(msgFunction instanceof ConstantFunction || msgFunction == null) ? msgFunction.andThen(PaperAdventure::asAdventure) : viewer -> fallbackSupplier.get(); ++ private void broadcastToViewers(Collection viewers, final ChatType.Bound chatType, final @Nullable Function msgFunction) { + 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); ++ if (acceptsNative(viewer)) { ++ this.sendNative(viewer, chatType, msgFunction); + } else { -+ viewer.sendMessage(source, audienceMsgFunction.apply(viewer), MessageType.CHAT); ++ final net.minecraft.network.chat.@Nullable Component unsigned = Util.mapNullable(msgFunction, f -> f.apply(viewer)); ++ final PlayerChatMessage msg = unsigned == null ? ChatProcessor.this.message : ChatProcessor.this.message.withUnsignedContent(unsigned); ++ viewer.sendMessage(msg.adventureView(), this.adventure(chatType)); + } + } + } + -+ private void sendToViewer(final CommandSender viewer, final ChatType.Bound chatType, final @Nullable Function msgFunction) { ++ private static final Map BUILT_IN_CHAT_TYPES = Util.make(() -> { ++ final Map map = new HashMap<>(); ++ for (final Field declaredField : net.kyori.adventure.chat.ChatType.class.getDeclaredFields()) { ++ if (Modifier.isStatic(declaredField.getModifiers()) && declaredField.getType().equals(ChatType.class)) { ++ try { ++ final net.kyori.adventure.chat.ChatType type = (net.kyori.adventure.chat.ChatType) declaredField.get(null); ++ map.put(type.key().asString(), type); ++ } catch (final ReflectiveOperationException ignore) { ++ } ++ } ++ } ++ return map; ++ }); ++ ++ private net.kyori.adventure.chat.ChatType.Bound adventure(ChatType.Bound chatType) { ++ final String stringKey = Objects.requireNonNull( ++ ChatProcessor.this.server.registryAccess().registryOrThrow(Registries.CHAT_TYPE).getKey(chatType.chatType()), ++ () -> "No key for '%s' in CHAT_TYPE registry.".formatted(chatType) ++ ).toString(); ++ net.kyori.adventure.chat.@Nullable ChatType adventure = BUILT_IN_CHAT_TYPES.get(stringKey); ++ if (adventure == null) { ++ adventure = net.kyori.adventure.chat.ChatType.chatType(Key.key(stringKey)); ++ } ++ return adventure.bind( ++ PaperAdventure.asAdventure(chatType.name()), ++ PaperAdventure.asAdventure(chatType.targetName()) ++ ); ++ } ++ ++ private static boolean acceptsNative(final Audience viewer) { ++ if (viewer instanceof Player || viewer instanceof ConsoleCommandSender) { ++ return true; ++ } ++ if (viewer instanceof ForwardingAudience.Single single) { ++ return acceptsNative(single.audience()); ++ } ++ return false; ++ } ++ ++ private void sendNative(final Audience 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 if (viewer instanceof ForwardingAudience.Single single) { ++ this.sendNative(single.audience(), chatType, msgFunction); + } else { -+ throw new IllegalStateException("Should only be a Player or Console"); ++ throw new IllegalStateException("Should only be a Player or Console or ForwardingAudience.Single pointing to one!"); + } + } + @@ -564,13 +608,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + final PlayerChatMessage toConsoleMessage = msgFunction == null ? ChatProcessor.this.message : ChatProcessor.this.message.withUnsignedContent(msgFunction.apply(ChatProcessor.this.server.console)); + ChatProcessor.this.server.logChatMessage(toConsoleMessage.decoratedContent(), chatType, ChatProcessor.this.server.getPlayerList().verifyChatTrusted(toConsoleMessage) ? 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; -+ } -+ } + } + + private Set viewersFromLegacy(final Set recipients) { @@ -1669,6 +1706,25 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 MutableComponent mutableComponent = text.getContents().resolve(source, sender, depth + 1); for(Component component : text.getSiblings()) { +diff --git a/src/main/java/net/minecraft/network/chat/MessageSignature.java b/src/main/java/net/minecraft/network/chat/MessageSignature.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/network/chat/MessageSignature.java ++++ b/src/main/java/net/minecraft/network/chat/MessageSignature.java +@@ -0,0 +0,0 @@ import net.minecraft.util.ExtraCodecs; + import net.minecraft.util.SignatureUpdater; + import net.minecraft.util.SignatureValidator; + +-public record MessageSignature(byte[] bytes) { ++public record MessageSignature(byte[] bytes) implements net.kyori.adventure.chat.SignedMessage.Signature { // Paper + public static final Codec CODEC = ExtraCodecs.BASE64_STRING.xmap(MessageSignature::new, MessageSignature::bytes); + public static final int BYTES = 256; + + public MessageSignature { +- Preconditions.checkState(bs.length == 256, "Invalid message signature size"); ++ Preconditions.checkState(bytes.length == 256, "Invalid message signature size"); // Paper - decompile fix + } + + public static MessageSignature read(FriendlyByteBuf buf) { diff --git a/src/main/java/net/minecraft/network/chat/OutgoingChatMessage.java b/src/main/java/net/minecraft/network/chat/OutgoingChatMessage.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/network/chat/OutgoingChatMessage.java @@ -1735,6 +1791,40 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public net.minecraft.network.chat.ChatDecorator.Result requireResult() { + return Objects.requireNonNull(this.result, "Requires a decoration result to be set here"); + } ++ public final class AdventureView implements net.kyori.adventure.chat.SignedMessage { ++ private AdventureView() { ++ } ++ @Override ++ public @org.jetbrains.annotations.NotNull Instant timestamp() { ++ return PlayerChatMessage.this.timeStamp(); ++ } ++ @Override ++ public long salt() { ++ return PlayerChatMessage.this.salt(); ++ } ++ @Override ++ public @org.jetbrains.annotations.Nullable Signature signature() { ++ return PlayerChatMessage.this.signature(); ++ } ++ @Override ++ public net.kyori.adventure.text.@org.jetbrains.annotations.Nullable Component unsignedContent() { ++ return PlayerChatMessage.this.unsignedContent() == null ? null : io.papermc.paper.adventure.PaperAdventure.asAdventure(PlayerChatMessage.this.unsignedContent()); ++ } ++ @Override ++ public @org.jetbrains.annotations.NotNull String message() { ++ return PlayerChatMessage.this.signedContent(); ++ } ++ @Override ++ public @org.jetbrains.annotations.NotNull net.kyori.adventure.identity.Identity identity() { ++ return net.kyori.adventure.identity.Identity.identity(PlayerChatMessage.this.sender()); ++ } ++ public PlayerChatMessage playerChatMessage() { ++ return PlayerChatMessage.this; ++ } ++ } ++ public AdventureView adventureView() { ++ return new AdventureView(); ++ } + // Paper end public static final MapCodec MAP_CODEC = RecordCodecBuilder.mapCodec((instance) -> { return instance.group(SignedMessageLink.CODEC.fieldOf("link").forGetter(PlayerChatMessage::link), MessageSignature.CODEC.optionalFieldOf("signature").forGetter((message) -> { @@ -3456,6 +3546,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public void sendMessage(net.kyori.adventure.chat.SignedMessage signedMessage, net.kyori.adventure.chat.ChatType.Bound boundChatType) { + if (getHandle().connection == null) return; + ++ if (signedMessage instanceof PlayerChatMessage.AdventureView view) { ++ this.getHandle().sendChatMessage(net.minecraft.network.chat.OutgoingChatMessage.create(view.playerChatMessage()), this.getHandle().isTextFilteringEnabled(), this.toHandle(boundChatType)); ++ return; ++ } + net.kyori.adventure.text.Component message = signedMessage.unsignedContent() == null ? net.kyori.adventure.text.Component.text(signedMessage.message()) : signedMessage.unsignedContent(); + if (signedMessage.isSystem()) { + this.sendMessage(message, boundChatType); diff --git a/patches/server/Option-to-use-vanilla-per-world-scoreboard-coloring-.patch b/patches/server/Option-to-use-vanilla-per-world-scoreboard-coloring-.patch index d8bc643f24..cbfbc0bb0c 100644 --- a/patches/server/Option-to-use-vanilla-per-world-scoreboard-coloring-.patch +++ b/patches/server/Option-to-use-vanilla-per-world-scoreboard-coloring-.patch @@ -20,7 +20,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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;