More more patches, including hopper optimization patch

This commit is contained in:
Nassim Jahnke 2024-04-25 14:07:39 +02:00
parent c9907c650f
commit 2debcaff9d
No known key found for this signature in database
GPG Key ID: EF6771C01F6EF02F
11 changed files with 690 additions and 663 deletions

View File

@ -5,12 +5,12 @@ Subject: [PATCH] Use Velocity compression and cipher natives
diff --git a/build.gradle.kts b/build.gradle.kts
index f9056ee057a22a11288405cd42cd0ba4c9d120c3..bcfe59b6efb628ee1e7f9d60667360d4d885fb6a 100644
index 2fb342f9d86e169571070b2b40538633f4b0d7cf..e2e3abe6a4b837fcef96ce7da6679b14afba0519 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -40,6 +40,11 @@ dependencies {
runtimeOnly("org.xerial:sqlite-jdbc:3.42.0.1")
runtimeOnly("com.mysql:mysql-connector-j:8.2.0")
@@ -38,6 +38,11 @@ dependencies {
implementation("org.spongepowered:configurate-yaml:4.2.0-SNAPSHOT") // Paper - config files
implementation("commons-lang:commons-lang:2.6")
runtimeOnly("com.lmax:disruptor:3.4.4") // Paper
+ // Paper start - Use Velocity cipher
+ implementation("com.velocitypowered:velocity-native:3.1.2-SNAPSHOT") {
@ -102,14 +102,14 @@ index 0f3d502a9680006bcdcd7d272240a2e5c3b46790..ffa1c48585fbbc1d30826d435043527f
+ // Paper end - Use Velocity cipher
}
diff --git a/src/main/java/net/minecraft/network/CompressionDecoder.java b/src/main/java/net/minecraft/network/CompressionDecoder.java
index 5927c928b27f64bd3973e95d5867b59f67476d41..76aeebe60ac321ed604661a0ec969bb25210643f 100644
index 5927c928b27f64bd3973e95d5867b59f67476d41..ba3619b03ea73e4ea55ae2eb79d3b6cd1f48a191 100644
--- a/src/main/java/net/minecraft/network/CompressionDecoder.java
+++ b/src/main/java/net/minecraft/network/CompressionDecoder.java
@@ -13,13 +13,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 - Use Velocity cipher
+ private com.velocitypowered.natives.compression.VelocityCompressor compressor; // Paper - Use Velocity cipher
private int threshold;
private boolean validateDecompressed;
@ -170,11 +170,20 @@ index 5927c928b27f64bd3973e95d5867b59f67476d41..76aeebe60ac321ed604661a0ec969bb2
private void setupInflaterInput(ByteBuf buf) {
ByteBuffer byteBuffer;
if (buf.nioBufferCount() > 0) {
@@ -82,7 +117,7 @@ public class CompressionDecoder extends ByteToMessageDecoder {
}
}
- public void setThreshold(int compressionThreshold, boolean rejectsBadPackets) {
+ public void setThreshold(com.velocitypowered.natives.compression.VelocityCompressor compressor, int compressionThreshold, boolean rejectsBadPackets) { // Paper - Use Velocity cipher
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 11a466558c77b43969b8e4be3a3470f84c7fcb1a..ae6e8ab9c1afa31d808f1fce2654a8b95bee6c31 100644
index 34a80d2f34555663ab1b394972957089214cb337..ec30c291188ac3bba7f1c3bc397576d1edb0a57f 100644
--- a/src/main/java/net/minecraft/network/CompressionEncoder.java
+++ b/src/main/java/net/minecraft/network/CompressionEncoder.java
@@ -6,21 +6,37 @@ import io.netty.handler.codec.MessageToByteEncoder;
@@ -6,16 +6,31 @@ import io.netty.handler.codec.MessageToByteEncoder;
import java.util.zip.Deflater;
public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
@ -207,32 +216,35 @@ index 11a466558c77b43969b8e4be3a3470f84c7fcb1a..ae6e8ab9c1afa31d808f1fce2654a8b9
- protected void encode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, ByteBuf byteBuf2) {
+ protected void encode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, ByteBuf byteBuf2) throws Exception { // Paper - Use Velocity cipher
int i = byteBuf.readableBytes();
if (i < this.threshold) {
VarInt.write(byteBuf2, 0);
byteBuf2.writeBytes(byteBuf);
} else {
+ if (this.deflater != null) { // Paper - Use Velocity cipher
byte[] bs = new byte[i];
byteBuf.readBytes(bs);
VarInt.write(byteBuf2, bs.length);
@@ -33,6 +49,43 @@ public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
}
if (i > 8388608) {
throw new IllegalArgumentException("Packet too big (is " + i + ", should be less than 8388608)");
@@ -24,6 +39,7 @@ public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
VarInt.write(byteBuf2, 0);
byteBuf2.writeBytes(byteBuf);
} else {
+ if (this.deflater != null) { // Paper - Use Velocity cipher
byte[] bs = new byte[i];
byteBuf.readBytes(bs);
VarInt.write(byteBuf2, bs.length);
@@ -36,10 +52,47 @@ public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
}
this.deflater.reset();
+ // Paper start - Use Velocity cipher
+ return;
+ }
+
+ VarInt.write(byteBuf2, i);
+ ByteBuf compatibleIn = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(channelHandlerContext.alloc(), this.compressor, byteBuf);
+ try {
+ this.compressor.deflate(compatibleIn, byteBuf2);
+ } finally {
+ compatibleIn.release();
+ }
+ }
+ }
this.deflater.reset();
+ // Paper start - Use Velocity cipher
+ return;
+ }
+
+ VarInt.write(byteBuf2, i);
+ final ByteBuf compatibleIn = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(channelHandlerContext.alloc(), this.compressor, byteBuf);
+ try {
+ this.compressor.deflate(compatibleIn, byteBuf2);
+ } finally {
+ compatibleIn.release();
+ }
}
}
}
+ @Override
+ protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, ByteBuf msg, boolean preferDirect) throws Exception{
+ if (this.compressor != null) {
@ -244,7 +256,7 @@ index 11a466558c77b43969b8e4be3a3470f84c7fcb1a..ae6e8ab9c1afa31d808f1fce2654a8b9
+ // 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;
+ final int initialBufferSize = msg.readableBytes() + 1;
+ return com.velocitypowered.natives.util.MoreByteBufUtils.preferredBuffer(ctx.alloc(), this.compressor, initialBufferSize);
+ }
+
@ -256,14 +268,17 @@ index 11a466558c77b43969b8e4be3a3470f84c7fcb1a..ae6e8ab9c1afa31d808f1fce2654a8b9
+ if (this.compressor != null) {
+ this.compressor.close();
+ // Paper end - Use Velocity cipher
}
+ }
+ }
+
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 16eb94eb1f40485daef2713f740f6e0beeb1463f..fae2a57570a4007b67b9949b9b16504da36a9886 100644
index f94458d4270042062b9ae18931cc8179ef1fb420..63066dfde00569833546da01cd580434f8be6593 100644
--- a/src/main/java/net/minecraft/network/Connection.java
+++ b/src/main/java/net/minecraft/network/Connection.java
@@ -735,11 +735,28 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -763,11 +763,28 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
return networkmanager;
}
@ -296,28 +311,32 @@ index 16eb94eb1f40485daef2713f740f6e0beeb1463f..fae2a57570a4007b67b9949b9b16504d
public boolean isEncrypted() {
return this.encrypted;
@@ -772,16 +789,17 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -800,12 +817,13 @@ 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(io.papermc.paper.configuration.GlobalConfiguration.get().misc.compressionLevel.or(-1)); // Paper - Use Velocity cipher
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 - Use Velocity cipher
}
ChannelHandler channelhandler = this.channel.pipeline().get("decompress");
if (this.channel.pipeline().get("compress") instanceof CompressionEncoder) {
((CompressionEncoder) this.channel.pipeline().get("compress")).setThreshold(compressionThreshold);
if (channelhandler instanceof CompressionDecoder) {
CompressionDecoder packetdecompressor = (CompressionDecoder) channelhandler;
- packetdecompressor.setThreshold(compressionThreshold, rejectsBadPackets);
+ packetdecompressor.setThreshold(compressor, compressionThreshold, rejectsBadPackets); // Paper - Use Velocity cipher
} else {
- this.channel.pipeline().addBefore("encoder", "compress", new CompressionEncoder(compressionThreshold));
+ this.channel.pipeline().addBefore("encoder", "compress", new CompressionEncoder(compressor, compressionThreshold)); // Paper - Use Velocity cipher
this.channel.pipeline().addAfter("splitter", "decompress", new CompressionDecoder(compressionThreshold, rejectsBadPackets));
}
@@ -816,7 +834,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
packetcompressor.setThreshold(compressionThreshold);
} else {
- this.channel.pipeline().addAfter("prepender", "compress", new CompressionEncoder(compressionThreshold));
+ this.channel.pipeline().addAfter("prepender", "compress", new CompressionEncoder(compressor, compressionThreshold)); // Paper - Use Velocity cipher
}
this.channel.pipeline().fireUserEventTriggered(io.papermc.paper.network.ConnectionEvent.COMPRESSION_THRESHOLD_SET); // Paper - Add Channel initialization listeners
} else {
diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
index a4a29a7ea0035ecf4c61ee8547a9eb24acb667d0..586521a2cbb1d4dcfb912029f65e4363ec7674a7 100644
index a08d9aa6e420f691795df9b627a9cd5b5c0112c5..52f537b7bfbdeaad9d17c0e88a1ed1c8925a833f 100644
--- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
+++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
@@ -106,6 +106,11 @@ public class ServerConnectionListener {
@ -331,12 +350,12 @@ index a4a29a7ea0035ecf4c61ee8547a9eb24acb667d0..586521a2cbb1d4dcfb912029f65e4363
+
this.channels.add(((ServerBootstrap) ((ServerBootstrap) (new ServerBootstrap()).channel(oclass)).childHandler(new ChannelInitializer<Channel>() {
protected void initChannel(Channel channel) {
Connection.setInitialProtocolAttributes(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 b8d8f14c30786321949901ca5184c43bee716355..c5fa9f4d28f9a7f64a50a902ee5e631bfc00119c 100644
index 21d97c2b533a6528dd73c4e514d49273c120e171..cb25d42ba40bd0901bbe0d8399e5d8e87988706f 100644
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
@@ -235,12 +235,14 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
@@ -274,12 +274,14 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
}
SecretKey secretkey = packet.getSecretKey(privatekey);

View File

@ -7,28 +7,28 @@ Subject: [PATCH] Detail more information in watchdog dumps
- Dump player name, player uuid, position, and world for packet handling
diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
index fae2a57570a4007b67b9949b9b16504da36a9886..a536ebcf29d8ef0ed32863bd8d5e70f7a0636e8d 100644
index 63066dfde00569833546da01cd580434f8be6593..7fb162fa031fd76aa9a94f5fdaa3e32ceb9b9abc 100644
--- a/src/main/java/net/minecraft/network/Connection.java
+++ b/src/main/java/net/minecraft/network/Connection.java
@@ -587,7 +587,13 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -607,7 +607,13 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
if (!(this.packetListener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl loginPacketListener)
|| loginPacketListener.state != net.minecraft.server.network.ServerLoginPacketListenerImpl.State.VERIFYING
|| Connection.joinAttemptsThisTick++ < MAX_PER_TICK) {
+ // Paper start - detailed watchdog information
+ net.minecraft.network.protocol.PacketUtils.packetProcessing.push(this.packetListener);
+ try { // Paper end - detailed watchdog information
+ try {
tickablepacketlistener.tick();
+ } finally { // Paper start - detailed watchdog information
+ } finally {
+ net.minecraft.network.protocol.PacketUtils.packetProcessing.pop();
+ } // Paper end - detailed watchdog information
}
// Paper end - Buffer joins to world
} // Paper end - Buffer joins to world
}
diff --git a/src/main/java/net/minecraft/network/protocol/PacketUtils.java b/src/main/java/net/minecraft/network/protocol/PacketUtils.java
index b7ffab0284b0bccd79775b8d03c8b2e088f91d1d..83302c252f54481f239522e5c6861ccfe233070a 100644
index e161ad0f53a21a68e8c78575ba5d3cdbdb11fca0..57e76b53e5e314c3e6b8856010f7a84188121582 100644
--- a/src/main/java/net/minecraft/network/protocol/PacketUtils.java
+++ b/src/main/java/net/minecraft/network/protocol/PacketUtils.java
@@ -18,6 +18,24 @@ public class PacketUtils {
@@ -19,6 +19,24 @@ public class PacketUtils {
private static final Logger LOGGER = LogUtils.getLogger();
@ -53,7 +53,7 @@ index b7ffab0284b0bccd79775b8d03c8b2e088f91d1d..83302c252f54481f239522e5c6861ccf
public PacketUtils() {}
public static <T extends PacketListener> void ensureRunningOnSameThread(Packet<T> packet, T listener, ServerLevel world) throws RunningOnDifferentThreadException {
@@ -27,6 +45,8 @@ public class PacketUtils {
@@ -28,6 +46,8 @@ public class PacketUtils {
public static <T extends PacketListener> void ensureRunningOnSameThread(Packet<T> packet, T listener, BlockableEventLoop<?> engine) throws RunningOnDifferentThreadException {
if (!engine.isSameThread()) {
engine.executeIfPossible(() -> {
@ -62,7 +62,7 @@ index b7ffab0284b0bccd79775b8d03c8b2e088f91d1d..83302c252f54481f239522e5c6861ccf
if (listener instanceof ServerCommonPacketListenerImpl serverCommonPacketListener && serverCommonPacketListener.processedDisconnect) return; // CraftBukkit - Don't handle sync packets for kicked players
if (listener.shouldHandleMessage(packet)) {
co.aikar.timings.Timing timing = co.aikar.timings.MinecraftTimings.getPacketTiming(packet); // Paper - timings
@@ -64,6 +84,12 @@ public class PacketUtils {
@@ -47,6 +67,12 @@ public class PacketUtils {
} else {
PacketUtils.LOGGER.debug("Ignoring packet due to disconnection: {}", packet);
}
@ -76,10 +76,10 @@ index b7ffab0284b0bccd79775b8d03c8b2e088f91d1d..83302c252f54481f239522e5c6861ccf
});
throw RunningOnDifferentThreadException.RUNNING_ON_DIFFERENT_THREAD;
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 9d18da228c6709e7665ba8babb6ee6d0b36b5dc5..af9f58328c09dddb2875f79128f906b8b276ab88 100644
index 16d24e70072e3846b3c35d331c3f474238a8def2..98fded81545a96deb6a05df713a5b69e27189cf4 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -1239,7 +1239,26 @@ public class ServerLevel extends Level implements WorldGenLevel {
@@ -1245,7 +1245,26 @@ public class ServerLevel extends Level implements WorldGenLevel {
}
@ -106,7 +106,7 @@ index 9d18da228c6709e7665ba8babb6ee6d0b36b5dc5..af9f58328c09dddb2875f79128f906b8
++TimingHistory.entityTicks; // Paper - timings
// Spigot start
co.aikar.timings.Timing timer; // Paper
@@ -1279,7 +1298,13 @@ public class ServerLevel extends Level implements WorldGenLevel {
@@ -1285,7 +1304,13 @@ public class ServerLevel extends Level implements WorldGenLevel {
this.tickPassenger(entity, entity1);
}
// } finally { timer.stopTiming(); } // Paper - timings - move up
@ -122,10 +122,10 @@ index 9d18da228c6709e7665ba8babb6ee6d0b36b5dc5..af9f58328c09dddb2875f79128f906b8
private void tickPassenger(Entity vehicle, Entity passenger) {
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index ab8a736bd8da140c48e6bd66449d7aa3b4f29a16..9a01eff5a93c68edd45f98e9a6f8d24656650fb6 100644
index 257943b4c984d6faee29eca17c8f951e7f43168b..0fbcf60a994f67bdd81d40e4a8bf38f0cbb8993d 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -1063,8 +1063,43 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S
@@ -1074,8 +1074,43 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
return this.onGround;
}
@ -169,7 +169,7 @@ index ab8a736bd8da140c48e6bd66449d7aa3b4f29a16..9a01eff5a93c68edd45f98e9a6f8d246
if (this.noPhysics) {
this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z);
} else {
@@ -1234,6 +1269,13 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S
@@ -1245,6 +1280,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
this.level().getProfiler().pop();
}
}
@ -183,7 +183,7 @@ index ab8a736bd8da140c48e6bd66449d7aa3b4f29a16..9a01eff5a93c68edd45f98e9a6f8d246
}
private boolean isStateClimbable(BlockState state) {
@@ -4379,7 +4421,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S
@@ -4405,7 +4447,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
}
public void setDeltaMovement(Vec3 velocity) {
@ -193,7 +193,7 @@ index ab8a736bd8da140c48e6bd66449d7aa3b4f29a16..9a01eff5a93c68edd45f98e9a6f8d246
}
public void addDeltaMovement(Vec3 velocity) {
@@ -4482,7 +4526,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S
@@ -4508,7 +4552,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
}
// Paper end - Fix MC-4
if (this.position.x != x || this.position.y != y || this.position.z != z) {
@ -204,7 +204,7 @@ index ab8a736bd8da140c48e6bd66449d7aa3b4f29a16..9a01eff5a93c68edd45f98e9a6f8d246
int j = Mth.floor(y);
int k = Mth.floor(z);
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
index 0234555978d1b13051f876a257e47bafad37b0f8..9e638f72f180ff5ef63ec3dd6cf548c53f7bd4a5 100644
index 577f29519156f33b49ee319a64a52249630e28d8..6db566e3111ec08a99aa429624979cb83a85e272 100644
--- a/src/main/java/org/spigotmc/WatchdogThread.java
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
@@ -22,6 +22,78 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa

View File

@ -2153,10 +2153,10 @@ index 0000000000000000000000000000000000000000..1f42bdfdb052056e62a939ab0d1944f8
+
+}
diff --git a/src/main/java/net/minecraft/core/Direction.java b/src/main/java/net/minecraft/core/Direction.java
index 75694cfd7d8adde6b9246518c20fe75774297a57..84a760fdc50bdafc9150f977e9c5d557a30ee220 100644
index 03c45ee77276462818a6f774b5945b25924aa3f0..ab289a6ca85459e03acb2089c6b9e931caa9c873 100644
--- a/src/main/java/net/minecraft/core/Direction.java
+++ b/src/main/java/net/minecraft/core/Direction.java
@@ -53,6 +53,21 @@ public enum Direction implements StringRepresentable {
@@ -60,6 +60,21 @@ public enum Direction implements StringRepresentable {
private final int adjY;
private final int adjZ;
// Paper end - Perf: Inline shift direction fields
@ -2176,13 +2176,13 @@ index 75694cfd7d8adde6b9246518c20fe75774297a57..84a760fdc50bdafc9150f977e9c5d557
+ }
+ // Paper end - optimise collisions
private Direction(int id, int idOpposite, int idHorizontal, String name, Direction.AxisDirection direction, Direction.Axis axis, Vec3i vector) {
this.data3d = id;
private Direction(
final int id,
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index acc1751324f040accc4fc18914ed281e572358eb..17a6d43685f35a6978c2d941876a1f8a9a2c8b42 100644
index e06b9b0c7b1c3a200b89819e0e521f1c88dc981b..ed42a78aebeda86b77f27cba4fcefbc6c17f86fc 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -496,7 +496,7 @@ public class ServerPlayer extends Player {
@@ -512,7 +512,7 @@ public class ServerPlayer extends Player {
if (blockposition1 != null) {
this.moveTo(blockposition1, world.getSharedSpawnAngle(), 0.0F); // Paper - MC-200092 - fix first spawn pos yaw being ignored
@ -2191,7 +2191,7 @@ index acc1751324f040accc4fc18914ed281e572358eb..17a6d43685f35a6978c2d941876a1f8a
break;
}
}
@@ -504,7 +504,7 @@ public class ServerPlayer extends Player {
@@ -520,7 +520,7 @@ public class ServerPlayer extends Player {
} else {
this.moveTo(blockposition, world.getSharedSpawnAngle(), 0.0F); // Paper - MC-200092 - fix first spawn pos yaw being ignored
@ -2201,10 +2201,10 @@ index acc1751324f040accc4fc18914ed281e572358eb..17a6d43685f35a6978c2d941876a1f8a
}
}
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 594cb6ce4bfa6c42212000a1ed983ea95ee2c4bf..97b0119ac71284b3a223c089bec26d87a01d3b25 100644
index 3e3bca13578ab9e5b6ca0159383bee0b2a60a86e..c83ec24c0bf54f8699caa2d37bfe82d273f7b16c 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -936,7 +936,7 @@ public abstract class PlayerList {
@@ -935,7 +935,7 @@ public abstract class PlayerList {
entityplayer1.forceSetPositionRotation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
worldserver1.getChunkSource().addRegionTicket(net.minecraft.server.level.TicketType.POST_TELEPORT, new net.minecraft.world.level.ChunkPos(location.getBlockX() >> 4, location.getBlockZ() >> 4), 1, entityplayer.getId()); // Paper
@ -2214,10 +2214,10 @@ index 594cb6ce4bfa6c42212000a1ed983ea95ee2c4bf..97b0119ac71284b3a223c089bec26d87
entityplayer1.setPos(entityplayer1.getX(), entityplayer1.getY() + 1.0D, entityplayer1.getZ());
}
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 9a01eff5a93c68edd45f98e9a6f8d24656650fb6..7992375dc55492aeb6defb204b28dd267be4a6e7 100644
index 0fbcf60a994f67bdd81d40e4a8bf38f0cbb8993d..8ad2d17615ff489b2fbbb13480dd0b217a42d805 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -1250,9 +1250,44 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S
@@ -1261,9 +1261,44 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
float f = this.getBlockSpeedFactor();
this.setDeltaMovement(this.getDeltaMovement().multiply((double) f, 1.0D, (double) f));
@ -2265,7 +2265,7 @@ index 9a01eff5a93c68edd45f98e9a6f8d24656650fb6..7992375dc55492aeb6defb204b28dd26
if (this.remainingFireTicks <= 0) {
this.setRemainingFireTicks(-this.getFireImmuneTicks());
}
@@ -1432,32 +1467,82 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S
@@ -1443,32 +1478,82 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
}
private Vec3 collide(Vec3 movement) {
@ -2364,8 +2364,8 @@ index 9a01eff5a93c68edd45f98e9a6f8d24656650fb6..7992375dc55492aeb6defb204b28dd26
}
public static Vec3 collideBoundingBox(@Nullable Entity entity, Vec3 movement, AABB entityBoundingBox, Level world, List<VoxelShape> collisions) {
@@ -2707,11 +2792,70 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S
float f = this.dimensions.width * 0.8F;
@@ -2735,11 +2820,70 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
float f = this.dimensions.width() * 0.8F;
AABB axisalignedbb = AABB.ofSize(this.getEyePosition(), (double) f, 1.0E-6D, (double) f);
- return BlockPos.betweenClosedStream(axisalignedbb).anyMatch((blockposition) -> {
@ -2440,10 +2440,10 @@ index 9a01eff5a93c68edd45f98e9a6f8d24656650fb6..7992375dc55492aeb6defb204b28dd26
}
diff --git a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
index bbe299afd361a107e3936c8ea1a62067fcac9b7e..eadcebd7845ee716e33c0ac0544502da1a6c5941 100644
index 2ed6845f16fab175e2e9e96e76391e63ab4a43e2..c2bd2e303f956d390319f6bbbe9a6492ebec5154 100644
--- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
+++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
@@ -354,7 +354,7 @@ public class ArmorStand extends LivingEntity {
@@ -360,7 +360,7 @@ public class ArmorStand extends LivingEntity {
@Override
protected void pushEntities() {
if (!this.level().paperConfig().entities.armorStands.doCollisionEntityLookups) return; // Paper - Option to prevent armor stands from doing entity lookups
@ -2453,10 +2453,10 @@ index bbe299afd361a107e3936c8ea1a62067fcac9b7e..eadcebd7845ee716e33c0ac0544502da
while (iterator.hasNext()) {
diff --git a/src/main/java/net/minecraft/world/entity/monster/Spider.java b/src/main/java/net/minecraft/world/entity/monster/Spider.java
index ffa4f34d964fbcc53e2dfe11677832db21a6eb93..7618364e5373fe17cfe45a5a4ee9ab25e591581c 100644
index f0127f1b55999aa4a841341ad02cbcde45702b50..ef8911f7bcf6a97496675abb4689bb09cf322e85 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Spider.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Spider.java
@@ -86,7 +86,7 @@ public class Spider extends Monster {
@@ -82,7 +82,7 @@ public class Spider extends Monster {
public void tick() {
super.tick();
if (!this.level().isClientSide) {
@ -2479,7 +2479,7 @@ index cd89623a44f02d7db77f0d0f87545cf80841f403..48710a60561824a3670ebef3601f284d
}
} else {
diff --git a/src/main/java/net/minecraft/world/level/ClipContext.java b/src/main/java/net/minecraft/world/level/ClipContext.java
index 86a4f30c8784c602436ecf1c78efb0bdca4b7089..b0bea28e9261767c60d30fb0e76f4f3af8a5634e 100644
index 3fa2964b979053ecbefc946c7fe76828de86d8f1..2634ba06147c936b0fae08a190c7820c832e6b23 100644
--- a/src/main/java/net/minecraft/world/level/ClipContext.java
+++ b/src/main/java/net/minecraft/world/level/ClipContext.java
@@ -17,8 +17,8 @@ public class ClipContext {
@ -2616,10 +2616,10 @@ index 9a28912f52824acdc80a62243b136e6f365bf567..21843501355a0c0c8d594e3e5312e978
// Paper start - Affects Spawning API
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 47e83adf64df673bc40077335baf786f865411e8..bb57f97dbc2fcc7c28ebfb54ff00796fc7f51efe 100644
index 5b3143723e1637c2ab44363b208cd26b659d70cc..ae569a4837dc82bbc390d281d774179706772959 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -294,6 +294,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
@@ -288,6 +288,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
this.entityLimiter = new org.spigotmc.TickLimiter(this.spigotConfig.entityMaxTickTime);
this.tileLimiter = new org.spigotmc.TickLimiter(this.spigotConfig.tileMaxTickTime);
this.chunkPacketBlockController = this.paperConfig().anticheat.antiXray.enabled ? new com.destroystokyo.paper.antixray.ChunkPacketBlockControllerAntiXray(this, executor) : com.destroystokyo.paper.antixray.ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray
@ -2630,7 +2630,7 @@ index 47e83adf64df673bc40077335baf786f865411e8..bb57f97dbc2fcc7c28ebfb54ff00796f
}
// Paper start - Cancel hit for vanished players
@@ -335,6 +339,366 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
@@ -329,6 +333,366 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
return true;
}
// Paper end - Cancel hit for vanished players
@ -2997,7 +2997,7 @@ index 47e83adf64df673bc40077335baf786f865411e8..bb57f97dbc2fcc7c28ebfb54ff00796f
@Override
public boolean isClientSide() {
return this.isClientSide;
@@ -958,7 +1322,17 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
@@ -950,7 +1314,17 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
@Override
public boolean noCollision(@Nullable Entity entity, AABB box) {
if (entity instanceof net.minecraft.world.entity.decoration.ArmorStand && !entity.level().paperConfig().entities.armorStands.doCollisionEntityLookups) return false;
@ -3017,10 +3017,10 @@ index 47e83adf64df673bc40077335baf786f865411e8..bb57f97dbc2fcc7c28ebfb54ff00796f
// Paper end - Option to prevent armor stands from doing entity lookups
diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java
index b60a52788e73de3dcb086c1a4628466b25c9d3ef..22036ed3ea0629bc12981a8d91a03e55cc2117d6 100644
index 054593fc0b8d13f6bf449cc20a1f7ddfd5f1d1f0..cf8b8c8efd1c9c81eb5f02d75bd75875eb66771f 100644
--- a/src/main/java/net/minecraft/world/level/block/Block.java
+++ b/src/main/java/net/minecraft/world/level/block/Block.java
@@ -284,7 +284,7 @@ public class Block extends BlockBehaviour implements ItemLike {
@@ -280,7 +280,7 @@ public class Block extends BlockBehaviour implements ItemLike {
}
public static boolean isShapeFullBlock(VoxelShape shape) {
@ -3028,12 +3028,12 @@ index b60a52788e73de3dcb086c1a4628466b25c9d3ef..22036ed3ea0629bc12981a8d91a03e55
+ return shape.isFullBlock(); // Paper - optimise collisions
}
public boolean propagatesSkylightDown(BlockState state, BlockGetter world, BlockPos pos) {
public void animateTick(BlockState state, Level world, BlockPos pos, RandomSource random) {}
diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
index e493b34aa8726ed48f8e5db2ae8ea561cc5b1f75..2892e586146cbc560f0bcf4b9af6d0575cb0a82e 100644
index f863f3a553e26af1fb656622da052505e6ef1c01..d3c0e767758aa791d51e708d4ec6efad726741e8 100644
--- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
+++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
@@ -882,6 +882,10 @@ public abstract class BlockBehaviour implements FeatureElement {
@@ -813,6 +813,10 @@ public abstract class BlockBehaviour implements FeatureElement {
this.instrument = blockbase_info.instrument;
this.replaceable = blockbase_info.replaceable;
this.conditionallyFullOpaque = this.canOcclude & this.useShapeForLightOcclusion; // Paper
@ -3044,7 +3044,7 @@ index e493b34aa8726ed48f8e5db2ae8ea561cc5b1f75..2892e586146cbc560f0bcf4b9af6d057
}
// Paper start - Perf: impl cached craft block data, lazy load to fix issue with loading at the wrong time
private org.bukkit.craftbukkit.block.data.CraftBlockData cachedCraftBlockData;
@@ -930,6 +934,52 @@ public abstract class BlockBehaviour implements FeatureElement {
@@ -861,6 +865,52 @@ public abstract class BlockBehaviour implements FeatureElement {
return this.conditionallyFullOpaque;
}
// Paper end - starlight
@ -3097,7 +3097,7 @@ index e493b34aa8726ed48f8e5db2ae8ea561cc5b1f75..2892e586146cbc560f0bcf4b9af6d057
public void initCache() {
this.fluidState = ((Block) this.owner).getFluidState(this.asState());
@@ -941,6 +991,39 @@ public abstract class BlockBehaviour implements FeatureElement {
@@ -872,6 +922,39 @@ public abstract class BlockBehaviour implements FeatureElement {
this.opacityIfCached = this.cache == null || this.isConditionallyFullOpaque() ? -1 : this.cache.lightBlock; // Paper - starlight - cache opacity for light
this.legacySolid = this.calculateSolid();
@ -3138,7 +3138,7 @@ index e493b34aa8726ed48f8e5db2ae8ea561cc5b1f75..2892e586146cbc560f0bcf4b9af6d057
public Block getBlock() {
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
index eb05c01e85825cbd5b7cf43bc6d261db0b871b92..796bbef3544e06b8e7aac7e8ac5f740a2613f4bd 100644
index 8cd6c1d838e0332125fde3fc36475034aa4effa0..a2a5aef769ee8bb638a5a9f3da9812fa4a85dda5 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
@@ -26,6 +26,22 @@ public class LevelChunkSection {
@ -3194,9 +3194,9 @@ index eb05c01e85825cbd5b7cf43bc6d261db0b871b92..796bbef3544e06b8e7aac7e8ac5f740a
+ // Paper end - optimise collisions
});
}
// Paper end
// Paper end - unfuck this
diff --git a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java
index a98ab20814cc29a25e9d29adfbb7e70d46768df2..6d8ff6c06af5545634f255ed17dc1e489ece2548 100644
index 1c0712295695727ee9c4d430d4157b8e17cbd71f..c2943d892b067b3f1fb3b93301a092e912d71f08 100644
--- a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java
+++ b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java
@@ -240,6 +240,17 @@ public abstract class FlowingFluid extends Fluid {
@ -3276,7 +3276,7 @@ index fc7f986812bdf74e0aea3bd09a1d53ba6def697f..0583d40a235aaecd9d6081486bbfb735
+
}
diff --git a/src/main/java/net/minecraft/world/phys/shapes/BitSetDiscreteVoxelShape.java b/src/main/java/net/minecraft/world/phys/shapes/BitSetDiscreteVoxelShape.java
index 31b570517c1047e8e1cd5280baf80977af2b6121..d8b80632f6186641ee2ddaef9eba7ba998b09136 100644
index e8f3307727e7e3da9a7629cafc6e1ee53790b75d..a71421947b161697d43bd8602e2af95aa272ed3f 100644
--- a/src/main/java/net/minecraft/world/phys/shapes/BitSetDiscreteVoxelShape.java
+++ b/src/main/java/net/minecraft/world/phys/shapes/BitSetDiscreteVoxelShape.java
@@ -4,13 +4,13 @@ import java.util.BitSet;
@ -3308,22 +3308,11 @@ index 31b570517c1047e8e1cd5280baf80977af2b6121..d8b80632f6186641ee2ddaef9eba7ba9
+ // Paper start - optimise collisions
+ // called with the shape of a VoxelShape, so we can expect the cache to exist
+ final io.papermc.paper.util.collisions.CachedShapeData cache = voxelSet.getOrCreateCachedShapeData();
- for (int i = 0; i < bitSetDiscreteVoxelShape.ySize; i++) {
- for (int j = 0; j < bitSetDiscreteVoxelShape.xSize; j++) {
- int k = -1;
+
+ final int sizeX = cache.sizeX();
+ final int sizeY = cache.sizeY();
+ final int sizeZ = cache.sizeZ();
- for (int l = 0; l <= bitSetDiscreteVoxelShape.zSize; l++) {
- if (bitSetDiscreteVoxelShape.isFullWide(j, i, l)) {
- if (coalesce) {
- if (k == -1) {
- k = l;
- }
- } else {
- callback.consume(j, i, l, j + 1, i + 1, l + 1);
+
+ int indexX;
+ int indexY = 0;
+ int indexZ;
@ -3353,10 +3342,21 @@ index 31b570517c1047e8e1cd5280baf80977af2b6121..d8b80632f6186641ee2ddaef9eba7ba9
+ } else {
+ // same notes about loop order as the above
+ // this branch is actually important to optimise, as it affects uncached toAabbs() (which affects optimize())
+
- for (int i = 0; i < bitSetDiscreteVoxelShape.ySize; i++) {
- for (int j = 0; j < bitSetDiscreteVoxelShape.xSize; j++) {
- int k = -1;
+ // only clone when we may write to it
+ bitset = bitset.clone();
+
- for (int l = 0; l <= bitSetDiscreteVoxelShape.zSize; l++) {
- if (bitSetDiscreteVoxelShape.isFullWide(j, i, l)) {
- if (coalesce) {
- if (k == -1) {
- k = l;
- }
- } else {
- callback.consume(j, i, l, j + 1, i + 1, l + 1);
+ for (int y = 0; y < sizeY; ++y, indexY += incY) {
+ indexX = indexY;
+ for (int x = 0; x < sizeX; ++x, indexX += incX) {
@ -3365,6 +3365,11 @@ index 31b570517c1047e8e1cd5280baf80977af2b6121..d8b80632f6186641ee2ddaef9eba7ba9
+
+ if (firstSetZ == -1) {
+ break;
+ }
+
+ int lastSetZ = io.papermc.paper.util.collisions.FlatBitsetUtil.firstClear(bitset, firstSetZ, endIndex);
+ if (lastSetZ == -1) {
+ lastSetZ = endIndex;
}
- } else if (k != -1) {
- int m = j;
@ -3375,14 +3380,6 @@ index 31b570517c1047e8e1cd5280baf80977af2b6121..d8b80632f6186641ee2ddaef9eba7ba9
- bitSetDiscreteVoxelShape.clearZStrip(k, l, m + 1, i);
- m++;
+
+ int lastSetZ = io.papermc.paper.util.collisions.FlatBitsetUtil.firstClear(bitset, firstSetZ, endIndex);
+ if (lastSetZ == -1) {
+ lastSetZ = endIndex;
}
- while (bitSetDiscreteVoxelShape.isXZRectangleFull(j, m + 1, k, l, n + 1)) {
- for (int o = j; o <= m; o++) {
- bitSetDiscreteVoxelShape.clearZStrip(k, l, o, n + 1);
+ io.papermc.paper.util.collisions.FlatBitsetUtil.clearRange(bitset, firstSetZ, lastSetZ);
+
+ // try to merge neighbouring on the X axis
@ -3393,8 +3390,11 @@ index 31b570517c1047e8e1cd5280baf80977af2b6121..d8b80632f6186641ee2ddaef9eba7ba9
+
+ ++endX;
+ io.papermc.paper.util.collisions.FlatBitsetUtil.clearRange(bitset, neighbourIdxStart, neighbourIdxEnd);
+ }
+
}
- while (bitSetDiscreteVoxelShape.isXZRectangleFull(j, m + 1, k, l, n + 1)) {
- for (int o = j; o <= m; o++) {
- bitSetDiscreteVoxelShape.clearZStrip(k, l, o, n + 1);
+ // try to merge neighbouring on the Y axis
+
+ int endY; // exclusive
@ -3446,7 +3446,7 @@ index 32632368f06b79f53342fde060bbcd1b7c64767a..b9af1d14c7815c99273bce8165cf384d
@Override
diff --git a/src/main/java/net/minecraft/world/phys/shapes/DiscreteVoxelShape.java b/src/main/java/net/minecraft/world/phys/shapes/DiscreteVoxelShape.java
index 87a8f12dc3d47fb093115030e0222f065f1dcb1c..44b62f1f6685084c0cff02bd31eb5a7c2ef9eead 100644
index 01693ba050b12b9debcdaefceeff9cbcd503b369..a7af766f1c28f2c9ca2a430808ac4c07fe24df68 100644
--- a/src/main/java/net/minecraft/world/phys/shapes/DiscreteVoxelShape.java
+++ b/src/main/java/net/minecraft/world/phys/shapes/DiscreteVoxelShape.java
@@ -9,6 +9,71 @@ public abstract class DiscreteVoxelShape {

View File

@ -8,10 +8,10 @@ Move collision logic to just the hasNewCollision call instead of getCubes + hasN
CHECK ME
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 33560f75dd76f946203faa34ca5d10f213cd62c9..d0ae2c485b0e37406633c79043bd833a8a6b3e2d 100644
index 6061f7104dd2094e316739a1b0e541475aed40b0..88fc56fa521c36accd807ca1704136f29733e52f 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -552,7 +552,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
@@ -578,7 +578,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
return;
}
@ -20,7 +20,7 @@ index 33560f75dd76f946203faa34ca5d10f213cd62c9..d0ae2c485b0e37406633c79043bd833a
d6 = d3 - this.vehicleLastGoodX; // Paper - diff on change, used for checking large move vectors above
d7 = d4 - this.vehicleLastGoodY - 1.0E-6D; // Paper - diff on change, used for checking large move vectors above
@@ -568,6 +568,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
@@ -594,6 +594,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
}
entity.move(MoverType.PLAYER, new Vec3(d6, d7, d8));
@ -28,7 +28,7 @@ index 33560f75dd76f946203faa34ca5d10f213cd62c9..d0ae2c485b0e37406633c79043bd833a
double d11 = d7;
d6 = d3 - entity.getX();
@@ -581,15 +582,23 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
@@ -607,15 +608,23 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
boolean flag2 = false;
if (d10 > org.spigotmc.SpigotConfig.movedWronglyThreshold) { // Spigot
@ -55,7 +55,7 @@ index 33560f75dd76f946203faa34ca5d10f213cd62c9..d0ae2c485b0e37406633c79043bd833a
entity.absMoveTo(d0, d1, d2, f, f1);
this.player.absMoveTo(d0, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit
this.send(new ClientboundMoveVehiclePacket(entity));
@@ -668,7 +677,32 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
@@ -694,7 +703,32 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
}
private boolean noBlocksAround(Entity entity) {
@ -89,7 +89,7 @@ index 33560f75dd76f946203faa34ca5d10f213cd62c9..d0ae2c485b0e37406633c79043bd833a
}
@Override
@@ -1282,7 +1316,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
@@ -1289,7 +1323,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
}
if (this.awaitingPositionFromClient != null) {
@ -98,7 +98,7 @@ index 33560f75dd76f946203faa34ca5d10f213cd62c9..d0ae2c485b0e37406633c79043bd833a
this.awaitingTeleportTime = this.tickCount;
this.teleport(this.awaitingPositionFromClient.x, this.awaitingPositionFromClient.y, this.awaitingPositionFromClient.z, this.player.getYRot(), this.player.getXRot());
}
@@ -1389,7 +1423,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
@@ -1398,7 +1432,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
}
}
@ -107,7 +107,7 @@ index 33560f75dd76f946203faa34ca5d10f213cd62c9..d0ae2c485b0e37406633c79043bd833a
d6 = d0 - this.lastGoodX; // Paper - diff on change, used for checking large move vectors above
d7 = d1 - this.lastGoodY; // Paper - diff on change, used for checking large move vectors above
@@ -1431,6 +1465,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
@@ -1440,6 +1474,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
this.player.move(MoverType.PLAYER, new Vec3(d6, d7, d8));
this.player.onGround = packet.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move
@ -115,10 +115,10 @@ index 33560f75dd76f946203faa34ca5d10f213cd62c9..d0ae2c485b0e37406633c79043bd833a
// Paper start - prevent position desync
if (this.awaitingPositionFromClient != null) {
return; // ... thanks Mojang for letting move calls teleport across dimensions.
@@ -1459,7 +1494,17 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
}
@@ -1470,7 +1505,17 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
}
// Paper start - Add fail move event
- boolean teleportBack = !this.player.noPhysics && !this.player.isSleeping() && (movedWrongly && worldserver.noCollision(this.player, axisalignedbb) || this.isPlayerCollidingWithAnythingNew(worldserver, axisalignedbb, d0, d1, d2));
+ // Paper start - optimise out extra getCubes
+ boolean teleportBack = !this.player.noPhysics && !this.player.isSleeping() && movedWrongly;
@ -134,7 +134,7 @@ index 33560f75dd76f946203faa34ca5d10f213cd62c9..d0ae2c485b0e37406633c79043bd833a
if (teleportBack) {
io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.CLIPPED_INTO_BLOCK,
toX, toY, toZ, toYaw, toPitch, false);
@@ -1559,6 +1604,33 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
@@ -1576,6 +1621,33 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
}
}

View File

@ -6,10 +6,10 @@ Subject: [PATCH] Fix tripwire disarming not working as intended
Fixes MC-129055
diff --git a/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java b/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java
index d9b3877257b31ca1b5acc4a47fbf5b993de69ae0..efd8d77a441fd334ea4c09c5e31c6d946c1ae0b7 100644
index 8614fad5b3df7a6030384b108b1689bf6b9f1209..76aca266d3f3222502ff4c196228f08fcd88c5f8 100644
--- a/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java
@@ -201,9 +201,8 @@ public class TripWireHookBlock extends Block {
@@ -202,9 +202,8 @@ public class TripWireHookBlock extends Block {
BlockState iblockdata4 = aiblockdata[l];
if (iblockdata4 != null) {

View File

@ -10,10 +10,10 @@ when if this was fixed on the client, that wouldn't be needed.
Mojira Issue: https://bugs.mojang.com/browse/MC-235045
diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java
index faa375f2722793a86265248a4be4fa14736d9818..f341813e9713e39bfe142ca34b751de3d8efd25b 100644
index 3c0d2332207ba638faaaa4280bce18c334a01271..e6c7f62ed379a78645933670299e4fcda8540ed1 100644
--- a/src/main/java/net/minecraft/commands/CommandSourceStack.java
+++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java
@@ -466,4 +466,20 @@ public class CommandSourceStack implements ExecutionCommandSource<CommandSourceS
@@ -462,4 +462,20 @@ public class CommandSourceStack implements ExecutionCommandSource<CommandSourceS
return this.source.getBukkitSender(this);
}
// CraftBukkit end
@ -35,10 +35,10 @@ index faa375f2722793a86265248a4be4fa14736d9818..f341813e9713e39bfe142ca34b751de3
+ // Paper end - tell clients to ask server for suggestions for EntityArguments
}
diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java
index df06c28c778255cb2d8d5e14960bd38a2af9ad22..b7f338e982d0dcab99137ab6dc200b82ac6b7cba 100644
index 60406cb01c5a409ba6fe98677a5cc332effaebea..a0702dccbb07c79febe2e65a2ff82c4436c09f12 100644
--- a/src/main/java/net/minecraft/commands/Commands.java
+++ b/src/main/java/net/minecraft/commands/Commands.java
@@ -522,6 +522,7 @@ public class Commands {
@@ -525,6 +525,7 @@ public class Commands {
private void fillUsableCommands(CommandNode<CommandSourceStack> tree, CommandNode<SharedSuggestionProvider> result, CommandSourceStack source, Map<CommandNode<CommandSourceStack>, CommandNode<SharedSuggestionProvider>> resultNodes) {
Iterator iterator = tree.getChildren().iterator();
@ -46,7 +46,7 @@ index df06c28c778255cb2d8d5e14960bd38a2af9ad22..b7f338e982d0dcab99137ab6dc200b82
while (iterator.hasNext()) {
CommandNode<CommandSourceStack> commandnode2 = (CommandNode) iterator.next();
// Paper start - Brigadier API
@@ -548,6 +549,12 @@ public class Commands {
@@ -551,6 +552,12 @@ public class Commands {
if (requiredargumentbuilder.getSuggestionsProvider() != null) {
requiredargumentbuilder.suggests(SuggestionProviders.safelySwap(requiredargumentbuilder.getSuggestionsProvider()));
@ -60,10 +60,10 @@ index df06c28c778255cb2d8d5e14960bd38a2af9ad22..b7f338e982d0dcab99137ab6dc200b82
}
diff --git a/src/main/java/net/minecraft/commands/arguments/EntityArgument.java b/src/main/java/net/minecraft/commands/arguments/EntityArgument.java
index 8e008e752c5b11781088e2b4b5ba180bacb59326..8d79cfa371546996ef65f94232c1d344e7c590ec 100644
index 2043001c16b3530c2d3f52efda10bcad424881c0..7976885b902a6ce7d80f31e49448c99452eb9765 100644
--- a/src/main/java/net/minecraft/commands/arguments/EntityArgument.java
+++ b/src/main/java/net/minecraft/commands/arguments/EntityArgument.java
@@ -132,7 +132,7 @@ public class EntityArgument implements ArgumentType<EntitySelector> {
@@ -131,7 +131,7 @@ public class EntityArgument implements ArgumentType<EntitySelector> {
final boolean permission = object instanceof CommandSourceStack stack
? stack.bypassSelectorPermissions || stack.hasPermission(2, "minecraft.command.selector")
: icompletionprovider.hasPermission(2);
@ -72,7 +72,7 @@ index 8e008e752c5b11781088e2b4b5ba180bacb59326..8d79cfa371546996ef65f94232c1d344
// Paper end - Fix EntityArgument suggestion permissions
try {
@@ -142,7 +142,19 @@ public class EntityArgument implements ArgumentType<EntitySelector> {
@@ -141,7 +141,19 @@ public class EntityArgument implements ArgumentType<EntitySelector> {
}
return argumentparserselector.fillSuggestions(suggestionsbuilder, (suggestionsbuilder1) -> {
@ -118,10 +118,10 @@ index 3d897ec6920eff6176ddac9f0442a997b9ef14fd..abaf1ea340c69c8bee80e64567b44b5c
this.level = MinMaxBounds.Ints.ANY;
this.rotX = WrappedMinMaxBounds.ANY;
diff --git a/src/main/java/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java b/src/main/java/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java
index 0ed0679af07445f0ba241c791f15dcc2b6731b12..01ec7813cd7abe94cb87927c4c2324c8be6c3a56 100644
index 44982ff2cdd6e03f0b9ce8c3cc87561ef183ef06..626fe7a45c2edba68eb201974e9f8f5eebf75cc0 100644
--- a/src/main/java/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java
+++ b/src/main/java/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java
@@ -75,6 +75,19 @@ public class EntitySelectorOptions {
@@ -76,6 +76,19 @@ public class EntitySelectorOptions {
public static final DynamicCommandExceptionType ERROR_ENTITY_TYPE_INVALID = new DynamicCommandExceptionType(
entity -> Component.translatableEscape("argument.entity.options.type.invalid", entity)
);
@ -141,7 +141,7 @@ index 0ed0679af07445f0ba241c791f15dcc2b6731b12..01ec7813cd7abe94cb87927c4c2324c8
private static void register(String id, EntitySelectorOptions.Modifier handler, Predicate<EntitySelectorParser> condition, Component description) {
OPTIONS.put(id, new EntitySelectorOptions.Option(handler, condition, description));
@@ -296,6 +309,12 @@ public class EntitySelectorOptions {
@@ -297,6 +310,12 @@ public class EntitySelectorOptions {
if (reader.isTag()) {
TagKey<EntityType<?>> tagKey = TagKey.create(Registries.ENTITY_TYPE, ResourceLocation.read(reader.getReader()));

View File

@ -2009,10 +2009,10 @@ index 0000000000000000000000000000000000000000..33cd90c30c22200a4e1ae64f40a0bf78
+ }
+}
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index af9f58328c09dddb2875f79128f906b8b276ab88..c9405cbea1202e5603dde42637cf2a78592b92e1 100644
index 98fded81545a96deb6a05df713a5b69e27189cf4..a2a5a43c5e73ba2cccbec4e1ac563f692ae901b5 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -223,6 +223,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
@@ -228,6 +228,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
public final UUID uuid;
public boolean hasPhysicsEvent = true; // Paper - BlockPhysicsEvent
public boolean hasEntityMoveEvent; // Paper - Add EntityMoveEvent
@ -2020,7 +2020,7 @@ index af9f58328c09dddb2875f79128f906b8b276ab88..c9405cbea1202e5603dde42637cf2a78
public LevelChunk getChunkIfLoaded(int x, int z) {
return this.chunkSource.getChunkAtIfLoadedImmediately(x, z); // Paper - Use getChunkIfLoadedImmediately
@@ -2593,6 +2594,13 @@ public class ServerLevel extends Level implements WorldGenLevel {
@@ -2560,6 +2561,13 @@ public class ServerLevel extends Level implements WorldGenLevel {
return crashreportsystemdetails;
}
@ -2035,10 +2035,10 @@ index af9f58328c09dddb2875f79128f906b8b276ab88..c9405cbea1202e5603dde42637cf2a78
EntityCallbacks() {}
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index bb57f97dbc2fcc7c28ebfb54ff00796fc7f51efe..a09017e74d972a12d0b88b4ade9a3532ce0ecd08 100644
index ae569a4837dc82bbc390d281d774179706772959..68746df814aa1a8714e199ff887cad9f8bfa283c 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -1887,4 +1887,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
@@ -1882,4 +1882,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
return ret;
}
// Paper end
@ -2054,10 +2054,10 @@ index bb57f97dbc2fcc7c28ebfb54ff00796fc7f51efe..a09017e74d972a12d0b88b4ade9a3532
+ // Paper end - optimize redstone (Alternate Current)
}
diff --git a/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java b/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java
index c80af964a2b4026f738aecd2058a7e99d225cce0..b5a71fd4e2f55bf036c2c697da5d50cc90fc657c 100644
index 7ec3b0f9488b732c51cd1b02fb0dfe3c45aec2a4..f6c1e40001af507b4eed8f46a9ed4e4704b48d72 100644
--- a/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java
@@ -259,7 +259,7 @@ public class RedStoneWireBlock extends Block {
@@ -258,7 +258,7 @@ public class RedStoneWireBlock extends Block {
return floor.isFaceSturdy(world, pos, Direction.UP) || floor.is(Blocks.HOPPER);
}
@ -2066,9 +2066,9 @@ index c80af964a2b4026f738aecd2058a7e99d225cce0..b5a71fd4e2f55bf036c2c697da5d50cc
// The bulk of the new functionality is found in RedstoneWireTurbo.java
com.destroystokyo.paper.util.RedstoneWireTurbo turbo = new com.destroystokyo.paper.util.RedstoneWireTurbo(this);
@@ -461,7 +461,13 @@ public class RedStoneWireBlock extends Block {
@@ -460,7 +460,13 @@ public class RedStoneWireBlock extends Block {
@Override
public void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify) {
protected void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify) {
if (!oldState.is(state.getBlock()) && !world.isClientSide) {
- this.updateSurroundingRedstone(world, pos, state, null); // Paper - Optimize redstone
+ // Paper start - optimize redstone - replace call to updatePowerStrength
@ -2081,7 +2081,7 @@ index c80af964a2b4026f738aecd2058a7e99d225cce0..b5a71fd4e2f55bf036c2c697da5d50cc
Iterator iterator = Direction.Plane.VERTICAL.iterator();
while (iterator.hasNext()) {
@@ -488,7 +494,13 @@ public class RedStoneWireBlock extends Block {
@@ -487,7 +493,13 @@ public class RedStoneWireBlock extends Block {
world.updateNeighborsAt(pos.relative(enumdirection), this);
}
@ -2096,9 +2096,9 @@ index c80af964a2b4026f738aecd2058a7e99d225cce0..b5a71fd4e2f55bf036c2c697da5d50cc
this.updateNeighborsOfNeighboringWires(world, pos);
}
}
@@ -522,8 +534,14 @@ public class RedStoneWireBlock extends Block {
@@ -521,8 +533,14 @@ public class RedStoneWireBlock extends Block {
@Override
public void neighborChanged(BlockState state, Level world, BlockPos pos, Block sourceBlock, BlockPos sourcePos, boolean notify) {
protected void neighborChanged(BlockState state, Level world, BlockPos pos, Block sourceBlock, BlockPos sourcePos, boolean notify) {
if (!world.isClientSide) {
+ // Paper start - optimize redstone (Alternate Current)
+ // Alternate Current handles breaking of redstone wires in the WireHandler.

View File

@ -5,10 +5,10 @@ Subject: [PATCH] optimize dirt and snow spreading
diff --git a/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java b/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java
index 4e2e80006bd4edae227af7be5ca8e3284b7494f6..f3003a3832deff7724d28b4b3a091f4802a4cb29 100644
index 5a39e8d359dc13383711e49ffb2d1294dad26192..b7165ec19bef1a07f6618fc0429d86cda1b08da4 100644
--- a/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java
@@ -19,8 +19,13 @@ public abstract class SpreadingSnowyDirtBlock extends SnowyDirtBlock {
@@ -18,8 +18,13 @@ public abstract class SpreadingSnowyDirtBlock extends SnowyDirtBlock {
}
private static boolean canBeGrass(BlockState state, LevelReader world, BlockPos pos) {
@ -23,7 +23,7 @@ index 4e2e80006bd4edae227af7be5ca8e3284b7494f6..f3003a3832deff7724d28b4b3a091f48
if (iblockdata1.is(Blocks.SNOW) && (Integer) iblockdata1.getValue(SnowLayerBlock.LAYERS) == 1) {
return true;
@@ -37,15 +42,27 @@ public abstract class SpreadingSnowyDirtBlock extends SnowyDirtBlock {
@@ -36,15 +41,27 @@ public abstract class SpreadingSnowyDirtBlock extends SnowyDirtBlock {
protected abstract MapCodec<? extends SpreadingSnowyDirtBlock> codec();
private static boolean canPropagate(BlockState state, LevelReader world, BlockPos pos) {
@ -40,20 +40,20 @@ index 4e2e80006bd4edae227af7be5ca8e3284b7494f6..f3003a3832deff7724d28b4b3a091f48
}
@Override
public void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
if (this instanceof GrassBlock && world.paperConfig().tickRates.grassSpread != 1 && (world.paperConfig().tickRates.grassSpread < 1 || (MinecraftServer.currentTick + pos.hashCode()) % world.paperConfig().tickRates.grassSpread != 0)) { return; } // Paper - Configurable random tick rates for blocks
protected void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
if (this instanceof GrassBlock && world.paperConfig().tickRates.grassSpread != 1 && (world.paperConfig().tickRates.grassSpread < 1 || (net.minecraft.server.MinecraftServer.currentTick + pos.hashCode()) % world.paperConfig().tickRates.grassSpread != 0)) { return; } // Paper - Configurable random tick rates for blocks
- if (!SpreadingSnowyDirtBlock.canBeGrass(state, world, pos)) {
+ // Paper start - Perf: optimize dirt and snow spreading
+ net.minecraft.world.level.chunk.ChunkAccess cachedBlockChunk = world.getChunkIfLoaded(pos);
+ final net.minecraft.world.level.chunk.ChunkAccess cachedBlockChunk = world.getChunkIfLoaded(pos);
+ if (cachedBlockChunk == null) { // Is this needed?
+ return;
+ }
+ if (!SpreadingSnowyDirtBlock.canBeGrass(cachedBlockChunk, state, world, pos)) {
+ // Paper end - Perf: optimize dirt and snow spreading
+ // Paper end - Perf: optimize dirt and snow spreading
// CraftBukkit start
if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(world, pos, Blocks.DIRT.defaultBlockState()).isCancelled()) {
return;
@@ -58,9 +75,19 @@ public abstract class SpreadingSnowyDirtBlock extends SnowyDirtBlock {
@@ -57,9 +74,19 @@ public abstract class SpreadingSnowyDirtBlock extends SnowyDirtBlock {
for (int i = 0; i < 4; ++i) {
BlockPos blockposition1 = pos.offset(random.nextInt(3) - 1, random.nextInt(5) - 3, random.nextInt(3) - 1);

View File

@ -0,0 +1,337 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Wed, 7 Dec 2022 17:25:19 -0500
Subject: [PATCH] Properly resend entities
This resolves some issues which caused entities to not be resent correctly.
Entities that are interacted with need to be resent to the client, so we resend all the entity
data to the player whilst making sure not to clear dirty entries from the tracker. This makes
sure that values will be correctly updated to other players.
This also adds utilities to aid in further preventing entity desyncs.
This also also fixes the bug causing cancelling PlayerInteractEvent to cause items to continue
to be used despite being cancelled on the server.
For example, items being consumed but never finishing, shields being put up, etc.
The underlying issue of this is that the client modifies their synced data values,
and so we have to (forcibly) resend them in order for the client to reset their using item state.
See: https://github.com/PaperMC/Paper/pull/1896
== AT ==
public net.minecraft.server.level.ChunkMap$TrackedEntity serverEntity
diff --git a/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java b/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java
index 02bf2705ca1c99023a83a22d92e1962181102297..0f99733660f91280e4c6262cf75b3c9cae86f65a 100644
--- a/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java
+++ b/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java
@@ -50,7 +50,7 @@ public class SynchedEntityData {
}
}
- private <T> SynchedEntityData.DataItem<T> getItem(EntityDataAccessor<T> key) {
+ public <T> SynchedEntityData.DataItem<T> getItem(EntityDataAccessor<T> key) { // Paper - public
return (SynchedEntityData.DataItem<T>) this.itemsById[key.id()]; // CraftBukkit - decompile error
}
@@ -151,6 +151,20 @@ public class SynchedEntityData {
}
}
+ // Paper start
+ // We need to pack all as we cannot rely on "non default values" or "dirty" ones.
+ // Because these values can possibly be desynced on the client.
+ @Nullable
+ public List<SynchedEntityData.DataValue<?>> packAll() {
+ final List<SynchedEntityData.DataValue<?>> list = new ArrayList<>();
+ for (final DataItem<?> dataItem : this.itemsById) {
+ list.add(dataItem.value());
+ }
+
+ return list;
+ }
+ // Paper end
+
public static class DataItem<T> {
final EntityDataAccessor<T> accessor;
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
index abb9a86cd42a34cf722a312068134e820ac21956..3b6ebe8f9575783a1607eb6667554ca66de94271 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
@@ -556,6 +556,7 @@ public class ServerPlayerGameMode {
}
// Paper end - extend Player Interact cancellation
player.getBukkitEntity().updateInventory(); // SPIGOT-2867
+ this.player.resyncUsingItem(this.player); // Paper - Properly cancel usable items
return (event.useItemInHand() != Event.Result.ALLOW) ? InteractionResult.SUCCESS : InteractionResult.PASS;
} else if (this.gameModeForPlayer == GameType.SPECTATOR) {
MenuProvider itileinventory = iblockdata.getMenuProvider(world, blockposition);
@@ -609,6 +610,11 @@ public class ServerPlayerGameMode {
} else {
return InteractionResult.PASS;
}
+ // Paper start - Properly cancel usable items; Cancel only if cancelled + if the interact result is different from default response
+ else if (this.interactResult && this.interactResult != cancelledItem) {
+ this.player.resyncUsingItem(this.player);
+ }
+ // Paper end - Properly cancel usable items
}
}
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 88fc56fa521c36accd807ca1704136f29733e52f..32076a765d48d59b339d600f69afa85edbcf833c 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -45,7 +45,6 @@ import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.Connection;
import net.minecraft.network.ConnectionProtocol;
import net.minecraft.network.TickablePacketListener;
-import net.minecraft.network.chat.ChatDecorator;
import net.minecraft.network.chat.ChatType;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.LastSeenMessages;
@@ -63,7 +62,6 @@ import net.minecraft.network.protocol.PacketUtils;
import net.minecraft.network.protocol.common.ServerboundClientInformationPacket;
import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket;
import net.minecraft.network.protocol.configuration.ConfigurationProtocols;
-import net.minecraft.network.protocol.game.ClientboundAddEntityPacket;
import net.minecraft.network.protocol.game.ClientboundBlockChangedAckPacket;
import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket;
import net.minecraft.network.protocol.game.ClientboundCommandSuggestionsPacket;
@@ -185,7 +183,6 @@ import net.minecraft.world.level.block.entity.CrafterBlockEntity;
import net.minecraft.world.level.block.entity.JigsawBlockEntity;
import net.minecraft.world.level.block.entity.SignBlockEntity;
import net.minecraft.world.level.block.entity.StructureBlockEntity;
-import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.BlockHitResult;
@@ -216,7 +213,6 @@ import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.event.CraftEventFactory;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.craftbukkit.inventory.CraftItemType;
-import org.bukkit.craftbukkit.util.CraftChatMessage;
import org.bukkit.craftbukkit.util.CraftNamespacedKey;
import org.bukkit.craftbukkit.util.LazyPlayerSet;
import org.bukkit.craftbukkit.util.Waitable;
@@ -231,8 +227,6 @@ import org.bukkit.event.inventory.InventoryCreativeEvent;
import org.bukkit.event.inventory.InventoryType.SlotType;
import org.bukkit.event.inventory.SmithItemEvent;
import org.bukkit.event.player.AsyncPlayerChatEvent;
-import org.bukkit.event.player.PlayerAnimationEvent;
-import org.bukkit.event.player.PlayerAnimationType;
import org.bukkit.event.player.PlayerChatEvent;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.player.PlayerInteractAtEntityEvent;
@@ -2010,6 +2004,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
}
if (cancelled) {
+ this.player.resyncUsingItem(this.player); // Paper - Properly cancel usable items
this.player.getBukkitEntity().updateInventory(); // SPIGOT-2524
return;
}
@@ -2794,7 +2789,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
// Entity in bucket - SPIGOT-4048 and SPIGOT-6859a
if ((entity instanceof Bucketable && entity instanceof LivingEntity && origItem != null && origItem.asItem() == Items.WATER_BUCKET) && (event.isCancelled() || ServerGamePacketListenerImpl.this.player.getInventory().getSelected() == null || ServerGamePacketListenerImpl.this.player.getInventory().getSelected().getItem() != origItem)) {
- ServerGamePacketListenerImpl.this.send(new ClientboundAddEntityPacket(entity));
+ entity.getEntityData().resendPossiblyDesyncedEntityData(player); // Paper - The entire mob gets deleted, so resend it.
ServerGamePacketListenerImpl.this.player.containerMenu.sendAllDataToRemote();
}
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index c83ec24c0bf54f8699caa2d37bfe82d273f7b16c..dd628c8190704505fde543a8853d5b4dbc8252d5 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -393,7 +393,7 @@ public abstract class PlayerList {
((ServerLevel)player.level()).getChunkSource().chunkMap.addEntity(player); // Paper - Fire PlayerJoinEvent when Player is actually ready; track entity now
// CraftBukkit end
- player.refreshEntityData(player); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn
+ //player.refreshEntityData(player); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn // Paper - THIS IS NOT NEEDED ANYMORE
this.sendLevelInfo(player, worldserver1);
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 8ad2d17615ff489b2fbbb13480dd0b217a42d805..130ad5dc8ef5cfe1cfc0a166eba2cf67d424ff69 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -6,6 +6,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.collect.UnmodifiableIterator;
import com.mojang.logging.LogUtils;
+import io.papermc.paper.util.MCUtil;
import it.unimi.dsi.fastutil.objects.Object2DoubleArrayMap;
import it.unimi.dsi.fastutil.objects.Object2DoubleMap;
import java.util.Arrays;
@@ -59,7 +60,6 @@ import net.minecraft.network.syncher.SyncedDataHolder;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
-import io.papermc.paper.util.MCUtil;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
@@ -129,28 +129,22 @@ import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraft.world.scores.PlayerTeam;
import net.minecraft.world.scores.ScoreHolder;
import net.minecraft.world.scores.Team;
-import org.slf4j.Logger;
import org.bukkit.Bukkit;
import org.bukkit.Location;
-import org.bukkit.Server;
import org.bukkit.block.BlockFace;
import org.bukkit.command.CommandSender;
-import org.bukkit.craftbukkit.event.CraftPortalEvent;
-import org.bukkit.entity.Hanging;
-import org.bukkit.entity.LivingEntity;
-import org.bukkit.entity.Vehicle;
-import org.bukkit.event.entity.EntityCombustByEntityEvent;
-import org.bukkit.event.hanging.HangingBreakByEntityEvent;
-import org.bukkit.event.vehicle.VehicleBlockCollisionEvent;
-import org.bukkit.event.vehicle.VehicleEnterEvent;
-import org.bukkit.event.vehicle.VehicleExitEvent;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.entity.CraftEntity;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.craftbukkit.event.CraftPortalEvent;
import org.bukkit.craftbukkit.util.CraftLocation;
+import org.bukkit.entity.Hanging;
+import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Pose;
+import org.bukkit.entity.Vehicle;
import org.bukkit.event.entity.EntityAirChangeEvent;
+import org.bukkit.event.entity.EntityCombustByEntityEvent;
import org.bukkit.event.entity.EntityCombustEvent;
import org.bukkit.event.entity.EntityDismountEvent;
import org.bukkit.event.entity.EntityDropItemEvent;
@@ -158,8 +152,13 @@ import org.bukkit.event.entity.EntityMountEvent;
import org.bukkit.event.entity.EntityPortalEvent;
import org.bukkit.event.entity.EntityPoseChangeEvent;
import org.bukkit.event.entity.EntityRemoveEvent;
+import org.bukkit.event.hanging.HangingBreakByEntityEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
+import org.bukkit.event.vehicle.VehicleBlockCollisionEvent;
+import org.bukkit.event.vehicle.VehicleEnterEvent;
+import org.bukkit.event.vehicle.VehicleExitEvent;
import org.bukkit.plugin.PluginManager;
+import org.slf4j.Logger;
// CraftBukkit end
public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess, CommandSource, ScoreHolder {
@@ -704,13 +703,44 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
// CraftBukkit start
public void refreshEntityData(ServerPlayer to) {
- List<SynchedEntityData.DataValue<?>> list = this.getEntityData().getNonDefaultValues();
+ List<SynchedEntityData.DataValue<?>> list = this.entityData.packAll(); // Paper - Update EVERYTHING not just not default
- if (list != null) {
+ if (list != null && to.getBukkitEntity().canSee(this.getBukkitEntity())) { // Paper
to.connection.send(new ClientboundSetEntityDataPacket(this.getId(), list));
}
}
// CraftBukkit end
+ // Paper start
+ // This method should only be used if the data of an entity could have become desynced
+ // due to interactions on the client.
+ public void resendPossiblyDesyncedEntityData(net.minecraft.server.level.ServerPlayer player) {
+ if (this.tracker == null) {
+ return;
+ }
+
+ if (player.getBukkitEntity().canSee(this.getBukkitEntity())) {
+ final net.minecraft.server.level.ServerEntity serverEntity = this.tracker.serverEntity;
+ final List<net.minecraft.network.protocol.Packet<? super net.minecraft.network.protocol.game.ClientGamePacketListener>> list = new java.util.ArrayList<>();
+ serverEntity.sendPairingData(player, list::add);
+ player.connection.send(new net.minecraft.network.protocol.game.ClientboundBundlePacket(list));
+ }
+ }
+
+ // This method allows you to specifically resend certain data accessor keys to the client
+ public void resendPossiblyDesyncedDataValues(List<EntityDataAccessor<?>> keys, ServerPlayer to) {
+ if (!to.getBukkitEntity().canSee(this.getBukkitEntity())) {
+ return;
+ }
+
+ final List<SynchedEntityData.DataValue<?>> values = new java.util.ArrayList<>(keys.size());
+ for (final EntityDataAccessor<?> key : keys) {
+ final SynchedEntityData.DataItem<?> synchedValue = this.entityData.getItem(key);
+ values.add(synchedValue.value());
+ }
+
+ to.connection.send(new ClientboundSetEntityDataPacket(this.id, values));
+ }
+ // Paper end
public boolean equals(Object object) {
return object instanceof Entity ? ((Entity) object).id == this.id : false;
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 75e01c1e01e0782fc8af48777bbe4716d37aeafa..9ff43ff4076c658b8561c5a7abd067423830f964 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -3828,6 +3828,11 @@ public abstract class LivingEntity extends Entity implements Attackable {
return ((Byte) this.entityData.get(LivingEntity.DATA_LIVING_ENTITY_FLAGS) & 2) > 0 ? InteractionHand.OFF_HAND : InteractionHand.MAIN_HAND;
}
+ // Paper start - Properly cancel usable items
+ public void resyncUsingItem(ServerPlayer serverPlayer) {
+ this.getEntityData().resendPossiblyDesyncedDataValues(java.util.List.of(DATA_LIVING_ENTITY_FLAGS), serverPlayer);
+ }
+ // Paper end - Properly cancel usable items
private void updatingUsingItem() {
if (this.isUsingItem()) {
if (ItemStack.isSameItem(this.getItemInHand(this.getUsedItemHand()), this.useItem)) {
diff --git a/src/main/java/net/minecraft/world/entity/animal/Bucketable.java b/src/main/java/net/minecraft/world/entity/animal/Bucketable.java
index cb4a6439e9774bbec07e69b13df8dddd395b9ece..cfe37b4f5e33795ee717d824d86e3a0919129cf5 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Bucketable.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Bucketable.java
@@ -109,8 +109,7 @@ public interface Bucketable {
itemstack1 = CraftItemStack.asNMSCopy(playerBucketFishEvent.getEntityBucket());
if (playerBucketFishEvent.isCancelled()) {
((ServerPlayer) player).containerMenu.sendAllDataToRemote(); // We need to update inventory to resync client's bucket
- ((ServerPlayer) player).connection.send(new ClientboundAddEntityPacket(entity)); // We need to play out these packets as the client assumes the fish is gone
- entity.refreshEntityData((ServerPlayer) player); // Need to send data such as the display name to client
+ entity.resendPossiblyDesyncedEntityData((ServerPlayer) player); // Paper
return Optional.of(InteractionResult.FAIL);
}
entity.playSound(((Bucketable) entity).getPickupSound(), 1.0F, 1.0F);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index 3ab04c4bdbe26ff7f6f54eb9cdd58376c592fa05..f949514cf68d0ae2db754576e46f5bfc14ffdff4 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -1010,7 +1010,11 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
return;
}
- entityTracker.broadcast(this.getHandle().getAddEntityPacket());
+ // Paper start, resend possibly desynced entity instead of add entity packet
+ for (ServerPlayerConnection playerConnection : entityTracker.seenBy) {
+ this.getHandle().getEntityData().resendPossiblyDesyncedEntityData(playerConnection.getPlayer());
+ }
+ // Paper end
}
private static PermissibleBase getPermissibleBase() {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftItemFrame.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftItemFrame.java
index 0801bcdee8fcff0d388d302387e4f1d587e0a283..2fcd9b836d42e3549a3b6b921c57a4c103146dff 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftItemFrame.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftItemFrame.java
@@ -39,9 +39,11 @@ public class CraftItemFrame extends CraftHanging implements ItemFrame {
protected void update() {
super.update();
+ // Paper start, don't mark as dirty as this is handled in super.update()
// mark dirty, so that the client gets updated with item and rotation
- this.getHandle().getEntityData().markDirty(net.minecraft.world.entity.decoration.ItemFrame.DATA_ITEM);
- this.getHandle().getEntityData().markDirty(net.minecraft.world.entity.decoration.ItemFrame.DATA_ROTATION);
+ //this.getHandle().getEntityData().markDirty(net.minecraft.world.entity.decoration.ItemFrame.DATA_ITEM);
+ //this.getHandle().getEntityData().markDirty(net.minecraft.world.entity.decoration.ItemFrame.DATA_ROTATION);
+ // Paper end
// update redstone
if (!this.getHandle().generation) {

View File

@ -50,22 +50,22 @@ index 0000000000000000000000000000000000000000..5c42823726e70ce6c9d0121d07431548
+ }
+}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 636ad032f9b6b20557327e7d0b0aefff7780d1f3..2f263ef5120982b3167ab008a0e22b8cbc9b9fdd 100644
index 88549de2768149885c4eabbaaa71a38341453aed..1adcbfb16ea1fe3378cde7c53e8868840eade963 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1692,6 +1692,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1756,6 +1756,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
ServerLevel worldserver = (ServerLevel) iterator.next();
worldserver.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - BlockPhysicsEvent
worldserver.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent
+ net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = worldserver.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper - Perf: Optimize Hoppers
this.profiler.push(() -> {
return worldserver + " " + worldserver.dimension().location();
String s = String.valueOf(worldserver);
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
index 06dc04a1fbb91a5a20d662aeee168b6a319551d0..1ad126d992d95062a3db08374db7a927f23a0cac 100644
index 9510558d03faf5b704a763456c5f2d4f28bca6e8..8e5d8e146ae045797e07260e4108ba5f1e4d976d 100644
--- a/src/main/java/net/minecraft/world/item/ItemStack.java
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java
@@ -752,10 +752,16 @@ public final class ItemStack {
@@ -795,7 +795,13 @@ public final class ItemStack implements DataComponentHolder {
}
public ItemStack copy() {
@ -79,16 +79,12 @@ index 06dc04a1fbb91a5a20d662aeee168b6a319551d0..1ad126d992d95062a3db08374db7a927
+ // Paper end - Perf: Optimize Hoppers
return ItemStack.EMPTY;
} else {
- ItemStack itemstack = new ItemStack(this.getItem(), this.count);
+ ItemStack itemstack = new ItemStack(originalItem ? this.item : this.getItem(), this.count); // Paper - Perf: Optimize Hoppers
itemstack.setPopTime(this.getPopTime());
if (this.tag != null) {
ItemStack itemstack = new ItemStack(this.getItem(), this.count, this.components.copy());
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 20201430ee8f28245aa845acb172d0f5d80458ff..9ea74d37cd951e0dc76d20ed8234b5871035566c 100644
index a7dfad2696e7145af1355a5db132af14d09a6f30..b0421823684ff6b9474b81675742d2ee3b17edf7 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
@@ -26,6 +26,7 @@ import co.aikar.timings.MinecraftTimings; // Paper
@@ -37,6 +37,7 @@ import co.aikar.timings.MinecraftTimings; // Paper
import co.aikar.timings.Timing; // Paper
public abstract class BlockEntity {
@ -96,7 +92,7 @@ index 20201430ee8f28245aa845acb172d0f5d80458ff..9ea74d37cd951e0dc76d20ed8234b587
public Timing tickTimer = MinecraftTimings.getTileEntityTimings(this); // Paper
// CraftBukkit start - data containers
@@ -161,6 +162,7 @@ public abstract class BlockEntity {
@@ -210,6 +211,7 @@ public abstract class BlockEntity {
public void setChanged() {
if (this.level != null) {
@ -105,10 +101,10 @@ index 20201430ee8f28245aa845acb172d0f5d80458ff..9ea74d37cd951e0dc76d20ed8234b587
}
diff --git a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
index e3b6f2bf93710ea695b0c25c0b6968a8f24f0829..cdb739df2a285032d25d84f4464f202a7a3fa578 100644
index 43ee9017fbbe0a5485a281712f76c23b059a849b..57dc38e39a11fa51f0d27830b709fe5b7ae9dc8b 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
@@ -152,6 +152,43 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
@@ -156,6 +156,43 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
}
@ -152,15 +148,14 @@ index e3b6f2bf93710ea695b0c25c0b6968a8f24f0829..cdb739df2a285032d25d84f4464f202a
private static boolean tryMoveItems(Level world, BlockPos pos, BlockState state, HopperBlockEntity blockEntity, BooleanSupplier booleansupplier) {
if (world.isClientSide) {
return false;
@@ -159,11 +196,13 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
@@ -163,11 +200,12 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
if (!blockEntity.isOnCooldown() && (Boolean) state.getValue(HopperBlock.ENABLED)) {
boolean flag = false;
- if (!blockEntity.isEmpty()) {
+ int fullState = getFullState(blockEntity); // Paper - Perf: Optimize Hoppers
+
+ if (fullState != HOPPER_EMPTY) { // Paper - Perf: Optimize Hopperss
flag = HopperBlockEntity.ejectItems(world, pos, state, (Container) blockEntity, blockEntity); // CraftBukkit
+ final int fullState = getFullState(blockEntity); // Paper - Perf: Optimize Hoppers
+ if (fullState != HOPPER_EMPTY) { // Paper - Perf: Optimize Hoppers
flag = HopperBlockEntity.ejectItems(world, pos, blockEntity);
}
- if (!blockEntity.inventoryFull()) {
@ -168,7 +163,7 @@ index e3b6f2bf93710ea695b0c25c0b6968a8f24f0829..cdb739df2a285032d25d84f4464f202a
flag |= booleansupplier.getAsBoolean();
}
@@ -194,6 +233,202 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
@@ -198,6 +236,202 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
return false;
}
@ -368,181 +363,119 @@ index e3b6f2bf93710ea695b0c25c0b6968a8f24f0829..cdb739df2a285032d25d84f4464f202a
+ private static final java.util.function.BiPredicate<ItemStack, Integer> IS_EMPTY_TEST = (itemstack, i) -> itemstack.isEmpty();
+ // Paper end - Perf: Optimize Hoppers
+
private static boolean ejectItems(Level world, BlockPos blockposition, BlockState iblockdata, Container iinventory, HopperBlockEntity hopper) { // CraftBukkit
Container iinventory1 = HopperBlockEntity.getAttachedContainer(world, blockposition, iblockdata);
private static boolean ejectItems(Level world, BlockPos pos, HopperBlockEntity blockEntity) {
Container iinventory = HopperBlockEntity.getAttachedContainer(world, pos, blockEntity);
@@ -205,46 +440,49 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
if (HopperBlockEntity.isFullContainer(iinventory1, enumdirection)) {
@@ -209,47 +443,50 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
if (HopperBlockEntity.isFullContainer(iinventory, enumdirection)) {
return false;
} else {
- for (int i = 0; i < iinventory.getContainerSize(); ++i) {
- if (!iinventory.getItem(i).isEmpty()) {
- ItemStack itemstack = iinventory.getItem(i).copy();
- // ItemStack itemstack1 = addItem(iinventory, iinventory1, iinventory.removeItem(i, 1), enumdirection);
- for (int i = 0; i < blockEntity.getContainerSize(); ++i) {
- ItemStack itemstack = blockEntity.getItem(i);
-
- if (!itemstack.isEmpty()) {
- int j = itemstack.getCount();
- // CraftBukkit start - Call event when pushing items into other inventories
- CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot
- CraftItemStack oitemstack = CraftItemStack.asCraftMirror(blockEntity.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot
-
- Inventory destinationInventory;
- // Have to special case large chests as they work oddly
- if (iinventory1 instanceof CompoundContainer) {
- destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory1);
- } else if (iinventory1.getOwner() != null) {
- destinationInventory = iinventory1.getOwner().getInventory();
- if (iinventory instanceof CompoundContainer) {
- destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory);
- } else if (iinventory.getOwner() != null) {
- destinationInventory = iinventory.getOwner().getInventory();
- } else {
- destinationInventory = new CraftInventory(iinventory);
- }
-
- InventoryMoveItemEvent event = new InventoryMoveItemEvent(iinventory.getOwner().getInventory(), oitemstack.clone(), destinationInventory, true);
- InventoryMoveItemEvent event = new InventoryMoveItemEvent(iinventory.getOwner().getInventory(), oitemstack, destinationInventory, true);
- world.getCraftServer().getPluginManager().callEvent(event);
- if (event.isCancelled()) {
- hopper.setItem(i, itemstack);
- hopper.setCooldown(world.spigotConfig.hopperTransfer); // Spigot
- blockEntity.setItem(i, itemstack);
- blockEntity.setCooldown(world.spigotConfig.hopperTransfer); // Delay hopper checks // Spigot
- return false;
- }
- int origCount = event.getItem().getAmount(); // Spigot
- ItemStack itemstack1 = HopperBlockEntity.addItem(iinventory, iinventory1, CraftItemStack.asNMSCopy(event.getItem()), enumdirection);
+ // Paper start - replace logic; MAKE SURE TO CHECK FOR DIFFS ON UPDATES
+ return hopperPush(world, iinventory1, enumdirection, hopper);
+ // for (int i = 0; i < iinventory.getContainerSize(); ++i) {
+ // if (!iinventory.getItem(i).isEmpty()) {
+ // ItemStack itemstack = iinventory.getItem(i).copy();
+ // // ItemStack itemstack1 = addItem(iinventory, iinventory1, iinventory.removeItem(i, 1), enumdirection);
+
+ // // CraftBukkit start - Call event when pushing items into other inventories
+ // CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot
+
+ // Inventory destinationInventory;
+ // // Have to special case large chests as they work oddly
+ // if (iinventory1 instanceof CompoundContainer) {
+ // destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory1);
+ // } else if (iinventory1.getOwner() != null) {
+ // destinationInventory = iinventory1.getOwner().getInventory();
+ // } else {
+ // destinationInventory = new CraftInventory(iinventory);
+ // }
+
+ // InventoryMoveItemEvent event = new InventoryMoveItemEvent(iinventory.getOwner().getInventory(), oitemstack.clone(), destinationInventory, true);
+ // world.getCraftServer().getPluginManager().callEvent(event);
+ // if (event.isCancelled()) {
+ // hopper.setItem(i, itemstack);
+ // hopper.setCooldown(world.spigotConfig.hopperTransfer); // Spigot
+ // return false;
+ // }
+ // int origCount = event.getItem().getAmount(); // Spigot
+ // ItemStack itemstack1 = HopperBlockEntity.addItem(iinventory, iinventory1, CraftItemStack.asNMSCopy(event.getItem()), enumdirection);
// CraftBukkit end
- ItemStack itemstack1 = HopperBlockEntity.addItem(blockEntity, iinventory, CraftItemStack.asNMSCopy(event.getItem()), enumdirection);
- // CraftBukkit end
-
- if (itemstack1.isEmpty()) {
- iinventory1.setChanged();
- iinventory.setChanged();
- return true;
- }
+ // if (itemstack1.isEmpty()) {
+ // iinventory1.setChanged();
+ // return true;
+ // }
- itemstack.shrink(origCount - itemstack1.getCount()); // Spigot
- iinventory.setItem(i, itemstack);
-
- itemstack.setCount(j);
- if (j == 1) {
- blockEntity.setItem(i, itemstack);
- }
- }
- }
+ // itemstack.shrink(origCount - itemstack1.getCount()); // Spigot
+ // iinventory.setItem(i, itemstack);
+ // }
+ // }
-
- return false;
+ // Paper start - Perf: Optimize Hoppers
+ return hopperPush(world, iinventory, enumdirection, blockEntity);
+ //for (int i = 0; i < blockEntity.getContainerSize(); ++i) {
+ // ItemStack itemstack = blockEntity.getItem(i);
+
+ // if (!itemstack.isEmpty()) {
+ // int j = itemstack.getCount();
+ // // CraftBukkit start - Call event when pushing items into other inventories
+ // CraftItemStack oitemstack = CraftItemStack.asCraftMirror(blockEntity.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot
+
+ // Inventory destinationInventory;
+ // // Have to special case large chests as they work oddly
+ // if (iinventory instanceof CompoundContainer) {
+ // destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory);
+ // } else if (iinventory.getOwner() != null) {
+ // destinationInventory = iinventory.getOwner().getInventory();
+ // } else {
+ // destinationInventory = new CraftInventory(iinventory);
+ // }
+
+ // InventoryMoveItemEvent event = new InventoryMoveItemEvent(iinventory.getOwner().getInventory(), oitemstack, destinationInventory, true);
+ // world.getCraftServer().getPluginManager().callEvent(event);
+ // if (event.isCancelled()) {
+ // blockEntity.setItem(i, itemstack);
+ // blockEntity.setCooldown(world.spigotConfig.hopperTransfer); // Delay hopper checks // Spigot
+ // return false;
+ // }
+ // ItemStack itemstack1 = HopperBlockEntity.addItem(blockEntity, iinventory, CraftItemStack.asNMSCopy(event.getItem()), enumdirection);
+ // // CraftBukkit end
+
+ // if (itemstack1.isEmpty()) {
+ // iinventory.setChanged();
+ // return true;
+ // }
+
+ // itemstack.setCount(j);
+ // if (j == 1) {
+ // blockEntity.setItem(i, itemstack);
+ // }
+ // }
+ //}
+
+ // return false;
+ // Paper end - Perf: Optimize Hoppers
}
}
}
@@ -254,17 +492,29 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
}
private static boolean isFullContainer(Container inventory, Direction direction) {
- return HopperBlockEntity.getSlots(inventory, direction).allMatch((i) -> {
- ItemStack itemstack = inventory.getItem(i);
@@ -300,7 +537,6 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
return false;
}
}
-
- return itemstack.getCount() >= itemstack.getMaxStackSize();
- });
+ // Paper start - Perf: Optimize Hoppers
+ if (inventory instanceof WorldlyContainer worldlyContainer) {
+ for (final int slot : worldlyContainer.getSlotsForFace(direction)) {
+ final ItemStack stack = inventory.getItem(slot);
+ if (stack.getCount() < stack.getMaxStackSize()) {
+ return false;
+ }
+ }
+ return true;
+ } else {
+ for (int slot = 0, max = inventory.getContainerSize(); slot < max; ++slot) {
+ final ItemStack stack = inventory.getItem(slot);
+ if (stack.getCount() < stack.getMaxStackSize()) {
+ return false;
+ }
+ }
+ return true;
+ }
+ // Paper end - Perf: Optimize Hoppers
return true;
}
private static boolean isEmptyContainer(Container inv, Direction facing) {
- return HopperBlockEntity.getSlots(inv, facing).allMatch((i) -> {
- return inv.getItem(i).isEmpty();
- });
+ return allMatch(inv, facing, IS_EMPTY_TEST); // Paper - Perf: Optimize Hoppers
}
public static boolean suckInItems(Level world, Hopper hopper) {
@@ -273,9 +523,33 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
if (iinventory != null) {
Direction enumdirection = Direction.DOWN;
- return HopperBlockEntity.isEmptyContainer(iinventory, enumdirection) ? false : HopperBlockEntity.getSlots(iinventory, enumdirection).anyMatch((i) -> {
- return HopperBlockEntity.a(hopper, iinventory, i, enumdirection, world); // Spigot
- });
+ // Paper start - Perf: Optimize Hoppers
+ skipPullModeEventFire = skipHopperEvents;
+ // merge container isEmpty check and move logic into one loop
+ if (iinventory instanceof WorldlyContainer worldlyContainer) {
+ for (final int slot : worldlyContainer.getSlotsForFace(enumdirection)) {
+ ItemStack item = worldlyContainer.getItem(slot);
+ if (item.isEmpty() || !canTakeItemFromContainer(hopper, iinventory, item, slot, enumdirection)) {
+ continue;
+ }
+ if (hopperPull(world, hopper, iinventory, item, slot)) {
+ return true;
+ }
+ }
+ return false;
+ } else {
+ for (int slot = 0, max = iinventory.getContainerSize(); slot < max; ++slot) {
+ ItemStack item = iinventory.getItem(slot);
+ if (item.isEmpty() || !canTakeItemFromContainer(hopper, iinventory, item, slot, enumdirection)) {
+ continue;
+ }
+ if (hopperPull(world, hopper, iinventory, item, slot)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ // Paper end - Perf: Optimize Hoppers
} else {
Iterator iterator = HopperBlockEntity.getItemsAtAndAbove(world, hopper).iterator();
@@ -293,48 +567,52 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
@@ -342,48 +578,52 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
}
}
+ @io.papermc.paper.annotation.DoNotUse // Paper - method unused as logic is inlined above
private static boolean a(Hopper ihopper, Container iinventory, int i, Direction enumdirection, Level world) { // Spigot
+ @io.papermc.paper.annotation.DoNotUse // Paper - Optimize hoppers
private static boolean tryTakeInItemFromSlot(Hopper ihopper, Container iinventory, int i, Direction enumdirection, Level world) { // Spigot
ItemStack itemstack = iinventory.getItem(i);
- if (!itemstack.isEmpty() && HopperBlockEntity.canTakeItemFromContainer(ihopper, iinventory, itemstack, i, enumdirection)) {
- ItemStack itemstack1 = itemstack.copy();
- // ItemStack itemstack2 = addItem(iinventory, ihopper, iinventory.removeItem(i, 1), (EnumDirection) null);
if (!itemstack.isEmpty() && HopperBlockEntity.canTakeItemFromContainer(ihopper, iinventory, itemstack, i, enumdirection)) {
- int j = itemstack.getCount();
- // CraftBukkit start - Call event on collection of items from inventories into the hopper
- CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot
-
@ -556,11 +489,11 @@ index e3b6f2bf93710ea695b0c25c0b6968a8f24f0829..cdb739df2a285032d25d84f4464f202a
- sourceInventory = new CraftInventory(iinventory);
- }
-
- InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory, oitemstack.clone(), ihopper.getOwner().getInventory(), false);
- InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory, oitemstack, ihopper.getOwner().getInventory(), false);
-
- Bukkit.getServer().getPluginManager().callEvent(event);
- if (event.isCancelled()) {
- iinventory.setItem(i, itemstack1);
- iinventory.setItem(i, itemstack);
-
- if (ihopper instanceof HopperBlockEntity) {
- ((HopperBlockEntity) ihopper).setCooldown(world.spigotConfig.hopperTransfer); // Spigot
@ -568,63 +501,63 @@ index e3b6f2bf93710ea695b0c25c0b6968a8f24f0829..cdb739df2a285032d25d84f4464f202a
-
- return false;
- }
- int origCount = event.getItem().getAmount(); // Spigot
- ItemStack itemstack2 = HopperBlockEntity.addItem(iinventory, ihopper, CraftItemStack.asNMSCopy(event.getItem()), null);
- ItemStack itemstack1 = HopperBlockEntity.addItem(iinventory, ihopper, CraftItemStack.asNMSCopy(event.getItem()), null);
- // CraftBukkit end
-
- if (itemstack2.isEmpty()) {
- if (itemstack1.isEmpty()) {
- iinventory.setChanged();
- return true;
- }
-
- itemstack1.shrink(origCount - itemstack2.getCount()); // Spigot
- iinventory.setItem(i, itemstack1);
+ // Paper start - Perf: Optimize Hoppers; replace pull logic; MAKE SURE TO CHECK FOR DIFFS WHEN UPDATING
+ if (!itemstack.isEmpty() && HopperBlockEntity.canTakeItemFromContainer(ihopper, iinventory, itemstack, i, enumdirection)) { // If this logic changes, update above. this is left unused incase reflective plugins
- itemstack.setCount(j);
- if (j == 1) {
- iinventory.setItem(i, itemstack);
- }
+ // Paper start - Perf: Optimize Hoppers
+ return hopperPull(world, ihopper, iinventory, itemstack, i);
+ // ItemStack itemstack1 = itemstack.copy();
+ // // ItemStack itemstack2 = addItem(iinventory, ihopper, iinventory.removeItem(i, 1), (EnumDirection) null);
+ // // CraftBukkit start - Call event on collection of items from inventories into the hopper
+ // CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot
+ // int j = itemstack.getCount();
+ // // CraftBukkit start - Call event on collection of items from inventories into the hopper
+ // CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot
+
+ // Inventory sourceInventory;
+ // // Have to special case large chests as they work oddly
+ // if (iinventory instanceof CompoundContainer) {
+ // sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory);
+ // } else if (iinventory.getOwner() != null) {
+ // sourceInventory = iinventory.getOwner().getInventory();
+ // } else {
+ // sourceInventory = new CraftInventory(iinventory);
+ // }
+ // Inventory sourceInventory;
+ // // Have to special case large chests as they work oddly
+ // if (iinventory instanceof CompoundContainer) {
+ // sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory);
+ // } else if (iinventory.getOwner() != null) {
+ // sourceInventory = iinventory.getOwner().getInventory();
+ // } else {
+ // sourceInventory = new CraftInventory(iinventory);
+ // }
+
+ // InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory, oitemstack.clone(), ihopper.getOwner().getInventory(), false);
+ // InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory, oitemstack, ihopper.getOwner().getInventory(), false);
+
+ // Bukkit.getServer().getPluginManager().callEvent(event);
+ // if (event.isCancelled()) {
+ // iinventory.setItem(i, itemstack1);
+ // Bukkit.getServer().getPluginManager().callEvent(event);
+ // if (event.isCancelled()) {
+ // iinventory.setItem(i, itemstack);
+
+ // if (ihopper instanceof HopperBlockEntity) {
+ // ((HopperBlockEntity) ihopper).setCooldown(world.spigotConfig.hopperTransfer); // Spigot
+ // }
+ // if (ihopper instanceof HopperBlockEntity) {
+ // ((HopperBlockEntity) ihopper).setCooldown(world.spigotConfig.hopperTransfer); // Spigot
+ // }
+
+ // return false;
+ // }
+ // int origCount = event.getItem().getAmount(); // Spigot
+ // ItemStack itemstack2 = HopperBlockEntity.addItem(iinventory, ihopper, CraftItemStack.asNMSCopy(event.getItem()), null);
+ // // CraftBukkit end
+ // return false;
+ // }
+ // ItemStack itemstack1 = HopperBlockEntity.addItem(iinventory, ihopper, CraftItemStack.asNMSCopy(event.getItem()), null);
+ // // CraftBukkit end
+
+ // if (itemstack2.isEmpty()) {
+ // iinventory.setChanged();
+ // return true;
+ // }
+ // if (itemstack1.isEmpty()) {
+ // iinventory.setChanged();
+ // return true;
+ // }
+
+ // itemstack1.shrink(origCount - itemstack2.getCount()); // Spigot
+ // iinventory.setItem(i, itemstack1);
+ // itemstack.setCount(j);
+ // if (j == 1) {
+ // iinventory.setItem(i, itemstack);
+ // }
+ // Paper end - Perf: Optimize Hoppers
}
return false;
@@ -343,12 +621,14 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
@@ -392,12 +632,14 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
public static boolean addItem(Container inventory, ItemEntity itemEntity) {
boolean flag = false;
// CraftBukkit start
@ -640,7 +573,7 @@ index e3b6f2bf93710ea695b0c25c0b6968a8f24f0829..cdb739df2a285032d25d84f4464f202a
ItemStack itemstack = itemEntity.getItem().copy();
ItemStack itemstack1 = HopperBlockEntity.addItem((Container) null, inventory, itemstack, (Direction) null);
@@ -444,7 +724,9 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
@@ -491,7 +733,9 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
stack = stack.split(to.getMaxStackSize());
}
// Spigot end
@ -650,101 +583,55 @@ index e3b6f2bf93710ea695b0c25c0b6968a8f24f0829..cdb739df2a285032d25d84f4464f202a
stack = leftover; // Paper - Make hoppers respect inventory max stack size
flag = true;
} else if (HopperBlockEntity.canMergeItems(itemstack1, stack)) {
@@ -518,19 +800,47 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
// CraftBukkit end
}
+ // Paper start - Perf: Optimize Hoppers
+ static final AABB HOPPER_ITEM_SUCK_OVERALL = Hopper.SUCK.bounds();
+ static final AABB[] HOPPER_ITEM_SUCK_INDIVIDUAL = Hopper.SUCK.toAabbs().toArray(new AABB[0]);
+ // Paper end - Perf: Optimize Hoppers
+
public static List<ItemEntity> getItemsAtAndAbove(Level world, Hopper hopper) {
- return (List) hopper.getSuckShape().toAabbs().stream().flatMap((axisalignedbb) -> {
- return world.getEntitiesOfClass(ItemEntity.class, axisalignedbb.move(hopper.getLevelX() - 0.5D, hopper.getLevelY() - 0.5D, hopper.getLevelZ() - 0.5D), EntitySelector.ENTITY_STILL_ALIVE).stream();
- }).collect(Collectors.toList());
+ // Paper start - Perf: Optimize Hoppers
+ // eliminate multiple getEntitiesOfClass() but maintain the voxelshape collision by moving
+ // the individual AABB checks into the predicate
+ final double shiftX = hopper.getLevelX() - 0.5D;
+ final double shiftY = hopper.getLevelY() - 0.5D;
+ final double shiftZ = hopper.getLevelZ() - 0.5D;
+ return world.getEntitiesOfClass(ItemEntity.class, HOPPER_ITEM_SUCK_OVERALL.move(shiftX, shiftY, shiftZ), (final Entity entity) -> {
+ if (!entity.isAlive()) { // EntitySelector.ENTITY_STILL_ALIVE
+ return false;
+ }
+
+ for (final AABB aabb : HOPPER_ITEM_SUCK_INDIVIDUAL) {
+ if (aabb.move(shiftX, shiftY, shiftZ).intersects(entity.getBoundingBox())) {
+ return true;
+ }
+ }
+
+ return false;
+ });
+ // Paper end - Perf: Optimize Hoppers
}
@@ -571,14 +815,20 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
@Nullable
public static Container getContainerAt(Level world, BlockPos pos) {
- return HopperBlockEntity.getContainerAt(world, (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D);
+ return HopperBlockEntity.getContainerAt(world, (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, true); // Paper - Perf: Optimize Hoppers
- return HopperBlockEntity.getContainerAt(world, pos, world.getBlockState(pos), (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D);
+ return HopperBlockEntity.getContainerAt(world, pos, world.getBlockState(pos), (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, true);
}
@Nullable
private static Container getContainerAt(Level world, double x, double y, double z) {
private static Container getContainerAt(Level world, BlockPos pos, BlockState state, double x, double y, double z) {
+ // Paper start - Perf: Optimize Hoppers
+ return HopperBlockEntity.getContainerAt(world, x, y, z, false);
+ return HopperBlockEntity.getContainerAt(world, pos, state, x, y, z, false);
+ }
+ @Nullable
+ private static Container getContainerAt(Level world, double x, double y, double z, final boolean optimizeEntities) {
+ private static Container getContainerAt(Level world, BlockPos pos, BlockState state, double x, double y, double z, boolean optimizeEntities) {
+ // Paper end - Perf: Optimize Hoppers
Object object = null;
BlockPos blockposition = BlockPos.containing(x, y, z);
if ( !world.spigotConfig.hopperCanLoadChunks && !world.hasChunkAt( blockposition ) ) return null; // Spigot
@@ -550,8 +860,8 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
}
Container iinventory = HopperBlockEntity.getBlockContainer(world, pos, state);
- if (iinventory == null) {
+ if (iinventory == null && (!optimizeEntities || !world.paperConfig().hopper.ignoreOccludingBlocks || !state.getBukkitMaterial().isOccluding())) { // Paper - Perf: Optimize Hoppers
iinventory = HopperBlockEntity.getEntityContainer(world, x, y, z);
}
- if (object == null) {
- List<Entity> list = world.getEntities((Entity) null, new AABB(x - 0.5D, y - 0.5D, z - 0.5D, x + 0.5D, y + 0.5D, z + 0.5D), EntitySelector.CONTAINER_ENTITY_SELECTOR);
+ if (object == null && (!optimizeEntities || !world.paperConfig().hopper.ignoreOccludingBlocks || !iblockdata.getBukkitMaterial().isOccluding())) { // Paper - Perf: Optimize Hoppers
+ List<Entity> list = world.getEntitiesOfClass((Class)Container.class, new AABB(x - 0.5D, y - 0.5D, z - 0.5D, x + 0.5D, y + 0.5D, z + 0.5D), EntitySelector.CONTAINER_ENTITY_SELECTOR); // Paper - Perf: Optimize Hoppers
@@ -613,13 +863,13 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
if (!list.isEmpty()) {
object = (Container) list.get(world.random.nextInt(list.size()));
@@ -562,7 +872,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
@Nullable
private static Container getEntityContainer(Level world, double x, double y, double z) {
- List<Entity> list = world.getEntities((Entity) null, new AABB(x - 0.5D, y - 0.5D, z - 0.5D, x + 0.5D, y + 0.5D, z + 0.5D), EntitySelector.CONTAINER_ENTITY_SELECTOR);
+ List<Entity> list = world.getEntitiesOfClass((Class) Container.class, new AABB(x - 0.5D, y - 0.5D, z - 0.5D, x + 0.5D, y + 0.5D, z + 0.5D), EntitySelector.CONTAINER_ENTITY_SELECTOR); // Paper - Perf: Optimize hoppers
return !list.isEmpty() ? (Container) list.get(world.random.nextInt(list.size())) : null;
}
private static boolean canMergeItems(ItemStack first, ItemStack second) {
- return first.getCount() <= first.getMaxStackSize() && ItemStack.isSameItemSameTags(first, second);
+ return first.getCount() < first.getMaxStackSize() && first.is(second.getItem()) && first.getDamageValue() == second.getDamageValue() && ((first.isEmpty() && second.isEmpty()) || java.util.Objects.equals(first.getTag(), second.getTag())); // Paper - Perf: Optimize Hoppers; used to return true for full itemstacks?!
- return first.getCount() <= first.getMaxStackSize() && ItemStack.isSameItemSameComponents(first, second);
+ return first.getCount() < first.getMaxStackSize() && ItemStack.isSameItemSameComponents(first, second); // Paper - Perf: Optimize Hoppers; used to return true for full itemstacks?!
}
@Override
diff --git a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
index f33c4633094002a3dd0c54353b62f7b358628be3..dfd1246b735fe64c5beae83567a013861eb00822 100644
index 6a6473ebf03e5b1e502db7e66203783b9980d072..674c3c2b3cc2c00a8830900baf797bc20f154fe7 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
@@ -93,12 +93,19 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc
@Override
public boolean isEmpty() {
this.unpackLootTable(null);
- return this.getItems().stream().allMatch(ItemStack::isEmpty);
+ // Paper start - Perf: Optimize Hoppers
+ for (final ItemStack itemStack : this.getItems()) {
+ if (!itemStack.isEmpty()) {
+ return false;
+ }
+ }
+ return true;
+ // Paper end - Perf: Optimize Hoppers
}
@@ -105,7 +105,7 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc
@Override
public ItemStack getItem(int slot) {
- this.unpackLootTable(null);
+ if (slot == 0) this.unpackLootTable(null); // Paper - Perf: Optimize Hoppers
return this.getItems().get(slot);
return super.getItem(slot);
}

View File

@ -1,216 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Wed, 7 Dec 2022 17:25:19 -0500
Subject: [PATCH] Properly resend entities
This resolves some issues which caused entities to not be resent correctly.
Entities that are interacted with need to be resent to the client, so we resend all the entity
data to the player whilst making sure not to clear dirty entries from the tracker. This makes
sure that values will be correctly updated to other players.
This also adds utilities to aid in further preventing entity desyncs.
This also also fixes the bug causing cancelling PlayerInteractEvent to cause items to continue
to be used despite being cancelled on the server.
For example, items being consumed but never finishing, shields being put up, etc.
The underlying issue of this is that the client modifies their synced data values,
and so we have to (forcibly) resend them in order for the client to reset their using item state.
See: https://github.com/PaperMC/Paper/pull/1896
== AT ==
public net.minecraft.server.level.ChunkMap$TrackedEntity serverEntity
diff --git a/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java b/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java
index 07a362f9e485d0d507f16f1dda1ac84ade07ab27..58b602e550258c1062ee940bc46538dac95d8979 100644
--- a/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java
+++ b/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java
@@ -275,14 +275,63 @@ public class SynchedEntityData {
// CraftBukkit start
public void refresh(ServerPlayer to) {
if (!this.isEmpty()) {
- List<SynchedEntityData.DataValue<?>> list = this.getNonDefaultValues();
+ List<SynchedEntityData.DataValue<?>> list = this.packAll(); // Paper - Update EVERYTHING not just not default
if (list != null) {
+ if (to.getBukkitEntity().canSee(this.entity.getBukkitEntity())) { // Paper
to.connection.send(new ClientboundSetEntityDataPacket(this.entity.getId(), list));
+ } // Paper
}
}
}
// CraftBukkit end
+ // Paper start
+ // We need to pack all as we cannot rely on "non default values" or "dirty" ones.
+ // Because these values can possibly be desynced on the client.
+ @Nullable
+ private List<SynchedEntityData.DataValue<?>> packAll() {
+ if (this.isEmpty()) {
+ return null;
+ }
+
+ List<SynchedEntityData.DataValue<?>> list = new ArrayList<>();
+ for (DataItem<?> dataItem : this.itemsById.values()) {
+ list.add(dataItem.value());
+ }
+
+ return list;
+ }
+
+ // This method should only be used if the data of an entity could have became desynced
+ // due to interactions on the client.
+ public void resendPossiblyDesyncedEntity(ServerPlayer player) {
+ if (this.entity.tracker == null) {
+ return;
+ }
+
+ if (player.getBukkitEntity().canSee(entity.getBukkitEntity())) {
+ net.minecraft.server.level.ServerEntity serverEntity = this.entity.tracker.serverEntity;
+
+ List<net.minecraft.network.protocol.Packet<net.minecraft.network.protocol.game.ClientGamePacketListener>> list = new ArrayList<>();
+ serverEntity.sendPairingData(player, list::add);
+ player.connection.send(new net.minecraft.network.protocol.game.ClientboundBundlePacket(list));
+ }
+ }
+
+ // This method allows you to specifically resend certain data accessor keys to the client
+ public void resendPossiblyDesyncedDataValues(List<EntityDataAccessor<?>> keys, ServerPlayer to) {
+ if (!to.getBukkitEntity().canSee(this.entity.getBukkitEntity())) {
+ return;
+ }
+ List<SynchedEntityData.DataValue<?>> values = new ArrayList<>(keys.size());
+ for (EntityDataAccessor<?> key : keys) {
+ SynchedEntityData.DataItem<?> synchedValue = this.getItem(key);
+ values.add(synchedValue.value());
+ }
+
+ to.connection.send(new ClientboundSetEntityDataPacket(this.entity.getId(), values));
+ }
+ // Paper end
public static class DataItem<T> {
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
index 692a01b52a71e26887ee42cbd5fd64b0a81bfc99..ef3048a4748113538a0ee0af5b526b2cd51d5c29 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
@@ -561,6 +561,7 @@ public class ServerPlayerGameMode {
}
// Paper end - extend Player Interact cancellation
player.getBukkitEntity().updateInventory(); // SPIGOT-2867
+ this.player.resyncUsingItem(this.player); // Paper - Properly cancel usable items
enuminteractionresult = (event.useItemInHand() != Event.Result.ALLOW) ? InteractionResult.SUCCESS : InteractionResult.PASS;
} else if (this.gameModeForPlayer == GameType.SPECTATOR) {
MenuProvider itileinventory = iblockdata.getMenuProvider(world, blockposition);
@@ -604,6 +605,11 @@ public class ServerPlayerGameMode {
return enuminteractionresult1;
}
+ // Paper start - Properly cancel usable items; Cancel only if cancelled + if the interact result is different from default response
+ else if (this.interactResult && this.interactResult != cancelledItem) {
+ this.player.resyncUsingItem(this.player);
+ }
+ // Paper end - Properly cancel usable items
}
return enuminteractionresult;
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index d0ae2c485b0e37406633c79043bd833a8a6b3e2d..b8db3c3a5870e9d7dbba38caf7c9e1c1f3849bde 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -1990,6 +1990,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
}
if (cancelled) {
+ this.player.resyncUsingItem(this.player); // Paper - Properly cancel usable items
this.player.getBukkitEntity().updateInventory(); // SPIGOT-2524
return;
}
@@ -2708,7 +2709,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
// Entity in bucket - SPIGOT-4048 and SPIGOT-6859a
if ((entity instanceof Bucketable && entity instanceof LivingEntity && origItem != null && origItem.asItem() == Items.WATER_BUCKET) && (event.isCancelled() || ServerGamePacketListenerImpl.this.player.getInventory().getSelected() == null || ServerGamePacketListenerImpl.this.player.getInventory().getSelected().getItem() != origItem)) {
- ServerGamePacketListenerImpl.this.send(new ClientboundAddEntityPacket(entity));
+ entity.getEntityData().resendPossiblyDesyncedEntity(player); // Paper - The entire mob gets deleted, so resend it.
ServerGamePacketListenerImpl.this.player.containerMenu.sendAllDataToRemote();
}
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 97b0119ac71284b3a223c089bec26d87a01d3b25..1e5f709115007ff19901c0a6c3cf884d9e4d3a6c 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -391,7 +391,7 @@ public abstract class PlayerList {
((ServerLevel)player.level()).getChunkSource().chunkMap.addEntity(player); // Paper - Fire PlayerJoinEvent when Player is actually ready; track entity now
// CraftBukkit end
- player.getEntityData().refresh(player); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn
+ //player.getEntityData().refresh(player); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn Paper - THIS IS NOT NEEDED ANYMORE
this.sendLevelInfo(player, worldserver1);
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index a9d549d1f35928b7e9220e1e2e4ac30f3199ba2d..28b4e9ebc35058c3e094c1f8bd87130e288cea33 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -3844,6 +3844,11 @@ public abstract class LivingEntity extends Entity implements Attackable {
return ((Byte) this.entityData.get(LivingEntity.DATA_LIVING_ENTITY_FLAGS) & 2) > 0 ? InteractionHand.OFF_HAND : InteractionHand.MAIN_HAND;
}
+ // Paper start - Properly cancel usable items
+ public void resyncUsingItem(ServerPlayer serverPlayer) {
+ this.getEntityData().resendPossiblyDesyncedDataValues(java.util.List.of(DATA_LIVING_ENTITY_FLAGS), serverPlayer);
+ }
+ // Paper end - Properly cancel usable items
private void updatingUsingItem() {
if (this.isUsingItem()) {
if (ItemStack.isSameItem(this.getItemInHand(this.getUsedItemHand()), this.useItem)) {
diff --git a/src/main/java/net/minecraft/world/entity/animal/Bucketable.java b/src/main/java/net/minecraft/world/entity/animal/Bucketable.java
index a1bfd700cd4c39e4bb1b9c140b54b7c82cd8b32c..205b52e486123aa23a1469de896ab1ec2e70ca13 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Bucketable.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Bucketable.java
@@ -110,8 +110,7 @@ public interface Bucketable {
itemstack1 = CraftItemStack.asNMSCopy(playerBucketFishEvent.getEntityBucket());
if (playerBucketFishEvent.isCancelled()) {
((ServerPlayer) player).containerMenu.sendAllDataToRemote(); // We need to update inventory to resync client's bucket
- ((ServerPlayer) player).connection.send(new ClientboundAddEntityPacket(entity)); // We need to play out these packets as the client assumes the fish is gone
- entity.getEntityData().refresh((ServerPlayer) player); // Need to send data such as the display name to client
+ entity.getEntityData().resendPossiblyDesyncedEntity((ServerPlayer) player); // Paper
return Optional.of(InteractionResult.FAIL);
}
entity.playSound(((Bucketable) entity).getPickupSound(), 1.0F, 1.0F);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index 76193067a21ff962cf2634b36d0ddf3eff8f85d7..e8e4489bcd64fde1b3226bdc7a7cc612508bda3f 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -1000,7 +1000,11 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
return;
}
- entityTracker.broadcast(this.getHandle().getAddEntityPacket());
+ // Paper start, resend possibly desynced entity instead of add entity packet
+ for (ServerPlayerConnection playerConnection : entityTracker.seenBy) {
+ this.getHandle().getEntityData().resendPossiblyDesyncedEntity(playerConnection.getPlayer());
+ }
+ // Paper end
}
private static PermissibleBase getPermissibleBase() {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftItemFrame.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftItemFrame.java
index 0801bcdee8fcff0d388d302387e4f1d587e0a283..2fcd9b836d42e3549a3b6b921c57a4c103146dff 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftItemFrame.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftItemFrame.java
@@ -39,9 +39,11 @@ public class CraftItemFrame extends CraftHanging implements ItemFrame {
protected void update() {
super.update();
+ // Paper start, don't mark as dirty as this is handled in super.update()
// mark dirty, so that the client gets updated with item and rotation
- this.getHandle().getEntityData().markDirty(net.minecraft.world.entity.decoration.ItemFrame.DATA_ITEM);
- this.getHandle().getEntityData().markDirty(net.minecraft.world.entity.decoration.ItemFrame.DATA_ROTATION);
+ //this.getHandle().getEntityData().markDirty(net.minecraft.world.entity.decoration.ItemFrame.DATA_ITEM);
+ //this.getHandle().getEntityData().markDirty(net.minecraft.world.entity.decoration.ItemFrame.DATA_ROTATION);
+ // Paper end
// update redstone
if (!this.getHandle().generation) {