geforkt von Mirrors/Paper
Work
Dieser Commit ist enthalten in:
Ursprung
bda639725b
Commit
43227a418f
@ -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")
|
||||
|
@ -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.
|
@ -1,271 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
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;
|
@ -1,265 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Vainomaa <mikroskeem@mikroskeem.eu>
|
||||
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<SocketAddress, QueryThreadGs4.RequestChallenge> 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<com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation> 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<com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation> 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();
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: AgentTroll <woodyc40@gmail.com>
|
||||
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()) {
|
@ -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<Entity> 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
|
209
patches/server/Fire-event-on-GS4-query.patch
Normale Datei
209
patches/server/Fire-event-on-GS4-query.patch
Normale Datei
@ -0,0 +1,209 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Vainomaa <mikroskeem@mikroskeem.eu>
|
||||
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<com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation> 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<com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation> 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();
|
||||
}
|
||||
}
|
@ -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<ClientGamePacketListe
|
||||
private boolean fullChunk;
|
||||
|
||||
public ClientboundLevelChunkPacket() {}
|
||||
private final int[] biomes;
|
||||
private final byte[] buffer;
|
||||
private final List<CompoundTag> blockEntitiesTags;
|
||||
+ // Paper start
|
||||
+ private final java.util.List<Packet> extraPackets = new java.util.ArrayList<>();
|
||||
+ private static final int TE_LIMIT = Integer.getInteger("Paper.excessiveTELimit", 750);
|
||||
|
||||
+
|
||||
+ @Override
|
||||
+ public java.util.List<Packet> 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<ClientGamePacketListe
|
||||
this.availableSections = this.extractChunkData(new FriendlyByteBuf(this.getWriteBuffer()), chunk, includedSectionsMask);
|
||||
this.buffer = new byte[this.calculateChunkSize(chunk)];
|
||||
this.availableSections = this.extractChunkData(new FriendlyByteBuf(this.getWriteBuffer()), chunk);
|
||||
this.blockEntitiesTags = Lists.newArrayList();
|
||||
iterator = chunk.getBlockEntities().entrySet().iterator();
|
||||
+ int totalTileEntities = 0; // Paper
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
entry = (Entry) iterator.next();
|
||||
@@ -0,0 +0,0 @@ public class ClientboundLevelChunkPacket implements Packet<ClientGamePacketListe
|
||||
int j = blockposition.getY() >> 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<BlockPos, BlockEntity> 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);
|
@ -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
|
@ -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
|
@ -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<Packet<?>> {
|
||||
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<Connection.PacketHolder> 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<? extends Future<? super Void>> genericFutureListener) { this.sendPacket(packet, genericFutureListener); } // Paper - OBFHELPER
|
||||
private void sendPacket(Packet<?> packet, @Nullable GenericFutureListener<? extends Future<? super Void>> callback) {
|
||||
@@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
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<PacketHolder> 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<Packet<?>> {
|
||||
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<Packet<?>> {
|
||||
} 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<T extends PacketListener> {
|
||||
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<Packet> 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<Connection> 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<Connection> 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);
|
76
patches/server/Update-entity-Metadata-for-all-tracked-players.patch
Normale Datei
76
patches/server/Update-entity-Metadata-for-all-tracked-players.patch
Normale Datei
@ -0,0 +1,76 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: AgentTroll <woodyc40@gmail.com>
|
||||
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;
|
@ -15,17 +15,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
||||
public class ClientboundChatPacket implements Packet<ClientGamePacketListener> {
|
||||
-
|
||||
+ 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<ClientGamePacketListener> {
|
||||
//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
|
@ -1,5 +1,6 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
gradlePluginPortal()
|
||||
maven("https://wav.jfrog.io/artifactory/repo/")
|
||||
}
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren