mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-30 16:19:03 +01:00
ChatProcessor fixes (#8690)
Fixes handling for `ForwardingAudience.Single` and passes the signed message to non-native `Audience` types
This commit is contained in:
parent
968a3ee539
commit
1de7f28233
2 changed files with 117 additions and 24 deletions
|
@ -257,22 +257,27 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
@@ -0,0 +0,0 @@
|
@@ -0,0 +0,0 @@
|
||||||
+package io.papermc.paper.adventure;
|
+package io.papermc.paper.adventure;
|
||||||
+
|
+
|
||||||
+import com.google.common.base.Suppliers;
|
|
||||||
+import io.papermc.paper.chat.ChatRenderer;
|
+import io.papermc.paper.chat.ChatRenderer;
|
||||||
+import io.papermc.paper.event.player.AbstractChatEvent;
|
+import io.papermc.paper.event.player.AbstractChatEvent;
|
||||||
+import io.papermc.paper.event.player.AsyncChatEvent;
|
+import io.papermc.paper.event.player.AsyncChatEvent;
|
||||||
+import io.papermc.paper.event.player.ChatEvent;
|
+import io.papermc.paper.event.player.ChatEvent;
|
||||||
|
+import java.lang.reflect.Field;
|
||||||
|
+import java.lang.reflect.Modifier;
|
||||||
+import java.util.BitSet;
|
+import java.util.BitSet;
|
||||||
+import java.util.Collection;
|
+import java.util.Collection;
|
||||||
|
+import java.util.HashMap;
|
||||||
+import java.util.HashSet;
|
+import java.util.HashSet;
|
||||||
|
+import java.util.Map;
|
||||||
|
+import java.util.Objects;
|
||||||
+import java.util.Set;
|
+import java.util.Set;
|
||||||
+import java.util.concurrent.ExecutionException;
|
+import java.util.concurrent.ExecutionException;
|
||||||
+import java.util.function.Function;
|
+import java.util.function.Function;
|
||||||
+import java.util.function.Supplier;
|
|
||||||
+import net.kyori.adventure.audience.Audience;
|
+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.kyori.adventure.text.Component;
|
||||||
+import net.minecraft.Util;
|
+import net.minecraft.Util;
|
||||||
|
+import net.minecraft.core.registries.Registries;
|
||||||
+import net.minecraft.network.chat.ChatDecorator;
|
+import net.minecraft.network.chat.ChatDecorator;
|
||||||
+import net.minecraft.network.chat.ChatType;
|
+import net.minecraft.network.chat.ChatType;
|
||||||
+import net.minecraft.network.chat.OutgoingChatMessage;
|
+import net.minecraft.network.chat.OutgoingChatMessage;
|
||||||
|
@ -280,7 +285,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
+import net.minecraft.resources.ResourceKey;
|
+import net.minecraft.resources.ResourceKey;
|
||||||
+import net.minecraft.server.MinecraftServer;
|
+import net.minecraft.server.MinecraftServer;
|
||||||
+import net.minecraft.server.level.ServerPlayer;
|
+import net.minecraft.server.level.ServerPlayer;
|
||||||
+import org.bukkit.command.CommandSender;
|
|
||||||
+import org.bukkit.command.ConsoleCommandSender;
|
+import org.bukkit.command.ConsoleCommandSender;
|
||||||
+import org.bukkit.craftbukkit.entity.CraftPlayer;
|
+import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||||
+import org.bukkit.craftbukkit.util.LazyPlayerSet;
|
+import org.bukkit.craftbukkit.util.LazyPlayerSet;
|
||||||
|
@ -524,39 +528,79 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
+ final class ViewersOutgoingChat implements OutgoingChat {
|
+ final class ViewersOutgoingChat implements OutgoingChat {
|
||||||
+ @Override
|
+ @Override
|
||||||
+ public void sendFormatChangedViewerAware(CraftPlayer player, Component displayName, Component message, ChatRenderer renderer, Set<Audience> viewers, ChatType.Bound chatType) {
|
+ public void sendFormatChangedViewerAware(CraftPlayer player, Component displayName, Component message, ChatRenderer renderer, Set<Audience> 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
|
+ @Override
|
||||||
+ public void sendMessageChanged(CraftPlayer player, net.minecraft.network.chat.Component renderedMessage, Set<Audience> viewers, ChatType.Bound chatType) {
|
+ public void sendMessageChanged(CraftPlayer player, net.minecraft.network.chat.Component renderedMessage, Set<Audience> viewers, ChatType.Bound chatType) {
|
||||||
+ this.broadcastToViewers(viewers, player, chatType, new ConstantFunction(renderedMessage));
|
+ this.broadcastToViewers(viewers, chatType, $ -> renderedMessage);
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ @Override
|
+ @Override
|
||||||
+ public void sendOriginal(CraftPlayer player, Set<Audience> viewers, ChatType.Bound chatType) {
|
+ public void sendOriginal(CraftPlayer player, Set<Audience> viewers, ChatType.Bound chatType) {
|
||||||
+ this.broadcastToViewers(viewers, player, chatType, null);
|
+ this.broadcastToViewers(viewers, chatType, null);
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ private void broadcastToViewers(Collection<Audience> viewers, final Player source, final ChatType.Bound chatType, final @Nullable Function<Audience, net.minecraft.network.chat.Component> msgFunction) {
|
+ private void broadcastToViewers(Collection<Audience> viewers, final ChatType.Bound chatType, final @Nullable Function<Audience, net.minecraft.network.chat.Component> msgFunction) {
|
||||||
+ final Supplier<Component> fallbackSupplier = Suppliers.memoize(() -> PaperAdventure.asAdventure(msgFunction instanceof ConstantFunction constantFunction ? constantFunction.component : ChatProcessor.this.message.decoratedContent()));
|
|
||||||
+ final Function<Audience, Component> audienceMsgFunction = !(msgFunction instanceof ConstantFunction || msgFunction == null) ? msgFunction.andThen(PaperAdventure::asAdventure) : viewer -> fallbackSupplier.get();
|
|
||||||
+ for (Audience viewer : viewers) {
|
+ for (Audience viewer : viewers) {
|
||||||
+ if (viewer instanceof Player || viewer instanceof ConsoleCommandSender) {
|
+ if (acceptsNative(viewer)) {
|
||||||
+ // players and console have builtin PlayerChatMessage sending support while other audiences do not
|
+ this.sendNative(viewer, chatType, msgFunction);
|
||||||
+ this.sendToViewer((CommandSender) viewer, chatType, msgFunction);
|
|
||||||
+ } else {
|
+ } 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<Audience, net.minecraft.network.chat.Component> msgFunction) {
|
+ private static final Map<String, net.kyori.adventure.chat.ChatType> BUILT_IN_CHAT_TYPES = Util.make(() -> {
|
||||||
|
+ final Map<String, net.kyori.adventure.chat.ChatType> 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<Audience, net.minecraft.network.chat.Component> msgFunction) {
|
||||||
+ if (viewer instanceof ConsoleCommandSender) {
|
+ if (viewer instanceof ConsoleCommandSender) {
|
||||||
+ this.sendToServer(chatType, msgFunction);
|
+ this.sendToServer(chatType, msgFunction);
|
||||||
+ } else if (viewer instanceof CraftPlayer craftPlayer) {
|
+ } 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)));
|
+ 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 {
|
+ } 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));
|
+ 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");
|
+ 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<Audience, net.minecraft.network.chat.Component> {
|
|
||||||
+ @Override
|
|
||||||
+ public net.minecraft.network.chat.Component apply(Audience audience) {
|
|
||||||
+ return this.component;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ private Set<Audience> viewersFromLegacy(final Set<Player> recipients) {
|
+ private Set<Audience> viewersFromLegacy(final Set<Player> recipients) {
|
||||||
|
@ -1669,6 +1706,25 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
MutableComponent mutableComponent = text.getContents().resolve(source, sender, depth + 1);
|
MutableComponent mutableComponent = text.getContents().resolve(source, sender, depth + 1);
|
||||||
|
|
||||||
for(Component component : text.getSiblings()) {
|
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<MessageSignature> 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
|
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
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||||
--- a/src/main/java/net/minecraft/network/chat/OutgoingChatMessage.java
|
--- 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() {
|
+ public net.minecraft.network.chat.ChatDecorator.Result requireResult() {
|
||||||
+ return Objects.requireNonNull(this.result, "Requires a decoration result to be set here");
|
+ 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
|
+ // Paper end
|
||||||
public static final MapCodec<PlayerChatMessage> MAP_CODEC = RecordCodecBuilder.mapCodec((instance) -> {
|
public static final MapCodec<PlayerChatMessage> MAP_CODEC = RecordCodecBuilder.mapCodec((instance) -> {
|
||||||
return instance.group(SignedMessageLink.CODEC.fieldOf("link").forGetter(PlayerChatMessage::link), MessageSignature.CODEC.optionalFieldOf("signature").forGetter((message) -> {
|
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) {
|
+ public void sendMessage(net.kyori.adventure.chat.SignedMessage signedMessage, net.kyori.adventure.chat.ChatType.Bound boundChatType) {
|
||||||
+ if (getHandle().connection == null) return;
|
+ 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();
|
+ net.kyori.adventure.text.Component message = signedMessage.unsignedContent() == null ? net.kyori.adventure.text.Component.text(signedMessage.message()) : signedMessage.unsignedContent();
|
||||||
+ if (signedMessage.isSystem()) {
|
+ if (signedMessage.isSystem()) {
|
||||||
+ this.sendMessage(message, boundChatType);
|
+ this.sendMessage(message, boundChatType);
|
||||||
|
|
|
@ -20,7 +20,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
+import org.bukkit.ChatColor;
|
+import org.bukkit.ChatColor;
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.command.ConsoleCommandSender;
|
import org.bukkit.command.ConsoleCommandSender;
|
||||||
+import org.bukkit.craftbukkit.CraftWorld;
|
+import org.bukkit.craftbukkit.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||||
|
|
Loading…
Reference in a new issue