diff --git a/paper-api/src/main/java/com/destroystokyo/paper/event/server/PaperServerListPingEvent.java b/paper-api/src/main/java/com/destroystokyo/paper/event/server/PaperServerListPingEvent.java
index 15b12abe17da..3a576941ae73 100644
--- a/paper-api/src/main/java/com/destroystokyo/paper/event/server/PaperServerListPingEvent.java
+++ b/paper-api/src/main/java/com/destroystokyo/paper/event/server/PaperServerListPingEvent.java
@@ -31,6 +31,16 @@
/**
* Extended version of {@link ServerListPingEvent} that allows full control
* of the response sent to the client.
+ *
+ * This event will sometimes fire synchronously, depending on how it was
+ * triggered.
+ *
+ * If a request is done from outside the server, via the Minecraft client
+ * server menu or external tools, this event will be asynchronous.
+ * If a player joins the server, this event will be synchronous.
+ *
+ * Care should be taken to check {@link #isAsynchronous()} and treat the event
+ * appropriately.
*/
public class PaperServerListPingEvent extends ServerListPingEvent implements Cancellable {
@@ -56,9 +66,9 @@ public class PaperServerListPingEvent extends ServerListPingEvent implements Can
private Object[] players;
@ApiStatus.Internal
- public PaperServerListPingEvent(@NotNull StatusClient client, @NotNull net.kyori.adventure.text.Component motd, int numPlayers, int maxPlayers,
- @NotNull String version, int protocolVersion, @Nullable CachedServerIcon favicon) {
- super("", client.getAddress().getAddress(), motd, numPlayers, maxPlayers);
+ public PaperServerListPingEvent(final boolean async, @NotNull StatusClient client, @NotNull net.kyori.adventure.text.Component motd, int numPlayers,
+ int maxPlayers, @NotNull String version, int protocolVersion, @Nullable CachedServerIcon favicon) {
+ super(async, "", client.getAddress().getAddress(), motd, numPlayers, maxPlayers);
this.client = client;
this.numPlayers = numPlayers;
this.version = version;
diff --git a/paper-api/src/main/java/org/bukkit/event/server/ServerListPingEvent.java b/paper-api/src/main/java/org/bukkit/event/server/ServerListPingEvent.java
index fdc39724354f..45aa876dfce1 100644
--- a/paper-api/src/main/java/org/bukkit/event/server/ServerListPingEvent.java
+++ b/paper-api/src/main/java/org/bukkit/event/server/ServerListPingEvent.java
@@ -35,8 +35,8 @@ public class ServerListPingEvent extends ServerEvent implements Iterable
@ApiStatus.Internal
@Deprecated(forRemoval = true)
- public ServerListPingEvent(@NotNull final String hostname, @NotNull final InetAddress address, @NotNull final String motd, final int numPlayers, final int maxPlayers) {
- super(true);
+ public ServerListPingEvent(final boolean async, @NotNull final String hostname, @NotNull final InetAddress address, @NotNull final String motd, final int numPlayers, final int maxPlayers) {
+ super(async);
Preconditions.checkArgument(numPlayers >= 0, "Cannot have negative number of players online", numPlayers);
this.hostname = hostname;
this.address = address;
@@ -47,8 +47,8 @@ public ServerListPingEvent(@NotNull final String hostname, @NotNull final InetAd
@ApiStatus.Internal
@Deprecated(forRemoval = true)
- protected ServerListPingEvent(@NotNull final String hostname, @NotNull final InetAddress address, @NotNull final String motd, final int maxPlayers) {
- super(true);
+ protected ServerListPingEvent(final boolean async, @NotNull final String hostname, @NotNull final InetAddress address, @NotNull final String motd, final int maxPlayers) {
+ super(async);
this.numPlayers = MAGIC_PLAYER_COUNT;
this.hostname = hostname;
this.address = address;
@@ -58,13 +58,13 @@ protected ServerListPingEvent(@NotNull final String hostname, @NotNull final Ine
@ApiStatus.Internal
@Deprecated(forRemoval = true)
- public ServerListPingEvent(@NotNull final InetAddress address, @NotNull final Component motd, final int numPlayers, final int maxPlayers) {
- this("", address, motd, numPlayers, maxPlayers);
+ public ServerListPingEvent(final boolean async, @NotNull final InetAddress address, @NotNull final Component motd, final int numPlayers, final int maxPlayers) {
+ this(async, "", address, motd, numPlayers, maxPlayers);
}
@ApiStatus.Internal
- public ServerListPingEvent(@NotNull final String hostname, @NotNull final InetAddress address, @NotNull final Component motd, final int numPlayers, final int maxPlayers) {
- super(true);
+ public ServerListPingEvent(final boolean async, @NotNull final String hostname, @NotNull final InetAddress address, @NotNull final Component motd, final int numPlayers, final int maxPlayers) {
+ super(async);
this.hostname = hostname;
this.address = address;
this.motd = motd;
diff --git a/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch b/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch
index 7ba449bd2628..5ccf096d56af 100644
--- a/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch
+++ b/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch
@@ -86,7 +86,7 @@
serverGamePacketListenerImpl.send(new ClientboundChangeDifficultyPacket(levelData.getDifficulty(), levelData.isDifficultyLocked()));
serverGamePacketListenerImpl.send(new ClientboundPlayerAbilitiesPacket(player.getAbilities()));
serverGamePacketListenerImpl.send(new ClientboundSetHeldSlotPacket(player.getInventory().getSelectedSlot()));
-@@ -203,24 +_,129 @@
+@@ -203,24 +_,135 @@
mutableComponent = Component.translatable("multiplayer.player.joined.renamed", player.getDisplayName(), string);
}
@@ -97,7 +97,14 @@
serverGamePacketListenerImpl.teleport(player.getX(), player.getY(), player.getZ(), player.getYRot(), player.getXRot());
ServerStatus status = this.server.getStatus();
if (status != null && !cookie.transferred()) {
- player.sendServerStatus(status);
+- player.sendServerStatus(status);
++ // Paper start - Fire PaperServerListPingEvent when the player joins
++ // player.sendServerStatus(status);
++ status = com.destroystokyo.paper.network.StandardPaperServerListPingEventImpl.getEventResponse(this.server, player.connection.connection, false);
++ if (status != null) {
++ player.sendServerStatus(status);
++ }
++ // Paper end - Fire PaperServerListPingEvent when the player joins
}
- player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(this.players));
diff --git a/paper-server/src/main/java/com/destroystokyo/paper/network/PaperLegacyStatusClient.java b/paper-server/src/main/java/com/destroystokyo/paper/network/PaperLegacyStatusClient.java
index cc54b1c20798..fdb44713a432 100644
--- a/paper-server/src/main/java/com/destroystokyo/paper/network/PaperLegacyStatusClient.java
+++ b/paper-server/src/main/java/com/destroystokyo/paper/network/PaperLegacyStatusClient.java
@@ -47,7 +47,7 @@ public static PaperServerListPingEvent processRequest(MinecraftServer server,
InetSocketAddress address, int protocolVersion, @Nullable InetSocketAddress virtualHost) {
PaperServerListPingEvent event = new PaperServerListPingEventImpl(server,
- new PaperLegacyStatusClient(address, protocolVersion, virtualHost), Byte.MAX_VALUE, null);
+ new PaperLegacyStatusClient(address, protocolVersion, virtualHost), Byte.MAX_VALUE, null, true);
server.server.getPluginManager().callEvent(event);
if (event.isCancelled()) {
diff --git a/paper-server/src/main/java/com/destroystokyo/paper/network/PaperServerListPingEventImpl.java b/paper-server/src/main/java/com/destroystokyo/paper/network/PaperServerListPingEventImpl.java
index 6ed2114f577c..cb6ee6155081 100644
--- a/paper-server/src/main/java/com/destroystokyo/paper/network/PaperServerListPingEventImpl.java
+++ b/paper-server/src/main/java/com/destroystokyo/paper/network/PaperServerListPingEventImpl.java
@@ -12,8 +12,8 @@ class PaperServerListPingEventImpl extends PaperServerListPingEvent {
private final MinecraftServer server;
- PaperServerListPingEventImpl(MinecraftServer server, StatusClient client, int protocolVersion, @Nullable CachedServerIcon icon) {
- super(client, server.motd(), server.getPlayerCount(), server.getMaxPlayers(),
+ PaperServerListPingEventImpl(MinecraftServer server, StatusClient client, int protocolVersion, @Nullable CachedServerIcon icon, boolean async) {
+ super(async, client, server.motd(), server.getPlayerCount(), server.getMaxPlayers(),
server.getServerModName() + ' ' + server.getServerVersion(), protocolVersion, icon);
this.server = server;
}
diff --git a/paper-server/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java b/paper-server/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java
index b40b79beb311..5bd854dfd057 100644
--- a/paper-server/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java
+++ b/paper-server/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java
@@ -20,8 +20,8 @@ public final class StandardPaperServerListPingEventImpl extends PaperServerListP
private List originalSample;
- private StandardPaperServerListPingEventImpl(MinecraftServer server, Connection networkManager, ServerStatus ping) {
- super(server, new PaperStatusClient(networkManager), ping.version().map(ServerStatus.Version::protocol).orElse(-1), server.server.getServerIcon());
+ private StandardPaperServerListPingEventImpl(MinecraftServer server, Connection networkManager, ServerStatus ping, boolean async) {
+ super(server, new PaperStatusClient(networkManager), ping.version().map(ServerStatus.Version::protocol).orElse(-1), server.server.getServerIcon(), async);
this.originalSample = ping.players().map(ServerStatus.Players::sample).orElse(null); // GH-1473 - pre-tick race condition NPE
}
@@ -64,13 +64,24 @@ private List getPlayerSampleHandle() {
}
public static void processRequest(MinecraftServer server, Connection networkManager) {
- StandardPaperServerListPingEventImpl event = new StandardPaperServerListPingEventImpl(server, networkManager, server.getStatus());
+ ServerStatus ping = getEventResponse(server, networkManager, true);
+
+ if (ping == null) {
+ networkManager.disconnect((Component) null);
+ return;
+ }
+
+ // Send response
+ networkManager.send(new ClientboundStatusResponsePacket(ping));
+ }
+
+ public static ServerStatus getEventResponse(MinecraftServer server, Connection networkManager, boolean async) {
+ StandardPaperServerListPingEventImpl event = new StandardPaperServerListPingEventImpl(server, networkManager, server.getStatus(), async);
server.server.getPluginManager().callEvent(event);
// Close connection immediately if event is cancelled
if (event.isCancelled()) {
- networkManager.disconnect((Component) null);
- return;
+ return null;
}
// Setup response
@@ -96,10 +107,9 @@ public static void processRequest(MinecraftServer server, Connection networkMana
} else {
favicon = Optional.empty();
}
- final ServerStatus ping = new ServerStatus(description, players, Optional.of(version), favicon, server.enforceSecureProfile());
- // Send response
- networkManager.send(new ClientboundStatusResponsePacket(ping));
+ // Return response
+ return new ServerStatus(description, players, Optional.of(version), favicon, server.enforceSecureProfile());
}
}