mirror of
https://github.com/PaperMC/Paper.git
synced 2025-07-20 10:11:58 +00:00
160 lines
10 KiB
Diff
160 lines
10 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
|
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 08aba415735733f5968fd032ab7ca249cdcf6cde..ee4397711625344622c81424afd11fd6d967efba 100644
|
|
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
|
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
|
@@ -606,6 +606,7 @@ public class ServerGamePacketListenerImpl
|
|
}
|
|
|
|
rootVehicle.move(MoverType.PLAYER, new Vec3(d3, d4, d5));
|
|
+ final 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...
|
|
double verticalDelta = d4;
|
|
d3 = d - rootVehicle.getX();
|
|
d4 = d1 - rootVehicle.getY();
|
|
@@ -617,12 +618,21 @@ public class ServerGamePacketListenerImpl
|
|
d7 = d3 * d3 + d4 * d4 + d5 * d5;
|
|
boolean flag1 = false;
|
|
if (d7 > org.spigotmc.SpigotConfig.movedWronglyThreshold) { // Spigot
|
|
- flag1 = true;
|
|
+ flag1 = 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));
|
|
}
|
|
|
|
- if (flag1 && serverLevel.noCollision(rootVehicle, boundingBox)
|
|
- || this.isEntityCollidingWithAnythingNew(serverLevel, rootVehicle, boundingBox, d, d1, d2)) {
|
|
+ // Paper start - optimise out extra getCubes
|
|
+ boolean teleportBack = flag1;
|
|
+ if (!teleportBack) {
|
|
+ // note: only call after setLocation, or else getBoundingBox is wrong
|
|
+ final AABB newBox = rootVehicle.getBoundingBox();
|
|
+ if (didCollide || !boundingBox.equals(newBox)) {
|
|
+ teleportBack = this.hasNewCollision(serverLevel, rootVehicle, boundingBox, newBox);
|
|
+ } // else: no collision at all detected, why do we care?
|
|
+ }
|
|
+ if (teleportBack) {
|
|
+ // Paper end - optimise out extra getCubes
|
|
rootVehicle.absSnapTo(x, y, z, f, f1);
|
|
this.send(ClientboundMoveVehiclePacket.fromEntity(rootVehicle));
|
|
rootVehicle.removeLatestMovementRecording();
|
|
@@ -701,9 +711,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
|
|
+ final AABB box = entity.getBoundingBox().inflate(0.0625).expandTowards(0.0, -0.55, 0.0);
|
|
+ final int minX = Mth.floor(box.minX);
|
|
+ final int minY = Mth.floor(box.minY);
|
|
+ final int minZ = Mth.floor(box.minZ);
|
|
+ final int maxX = Mth.floor(box.maxX);
|
|
+ final int maxY = Mth.floor(box.maxY);
|
|
+ final int maxZ = Mth.floor(box.maxZ);
|
|
+
|
|
+ final Level level = entity.level();
|
|
+ final 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);
|
|
+ final 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
|
|
@@ -1479,7 +1512,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
|
|
@@ -1518,6 +1551,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
|
|
+ final 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.
|
|
@@ -1550,7 +1584,17 @@ public class ServerGamePacketListenerImpl
|
|
}
|
|
|
|
// Paper start - Add fail move event
|
|
- boolean allowMovement = this.player.noPhysics || this.player.isSleeping() || (!movedWrongly || !serverLevel.noCollision(this.player, boundingBox)) && !this.isEntityCollidingWithAnythingNew(serverLevel, this.player, boundingBox, d, d1, d2);
|
|
+ // Paper start - optimise out extra getCubes
|
|
+ boolean allowMovement = this.player.noPhysics || this.player.isSleeping() || !movedWrongly;
|
|
+ this.player.absSnapTo(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() && allowMovement) {
|
|
+ final AABB newBox = this.player.getBoundingBox();
|
|
+ if (didCollide || !boundingBox.equals(newBox)) {
|
|
+ // note: only call after setLocation, or else getBoundingBox is wrong
|
|
+ allowMovement = !this.hasNewCollision(serverLevel, this.player, boundingBox, newBox);
|
|
+ } // else: no collision at all detected, why do we care?
|
|
+ }
|
|
+ // Paper end - optimise out extra getCubes
|
|
if (!allowMovement) {
|
|
io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.CLIPPED_INTO_BLOCK,
|
|
toX, toY, toZ, toYaw, toPitch, false);
|
|
@@ -1686,7 +1730,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,
|
|
@@ -1705,6 +1749,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 isEntityCollidingWithAnythingNew(LevelReader levelReader, Entity entity, AABB aabb, double d, double d1, double d2) {
|
|
AABB aabb1 = entity.getBoundingBox().move(d - entity.getX(), d1 - entity.getY(), d2 - entity.getZ());
|
|
Iterable<VoxelShape> preMoveCollisions = levelReader.getPreMoveCollisions(entity, aabb1.deflate(1.0E-5F), aabb.getBottomCenter());
|