even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even more patches

This commit is contained in:
Jason Penilla 2021-11-25 00:10:26 -08:00 committed by MiniDigger | Martin
parent b39fa92d5d
commit 055b8ab9cf
31 changed files with 96 additions and 97 deletions

View file

@ -1,363 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Andrew Steinborn <git@steinborn.me>
Date: Mon, 26 Jul 2021 02:15:17 -0400
Subject: [PATCH] Use Velocity compression and cipher natives
diff --git a/build.gradle.kts b/build.gradle.kts
index c7ebad49e04c36c27341cabc4a024f170d762f3f..f46f11c32560da6f4955284d93da3dd7e22555a3 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -55,6 +55,7 @@ dependencies {
implementation("io.netty:netty-all:4.1.65.Final") // Paper
implementation("net.fabricmc:mapping-io:0.3.0") // Paper - needed to read mappings for stacktrace deobfuscation
+ implementation("com.velocitypowered:velocity-native:1.1.0-SNAPSHOT") // Paper
testImplementation("io.github.classgraph:classgraph:4.8.47") // Paper - mob goal test
testImplementation("junit:junit:4.13.1")
diff --git a/src/main/java/net/minecraft/network/CipherDecoder.java b/src/main/java/net/minecraft/network/CipherDecoder.java
index 06d545bc7206dd0d56cf27c31935c0f5ed21ef08..201e5eb2d0ec985ea60c59ac89593bd88ad3ee4d 100644
--- a/src/main/java/net/minecraft/network/CipherDecoder.java
+++ b/src/main/java/net/minecraft/network/CipherDecoder.java
@@ -7,14 +7,30 @@ import java.util.List;
import javax.crypto.Cipher;
public class CipherDecoder extends MessageToMessageDecoder<ByteBuf> {
- private final CipherBase cipher;
+ private final com.velocitypowered.natives.encryption.VelocityCipher cipher; // Paper
- public CipherDecoder(Cipher cipher) {
- this.cipher = new CipherBase(cipher);
+ public CipherDecoder(com.velocitypowered.natives.encryption.VelocityCipher cipher) { // Paper
+ this.cipher = cipher; // Paper
}
@Override
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
- list.add(this.cipher.decipher(channelHandlerContext, byteBuf));
+ // Paper start
+ ByteBuf compatible = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(channelHandlerContext.alloc(), cipher, byteBuf);
+ try {
+ cipher.process(compatible);
+ list.add(compatible);
+ } catch (Exception e) {
+ compatible.release(); // compatible will never be used if we throw an exception
+ throw e;
+ }
+ // Paper end
}
+
+ // Paper start
+ @Override
+ public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
+ cipher.close();
+ }
+ // Paper end
}
diff --git a/src/main/java/net/minecraft/network/CipherEncoder.java b/src/main/java/net/minecraft/network/CipherEncoder.java
index 50a7058b18a8ca05363b73eaefbd812ef50d53f1..7319da27dfa5029c9893ec04bfd4325531af8a98 100644
--- a/src/main/java/net/minecraft/network/CipherEncoder.java
+++ b/src/main/java/net/minecraft/network/CipherEncoder.java
@@ -4,16 +4,33 @@ import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import javax.crypto.Cipher;
+import java.util.List;
-public class CipherEncoder extends MessageToByteEncoder<ByteBuf> {
- private final CipherBase cipher;
+public class CipherEncoder extends io.netty.handler.codec.MessageToMessageEncoder<ByteBuf> { // Paper - change superclass
+ private final com.velocitypowered.natives.encryption.VelocityCipher cipher; // Paper
- public CipherEncoder(Cipher cipher) {
- this.cipher = new CipherBase(cipher);
+ public CipherEncoder(com.velocitypowered.natives.encryption.VelocityCipher cipher) { // Paper
+ this.cipher = cipher; // Paper
}
@Override
- protected void encode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, ByteBuf byteBuf2) throws Exception {
- this.cipher.encipher(byteBuf, byteBuf2);
+ protected void encode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
+ // Paper start
+ ByteBuf compatible = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(channelHandlerContext.alloc(), cipher, byteBuf);
+ try {
+ cipher.process(compatible);
+ list.add(compatible);
+ } catch (Exception e) {
+ compatible.release(); // compatible will never be used if we throw an exception
+ throw e;
+ }
+ // Paper end
}
+
+ // Paper start
+ @Override
+ public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
+ cipher.close();
+ }
+ // Paper end
}
diff --git a/src/main/java/net/minecraft/network/CompressionDecoder.java b/src/main/java/net/minecraft/network/CompressionDecoder.java
index efd05c8c1114aab4c237ccbc2e4e935a08c076ee..3569fc49e87b773dce0e59b9069797834ae32613 100644
--- a/src/main/java/net/minecraft/network/CompressionDecoder.java
+++ b/src/main/java/net/minecraft/network/CompressionDecoder.java
@@ -12,13 +12,20 @@ public class CompressionDecoder extends ByteToMessageDecoder {
public static final int MAXIMUM_COMPRESSED_LENGTH = 2097152;
public static final int MAXIMUM_UNCOMPRESSED_LENGTH = 8388608;
private final Inflater inflater;
+ private final com.velocitypowered.natives.compression.VelocityCompressor compressor; // Paper
private int threshold;
private boolean validateDecompressed;
+ // Paper start
public CompressionDecoder(int compressionThreshold, boolean bl) {
+ this(null, compressionThreshold, bl);
+ }
+ public CompressionDecoder(com.velocitypowered.natives.compression.VelocityCompressor compressor, int compressionThreshold, boolean bl) {
this.threshold = compressionThreshold;
this.validateDecompressed = bl;
- this.inflater = new Inflater();
+ this.inflater = compressor == null ? new Inflater() : null;
+ this.compressor = compressor;
+ // Paper end
}
@Override
@@ -39,6 +46,8 @@ public class CompressionDecoder extends ByteToMessageDecoder {
}
}
+ // Paper start
+ if (this.inflater != null) {
byte[] bs = new byte[friendlyByteBuf.readableBytes()];
friendlyByteBuf.readBytes(bs);
this.inflater.setInput(bs);
@@ -46,10 +55,36 @@ public class CompressionDecoder extends ByteToMessageDecoder {
this.inflater.inflate(cs);
list.add(Unpooled.wrappedBuffer(cs));
this.inflater.reset();
+ return;
+ }
+
+ int claimedUncompressedSize = i; // OBFHELPER
+ ByteBuf compatibleIn = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(channelHandlerContext.alloc(), this.compressor, byteBuf);
+ ByteBuf uncompressed = com.velocitypowered.natives.util.MoreByteBufUtils.preferredBuffer(channelHandlerContext.alloc(), this.compressor, claimedUncompressedSize);
+ try {
+ this.compressor.inflate(compatibleIn, uncompressed, claimedUncompressedSize);
+ list.add(uncompressed);
+ byteBuf.clear();
+ } catch (Exception e) {
+ uncompressed.release();
+ throw e;
+ } finally {
+ compatibleIn.release();
+ }
+ // Paper end
}
}
}
+ // Paper start
+ @Override
+ public void handlerRemoved0(ChannelHandlerContext ctx) throws Exception {
+ if (this.compressor != null) {
+ this.compressor.close();
+ }
+ }
+ // Paper end
+
public void setThreshold(int compressionThreshold, boolean bl) {
this.threshold = compressionThreshold;
this.validateDecompressed = bl;
diff --git a/src/main/java/net/minecraft/network/CompressionEncoder.java b/src/main/java/net/minecraft/network/CompressionEncoder.java
index 524c0c674f63cfcb601416a18348f37aabb4e3ff..89bf5066b83e8d79c77c90fce1f7858c06b01730 100644
--- a/src/main/java/net/minecraft/network/CompressionEncoder.java
+++ b/src/main/java/net/minecraft/network/CompressionEncoder.java
@@ -6,23 +6,38 @@ import io.netty.handler.codec.MessageToByteEncoder;
import java.util.zip.Deflater;
public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
- private final byte[] encodeBuf = new byte[8192];
+ private final byte[] encodeBuf; // Paper
private final Deflater deflater;
+ private final com.velocitypowered.natives.compression.VelocityCompressor compressor; // Paper
private int threshold;
+ // Paper start
public CompressionEncoder(int compressionThreshold) {
+ this(null, compressionThreshold);
+ }
+ public CompressionEncoder(com.velocitypowered.natives.compression.VelocityCompressor compressor, int compressionThreshold) {
this.threshold = compressionThreshold;
- this.deflater = new Deflater();
+ if (compressor == null) {
+ this.encodeBuf = new byte[8192];
+ this.deflater = new Deflater();
+ } else {
+ this.encodeBuf = null;
+ this.deflater = null;
+ }
+ this.compressor = compressor;
+ // Paper end
}
@Override
- protected void encode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, ByteBuf byteBuf2) {
+ protected void encode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, ByteBuf byteBuf2) throws Exception { // Paper
int i = byteBuf.readableBytes();
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(byteBuf2);
if (i < this.threshold) {
friendlyByteBuf.writeVarInt(0);
friendlyByteBuf.writeBytes(byteBuf);
} else {
+ // Paper start
+ if (this.deflater != null) {
byte[] bs = new byte[i];
byteBuf.readBytes(bs);
friendlyByteBuf.writeVarInt(bs.length);
@@ -35,10 +50,48 @@ public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
}
this.deflater.reset();
+ return;
+ }
+
+ friendlyByteBuf.writeVarInt(i);
+ ByteBuf compatibleIn = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(channelHandlerContext.alloc(), this.compressor, byteBuf);
+ try {
+ this.compressor.deflate(compatibleIn, byteBuf2);
+ } finally {
+ compatibleIn.release();
+ }
+ // Paper end
}
}
+ // Paper start
+ @Override
+ protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, ByteBuf msg, boolean preferDirect) throws Exception{
+ if (this.compressor != null) {
+ // We allocate bytes to be compressed plus 1 byte. This covers two cases:
+ //
+ // - Compression
+ // According to https://github.com/ebiggers/libdeflate/blob/master/libdeflate.h#L103,
+ // if the data compresses well (and we do not have some pathological case) then the maximum
+ // size the compressed size will ever be is the input size minus one.
+ // - Uncompressed
+ // This is fairly obvious - we will then have one more than the uncompressed size.
+ int initialBufferSize = msg.readableBytes() + 1;
+ return com.velocitypowered.natives.util.MoreByteBufUtils.preferredBuffer(ctx.alloc(), this.compressor, initialBufferSize);
+ }
+
+ return super.allocateBuffer(ctx, msg, preferDirect);
+ }
+
+ @Override
+ public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
+ if (this.compressor != null) {
+ this.compressor.close();
+ }
+ }
+ // Paper end
+
public int getThreshold() {
return this.threshold;
}
diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
index 0dae504f49a4a3c66a01eb03896833a010cd5821..5f43459884daea61178c3fdb913204e64f833f61 100644
--- a/src/main/java/net/minecraft/network/Connection.java
+++ b/src/main/java/net/minecraft/network/Connection.java
@@ -657,11 +657,28 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
return networkmanager;
}
- public void setEncryptionKey(Cipher decryptionCipher, Cipher encryptionCipher) {
- this.encrypted = true;
- this.channel.pipeline().addBefore("splitter", "decrypt", new CipherDecoder(decryptionCipher));
- this.channel.pipeline().addBefore("prepender", "encrypt", new CipherEncoder(encryptionCipher));
+ // Paper start
+// public void setEncryptionKey(Cipher decryptionCipher, Cipher encryptionCipher) {
+// this.encrypted = true;
+// this.channel.pipeline().addBefore("splitter", "decrypt", new CipherDecoder(decryptionCipher));
+// this.channel.pipeline().addBefore("prepender", "encrypt", new CipherEncoder(encryptionCipher));
+// }
+
+ public void setupEncryption(javax.crypto.SecretKey key) throws net.minecraft.util.CryptException {
+ if (!this.encrypted) {
+ try {
+ com.velocitypowered.natives.encryption.VelocityCipher decryption = com.velocitypowered.natives.util.Natives.cipher.get().forDecryption(key);
+ com.velocitypowered.natives.encryption.VelocityCipher encryption = com.velocitypowered.natives.util.Natives.cipher.get().forEncryption(key);
+
+ this.encrypted = true;
+ this.channel.pipeline().addBefore("splitter", "decrypt", new CipherDecoder(decryption));
+ this.channel.pipeline().addBefore("prepender", "encrypt", new CipherEncoder(encryption));
+ } catch (java.security.GeneralSecurityException e) {
+ throw new net.minecraft.util.CryptException(e);
+ }
+ }
}
+ // Paper end
public boolean isEncrypted() {
return this.encrypted;
@@ -690,16 +707,17 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
public void setupCompression(int compressionThreshold, boolean flag) {
if (compressionThreshold >= 0) {
+ com.velocitypowered.natives.compression.VelocityCompressor compressor = com.velocitypowered.natives.util.Natives.compress.get().create(-1); // Paper
if (this.channel.pipeline().get("decompress") instanceof CompressionDecoder) {
((CompressionDecoder) this.channel.pipeline().get("decompress")).setThreshold(compressionThreshold, flag);
} else {
- this.channel.pipeline().addBefore("decoder", "decompress", new CompressionDecoder(compressionThreshold, flag));
+ this.channel.pipeline().addBefore("decoder", "decompress", new CompressionDecoder(compressor, compressionThreshold, flag)); // Paper
}
if (this.channel.pipeline().get("compress") instanceof CompressionEncoder) {
((CompressionEncoder) this.channel.pipeline().get("compress")).setThreshold(compressionThreshold);
} else {
- this.channel.pipeline().addBefore("encoder", "compress", new CompressionEncoder(compressionThreshold));
+ this.channel.pipeline().addBefore("encoder", "compress", new CompressionEncoder(compressor, compressionThreshold)); // Paper
}
} else {
if (this.channel.pipeline().get("decompress") instanceof CompressionDecoder) {
diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
index 961660f6f9e00b93252519e38b74c66c53388ed2..a7046da8c097254907e01cd17f4107c8744f4a6e 100644
--- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
+++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
@@ -104,6 +104,11 @@ public class ServerConnectionListener {
ServerConnectionListener.LOGGER.info("Using default channel type");
}
+ // Paper start - indicate Velocity natives in use
+ ServerConnectionListener.LOGGER.info("Paper: Using " + com.velocitypowered.natives.util.Natives.compress.getLoadedVariant() + " compression from Velocity.");
+ ServerConnectionListener.LOGGER.info("Paper: Using " + com.velocitypowered.natives.util.Natives.cipher.getLoadedVariant() + " cipher from Velocity.");
+ // Paper end
+
this.channels.add(((ServerBootstrap) ((ServerBootstrap) (new ServerBootstrap()).channel(oclass)).childHandler(new ChannelInitializer<Channel>() {
protected void initChannel(Channel channel) {
try {
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
index 45e77d96f673ce68cf15ce3d45fd1eeffed4d8d8..01fee879c946b6640da34d5890d686f0152437dc 100644
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
@@ -275,12 +275,14 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener
}
SecretKey secretkey = packet.getSecretKey(privatekey);
- Cipher cipher = Crypt.getCipher(2, secretkey);
- Cipher cipher1 = Crypt.getCipher(1, secretkey);
+ // Paper start
+// Cipher cipher = Crypt.getCipher(2, secretkey);
+// Cipher cipher1 = Crypt.getCipher(1, secretkey);
+ // Paper end
s = (new BigInteger(Crypt.digestData("", this.server.getKeyPair().getPublic(), secretkey))).toString(16);
this.state = ServerLoginPacketListenerImpl.State.AUTHENTICATING;
- this.connection.setEncryptionKey(cipher, cipher1);
+ this.connection.setupEncryption(secretkey); // Paper
} catch (CryptException cryptographyexception) {
throw new IllegalStateException("Protocol error", cryptographyexception);
}

View file

@ -1,31 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Mon, 30 Aug 2021 04:26:40 -0700
Subject: [PATCH] Reduce worldgen thread worker count for low core count CPUs
diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java
index 69faebb95924946f648cf9f86ff777d3274e3f28..505546d32eea4682452dbac02311433157f6a30e 100644
--- a/src/main/java/net/minecraft/Util.java
+++ b/src/main/java/net/minecraft/Util.java
@@ -120,7 +120,19 @@ public class Util {
private static ExecutorService makeExecutor(String s, int priorityModifier) { // Paper - add priority
// Paper start - use simpler thread pool that allows 1 thread
- int i = Math.min(8, Math.max(Runtime.getRuntime().availableProcessors() - 2, 1));
+ // Paper start - also try to avoid suffocating the system with the worldgen workers
+ int cpus = Runtime.getRuntime().availableProcessors() / 2;
+ int i;
+ if (cpus <= 4) {
+ i = cpus <= 2 ? 1 : 2;
+ } else if (cpus <= 8) {
+ // [5, 8]
+ i = Math.max(3, cpus - 2);
+ } else {
+ i = cpus * 2 / 3;
+ }
+ i = Math.min(8, i);
+ // Paper end - also try to avoid suffocating the system with the worldgen workers
i = Integer.getInteger("Paper.WorkerThreadCount", i);
ExecutorService executorService;

View file

@ -1,68 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Fri, 3 Sep 2021 15:50:25 +0100
Subject: [PATCH] Do not process entity loads in CraftChunk#getEntities
This re-introduces the issue behind #5872 but fixes #6543
The logic here is generally flawed however somewhat of a nuance,
upstream uses managedBlock which is basically needed to process
the posted entity adds, but, has the side-effect of processing any
chunk loads which has the naunce of stacking up and either causing a
massive performance hit, or can potentially lead the server to crash.
This issue is particularly noticable on paper due to the cumulative efforts
to drastically improve chunk loading speeds which means that there is much more
of a chance that we're about to eat a dirtload of chunk load callbacks, thus
making this issue much more of an issue
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
index 07dfe575dea0f41a75bb9dad0ee2d541e983f6d7..f194dbf29fefab6c94fe5aa11f565349499f4706 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
@@ -127,46 +127,6 @@ public class CraftChunk implements Chunk {
this.getWorld().getChunkAt(x, z); // Transient load for this tick
}
- PersistentEntitySectionManager<net.minecraft.world.entity.Entity> entityManager = this.getCraftWorld().getHandle().entityManager;
- long pair = ChunkPos.asLong(x, z);
-
- if (entityManager.areEntitiesLoaded(pair)) { // PAIL rename isEntitiesLoaded
- return getCraftWorld().getHandle().getChunkEntities(this.x, this.z); // Paper - optimise this
- }
-
- entityManager.ensureChunkQueuedForLoad(pair); // Start entity loading
-
- // SPIGOT-6772: Use entity mailbox and re-schedule entities if they get unloaded
- ProcessorMailbox<Runnable> mailbox = ((EntityStorage) entityManager.permanentStorage).entityDeserializerQueue;
- BooleanSupplier supplier = () -> {
- // only execute inbox if our entities are not present
- if (entityManager.areEntitiesLoaded(pair)) {
- return true;
- }
-
- if (!entityManager.isPending(pair)) {
- // Our entities got unloaded, this should normally not happen.
- entityManager.ensureChunkQueuedForLoad(pair); // Re-start entity loading
- }
-
- // tick loading inbox, which loads the created entities to the world
- // (if present)
- entityManager.tick();
- // check if our entities are loaded
- return entityManager.areEntitiesLoaded(pair);
- };
-
- // now we wait until the entities are loaded,
- // the converting from NBT to entity object is done on the main Thread which is why we wait
- while (!supplier.getAsBoolean()) {
- if (mailbox.size() != 0) { // PAIL rename size
- mailbox.run();
- } else {
- Thread.yield();
- LockSupport.parkNanos("waiting for entity loading", 100000L);
- }
- }
-
return getCraftWorld().getHandle().getChunkEntities(this.x, this.z); // Paper - optimise this
}

View file

@ -1,23 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Noah van der Aa <ndvdaa@gmail.com>
Date: Mon, 30 Aug 2021 15:22:18 +0200
Subject: [PATCH] Prevent softlocked end exit portal generation
diff --git a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java
index dec99c9d40705a89c395437d0d050f3ab36bc17b..44551fc6fc5888206c1a2da3ece5baa486faa1d5 100644
--- a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java
+++ b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java
@@ -409,6 +409,12 @@ public class EndDragonFight {
}
}
+ // Paper start - Prevent "softlocked" exit portal generation
+ if (this.portalLocation.getY() <= this.level.getMinBuildHeight()) {
+ this.portalLocation = this.portalLocation.atY(this.level.getMinBuildHeight() + 1);
+ }
+ // Paper end
+
endPodiumFeature.configured(FeatureConfiguration.NONE).place(this.level, this.level.getChunkSource().getGenerator(), new Random(), this.portalLocation);
}

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Tue, 7 Sep 2021 21:29:38 +0100
Subject: [PATCH] Fix CocaoDecorator causing a crash when trying to generate
without logs
diff --git a/src/main/java/net/minecraft/world/level/levelgen/feature/treedecorators/CocoaDecorator.java b/src/main/java/net/minecraft/world/level/levelgen/feature/treedecorators/CocoaDecorator.java
index c1d220726ca0877fb526e710ae07329b4705a8e5..4474586d199a12f1311ee3ad307b342f4be3690e 100644
--- a/src/main/java/net/minecraft/world/level/levelgen/feature/treedecorators/CocoaDecorator.java
+++ b/src/main/java/net/minecraft/world/level/levelgen/feature/treedecorators/CocoaDecorator.java
@@ -29,6 +29,7 @@ public class CocoaDecorator extends TreeDecorator {
@Override
public void place(LevelSimulatedReader world, BiConsumer<BlockPos, BlockState> replacer, Random random, List<BlockPos> logPositions, List<BlockPos> leavesPositions) {
+ if (logPositions.isEmpty()) return; // Paper
if (!(random.nextFloat() >= this.probability)) {
int i = logPositions.get(0).getY();
logPositions.stream().filter((pos) -> {

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Noah van der Aa <ndvdaa@gmail.com>
Date: Tue, 14 Sep 2021 16:24:45 +0200
Subject: [PATCH] Don't log debug logging being disabled
diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java
index ba0e8902e7205bc6da88efd28be70ece04cc1974..ec7938202e3890bccb809a8092362458d0f4ca75 100644
--- a/src/main/java/org/spigotmc/SpigotConfig.java
+++ b/src/main/java/org/spigotmc/SpigotConfig.java
@@ -382,7 +382,7 @@ public class SpigotConfig
Bukkit.getLogger().info( "Debug logging is enabled" );
} else
{
- Bukkit.getLogger().info( "Debug logging is disabled" );
+ // Bukkit.getLogger().info( "Debug logging is disabled" ); // Paper - Don't log if debug logging isn't enabled.
}
}

View file

@ -1,32 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Fri, 13 Aug 2021 16:38:08 -0700
Subject: [PATCH] Mark fish and axolotls from buckets as persistent
diff --git a/src/main/java/net/minecraft/world/entity/animal/AbstractFish.java b/src/main/java/net/minecraft/world/entity/animal/AbstractFish.java
index fc0cd86397b12e42756273a0317164d79ac51937..0701adf77a04a82df4fe1dceee196fee5d820961 100644
--- a/src/main/java/net/minecraft/world/entity/animal/AbstractFish.java
+++ b/src/main/java/net/minecraft/world/entity/animal/AbstractFish.java
@@ -90,7 +90,7 @@ public abstract class AbstractFish extends WaterAnimal implements Bucketable {
@Override
public void setFromBucket(boolean fromBucket) {
this.entityData.set(AbstractFish.FROM_BUCKET, fromBucket);
- this.setPersistenceRequired(this.isPersistenceRequired()); // CraftBukkit - SPIGOT-4106 update persistence
+ this.setPersistenceRequired(fromBucket || this.isPersistenceRequired()); // CraftBukkit - SPIGOT-4106 update persistence // Paper - actually set as persistent
}
@Override
diff --git a/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java b/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java
index f75333190f8b824e0b52ad2d74739f420644f469..2b8725087fd3bfeca7162bda2783fdacd13a8390 100644
--- a/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java
+++ b/src/main/java/net/minecraft/world/entity/animal/axolotl/Axolotl.java
@@ -236,7 +236,7 @@ public class Axolotl extends Animal implements LerpingModel, Bucketable {
@Override
public void setFromBucket(boolean fromBucket) {
this.entityData.set(Axolotl.FROM_BUCKET, fromBucket);
- this.setPersistenceRequired(this.isPersistenceRequired()); // CraftBukkit - SPIGOT-4106 update persistence
+ this.setPersistenceRequired(fromBucket || this.isPersistenceRequired()); // CraftBukkit - SPIGOT-4106 update persistence // Paper - actually set as persistent
}
@Nullable

View file

@ -1,23 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sun, 11 Jul 2021 12:52:56 -0700
Subject: [PATCH] fix various menus with empty level accesses
diff --git a/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java b/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java
index c96b04f045dda384cdee9254a1765ef97e5f7f03..f00a957a0f55e69f93e6d7dc80193304447c3dcb 100644
--- a/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java
+++ b/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java
@@ -27,6 +27,12 @@ public interface ContainerLevelAccess {
public <T> Optional<T> evaluate(BiFunction<Level, BlockPos, T> getter) {
return Optional.empty();
}
+ // Paper start
+ @Override
+ public org.bukkit.Location getLocation() {
+ return null;
+ }
+ // Paper end
};
static ContainerLevelAccess create(final Level world, final BlockPos pos) {

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nassim Jahnke <jahnke.nassim@gmail.com>
Date: Tue, 28 Sep 2021 09:47:47 +0200
Subject: [PATCH] Ensure valid vehicle status
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 4dfd185e47849c18c552e28370d93b48799d2eb9..11f46c1b8f4c8414e0667d1873542c17d6e01f2a 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -509,7 +509,7 @@ public class ServerPlayer extends Player {
}
}
- if (persistVehicle && entity1 != null && entity != this && entity.hasExactlyOnePlayerPassenger()) {
+ if (persistVehicle && entity1 != null && entity != this && entity.hasExactlyOnePlayerPassenger() && !entity.isRemoved()) { // Paper
// CraftBukkit end
CompoundTag nbttagcompound2 = new CompoundTag();
CompoundTag nbttagcompound3 = new CompoundTag();

View file

@ -1,72 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: lexikiq <noellekiq@gmail.com>
Date: Mon, 21 Jun 2021 23:21:58 -0400
Subject: [PATCH] Preserve overstacked loot
Preserves overstacked items in loot tables, such as shulker box drops, to prevent the items
from being deleted (as they'd overflow past the bounds of the container)-- or worse, causing
chunk bans via the large amount of NBT created by unstacking the items.
Fixes GH-5140 and GH-4748.
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index f1b1e0455806443cd55c350f9b4f74ef8f3a1158..00e302a278c1aef17596a5f1b91230614b13ceb2 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -935,6 +935,11 @@ public class PaperWorldConfig {
allowPlayerCrammingDamage = getBoolean("allow-player-cramming-damage", allowPlayerCrammingDamage);
}
+ public boolean splitOverstackedLoot = true;
+ private void splitOverstackedLoot() {
+ splitOverstackedLoot = getBoolean("split-overstacked-loot", splitOverstackedLoot);
+ }
+
private Table<String, String, Integer> sensorTickRates;
private Table<String, String, Integer> behaviorTickRates;
private void tickRates() {
diff --git a/src/main/java/net/minecraft/world/level/storage/loot/LootTable.java b/src/main/java/net/minecraft/world/level/storage/loot/LootTable.java
index db80db9d6382dd4748aa8f27dd3c3d3ae9fe9380..9827229d125addcfec8b0025724b9a4570c40a12 100644
--- a/src/main/java/net/minecraft/world/level/storage/loot/LootTable.java
+++ b/src/main/java/net/minecraft/world/level/storage/loot/LootTable.java
@@ -54,9 +54,17 @@ public class LootTable {
this.compositeFunction = LootItemFunctions.compose(functions);
}
+ @Deprecated // Paper - preserve overstacked items
public static Consumer<ItemStack> createStackSplitter(Consumer<ItemStack> lootConsumer) {
+ // Paper start - preserve overstacked items
+ return createStackSplitter(lootConsumer, null);
+ }
+
+ public static Consumer<ItemStack> createStackSplitter(Consumer<ItemStack> lootConsumer, @org.jetbrains.annotations.Nullable net.minecraft.server.level.ServerLevel world) {
+ boolean skipSplitter = world != null && !world.paperConfig.splitOverstackedLoot;
+ // Paper end
return (itemstack) -> {
- if (itemstack.getCount() < itemstack.getMaxStackSize()) {
+ if (skipSplitter || itemstack.getCount() < itemstack.getMaxStackSize()) { // Paper - preserve overstacked items
lootConsumer.accept(itemstack);
} else {
int i = itemstack.getCount();
@@ -93,7 +101,7 @@ public class LootTable {
}
public void getRandomItems(LootContext context, Consumer<ItemStack> lootConsumer) {
- this.getRandomItemsRaw(context, LootTable.createStackSplitter(lootConsumer));
+ this.getRandomItemsRaw(context, LootTable.createStackSplitter(lootConsumer, context.getLevel())); // Paper - preserve overstacked items
}
public List<ItemStack> getRandomItems(LootContext context) {
diff --git a/src/main/java/net/minecraft/world/level/storage/loot/functions/SetContainerContents.java b/src/main/java/net/minecraft/world/level/storage/loot/functions/SetContainerContents.java
index 6d63c5318e1711a27b254db950ae7576d333ad47..6b5e481980751ed83cda7badc160b738d5c56af9 100644
--- a/src/main/java/net/minecraft/world/level/storage/loot/functions/SetContainerContents.java
+++ b/src/main/java/net/minecraft/world/level/storage/loot/functions/SetContainerContents.java
@@ -39,7 +39,7 @@ public class SetContainerContents extends LootItemConditionalFunction {
NonNullList<ItemStack> nonNullList = NonNullList.create();
this.entries.forEach((entry) -> {
entry.expand(context, (choice) -> {
- choice.createItemStack(LootTable.createStackSplitter(nonNullList::add), context);
+ choice.createItemStack(LootTable.createStackSplitter(nonNullList::add, context.getLevel()), context); // Paper - preserve overstacked items
});
});
CompoundTag compoundTag = new CompoundTag();

View file

@ -1,29 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Mon, 21 Jun 2021 21:55:23 -0400
Subject: [PATCH] Update head rotation in missing places
In certain areas the player's head rotation could be desynced when teleported/moved.
This is because bukkit uses a separate head rotation field for yaw.
This issue only applies to players.
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 94857a736d2a16e8ade286c6f2ddf8bd798008eb..4f164f238177b5e2b18c76b7cc14596ec93409d1 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -1742,6 +1742,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
this.setXRot(Mth.clamp(pitch, -90.0F, 90.0F) % 360.0F);
this.yRotO = this.getYRot();
this.xRotO = this.getXRot();
+ this.setYHeadRot(yaw); // Paper - Update head rotation
}
public void absMoveTo(double x, double y, double z) {
@@ -1780,6 +1781,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
this.setXRot(pitch);
this.setOldPosAndRot();
this.reapplyPosition();
+ this.setYHeadRot(yaw); // Paper - Update head rotation
}
public final void setOldPosAndRot() {

View file

@ -1,18 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Mon, 13 Sep 2021 18:55:45 -0700
Subject: [PATCH] prevent unintended light block manipulation
diff --git a/src/main/java/net/minecraft/world/level/block/LightBlock.java b/src/main/java/net/minecraft/world/level/block/LightBlock.java
index 7f4acaab7e77f5184c8f8a30ed13b34949780227..59faf48727cfbccacdd5ffa067758466a240e90a 100644
--- a/src/main/java/net/minecraft/world/level/block/LightBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/LightBlock.java
@@ -46,6 +46,7 @@ public class LightBlock extends Block implements SimpleWaterloggedBlock {
@Override
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
if (!world.isClientSide) {
+ if (player.getItemInHand(hand).getItem() != Items.LIGHT || !player.mayInteract(world, pos) || !player.mayUseItemAt(pos, hit.getDirection(), player.getItemInHand(hand))) { return InteractionResult.FAIL; } // Paper
world.setBlock(pos, state.cycle(LEVEL), 2);
return InteractionResult.SUCCESS;
} else {

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Fri, 20 Aug 2021 18:36:02 -0700
Subject: [PATCH] Dont count named piglins and hoglins towards mob cap
diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
index 0b228b8bcae5ed2840ab244b6de35732f737504d..f316585ccf6baf5e7e514ba3a68b4344e781a82d 100644
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
@@ -83,7 +83,7 @@ public final class NaturalSpawner {
Mob entityinsentient = (Mob) entity;
// CraftBukkit - Split out persistent check, don't apply it to special persistent mobs
- if (entityinsentient.removeWhenFarAway(0) && entityinsentient.isPersistenceRequired()) {
+ if ((entityinsentient instanceof net.minecraft.world.entity.monster.piglin.Piglin || entityinsentient instanceof net.minecraft.world.entity.monster.hoglin.Hoglin || entityinsentient.removeWhenFarAway(0)) && entityinsentient.isPersistenceRequired()) { // Paper - what a jank fix, CBs like totally tried to change what removeWhenFarAway does, that method isnt even called here in vanilla, idk wtf is going on
continue;
}
}

View file

@ -1,32 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Mon, 4 Oct 2021 22:31:51 -0700
Subject: [PATCH] Fix CraftCriteria defaults map
diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java
index 22801e33fa15322c37cd11d73a40a43fa721a8e4..0cd63772871311fc0cb7111657cc9a9dac106167 100644
--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java
@@ -37,7 +37,7 @@ final class CraftCriteria {
}
static CraftCriteria getFromNMS(Objective objective) {
- return CraftCriteria.DEFAULTS.get(objective.getCriteria().getName());
+ return java.util.Objects.requireNonNullElseGet(CraftCriteria.DEFAULTS.get(objective.getCriteria().getName()), () -> new CraftCriteria(objective.getCriteria())); // Paper
}
static CraftCriteria getFromBukkit(String name) {
@@ -45,6 +45,12 @@ final class CraftCriteria {
if (criteria != null) {
return criteria;
}
+ // Paper start - fix criteria defaults
+ var nmsCriteria = ObjectiveCriteria.byName(name);
+ if (nmsCriteria.isPresent()) {
+ return new CraftCriteria(nmsCriteria.get());
+ }
+ // Paper end
return new CraftCriteria(name);
}

View file

@ -1,349 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Wed, 6 Oct 2021 20:50:48 -0700
Subject: [PATCH] Fix upstreams block state factories
Sometimes, blocks are changed and then logic is called before the associated
tile entity is removed. When this happens, the factories were relying on the
block at the position, not the tile entity. This change prioritizes using the
tile entity type to determine the block state factory and falls back on
the material type of the block at that location.
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
index 38c4dac82793930777eaf0189c5534234a9162ed..9b4a464fe820effa906af486cf71a74e283ccd4e 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
@@ -232,7 +232,7 @@ public abstract class BlockEntity implements net.minecraft.server.KeyedObject {
// Paper end
if (this.level == null) return null;
org.bukkit.block.Block block = this.level.getWorld().getBlockAt(this.worldPosition.getX(), this.worldPosition.getY(), this.worldPosition.getZ());
- if (block.getType() == org.bukkit.Material.AIR) return null;
+ // if (block.getType() == org.bukkit.Material.AIR) return null; // Paper - actually get the tile entity if it still exists
org.bukkit.block.BlockState state = block.getState(useSnapshot); // Paper
if (state instanceof InventoryHolder) return (InventoryHolder) state;
return null;
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java
index b794e04036df00dd9633b9bd808591f499238387..0356c33bc14bef73a7468d5360ea5cd309d5f623 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java
@@ -19,6 +19,7 @@ import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
import net.minecraft.world.level.block.entity.BellBlockEntity;
import net.minecraft.world.level.block.entity.BlastFurnaceBlockEntity;
import net.minecraft.world.level.block.entity.BlockEntity;
+import net.minecraft.world.level.block.entity.BlockEntityType; // Paper
import net.minecraft.world.level.block.entity.BrewingStandBlockEntity;
import net.minecraft.world.level.block.entity.CampfireBlockEntity;
import net.minecraft.world.level.block.entity.ChestBlockEntity;
@@ -106,183 +107,54 @@ public final class CraftBlockStates {
@Override
public CraftBlockState createBlockState(World world, BlockPos blockPosition, net.minecraft.world.level.block.state.BlockState blockData, BlockEntity tileEntity) {
// When a block is being destroyed, the TileEntity may temporarily still exist while the block's type has already been set to AIR. We ignore the TileEntity in this case.
- Preconditions.checkState(tileEntity == null || CraftMagicNumbers.getMaterial(blockData.getBlock()) == Material.AIR, "Unexpected BlockState for %s", CraftMagicNumbers.getMaterial(blockData.getBlock()));
+ Preconditions.checkState(tileEntity == null/* || CraftMagicNumbers.getMaterial(blockData.getBlock()) == Material.AIR*/, "Unexpected BlockState for %s", CraftMagicNumbers.getMaterial(blockData.getBlock())); // Paper - don't ignore the TileEntity while its still valid
return new CraftBlockState(world, blockPosition, blockData);
}
};
+ // Paper start
+ private static final Map<BlockEntityType<?>, BlockStateFactory<?>> FACTORIES_BY_BLOCK_ENTITY_TYPE = new HashMap<>();
+ private static void register(BlockEntityType<?> type, BlockStateFactory<?> factory) {
+ FACTORIES_BY_BLOCK_ENTITY_TYPE.put(type, factory);
+ }
+ // Paper end
static {
- register(
- Arrays.asList(
- Material.ACACIA_SIGN,
- Material.ACACIA_WALL_SIGN,
- Material.BIRCH_SIGN,
- Material.BIRCH_WALL_SIGN,
- Material.CRIMSON_SIGN,
- Material.CRIMSON_WALL_SIGN,
- Material.DARK_OAK_SIGN,
- Material.DARK_OAK_WALL_SIGN,
- Material.JUNGLE_SIGN,
- Material.JUNGLE_WALL_SIGN,
- Material.OAK_SIGN,
- Material.OAK_WALL_SIGN,
- Material.SPRUCE_SIGN,
- Material.SPRUCE_WALL_SIGN,
- Material.WARPED_SIGN,
- Material.WARPED_WALL_SIGN
- ), CraftSign.class, CraftSign::new, SignBlockEntity::new
- );
-
- register(
- Arrays.asList(
- Material.CREEPER_HEAD,
- Material.CREEPER_WALL_HEAD,
- Material.DRAGON_HEAD,
- Material.DRAGON_WALL_HEAD,
- Material.PLAYER_HEAD,
- Material.PLAYER_WALL_HEAD,
- Material.SKELETON_SKULL,
- Material.SKELETON_WALL_SKULL,
- Material.WITHER_SKELETON_SKULL,
- Material.WITHER_SKELETON_WALL_SKULL,
- Material.ZOMBIE_HEAD,
- Material.ZOMBIE_WALL_HEAD
- ), CraftSkull.class, CraftSkull::new, SkullBlockEntity::new
- );
-
- register(
- Arrays.asList(
- Material.COMMAND_BLOCK,
- Material.REPEATING_COMMAND_BLOCK,
- Material.CHAIN_COMMAND_BLOCK
- ), CraftCommandBlock.class, CraftCommandBlock::new, CommandBlockEntity::new
- );
-
- register(
- Arrays.asList(
- Material.BLACK_BANNER,
- Material.BLACK_WALL_BANNER,
- Material.BLUE_BANNER,
- Material.BLUE_WALL_BANNER,
- Material.BROWN_BANNER,
- Material.BROWN_WALL_BANNER,
- Material.CYAN_BANNER,
- Material.CYAN_WALL_BANNER,
- Material.GRAY_BANNER,
- Material.GRAY_WALL_BANNER,
- Material.GREEN_BANNER,
- Material.GREEN_WALL_BANNER,
- Material.LIGHT_BLUE_BANNER,
- Material.LIGHT_BLUE_WALL_BANNER,
- Material.LIGHT_GRAY_BANNER,
- Material.LIGHT_GRAY_WALL_BANNER,
- Material.LIME_BANNER,
- Material.LIME_WALL_BANNER,
- Material.MAGENTA_BANNER,
- Material.MAGENTA_WALL_BANNER,
- Material.ORANGE_BANNER,
- Material.ORANGE_WALL_BANNER,
- Material.PINK_BANNER,
- Material.PINK_WALL_BANNER,
- Material.PURPLE_BANNER,
- Material.PURPLE_WALL_BANNER,
- Material.RED_BANNER,
- Material.RED_WALL_BANNER,
- Material.WHITE_BANNER,
- Material.WHITE_WALL_BANNER,
- Material.YELLOW_BANNER,
- Material.YELLOW_WALL_BANNER
- ), CraftBanner.class, CraftBanner::new, BannerBlockEntity::new
- );
-
- register(
- Arrays.asList(
- Material.SHULKER_BOX,
- Material.WHITE_SHULKER_BOX,
- Material.ORANGE_SHULKER_BOX,
- Material.MAGENTA_SHULKER_BOX,
- Material.LIGHT_BLUE_SHULKER_BOX,
- Material.YELLOW_SHULKER_BOX,
- Material.LIME_SHULKER_BOX,
- Material.PINK_SHULKER_BOX,
- Material.GRAY_SHULKER_BOX,
- Material.LIGHT_GRAY_SHULKER_BOX,
- Material.CYAN_SHULKER_BOX,
- Material.PURPLE_SHULKER_BOX,
- Material.BLUE_SHULKER_BOX,
- Material.BROWN_SHULKER_BOX,
- Material.GREEN_SHULKER_BOX,
- Material.RED_SHULKER_BOX,
- Material.BLACK_SHULKER_BOX
- ), CraftShulkerBox.class, CraftShulkerBox::new, ShulkerBoxBlockEntity::new
- );
-
- register(
- Arrays.asList(
- Material.BLACK_BED,
- Material.BLUE_BED,
- Material.BROWN_BED,
- Material.CYAN_BED,
- Material.GRAY_BED,
- Material.GREEN_BED,
- Material.LIGHT_BLUE_BED,
- Material.LIGHT_GRAY_BED,
- Material.LIME_BED,
- Material.MAGENTA_BED,
- Material.ORANGE_BED,
- Material.PINK_BED,
- Material.PURPLE_BED,
- Material.RED_BED,
- Material.WHITE_BED,
- Material.YELLOW_BED
- ), CraftBed.class, CraftBed::new, BedBlockEntity::new
- );
-
- register(
- Arrays.asList(
- Material.BEEHIVE,
- Material.BEE_NEST
- ), CraftBeehive.class, CraftBeehive::new, BeehiveBlockEntity::new
- );
-
- register(
- Arrays.asList(
- Material.CAMPFIRE,
- Material.SOUL_CAMPFIRE
- ), CraftCampfire.class, CraftCampfire::new, CampfireBlockEntity::new
- );
-
- register(
- Arrays.asList(
- Material.CHEST,
- Material.TRAPPED_CHEST
- ), CraftChest.class, CraftChest::new, ChestBlockEntity::new
- );
-
- register(Material.BARREL, CraftBarrel.class, CraftBarrel::new, BarrelBlockEntity::new);
- register(Material.BEACON, CraftBeacon.class, CraftBeacon::new, BeaconBlockEntity::new);
- register(Material.BELL, CraftBell.class, CraftBell::new, BellBlockEntity::new);
- register(Material.BLAST_FURNACE, CraftBlastFurnace.class, CraftBlastFurnace::new, BlastFurnaceBlockEntity::new);
- register(Material.BREWING_STAND, CraftBrewingStand.class, CraftBrewingStand::new, BrewingStandBlockEntity::new);
- register(Material.COMPARATOR, CraftComparator.class, CraftComparator::new, ComparatorBlockEntity::new);
- register(Material.CONDUIT, CraftConduit.class, CraftConduit::new, ConduitBlockEntity::new);
- register(Material.DAYLIGHT_DETECTOR, CraftDaylightDetector.class, CraftDaylightDetector::new, DaylightDetectorBlockEntity::new);
- register(Material.DISPENSER, CraftDispenser.class, CraftDispenser::new, DispenserBlockEntity::new);
- register(Material.DROPPER, CraftDropper.class, CraftDropper::new, DropperBlockEntity::new);
- register(Material.ENCHANTING_TABLE, CraftEnchantingTable.class, CraftEnchantingTable::new, EnchantmentTableBlockEntity::new);
- register(Material.ENDER_CHEST, CraftEnderChest.class, CraftEnderChest::new, EnderChestBlockEntity::new);
- register(Material.END_GATEWAY, CraftEndGateway.class, CraftEndGateway::new, TheEndGatewayBlockEntity::new);
- register(Material.END_PORTAL, CraftEndPortal.class, CraftEndPortal::new, TheEndPortalBlockEntity::new);
- register(Material.FURNACE, CraftFurnaceFurnace.class, CraftFurnaceFurnace::new, FurnaceBlockEntity::new);
- register(Material.HOPPER, CraftHopper.class, CraftHopper::new, HopperBlockEntity::new);
- register(Material.JIGSAW, CraftJigsaw.class, CraftJigsaw::new, JigsawBlockEntity::new);
- register(Material.JUKEBOX, CraftJukebox.class, CraftJukebox::new, JukeboxBlockEntity::new);
- register(Material.LECTERN, CraftLectern.class, CraftLectern::new, LecternBlockEntity::new);
- register(Material.MOVING_PISTON, CraftMovingPiston.class, CraftMovingPiston::new, PistonMovingBlockEntity::new);
- register(Material.SCULK_SENSOR, CraftSculkSensor.class, CraftSculkSensor::new, SculkSensorBlockEntity::new);
- register(Material.SMOKER, CraftSmoker.class, CraftSmoker::new, SmokerBlockEntity::new);
- register(Material.SPAWNER, CraftCreatureSpawner.class, CraftCreatureSpawner::new, SpawnerBlockEntity::new);
- register(Material.STRUCTURE_BLOCK, CraftStructureBlock.class, CraftStructureBlock::new, StructureBlockEntity::new);
+ // Paper start - simplify
+ register(BlockEntityType.SIGN, CraftSign.class, CraftSign::new);
+ register(BlockEntityType.SKULL, CraftSkull.class, CraftSkull::new);
+ register(BlockEntityType.COMMAND_BLOCK, CraftCommandBlock.class, CraftCommandBlock::new);
+ register(BlockEntityType.BANNER, CraftBanner.class, CraftBanner::new);
+ register(BlockEntityType.SHULKER_BOX, CraftShulkerBox.class, CraftShulkerBox::new);
+ register(BlockEntityType.BED, CraftBed.class, CraftBed::new);
+ register(BlockEntityType.BEEHIVE, CraftBeehive.class, CraftBeehive::new);
+ register(BlockEntityType.CAMPFIRE, CraftCampfire.class, CraftCampfire::new);
+ register(BlockEntityType.CHEST, CraftChest.class, CraftChest::new); // Paper - split up chests due to different block entity types
+ register(BlockEntityType.TRAPPED_CHEST, CraftChest.class, CraftChest::new); // Paper - split up chests due to different block entity types
+ register(BlockEntityType.BARREL, CraftBarrel.class, CraftBarrel::new);
+ register(BlockEntityType.BEACON, CraftBeacon.class, CraftBeacon::new);
+ register(BlockEntityType.BELL, CraftBell.class, CraftBell::new);
+ register(BlockEntityType.BLAST_FURNACE, CraftBlastFurnace.class, CraftBlastFurnace::new);
+ register(BlockEntityType.BREWING_STAND, CraftBrewingStand.class, CraftBrewingStand::new);
+ register(BlockEntityType.COMPARATOR, CraftComparator.class, CraftComparator::new);
+ register(BlockEntityType.CONDUIT, CraftConduit.class, CraftConduit::new);
+ register(BlockEntityType.DAYLIGHT_DETECTOR, CraftDaylightDetector.class, CraftDaylightDetector::new);
+ register(BlockEntityType.DISPENSER, CraftDispenser.class, CraftDispenser::new);
+ register(BlockEntityType.DROPPER, CraftDropper.class, CraftDropper::new);
+ register(BlockEntityType.ENCHANTING_TABLE, CraftEnchantingTable.class, CraftEnchantingTable::new);
+ register(BlockEntityType.ENDER_CHEST, CraftEnderChest.class, CraftEnderChest::new);
+ register(BlockEntityType.END_GATEWAY, CraftEndGateway.class, CraftEndGateway::new);
+ register(BlockEntityType.END_PORTAL, CraftEndPortal.class, CraftEndPortal::new);
+ register(BlockEntityType.FURNACE, CraftFurnaceFurnace.class, CraftFurnaceFurnace::new);
+ register(BlockEntityType.HOPPER, CraftHopper.class, CraftHopper::new);
+ register(BlockEntityType.JIGSAW, CraftJigsaw.class, CraftJigsaw::new);
+ register(BlockEntityType.JUKEBOX, CraftJukebox.class, CraftJukebox::new);
+ register(BlockEntityType.LECTERN, CraftLectern.class, CraftLectern::new);
+ register(BlockEntityType.PISTON, CraftMovingPiston.class, CraftMovingPiston::new);
+ register(BlockEntityType.SCULK_SENSOR, CraftSculkSensor.class, CraftSculkSensor::new);
+ register(BlockEntityType.SMOKER, CraftSmoker.class, CraftSmoker::new);
+ register(BlockEntityType.MOB_SPAWNER, CraftCreatureSpawner.class, CraftCreatureSpawner::new);
+ register(BlockEntityType.STRUCTURE_BLOCK, CraftStructureBlock.class, CraftStructureBlock::new);
+ // Paper end
}
private static void register(Material blockType, BlockStateFactory<?> factory) {
@@ -290,35 +162,45 @@ public final class CraftBlockStates {
}
private static <T extends BlockEntity, B extends CraftBlockEntityState<T>> void register(
- Material blockType,
+ net.minecraft.world.level.block.entity.BlockEntityType<? extends T> blockEntityType, // Paper
Class<B> blockStateType,
- BiFunction<World, T, B> blockStateConstructor,
- BiFunction<BlockPos, net.minecraft.world.level.block.state.BlockState, T> tileEntityConstructor
+ BiFunction<World, T, B> blockStateConstructor // Paper
) {
- CraftBlockStates.register(Collections.singletonList(blockType), blockStateType, blockStateConstructor, tileEntityConstructor);
- }
-
- private static <T extends BlockEntity, B extends CraftBlockEntityState<T>> void register(
- List<Material> blockTypes,
- Class<B> blockStateType,
- BiFunction<World, T, B> blockStateConstructor,
- BiFunction<BlockPos, net.minecraft.world.level.block.state.BlockState, T> tileEntityConstructor
- ) {
- BlockStateFactory<B> factory = new BlockEntityStateFactory<>(blockStateType, blockStateConstructor, tileEntityConstructor);
- for (Material blockType : blockTypes) {
- CraftBlockStates.register(blockType, factory);
+ // Paper start
+ BlockStateFactory<B> factory = new BlockEntityStateFactory<>(blockStateType, blockStateConstructor, blockEntityType::create);
+ for (net.minecraft.world.level.block.Block block : blockEntityType.validBlocks) {
+ CraftBlockStates.register(CraftMagicNumbers.getMaterial(block), factory);
}
+ CraftBlockStates.register(blockEntityType, factory);
+ // Paper end
}
private static BlockStateFactory<?> getFactory(Material material) {
return CraftBlockStates.FACTORIES.getOrDefault(material, DEFAULT_FACTORY);
}
+ // Paper start
+ private static BlockStateFactory<?> getFactory(Material material, BlockEntityType<?> type) {
+ if (type != null) {
+ return CraftBlockStates.FACTORIES_BY_BLOCK_ENTITY_TYPE.getOrDefault(type, getFactory(material));
+ } else {
+ return getFactory(material);
+ }
+ }
+ // Paper end
+
public static Class<? extends CraftBlockState> getBlockStateType(Material material) {
Preconditions.checkNotNull(material, "material is null");
return CraftBlockStates.getFactory(material).blockStateType;
}
+ // Paper start
+ public static Class<? extends CraftBlockState> getBlockStateType(BlockEntityType<?> blockEntityType) {
+ Preconditions.checkNotNull(blockEntityType, "blockEntityType is null");
+ return CraftBlockStates.getFactory(null, blockEntityType).blockStateType;
+ }
+ // Paper end
+
public static BlockState getBlockState(Block block) {
Preconditions.checkNotNull(block, "block is null");
CraftBlock craftBlock = (CraftBlock) block;
@@ -361,7 +243,7 @@ public final class CraftBlockStates {
if (world != null && tileEntity == null && CraftBlockStates.isTileEntityOptional(material)) {
factory = CraftBlockStates.DEFAULT_FACTORY;
} else {
- factory = CraftBlockStates.getFactory(material);
+ factory = CraftBlockStates.getFactory(material, tileEntity != null ? tileEntity.getType() : null); // Paper
}
return factory.createBlockState(world, blockPosition, blockData, tileEntity);
}
diff --git a/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java b/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java
index 738227d8dbab8460d2bd7f75098e91bcae2d1ff3..8980163dabdd21d040bc7e622e9a22d01f73005b 100644
--- a/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java
+++ b/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java
@@ -26,4 +26,11 @@ public class BlockStateTest extends AbstractTestingBase {
}
}
}
+
+ @Test
+ public void testBlockEntityTypes() {
+ for (var blockEntityType : Registry.BLOCK_ENTITY_TYPE) {
+ org.junit.Assert.assertNotNull(CraftBlockStates.getBlockStateType(blockEntityType));
+ }
+ }
}

View file

@ -1,104 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Noah van der Aa <ndvdaa@gmail.com>
Date: Tue, 5 Oct 2021 20:04:21 +0200
Subject: [PATCH] Add config option for logging player ip addresses
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
index b3f4ac2ce6f515e406d2f31b1d2429729c9e2b60..0277627e97b51e20470ccf578cee48470e06a34b 100644
--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
@@ -489,6 +489,11 @@ public class PaperConfig {
}
}
+ public static boolean logPlayerIpAddresses = true;
+ private static void playerIpAddresses() {
+ logPlayerIpAddresses = getBoolean("settings.log-player-ip-addresses", logPlayerIpAddresses);
+ }
+
public static int maxJoinsPerTick;
private static void maxJoinsPerTick() {
maxJoinsPerTick = getInt("settings.max-joins-per-tick", 3);
diff --git a/src/main/java/net/minecraft/network/protocol/PacketUtils.java b/src/main/java/net/minecraft/network/protocol/PacketUtils.java
index acc12307f61e1e055896b68fe16654c9c4a606a0..c958a00535c0f7a015a7a566b97e2c80fc9a0efd 100644
--- a/src/main/java/net/minecraft/network/protocol/PacketUtils.java
+++ b/src/main/java/net/minecraft/network/protocol/PacketUtils.java
@@ -58,10 +58,11 @@ public class PacketUtils {
// Paper start
catch (Exception e) {
Connection networkmanager = listener.getConnection();
+ String playerIP = com.destroystokyo.paper.PaperConfig.logPlayerIpAddresses ? String.valueOf(networkmanager.getRemoteAddress()) : "<ip address withheld>"; // Paper
if (networkmanager.getPlayer() != null) {
- LOGGER.error("Error whilst processing packet {} for {}[{}]", packet, networkmanager.getPlayer().getScoreboardName(), networkmanager.getRemoteAddress(), e);
+ LOGGER.error("Error whilst processing packet {} for {}[{}]", packet, networkmanager.getPlayer().getScoreboardName(), playerIP, e); // Paper
} else {
- LOGGER.error("Error whilst processing packet {} for connection from {}", packet, networkmanager.getRemoteAddress(), e);
+ LOGGER.error("Error whilst processing packet {} for connection from {}", packet, playerIP, e); // Paper
}
TextComponent error = new TextComponent("Packet processing error");
networkmanager.send(new ClientboundDisconnectPacket(error), (future) -> {
diff --git a/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java b/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java
index 3962e82d4e4c5f792a37e825891e6960e737452d..dddc97094f0a7847b2818e6ea3b3f6cd4eb72b38 100644
--- a/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java
+++ b/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java
@@ -185,7 +185,7 @@ public class LegacyQueryHandler extends ChannelInboundHandlerAdapter {
buf.release();
this.buf = null;
- LOGGER.debug("Ping: (1.6) from {}", ctx.channel().remoteAddress());
+ LOGGER.debug("Ping: (1.6) from {}", com.destroystokyo.paper.PaperConfig.logPlayerIpAddresses ? ctx.channel().remoteAddress() : "<ip address withheld>"); // Paper
InetSocketAddress virtualHost = com.destroystokyo.paper.network.PaperNetworkClient.prepareVirtualHost(host, port);
com.destroystokyo.paper.event.server.PaperServerListPingEvent event = PaperLegacyStatusClient.processRequest(
diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
index a7046da8c097254907e01cd17f4107c8744f4a6e..43b085ee4c747a813ec5e2fa965c3369690789c5 100644
--- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
+++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
@@ -204,7 +204,7 @@ public class ServerConnectionListener {
throw new ReportedException(CrashReport.forThrowable(exception, "Ticking memory connection"));
}
- ServerConnectionListener.LOGGER.warn("Failed to handle packet for {}", networkmanager.getRemoteAddress(), exception);
+ ServerConnectionListener.LOGGER.warn("Failed to handle packet for {}", com.destroystokyo.paper.PaperConfig.logPlayerIpAddresses ? String.valueOf(networkmanager.getRemoteAddress()) : "<ip address withheld>", exception); // Paper
TextComponent chatcomponenttext = new TextComponent("Internal server error");
networkmanager.send(new ClientboundDisconnectPacket(chatcomponenttext), (future) -> {
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
index 01fee879c946b6640da34d5890d686f0152437dc..494ca8fa8c742d4eac9fb11878d3b3170d850265 100644
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
@@ -223,7 +223,10 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener
}
public String getUserName() {
- return this.gameProfile != null ? this.gameProfile + " (" + this.connection.getRemoteAddress() + ")" : String.valueOf(this.connection.getRemoteAddress());
+ // Paper start
+ String ip = com.destroystokyo.paper.PaperConfig.logPlayerIpAddresses ? String.valueOf(this.connection.getRemoteAddress()) : "<ip address withheld>";
+ return this.gameProfile != null ? this.gameProfile + " (" + ip + ")" : String.valueOf(ip);
+ // Paper end
}
@Override
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 99aa8f2ba2f10578f37de621d1a5a8e222cd70b1..eaa005c1c9b4386bcdbe1d6eb28c3eca7635066c 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -237,7 +237,7 @@ public abstract class PlayerList {
String s1 = "local";
if (connection.getRemoteAddress() != null) {
- s1 = connection.getRemoteAddress().toString();
+ s1 = com.destroystokyo.paper.PaperConfig.logPlayerIpAddresses ? connection.getRemoteAddress().toString() : "<ip address withheld>"; // Paper
}
// Spigot start - spawn location event
@@ -301,7 +301,7 @@ public abstract class PlayerList {
playerconnection.playerJoinReady = () -> {
postChunkLoadJoin(
player, finalWorldserver, connection, playerconnection,
- nbttagcompound, connection.getRemoteAddress().toString(), lastKnownName
+ nbttagcompound, com.destroystokyo.paper.PaperConfig.logPlayerIpAddresses ? connection.getRemoteAddress().toString() : "<ip address withheld>", lastKnownName // Paper
);
};
});

View file

@ -1,23 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Fri, 10 Sep 2021 15:49:12 -0700
Subject: [PATCH] VanillaCommandWrapper didnt account for entity senders
diff --git a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java
index e9d1fb479855194da5a05e86861848158736cbb4..4aa1dc543950b5de64345b3403a6d0bc41c521df 100644
--- a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java
+++ b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java
@@ -64,8 +64,10 @@ public final class VanillaCommandWrapper extends BukkitCommand {
}
public static CommandSourceStack getListener(CommandSender sender) {
- if (sender instanceof Player) {
- return ((CraftPlayer) sender).getHandle().createCommandSourceStack();
+ // Paper start - account for other entity command senders
+ if (sender instanceof org.bukkit.craftbukkit.entity.CraftEntity craftEntity) {
+ return craftEntity.getHandle().createCommandSourceStack();
+ // Paper end
}
if (sender instanceof BlockCommandSender) {
return ((CraftBlockCommandSender) sender).getWrapper();

View file

@ -1,79 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: egg82 <eggys82@gmail.com>
Date: Sat, 11 Sep 2021 22:55:14 +0200
Subject: [PATCH] Add root/admin user detection
This patch detects whether or not the server is currently executing as a privileged user and spits out a warning.
The warning serves as a sort-of PSA for newer server admins who don't understand the risks of running as root.
We've seen plenty of bad/malicious plugins hit markets, and there's been a few close-calls with exploits in the past.
Hopefully this helps mitigate some potential damage to servers, even if it is just a warning.
Co-authored-by: Noah van der Aa <ndvdaa@gmail.com>
diff --git a/src/main/java/io/papermc/paper/util/ServerEnvironment.java b/src/main/java/io/papermc/paper/util/ServerEnvironment.java
new file mode 100644
index 0000000000000000000000000000000000000000..6bd0afddbcc461149dfe9a5c7a86fff6ea13a5f1
--- /dev/null
+++ b/src/main/java/io/papermc/paper/util/ServerEnvironment.java
@@ -0,0 +1,40 @@
+package io.papermc.paper.util;
+
+import com.sun.security.auth.module.NTSystem;
+import com.sun.security.auth.module.UnixSystem;
+import org.apache.commons.lang.SystemUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Set;
+
+public class ServerEnvironment {
+ private static final boolean RUNNING_AS_ROOT_OR_ADMIN;
+ private static final String WINDOWS_HIGH_INTEGRITY_LEVEL = "S-1-16-12288";
+
+ static {
+ if (SystemUtils.IS_OS_WINDOWS) {
+ RUNNING_AS_ROOT_OR_ADMIN = Set.of(new NTSystem().getGroupIDs()).contains(WINDOWS_HIGH_INTEGRITY_LEVEL);
+ } else {
+ boolean isRunningAsRoot = false;
+ if (new UnixSystem().getUid() == 0) {
+ // Due to an OpenJDK bug (https://bugs.openjdk.java.net/browse/JDK-8274721), UnixSystem#getUid incorrectly
+ // returns 0 when the user doesn't have a username. Because of this, we'll have to double-check if the user ID is
+ // actually 0 by running the id -u command.
+ try {
+ Process process = new ProcessBuilder("id", "-u").start();
+ process.waitFor();
+ InputStream inputStream = process.getInputStream();
+ isRunningAsRoot = new String(inputStream.readAllBytes()).trim().equals("0");
+ } catch (InterruptedException | IOException ignored) {
+ isRunningAsRoot = false;
+ }
+ }
+ RUNNING_AS_ROOT_OR_ADMIN = isRunningAsRoot;
+ }
+ }
+
+ public static boolean userIsRootOrAdmin() {
+ return RUNNING_AS_ROOT_OR_ADMIN;
+ }
+}
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
index 7ce1ce59eeba8b57cd76b1c9c561733b476e7ebf..b6ee0e709b0f0529b99567bc9b8fb6bfd99bcd8e 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
@@ -190,6 +190,16 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
DedicatedServer.LOGGER.warn("To start the server with more ram, launch it as \"java -Xmx1024M -Xms1024M -jar minecraft_server.jar\"");
}
+ // Paper start - detect running as root
+ if (io.papermc.paper.util.ServerEnvironment.userIsRootOrAdmin()) {
+ DedicatedServer.LOGGER.warn("****************************");
+ DedicatedServer.LOGGER.warn("YOU ARE RUNNING THIS SERVER AS AN ADMINISTRATIVE OR ROOT USER. THIS IS NOT ADVISED.");
+ DedicatedServer.LOGGER.warn("YOU ARE OPENING YOURSELF UP TO POTENTIAL RISKS WHEN DOING THIS.");
+ DedicatedServer.LOGGER.warn("FOR MORE INFORMATION, SEE https://madelinemiller.dev/blog/root-minecraft-server/");
+ DedicatedServer.LOGGER.warn("****************************");
+ }
+ // Paper end
+
DedicatedServer.LOGGER.info("Loading properties");
DedicatedServerProperties dedicatedserverproperties = this.settings.getProperties();

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Mon, 21 Jun 2021 22:12:53 -0400
Subject: [PATCH] Always allow item changing in Fireball
diff --git a/src/main/java/net/minecraft/world/entity/projectile/Fireball.java b/src/main/java/net/minecraft/world/entity/projectile/Fireball.java
index 913edd9f55543332eb891a722d0b98a23637f85c..6a945497cdcd1aa607a1cb7fa9a96c7950902e7d 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/Fireball.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/Fireball.java
@@ -28,7 +28,7 @@ public abstract class Fireball extends AbstractHurtingProjectile implements Item
}
public void setItem(ItemStack stack) {
- if (!stack.is(Items.FIRE_CHARGE) || stack.hasTag()) {
+ if (true || !stack.is(Items.FIRE_CHARGE) || stack.hasTag()) { // Paper - always allow item changing
this.getEntityData().set(Fireball.DATA_ITEM_STACK, (ItemStack) Util.make(stack.copy(), (itemstack1) -> { // CraftBukkit - decompile error
itemstack1.setCount(1);
}));

View file

@ -1,22 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Thu, 2 Sep 2021 00:24:06 -0700
Subject: [PATCH] Fix merchant inventory not closing on entity removal
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 536c53fd1d009b86d2c1c3ca2364f458448bc38c..d40a367670ccea01978cabf7d45f3c1a690662fc 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -2419,6 +2419,11 @@ public class ServerLevel extends Level implements WorldGenLevel {
// Spigot end
// Spigot Start
if (entity.getBukkitEntity() instanceof org.bukkit.inventory.InventoryHolder) {
+ // Paper start
+ if (entity.getBukkitEntity() instanceof org.bukkit.inventory.Merchant merchant && merchant.getTrader() != null) {
+ merchant.getTrader().closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED);
+ }
+ // Paper end
for (org.bukkit.entity.HumanEntity h : Lists.newArrayList(((org.bukkit.inventory.InventoryHolder) entity.getBukkitEntity()).getInventory().getViewers())) {
h.closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED); // Paper
}

View file

@ -1,42 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Sat, 16 Oct 2021 01:36:00 -0700
Subject: [PATCH] Do not overload I/O threads with chunk data while flush
saving
If the chunk count is high, then the memory used by the
chunks adds up and could cause problems. By flushing
every so many chunks, the server will not become
stressed for memory. It will also not increase the total
time to save, as flush saving performs a full flush at
the end anyways.
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index 4b1797659f6bb5913b105641ecaac38954ce8bc0..65090afbb510231c05db3132ba416502d188f1c0 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -950,6 +950,16 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
// Paper end
protected void saveAllChunks(boolean flush) {
+ // Paper start - do not overload I/O threads with too much work when saving
+ int[] saved = new int[1];
+ int maxAsyncSaves = 50;
+ Runnable onChunkSave = () -> {
+ if (++saved[0] >= maxAsyncSaves) {
+ saved[0] = 0;
+ com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.flush();
+ }
+ };
+ // Paper end - do not overload I/O threads with too much work when saving
if (flush) {
List<ChunkHolder> list = (List) this.updatingChunks.getVisibleValuesCopy().stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).collect(Collectors.toList()); // Paper
MutableBoolean mutableboolean = new MutableBoolean();
@@ -972,6 +982,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}).filter((ichunkaccess) -> {
return ichunkaccess instanceof ImposterProtoChunk || ichunkaccess instanceof LevelChunk;
}).filter(this::save).forEach((ichunkaccess) -> {
+ onChunkSave.run(); // Paper - do not overload I/O threads with too much work when saving
mutableboolean.setTrue();
});
} while (mutableboolean.isTrue());

View file

@ -1,31 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: stonar96 <minecraft.stonar96@gmail.com>
Date: Sun, 12 Sep 2021 00:14:21 +0200
Subject: [PATCH] Check requirement before suggesting root nodes
Child nodes are handled by CommandDispatcher#parse checking
requirements.
Vanilla clients only send ServerboundCommandSuggestionPacket when
encountering a command node with ASK_SERVER suggestions, however a
modified client can send this packet whenever it wants.
diff --git a/src/main/java/com/mojang/brigadier/CommandDispatcher.java b/src/main/java/com/mojang/brigadier/CommandDispatcher.java
index ca24830bac1a04b798229d1946863429c7849495..5584040fe48c18aa809f5a1510157e735851df79 100644
--- a/src/main/java/com/mojang/brigadier/CommandDispatcher.java
+++ b/src/main/java/com/mojang/brigadier/CommandDispatcher.java
@@ -594,10 +594,14 @@ public class CommandDispatcher<S> {
int i = 0;
for (final CommandNode<S> node : parent.getChildren()) {
CompletableFuture<Suggestions> future = Suggestions.empty();
+ // Paper start - Don't suggest if the requirement isn't met
+ if (parent != this.root || node.canUse(context.getSource())) {
try {
future = node.listSuggestions(context.build(truncatedInput), new SuggestionsBuilder(truncatedInput, truncatedInputLowerCase, start));
} catch (final CommandSyntaxException ignored) {
}
+ }
+ // Paper end
futures[i++] = future;
}

View file

@ -1,23 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: stonar96 <minecraft.stonar96@gmail.com>
Date: Sun, 12 Sep 2021 00:14:21 +0200
Subject: [PATCH] Don't respond to ServerboundCommandSuggestionPacket when
tab-complete is disabled
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 71b4d5f7bbccf56cb519333ad2751d6a953f2c68..029c21d9416520469548293f9a2ec0c056507d05 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -796,6 +796,11 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
}
// Paper end
// CraftBukkit end
+ // Paper start - Don't suggest if tab-complete is disabled
+ if (org.spigotmc.SpigotConfig.tabComplete < 0) {
+ return;
+ }
+ // Paper end
StringReader stringreader = new StringReader(packet.getCommand());
if (stringreader.canRead() && stringreader.peek() == '/') {

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: sulu5890 <sulu@sulu.me>
Date: Sun, 24 Oct 2021 22:48:14 -0500
Subject: [PATCH] don't attempt to teleport dead entities
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index e17bda0d13bae337cfad5ae31b118aa7a85499fc..2ce32495758abf64eeeeeea1cdbf4904be77b697 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -702,7 +702,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
// CraftBukkit start
public void postTick() {
// No clean way to break out of ticking once the entity has been copied to a new world, so instead we move the portalling later in the tick cycle
- if (!(this instanceof ServerPlayer)) {
+ if (!(this instanceof ServerPlayer) && this.isAlive()) { // Paper - don't attempt to teleport dead entities
this.handleNetherPortal();
}
}

View file

@ -1,133 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Sun, 31 Oct 2021 21:34:00 -0700
Subject: [PATCH] Async catch modifications to critical entity state
These used to be here from Spigot, but were dropped with 1.17.
Now in 1.17, this state is _even more_ critical than it was before,
so these must exist to catch stupid plugins.
diff --git a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
index 28c1f144f2cc8675ed61dc814456859309970480..8cb246863e06c5b95ba1442e2ec47095026c4f39 100644
--- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
+++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
@@ -138,6 +138,7 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
}
private boolean addEntityUuid(T entity) {
+ org.spigotmc.AsyncCatcher.catchOp("Entity add by UUID"); // Paper
if (!this.knownUuids.add(entity.getUUID())) {
// Paper start
T conflict = this.visibleEntityStorage.getEntity(entity.getUUID());
@@ -166,6 +167,7 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
}
private boolean addEntity(T entity, boolean existing) {
+ org.spigotmc.AsyncCatcher.catchOp("Entity add"); // Paper
if (!this.addEntityUuid(entity)) {
return false;
} else {
@@ -210,19 +212,23 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
}
void startTicking(T entity) {
+ org.spigotmc.AsyncCatcher.catchOp("Entity start ticking"); // Paper
this.callbacks.onTickingStart(entity);
}
void stopTicking(T entity) {
+ org.spigotmc.AsyncCatcher.catchOp("Entity stop ticking"); // Paper
this.callbacks.onTickingEnd(entity);
}
void startTracking(T entity) {
+ org.spigotmc.AsyncCatcher.catchOp("Entity start tracking"); // Paper
this.visibleEntityStorage.add(entity);
this.callbacks.onTrackingStart(entity);
}
void stopTracking(T entity) {
+ org.spigotmc.AsyncCatcher.catchOp("Entity stop tracking"); // Paper
this.callbacks.onTrackingEnd(entity);
this.visibleEntityStorage.remove(entity);
}
@@ -236,6 +242,7 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
}
public void updateChunkStatus(ChunkPos chunkPos, Visibility trackingStatus) {
+ org.spigotmc.AsyncCatcher.catchOp("Update chunk status"); // Paper
long i = chunkPos.toLong();
if (trackingStatus == Visibility.HIDDEN) {
@@ -295,6 +302,7 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
private boolean storeChunkSections(long chunkPos, Consumer<T> action, boolean callEvent) {
// CraftBukkit end
+ org.spigotmc.AsyncCatcher.catchOp("Entity chunk save"); // Paper
PersistentEntitySectionManager.ChunkLoadStatus persistententitysectionmanager_b = (PersistentEntitySectionManager.ChunkLoadStatus) this.chunkLoadStatuses.get(chunkPos);
if (persistententitysectionmanager_b == PersistentEntitySectionManager.ChunkLoadStatus.PENDING) {
@@ -324,6 +332,7 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
}
private void requestChunkLoad(long chunkPos) {
+ org.spigotmc.AsyncCatcher.catchOp("Entity chunk load request"); // Paper
this.chunkLoadStatuses.put(chunkPos, PersistentEntitySectionManager.ChunkLoadStatus.PENDING);
ChunkPos chunkcoordintpair = new ChunkPos(chunkPos);
CompletableFuture completablefuture = this.permanentStorage.loadEntities(chunkcoordintpair);
@@ -337,6 +346,7 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
}
private boolean processChunkUnload(long chunkPos) {
+ org.spigotmc.AsyncCatcher.catchOp("Entity chunk unload process"); // Paper
boolean flag = this.storeChunkSections(chunkPos, (entityaccess) -> {
entityaccess.getPassengersAndSelf().forEach(this::unloadEntity);
}, true); // CraftBukkit - add boolean for event call
@@ -361,6 +371,7 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
}
private void processPendingLoads() {
+ org.spigotmc.AsyncCatcher.catchOp("Entity chunk process pending loads"); // Paper
ChunkEntities<T> chunkentities; // CraftBukkit - decompile error
while ((chunkentities = (ChunkEntities) this.loadingInbox.poll()) != null) {
@@ -383,6 +394,7 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
}
public void tick() {
+ org.spigotmc.AsyncCatcher.catchOp("Entity manager tick"); // Paper
this.processPendingLoads();
this.processUnloads();
}
@@ -403,6 +415,7 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
}
public void autoSave() {
+ org.spigotmc.AsyncCatcher.catchOp("Entity manager autosave"); // Paper
this.getAllChunksToSave().forEach((java.util.function.LongConsumer) (i) -> { // CraftBukkit - decompile error
boolean flag = this.chunkVisibility.get(i) == Visibility.HIDDEN;
@@ -417,6 +430,7 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
}
public void saveAll() {
+ org.spigotmc.AsyncCatcher.catchOp("Entity manager save"); // Paper
LongSet longset = this.getAllChunksToSave();
while (!longset.isEmpty()) {
@@ -524,6 +538,7 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
long i = SectionPos.asLong(blockposition); final long newSectionPos = i; // Paper - diff on change, new position section
if (i != this.currentSectionKey) {
+ org.spigotmc.AsyncCatcher.catchOp("Entity move"); // Paper
PersistentEntitySectionManager.this.entitySliceManager.moveEntity((Entity)this.entity); // Paper
Visibility visibility = this.currentSection.getStatus(); final Visibility oldVisibility = visibility; // Paper - diff on change - this should be OLD section visibility
// Paper start
@@ -589,6 +604,7 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
@Override
public void onRemove(Entity.RemovalReason reason) {
+ org.spigotmc.AsyncCatcher.catchOp("Entity remove"); // Paper
if (!this.currentSection.remove(this.entity)) {
PersistentEntitySectionManager.LOGGER.warn("Entity {} wasn't found in section {} (destroying due to {})", this.entity, SectionPos.of(this.currentSectionKey), reason);
}

View file

@ -1,61 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Sauve <paul@technove.co>
Date: Thu, 4 Feb 2021 23:28:46 -0600
Subject: [PATCH] Cache palette array
Instead of allocating the 4KB for every chunk section, cache it locally and
reuse it for other chunk sections to save on allocations. These allocations add
up very quickly when saving chunks frequently.
diff --git a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
index c9e942669458668a184aaec3bc0a5509dd6ab5f0..ac84d49d7819666a89cacbe9ef1199cf22ac2ac3 100644
--- a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
+++ b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
@@ -263,13 +263,17 @@ public class PalettedContainer<T> implements PaletteResize<T> {
}
+ // Paper start - allow reusing int array
public synchronized void write(CompoundTag nbt, String paletteKey, String dataKey) { // Paper - synchronize
+ this.write(nbt, paletteKey, dataKey, new int[4096]);
+ }
+ public synchronized void write(CompoundTag nbt, String paletteKey, String dataKey, int[] is) { // Paper - synchronize // Paper end
try {
this.acquire();
HashMapPalette<T> hashMapPalette = new HashMapPalette<>(this.registry, this.bits, this.dummyPaletteResize, this.reader, this.writer);
T object = this.defaultValue;
int i = hashMapPalette.idFor(this.defaultValue);
- int[] is = new int[4096];
+ //int[] is = new int[4096]; // Paper - will now be pulled from ThreadLocal
for(int j = 0; j < 4096; ++j) {
T object2 = this.get(j);
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
index 7921ee2786d0d6a60d43786b20efc03a0f9178e3..10f15b8c7763a980aec47a4b4dda5686e60642ce 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
@@ -500,6 +500,7 @@ public class ChunkSerializer {
return new AsyncSaveData(blockLight, skyLight, blockTickListSerialized, fluidTickListSerialized, blockEntitiesSerialized, world.getGameTime());
}
+ private static final ThreadLocal<int[]> PALETTE_ARRAY = ThreadLocal.withInitial(() -> new int[4096]); // Paper - maintain a per-thread cache for saving palettes
public static CompoundTag write(ServerLevel world, ChunkAccess chunk) {
return saveChunk(world, chunk, null);
}
@@ -533,6 +534,7 @@ public class ChunkSerializer {
ThreadedLevelLightEngine lightenginethreaded = world.getChunkSource().getLightEngine();
boolean flag = chunk.isLightCorrect();
+ int[] is = PALETTE_ARRAY.get(); // Paper - use cached
for (int i = lightenginethreaded.getMinLightSection(); i < lightenginethreaded.getMaxLightSection(); ++i) {
int finalI = i; // CraftBukkit - decompile errors
LevelChunkSection chunksection = (LevelChunkSection) Arrays.stream(achunksection).filter((chunksection1) -> {
@@ -547,7 +549,7 @@ public class ChunkSerializer {
nbttagcompound2.putByte("Y", (byte) (i & 255));
if (chunksection != LevelChunk.EMPTY_SECTION) {
- chunksection.getStates().write(nbttagcompound2, "Palette", "BlockStates");
+ chunksection.getStates().write(nbttagcompound2, "Palette", "BlockStates", is); // Paper - reuse array
}
// Paper start - replace light engine

View file

@ -1,45 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nassim Jahnke <jahnke.nassim@gmail.com>
Date: Sun, 24 Oct 2021 15:49:35 +0200
Subject: [PATCH] Fix Bukkit NamespacedKey shenanigans
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperMinecartLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperMinecartLootableInventory.java
index 6d2e0493729b7b4e109ff103a6ac36c9901568c0..83dd3c254fd10e4596e454cc75c8e5e976b73ac0 100644
--- a/src/main/java/com/destroystokyo/paper/loottable/PaperMinecartLootableInventory.java
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperMinecartLootableInventory.java
@@ -16,7 +16,7 @@ public class PaperMinecartLootableInventory implements PaperLootableEntityInvent
@Override
public org.bukkit.loot.LootTable getLootTable() {
- return entity.lootTable != null ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(entity.lootTable)) : null;
+ return entity.lootTable != null && !entity.lootTable.getPath().isEmpty() ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(entity.lootTable)) : null;
}
@Override
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java
index 3377b86c337d0234bbb9b0349e4034a7cd450a97..94dc68182ec5f6dc1294ad15523427836228086a 100644
--- a/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java
@@ -15,7 +15,7 @@ public class PaperTileEntityLootableInventory implements PaperLootableBlockInven
@Override
public org.bukkit.loot.LootTable getLootTable() {
- return tileEntityLootable.lootTable != null ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(tileEntityLootable.lootTable)) : null;
+ return tileEntityLootable.lootTable != null && !tileEntityLootable.lootTable.getPath().isEmpty() ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(tileEntityLootable.lootTable)) : null;
}
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java b/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java
index 5f40d240b879e3989897b6e45725a8e5a6a7f194..5014192edb9616ce725fc1592832034789527b6f 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java
@@ -13,7 +13,7 @@ public final class CraftNamespacedKey {
return null;
}
ResourceLocation minecraft = ResourceLocation.tryParse(string);
- return (minecraft == null) ? null : CraftNamespacedKey.fromMinecraft(minecraft);
+ return (minecraft == null || minecraft.getPath().isEmpty()) ? null : CraftNamespacedKey.fromMinecraft(minecraft); // Paper - Bukkit's parser does not match Vanilla for empty paths
}
public static NamespacedKey fromString(String string) {

View file

@ -1,71 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Bjarne Koll <lynxplay101@gmail.com>
Date: Sat, 6 Nov 2021 23:15:20 +0100
Subject: [PATCH] Fix setPatternColor on tropical fish bucket meta
Prior to this commit, the tropical fish bucket meta would set the body
color to the previous metas pattern colour when updating the pattern
colour.
This commit hence simply fixes this by using the proper body colour
value when updating the pattern color.
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java
index ad9f19ab7d2acf314e87e2cfc6671583de2cfab9..0ea574121c505479607772d761ea829bb6ddb380 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java
@@ -113,7 +113,7 @@ class CraftMetaTropicalFishBucket extends CraftMetaItem implements TropicalFishB
if (this.variant == null) {
this.variant = 0;
}
- this.variant = CraftTropicalFish.getData(color, this.getPatternColor(), this.getPattern());
+ this.variant = CraftTropicalFish.getData(color, this.getBodyColor(), this.getPattern()); // Paper - properly set tropical fish pattern color without mutating body color
}
@Override
diff --git a/src/test/java/io/papermc/paper/inventory/CraftMetaTropicalFishBucketTest.java b/src/test/java/io/papermc/paper/inventory/CraftMetaTropicalFishBucketTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..2e7f8ef88ae74c7cbfdb7f397951cbc8479a995f
--- /dev/null
+++ b/src/test/java/io/papermc/paper/inventory/CraftMetaTropicalFishBucketTest.java
@@ -0,0 +1,40 @@
+package io.papermc.paper.inventory;
+
+import org.bukkit.DyeColor;
+import org.bukkit.Material;
+import org.bukkit.entity.TropicalFish;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.TropicalFishBucketMeta;
+import org.bukkit.support.AbstractTestingBase;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class CraftMetaTropicalFishBucketTest extends AbstractTestingBase {
+
+ @Test
+ public void testAllCombinations() {
+ final var rawMeta = new ItemStack(Material.TROPICAL_FISH_BUCKET).getItemMeta();
+ Assert.assertTrue("Meta was not a tropical fish bucket", rawMeta instanceof TropicalFishBucketMeta);
+
+ final var meta = (TropicalFishBucketMeta) rawMeta;
+
+ for (final var bodyColor : DyeColor.values()) {
+ for (final var pattern : TropicalFish.Pattern.values()) {
+ for (final var patternColor : DyeColor.values()) {
+ meta.setBodyColor(bodyColor);
+ Assert.assertEquals("Body color did not match post body color!", bodyColor, meta.getBodyColor());
+
+ meta.setPattern(pattern);
+ Assert.assertEquals("Pattern did not match post pattern!", pattern, meta.getPattern());
+ Assert.assertEquals("Body color did not match post pattern!", bodyColor, meta.getBodyColor());
+
+ meta.setPatternColor(patternColor);
+ Assert.assertEquals("Pattern did not match post pattern color!", pattern, meta.getPattern());
+ Assert.assertEquals("Body color did not match post pattern color!", bodyColor, meta.getBodyColor());
+ Assert.assertEquals("Pattern color did not match post pattern color!", patternColor, meta.getPatternColor());
+ }
+ }
+ }
+ }
+
+}

View file

@ -1,26 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sun, 31 Oct 2021 14:49:43 -0700
Subject: [PATCH] Call onRemove logic for breakNaturally
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
index 5154cfffc414e1f6039e55f1a256bbaacb56bc55..6f01af8cc3f9ed4d2eaa3304990ca33f8692a453 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
@@ -513,8 +513,14 @@ public class CraftBlock implements Block {
if (triggerEffect) world.levelEvent(org.bukkit.Effect.STEP_SOUND.getId(), position, net.minecraft.world.level.block.Block.getId(block.defaultBlockState())); // Paper
result = true;
}
+ // Paper start
+ net.minecraft.world.level.block.state.BlockState newBlockState = Blocks.AIR.defaultBlockState();
+ if (this.world instanceof net.minecraft.world.level.Level level) {
+ iblockdata.onRemove(level, position, newBlockState, false);
+ }
+ // Paper end
- return this.setTypeAndData(Blocks.AIR.defaultBlockState(), true) && result;
+ return this.setTypeAndData(newBlockState, true) && result; // Paper
}
@Override

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jan Tuck <jan@tuck.dk>
Date: Mon, 15 Nov 2021 15:20:41 -0500
Subject: [PATCH] Fix anvil prepare event not working with zero xp
diff --git a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java
index 593e23c10f2b1616db7256158dfe564b2d289df1..b62c6b56867b645520cb3c3e382ec96d421e7e97 100644
--- a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java
@@ -60,7 +60,7 @@ public class AnvilMenu extends ItemCombinerMenu {
@Override
protected boolean mayPickup(Player player, boolean present) {
- return (player.getAbilities().instabuild || player.experienceLevel >= this.cost.get()) && this.cost.get() > 0;
+ return (player.getAbilities().instabuild || player.experienceLevel >= this.cost.get()) && this.cost.get() >= 0; // Paper - fix anvil prepare event not working with 0 xp
}
@Override