diff options
Diffstat (limited to 'patches/server/0181-Implement-extended-PaperServerListPingEvent.patch')
-rw-r--r-- | patches/server/0181-Implement-extended-PaperServerListPingEvent.patch | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/patches/server/0181-Implement-extended-PaperServerListPingEvent.patch b/patches/server/0181-Implement-extended-PaperServerListPingEvent.patch new file mode 100644 index 0000000000..fa4ddb2052 --- /dev/null +++ b/patches/server/0181-Implement-extended-PaperServerListPingEvent.patch @@ -0,0 +1,250 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Minecrell <[email protected]> +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..2b10ce4ce36e519b757af96cb80921dfc3f09418 +--- /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.server.motd(), server.previewsChat(), 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 67455a5ba75c9b816213e44d6872c5ddf8e27e98..23efad80934930beadf15e65781551d4ba7ff81b 100644 +--- a/src/main/java/net/minecraft/network/protocol/status/ClientboundStatusResponsePacket.java ++++ b/src/main/java/net/minecraft/network/protocol/status/ClientboundStatusResponsePacket.java +@@ -10,7 +10,9 @@ import net.minecraft.util.GsonHelper; + 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(io.papermc.paper.adventure.AdventureComponent.class, new io.papermc.paper.adventure.AdventureComponent.Serializer()) ++ .create(); + private final ServerStatus status; + + public ClientboundStatusResponsePacket(ServerStatus metadata) { +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 3bd4b16da49a730326f5b9039649eb59e3043bd0..d65423b8d7b69db79de05587efba13008602f743 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; +@@ -1303,7 +1306,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa + this.lastServerStatus = i; + this.status.setPlayers(new ServerStatus.Players(this.getMaxPlayers(), this.getPlayerCount())); + if (!this.hidesOnlinePlayers()) { +- 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 a426adfba3fccf1815177e0b8065684c9497ef45..29a22da1b94d51300481c071aa16bfd8cd02178f 100644 +--- a/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java +@@ -46,6 +46,8 @@ public class ServerStatusPacketListenerImpl implements ServerStatusPacketListene + this.connection.disconnect(ServerStatusPacketListenerImpl.DISCONNECT_REASON); + } else { + this.hasRequestedStatus = true; ++ // Paper start - Replace everything ++ /* + // CraftBukkit start + // this.connection.send(new PacketStatusOutServerInfo(this.server.getStatus())); + final Object[] players = this.server.getPlayerList().players.toArray(); +@@ -150,6 +152,9 @@ public class ServerStatusPacketListenerImpl implements ServerStatusPacketListene + + this.connection.send(new ClientboundStatusResponsePacket(ping)); + // CraftBukkit end ++ */ ++ com.destroystokyo.paper.network.StandardPaperServerListPingEventImpl.processRequest(this.server, this.connection); ++ // Paper end + } + } + +diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java +index c2e3d32e51902503af88f089e366e784f42d999a..645643d102118ad4916a152abfb9ab0d02751e11 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() + { +- SpigotConfig.playerSample = SpigotConfig.getInt( "settings.sample-count", 12 ); ++ SpigotConfig.playerSample = Math.max( SpigotConfig.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 + } + |