2024-12-20 23:18:34 +01:00
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
2021-12-05 11:56:09 +01:00
Date: Thu, 2 Jul 2020 12:02:43 -0700
Subject: [PATCH] Optimise collision checking in player move packet handling
Move collision logic to just the hasNewCollision call instead of getCubes + hasNewCollision
2024-12-17 12:46:53 +01:00
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
2024-12-20 23:18:34 +01:00
index e4869774b2a8096467e5913d73af5bde93dbcccf..e3c855b9335f3d86ba933e7acdd3fa2981919c99 100644
2024-12-17 12:46:53 +01:00
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
2024-12-20 23:18:34 +01:00
@@ -561,7 +561,7 @@ public class ServerGamePacketListenerImpl
2021-12-05 11:56:09 +01:00
return;
}
2024-12-17 12:46:53 +01:00
- boolean flag = serverLevel.noCollision(rootVehicle, rootVehicle.getBoundingBox().deflate(0.0625));
+ AABB oldBox = rootVehicle.getBoundingBox(); // Paper - copy from player movement packet
d3 = d - this.vehicleLastGoodX; // Paper - diff on change, used for checking large move vectors above
d4 = d1 - this.vehicleLastGoodY; // Paper - diff on change, used for checking large move vectors above
d5 = d2 - this.vehicleLastGoodZ; // Paper - diff on change, used for checking large move vectors above
2024-12-20 23:18:34 +01:00
@@ -571,6 +571,7 @@ public class ServerGamePacketListenerImpl
2023-06-08 09:20:03 +02:00
}
2022-03-01 06:43:03 +01:00
2024-12-17 12:46:53 +01:00
rootVehicle.move(MoverType.PLAYER, new Vec3(d3, d4, d5));
+ boolean didCollide = toX != rootVehicle.getX() || toY != rootVehicle.getY() || toZ != rootVehicle.getZ(); // Paper - needed here as the difference in Y can be reset - also note: this is only a guess at whether collisions took place, floating point errors can make this true when it shouldn't be...
d3 = d - rootVehicle.getX();
d4 = d1 - rootVehicle.getY();
if (d4 > -0.5 || d4 < 0.5) {
2024-12-20 23:18:34 +01:00
@@ -581,14 +582,22 @@ public class ServerGamePacketListenerImpl
2024-12-17 12:46:53 +01:00
d7 = d3 * d3 + d4 * d4 + d5 * d5;
2022-03-01 06:43:03 +01:00
boolean flag2 = false;
2024-12-17 12:46:53 +01:00
if (d7 > org.spigotmc.SpigotConfig.movedWronglyThreshold) { // Spigot
2022-03-01 06:43:03 +01:00
- flag2 = true;
+ flag2 = true; // Paper - diff on change, this should be moved wrongly
2024-12-17 12:46:53 +01:00
LOGGER.warn("{} (vehicle of {}) moved wrongly! {}", rootVehicle.getName().getString(), this.player.getName().getString(), Math.sqrt(d7));
2021-12-05 11:56:09 +01:00
}
2024-12-17 12:46:53 +01:00
rootVehicle.absMoveTo(d, d1, d2, f, f1);
this.player.absMoveTo(d, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit
- boolean flag3 = serverLevel.noCollision(rootVehicle, rootVehicle.getBoundingBox().deflate(0.0625));
2022-03-01 06:43:03 +01:00
- if (flag && (flag2 || !flag3)) {
2021-12-05 11:56:09 +01:00
+ // Paper start - optimise out extra getCubes
2022-03-01 06:43:03 +01:00
+ boolean teleportBack = flag2; // violating this is always a fail
2021-12-05 11:56:09 +01:00
+ if (!teleportBack) {
+ // note: only call after setLocation, or else getBoundingBox is wrong
2024-12-17 12:46:53 +01:00
+ AABB newBox = rootVehicle.getBoundingBox();
2021-12-05 11:56:09 +01:00
+ if (didCollide || !oldBox.equals(newBox)) {
2024-12-17 12:46:53 +01:00
+ teleportBack = this.hasNewCollision(serverLevel, rootVehicle, oldBox, newBox);
2021-12-05 11:56:09 +01:00
+ } // else: no collision at all detected, why do we care?
+ }
+ if (teleportBack) { // Paper end - optimise out extra getCubes
2024-12-17 12:46:53 +01:00
rootVehicle.absMoveTo(x, y, z, f, f1);
this.player.absMoveTo(x, y, z, this.player.getYRot(), this.player.getXRot()); // CraftBukkit
this.send(ClientboundMoveVehiclePacket.fromEntity(rootVehicle));
2024-12-20 23:18:34 +01:00
@@ -666,9 +675,32 @@ public class ServerGamePacketListenerImpl
2021-12-05 11:56:09 +01:00
}
private boolean noBlocksAround(Entity entity) {
2024-12-17 12:46:53 +01:00
- return entity.level()
- .getBlockStates(entity.getBoundingBox().inflate(0.0625).expandTowards(0.0, -0.55, 0.0))
- .allMatch(BlockBehaviour.BlockStateBase::isAir);
2021-12-05 11:56:09 +01:00
+ // Paper start - stop using streams, this is already a known fixed problem in Entity#move
2024-12-17 12:46:53 +01:00
+ AABB box = entity.getBoundingBox().inflate(0.0625).expandTowards(0.0, -0.55, 0.0);
2021-12-05 11:56:09 +01:00
+ int minX = Mth.floor(box.minX);
+ int minY = Mth.floor(box.minY);
+ int minZ = Mth.floor(box.minZ);
+ int maxX = Mth.floor(box.maxX);
+ int maxY = Mth.floor(box.maxY);
+ int maxZ = Mth.floor(box.maxZ);
+
2024-12-17 12:46:53 +01:00
+ Level level = entity.level();
2021-12-05 11:56:09 +01:00
+ BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
+
+ for (int y = minY; y <= maxY; ++y) {
+ for (int z = minZ; z <= maxZ; ++z) {
+ for (int x = minX; x <= maxX; ++x) {
+ pos.set(x, y, z);
2024-12-17 12:46:53 +01:00
+ BlockState blockState = level.getBlockStateIfLoaded(pos);
+ if (blockState != null && !blockState.isAir()) {
2021-12-05 11:56:09 +01:00
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ // Paper end - stop using streams, this is already a known fixed problem in Entity#move
}
@Override
2024-12-20 23:18:34 +01:00
@@ -1360,7 +1392,7 @@ public class ServerGamePacketListenerImpl
2021-12-05 11:56:09 +01:00
}
}
2024-12-17 12:46:53 +01:00
- AABB boundingBox = this.player.getBoundingBox();
+ AABB boundingBox = this.player.getBoundingBox(); // Paper - diff on change, should be old AABB
d3 = d - this.lastGoodX; // Paper - diff on change, used for checking large move vectors above
d4 = d1 - this.lastGoodY; // Paper - diff on change, used for checking large move vectors above
d5 = d2 - this.lastGoodZ; // Paper - diff on change, used for checking large move vectors above
2024-12-20 23:18:34 +01:00
@@ -1399,6 +1431,7 @@ public class ServerGamePacketListenerImpl
2024-12-17 12:46:53 +01:00
boolean flag1 = this.player.verticalCollisionBelow;
this.player.move(MoverType.PLAYER, new Vec3(d3, d4, d5));
2021-12-05 11:56:09 +01:00
this.player.onGround = packet.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move
2023-06-08 09:20:03 +02:00
+ boolean didCollide = toX != this.player.getX() || toY != this.player.getY() || toZ != this.player.getZ(); // Paper - needed here as the difference in Y can be reset - also note: this is only a guess at whether collisions took place, floating point errors can make this true when it shouldn't be...
2021-12-05 11:56:09 +01:00
// Paper start - prevent position desync
if (this.awaitingPositionFromClient != null) {
2023-06-08 09:20:03 +02:00
return; // ... thanks Mojang for letting move calls teleport across dimensions.
2024-12-20 23:18:34 +01:00
@@ -1430,7 +1463,17 @@ public class ServerGamePacketListenerImpl
2021-12-05 11:56:09 +01:00
}
2024-04-25 14:07:39 +02:00
// Paper start - Add fail move event
2024-12-17 12:46:53 +01:00
- boolean teleportBack = !this.player.noPhysics && !this.player.isSleeping() && (movedWrongly && serverLevel.noCollision(this.player, boundingBox) || this.isPlayerCollidingWithAnythingNew(serverLevel, boundingBox, d, d1, d2));
2021-12-05 11:56:09 +01:00
+ // Paper start - optimise out extra getCubes
2024-01-22 21:04:08 +01:00
+ boolean teleportBack = !this.player.noPhysics && !this.player.isSleeping() && movedWrongly;
2024-12-17 12:46:53 +01:00
+ this.player.absMoveTo(d, d1, d2, f, f1); // prevent desync by tping to the set position, dropped for unknown reasons by mojang
2021-12-05 11:56:09 +01:00
+ if (!this.player.noPhysics && !this.player.isSleeping() && !teleportBack) {
+ AABB newBox = this.player.getBoundingBox();
2024-12-17 12:46:53 +01:00
+ if (didCollide || !boundingBox.equals(newBox)) {
2021-12-05 11:56:09 +01:00
+ // note: only call after setLocation, or else getBoundingBox is wrong
2024-12-17 12:46:53 +01:00
+ teleportBack = this.hasNewCollision(serverLevel, this.player, boundingBox, newBox);
2021-12-05 11:56:09 +01:00
+ } // else: no collision at all detected, why do we care?
+ }
2024-01-22 21:04:08 +01:00
+ // Paper end - optimise out extra getCubes
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);
2024-12-20 23:18:34 +01:00
@@ -1566,7 +1609,7 @@ public class ServerGamePacketListenerImpl
2024-07-04 12:34:11 +02:00
private boolean updateAwaitingTeleport() {
if (this.awaitingPositionFromClient != null) {
- if (this.tickCount - this.awaitingTeleportTime > 20) {
+ if (false && this.tickCount - this.awaitingTeleportTime > 20) { // Paper - this will greatly screw with clients with > 1000ms RTT
this.awaitingTeleportTime = this.tickCount;
2024-12-17 12:46:53 +01:00
this.teleport(
this.awaitingPositionFromClient.x,
2024-12-20 23:18:34 +01:00
@@ -1585,6 +1628,33 @@ public class ServerGamePacketListenerImpl
2021-12-05 11:56:09 +01:00
}
}
+ // Paper start - optimise out extra getCubes
2024-12-17 12:46:53 +01:00
+ private boolean hasNewCollision(final ServerLevel level, final Entity entity, final AABB oldBox, final AABB newBox) {
2023-09-23 00:54:36 +02:00
+ final List<AABB> collisionsBB = new java.util.ArrayList<>();
+ final List<VoxelShape> collisionsVoxel = new java.util.ArrayList<>();
2024-08-16 15:56:13 +02:00
+ ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.getCollisions(
2024-12-17 12:46:53 +01:00
+ level, entity, newBox, collisionsVoxel, collisionsBB,
2024-08-16 15:56:13 +02:00
+ ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_COLLIDE_WITH_UNLOADED_CHUNKS | ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_CHECK_BORDER,
2023-09-23 00:54:36 +02:00
+ null, null
+ );
2021-12-05 11:56:09 +01:00
+
2023-09-23 00:54:36 +02:00
+ for (int i = 0, len = collisionsBB.size(); i < len; ++i) {
+ final AABB box = collisionsBB.get(i);
2024-08-16 15:56:13 +02:00
+ if (!ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.voxelShapeIntersect(box, oldBox)) {
2023-09-23 00:54:36 +02:00
+ return true;
2021-12-05 11:56:09 +01:00
+ }
2023-09-23 00:54:36 +02:00
+ }
2021-12-05 11:56:09 +01:00
+
2023-09-23 00:54:36 +02:00
+ for (int i = 0, len = collisionsVoxel.size(); i < len; ++i) {
+ final VoxelShape voxel = collisionsVoxel.get(i);
2024-08-16 15:56:13 +02:00
+ if (!ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.voxelShapeIntersectNoEmpty(voxel, oldBox)) {
2023-09-23 00:54:36 +02:00
+ return true;
+ }
2021-12-05 11:56:09 +01:00
+ }
2023-09-23 00:54:36 +02:00
+
+ return false;
2021-12-05 11:56:09 +01:00
+ }
+ // Paper end - optimise out extra getCubes
2024-12-17 12:46:53 +01:00
private boolean isPlayerCollidingWithAnythingNew(LevelReader level, AABB box, double x, double y, double z) {
AABB aabb = this.player.getBoundingBox().move(x - this.player.getX(), y - this.player.getY(), z - this.player.getZ());
Iterable<VoxelShape> collisions = level.getCollisions(this.player, aabb.deflate(1.0E-5F));