From 43227a418f28b863d4fa33311bc25a17c3437a1c Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Sun, 13 Jun 2021 11:41:07 +0200 Subject: [PATCH] Work --- build.gradle.kts | 2 +- .../Add-GS4-Query-event.patch | 0 .../Add-PlayerPostRespawnEvent.patch | 0 .../Annotation-Test-changes.patch | 0 .../Entity-getEntitySpawnReason.patch | 6 +- .../Allow-Saving-of-Oversized-Chunks.patch | 271 ------------------ .../Fire-event-on-GS4-query.patch | 265 ----------------- ...ity-Metadata-for-all-tracked-players.patch | 43 --- ...oggleEvent-when-whitelist-is-toggled.patch | 0 .../Entity-getEntitySpawnReason.patch | 42 +-- patches/server/Fire-event-on-GS4-query.patch | 209 ++++++++++++++ ...le-Oversized-Tile-Entities-in-chunks.patch | 46 ++- .../Implement-PlayerPostRespawnEvent.patch | 2 +- ...0-Fix-Whitelist-On-Off-inconsistency.patch | 15 +- ...-Manager-and-add-advanced-packet-sup.patch | 213 ++++---------- ...st-tick-at-start-of-drowning-process.patch | 0 ...ity-Metadata-for-all-tracked-players.patch | 76 +++++ ...ength-when-serialising-BungeeCord-te.patch | 8 +- settings.gradle.kts | 1 + 19 files changed, 399 insertions(+), 800 deletions(-) rename patches/{api-unmapped => api}/Add-GS4-Query-event.patch (100%) rename patches/{api-unmapped => api}/Add-PlayerPostRespawnEvent.patch (100%) rename patches/{api-unmapped => api}/Annotation-Test-changes.patch (100%) rename patches/{api-unmapped => api}/Entity-getEntitySpawnReason.patch (92%) delete mode 100644 patches/server-remapped/Allow-Saving-of-Oversized-Chunks.patch delete mode 100644 patches/server-remapped/Fire-event-on-GS4-query.patch delete mode 100644 patches/server-remapped/Update-entity-Metadata-for-all-tracked-players.patch rename patches/{server-remapped => server}/Call-WhitelistToggleEvent-when-whitelist-is-toggled.patch (100%) rename patches/{server-remapped => server}/Entity-getEntitySpawnReason.patch (81%) create mode 100644 patches/server/Fire-event-on-GS4-query.patch rename patches/{server-remapped => server}/Handle-Oversized-Tile-Entities-in-chunks.patch (53%) rename patches/{server-remapped => server}/Implement-PlayerPostRespawnEvent.patch (95%) rename patches/{server-remapped => server}/MC-145260-Fix-Whitelist-On-Off-inconsistency.patch (70%) rename patches/{server-remapped => server}/Optimize-Network-Manager-and-add-advanced-packet-sup.patch (55%) rename patches/{server-remapped => server}/Set-Zombie-last-tick-at-start-of-drowning-process.patch (100%) create mode 100644 patches/server/Update-entity-Metadata-for-all-tracked-players.patch rename patches/{server-remapped => server}/Use-proper-max-length-when-serialising-BungeeCord-te.patch (81%) diff --git a/build.gradle.kts b/build.gradle.kts index 407f27e9d2..101bc900a8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,7 +1,7 @@ plugins { java id("com.github.johnrengelman.shadow") version "7.0.0" apply false - id("io.papermc.paperweight.core") version "1.0.0-SNAPSHOT" + id("io.papermc.paperweight.core") version "1.0.0-LOCAL-SNAPSHOT" } val mcVersion = providers.gradleProperty("mcVersion") diff --git a/patches/api-unmapped/Add-GS4-Query-event.patch b/patches/api/Add-GS4-Query-event.patch similarity index 100% rename from patches/api-unmapped/Add-GS4-Query-event.patch rename to patches/api/Add-GS4-Query-event.patch diff --git a/patches/api-unmapped/Add-PlayerPostRespawnEvent.patch b/patches/api/Add-PlayerPostRespawnEvent.patch similarity index 100% rename from patches/api-unmapped/Add-PlayerPostRespawnEvent.patch rename to patches/api/Add-PlayerPostRespawnEvent.patch diff --git a/patches/api-unmapped/Annotation-Test-changes.patch b/patches/api/Annotation-Test-changes.patch similarity index 100% rename from patches/api-unmapped/Annotation-Test-changes.patch rename to patches/api/Annotation-Test-changes.patch diff --git a/patches/api-unmapped/Entity-getEntitySpawnReason.patch b/patches/api/Entity-getEntitySpawnReason.patch similarity index 92% rename from patches/api-unmapped/Entity-getEntitySpawnReason.patch rename to patches/api/Entity-getEntitySpawnReason.patch index 0008e705be..01af933d1f 100644 --- a/patches/api-unmapped/Entity-getEntitySpawnReason.patch +++ b/patches/api/Entity-getEntitySpawnReason.patch @@ -14,9 +14,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/org/bukkit/entity/Entity.java +++ b/src/main/java/org/bukkit/entity/Entity.java @@ -0,0 +0,0 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent - */ - @NotNull - Chunk getChunk(); + // TODO remove impl here + return getLocation().getChunk(); + } + + /** + * @return The {@link org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason} that spawned this entity. diff --git a/patches/server-remapped/Allow-Saving-of-Oversized-Chunks.patch b/patches/server-remapped/Allow-Saving-of-Oversized-Chunks.patch deleted file mode 100644 index 0b91912ed6..0000000000 --- a/patches/server-remapped/Allow-Saving-of-Oversized-Chunks.patch +++ /dev/null @@ -1,271 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Fri, 15 Feb 2019 01:08:19 -0500 -Subject: [PATCH] Allow Saving of Oversized Chunks - -The Minecraft World Region File format has a hard cap of 1MB per chunk. -This is due to the fact that the header of the file format only allocates -a single byte for sector count, meaning a maximum of 256 sectors, at 4k per sector. - -This limit can be reached fairly easily with books, resulting in the chunk being unable -to save to the world. Worse off, is that nothing printed when this occured, and silently -performed a chunk rollback on next load. - -This leads to security risk with duplication and is being actively exploited. - -This patch catches the too large scenario, falls back and moves any large Entity -or Tile Entity into a new compound, and this compound is saved into a different file. - -On Chunk Load, we check for oversized status, and if so, we load the extra file and -merge the Entities and Tile Entities from the oversized chunk back into the level to -then be loaded as normal. - -Once a chunk is returned back to normal size, the oversized flag will clear, and no -extra data file will exist. - -This fix maintains compatability with all existing Anvil Region Format tools as it -does not alter the save format. They will just not know about the extra entities. - -This fix also maintains compatability if someone switches server jars to one without -this fix, as the data will remain in the oversized file. Once the server returns -to a jar with this fix, the data will be restored. - -diff --git a/src/main/java/net/minecraft/nbt/NbtIo.java b/src/main/java/net/minecraft/nbt/NbtIo.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/nbt/NbtIo.java -+++ b/src/main/java/net/minecraft/nbt/NbtIo.java -@@ -0,0 +0,0 @@ public class NbtIo { - - } - -+ public static CompoundTag readNBT(DataInput datainput) throws IOException { return read(datainput); } // Paper - OBFHELPER - public static CompoundTag read(DataInput input) throws IOException { - return read(input, NbtAccounter.UNLIMITED); - } -@@ -0,0 +0,0 @@ public class NbtIo { - } - } - -+ public static void writeNBT(CompoundTag nbttagcompound, DataOutput dataoutput) throws IOException { write(nbttagcompound, dataoutput); } // Paper - OBFHELPER - public static void write(CompoundTag tag, DataOutput output) throws IOException { - writeUnnamedTag((Tag) tag, output); - } -diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java -+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java -@@ -0,0 +0,0 @@ import java.nio.file.LinkOption; - import java.nio.file.Path; - import java.nio.file.StandardCopyOption; - import java.nio.file.StandardOpenOption; -+import java.util.zip.InflaterInputStream; // Paper -+ - import javax.annotation.Nullable; - import net.minecraft.Util; -+import net.minecraft.nbt.CompoundTag; -+import net.minecraft.nbt.NbtIo; - import net.minecraft.world.level.ChunkPos; - import org.apache.logging.log4j.LogManager; - import org.apache.logging.log4j.Logger; -@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { - private final IntBuffer timestamps; - @VisibleForTesting - protected final RegionBitmap usedSectors; -+ public final File file; // Paper - - public RegionFile(File file, File directory, boolean dsync) throws IOException { - this(file.toPath(), directory.toPath(), RegionFileVersion.VERSION_DEFLATE, dsync); -@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { - - public RegionFile(Path file, Path directory, RegionFileVersion outputChunkStreamVersion, boolean dsync) throws IOException { - this.header = ByteBuffer.allocateDirect(8192); -+ this.file = file.toFile(); // Paper -+ initOversizedState(); // Paper - this.usedSectors = new RegionBitmap(); - this.version = outputChunkStreamVersion; - if (!Files.isDirectory(directory, new LinkOption[0])) { -@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { - void run() throws IOException; - } - -+ // Paper start -+ private final byte[] oversized = new byte[1024]; -+ private int oversizedCount = 0; -+ -+ private synchronized void initOversizedState() throws IOException { -+ File metaFile = getOversizedMetaFile(); -+ if (metaFile.exists()) { -+ final byte[] read = java.nio.file.Files.readAllBytes(metaFile.toPath()); -+ System.arraycopy(read, 0, oversized, 0, oversized.length); -+ for (byte temp : oversized) { -+ oversizedCount += temp; -+ } -+ } -+ } -+ -+ private static int getChunkIndex(int x, int z) { -+ return (x & 31) + (z & 31) * 32; -+ } -+ synchronized boolean isOversized(int x, int z) { -+ return this.oversized[getChunkIndex(x, z)] == 1; -+ } -+ synchronized void setOversized(int x, int z, boolean oversized) throws IOException { -+ final int offset = getChunkIndex(x, z); -+ boolean previous = this.oversized[offset] == 1; -+ this.oversized[offset] = (byte) (oversized ? 1 : 0); -+ if (!previous && oversized) { -+ oversizedCount++; -+ } else if (!oversized && previous) { -+ oversizedCount--; -+ } -+ if (previous && !oversized) { -+ File oversizedFile = getOversizedFile(x, z); -+ if (oversizedFile.exists()) { -+ oversizedFile.delete(); -+ } -+ } -+ if (oversizedCount > 0) { -+ if (previous != oversized) { -+ writeOversizedMeta(); -+ } -+ } else if (previous) { -+ File oversizedMetaFile = getOversizedMetaFile(); -+ if (oversizedMetaFile.exists()) { -+ oversizedMetaFile.delete(); -+ } -+ } -+ } -+ -+ private void writeOversizedMeta() throws IOException { -+ java.nio.file.Files.write(getOversizedMetaFile().toPath(), oversized); -+ } -+ -+ private File getOversizedMetaFile() { -+ return new File(this.file.getParentFile(), this.file.getName().replaceAll("\\.mca$", "") + ".oversized.nbt"); -+ } -+ -+ private File getOversizedFile(int x, int z) { -+ return new File(this.file.getParentFile(), this.file.getName().replaceAll("\\.mca$", "") + "_oversized_" + x + "_" + z + ".nbt"); -+ } -+ -+ synchronized CompoundTag getOversizedData(int x, int z) throws IOException { -+ File file = getOversizedFile(x, z); -+ try (DataInputStream out = new DataInputStream(new BufferedInputStream(new InflaterInputStream(new java.io.FileInputStream(file))))) { -+ return NbtIo.readNBT((java.io.DataInput) out); -+ } -+ -+ } -+ // Paper end - class ChunkBuffer extends ByteArrayOutputStream { - - private final ChunkPos pos; -diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -@@ -0,0 +0,0 @@ import java.io.File; - import java.io.IOException; - import javax.annotation.Nullable; - import net.minecraft.nbt.CompoundTag; -+import net.minecraft.nbt.ListTag; - import net.minecraft.nbt.NbtIo; -+import net.minecraft.nbt.Tag; - import net.minecraft.server.MinecraftServer; - import net.minecraft.util.ExceptionCollector; - import net.minecraft.world.level.ChunkPos; -@@ -0,0 +0,0 @@ public final class RegionFileStorage implements AutoCloseable { - } - } - -+ // Paper start -+ private static void printOversizedLog(String msg, File file, int x, int z) { -+ org.apache.logging.log4j.LogManager.getLogger().fatal(msg + " (" + file.toString().replaceAll(".+[\\\\/]", "") + " - " + x + "," + z + ") Go clean it up to remove this message. /minecraft:tp " + (x<<4)+" 128 "+(z<<4) + " - DO NOT REPORT THIS TO PAPER - You may ask for help on Discord, but do not file an issue. These error messages can not be removed."); -+ } -+ -+ private static final int DEFAULT_SIZE_THRESHOLD = 1024 * 8; -+ private static final int OVERZEALOUS_TOTAL_THRESHOLD = 1024 * 64; -+ private static final int OVERZEALOUS_THRESHOLD = 1024; -+ private static int SIZE_THRESHOLD = DEFAULT_SIZE_THRESHOLD; -+ private static void resetFilterThresholds() { -+ SIZE_THRESHOLD = Math.max(1024 * 4, Integer.getInteger("Paper.FilterThreshhold", DEFAULT_SIZE_THRESHOLD)); -+ } -+ static { -+ resetFilterThresholds(); -+ } -+ -+ static boolean isOverzealous() { -+ return SIZE_THRESHOLD == OVERZEALOUS_THRESHOLD; -+ } -+ -+ -+ private static CompoundTag readOversizedChunk(RegionFile regionfile, ChunkPos chunkCoordinate) throws IOException { -+ synchronized (regionfile) { -+ try (DataInputStream datainputstream = regionfile.getReadStream(chunkCoordinate)) { -+ CompoundTag oversizedData = regionfile.getOversizedData(chunkCoordinate.x, chunkCoordinate.z); -+ CompoundTag chunk = NbtIo.readNBT((DataInput) datainputstream); -+ if (oversizedData == null) { -+ return chunk; -+ } -+ CompoundTag oversizedLevel = oversizedData.getCompound("Level"); -+ CompoundTag level = chunk.getCompound("Level"); -+ -+ mergeChunkList(level, oversizedLevel, "Entities"); -+ mergeChunkList(level, oversizedLevel, "TileEntities"); -+ -+ chunk.put("Level", level); -+ -+ return chunk; -+ } catch (Throwable throwable) { -+ throwable.printStackTrace(); -+ throw throwable; -+ } -+ } -+ } -+ -+ private static void mergeChunkList(CompoundTag level, CompoundTag oversizedLevel, String key) { -+ ListTag levelList = level.getList(key, 10); -+ ListTag oversizedList = oversizedLevel.getList(key, 10); -+ -+ if (!oversizedList.isEmpty()) { -+ levelList.addAll(oversizedList); -+ level.put(key, levelList); -+ } -+ } -+ -+ private static int getNBTSize(Tag nbtBase) { -+ DataOutputStream test = new DataOutputStream(new org.apache.commons.io.output.NullOutputStream()); -+ try { -+ nbtBase.write(test); -+ return test.size(); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ return 0; -+ } -+ } -+ -+ // Paper End -+ - @Nullable - public CompoundTag read(ChunkPos pos) throws IOException { - // CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing -@@ -0,0 +0,0 @@ public final class RegionFileStorage implements AutoCloseable { - } - // CraftBukkit end - DataInputStream datainputstream = regionfile.getChunkDataInputStream(pos); -+ // Paper start -+ if (regionfile.isOversized(pos.x, pos.z)) { -+ printOversizedLog("Loading Oversized Chunk!", regionfile.file, pos.x, pos.z); -+ return readOversizedChunk(regionfile, pos); -+ } -+ // Paper end - Throwable throwable = null; - - CompoundTag nbttagcompound; -@@ -0,0 +0,0 @@ public final class RegionFileStorage implements AutoCloseable { - - try { - NbtIo.write(tag, (DataOutput) dataoutputstream); -+ regionfile.setOversized(pos.x, pos.z, false); // Paper - We don't do this anymore, mojang stores differently, but clear old meta flag if it exists to get rid of our own meta file once last oversized is gone - } catch (Throwable throwable1) { - throwable = throwable1; - throw throwable1; diff --git a/patches/server-remapped/Fire-event-on-GS4-query.patch b/patches/server-remapped/Fire-event-on-GS4-query.patch deleted file mode 100644 index 5ad8d81824..0000000000 --- a/patches/server-remapped/Fire-event-on-GS4-query.patch +++ /dev/null @@ -1,265 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mark Vainomaa -Date: Sun, 17 Mar 2019 21:46:56 +0200 -Subject: [PATCH] Fire event on GS4 query - - -diff --git a/src/main/java/net/minecraft/server/rcon/NetworkDataOutputStream.java b/src/main/java/net/minecraft/server/rcon/NetworkDataOutputStream.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/rcon/NetworkDataOutputStream.java -+++ b/src/main/java/net/minecraft/server/rcon/NetworkDataOutputStream.java -@@ -0,0 +0,0 @@ public class NetworkDataOutputStream { - this.dataOutputStream.write(abyte, 0, abyte.length); - } - -+ public void writeString(String string) throws IOException { this.writeString(string); } // Paper - OBFHELPER - public void writeString(String s) throws IOException { - this.dataOutputStream.writeBytes(s); - this.dataOutputStream.write(0); - } -+ // Paper start - unchecked exception variant to use in Stream API -+ public void writeStringUnchecked(String string) { -+ try { -+ writeString(string); -+ } catch (IOException e) { -+ com.destroystokyo.paper.util.SneakyThrow.sneaky(e); -+ } -+ } -+ // Paper end - -+ public void writeInt(int i) throws IOException { this.write(i); } // Paper - OBFHELPER - public void write(int i) throws IOException { - this.dataOutputStream.write(i); - } - -+ public void writeShort(short i) throws IOException { this.writeShort(i); } // Paper - OBFHELPER - public void writeShort(short short0) throws IOException { - this.dataOutputStream.writeShort(Short.reverseBytes(short0)); - } -diff --git a/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java b/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java -+++ b/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java -@@ -0,0 +0,0 @@ import java.util.Random; - import javax.annotation.Nullable; - import net.minecraft.Util; - import net.minecraft.server.ServerInterface; -+import net.minecraft.server.dedicated.DedicatedServer; - import net.minecraft.server.rcon.NetworkDataOutputStream; - import net.minecraft.server.rcon.PktUtils; - import org.apache.logging.log4j.LogManager; -@@ -0,0 +0,0 @@ public class QueryThreadGs4 extends GenericThread { - private static final Logger LOGGER = LogManager.getLogger(); - private long lastChallengeCheck; - private final int port; -- private final int serverPort; -- private final int maxPlayers; -- private final String serverName; -- private final String worldName; -+ private final int serverPort; private final int getServerPort() { return this.serverPort; } // Paper - OBFHELPER -+ private final int maxPlayers; private final int getMaxPlayers() { return this.maxPlayers; } // Paper - OBFHELPER -+ private final String serverName; private final String getMotd() { return this.serverName; } // Paper - OBFHELPER -+ private final String worldName; private final String getWorldName() { return this.worldName; } // Paper - OBFHELPER - private DatagramSocket socket; - private final byte[] buffer = new byte[1460]; -- private String hostIp; -+ private String hostIp; public final String getServerHost() { return this.hostIp; } // Paper - OBFHELPER - private String serverIp; - private final Map validChallenges; -- private final NetworkDataOutputStream rulesResponse; -+ private final NetworkDataOutputStream rulesResponse; private final NetworkDataOutputStream getCachedFullResponse() { return this.rulesResponse; } // Paper - OBFHELPER - private long lastRulesResponse; -- private final ServerInterface serverInterface; -+ private final ServerInterface serverInterface; private final ServerInterface getServer() { return this.serverInterface; } // Paper - OBFHELPER - - private QueryThreadGs4(ServerInterface server, int queryPort) { - super("Query Listener"); -@@ -0,0 +0,0 @@ public class QueryThreadGs4 extends GenericThread { - - remotestatusreply.write((int) 0); - remotestatusreply.writeBytes(this.getIdentBytes(packet.getSocketAddress())); -- remotestatusreply.writeString(this.serverName); -+ /* Paper start - GS4 Query event -+ remotestatusreply.a(this.i); -+ remotestatusreply.a("SMP"); -+ remotestatusreply.a(this.j); -+ remotestatusreply.a(Integer.toString(this.r.getPlayerCount())); -+ remotestatusreply.a(Integer.toString(this.h)); -+ remotestatusreply.a((short) this.g); -+ remotestatusreply.a(this.m); -+ */ -+ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType queryType = -+ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType.BASIC; -+ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse queryResponse = com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.builder() -+ .motd(this.getMotd()) -+ .map(this.getWorldName()) -+ .currentPlayers(this.getServer().getPlayerCount()) -+ .maxPlayers(this.getMaxPlayers()) -+ .port(this.getServerPort()) -+ .hostname(this.getServerHost()) -+ .gameVersion(this.getServer().getServerVersion()) -+ .serverVersion(org.bukkit.Bukkit.getServer().getName() + " on " + org.bukkit.Bukkit.getServer().getBukkitVersion()) -+ .build(); -+ com.destroystokyo.paper.event.server.GS4QueryEvent queryEvent = -+ new com.destroystokyo.paper.event.server.GS4QueryEvent(queryType, packet.getAddress(), queryResponse); -+ queryEvent.callEvent(); -+ queryResponse = queryEvent.getResponse(); -+ remotestatusreply.writeString(queryResponse.getMotd()); - remotestatusreply.writeString("SMP"); -- remotestatusreply.writeString(this.worldName); -- remotestatusreply.writeString(Integer.toString(this.serverInterface.getPlayerCount())); -- remotestatusreply.writeString(Integer.toString(this.maxPlayers)); -- remotestatusreply.writeShort((short) this.serverPort); -- remotestatusreply.writeString(this.hostIp); -+ remotestatusreply.writeString(queryResponse.getMap()); -+ remotestatusreply.writeString(Integer.toString(queryResponse.getCurrentPlayers())); -+ remotestatusreply.writeString(Integer.toString(queryResponse.getMaxPlayers())); -+ remotestatusreply.writeShort((short) queryResponse.getPort()); -+ remotestatusreply.writeString(queryResponse.getHostname()); -+ // Paper end - this.sendTo(remotestatusreply.toByteArray(), packet); - QueryThreadGs4.LOGGER.debug("Status [{}]", socketaddress); - } -@@ -0,0 +0,0 @@ public class QueryThreadGs4 extends GenericThread { - this.rulesResponse.writeString("splitnum"); - this.rulesResponse.write((int) 128); - this.rulesResponse.write((int) 0); -- this.rulesResponse.writeString("hostname"); -- this.rulesResponse.writeString(this.serverName); -- this.rulesResponse.writeString("gametype"); -- this.rulesResponse.writeString("SMP"); -- this.rulesResponse.writeString("game_id"); -- this.rulesResponse.writeString("MINECRAFT"); -- this.rulesResponse.writeString("version"); -- this.rulesResponse.writeString(this.serverInterface.getServerVersion()); -- this.rulesResponse.writeString("plugins"); -- this.rulesResponse.writeString(this.serverInterface.getPluginNames()); -- this.rulesResponse.writeString("map"); -- this.rulesResponse.writeString(this.worldName); -- this.rulesResponse.writeString("numplayers"); -- this.rulesResponse.writeString("" + this.serverInterface.getPlayerCount()); -- this.rulesResponse.writeString("maxplayers"); -- this.rulesResponse.writeString("" + this.maxPlayers); -- this.rulesResponse.writeString("hostport"); -- this.rulesResponse.writeString("" + this.serverPort); -- this.rulesResponse.writeString("hostip"); -- this.rulesResponse.writeString(this.hostIp); -- this.rulesResponse.write((int) 0); -- this.rulesResponse.write((int) 1); -- this.rulesResponse.writeString("player_"); -- this.rulesResponse.write((int) 0); -- String[] astring = this.serverInterface.getPlayerNames(); -+ /* Paper start - GS4 Query event -+ this.p.a("hostname"); -+ this.p.a(this.i); -+ this.p.a("gametype"); -+ this.p.a("SMP"); -+ this.p.a("game_id"); -+ this.p.a("MINECRAFT"); -+ this.p.a("version"); -+ this.p.a(this.r.getVersion()); -+ this.p.a("plugins"); -+ this.p.a(this.r.getPlugins()); -+ this.p.a("map"); -+ this.p.a(this.j); -+ this.p.a("numplayers"); -+ this.p.a("" + this.r.getPlayerCount()); -+ this.p.a("maxplayers"); -+ this.p.a("" + this.h); -+ this.p.a("hostport"); -+ this.p.a("" + this.g); -+ this.p.a("hostip"); -+ this.p.a(this.m); -+ this.p.a((int) 0); -+ this.p.a((int) 1); -+ this.p.a("player_"); -+ this.p.a((int) 0); -+ String[] astring = this.r.getPlayers(); - String[] astring1 = astring; - int j = astring.length; - - for (int k = 0; k < j; ++k) { - String s = astring1[k]; - -- this.rulesResponse.writeString(s); -+ this.p.a(s); - } - -- this.rulesResponse.write((int) 0); -+ this.p.a((int) 0); -+ */ -+ // Pack plugins -+ java.util.List plugins = java.util.Collections.emptyList(); -+ org.bukkit.plugin.Plugin[] bukkitPlugins; -+ if (((DedicatedServer) this.getServer()).server.getQueryPlugins() && (bukkitPlugins = org.bukkit.Bukkit.getPluginManager().getPlugins()).length > 0) { -+ plugins = java.util.stream.Stream.of(bukkitPlugins) -+ .map(plugin -> com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation.of(plugin.getName(), plugin.getDescription().getVersion())) -+ .collect(java.util.stream.Collectors.toList()); -+ } -+ -+ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse queryResponse = com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.builder() -+ .motd(this.getMotd()) -+ .map(this.getWorldName()) -+ .currentPlayers(this.getServer().getPlayerCount()) -+ .maxPlayers(this.getMaxPlayers()) -+ .port(this.getServerPort()) -+ .hostname(this.getServerHost()) -+ .plugins(plugins) -+ .players(this.getServer().getPlayerNames()) -+ .gameVersion(this.getServer().getServerVersion()) -+ .serverVersion(org.bukkit.Bukkit.getServer().getName() + " on " + org.bukkit.Bukkit.getServer().getBukkitVersion()) -+ .build(); -+ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType queryType = -+ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType.FULL; -+ com.destroystokyo.paper.event.server.GS4QueryEvent queryEvent = -+ new com.destroystokyo.paper.event.server.GS4QueryEvent(queryType, packet.getAddress(), queryResponse); -+ queryEvent.callEvent(); -+ queryResponse = queryEvent.getResponse(); -+ this.getCachedFullResponse().writeString("hostname"); -+ this.getCachedFullResponse().writeString(queryResponse.getMotd()); -+ this.getCachedFullResponse().writeString("gametype"); -+ this.getCachedFullResponse().writeString("SMP"); -+ this.getCachedFullResponse().writeString("game_id"); -+ this.getCachedFullResponse().writeString("MINECRAFT"); -+ this.getCachedFullResponse().writeString("version"); -+ this.getCachedFullResponse().writeString(queryResponse.getGameVersion()); -+ this.getCachedFullResponse().writeString("plugins"); -+ java.lang.StringBuilder pluginsString = new java.lang.StringBuilder(); -+ pluginsString.append(queryResponse.getServerVersion()); -+ if (!queryResponse.getPlugins().isEmpty()) { -+ pluginsString.append(": "); -+ java.util.Iterator iter = queryResponse.getPlugins().iterator(); -+ while (iter.hasNext()) { -+ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation info = iter.next(); -+ pluginsString.append(info.getName()); -+ if (info.getVersion() != null) { -+ pluginsString.append(' ').append(info.getVersion().replace(";", ",")); -+ } -+ if (iter.hasNext()) { -+ pluginsString.append(';').append(' '); -+ } -+ } -+ } -+ this.getCachedFullResponse().writeString(pluginsString.toString()); -+ this.getCachedFullResponse().writeString("map"); -+ this.getCachedFullResponse().writeString(queryResponse.getMap()); -+ this.getCachedFullResponse().writeString("numplayers"); -+ this.getCachedFullResponse().writeString(Integer.toString(queryResponse.getCurrentPlayers())); -+ this.getCachedFullResponse().writeString("maxplayers"); -+ this.getCachedFullResponse().writeString(Integer.toString(queryResponse.getMaxPlayers())); -+ this.getCachedFullResponse().writeString("hostport"); -+ this.getCachedFullResponse().writeString(Integer.toString(queryResponse.getPort())); -+ this.getCachedFullResponse().writeString("hostip"); -+ this.getCachedFullResponse().writeString(queryResponse.getHostname()); -+ // The "meaningless data" start, copied from above -+ this.getCachedFullResponse().writeInt(0); -+ this.getCachedFullResponse().writeInt(1); -+ this.getCachedFullResponse().writeString("player_"); -+ this.getCachedFullResponse().writeInt(0); -+ // "Meaningless data" end -+ queryResponse.getPlayers().forEach(this.getCachedFullResponse()::writeStringUnchecked); -+ this.getCachedFullResponse().writeInt(0); -+ // Paper end - return this.rulesResponse.toByteArray(); - } - } diff --git a/patches/server-remapped/Update-entity-Metadata-for-all-tracked-players.patch b/patches/server-remapped/Update-entity-Metadata-for-all-tracked-players.patch deleted file mode 100644 index 877a6dbf2a..0000000000 --- a/patches/server-remapped/Update-entity-Metadata-for-all-tracked-players.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: AgentTroll -Date: Fri, 22 Mar 2019 22:24:03 -0700 -Subject: [PATCH] Update entity Metadata for all tracked players - - -diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/level/ServerEntity.java -+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java -@@ -0,0 +0,0 @@ public class ServerEntity { - return ClientboundMoveEntityPacket.packetToEntity(this.xp, this.yp, this.zp); - } - -+ // Paper start - Add broadcast method -+ void broadcast(Packet packet) { -+ this.getPacketConsumer().accept(packet); -+ } -+ // Paper end -+ - private void broadcastAndSend(Packet packet) { - this.broadcast.accept(packet); - if (this.entity instanceof ServerPlayer) { -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerGamePacketListener { - - if (event.isCancelled() || this.player.inventory.getSelected() == null || this.player.inventory.getSelected().getItem() != origItem) { - // Refresh the current entity metadata -- this.send(new ClientboundSetEntityDataPacket(entity.getId(), entity.getEntityData(), true)); -+ // Paper start - update entity for all players -+ ClientboundSetEntityDataPacket packet1 = new ClientboundSetEntityDataPacket(entity.getId(), entity.getEntityData(), true); -+ if (entity.tracker != null) { -+ entity.tracker.broadcast(packet1); -+ } else { -+ this.send(packet1); -+ } -+ // Paper end - } - - if (event.isCancelled()) { diff --git a/patches/server-remapped/Call-WhitelistToggleEvent-when-whitelist-is-toggled.patch b/patches/server/Call-WhitelistToggleEvent-when-whitelist-is-toggled.patch similarity index 100% rename from patches/server-remapped/Call-WhitelistToggleEvent-when-whitelist-is-toggled.patch rename to patches/server/Call-WhitelistToggleEvent-when-whitelist-is-toggled.patch diff --git a/patches/server-remapped/Entity-getEntitySpawnReason.patch b/patches/server/Entity-getEntitySpawnReason.patch similarity index 81% rename from patches/server-remapped/Entity-getEntitySpawnReason.patch rename to patches/server/Entity-getEntitySpawnReason.patch index f322579511..604afd6332 100644 --- a/patches/server-remapped/Entity-getEntitySpawnReason.patch +++ b/patches/server/Entity-getEntitySpawnReason.patch @@ -18,9 +18,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private boolean addEntity0(Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { org.spigotmc.AsyncCatcher.catchOp("entity add"); // Spigot + if (entity.spawnReason == null) entity.spawnReason = spawnReason; // Paper - // Paper start - if (entity.valid) { - MinecraftServer.LOGGER.error("Attempted Double World add on " + entity, new Throwable()); + if (entity.isRemoved()) { + // WorldServer.LOGGER.warn("Tried to add entity {} but it was marked as removed already", EntityTypes.getName(entity.getEntityType())); // CraftBukkit + return false; diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java @@ -47,30 +47,30 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.vehicle.Boat; -@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s +@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n + } } }; - public List entitySlice = null; + public org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason; // Paper end public com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData; // Paper -@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s - tag.setUUID("Paper.OriginWorld", origin.getWorld().getUID()); - tag.put("Paper.Origin", this.createList(origin.getX(), origin.getY(), origin.getZ())); +@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n + nbt.setUUID("Paper.OriginWorld", origin.getWorld().getUID()); + nbt.put("Paper.Origin", this.newDoubleList(origin.getX(), origin.getY(), origin.getZ())); } + if (spawnReason != null) { -+ tag.putString("Paper.SpawnReason", spawnReason.name()); ++ nbt.putString("Paper.SpawnReason", spawnReason.name()); + } // Save entity's from mob spawner status if (spawnedViaMobSpawner) { - tag.putBoolean("Paper.FromMobSpawner", true); -@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s + nbt.putBoolean("Paper.FromMobSpawner", true); +@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n } - spawnedViaMobSpawner = tag.getBoolean("Paper.FromMobSpawner"); // Restore entity's from mob spawner status -+ if (tag.contains("Paper.SpawnReason")) { -+ String spawnReasonName = tag.getString("Paper.SpawnReason"); + spawnedViaMobSpawner = nbt.getBoolean("Paper.FromMobSpawner"); // Restore entity's from mob spawner status ++ if (nbt.contains("Paper.SpawnReason")) { ++ String spawnReasonName = nbt.getString("Paper.SpawnReason"); + try { + spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.valueOf(spawnReasonName); + } catch (Exception ignored) { @@ -81,7 +81,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (spawnedViaMobSpawner) { + spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER; + } else if (this instanceof Mob && (this instanceof Animal || this instanceof AbstractFish) && !((Mob) this).removeWhenFarAway(0.0)) { -+ if (!tag.getBoolean("PersistenceRequired")) { ++ if (!nbt.getBoolean("PersistenceRequired")) { + spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL; + } + } @@ -97,13 +97,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/world/level/BaseSpawner.java +++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java @@ -0,0 +0,0 @@ public abstract class BaseSpawner { - // Spigot End - } + // Spigot End + } entity.spawnedViaMobSpawner = true; // Paper -+ entity.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER; // Paper - flag = true; // Paper - // Spigot Start - if (org.bukkit.craftbukkit.event.CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { ++ entity.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER; // Paper + flag = true; // Paper + // Spigot Start + if (org.bukkit.craftbukkit.event.CraftEventFactory.callSpawnerSpawnEvent(entity, pos).isCancelled()) { diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java diff --git a/patches/server/Fire-event-on-GS4-query.patch b/patches/server/Fire-event-on-GS4-query.patch new file mode 100644 index 0000000000..d98be1e2f4 --- /dev/null +++ b/patches/server/Fire-event-on-GS4-query.patch @@ -0,0 +1,209 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mark Vainomaa +Date: Sun, 17 Mar 2019 21:46:56 +0200 +Subject: [PATCH] Fire event on GS4 query + + +diff --git a/src/main/java/net/minecraft/server/rcon/NetworkDataOutputStream.java b/src/main/java/net/minecraft/server/rcon/NetworkDataOutputStream.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/rcon/NetworkDataOutputStream.java ++++ b/src/main/java/net/minecraft/server/rcon/NetworkDataOutputStream.java +@@ -0,0 +0,0 @@ public class NetworkDataOutputStream { + this.dataOutputStream.write(0); + } + ++ // Paper start - unchecked exception variant to use in Stream API ++ public void writeStringUnchecked(String string) { ++ try { ++ writeString(string); ++ } catch (IOException e) { ++ com.destroystokyo.paper.util.SneakyThrow.sneaky(e); ++ } ++ } ++ // Paper end ++ + public void write(int value) throws IOException { + this.dataOutputStream.write(value); + } +diff --git a/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java b/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java ++++ b/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java +@@ -0,0 +0,0 @@ public class QueryThreadGs4 extends GenericThread { + if (3 <= i && -2 == bs[0] && -3 == bs[1]) { + LOGGER.debug("Packet '{}' [{}]", PktUtils.toHexString(bs[2]), socketAddress); + switch(bs[2]) { +- case 0: +- if (!this.validChallenge(packet)) { +- LOGGER.debug("Invalid challenge [{}]", (Object)socketAddress); +- return false; +- } else if (15 == i) { +- this.sendTo(this.buildRuleResponse(packet), packet); +- LOGGER.debug("Rules [{}]", (Object)socketAddress); +- } else { +- NetworkDataOutputStream networkDataOutputStream = new NetworkDataOutputStream(1460); +- networkDataOutputStream.write(0); +- networkDataOutputStream.writeBytes(this.getIdentBytes(packet.getSocketAddress())); +- networkDataOutputStream.writeString(this.serverName); +- networkDataOutputStream.writeString("SMP"); +- networkDataOutputStream.writeString(this.worldName); +- networkDataOutputStream.writeString(Integer.toString(this.serverInterface.getPlayerCount())); +- networkDataOutputStream.writeString(Integer.toString(this.maxPlayers)); +- networkDataOutputStream.writeShort((short)this.serverPort); +- networkDataOutputStream.writeString(this.hostIp); +- this.sendTo(networkDataOutputStream.toByteArray(), packet); +- LOGGER.debug("Status [{}]", (Object)socketAddress); +- } +- default: +- return true; +- case 9: +- this.sendChallenge(packet); +- LOGGER.debug("Challenge [{}]", (Object)socketAddress); +- return true; ++ case 0: ++ if (!this.validChallenge(packet)) { ++ LOGGER.debug("Invalid challenge [{}]", (Object)socketAddress); ++ return false; ++ } else if (15 == i) { ++ this.sendTo(this.buildRuleResponse(packet), packet); ++ LOGGER.debug("Rules [{}]", (Object)socketAddress); ++ } else { ++ NetworkDataOutputStream networkDataOutputStream = new NetworkDataOutputStream(1460); ++ networkDataOutputStream.write(0); ++ networkDataOutputStream.writeBytes(this.getIdentBytes(packet.getSocketAddress())); ++ ++ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType queryType = ++ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType.BASIC; ++ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse queryResponse = com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.builder() ++ .motd(this.serverName) ++ .map(this.worldName) ++ .currentPlayers(this.serverInterface.getPlayerCount()) ++ .maxPlayers(this.maxPlayers) ++ .port(this.serverPort) ++ .hostname(this.hostIp) ++ .gameVersion(this.serverInterface.getServerVersion()) ++ .serverVersion(org.bukkit.Bukkit.getServer().getName() + " on " + org.bukkit.Bukkit.getServer().getBukkitVersion()) ++ .build(); ++ com.destroystokyo.paper.event.server.GS4QueryEvent queryEvent = ++ new com.destroystokyo.paper.event.server.GS4QueryEvent(queryType, packet.getAddress(), queryResponse); ++ queryEvent.callEvent(); ++ queryResponse = queryEvent.getResponse(); ++ ++ networkDataOutputStream.writeString(queryResponse.getMotd()); ++ networkDataOutputStream.writeString("SMP"); ++ networkDataOutputStream.writeString(queryResponse.getMap()); ++ networkDataOutputStream.writeString(Integer.toString(queryResponse.getCurrentPlayers())); ++ networkDataOutputStream.writeString(Integer.toString(queryResponse.getMaxPlayers())); ++ networkDataOutputStream.writeShort((short) queryResponse.getPort()); ++ networkDataOutputStream.writeString(queryResponse.getHostname()); ++ // Paper end ++ this.sendTo(networkDataOutputStream.toByteArray(), packet); ++ LOGGER.debug("Status [{}]", (Object)socketAddress); ++ } ++ default: ++ return true; ++ case 9: ++ this.sendChallenge(packet); ++ LOGGER.debug("Challenge [{}]", (Object)socketAddress); ++ return true; + } + } else { + LOGGER.debug("Invalid packet [{}]", (Object)socketAddress); +@@ -0,0 +0,0 @@ public class QueryThreadGs4 extends GenericThread { + this.rulesResponse.writeString("splitnum"); + this.rulesResponse.write(128); + this.rulesResponse.write(0); ++ // Paper start ++ // Pack plugins ++ java.util.List plugins = java.util.Collections.emptyList(); ++ org.bukkit.plugin.Plugin[] bukkitPlugins; ++ if (((net.minecraft.server.dedicated.DedicatedServer) this.serverInterface).server.getQueryPlugins() && (bukkitPlugins = org.bukkit.Bukkit.getPluginManager().getPlugins()).length > 0) { ++ plugins = java.util.stream.Stream.of(bukkitPlugins) ++ .map(plugin -> com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation.of(plugin.getName(), plugin.getDescription().getVersion())) ++ .collect(java.util.stream.Collectors.toList()); ++ } ++ ++ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse queryResponse = com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.builder() ++ .motd(this.serverName) ++ .map(this.worldName) ++ .currentPlayers(this.serverInterface.getPlayerCount()) ++ .maxPlayers(this.maxPlayers) ++ .port(this.serverPort) ++ .hostname(this.hostIp) ++ .plugins(plugins) ++ .players(this.serverInterface.getPlayerNames()) ++ .gameVersion(this.serverInterface.getServerVersion()) ++ .serverVersion(org.bukkit.Bukkit.getServer().getName() + " on " + org.bukkit.Bukkit.getServer().getBukkitVersion()) ++ .build(); ++ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType queryType = ++ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType.FULL; ++ com.destroystokyo.paper.event.server.GS4QueryEvent queryEvent = ++ new com.destroystokyo.paper.event.server.GS4QueryEvent(queryType, packet.getAddress(), queryResponse); ++ queryEvent.callEvent(); ++ queryResponse = queryEvent.getResponse(); + this.rulesResponse.writeString("hostname"); +- this.rulesResponse.writeString(this.serverName); ++ this.rulesResponse.writeString(queryResponse.getMotd()); + this.rulesResponse.writeString("gametype"); + this.rulesResponse.writeString("SMP"); + this.rulesResponse.writeString("game_id"); + this.rulesResponse.writeString("MINECRAFT"); + this.rulesResponse.writeString("version"); +- this.rulesResponse.writeString(this.serverInterface.getServerVersion()); ++ this.rulesResponse.writeString(queryResponse.getGameVersion()); + this.rulesResponse.writeString("plugins"); +- this.rulesResponse.writeString(this.serverInterface.getPluginNames()); ++ java.lang.StringBuilder pluginsString = new java.lang.StringBuilder(); ++ pluginsString.append(queryResponse.getServerVersion()); ++ if (!queryResponse.getPlugins().isEmpty()) { ++ pluginsString.append(": "); ++ java.util.Iterator iter = queryResponse.getPlugins().iterator(); ++ while (iter.hasNext()) { ++ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation info = iter.next(); ++ pluginsString.append(info.getName()); ++ if (info.getVersion() != null) { ++ pluginsString.append(' ').append(info.getVersion().replace(";", ",")); ++ } ++ if (iter.hasNext()) { ++ pluginsString.append(';').append(' '); ++ } ++ } ++ } ++ this.rulesResponse.writeString(pluginsString.toString()); + this.rulesResponse.writeString("map"); +- this.rulesResponse.writeString(this.worldName); ++ this.rulesResponse.writeString(queryResponse.getMap()); + this.rulesResponse.writeString("numplayers"); +- this.rulesResponse.writeString("" + this.serverInterface.getPlayerCount()); ++ this.rulesResponse.writeString(Integer.toString(queryResponse.getCurrentPlayers())); + this.rulesResponse.writeString("maxplayers"); +- this.rulesResponse.writeString("" + this.maxPlayers); ++ this.rulesResponse.writeString(Integer.toString(queryResponse.getMaxPlayers())); + this.rulesResponse.writeString("hostport"); +- this.rulesResponse.writeString("" + this.serverPort); ++ this.rulesResponse.writeString(Integer.toString(queryResponse.getPort())); + this.rulesResponse.writeString("hostip"); +- this.rulesResponse.writeString(this.hostIp); +- this.rulesResponse.write(0); +- this.rulesResponse.write(1); ++ this.rulesResponse.writeString(queryResponse.getHostname()); ++ // The "meaningless data" start, copied from above ++ this.rulesResponse.writeInt(0); ++ this.rulesResponse.writeInt(1); + this.rulesResponse.writeString("player_"); +- this.rulesResponse.write(0); +- String[] strings = this.serverInterface.getPlayerNames(); +- +- for(String string : strings) { +- this.rulesResponse.writeString(string); +- } +- +- this.rulesResponse.write(0); ++ this.rulesResponse.writeInt(0); ++ // "Meaningless data" end ++ queryResponse.getPlayers().forEach(this.rulesResponse::writeStringUnchecked); ++ this.rulesResponse.writeInt(0); ++ // Paper end + return this.rulesResponse.toByteArray(); + } + } diff --git a/patches/server-remapped/Handle-Oversized-Tile-Entities-in-chunks.patch b/patches/server/Handle-Oversized-Tile-Entities-in-chunks.patch similarity index 53% rename from patches/server-remapped/Handle-Oversized-Tile-Entities-in-chunks.patch rename to patches/server/Handle-Oversized-Tile-Entities-in-chunks.patch index 48096b1e53..080cde99cd 100644 --- a/patches/server-remapped/Handle-Oversized-Tile-Entities-in-chunks.patch +++ b/patches/server/Handle-Oversized-Tile-Entities-in-chunks.patch @@ -13,42 +13,38 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacket.java +++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacket.java @@ -0,0 +0,0 @@ public class ClientboundLevelChunkPacket implements Packet blockEntitiesTags; + // Paper start + private final java.util.List extraPackets = new java.util.ArrayList<>(); + private static final int TE_LIMIT = Integer.getInteger("Paper.excessiveTELimit", 750); - ++ + @Override + public java.util.List getExtraPackets() { + return extraPackets; + } + // Paper end - public ClientboundLevelChunkPacket(LevelChunk chunk, int includedSectionsMask) { - ChunkPos chunkcoordintpair = chunk.getPos(); + public ClientboundLevelChunkPacket(LevelChunk chunk) { + ChunkPos chunkPos = chunk.getPos(); @@ -0,0 +0,0 @@ public class ClientboundLevelChunkPacket implements Packet> 4; - - if (this.isFullChunk() || (includedSectionsMask & 1 << j) != 0) { -+ // Paper start - improve oversized chunk data packet handling -+ if (++totalTileEntities > TE_LIMIT) { -+ ClientboundBlockEntityDataPacket updatePacket = tileentity.getUpdatePacket(); -+ if (updatePacket != null) { -+ this.extraPackets.add(updatePacket); -+ continue; -+ } + for(Entry entry2 : chunk.getBlockEntities().entrySet()) { + BlockEntity blockEntity = entry2.getValue(); ++ // Paper start - improve oversized chunk data packet handling ++ if (++totalTileEntities > TE_LIMIT) { ++ ClientboundBlockEntityDataPacket updatePacket = blockEntity.getUpdatePacket(); ++ if (updatePacket != null) { ++ this.extraPackets.add(updatePacket); ++ continue; + } -+ // Paper end - CompoundTag nbttagcompound = tileentity.getUpdateTag(); - if (tileentity instanceof SkullBlockEntity) { SkullBlockEntity.sanitizeTileEntityUUID(nbttagcompound); } // Paper - ++ } ++ // Paper end + CompoundTag compoundTag = blockEntity.getUpdateTag(); + if (blockEntity instanceof net.minecraft.world.level.block.entity.SkullBlockEntity) { net.minecraft.world.level.block.entity.SkullBlockEntity.sanitizeTileEntityUUID(compoundTag); } // Paper + this.blockEntitiesTags.add(compoundTag); diff --git a/patches/server-remapped/Implement-PlayerPostRespawnEvent.patch b/patches/server/Implement-PlayerPostRespawnEvent.patch similarity index 95% rename from patches/server-remapped/Implement-PlayerPostRespawnEvent.patch rename to patches/server/Implement-PlayerPostRespawnEvent.patch index 2f89cb7af8..35a98837a2 100644 --- a/patches/server-remapped/Implement-PlayerPostRespawnEvent.patch +++ b/patches/server/Implement-PlayerPostRespawnEvent.patch @@ -9,7 +9,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java @@ -0,0 +0,0 @@ public abstract class PlayerList { - // this.a(entityplayer1, entityplayer, worldserver1); // CraftBukkit - removed + boolean flag2 = false; + // Paper start diff --git a/patches/server-remapped/MC-145260-Fix-Whitelist-On-Off-inconsistency.patch b/patches/server/MC-145260-Fix-Whitelist-On-Off-inconsistency.patch similarity index 70% rename from patches/server-remapped/MC-145260-Fix-Whitelist-On-Off-inconsistency.patch rename to patches/server/MC-145260-Fix-Whitelist-On-Off-inconsistency.patch index 9dc0bf6552..fb0b1b1815 100644 --- a/patches/server-remapped/MC-145260-Fix-Whitelist-On-Off-inconsistency.patch +++ b/patches/server/MC-145260-Fix-Whitelist-On-Off-inconsistency.patch @@ -27,19 +27,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public boolean isWhitelisted(GameProfile gameprofile, org.bukkit.event.player.PlayerLoginEvent loginEvent) { boolean isOp = this.ops.contains(gameprofile); - boolean isWhitelisted = !this.doWhiteList || isOp || this.whitelist.contains(gameprofile); -+ boolean isWhitelisted = !this.isUsingWhitelist() || isOp || this.whitelist.contains(gameprofile); ++ boolean isWhitelisted = !this.isUsingWhitelist() || isOp || this.whitelist.contains(gameprofile); // Paper - use isUsingWhitelist() final com.destroystokyo.paper.event.profile.ProfileWhitelistVerifyEvent event; -- event = new com.destroystokyo.paper.event.profile.ProfileWhitelistVerifyEvent(MCUtil.toBukkit(gameprofile), this.doWhiteList, isWhitelisted, isOp, org.spigotmc.SpigotConfig.whitelistMessage); -+ event = new com.destroystokyo.paper.event.profile.ProfileWhitelistVerifyEvent(MCUtil.toBukkit(gameprofile), this.isUsingWhitelist(), isWhitelisted, isOp, org.spigotmc.SpigotConfig.whitelistMessage); +- event = new com.destroystokyo.paper.event.profile.ProfileWhitelistVerifyEvent(net.minecraft.server.MCUtil.toBukkit(gameprofile), this.doWhiteList, isWhitelisted, isOp, org.spigotmc.SpigotConfig.whitelistMessage); ++ event = new com.destroystokyo.paper.event.profile.ProfileWhitelistVerifyEvent(net.minecraft.server.MCUtil.toBukkit(gameprofile), this.isUsingWhitelist(), isWhitelisted, isOp, org.spigotmc.SpigotConfig.whitelistMessage); // Paper - use isUsingWhitelist() event.callEvent(); if (!event.isWhitelisted()) { if (loginEvent != null) { -@@ -0,0 +0,0 @@ public abstract class PlayerList { - MCUtil.ensureMain("Save Players" , () -> { // Paper - Ensure main - MinecraftTimings.savePlayers.startTiming(); // Paper - for (int i = 0; i < this.players.size(); ++i) { -- this.savePlayerFile((EntityPlayer) this.players.get(i)); -+ this.save((ServerPlayer) this.players.get(i)); - } - MinecraftTimings.savePlayers.stopTiming(); // Paper - return null; }); // Paper - ensure main diff --git a/patches/server-remapped/Optimize-Network-Manager-and-add-advanced-packet-sup.patch b/patches/server/Optimize-Network-Manager-and-add-advanced-packet-sup.patch similarity index 55% rename from patches/server-remapped/Optimize-Network-Manager-and-add-advanced-packet-sup.patch rename to patches/server/Optimize-Network-Manager-and-add-advanced-packet-sup.patch index 9d106e5dda..90e3b571dd 100644 --- a/patches/server-remapped/Optimize-Network-Manager-and-add-advanced-packet-sup.patch +++ b/patches/server/Optimize-Network-Manager-and-add-advanced-packet-sup.patch @@ -31,22 +31,6 @@ diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/network/Connection.java +++ b/src/main/java/net/minecraft/network/Connection.java -@@ -0,0 +0,0 @@ import net.minecraft.network.chat.Component; - import net.minecraft.network.chat.TranslatableComponent; - import net.minecraft.network.protocol.Packet; - import net.minecraft.network.protocol.PacketFlow; -+import net.minecraft.network.protocol.game.ClientboundBossEventPacket; -+import net.minecraft.network.protocol.game.ClientboundChatPacket; -+import net.minecraft.network.protocol.game.ClientboundCommandSuggestionsPacket; - import net.minecraft.network.protocol.game.ClientboundDisconnectPacket; -+import net.minecraft.network.protocol.game.ClientboundKeepAlivePacket; -+import net.minecraft.network.protocol.game.ClientboundSetTitlesPacket; -+import net.minecraft.server.MCUtil; - import net.minecraft.server.RunningOnDifferentThreadException; -+import net.minecraft.server.level.ServerPlayer; - import net.minecraft.server.network.ServerGamePacketListenerImpl; - import net.minecraft.server.network.ServerLoginPacketListenerImpl; - import net.minecraft.util.LazyLoadedValue; @@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler> { public int protocolVersion; public java.net.InetSocketAddress virtualHost; @@ -71,7 +55,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.packetListener = listener; } + // Paper start -+ public ServerPlayer getPlayer() { ++ public net.minecraft.server.level.ServerPlayer getPlayer() { + if (packetListener instanceof ServerGamePacketListenerImpl) { + return ((ServerGamePacketListenerImpl) packetListener).player; + } else { @@ -101,11 +85,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start + private static boolean canSendImmediate(Connection networkManager, Packet packet) { + return networkManager.isPending || networkManager.protocol != ConnectionProtocol.PLAY || -+ packet instanceof ClientboundKeepAlivePacket || -+ packet instanceof ClientboundChatPacket || -+ packet instanceof ClientboundCommandSuggestionsPacket || -+ packet instanceof ClientboundSetTitlesPacket || -+ packet instanceof ClientboundBossEventPacket; ++ packet instanceof net.minecraft.network.protocol.game.ClientboundKeepAlivePacket || ++ packet instanceof net.minecraft.network.protocol.game.ClientboundChatPacket || ++ packet instanceof net.minecraft.network.protocol.game.ClientboundCommandSuggestionsPacket || ++ packet instanceof net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket || ++ packet instanceof net.minecraft.network.protocol.game.ClientboundSetSubtitleTextPacket || ++ packet instanceof net.minecraft.network.protocol.game.ClientboundSetActionBarTextPacket || ++ packet instanceof net.minecraft.network.protocol.game.ClientboundSetTitlesAnimationPacket || ++ packet instanceof net.minecraft.network.protocol.game.ClientboundClearTitlesPacket || ++ packet instanceof net.minecraft.network.protocol.game.ClientboundBossEventPacket; + } + // Paper end + } @@ -128,10 +116,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + packet.onPacketDispatch(getPlayer()); + if (connected && (InnerUtil.canSendImmediate(this, packet) || ( -+ MCUtil.isMainThread() && packet.isReady() && this.queue.isEmpty() && ++ net.minecraft.server.MCUtil.isMainThread() && packet.isReady() && this.queue.isEmpty() && + (packet.getExtraPackets() == null || packet.getExtraPackets().isEmpty()) + ))) { -+ this.dispatchPacket(packet, callback); ++ this.send(packet, callback); + return; } + // write the packets to the queue, then flush - antixray hooks there already @@ -142,106 +130,67 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } else { + java.util.List packets = new java.util.ArrayList<>(1 + extraPackets.size()); + packets.add(new Connection.PacketHolder(packet, null)); // delay the future listener until the end of the extra packets -+ + + for (int i = 0, len = extraPackets.size(); i < len;) { + Packet extra = extraPackets.get(i); + boolean end = ++i == len; + packets.add(new Connection.PacketHolder(extra, end ? callback : null)); // append listener to the end + } - + this.queue.addAll(packets); // atomic + } -+ this.sendPacketQueue(); ++ this.flushQueue(); + // Paper end } - private void dispatchPacket(Packet packet, @Nullable GenericFutureListener> genericFutureListener) { this.sendPacket(packet, genericFutureListener); } // Paper - OBFHELPER + private void sendPacket(Packet packet, @Nullable GenericFutureListener> callback) { @@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler> { - this.channel.config().setAutoRead(false); + this.setProtocol(enumprotocol); } -+ ServerPlayer player = getPlayer(); // Paper - if (this.channel.eventLoop().inEventLoop()) { - if (enumprotocol != enumprotocol1) { - this.setProtocol(enumprotocol); - } -+ // Paper start -+ if (!isConnected()) { -+ packet.onPacketDispatchFinish(player, null); -+ return; -+ } -+ try { -+ // Paper end - - ChannelFuture channelfuture = this.channel.writeAndFlush(packet); - - if (callback != null) { - channelfuture.addListener(callback); - } -+ // Paper start -+ if (packet.hasFinishListener()) { -+ channelfuture.addListener((ChannelFutureListener) channelFuture -> packet.onPacketDispatchFinish(player, channelFuture)); -+ } -+ // Paper end - - channelfuture.addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); -+ // Paper start -+ } catch (Exception e) { -+ LOGGER.error("NetworkException: " + player, e); -+ disconnect(new TranslatableComponent("disconnect.genericReason", "Internal Exception: " + e.getMessage()));; -+ packet.onPacketDispatchFinish(player, null); -+ } -+ // Paper end - } else { - this.channel.eventLoop().execute(() -> { - if (enumprotocol != enumprotocol1) { - this.setProtocol(enumprotocol); - } - -+ // Paper start -+ if (!isConnected()) { -+ packet.onPacketDispatchFinish(player, null); -+ return; -+ } -+ try { -+ // Paper end - ChannelFuture channelfuture1 = this.channel.writeAndFlush(packet); - ++ // Paper start ++ net.minecraft.server.level.ServerPlayer player = getPlayer(); ++ if (!isConnected()) { ++ packet.onPacketDispatchFinish(player, null); ++ return; ++ } + - if (callback != null) { - channelfuture1.addListener(callback); - } -+ // Paper start -+ if (packet.hasFinishListener()) { -+ channelfuture1.addListener((ChannelFutureListener) channelFuture -> packet.onPacketDispatchFinish(player, channelFuture)); -+ } -+ // Paper end ++ try { ++ // Paper end + ChannelFuture channelfuture = this.channel.writeAndFlush(packet); - channelfuture1.addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); -+ // Paper start -+ } catch (Exception e) { -+ LOGGER.error("NetworkException: " + player, e); -+ disconnect(new TranslatableComponent("disconnect.genericReason", "Internal Exception: " + e.getMessage()));; -+ packet.onPacketDispatchFinish(player, null); -+ } -+ // Paper end - }); + if (genericfuturelistener != null) { + channelfuture.addListener(genericfuturelistener); } ++ // Paper start ++ if (packet.hasFinishListener()) { ++ channelfuture.addListener((ChannelFutureListener) channelFuture -> packet.onPacketDispatchFinish(player, channelFuture)); ++ } ++ // Paper end + channelfuture.addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); ++ // Paper start ++ } catch (Exception e) { ++ LOGGER.error("NetworkException: " + player, e); ++ disconnect(new net.minecraft.network.chat.TranslatableComponent("disconnect.genericReason", "Internal Exception: " + e.getMessage())); ++ packet.onPacketDispatchFinish(player, null); ++ } ++ // Paper end + } + + private ConnectionProtocol getCurrentProtocol() { + return (ConnectionProtocol) this.channel.attr(Connection.ATTRIBUTE_PROTOCOL).get(); } -- private void sendPacketQueue() { this.flushQueue(); } // Paper - OBFHELPER - private void flushQueue() { - if (this.channel != null && this.channel.isOpen()) { - Queue queue = this.queue; - + // Paper start - rewrite this to be safer if ran off main thread -+ private boolean sendPacketQueue() { return this.p(); } // OBFHELPER // void -> boolean -+ private boolean p() { // void -> boolean ++ private boolean flushQueue() { // void -> boolean + if (!isConnected()) { + return true; + } -+ if (MCUtil.isMainThread()) { ++ if (net.minecraft.server.MCUtil.isMainThread()) { + return processQueue(); + } else if (isPending) { + // Should only happen during login/status stages @@ -262,19 +211,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // But if we are not on main due to login/status, the parent is synchronized on packetQueue + java.util.Iterator iterator = this.queue.iterator(); + while (iterator.hasNext()) { -+ Connection.PacketHolder queued = iterator.next(); // poll -> peek ++ PacketHolder queued = iterator.next(); // poll -> peek + + // Fix NPE (Spigot bug caused by handleDisconnection()) + if (queued == null) { + return true; + } -+ Packet packet = queued.getPacket(); ++ Packet packet = queued.packet; + if (!packet.isReady()) { + return false; + } else { + iterator.remove(); -+ this.dispatchPacket(packet, queued.getGenericFutureListener()); ++ this.sendPacket(packet, queued.listener); } } + return true; @@ -282,26 +231,23 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end public void tick() { -- this.flushQueue(); -+ this.p(); - if (this.packetListener instanceof ServerLoginPacketListenerImpl) { - ((ServerLoginPacketListenerImpl) this.packetListener).tick(); - } + this.flushQueue(); @@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler> { return this.address; } + // Paper start + public void clearPacketQueue() { -+ ServerPlayer player = getPlayer(); ++ net.minecraft.server.level.ServerPlayer player = getPlayer(); + queue.forEach(queuedPacket -> { -+ Packet packet = queuedPacket.getPacket(); ++ Packet packet = queuedPacket.packet; + if (packet.hasFinishListener()) { + packet.onPacketDispatchFinish(player, null); + } + }); + queue.clear(); -+ } // Paper end ++ } ++ // Paper end public void disconnect(Component disconnectReason) { // Spigot Start this.preparing = false; @@ -314,13 +260,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (this.channel != null && !this.channel.isOpen()) { if (this.disconnectionHandled) { - Connection.LOGGER.warn("handleDisconnection() called twice"); -+ //NetworkManager.LOGGER.warn("handleDisconnection() called twice"); // Paper - Do not log useless message ++ //Connection.LOGGER.warn("handleDisconnection() called twice"); // Paper - Do not log useless message } else { this.disconnectionHandled = true; if (this.getDisconnectedReason() != null) { @@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler> { } else if (this.getPacketListener() != null) { - this.getPacketListener().a(new TranslatableComponent("multiplayer.disconnect.generic")); + this.getPacketListener().onDisconnect(new TranslatableComponent("multiplayer.disconnect.generic")); } - this.queue.clear(); // Free up packet queue. + clearPacketQueue(); // Paper @@ -331,64 +277,23 @@ diff --git a/src/main/java/net/minecraft/network/protocol/Packet.java b/src/main index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/network/protocol/Packet.java +++ b/src/main/java/net/minecraft/network/protocol/Packet.java -@@ -0,0 +0,0 @@ - package net.minecraft.network.protocol; - -+import io.netty.channel.ChannelFuture; // Paper - import java.io.IOException; - import net.minecraft.network.FriendlyByteBuf; - import net.minecraft.network.PacketListener; @@ -0,0 +0,0 @@ public interface Packet { void handle(T listener); // Paper start -+ + /** + * @param player Null if not at PLAY stage yet + */ -+ default void onPacketDispatch(@javax.annotation.Nullable EntityPlayer player) {} ++ default void onPacketDispatch(@javax.annotation.Nullable net.minecraft.server.level.ServerPlayer player) {} + + /** + * @param player Null if not at PLAY stage yet + * @param future Can be null if packet was cancelled + */ -+ default void onPacketDispatchFinish(@javax.annotation.Nullable EntityPlayer player, @javax.annotation.Nullable ChannelFuture future) {} ++ default void onPacketDispatchFinish(@javax.annotation.Nullable net.minecraft.server.level.ServerPlayer player, @javax.annotation.Nullable io.netty.channel.ChannelFuture future) {} + default boolean hasFinishListener() { return false; } + default boolean isReady() { return true; } + default java.util.List getExtraPackets() { return null; } - default boolean packetTooLarge(NetworkManager manager) { + default boolean packetTooLarge(net.minecraft.network.Connection manager) { return false; } -diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -+++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -@@ -0,0 +0,0 @@ import io.netty.channel.epoll.EpollServerSocketChannel; - import io.netty.channel.nio.NioEventLoopGroup; - import io.netty.channel.socket.ServerSocketChannel; - import io.netty.channel.socket.nio.NioServerSocketChannel; -+import io.netty.handler.flush.FlushConsolidationHandler; // Paper - import io.netty.handler.timeout.ReadTimeoutHandler; - import java.io.IOException; - import java.net.InetAddress; -@@ -0,0 +0,0 @@ public class ServerConnectionListener { - private final List connections = Collections.synchronizedList(Lists.newArrayList()); - // Paper start - prevent blocking on adding a new network manager while the server is ticking - private final java.util.Queue pending = new java.util.concurrent.ConcurrentLinkedQueue<>(); -+ private static final boolean disableFlushConsolidation = Boolean.getBoolean("Paper.disableFlushConsolidate"); // Paper - private void addPending() { - Connection manager = null; - while ((manager = pending.poll()) != null) { - connections.add(manager); -+ manager.isPending = false; - } - } - // Paper end -@@ -0,0 +0,0 @@ public class ServerConnectionListener { - ; - } - -+ if (!disableFlushConsolidation) channel.pipeline().addFirst(new FlushConsolidationHandler()); // Paper - channel.pipeline().addLast("timeout", new ReadTimeoutHandler(30)).addLast("legacy_query", new LegacyQueryHandler(ServerConnectionListener.this)).addLast("splitter", new Varint21FrameDecoder()).addLast("decoder", new PacketDecoder(PacketFlow.SERVERBOUND)).addLast("prepender", new Varint21LengthFieldPrepender()).addLast("encoder", new PacketEncoder(PacketFlow.CLIENTBOUND)); - int j = ServerConnectionListener.this.server.getRateLimitPacketsPerSecond(); - Object object = j > 0 ? new RateKickingConnection(j) : new Connection(PacketFlow.SERVERBOUND); diff --git a/patches/server-remapped/Set-Zombie-last-tick-at-start-of-drowning-process.patch b/patches/server/Set-Zombie-last-tick-at-start-of-drowning-process.patch similarity index 100% rename from patches/server-remapped/Set-Zombie-last-tick-at-start-of-drowning-process.patch rename to patches/server/Set-Zombie-last-tick-at-start-of-drowning-process.patch diff --git a/patches/server/Update-entity-Metadata-for-all-tracked-players.patch b/patches/server/Update-entity-Metadata-for-all-tracked-players.patch new file mode 100644 index 0000000000..25c1aeaf0a --- /dev/null +++ b/patches/server/Update-entity-Metadata-for-all-tracked-players.patch @@ -0,0 +1,76 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: AgentTroll +Date: Fri, 22 Mar 2019 22:24:03 -0700 +Subject: [PATCH] Update entity Metadata for all tracked players + + +diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/level/ChunkMap.java ++++ b/src/main/java/net/minecraft/server/level/ChunkMap.java +@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + } else { + ChunkMap.TrackedEntity playerchunkmap_entitytracker = new ChunkMap.TrackedEntity(entity, i, j, entitytypes.trackDeltas()); + ++ entity.tracker = playerchunkmap_entitytracker; // Paper - Fast access to tracker + this.entityMap.put(entity.getId(), playerchunkmap_entitytracker); + playerchunkmap_entitytracker.updatePlayers(this.level.players()); + if (entity instanceof ServerPlayer) { +@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + if (playerchunkmap_entitytracker1 != null) { + playerchunkmap_entitytracker1.broadcastRemoved(); + } +- ++ entity.tracker = null; // Paper - We're no longer tracked + } + + protected void tick() { +diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/level/ServerEntity.java ++++ b/src/main/java/net/minecraft/server/level/ServerEntity.java +@@ -0,0 +0,0 @@ public class ServerEntity { + return ClientboundMoveEntityPacket.packetToEntity(this.xp, this.yp, this.zp); + } + ++ // Paper start - Add broadcast method ++ void broadcast(Packet packet) { ++ this.broadcast.accept(packet); ++ } ++ // Paper end ++ + private void broadcastAndSend(Packet packet) { + this.broadcast.accept(packet); + if (this.entity instanceof ServerPlayer) { +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser + + if (event.isCancelled() || ServerGamePacketListenerImpl.this.player.getInventory().getSelected() == null || ServerGamePacketListenerImpl.this.player.getInventory().getSelected().getItem() != origItem) { + // Refresh the current entity metadata +- ServerGamePacketListenerImpl.this.send(new ClientboundSetEntityDataPacket(entity.getId(), entity.getEntityData(), true)); ++ // Paper start - update entity for all players ++ ClientboundSetEntityDataPacket packet1 = new ClientboundSetEntityDataPacket(entity.getId(), entity.getEntityData(), true); ++ if (entity.tracker != null) { ++ entity.tracker.broadcast(packet1); ++ } else { ++ ServerGamePacketListenerImpl.this.send(packet1); ++ } ++ // Paper end + } + + if (event.isCancelled()) { +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n + public boolean forceExplosionKnockback; // SPIGOT-949 + public boolean persistentInvisibility = false; + public org.bukkit.Location origin; // Paper ++ public net.minecraft.server.level.ChunkMap.TrackedEntity tracker; // Paper - fast access to tracker + // Spigot start + public final org.spigotmc.ActivationRange.ActivationType activationType = org.spigotmc.ActivationRange.initializeEntityActivationType(this); + public final boolean defaultActivationState; diff --git a/patches/server-remapped/Use-proper-max-length-when-serialising-BungeeCord-te.patch b/patches/server/Use-proper-max-length-when-serialising-BungeeCord-te.patch similarity index 81% rename from patches/server-remapped/Use-proper-max-length-when-serialising-BungeeCord-te.patch rename to patches/server/Use-proper-max-length-when-serialising-BungeeCord-te.patch index 4fe5407cb3..dc7d33890a 100644 --- a/patches/server-remapped/Use-proper-max-length-when-serialising-BungeeCord-te.patch +++ b/patches/server/Use-proper-max-length-when-serialising-BungeeCord-te.patch @@ -15,17 +15,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public class ClientboundChatPacket implements Packet { - + private static final int MAX_LENGTH = Short.MAX_VALUE * 8 + 8; // Paper - private Component message; + private final Component message; public net.kyori.adventure.text.Component adventure$message; // Paper public net.md_5.bungee.api.chat.BaseComponent[] components; // Spigot @@ -0,0 +0,0 @@ public class ClientboundChatPacket implements Packet { - //packetdataserializer.a(net.md_5.bungee.chat.ComponentSerializer.toString(components)); // Paper - comment, replaced with below + // buf.writeUtf(net.md_5.bungee.chat.ComponentSerializer.toString(components)); // Paper - comment, replaced with below // Paper start - don't nest if we don't need to so that we can preserve formatting if (this.components.length == 1) { -- buf.writeByteArray(net.md_5.bungee.chat.ComponentSerializer.toString(this.components[0])); +- buf.writeUtf(net.md_5.bungee.chat.ComponentSerializer.toString(this.components[0])); + buf.writeUtf(net.md_5.bungee.chat.ComponentSerializer.toString(this.components[0]), MAX_LENGTH); // Paper - use proper max length } else { -- buf.writeByteArray(net.md_5.bungee.chat.ComponentSerializer.toString(this.components)); +- buf.writeUtf(net.md_5.bungee.chat.ComponentSerializer.toString(this.components)); + buf.writeUtf(net.md_5.bungee.chat.ComponentSerializer.toString(this.components), MAX_LENGTH); // Paper - use proper max length } // Paper end diff --git a/settings.gradle.kts b/settings.gradle.kts index 54bb957497..302bcb31ab 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,5 +1,6 @@ pluginManagement { repositories { + mavenLocal() gradlePluginPortal() maven("https://wav.jfrog.io/artifactory/repo/") }