diff --git a/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch b/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch index ba869e11d8..41df18c7dc 100644 --- a/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch @@ -1,6 +1,16 @@ --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java -@@ -45,7 +45,6 @@ +@@ -3,6 +3,9 @@ + import com.google.common.base.Preconditions; + 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; +@@ -45,7 +48,6 @@ import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; @@ -8,7 +18,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.LockSupport; import java.util.function.BooleanSupplier; -@@ -84,17 +83,6 @@ +@@ -84,17 +86,6 @@ import net.minecraft.obfuscate.DontObfuscate; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; @@ -26,7 +36,7 @@ import net.minecraft.server.packs.PackType; import net.minecraft.server.packs.repository.Pack; import net.minecraft.server.packs.repository.PackRepository; -@@ -116,6 +104,7 @@ +@@ -116,6 +107,7 @@ import net.minecraft.util.RandomSource; import net.minecraft.util.SignatureValidator; import net.minecraft.util.TimeUtil; @@ -34,7 +44,7 @@ import net.minecraft.util.debugchart.RemoteDebugSampleType; import net.minecraft.util.debugchart.SampleLogger; import net.minecraft.util.debugchart.TpsDebugDimensions; -@@ -156,37 +145,71 @@ +@@ -156,37 +148,71 @@ import net.minecraft.world.level.biome.BiomeManager; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.FuelValues; @@ -114,7 +124,7 @@ private static final int OVERLOADED_TICKS_THRESHOLD = 20; private static final long OVERLOADED_WARNING_INTERVAL_NANOS = 10L * TimeUtil.NANOSECONDS_PER_SECOND; private static final int OVERLOADED_TICKS_WARNING_INTERVAL = 100; -@@ -224,6 +247,7 @@ +@@ -224,6 +250,7 @@ private Map, ServerLevel> levels; private PlayerList playerList; private volatile boolean running; @@ -122,7 +132,7 @@ private boolean stopped; private int tickCount; private int ticksUntilAutosave; -@@ -232,8 +256,7 @@ +@@ -232,8 +259,7 @@ private boolean preventProxyConnections; private boolean pvp; private boolean allowFlight; @@ -132,7 +142,7 @@ private int playerIdleTimeout; private final long[] tickTimesNanos; private long aggregatedTickTimesNanos; -@@ -277,6 +300,26 @@ +@@ -277,6 +303,26 @@ private final SuppressedExceptionCollector suppressedExceptions; private final DiscontinuousFrame tickFrame; @@ -159,7 +169,7 @@ public static S spin(Function serverFactory) { AtomicReference atomicreference = new AtomicReference(); Thread thread = new Thread(() -> { -@@ -290,15 +333,16 @@ +@@ -290,15 +336,16 @@ thread.setPriority(8); } @@ -178,7 +188,7 @@ this.metricsRecorder = InactiveMetricsRecorder.INSTANCE; this.onMetricsRecordingStopped = (methodprofilerresults) -> { this.stopRecordingMetrics(); -@@ -319,36 +363,68 @@ +@@ -319,36 +366,68 @@ this.scoreboard = new ServerScoreboard(this); this.customBossEvents = new CustomBossEvents(); this.suppressedExceptions = new SuppressedExceptionCollector(); @@ -262,7 +272,7 @@ } private void readScoreboard(DimensionDataStorage persistentStateManager) { -@@ -357,7 +433,7 @@ +@@ -357,7 +436,7 @@ protected abstract boolean initServer() throws IOException; @@ -271,7 +281,7 @@ if (!JvmProfiler.INSTANCE.isRunning()) { ; } -@@ -365,12 +441,8 @@ +@@ -365,12 +444,8 @@ boolean flag = false; ProfiledDuration profiledduration = JvmProfiler.INSTANCE.onWorldLoadedStarted(); @@ -285,7 +295,7 @@ if (profiledduration != null) { profiledduration.finish(true); } -@@ -387,23 +459,232 @@ +@@ -387,23 +462,232 @@ protected void forceDifficulty() {} @@ -532,7 +542,7 @@ if (!iworlddataserver.isInitialized()) { try { -@@ -427,30 +708,8 @@ +@@ -427,30 +711,8 @@ iworlddataserver.setInitialized(true); } @@ -564,7 +574,7 @@ private static void setInitialSpawn(ServerLevel world, ServerLevelData worldProperties, boolean bonusChest, boolean debugWorld) { if (debugWorld) { -@@ -458,6 +717,21 @@ +@@ -458,6 +720,21 @@ } else { ServerChunkCache chunkproviderserver = world.getChunkSource(); ChunkPos chunkcoordintpair = new ChunkPos(chunkproviderserver.randomState().sampler().findSpawnPosition()); @@ -586,7 +596,7 @@ int i = chunkproviderserver.getGenerator().getSpawnHeight(world); if (i < world.getMinY()) { -@@ -516,31 +790,36 @@ +@@ -516,31 +793,36 @@ iworlddataserver.setGameType(GameType.SPECTATOR); } @@ -634,7 +644,7 @@ ForcedChunksSavedData forcedchunk = (ForcedChunksSavedData) worldserver1.getDataStorage().get(ForcedChunksSavedData.factory(), "chunks"); if (forcedchunk != null) { -@@ -555,10 +834,17 @@ +@@ -555,10 +837,17 @@ } } @@ -656,7 +666,7 @@ } public GameType getDefaultGameType() { -@@ -588,12 +874,16 @@ +@@ -588,12 +877,16 @@ worldserver.save((ProgressListener) null, flush, worldserver.noSave && !force); } @@ -675,7 +685,7 @@ if (flush) { Iterator iterator1 = this.getAllLevels().iterator(); -@@ -628,18 +918,41 @@ +@@ -628,18 +921,41 @@ this.stopServer(); } @@ -718,7 +728,7 @@ } MinecraftServer.LOGGER.info("Saving worlds"); -@@ -693,6 +1006,15 @@ +@@ -693,6 +1009,15 @@ } catch (IOException ioexception1) { MinecraftServer.LOGGER.error("Failed to unlock level {}", this.storageSource.getLevelId(), ioexception1); } @@ -734,7 +744,7 @@ } -@@ -709,16 +1031,80 @@ +@@ -709,6 +1034,12 @@ } public void halt(boolean waitForShutdown) { @@ -747,14 +757,10 @@ this.running = false; if (waitForShutdown) { try { - this.serverThread.join(); - } catch (InterruptedException interruptedexception) { - MinecraftServer.LOGGER.error("Error while shutting down", interruptedexception); -+ } -+ } -+ -+ } -+ +@@ -720,6 +1051,64 @@ + + } + + // Spigot Start + private static double calcTps(double avg, double exp, double tps) + { @@ -787,9 +793,9 @@ + for (int i = 0; i < size; i++) { + this.samples[i] = dec(TPS); + this.times[i] = SEC_IN_NANO; - } - } - ++ } ++ } ++ + private static java.math.BigDecimal dec(long t) { + return new java.math.BigDecimal(t); + } @@ -808,14 +814,15 @@ + public double getAverage() { + return total.divide(dec(time), 30, java.math.RoundingMode.HALF_UP).doubleValue(); + } - } ++ } + private static final java.math.BigDecimal TPS_BASE = new java.math.BigDecimal(1E9).multiply(new java.math.BigDecimal(SAMPLE_INTERVAL)); + // Paper end + // Spigot End - ++ protected void runServer() { try { -@@ -727,9 +1113,15 @@ + if (!this.initServer()) { +@@ -727,9 +1116,15 @@ } this.nextTickTimeNanos = Util.getNanos(); @@ -832,7 +839,7 @@ while (this.running) { long i; -@@ -744,12 +1136,31 @@ +@@ -744,11 +1139,30 @@ if (j > MinecraftServer.OVERLOADED_THRESHOLD_NANOS + 20L * i && this.nextTickTimeNanos - this.lastOverloadWarningNanos >= MinecraftServer.OVERLOADED_WARNING_INTERVAL_NANOS + 100L * i) { long k = j / i; @@ -841,7 +848,7 @@ this.nextTickTimeNanos += k * i; this.lastOverloadWarningNanos = this.nextTickTimeNanos; } - } ++ } + // Spigot start + // Paper start - further improve server tick loop + currentTime = Util.getNanos(); @@ -851,20 +858,19 @@ + tps1.add(currentTps, diff); + tps5.add(currentTps, diff); + tps15.add(currentTps, diff); - ++ + // Backwards compat with bad plugins + this.recentTps[0] = tps1.getAverage(); + this.recentTps[1] = tps5.getAverage(); + this.recentTps[2] = tps15.getAverage(); + tickSection = currentTime; -+ } + } + // Paper end - further improve server tick loop + // Spigot end -+ + boolean flag = i == 0L; - if (this.debugCommandProfilerDelayStart) { -@@ -757,6 +1168,8 @@ +@@ -757,6 +1171,8 @@ this.debugCommandProfiler = new MinecraftServer.TimeProfiler(Util.getNanos(), this.tickCount); } @@ -873,7 +879,7 @@ this.nextTickTimeNanos += i; try { -@@ -830,6 +1243,13 @@ +@@ -830,6 +1246,13 @@ this.services.profileCache().clearExecutor(); } @@ -887,7 +893,7 @@ this.onServerExit(); } -@@ -889,9 +1309,16 @@ +@@ -889,9 +1312,16 @@ } private boolean haveTime() { @@ -905,7 +911,7 @@ public static boolean throwIfFatalException() { RuntimeException runtimeexception = (RuntimeException) MinecraftServer.fatalException.get(); -@@ -903,7 +1330,7 @@ +@@ -903,7 +1333,7 @@ } public static void setFatalException(RuntimeException exception) { @@ -914,7 +920,7 @@ } @Override -@@ -977,7 +1404,7 @@ +@@ -977,7 +1407,7 @@ } } @@ -923,7 +929,7 @@ Profiler.get().incrementCounter("runTask"); super.doRunTask(ticktask); } -@@ -1025,6 +1452,7 @@ +@@ -1025,6 +1455,7 @@ } public void tickServer(BooleanSupplier shouldKeepTicking) { @@ -931,7 +937,7 @@ long i = Util.getNanos(); int j = this.pauseWhileEmptySeconds() * 20; -@@ -1041,6 +1469,7 @@ +@@ -1041,6 +1472,7 @@ this.autoSave(); } @@ -939,7 +945,7 @@ this.tickConnection(); return; } -@@ -1055,12 +1484,13 @@ +@@ -1055,12 +1487,13 @@ } --this.ticksUntilAutosave; @@ -954,7 +960,7 @@ gameprofilerfiller.push("tallying"); long k = Util.getNanos() - i; int l = this.tickCount % 100; -@@ -1074,7 +1504,7 @@ +@@ -1074,7 +1507,7 @@ } private void autoSave() { @@ -963,7 +969,7 @@ MinecraftServer.LOGGER.debug("Autosave started"); ProfilerFiller gameprofilerfiller = Profiler.get(); -@@ -1123,7 +1553,7 @@ +@@ -1123,7 +1556,7 @@ private ServerStatus buildServerStatus() { ServerStatus.Players serverping_serverpingplayersample = this.buildPlayerStatus(); @@ -972,7 +978,16 @@ } private ServerStatus.Players buildPlayerStatus() { -@@ -1154,24 +1584,43 @@ +@@ -1133,7 +1566,7 @@ + if (this.hidesOnlinePlayers()) { + return new ServerStatus.Players(i, list.size(), List.of()); + } else { +- int j = Math.min(list.size(), 12); ++ int j = Math.min(list.size(), org.spigotmc.SpigotConfig.playerSample); // Paper - PaperServerListPingEvent + ObjectArrayList objectarraylist = new ObjectArrayList(j); + int k = Mth.nextInt(this.random, 0, list.size() - j); + +@@ -1154,24 +1587,43 @@ this.getPlayerList().getPlayers().forEach((entityplayer) -> { entityplayer.connection.suspendFlushing(); }); @@ -982,13 +997,13 @@ this.getFunctions().tick(); gameprofilerfiller.popPush("levels"); Iterator iterator = this.getAllLevels().iterator(); -+ + + // CraftBukkit start + // Run tasks that are waiting on processing + while (!this.processQueue.isEmpty()) { + this.processQueue.remove().run(); + } - ++ + // Send time updates to everyone, it will get the right time from the world the player is in. + if (this.tickCount % 20 == 0) { + for (int i = 0; i < this.getPlayerList().players.size(); ++i) { @@ -1016,7 +1031,7 @@ gameprofilerfiller.push("tick"); -@@ -1186,6 +1635,7 @@ +@@ -1186,6 +1638,7 @@ gameprofilerfiller.pop(); gameprofilerfiller.pop(); @@ -1024,18 +1039,20 @@ } gameprofilerfiller.popPush("connection"); -@@ -1267,6 +1717,22 @@ +@@ -1265,8 +1718,24 @@ + @Nullable + public ServerLevel getLevel(ResourceKey key) { return (ServerLevel) this.levels.get(key); - } - ++ } ++ + // CraftBukkit start + public void addLevel(ServerLevel level) { + Map, ServerLevel> oldLevels = this.levels; + Map, ServerLevel> newLevels = Maps.newLinkedHashMap(oldLevels); + newLevels.put(level.dimension(), level); + this.levels = Collections.unmodifiableMap(newLevels); -+ } -+ + } + + public void removeLevel(ServerLevel level) { + Map, ServerLevel> oldLevels = this.levels; + Map, ServerLevel> newLevels = Maps.newLinkedHashMap(oldLevels); @@ -1047,7 +1064,7 @@ public Set> levelKeys() { return this.levels.keySet(); } -@@ -1296,7 +1762,7 @@ +@@ -1296,7 +1765,7 @@ @DontObfuscate public String getServerModName() { @@ -1056,7 +1073,7 @@ } public SystemReport fillSystemReport(SystemReport details) { -@@ -1347,7 +1813,7 @@ +@@ -1347,7 +1816,7 @@ @Override public void sendSystemMessage(Component message) { @@ -1065,7 +1082,7 @@ } public KeyPair getKeyPair() { -@@ -1481,10 +1947,20 @@ +@@ -1481,10 +1950,20 @@ @Override public String getMotd() { @@ -1087,7 +1104,7 @@ this.motd = motd; } -@@ -1507,7 +1983,7 @@ +@@ -1507,7 +1986,7 @@ } public ServerConnectionListener getConnection() { @@ -1096,7 +1113,7 @@ } public boolean isReady() { -@@ -1634,11 +2110,11 @@ +@@ -1634,11 +2113,11 @@ public CompletableFuture reloadResources(Collection dataPacks) { CompletableFuture completablefuture = CompletableFuture.supplyAsync(() -> { @@ -1110,7 +1127,7 @@ }, this).thenCompose((immutablelist) -> { MultiPackResourceManager resourcemanager = new MultiPackResourceManager(PackType.SERVER_DATA, immutablelist); List> list = TagLoader.loadTagsForExistingRegistries(resourcemanager, this.registries.compositeAccess()); -@@ -1654,6 +2130,7 @@ +@@ -1654,6 +2133,7 @@ }).thenAcceptAsync((minecraftserver_reloadableresources) -> { this.resources.close(); this.resources = minecraftserver_reloadableresources; @@ -1118,7 +1135,7 @@ this.packRepository.setSelected(dataPacks); WorldDataConfiguration worlddataconfiguration = new WorldDataConfiguration(MinecraftServer.getSelectedPacks(this.packRepository, true), this.worldData.enabledFeatures()); -@@ -1952,7 +2429,7 @@ +@@ -1952,7 +2432,7 @@ final List list = Lists.newArrayList(); final GameRules gamerules = this.getGameRules(); @@ -1127,7 +1144,7 @@ @Override public > void visit(GameRules.Key key, GameRules.Type type) { list.add(String.format(Locale.ROOT, "%s=%s\n", key.getId(), gamerules.getRule(key))); -@@ -2058,7 +2535,7 @@ +@@ -2058,7 +2538,7 @@ try { label51: { @@ -1136,13 +1153,10 @@ try { arraylist = Lists.newArrayList(NativeModuleLister.listModules()); -@@ -2105,8 +2582,23 @@ - if (bufferedwriter != null) { - bufferedwriter.close(); - } -+ -+ } -+ +@@ -2108,6 +2588,21 @@ + + } + + // CraftBukkit start + public boolean isDebugging() { + return false; @@ -1151,16 +1165,17 @@ + public static MinecraftServer getServer() { + return SERVER; // Paper + } - ++ + @Deprecated + public static RegistryAccess getDefaultRegistryAccess() { + return CraftRegistry.getMinecraftRegistry(); - } ++ } + // CraftBukkit end - ++ private ProfilerFiller createProfiler() { if (this.willStartRecordingMetrics) { -@@ -2225,18 +2717,24 @@ + this.metricsRecorder = ActiveMetricsRecorder.createStarted(new ServerMetricsSamplersProvider(Util.timeSource, this.isDedicatedServer()), Util.timeSource, Util.ioPool(), new MetricsPersister("server"), this.onMetricsRecordingStopped, (path) -> { +@@ -2225,18 +2720,24 @@ } public void logChatMessage(Component message, ChatType.Bound params, @Nullable String prefix) { diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerStatusPacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerStatusPacketListenerImpl.java.patch index eda30ce038..7ea7e46622 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerStatusPacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerStatusPacketListenerImpl.java.patch @@ -20,11 +20,13 @@ public class ServerStatusPacketListenerImpl implements ServerStatusPacketListener { -@@ -36,7 +49,108 @@ +@@ -36,7 +49,113 @@ this.connection.disconnect(ServerStatusPacketListenerImpl.DISCONNECT_REASON); } else { this.hasRequestedStatus = true; - this.connection.send(new ClientboundStatusResponsePacket(this.status)); ++ // Paper start - Replace everything ++ /* + // CraftBukkit start + // this.connection.send(new PacketStatusOutServerInfo(this.status)); + MinecraftServer server = MinecraftServer.getServer(); @@ -127,6 +129,9 @@ + + this.connection.send(new ClientboundStatusResponsePacket(ping)); + // CraftBukkit end ++ */ ++ com.destroystokyo.paper.network.StandardPaperServerListPingEventImpl.processRequest(MinecraftServer.getServer(), this.connection); ++ // Paper end } } 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 new file mode 100644 index 0000000000..6ed2114f57 --- /dev/null +++ b/paper-server/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.motd(), 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/paper-server/src/main/java/com/destroystokyo/paper/network/PaperStatusClient.java b/paper-server/src/main/java/com/destroystokyo/paper/network/PaperStatusClient.java new file mode 100644 index 0000000000..d926ad8043 --- /dev/null +++ b/paper-server/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/paper-server/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java b/paper-server/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java new file mode 100644 index 0000000000..30a19d1086 --- /dev/null +++ b/paper-server/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java @@ -0,0 +1,105 @@ +package com.destroystokyo.paper.network; + +import com.destroystokyo.paper.profile.PlayerProfile; +import com.mojang.authlib.GameProfile; +import io.papermc.paper.adventure.AdventureComponent; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import javax.annotation.Nonnull; +import net.minecraft.network.Connection; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.status.ClientboundStatusResponsePacket; +import net.minecraft.network.protocol.status.ServerStatus; +import net.minecraft.server.MinecraftServer; +import org.bukkit.craftbukkit.util.CraftIconCache; +import org.jetbrains.annotations.NotNull; + +public final class StandardPaperServerListPingEventImpl extends PaperServerListPingEventImpl { + + 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()); + this.originalSample = ping.players().map(ServerStatus.Players::sample).orElse(null); // GH-1473 - pre-tick race condition NPE + } + + @Nonnull + @Override + public List getListedPlayers() { + List sample = super.getListedPlayers(); + + if (this.originalSample != null) { + for (GameProfile profile : this.originalSample) { + sample.add(new ListedPlayerInfo(profile.getName(), profile.getId())); + } + this.originalSample = null; + } + + return sample; + } + + @Override + public @NotNull List getPlayerSample() { + this.getListedPlayers(); // Populate the backing list for the transforming view, and null out originalSample (see getListedPlayers and processRequest) + return super.getPlayerSample(); + } + + private List getPlayerSampleHandle() { + if (this.originalSample != null) { + return this.originalSample; + } + + List entries = super.getListedPlayers(); + if (entries.isEmpty()) { + return Collections.emptyList(); + } + + final List profiles = new ArrayList<>(); + for (ListedPlayerInfo playerInfo : entries) { + profiles.add(new GameProfile(playerInfo.id(), playerInfo.name())); + } + return profiles; + } + + 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((Component) null); + return; + } + + // Setup response + + // Description + final Component description = new AdventureComponent(event.motd()); + + // Players + final Optional players; + if (!event.shouldHidePlayers()) { + players = Optional.of(new ServerStatus.Players(event.getMaxPlayers(), event.getNumPlayers(), event.getPlayerSampleHandle())); + } else { + players = Optional.empty(); + } + + // Version + final ServerStatus.Version version = new ServerStatus.Version(event.getVersion(), event.getProtocolVersion()); + + // Favicon + final Optional favicon; + if (event.getServerIcon() != null) { + favicon = Optional.of(new ServerStatus.Favicon(((CraftIconCache) event.getServerIcon()).value)); + } else { + favicon = Optional.empty(); + } + final ServerStatus ping = new ServerStatus(description, players, Optional.of(version), favicon, server.enforceSecureProfile()); + + // Send response + networkManager.send(new ClientboundStatusResponsePacket(ping)); + } + +} diff --git a/paper-server/src/main/java/org/spigotmc/SpigotConfig.java b/paper-server/src/main/java/org/spigotmc/SpigotConfig.java index d9e73e37b5..b97ff4a9b6 100644 --- a/paper-server/src/main/java/org/spigotmc/SpigotConfig.java +++ b/paper-server/src/main/java/org/spigotmc/SpigotConfig.java @@ -285,7 +285,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 }