379 lines
19 KiB
Diff
379 lines
19 KiB
Diff
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
|
From: Minecrell <minecrell@minecrell.net>
|
||
|
Date: Wed, 11 Oct 2017 15:56:26 +0200
|
||
|
Subject: [PATCH] Implement extended PaperServerListPingEvent
|
||
|
|
||
|
|
||
|
diff --git a/src/main/java/com/destroystokyo/paper/network/PaperServerListPingEventImpl.java b/src/main/java/com/destroystokyo/paper/network/PaperServerListPingEventImpl.java
|
||
|
new file mode 100644
|
||
|
index 0000000000000000000000000000000000000000..4ecd0c5bbea55f68549c85aa27e80e2c7e6265d4
|
||
|
--- /dev/null
|
||
|
+++ b/src/main/java/com/destroystokyo/paper/network/PaperServerListPingEventImpl.java
|
||
|
@@ -0,0 +1,31 @@
|
||
|
+package com.destroystokyo.paper.network;
|
||
|
+
|
||
|
+import com.destroystokyo.paper.event.server.PaperServerListPingEvent;
|
||
|
+import net.minecraft.server.MinecraftServer;
|
||
|
+import net.minecraft.server.level.ServerPlayer;
|
||
|
+import org.bukkit.entity.Player;
|
||
|
+import org.bukkit.util.CachedServerIcon;
|
||
|
+
|
||
|
+import javax.annotation.Nullable;
|
||
|
+
|
||
|
+class PaperServerListPingEventImpl extends PaperServerListPingEvent {
|
||
|
+
|
||
|
+ private final MinecraftServer server;
|
||
|
+
|
||
|
+ PaperServerListPingEventImpl(MinecraftServer server, StatusClient client, int protocolVersion, @Nullable CachedServerIcon icon) {
|
||
|
+ super(client, server.getMotd(), server.getPlayerCount(), server.getMaxPlayers(),
|
||
|
+ server.getServerModName() + ' ' + server.getServerVersion(), protocolVersion, icon);
|
||
|
+ this.server = server;
|
||
|
+ }
|
||
|
+
|
||
|
+ @Override
|
||
|
+ protected final Object[] getOnlinePlayers() {
|
||
|
+ return this.server.getPlayerList().players.toArray();
|
||
|
+ }
|
||
|
+
|
||
|
+ @Override
|
||
|
+ protected final Player getBukkitPlayer(Object player) {
|
||
|
+ return ((ServerPlayer) player).getBukkitEntity();
|
||
|
+ }
|
||
|
+
|
||
|
+}
|
||
|
diff --git a/src/main/java/com/destroystokyo/paper/network/PaperStatusClient.java b/src/main/java/com/destroystokyo/paper/network/PaperStatusClient.java
|
||
|
new file mode 100644
|
||
|
index 0000000000000000000000000000000000000000..d926ad804355ee2fdc5910b2505e8671602acdab
|
||
|
--- /dev/null
|
||
|
+++ b/src/main/java/com/destroystokyo/paper/network/PaperStatusClient.java
|
||
|
@@ -0,0 +1,11 @@
|
||
|
+package com.destroystokyo.paper.network;
|
||
|
+
|
||
|
+import net.minecraft.network.Connection;
|
||
|
+
|
||
|
+class PaperStatusClient extends PaperNetworkClient implements StatusClient {
|
||
|
+
|
||
|
+ PaperStatusClient(Connection networkManager) {
|
||
|
+ super(networkManager);
|
||
|
+ }
|
||
|
+
|
||
|
+}
|
||
|
diff --git a/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java b/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java
|
||
|
new file mode 100644
|
||
|
index 0000000000000000000000000000000000000000..4c2351b03b58511b80017b58ee9b20ab5193adc9
|
||
|
--- /dev/null
|
||
|
+++ b/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java
|
||
|
@@ -0,0 +1,110 @@
|
||
|
+package com.destroystokyo.paper.network;
|
||
|
+
|
||
|
+import com.destroystokyo.paper.profile.CraftPlayerProfile;
|
||
|
+import com.destroystokyo.paper.profile.PlayerProfile;
|
||
|
+import com.google.common.base.MoreObjects;
|
||
|
+import com.google.common.base.Strings;
|
||
|
+import com.mojang.authlib.GameProfile;
|
||
|
+import io.papermc.paper.adventure.AdventureComponent;
|
||
|
+import java.util.List;
|
||
|
+import java.util.UUID;
|
||
|
+import javax.annotation.Nonnull;
|
||
|
+import net.minecraft.network.Connection;
|
||
|
+import net.minecraft.network.protocol.status.ClientboundStatusResponsePacket;
|
||
|
+import net.minecraft.network.protocol.status.ServerStatus;
|
||
|
+import net.minecraft.server.MinecraftServer;
|
||
|
+
|
||
|
+public final class StandardPaperServerListPingEventImpl extends PaperServerListPingEventImpl {
|
||
|
+
|
||
|
+ private static final GameProfile[] EMPTY_PROFILES = new GameProfile[0];
|
||
|
+ private static final UUID FAKE_UUID = new UUID(0, 0);
|
||
|
+
|
||
|
+ private GameProfile[] originalSample;
|
||
|
+
|
||
|
+ private StandardPaperServerListPingEventImpl(MinecraftServer server, Connection networkManager, ServerStatus ping) {
|
||
|
+ super(server, new PaperStatusClient(networkManager), ping.getVersion() != null ? ping.getVersion().getProtocol() : -1, server.server.getServerIcon());
|
||
|
+ this.originalSample = ping.getPlayers() == null ? null : ping.getPlayers().getSample(); // GH-1473 - pre-tick race condition NPE
|
||
|
+ }
|
||
|
+
|
||
|
+ @Nonnull
|
||
|
+ @Override
|
||
|
+ public List<PlayerProfile> getPlayerSample() {
|
||
|
+ List<PlayerProfile> sample = super.getPlayerSample();
|
||
|
+
|
||
|
+ if (this.originalSample != null) {
|
||
|
+ for (GameProfile profile : this.originalSample) {
|
||
|
+ sample.add(CraftPlayerProfile.asBukkitCopy(profile));
|
||
|
+ }
|
||
|
+ this.originalSample = null;
|
||
|
+ }
|
||
|
+
|
||
|
+ return sample;
|
||
|
+ }
|
||
|
+
|
||
|
+ private GameProfile[] getPlayerSampleHandle() {
|
||
|
+ if (this.originalSample != null) {
|
||
|
+ return this.originalSample;
|
||
|
+ }
|
||
|
+
|
||
|
+ List<PlayerProfile> entries = super.getPlayerSample();
|
||
|
+ if (entries.isEmpty()) {
|
||
|
+ return EMPTY_PROFILES;
|
||
|
+ }
|
||
|
+
|
||
|
+ GameProfile[] profiles = new GameProfile[entries.size()];
|
||
|
+ for (int i = 0; i < profiles.length; i++) {
|
||
|
+ /*
|
||
|
+ * Avoid null UUIDs/names since that will make the response invalid
|
||
|
+ * on the client.
|
||
|
+ * Instead, fall back to a fake/empty UUID and an empty string as name.
|
||
|
+ * This can be used to create custom lines in the player list that do not
|
||
|
+ * refer to a specific player.
|
||
|
+ */
|
||
|
+
|
||
|
+ PlayerProfile profile = entries.get(i);
|
||
|
+ if (profile.getId() != null && profile.getName() != null) {
|
||
|
+ profiles[i] = CraftPlayerProfile.asAuthlib(profile);
|
||
|
+ } else {
|
||
|
+ profiles[i] = new GameProfile(MoreObjects.firstNonNull(profile.getId(), FAKE_UUID), Strings.nullToEmpty(profile.getName()));
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ return profiles;
|
||
|
+ }
|
||
|
+
|
||
|
+ @SuppressWarnings("deprecation")
|
||
|
+ public static void processRequest(MinecraftServer server, Connection networkManager) {
|
||
|
+ StandardPaperServerListPingEventImpl event = new StandardPaperServerListPingEventImpl(server, networkManager, server.getStatus());
|
||
|
+ server.server.getPluginManager().callEvent(event);
|
||
|
+
|
||
|
+ // Close connection immediately if event is cancelled
|
||
|
+ if (event.isCancelled()) {
|
||
|
+ networkManager.disconnect(null);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ // Setup response
|
||
|
+ ServerStatus ping = new ServerStatus();
|
||
|
+
|
||
|
+ // Description
|
||
|
+ ping.setDescription(new AdventureComponent(event.motd()));
|
||
|
+
|
||
|
+ // Players
|
||
|
+ if (!event.shouldHidePlayers()) {
|
||
|
+ ping.setPlayers(new ServerStatus.Players(event.getMaxPlayers(), event.getNumPlayers()));
|
||
|
+ ping.getPlayers().setSample(event.getPlayerSampleHandle());
|
||
|
+ }
|
||
|
+
|
||
|
+ // Version
|
||
|
+ ping.setVersion(new ServerStatus.Version(event.getVersion(), event.getProtocolVersion()));
|
||
|
+
|
||
|
+ // Favicon
|
||
|
+ if (event.getServerIcon() != null) {
|
||
|
+ ping.setFavicon(event.getServerIcon().getData());
|
||
|
+ }
|
||
|
+
|
||
|
+ // Send response
|
||
|
+ networkManager.send(new ClientboundStatusResponsePacket(ping));
|
||
|
+ }
|
||
|
+
|
||
|
+}
|
||
|
diff --git a/src/main/java/net/minecraft/network/protocol/status/ClientboundStatusResponsePacket.java b/src/main/java/net/minecraft/network/protocol/status/ClientboundStatusResponsePacket.java
|
||
|
index b985d238eadf857602636ba5e5c277d4b1992d35..5b2081f920304244df96de78b2c66cf8a49a5b85 100644
|
||
|
--- a/src/main/java/net/minecraft/network/protocol/status/ClientboundStatusResponsePacket.java
|
||
|
+++ b/src/main/java/net/minecraft/network/protocol/status/ClientboundStatusResponsePacket.java
|
||
|
@@ -2,6 +2,7 @@ package net.minecraft.network.protocol.status;
|
||
|
|
||
|
import com.google.gson.Gson;
|
||
|
import com.google.gson.GsonBuilder;
|
||
|
+import io.papermc.paper.adventure.AdventureComponent; // Paper
|
||
|
import java.io.IOException;
|
||
|
import net.minecraft.network.FriendlyByteBuf;
|
||
|
import net.minecraft.network.chat.Component;
|
||
|
@@ -12,7 +13,9 @@ import net.minecraft.util.LowerCaseEnumTypeAdapterFactory;
|
||
|
|
||
|
public class ClientboundStatusResponsePacket implements Packet<ClientStatusPacketListener> {
|
||
|
|
||
|
- private static final Gson GSON = (new GsonBuilder()).registerTypeAdapter(ServerStatus.Version.class, new ServerStatus.Version.Serializer()).registerTypeAdapter(ServerStatus.Players.class, new ServerStatus.Players.Serializer()).registerTypeAdapter(ServerStatus.class, new ServerStatus.Serializer()).registerTypeHierarchyAdapter(Component.class, new Component.Serializer()).registerTypeHierarchyAdapter(Style.class, new Style.Serializer()).registerTypeAdapterFactory(new LowerCaseEnumTypeAdapterFactory()).create();
|
||
|
+ private static final Gson GSON = (new GsonBuilder()).registerTypeAdapter(ServerStatus.Version.class, new ServerStatus.Version.Serializer()).registerTypeAdapter(ServerStatus.Players.class, new ServerStatus.Players.Serializer()).registerTypeAdapter(ServerStatus.class, new ServerStatus.Serializer()).registerTypeHierarchyAdapter(Component.class, new Component.Serializer()).registerTypeHierarchyAdapter(Style.class, new Style.Serializer()).registerTypeAdapterFactory(new LowerCaseEnumTypeAdapterFactory())
|
||
|
+ .registerTypeAdapter(AdventureComponent.class, new AdventureComponent.Serializer())
|
||
|
+ .create();
|
||
|
private ServerStatus status;
|
||
|
|
||
|
public ClientboundStatusResponsePacket() {}
|
||
|
diff --git a/src/main/java/net/minecraft/network/protocol/status/ServerStatus.java b/src/main/java/net/minecraft/network/protocol/status/ServerStatus.java
|
||
|
index d6be3dd6cfed3f65325398fc33663cb251f87ac7..31d45cd635eae2ff406cb0441f2cd2aee833b945 100644
|
||
|
--- a/src/main/java/net/minecraft/network/protocol/status/ServerStatus.java
|
||
|
+++ b/src/main/java/net/minecraft/network/protocol/status/ServerStatus.java
|
||
|
@@ -31,6 +31,7 @@ public class ServerStatus {
|
||
|
this.description = description;
|
||
|
}
|
||
|
|
||
|
+ public Players getPlayers() { return getPlayers(); } // Paper - OBFHELPER
|
||
|
public ServerStatus.Players getPlayers() {
|
||
|
return this.players;
|
||
|
}
|
||
|
@@ -162,10 +163,12 @@ public class ServerStatus {
|
||
|
return this.numPlayers;
|
||
|
}
|
||
|
|
||
|
+ public GameProfile[] getSample() { return getSample(); } // Paper - OBFHELPER
|
||
|
public GameProfile[] getSample() {
|
||
|
return this.sample;
|
||
|
}
|
||
|
|
||
|
+ public void setSample(GameProfile[] sample) { setSample(sample); } // Paper - OBFHELPER
|
||
|
public void setSample(GameProfile[] sample) {
|
||
|
this.sample = sample;
|
||
|
}
|
||
|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||
|
index 4b3341877629c7065496fb0f0b4d509f5a48db6d..d34da1eb172a7dcda564680afecf3dc145bf09f3 100644
|
||
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||
|
@@ -2,6 +2,9 @@ package net.minecraft.server;
|
||
|
|
||
|
import com.google.common.base.Splitter;
|
||
|
import com.google.common.collect.ImmutableList;
|
||
|
+import co.aikar.timings.Timings;
|
||
|
+import com.destroystokyo.paper.event.server.PaperServerListPingEvent;
|
||
|
+import com.google.common.base.Stopwatch;
|
||
|
import com.google.common.collect.Lists;
|
||
|
import com.google.common.collect.Maps;
|
||
|
import com.google.common.collect.Sets;
|
||
|
@@ -1238,7 +1241,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||
|
if (i - this.lastServerStatus >= 5000000000L) {
|
||
|
this.lastServerStatus = i;
|
||
|
this.status.setPlayers(new ServerStatus.Players(this.getMaxPlayers(), this.getPlayerCount()));
|
||
|
- GameProfile[] agameprofile = new GameProfile[Math.min(this.getPlayerCount(), 12)];
|
||
|
+ GameProfile[] agameprofile = new GameProfile[Math.min(this.getPlayerCount(), org.spigotmc.SpigotConfig.playerSample)]; // Paper
|
||
|
int j = Mth.nextInt(this.random, 0, this.getPlayerCount() - agameprofile.length);
|
||
|
|
||
|
for (int k = 0; k < agameprofile.length; ++k) {
|
||
|
diff --git a/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java
|
||
|
index 223df8d27c2ff1cbff634bca3dbde5cc24de7f98..f74e3cbdff8c2d83809f04f42717501d7b1a1ed2 100644
|
||
|
--- a/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java
|
||
|
+++ b/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java
|
||
|
@@ -1,7 +1,7 @@
|
||
|
package net.minecraft.server.network;
|
||
|
|
||
|
import net.minecraft.server.MinecraftServer;
|
||
|
-import net.minecraft.server.level.ServerPlayer;
|
||
|
+
|
||
|
// CraftBukkit start
|
||
|
import com.mojang.authlib.GameProfile;
|
||
|
import java.net.InetSocketAddress;
|
||
|
@@ -11,8 +11,6 @@ import net.minecraft.network.Connection;
|
||
|
import net.minecraft.network.chat.Component;
|
||
|
import net.minecraft.network.chat.TranslatableComponent;
|
||
|
import net.minecraft.network.protocol.status.ClientboundPongResponsePacket;
|
||
|
-import net.minecraft.network.protocol.status.ClientboundStatusResponsePacket;
|
||
|
-import net.minecraft.network.protocol.status.ServerStatus;
|
||
|
import net.minecraft.network.protocol.status.ServerStatusPacketListener;
|
||
|
import net.minecraft.network.protocol.status.ServerboundPingRequestPacket;
|
||
|
import net.minecraft.network.protocol.status.ServerboundStatusRequestPacket;
|
||
|
@@ -47,15 +45,17 @@ public class ServerStatusPacketListenerImpl implements ServerStatusPacketListene
|
||
|
this.connection.disconnect(ServerStatusPacketListenerImpl.DISCONNECT_REASON);
|
||
|
} else {
|
||
|
this.hasRequestedStatus = true;
|
||
|
+ // Paper start - Replace everything
|
||
|
+ /*
|
||
|
// CraftBukkit start
|
||
|
// this.networkManager.sendPacket(new PacketStatusOutServerInfo(this.minecraftServer.getServerPing()));
|
||
|
- final Object[] players = server.getPlayerList().players.toArray();
|
||
|
+ final Object[] players = minecraftServer.getPlayerList().players.toArray();
|
||
|
class ServerListPingEvent extends org.bukkit.event.server.ServerListPingEvent {
|
||
|
|
||
|
- CraftIconCache icon = server.server.getServerIcon();
|
||
|
+ CraftIconCache icon = minecraftServer.server.getServerIcon();
|
||
|
|
||
|
ServerListPingEvent() {
|
||
|
- super(((InetSocketAddress) connection.getRemoteAddress()).getAddress(), server.server.motd(), server.getPlayerList().getMaxPlayers()); // Paper - Adventure
|
||
|
+ super(((InetSocketAddress) networkManager.getSocketAddress()).getAddress(), minecraftServer.server.motd(), minecraftServer.getPlayerList().getMaxPlayers()); // Paper - Adventure
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
@@ -71,7 +71,7 @@ public class ServerStatusPacketListenerImpl implements ServerStatusPacketListene
|
||
|
return new Iterator<Player>() {
|
||
|
int i;
|
||
|
int ret = Integer.MIN_VALUE;
|
||
|
- ServerPlayer player;
|
||
|
+ EntityPlayer player;
|
||
|
|
||
|
@Override
|
||
|
public boolean hasNext() {
|
||
|
@@ -80,7 +80,7 @@ public class ServerStatusPacketListenerImpl implements ServerStatusPacketListene
|
||
|
}
|
||
|
final Object[] currentPlayers = players;
|
||
|
for (int length = currentPlayers.length, i = this.i; i < length; i++) {
|
||
|
- final ServerPlayer player = (ServerPlayer) currentPlayers[i];
|
||
|
+ final EntityPlayer player = (EntityPlayer) currentPlayers[i];
|
||
|
if (player != null) {
|
||
|
this.i = i + 1;
|
||
|
this.player = player;
|
||
|
@@ -95,7 +95,7 @@ public class ServerStatusPacketListenerImpl implements ServerStatusPacketListene
|
||
|
if (!hasNext()) {
|
||
|
throw new java.util.NoSuchElementException();
|
||
|
}
|
||
|
- final ServerPlayer player = this.player;
|
||
|
+ final EntityPlayer player = this.player;
|
||
|
this.player = null;
|
||
|
this.ret = this.i - 1;
|
||
|
return player.getBukkitEntity();
|
||
|
@@ -115,16 +115,16 @@ public class ServerStatusPacketListenerImpl implements ServerStatusPacketListene
|
||
|
}
|
||
|
|
||
|
ServerListPingEvent event = new ServerListPingEvent();
|
||
|
- this.server.server.getPluginManager().callEvent(event);
|
||
|
+ this.minecraftServer.server.getPluginManager().callEvent(event);
|
||
|
|
||
|
java.util.List<GameProfile> profiles = new java.util.ArrayList<GameProfile>(players.length);
|
||
|
for (Object player : players) {
|
||
|
if (player != null) {
|
||
|
- profiles.add(((ServerPlayer) player).getGameProfile());
|
||
|
+ profiles.add(((EntityPlayer) player).getProfile());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- ServerStatus.Players playerSample = new ServerStatus.Players(event.getMaxPlayers(), profiles.size());
|
||
|
+ ServerPing.ServerPingPlayerSample playerSample = new ServerPing.ServerPingPlayerSample(event.getMaxPlayers(), profiles.size());
|
||
|
// Spigot Start
|
||
|
if ( !profiles.isEmpty() )
|
||
|
{
|
||
|
@@ -132,16 +132,19 @@ public class ServerStatusPacketListenerImpl implements ServerStatusPacketListene
|
||
|
profiles = profiles.subList( 0, Math.min( profiles.size(), org.spigotmc.SpigotConfig.playerSample ) ); // Cap the sample to n (or less) displayed players, ie: Vanilla behaviour
|
||
|
}
|
||
|
// Spigot End
|
||
|
- playerSample.setSample(profiles.toArray(new GameProfile[profiles.size()]));
|
||
|
+ playerSample.a(profiles.toArray(new GameProfile[profiles.size()]));
|
||
|
|
||
|
- ServerStatus ping = new ServerStatus();
|
||
|
+ ServerPing ping = new ServerPing();
|
||
|
ping.setFavicon(event.icon.value);
|
||
|
- ping.setDescription(CraftChatMessage.fromString(event.getMotd(), true)[0]);
|
||
|
- ping.setPlayers(playerSample);
|
||
|
- int version = SharedConstants.getCurrentVersion().getProtocolVersion();
|
||
|
- ping.setVersion(new ServerStatus.Version(server.getServerModName() + " " + server.getServerVersion(), version));
|
||
|
-
|
||
|
- this.connection.send(new ClientboundStatusResponsePacket(ping));
|
||
|
+ ping.setMOTD(CraftChatMessage.fromString(event.getMotd(), true)[0]);
|
||
|
+ ping.setPlayerSample(playerSample);
|
||
|
+ int version = SharedConstants.getGameVersion().getProtocolVersion();
|
||
|
+ ping.setServerInfo(new ServerPing.ServerData(minecraftServer.getServerModName() + " " + minecraftServer.getVersion(), version));
|
||
|
+
|
||
|
+ this.networkManager.sendPacket(new PacketStatusOutServerInfo(ping));
|
||
|
+ */
|
||
|
+ com.destroystokyo.paper.network.StandardPaperServerListPingEventImpl.processRequest(this.server, this.connection);
|
||
|
+ // Paper end
|
||
|
}
|
||
|
// CraftBukkit end
|
||
|
}
|
||
|
diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java
|
||
|
index 3981ba5957fdc2929d54515f2b98bb7a4611e938..652b820a4c0bbf7b6bbb8200927a663665583606 100644
|
||
|
--- a/src/main/java/org/spigotmc/SpigotConfig.java
|
||
|
+++ b/src/main/java/org/spigotmc/SpigotConfig.java
|
||
|
@@ -289,7 +289,7 @@ public class SpigotConfig
|
||
|
public static int playerSample;
|
||
|
private static void playerSample()
|
||
|
{
|
||
|
- playerSample = getInt( "settings.sample-count", 12 );
|
||
|
+ playerSample = Math.max( getInt( "settings.sample-count", 12 ), 0 ); // Paper - Avoid negative counts
|
||
|
Bukkit.getLogger().log( Level.INFO, "Server Ping Player Sample Count: {0}", playerSample ); // Paper - Use logger
|
||
|
}
|
||
|
|