diff --git a/paper-api/src/main/java/org/bukkit/plugin/messaging/Messenger.java b/paper-api/src/main/java/org/bukkit/plugin/messaging/Messenger.java index 2554d383d3..dd091124b6 100644 --- a/paper-api/src/main/java/org/bukkit/plugin/messaging/Messenger.java +++ b/paper-api/src/main/java/org/bukkit/plugin/messaging/Messenger.java @@ -1,9 +1,11 @@ package org.bukkit.plugin.messaging; import java.util.Set; +import io.papermc.paper.connection.PlayerConnection; import org.bukkit.NamespacedKey; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; /** @@ -230,4 +232,14 @@ public interface Messenger { * @param message Raw payload of the message. */ public void dispatchIncomingMessage(@NotNull Player source, @NotNull String channel, byte @NotNull [] message); + + /** + * Dispatches the specified incoming message to any registered listeners. + * + * @param source Source of the message. + * @param channel Channel that the message was sent by. + * @param message Raw payload of the message. + */ + @ApiStatus.Experimental + public void dispatchIncomingMessage(@NotNull PlayerConnection source, @NotNull String channel, byte @NotNull [] message); } diff --git a/paper-api/src/main/java/org/bukkit/plugin/messaging/PluginMessageListener.java b/paper-api/src/main/java/org/bukkit/plugin/messaging/PluginMessageListener.java index a9561e3ba4..e4f6970240 100644 --- a/paper-api/src/main/java/org/bukkit/plugin/messaging/PluginMessageListener.java +++ b/paper-api/src/main/java/org/bukkit/plugin/messaging/PluginMessageListener.java @@ -1,7 +1,9 @@ package org.bukkit.plugin.messaging; import io.papermc.paper.connection.PlayerCommonConnection; +import io.papermc.paper.connection.PlayerConnection; import org.bukkit.entity.Player; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; /** @@ -28,7 +30,8 @@ public interface PluginMessageListener { * @param connection Source of the message. * @param message The raw message that was sent. */ - default void onPluginMessageReceived(@NotNull String channel, @NotNull PlayerCommonConnection connection, byte @NotNull [] message) { + @ApiStatus.Experimental + default void onPluginMessageReceived(@NotNull String channel, @NotNull PlayerConnection connection, byte @NotNull [] message) { } } diff --git a/paper-api/src/main/java/org/bukkit/plugin/messaging/StandardMessenger.java b/paper-api/src/main/java/org/bukkit/plugin/messaging/StandardMessenger.java index 5580fdfe88..f08b084ab3 100644 --- a/paper-api/src/main/java/org/bukkit/plugin/messaging/StandardMessenger.java +++ b/paper-api/src/main/java/org/bukkit/plugin/messaging/StandardMessenger.java @@ -8,6 +8,7 @@ import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.logging.Level; +import io.papermc.paper.connection.PlayerConnection; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.NotNull; @@ -462,6 +463,30 @@ public class StandardMessenger implements Messenger { } } + @Override + public void dispatchIncomingMessage(@NotNull PlayerConnection source, @NotNull String channel, byte @NotNull [] message) { + if (source == null) { + throw new IllegalArgumentException("Player source cannot be null"); + } + if (message == null) { + throw new IllegalArgumentException("Message cannot be null"); + } + channel = validateAndCorrectChannel(channel); + + Set registrations = getIncomingChannelRegistrations(channel); + + for (PluginMessageListenerRegistration registration : registrations) { + try { + registration.getListener().onPluginMessageReceived(channel, source, message); + } catch (Throwable t) { + registration.getPlugin().getLogger().log(Level.WARNING, + String.format("Plugin %s generated an exception whilst handling plugin message", + registration.getPlugin().getDescription().getFullName() + ), t); + } + } + } + /** * Validates a Plugin Channel name. * diff --git a/paper-server/patches/features/0032-Improve-keepalive-ping-system.patch b/paper-server/patches/features/0032-Improve-keepalive-ping-system.patch index 0d8ff77121..f14cd58186 100644 --- a/paper-server/patches/features/0032-Improve-keepalive-ping-system.patch +++ b/paper-server/patches/features/0032-Improve-keepalive-ping-system.patch @@ -85,22 +85,22 @@ index 0000000000000000000000000000000000000000..4a2520f554c2ee74faf86d7c93baccf0 + } +} diff --git a/net/minecraft/server/network/CommonListenerCookie.java b/net/minecraft/server/network/CommonListenerCookie.java -index b94988d6dd98bfb7d3d2f08c2adaa96d7c7a8b55..7e61c8222d567feb8c2b988699e1cfe83bf4be31 100644 +index 962084054c0208470d0c3c99c5dca6327c9b8752..2abc21102bbd2da79dc0c50826cff7da01a0f9bc 100644 --- a/net/minecraft/server/network/CommonListenerCookie.java +++ b/net/minecraft/server/network/CommonListenerCookie.java @@ -3,8 +3,8 @@ package net.minecraft.server.network; import com.mojang.authlib.GameProfile; import net.minecraft.server.level.ClientInformation; --public record CommonListenerCookie(GameProfile gameProfile, int latency, ClientInformation clientInformation, boolean transferred, @org.jetbrains.annotations.Nullable String brandName) { // Paper -+public record CommonListenerCookie(GameProfile gameProfile, int latency, ClientInformation clientInformation, boolean transferred, @org.jetbrains.annotations.Nullable String brandName, io.papermc.paper.util.KeepAlive keepAlive) { // Paper +-public record CommonListenerCookie(GameProfile gameProfile, int latency, ClientInformation clientInformation, boolean transferred, @org.jetbrains.annotations.Nullable String brandName, java.util.Set channels) { // Paper ++public record CommonListenerCookie(GameProfile gameProfile, int latency, ClientInformation clientInformation, boolean transferred, @org.jetbrains.annotations.Nullable String brandName, java.util.Set channels, io.papermc.paper.util.KeepAlive keepAlive) { // Paper public static CommonListenerCookie createInitial(GameProfile gameProfile, boolean transferred) { -- return new CommonListenerCookie(gameProfile, 0, ClientInformation.createDefault(), transferred, null); // Paper -+ return new CommonListenerCookie(gameProfile, 0, ClientInformation.createDefault(), transferred, null, new io.papermc.paper.util.KeepAlive()); // Paper +- return new CommonListenerCookie(gameProfile, 0, ClientInformation.createDefault(), transferred, null, new java.util.HashSet<>()); // Paper ++ return new CommonListenerCookie(gameProfile, 0, ClientInformation.createDefault(), transferred, null, new java.util.HashSet<>(), new io.papermc.paper.util.KeepAlive()); // Paper } } diff --git a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -index fae1523404b7afa2b904faad9242273b3c406aac..16962ccab91d0941e428a2e53aa37e9ca975f62f 100644 +index ab2bcd5b547c8db418de7ea0b7f144058aa8b0f4..1ae3724eec5fac852c6cc6bb88b1ecb9f0b790f0 100644 --- a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java +++ b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java @@ -38,12 +38,13 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack @@ -121,7 +121,7 @@ index fae1523404b7afa2b904faad9242273b3c406aac..16962ccab91d0941e428a2e53aa37e9c private volatile boolean suspendFlushingOnServerThread = false; // CraftBukkit start protected final org.bukkit.craftbukkit.CraftServer cserver; -@@ -57,12 +58,13 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack +@@ -60,13 +61,14 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack public ServerCommonPacketListenerImpl(MinecraftServer server, Connection connection, CommonListenerCookie cookie) { this.server = server; this.connection = connection; @@ -132,11 +132,12 @@ index fae1523404b7afa2b904faad9242273b3c406aac..16962ccab91d0941e428a2e53aa37e9c // Paper start this.playerBrand = cookie.brandName(); this.cserver = server.server; + this.pluginMessagerChannels = cookie.channels(); + this.keepAlive = cookie.keepAlive(); // Paper end } -@@ -89,13 +91,41 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack +@@ -93,13 +95,41 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack @Override public void handleKeepAlive(ServerboundKeepAlivePacket packet) { @@ -184,7 +185,7 @@ index fae1523404b7afa2b904faad9242273b3c406aac..16962ccab91d0941e428a2e53aa37e9c } @Override -@@ -148,20 +178,23 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack +@@ -225,20 +255,23 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack protected void keepConnectionAlive() { Profiler.get().push("keepAlive"); long millis = Util.getMillis(); @@ -222,13 +223,11 @@ index fae1523404b7afa2b904faad9242273b3c406aac..16962ccab91d0941e428a2e53aa37e9c } } -@@ -341,6 +374,6 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack +@@ -418,6 +451,6 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack } protected CommonListenerCookie createCookie(ClientInformation clientInformation) { -- return new CommonListenerCookie(this.playerProfile(), this.latency, clientInformation, this.transferred, this.playerBrand); // Paper -+ return new CommonListenerCookie(this.playerProfile(), this.latency, clientInformation, this.transferred, this.playerBrand, this.keepAlive); // Paper +- return new CommonListenerCookie(this.playerProfile(), this.latency, clientInformation, this.transferred, this.playerBrand, this.pluginMessagerChannels); // Paper ++ return new CommonListenerCookie(this.playerProfile(), this.latency, clientInformation, this.transferred, this.playerBrand, this.pluginMessagerChannels, this.keepAlive); // Paper } --} -+} -\ No newline at end of file + } diff --git a/paper-server/patches/sources/net/minecraft/server/network/CommonListenerCookie.java.patch b/paper-server/patches/sources/net/minecraft/server/network/CommonListenerCookie.java.patch index 38dc666c1a..fb1abbc461 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/CommonListenerCookie.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/CommonListenerCookie.java.patch @@ -5,9 +5,9 @@ import net.minecraft.server.level.ClientInformation; -public record CommonListenerCookie(GameProfile gameProfile, int latency, ClientInformation clientInformation, boolean transferred) { -+public record CommonListenerCookie(GameProfile gameProfile, int latency, ClientInformation clientInformation, boolean transferred, @org.jetbrains.annotations.Nullable String brandName) { // Paper ++public record CommonListenerCookie(GameProfile gameProfile, int latency, ClientInformation clientInformation, boolean transferred, @org.jetbrains.annotations.Nullable String brandName, java.util.Set channels) { // Paper public static CommonListenerCookie createInitial(GameProfile gameProfile, boolean transferred) { - return new CommonListenerCookie(gameProfile, 0, ClientInformation.createDefault(), transferred); -+ return new CommonListenerCookie(gameProfile, 0, ClientInformation.createDefault(), transferred, null); // Paper ++ return new CommonListenerCookie(gameProfile, 0, ClientInformation.createDefault(), transferred, null, new java.util.HashSet<>()); // Paper } } diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch index a3d4b912c9..1b1b3dddf5 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch @@ -9,7 +9,7 @@ private final boolean transferred; private long keepAliveTime; private boolean keepAlivePending; -@@ -45,6 +_,14 @@ +@@ -45,6 +_,17 @@ private boolean closed = false; private int latency; private volatile boolean suspendFlushingOnServerThread = false; @@ -20,17 +20,21 @@ + public final java.util.Map packCallbacks = new java.util.concurrent.ConcurrentHashMap<>(); // Paper - adventure resource pack callbacks + private static final long KEEPALIVE_LIMIT = Long.getLong("paper.playerconnection.keepalive", 30) * 1000; // Paper - provide property to set keepalive limit + protected static final net.minecraft.resources.ResourceLocation MINECRAFT_BRAND = net.minecraft.resources.ResourceLocation.withDefaultNamespace("brand"); // Paper - Brand support -+ public @Nullable String playerBrand; // Paper ++ // Paper start - retain certain values ++ public @Nullable String playerBrand; ++ public final java.util.Set pluginMessagerChannels; ++ // Paper end - retain certain values public ServerCommonPacketListenerImpl(MinecraftServer server, Connection connection, CommonListenerCookie cookie) { this.server = server; -@@ -52,6 +_,10 @@ +@@ -52,6 +_,11 @@ this.keepAliveTime = Util.getMillis(); this.latency = cookie.latency(); this.transferred = cookie.transferred(); + // Paper start + this.playerBrand = cookie.brandName(); + this.cserver = server.server; ++ this.pluginMessagerChannels = cookie.channels(); + // Paper end } @@ -44,6 +48,88 @@ } } +@@ -90,8 +_,81 @@ + public void handlePong(ServerboundPongPacket packet) { + } + ++ // Paper start ++ public static final net.minecraft.resources.ResourceLocation CUSTOM_REGISTER = net.minecraft.resources.ResourceLocation.withDefaultNamespace("register"); ++ private static final net.minecraft.resources.ResourceLocation CUSTOM_UNREGISTER = net.minecraft.resources.ResourceLocation.withDefaultNamespace("unregister"); ++ // Paper end ++ + @Override + public void handleCustomPayload(ServerboundCustomPayloadPacket packet) { ++ // Paper start ++ if (!(packet.payload() instanceof final net.minecraft.network.protocol.common.custom.DiscardedPayload discardedPayload)) { ++ return; ++ } ++ ++ net.minecraft.network.protocol.PacketUtils.ensureRunningOnSameThread(packet, this, this.server); ++ ++ final net.minecraft.resources.ResourceLocation identifier = packet.payload().type().id(); ++ final byte[] data = discardedPayload.data(); ++ try { ++ final boolean registerChannel = CUSTOM_REGISTER.equals(identifier); ++ if (registerChannel || CUSTOM_UNREGISTER.equals(identifier)) { ++ // Strings separated by zeros instead of length prefixes ++ int startIndex = 0; ++ for (int i = 0; i < data.length; i++) { ++ final byte b = data[i]; ++ if (b != 0) { ++ continue; ++ } ++ ++ readChannelIdentifier(data, startIndex, i, registerChannel); ++ startIndex = i + 1; ++ } ++ ++ // Read the last one ++ readChannelIdentifier(data, startIndex, data.length, registerChannel); ++ return; ++ } ++ ++ if (identifier.equals(MINECRAFT_BRAND)) { ++ this.playerBrand = new net.minecraft.network.FriendlyByteBuf(io.netty.buffer.Unpooled.wrappedBuffer(data)).readUtf(256); ++ } ++ ++ ++ if (this instanceof ServerGamePacketListenerImpl gamePacketListener) { ++ this.cserver.getMessenger().dispatchIncomingMessage(gamePacketListener.player.getBukkitEntity(), identifier.toString(), data); ++ } else if (this instanceof ServerConfigurationPacketListenerImpl configurationPacketListener) { ++ this.cserver.getMessenger().dispatchIncomingMessage(configurationPacketListener.paperConnection, identifier.toString(), data); ++ } ++ } catch (final Exception e) { ++ ServerGamePacketListenerImpl.LOGGER.error("Couldn't handle custom payload on channel {}", identifier, e); ++ this.disconnect(net.minecraft.network.chat.Component.literal("Invalid custom payload payload!"), io.papermc.paper.connection.DisconnectionReason.INVALID_PAYLOAD); // Paper - kick event cause ++ } ++ } ++ ++ private void readChannelIdentifier(final byte[] data, final int from, final int to, final boolean register) { ++ io.papermc.paper.connection.PluginMessageBridgeImpl bridge = switch (this) { ++ case ServerGamePacketListenerImpl gamePacketListener -> gamePacketListener.player.getBukkitEntity(); ++ case ServerConfigurationPacketListenerImpl commonPacketListener -> commonPacketListener.paperConnection; ++ default -> null; ++ }; ++ if (bridge == null) { ++ return; ++ } ++ ++ ++ final int length = to - from; ++ if (length == 0) { ++ return; ++ } ++ ++ final String channel = new String(data, from, length, java.nio.charset.StandardCharsets.US_ASCII); ++ if (register) { ++ bridge.addChannel(channel); ++ } else { ++ bridge.removeChannel(channel); ++ } ++ // Paper end + } + + @Override @@ -105,21 +_,46 @@ PacketUtils.ensureRunningOnSameThread(packet, this, this.server); if (packet.action() == ServerboundResourcePackPacket.Action.DECLINED && this.server.isResourcePackRequired()) { @@ -245,6 +331,6 @@ protected CommonListenerCookie createCookie(ClientInformation clientInformation) { - return new CommonListenerCookie(this.playerProfile(), this.latency, clientInformation, this.transferred); -+ return new CommonListenerCookie(this.playerProfile(), this.latency, clientInformation, this.transferred, this.playerBrand); // Paper ++ return new CommonListenerCookie(this.playerProfile(), this.latency, clientInformation, this.transferred, this.playerBrand, this.pluginMessagerChannels); // Paper } } diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch index d14ee1bbae..88302d352d 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch @@ -99,7 +99,7 @@ this.connection.send(new ClientboundDisconnectPacket(DISCONNECT_REASON_INVALID_DATA)); this.connection.disconnect(DISCONNECT_REASON_INVALID_DATA); } -@@ -180,4 +_,31 @@ +@@ -180,4 +_,29 @@ this.startNextTask(); } } @@ -125,9 +125,7 @@ + + @Override + public void handleCustomPayload(net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket packet) { -+ if (packet.payload() instanceof net.minecraft.network.protocol.common.custom.BrandPayload(String brand)) { -+ this.playerBrand = brand; -+ } ++ super.handleCustomPayload(packet); + } + // Paper end } diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch index cd9988cb2b..8ea0024bc8 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch @@ -2576,7 +2576,7 @@ } } -@@ -2027,27 +_,27 @@ +@@ -2027,27 +_,32 @@ private void resetPlayerChatState(RemoteChatSession chatSession) { this.chatSession = chatSession; @@ -2596,10 +2596,11 @@ + }); } ); -- } -- -- @Override -- public void handleCustomPayload(ServerboundCustomPayloadPacket packet) { + } + + @Override + public void handleCustomPayload(ServerboundCustomPayloadPacket packet) { ++ super.handleCustomPayload(packet); // Paper } @Override @@ -2609,7 +2610,7 @@ if (!this.receivedMovementThisTick) { this.player.setKnownMovement(Vec3.ZERO); } -@@ -2078,4 +_,157 @@ +@@ -2078,4 +_,93 @@ interface EntityInteraction { InteractionResult run(ServerPlayer player, Entity entity, InteractionHand hand); } @@ -2661,70 +2662,6 @@ + }); + } + -+ // Paper start -+ public static final ResourceLocation CUSTOM_REGISTER = ResourceLocation.withDefaultNamespace("register"); // CraftBukkit -+ private static final ResourceLocation CUSTOM_UNREGISTER = ResourceLocation.withDefaultNamespace("unregister"); // CraftBukkit -+ -+ @Override -+ public void handleCustomPayload(ServerboundCustomPayloadPacket packet) { -+ // Paper start -+ if (packet.payload() instanceof net.minecraft.network.protocol.common.custom.BrandPayload(String brand)) { -+ this.playerBrand = brand; -+ } -+ -+ if (!(packet.payload() instanceof final net.minecraft.network.protocol.common.custom.DiscardedPayload discardedPayload)) { -+ return; -+ } -+ -+ PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); -+ -+ final net.minecraft.resources.ResourceLocation identifier = packet.payload().type().id(); -+ final byte[] data = discardedPayload.data(); -+ try { -+ final boolean registerChannel = CUSTOM_REGISTER.equals(identifier); -+ if (registerChannel || CUSTOM_UNREGISTER.equals(identifier)) { -+ // Strings separated by zeros instead of length prefixes -+ int startIndex = 0; -+ for (int i = 0; i < data.length; i++) { -+ final byte b = data[i]; -+ if (b != 0) { -+ continue; -+ } -+ -+ readChannelIdentifier(data, startIndex, i, registerChannel); -+ startIndex = i + 1; -+ } -+ -+ // Read the last one -+ readChannelIdentifier(data, startIndex, data.length, registerChannel); -+ return; -+ } -+ -+ if (identifier.equals(MINECRAFT_BRAND)) { -+ this.player.connection.playerBrand = new net.minecraft.network.FriendlyByteBuf(io.netty.buffer.Unpooled.wrappedBuffer(data)).readUtf(256); -+ } -+ -+ this.cserver.getMessenger().dispatchIncomingMessage(this.player.getBukkitEntity(), identifier.toString(), data); -+ } catch (final Exception e) { -+ ServerGamePacketListenerImpl.LOGGER.error("Couldn't handle custom payload on channel {}", identifier, e); -+ this.disconnect(Component.literal("Invalid custom payload payload!"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PAYLOAD); // Paper - kick event cause -+ } -+ } -+ -+ private void readChannelIdentifier(final byte[] data, final int from, final int to, final boolean register) { -+ final int length = to - from; -+ if (length == 0) { -+ return; -+ } -+ -+ final String channel = new String(data, from, length, java.nio.charset.StandardCharsets.US_ASCII); -+ if (register) { -+ this.getCraftPlayer().addChannel(channel); -+ } else { -+ this.getCraftPlayer().removeChannel(channel); -+ } -+ } -+ + public final boolean isDisconnected() { + return (!this.player.joining && !this.connection.isConnected()) || this.processedDisconnect; // Paper - Fix duplication bugs + } diff --git a/paper-server/src/main/java/io/papermc/paper/connection/DisconnectionReason.java b/paper-server/src/main/java/io/papermc/paper/connection/DisconnectionReason.java index 64fac9b463..8219e75099 100644 --- a/paper-server/src/main/java/io/papermc/paper/connection/DisconnectionReason.java +++ b/paper-server/src/main/java/io/papermc/paper/connection/DisconnectionReason.java @@ -11,6 +11,7 @@ public interface DisconnectionReason { DisconnectionReason RESOURCE_PACK_REJECTION = game(PlayerKickEvent.Cause.RESOURCE_PACK_REJECTION); DisconnectionReason INVALID_COOKIE = game(PlayerKickEvent.Cause.INVALID_COOKIE); DisconnectionReason DUPLICATE_LOGIN_MESSAGE = game(PlayerKickEvent.Cause.DUPLICATE_LOGIN); + DisconnectionReason INVALID_PAYLOAD = game(PlayerKickEvent.Cause.INVALID_PAYLOAD); Optional game(); diff --git a/paper-server/src/main/java/io/papermc/paper/connection/PaperPlayerConfigurationConnection.java b/paper-server/src/main/java/io/papermc/paper/connection/PaperPlayerConfigurationConnection.java index b71fbf68de..ff450bb493 100644 --- a/paper-server/src/main/java/io/papermc/paper/connection/PaperPlayerConfigurationConnection.java +++ b/paper-server/src/main/java/io/papermc/paper/connection/PaperPlayerConfigurationConnection.java @@ -1,7 +1,5 @@ package io.papermc.paper.connection; -import com.destroystokyo.paper.ClientOption; -import com.destroystokyo.paper.PaperSkinParts; import com.destroystokyo.paper.profile.CraftPlayerProfile; import com.destroystokyo.paper.profile.PlayerProfile; import io.papermc.paper.adventure.PaperAdventure; @@ -19,11 +17,13 @@ import net.minecraft.server.network.ConfigurationTask; import net.minecraft.server.network.ServerConfigurationPacketListenerImpl; import org.jspecify.annotations.Nullable; +import java.util.HashSet; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.UUID; -public class PaperPlayerConfigurationConnection extends PaperCommonConnection implements PlayerConfigurationConnection, Audience { +public class PaperPlayerConfigurationConnection extends PaperCommonConnection implements PlayerConfigurationConnection, Audience, PluginMessageBridgeImpl { private @Nullable Pointers adventurePointers; @@ -101,4 +101,9 @@ public class PaperPlayerConfigurationConnection extends PaperCommonConnection channels() { + return this.handle.pluginMessagerChannels; + } } diff --git a/paper-server/src/main/java/io/papermc/paper/connection/PluginMessageBridgeImpl.java b/paper-server/src/main/java/io/papermc/paper/connection/PluginMessageBridgeImpl.java new file mode 100644 index 0000000000..798ebc2be5 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/connection/PluginMessageBridgeImpl.java @@ -0,0 +1,43 @@ +package io.papermc.paper.connection; + +import com.google.common.base.Preconditions; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.event.player.PlayerRegisterChannelEvent; +import org.bukkit.event.player.PlayerUnregisterChannelEvent; +import org.bukkit.plugin.messaging.StandardMessenger; +import org.jspecify.annotations.NullMarked; +import java.util.Set; + +@NullMarked +public interface PluginMessageBridgeImpl { + + boolean DISABLE_CHANNEL_LIMIT = System.getProperty("paper.disableChannelLimit") != null; // Paper - add a flag to disable the channel limit + + default boolean addChannel(String channel) { + Preconditions.checkState(DISABLE_CHANNEL_LIMIT || this.channels().size() < 128, "Cannot register channel. Too many channels registered!"); // Paper - flag to disable channel limit + channel = StandardMessenger.validateAndCorrectChannel(channel); + if (channels().add(channel)) { + if (this instanceof CraftPlayer player) { + Bukkit.getPluginManager().callEvent(new PlayerRegisterChannelEvent(player, channel)); + } + return true; + } + + return false; + } + + default boolean removeChannel(String channel) { + channel = StandardMessenger.validateAndCorrectChannel(channel); + if (channels().remove(channel)) { + if (this instanceof CraftPlayer player) { + Bukkit.getPluginManager().callEvent(new PlayerUnregisterChannelEvent(player, channel)); + } + return true; + } + + return false; + }; + + Set channels(); +} diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index 3ea6d207b2..1e2e8d81e6 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -8,8 +8,8 @@ import com.google.common.io.BaseEncoding; import com.mojang.authlib.GameProfile; import com.mojang.datafixers.util.Pair; import io.papermc.paper.FeatureHooks; -import io.papermc.paper.configuration.GlobalConfiguration; import io.papermc.paper.connection.PlayerGameConnection; +import io.papermc.paper.connection.PluginMessageBridgeImpl; import io.papermc.paper.entity.LookAnchor; import io.papermc.paper.entity.PaperPlayerGiveResult; import io.papermc.paper.entity.PlayerGiveResult; @@ -33,11 +33,9 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Queue; import java.util.Set; import java.util.UUID; import java.util.WeakHashMap; @@ -54,20 +52,13 @@ import net.minecraft.commands.Commands; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.SectionPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.ConnectionProtocol; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.PlayerChatMessage; -import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket; import net.minecraft.network.protocol.common.ClientboundResourcePackPopPacket; import net.minecraft.network.protocol.common.ClientboundResourcePackPushPacket; import net.minecraft.network.protocol.common.ClientboundServerLinksPacket; -import net.minecraft.network.protocol.common.ClientboundStoreCookiePacket; -import net.minecraft.network.protocol.common.ClientboundTransferPacket; import net.minecraft.network.protocol.common.custom.DiscardedPayload; -import net.minecraft.network.protocol.cookie.ClientboundCookieRequestPacket; -import net.minecraft.network.protocol.cookie.ServerboundCookieResponsePacket; import net.minecraft.network.protocol.game.ClientboundBlockDestructionPacket; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; @@ -196,10 +187,8 @@ import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.event.player.PlayerExpCooldownChangeEvent; import org.bukkit.event.player.PlayerHideEntityEvent; -import org.bukkit.event.player.PlayerRegisterChannelEvent; import org.bukkit.event.player.PlayerShowEntityEvent; import org.bukkit.event.player.PlayerTeleportEvent; -import org.bukkit.event.player.PlayerUnregisterChannelEvent; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.InventoryView.Property; import org.bukkit.inventory.ItemStack; @@ -215,7 +204,7 @@ import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; @DelegateDeserialization(CraftOfflinePlayer.class) -public class CraftPlayer extends CraftHumanEntity implements Player { +public class CraftPlayer extends CraftHumanEntity implements Player, PluginMessageBridgeImpl { private static final PointersSupplier POINTERS_SUPPLIER = PointersSupplier.builder() .parent(CraftEntity.POINTERS_SUPPLIER) .resolving(Identity.NAME, Player::getName) @@ -227,7 +216,6 @@ public class CraftPlayer extends CraftHumanEntity implements Player { private long lastPlayed = 0; private boolean hasPlayedBefore = false; private final ConversationTracker conversationTracker = new ConversationTracker(); - private final Set channels = new HashSet(); private final Map>> invertedVisibilityEntities = new HashMap<>(); private final Set unlistedEntities = new HashSet<>(); // Paper - Add Listing API for Player private static final WeakHashMap> pluginWeakReferences = new WeakHashMap<>(); @@ -238,7 +226,6 @@ public class CraftPlayer extends CraftHumanEntity implements Player { private CraftWorldBorder clientWorldBorder = null; private BorderChangeListener clientWorldBorderListener = this.createWorldBorderListener(); public org.bukkit.event.player.PlayerResourcePackStatusEvent.Status resourcePackStatus; // Paper - more resource pack API - private static final boolean DISABLE_CHANNEL_LIMIT = System.getProperty("paper.disableChannelLimit") != null; // Paper - add a flag to disable the channel limit private long lastSaveTime; // Paper - getLastPlayed replacement API public CraftPlayer(CraftServer server, ServerPlayer entity) { @@ -2378,7 +2365,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { StandardMessenger.validatePluginMessage(this.server.getMessenger(), source, channel, message); if (this.getHandle().connection == null) return; - if (this.channels.contains(channel)) { + if (this.channels().contains(channel)) { ResourceLocation id = ResourceLocation.parse(StandardMessenger.validateAndCorrectChannel(channel)); this.sendCustomPayload(id, message); } @@ -2530,24 +2517,16 @@ public class CraftPlayer extends CraftHumanEntity implements Player { this.getHandle().connection.send(resourcePackPushPacket); } - public void addChannel(String channel) { - Preconditions.checkState(DISABLE_CHANNEL_LIMIT || this.channels.size() < 128, "Cannot register channel. Too many channels registered!"); // Paper - flag to disable channel limit - channel = StandardMessenger.validateAndCorrectChannel(channel); - if (this.channels.add(channel)) { - this.server.getPluginManager().callEvent(new PlayerRegisterChannelEvent(this, channel)); - } - } + @Override + public Set channels() { + if (this.getHandle().connection == null) return new HashSet<>(); - public void removeChannel(String channel) { - channel = StandardMessenger.validateAndCorrectChannel(channel); - if (this.channels.remove(channel)) { - this.server.getPluginManager().callEvent(new PlayerUnregisterChannelEvent(this, channel)); - } + return this.getHandle().connection.pluginMessagerChannels; } @Override public Set getListeningPluginChannels() { - return ImmutableSet.copyOf(this.channels); + return ImmutableSet.copyOf(this.channels()); } public void sendSupportedChannels() {