diff options
Diffstat (limited to 'paper-server/patches/features/0030-Optimise-collision-checking-in-player-move-packet-ha.patch')
-rw-r--r-- | paper-server/patches/features/0030-Optimise-collision-checking-in-player-move-packet-ha.patch | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/paper-server/patches/features/0030-Optimise-collision-checking-in-player-move-packet-ha.patch b/paper-server/patches/features/0030-Optimise-collision-checking-in-player-move-packet-ha.patch new file mode 100644 index 0000000000..5ab3533b9d --- /dev/null +++ b/paper-server/patches/features/0030-Optimise-collision-checking-in-player-move-packet-ha.patch @@ -0,0 +1,169 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf <[email protected]> +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 + +diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index 96d36b2e285ec0a518b15ccdff4d7d1850b0a7e2..9a0a2a628d76a4e0410839d919a8bf38ff73a650 100644 +--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -561,7 +561,7 @@ public class ServerGamePacketListenerImpl + return; + } + +- 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 +@@ -571,6 +571,7 @@ public class ServerGamePacketListenerImpl + } + + 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) { +@@ -581,14 +582,22 @@ public class ServerGamePacketListenerImpl + d7 = d3 * d3 + d4 * d4 + d5 * d5; + boolean flag2 = false; + if (d7 > org.spigotmc.SpigotConfig.movedWronglyThreshold) { // Spigot +- flag2 = true; ++ flag2 = true; // Paper - diff on change, this should be moved wrongly + LOGGER.warn("{} (vehicle of {}) moved wrongly! {}", rootVehicle.getName().getString(), this.player.getName().getString(), Math.sqrt(d7)); + } + + 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)); +- if (flag && (flag2 || !flag3)) { ++ // Paper start - optimise out extra getCubes ++ boolean teleportBack = flag2; // violating this is always a fail ++ if (!teleportBack) { ++ // note: only call after setLocation, or else getBoundingBox is wrong ++ AABB newBox = rootVehicle.getBoundingBox(); ++ if (didCollide || !oldBox.equals(newBox)) { ++ teleportBack = this.hasNewCollision(serverLevel, rootVehicle, oldBox, newBox); ++ } // else: no collision at all detected, why do we care? ++ } ++ if (teleportBack) { // Paper end - optimise out extra getCubes + 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)); +@@ -666,9 +675,32 @@ public class ServerGamePacketListenerImpl + } + + private boolean noBlocksAround(Entity entity) { +- return entity.level() +- .getBlockStates(entity.getBoundingBox().inflate(0.0625).expandTowards(0.0, -0.55, 0.0)) +- .allMatch(BlockBehaviour.BlockStateBase::isAir); ++ // Paper start - stop using streams, this is already a known fixed problem in Entity#move ++ AABB box = entity.getBoundingBox().inflate(0.0625).expandTowards(0.0, -0.55, 0.0); ++ 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); ++ ++ Level level = entity.level(); ++ 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); ++ BlockState blockState = level.getBlockStateIfLoaded(pos); ++ if (blockState != null && !blockState.isAir()) { ++ return false; ++ } ++ } ++ } ++ } ++ ++ return true; ++ // Paper end - stop using streams, this is already a known fixed problem in Entity#move + } + + @Override +@@ -1360,7 +1392,7 @@ public class ServerGamePacketListenerImpl + } + } + +- 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 +@@ -1399,6 +1431,7 @@ public class ServerGamePacketListenerImpl + boolean flag1 = this.player.verticalCollisionBelow; + this.player.move(MoverType.PLAYER, new Vec3(d3, d4, d5)); + this.player.onGround = packet.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move ++ 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... + // Paper start - prevent position desync + if (this.awaitingPositionFromClient != null) { + return; // ... thanks Mojang for letting move calls teleport across dimensions. +@@ -1430,7 +1463,17 @@ public class ServerGamePacketListenerImpl + } + + // Paper start - Add fail move event +- boolean teleportBack = !this.player.noPhysics && !this.player.isSleeping() && (movedWrongly && serverLevel.noCollision(this.player, boundingBox) || this.isPlayerCollidingWithAnythingNew(serverLevel, boundingBox, d, d1, d2)); ++ // Paper start - optimise out extra getCubes ++ boolean teleportBack = !this.player.noPhysics && !this.player.isSleeping() && movedWrongly; ++ this.player.absMoveTo(d, d1, d2, f, f1); // prevent desync by tping to the set position, dropped for unknown reasons by mojang ++ if (!this.player.noPhysics && !this.player.isSleeping() && !teleportBack) { ++ AABB newBox = this.player.getBoundingBox(); ++ if (didCollide || !boundingBox.equals(newBox)) { ++ // note: only call after setLocation, or else getBoundingBox is wrong ++ teleportBack = this.hasNewCollision(serverLevel, this.player, boundingBox, newBox); ++ } // else: no collision at all detected, why do we care? ++ } ++ // 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); +@@ -1566,7 +1609,7 @@ public class ServerGamePacketListenerImpl + + 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; + this.teleport( + this.awaitingPositionFromClient.x, +@@ -1585,6 +1628,33 @@ public class ServerGamePacketListenerImpl + } + } + ++ // Paper start - optimise out extra getCubes ++ private boolean hasNewCollision(final ServerLevel level, final Entity entity, final AABB oldBox, final AABB newBox) { ++ final List<AABB> collisionsBB = new java.util.ArrayList<>(); ++ final List<VoxelShape> collisionsVoxel = new java.util.ArrayList<>(); ++ ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.getCollisions( ++ level, entity, newBox, collisionsVoxel, collisionsBB, ++ ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_COLLIDE_WITH_UNLOADED_CHUNKS | ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_CHECK_BORDER, ++ null, null ++ ); ++ ++ for (int i = 0, len = collisionsBB.size(); i < len; ++i) { ++ final AABB box = collisionsBB.get(i); ++ if (!ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.voxelShapeIntersect(box, oldBox)) { ++ return true; ++ } ++ } ++ ++ for (int i = 0, len = collisionsVoxel.size(); i < len; ++i) { ++ final VoxelShape voxel = collisionsVoxel.get(i); ++ if (!ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.voxelShapeIntersectNoEmpty(voxel, oldBox)) { ++ return true; ++ } ++ } ++ ++ return false; ++ } ++ // Paper end - optimise out extra getCubes + 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)); |