even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even even 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:
parent
b39fa92d5d
commit
055b8ab9cf
31 changed files with 96 additions and 97 deletions
|
@ -25,7 +25,7 @@ index dcfc726ab96dccc05848219e824ad7612dbfbdab..7713f26d4a97df94c27694d28881d298
|
|||
return this.isPassenger() ? false : this.saveAsPassenger(nbt);
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
index ee50ea695585639d0ff184b675f3fb3b205b9f86..0bd800e1aeda87689a6c56ee6fadda381c74a4ff 100644
|
||||
index ee50ea695585639d0ff184b675f3fb3b205b9f86..5aae88e20bc04560d6ad52cfcaa872d28bfcee8f 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
@@ -1276,5 +1276,15 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||
|
@ -40,7 +40,7 @@ index ee50ea695585639d0ff184b675f3fb3b205b9f86..0bd800e1aeda87689a6c56ee6fadda38
|
|||
+ entity.level = ((CraftWorld) location.getWorld()).getHandle();
|
||||
+ entity.setPos(location.getX(), location.getY(), location.getZ());
|
||||
+ entity.setRot(location.getYaw(), location.getPitch());
|
||||
+ return !entity.valid && entity.level.addEntity(entity, reason);
|
||||
+ return !entity.valid && entity.level.addFreshEntity(entity, reason);
|
||||
+ }
|
||||
// Paper end
|
||||
}
|
||||
|
|
|
@ -0,0 +1,360 @@
|
|||
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 7d69f9e39361644796895254dfa518ef83d9e578..e572f524046d4799adec7f08b1609d82a64ab94f 100644
|
||||
--- a/build.gradle.kts
|
||||
+++ b/build.gradle.kts
|
||||
@@ -49,6 +49,7 @@ dependencies {
|
||||
runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.7.0")
|
||||
|
||||
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 778beb445eac5769b9e4e07b4d1294c50ae2602b..c712fb8193115e1ab71b5e40fb0ccb9413062b03 100644
|
||||
--- a/src/main/java/net/minecraft/network/CipherDecoder.java
|
||||
+++ b/src/main/java/net/minecraft/network/CipherDecoder.java
|
||||
@@ -7,13 +7,29 @@ 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
|
||||
}
|
||||
|
||||
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 0f3d502a9680006bcdcd7d272240a2e5c3b46790..5dd7be70603e8754d2625bb9d16900cb01b9c730 100644
|
||||
--- a/src/main/java/net/minecraft/network/CipherEncoder.java
|
||||
+++ b/src/main/java/net/minecraft/network/CipherEncoder.java
|
||||
@@ -4,15 +4,32 @@ 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
|
||||
}
|
||||
|
||||
- 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 b62be99c57b0a5bba0dc29809557d4d247698b13..f4d4ad983baf24d889441541d5a84dc1f49ea4d4 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 rejectsBadPackets) {
|
||||
+ this(null, compressionThreshold, rejectsBadPackets);
|
||||
+ }
|
||||
+ public CompressionDecoder(com.velocitypowered.natives.compression.VelocityCompressor compressor, int compressionThreshold, boolean rejectsBadPackets) {
|
||||
this.threshold = compressionThreshold;
|
||||
this.validateDecompressed = rejectsBadPackets;
|
||||
- this.inflater = new Inflater();
|
||||
+ this.inflater = compressor == null ? new Inflater() : null;
|
||||
+ this.compressor = compressor;
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
|
||||
@@ -38,6 +45,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);
|
||||
@@ -45,10 +54,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 rejectsBadPackets) {
|
||||
this.threshold = compressionThreshold;
|
||||
this.validateDecompressed = rejectsBadPackets;
|
||||
diff --git a/src/main/java/net/minecraft/network/CompressionEncoder.java b/src/main/java/net/minecraft/network/CompressionEncoder.java
|
||||
index 792883afe53d2b7989c25a81c2f9a639d5e21d20..c04379ca8a4db0f4de46ad2b3b3384310eebddf3 100644
|
||||
--- a/src/main/java/net/minecraft/network/CompressionEncoder.java
|
||||
+++ b/src/main/java/net/minecraft/network/CompressionEncoder.java
|
||||
@@ -6,22 +6,37 @@ 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
|
||||
}
|
||||
|
||||
- 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);
|
||||
@@ -34,10 +49,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 a1aafb037fd340dc93dd2afb758ffc7457d15f84..a7e7fe4be2784ff34f7f8d0b6c2f82d65de8c145 100644
|
||||
--- a/src/main/java/net/minecraft/network/Connection.java
|
||||
+++ b/src/main/java/net/minecraft/network/Connection.java
|
||||
@@ -628,11 +628,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;
|
||||
@@ -661,16 +678,17 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
|
||||
public void setupCompression(int compressionThreshold, boolean rejectsBadPackets) {
|
||||
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, rejectsBadPackets);
|
||||
} else {
|
||||
- this.channel.pipeline().addBefore("decoder", "decompress", new CompressionDecoder(compressionThreshold, rejectsBadPackets));
|
||||
+ this.channel.pipeline().addBefore("decoder", "decompress", new CompressionDecoder(compressor, compressionThreshold, rejectsBadPackets)); // 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 f7aa0125e4724f1efddf28814f926289c1ae37d4..477aa83c3b342705a8a9b7ab41b2f77008e2e281 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 45db764f4499ee71bef691d37b604f21da120fe7..d2dd8b802ecea7fd2efe5f07fcef65c26e1adfbc 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
@@ -276,12 +276,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);
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
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 f4b8dca0a3cbccb55b23b2408e9a17185fd2896f..faffd25b11836915764add5c6afd63cfe424979a 100644
|
||||
--- a/src/main/java/net/minecraft/Util.java
|
||||
+++ b/src/main/java/net/minecraft/Util.java
|
||||
@@ -124,7 +124,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;
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
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 fa1b3762ce94290f3a162f7b9628779cf8a2849c..587d5535c9ad3aa5a6b91d63a52e57b4f3fe008b 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
||||
@@ -128,46 +128,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)) {
|
||||
- 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) {
|
||||
- mailbox.run();
|
||||
- } else {
|
||||
- Thread.yield();
|
||||
- LockSupport.parkNanos("waiting for entity loading", 100000L);
|
||||
- }
|
||||
- }
|
||||
-
|
||||
return getCraftWorld().getHandle().getChunkEntities(this.x, this.z); // Paper - optimise this
|
||||
}
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
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 d963243431e1a75f95e673e1268faa7c2320c6b6..114569250b8bb99ebf5714f334b7a23dc3d3ca37 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) {
|
||||
@@ -280,6 +287,7 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
||||
}
|
||||
|
||||
public void ensureChunkQueuedForLoad(long chunkPos) {
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("Entity chunk save"); // Paper
|
||||
PersistentEntitySectionManager.ChunkLoadStatus persistententitysectionmanager_b = (PersistentEntitySectionManager.ChunkLoadStatus) this.chunkLoadStatuses.get(chunkPos);
|
||||
|
||||
if (persistententitysectionmanager_b == PersistentEntitySectionManager.ChunkLoadStatus.FRESH) {
|
||||
@@ -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) {
|
||||
@@ -377,6 +388,7 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("Entity manager tick"); // Paper
|
||||
this.processPendingLoads();
|
||||
this.processUnloads();
|
||||
}
|
||||
@@ -397,6 +409,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;
|
||||
|
||||
@@ -411,6 +424,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()) {
|
||||
@@ -513,6 +527,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
|
||||
@@ -578,6 +593,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);
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
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) {
|
|
@ -0,0 +1,22 @@
|
|||
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 8837c9793eb25ad88bdb4b0f6198dc7ae353b9b2..e84969a7b4ed92727a9917b266e5fbe3c9dac1f9 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -2406,6 +2406,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
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
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;
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
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 7b6cf326dfab9bd0b13dfc330d143d2efeea9aa1..3eba6962040f33b7b31b16c9de22d90f225710b4 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -762,6 +762,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() == '/') {
|
|
@ -0,0 +1,71 @@
|
|||
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());
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+}
|
19
patches/server/0780-Ensure-valid-vehicle-status.patch
Normal file
19
patches/server/0780-Ensure-valid-vehicle-status.patch
Normal file
|
@ -0,0 +1,19 @@
|
|||
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 67b482f6cafc55b6b262f23c2b56e4d8c6d089c2..510334bc98d2112489fcece46b660000b14ce6a5 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -487,7 +487,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();
|
|
@ -0,0 +1,23 @@
|
|||
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 467e2af08698ca40fbbe1fa7b0bafb9561f4fa65..be5952133720bf0ac3483cc2fed334967e6fc0c4 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
|
||||
@@ -412,6 +412,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);
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
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) -> {
|
|
@ -0,0 +1,19 @@
|
|||
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.
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
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 58428eebf24e328b3faf32ca473be8f19d4f6cca..3484defdfd5a487b11917310d7b1d1543291eee1 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/AbstractFish.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/AbstractFish.java
|
||||
@@ -81,7 +81,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 67bb476693fa16aa391c120f8acae7c7279efc20..86acf89ce875e215da8469947b382f70e42314b0 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
|
||||
@@ -237,7 +237,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
|
|
@ -0,0 +1,23 @@
|
|||
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) {
|
|
@ -0,0 +1,42 @@
|
|||
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 6fc7c1cf269466362dce91fa2cf525e67bee6c15..176065656029a8486f2bfb39bdd4da1e86fbca89 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -665,6 +665,16 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
}
|
||||
|
||||
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();
|
||||
@@ -687,6 +697,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());
|
72
patches/server/0787-Preserve-overstacked-loot.patch
Normal file
72
patches/server/0787-Preserve-overstacked-loot.patch
Normal file
|
@ -0,0 +1,72 @@
|
|||
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 7eacd9265a8d4cee6e3c3608ab08603a3b6e5a15..a9c7aae7668c3dbc307b26680efba4cd827ba528 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
@@ -844,6 +844,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 276c444a0fddb6962818635d5fc7721a56b30784..4f240fc74fb9551d752855dcdf2a376ff30f536b 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 057676201aa2d19032537832849f3857425d357a..b5c6b7280a9c6964e2ad4aa9bd4517146c98e727 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
|
||||
@@ -46,7 +46,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();
|
|
@ -0,0 +1,29 @@
|
|||
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 96794dcb87c3606e9d112d4159be8be31ad4329e..9cb875b2904c902f3fb0af5b0dd571c3e02aacbd 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -1616,6 +1616,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i
|
||||
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) {
|
||||
@@ -1654,6 +1655,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i
|
||||
this.setXRot(pitch);
|
||||
this.setOldPosAndRot();
|
||||
this.reapplyPosition();
|
||||
+ this.setYHeadRot(yaw); // Paper - Update head rotation
|
||||
}
|
||||
|
||||
public final void setOldPosAndRot() {
|
|
@ -0,0 +1,18 @@
|
|||
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 d648902737350103c2078c80796038a054f16acc..98124ee3bea51e40a9a3cb9014ee84bfc26e91f7 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 {
|
|
@ -0,0 +1,19 @@
|
|||
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 e9a37fc6791366ea421f2766a36dc2e014ab7951..578d7282190ca97368529cd24b578d31399c4867 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;
|
||||
}
|
||||
}
|
32
patches/server/0791-Fix-CraftCriteria-defaults-map.patch
Normal file
32
patches/server/0791-Fix-CraftCriteria-defaults-map.patch
Normal file
|
@ -0,0 +1,32 @@
|
|||
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);
|
||||
}
|
||||
|
349
patches/server/0792-Fix-upstreams-block-state-factories.patch
Normal file
349
patches/server/0792-Fix-upstreams-block-state-factories.patch
Normal file
|
@ -0,0 +1,349 @@
|
|||
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 0e37da7227eaba0d089e5bd136eca088ab2b5eb3..5601d0c2fe635a2a4f073c333531e1a8adf1833c 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
|
||||
@@ -270,7 +270,7 @@ public abstract class BlockEntity implements io.papermc.paper.util.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));
|
||||
+ }
|
||||
+ }
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
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 95b52e9f6d2b87c525b9eac88fae2e73b08bca82..fee271d0f1200df6475db5aa463b921a958648d7 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
||||
@@ -91,6 +91,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 477aa83c3b342705a8a9b7ab41b2f77008e2e281..a821b68fbe7e172c08540e4b04c857b8b5929120 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 d2dd8b802ecea7fd2efe5f07fcef65c26e1adfbc..33a29890435d6065a2cc4f8e8bf8209c01d5d114 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
@@ -224,7 +224,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 dca3b995c02507e5df299abe60f518480ce56d21..600005948a3106f2e074be5e816e4b4b82519a11 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -236,7 +236,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
|
||||
@@ -299,7 +299,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
|
||||
);
|
||||
};
|
||||
});
|
|
@ -0,0 +1,23 @@
|
|||
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();
|
79
patches/server/0795-Add-root-admin-user-detection.patch
Normal file
79
patches/server/0795-Add-root-admin-user-detection.patch
Normal file
|
@ -0,0 +1,79 @@
|
|||
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 82cee660a029547eda8abdf4188b9d1fb4ba0d53..38a0fb9a7c4ade9cacfd30dffabfea7e6b773981 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -188,6 +188,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();
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
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 838ba52969550f783d26e626267c556ab09b5f3e..7f4e3dfab421591151fda7ec39d9c00b464d62de 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) -> {
|
||||
itemstack1.setCount(1);
|
||||
}));
|
|
@ -0,0 +1,19 @@
|
|||
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 9cb875b2904c902f3fb0af5b0dd571c3e02aacbd..e8ed9ae272ee203b3e8ad036bd4e45aac14f9a6a 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -673,7 +673,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i
|
||||
// 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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
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 808bdd0e8d6b679c2eee87c3078a4c3dbcd08b8b..2da1609c42bc85f173ed56767933bcafd5f0422e 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
|
||||
@@ -516,8 +516,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
|
|
@ -0,0 +1,19 @@
|
|||
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 b40377e882d9cc3571f527e706862e27c59b1fd0..073cec4838b88bf4e7444321a74ab73fff732486 100644
|
||||
--- a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java
|
||||
+++ b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java
|
||||
@@ -59,7 +59,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
|
Loading…
Add table
Add a link
Reference in a new issue