aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/server/1015-Collision-optimisations.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches/server/1015-Collision-optimisations.patch')
-rw-r--r--patches/server/1015-Collision-optimisations.patch313
1 files changed, 183 insertions, 130 deletions
diff --git a/patches/server/1015-Collision-optimisations.patch b/patches/server/1015-Collision-optimisations.patch
index 176352b0ab..2b153fafde 100644
--- a/patches/server/1015-Collision-optimisations.patch
+++ b/patches/server/1015-Collision-optimisations.patch
@@ -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 073c717bb676b9e99aada00c349fb7eee91df1e7..2a9fc1f1dfc0c5894c1e74dad5a79ae9b02ac74f 100644
+index 83a2b952df749b7aaab439db4ec2d38bc4f5b11c..6bcf4d8e5c69dbc655d522abadc7f14ee7b21d71 100644
--- a/src/main/java/net/minecraft/core/Direction.java
+++ b/src/main/java/net/minecraft/core/Direction.java
-@@ -57,6 +57,21 @@ public enum Direction implements StringRepresentable {
+@@ -53,6 +53,21 @@ public enum Direction implements StringRepresentable {
private final int adjY;
private final int adjZ;
// Paper end - Perf: Inline shift direction fields
@@ -2179,7 +2179,7 @@ index 073c717bb676b9e99aada00c349fb7eee91df1e7..2a9fc1f1dfc0c5894c1e74dad5a79ae9
private Direction(int id, int idOpposite, int idHorizontal, String name, Direction.AxisDirection direction, Direction.Axis axis, Vec3i vector) {
this.data3d = id;
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-index acc9858e0cf10cb2aae0554037096411a208bd05..c99d2f2d64b73179e4e27b63030e26a07953041b 100644
+index acc1751324f040accc4fc18914ed281e572358eb..17a6d43685f35a6978c2d941876a1f8a9a2c8b42 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 {
@@ -2214,7 +2214,7 @@ 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 c1a8de736ee39e4e177399bc51aedfd135a8100d..6de971aca46caad091271d125a079a1b7a5f163d 100644
+index 865c5ee8a8a14ef1a7d71dcab3e324932d065d5f..8c2c877a26af90dae6d083e12a51384755c7a1de 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
@@ -2466,10 +2466,10 @@ index ffa4f34d964fbcc53e2dfe11677832db21a6eb93..7618364e5373fe17cfe45a5a4ee9ab25
}
diff --git a/src/main/java/net/minecraft/world/level/BlockCollisions.java b/src/main/java/net/minecraft/world/level/BlockCollisions.java
-index a3eaf80b020c3bbc0306c5d17659ee661dfd275b..1b6f72932fbdd567a1534bcf15e8a610b00f974d 100644
+index 354290f88af285af229e4315e53e9bd76439d0da..b87bcc4a465fb83463da4811a79c381141c6f70b 100644
--- a/src/main/java/net/minecraft/world/level/BlockCollisions.java
+++ b/src/main/java/net/minecraft/world/level/BlockCollisions.java
-@@ -105,7 +105,7 @@ public class BlockCollisions<T> extends AbstractIterator<T> {
+@@ -107,7 +107,7 @@ public class BlockCollisions<T> extends AbstractIterator<T> {
VoxelShape voxelShape = blockState.getCollisionShape(this.collisionGetter, this.pos, this.context);
if (voxelShape == Shapes.block()) {
@@ -2494,7 +2494,7 @@ index 86a4f30c8784c602436ecf1c78efb0bdca4b7089..b0bea28e9261767c60d30fb0e76f4f3a
public ClipContext(Vec3 start, Vec3 end, ClipContext.Block shapeType, ClipContext.Fluid fluidHandling, Entity entity) {
diff --git a/src/main/java/net/minecraft/world/level/CollisionGetter.java b/src/main/java/net/minecraft/world/level/CollisionGetter.java
-index c476e37df8a75d77f5093b2a449e04f25ef2c2dd..5d66aadae51db1ae760812849bfc8740b82af9a9 100644
+index a4200e1992207e7665673c2acdb45facfd0bc676..4e32426a3d261f77d6066bb5256596a4ae0de0a3 100644
--- a/src/main/java/net/minecraft/world/level/CollisionGetter.java
+++ b/src/main/java/net/minecraft/world/level/CollisionGetter.java
@@ -35,6 +35,12 @@ public interface CollisionGetter extends BlockGetter {
@@ -2508,13 +2508,13 @@ index c476e37df8a75d77f5093b2a449e04f25ef2c2dd..5d66aadae51db1ae760812849bfc8740
+ // Paper end - optimise collisions
+
default boolean noCollision(AABB box) {
- return this.noCollision((Entity)null, box);
+ return this.noCollision(null, box);
}
diff --git a/src/main/java/net/minecraft/world/level/EntityGetter.java b/src/main/java/net/minecraft/world/level/EntityGetter.java
-index cc888bbcd6a50124fa553bc4a8ffd1e8885d3856..f42dd9602805e9d538506ee4e3eac7e2811a3da6 100644
+index eba4663a6928989bfa14d57303d77fdabea31481..44cfa3821774f22ac05aa679fdee34d8d68b7d60 100644
--- a/src/main/java/net/minecraft/world/level/EntityGetter.java
+++ b/src/main/java/net/minecraft/world/level/EntityGetter.java
-@@ -45,17 +45,36 @@ public interface EntityGetter {
+@@ -46,20 +46,36 @@ public interface EntityGetter {
}
default boolean isUnobstructed(@Nullable Entity except, VoxelShape shape) {
@@ -2522,8 +2522,11 @@ index cc888bbcd6a50124fa553bc4a8ffd1e8885d3856..f42dd9602805e9d538506ee4e3eac7e2
if (shape.isEmpty()) {
- return true;
- } else {
-- for(Entity entity : this.getEntities(except, shape.bounds())) {
-- if (!entity.isRemoved() && entity.blocksBuilding && (except == null || !entity.isPassengerOfSameVehicle(except)) && Shapes.joinIsNotEmpty(shape, Shapes.create(entity.getBoundingBox()), BooleanOp.AND)) {
+- for (Entity entity : this.getEntities(except, shape.bounds())) {
+- if (!entity.isRemoved()
+- && entity.blocksBuilding
+- && (except == null || !entity.isPassengerOfSameVehicle(except))
+- && Shapes.joinIsNotEmpty(shape, Shapes.create(entity.getBoundingBox()), BooleanOp.AND)) {
- return false;
+ return false;
+ }
@@ -2557,11 +2560,11 @@ index cc888bbcd6a50124fa553bc4a8ffd1e8885d3856..f42dd9602805e9d538506ee4e3eac7e2
}
default <T extends Entity> List<T> getEntitiesOfClass(Class<T> entityClass, AABB box) {
-@@ -63,23 +82,41 @@ public interface EntityGetter {
+@@ -67,23 +83,41 @@ public interface EntityGetter {
}
default List<VoxelShape> getEntityCollisions(@Nullable Entity entity, AABB box) {
-- if (box.getSize() < 1.0E-7D) {
+- if (box.getSize() < 1.0E-7) {
- return List.of();
+ // Paper start - optimise collisions
+ // first behavior change is to correctly check for empty AABB
@@ -2580,13 +2583,13 @@ index cc888bbcd6a50124fa553bc4a8ffd1e8885d3856..f42dd9602805e9d538506ee4e3eac7e2
+ entities = this.getEntities(entity, box, null);
} else {
- Predicate<Entity> predicate = entity == null ? EntitySelector.CAN_BE_COLLIDED_WITH : EntitySelector.NO_SPECTATORS.and(entity::canCollideWith);
-- List<Entity> list = this.getEntities(entity, box.inflate(1.0E-7D), predicate);
+- List<Entity> list = this.getEntities(entity, box.inflate(1.0E-7), predicate);
- if (list.isEmpty()) {
- return List.of();
- } else {
-- ImmutableList.Builder<VoxelShape> builder = ImmutableList.builderWithExpectedSize(list.size());
+- Builder<VoxelShape> builder = ImmutableList.builderWithExpectedSize(list.size());
-
-- for(Entity entity2 : list) {
+- for (Entity entity2 : list) {
- builder.add(Shapes.create(entity2.getBoundingBox()));
- }
+ entities = this.getHardCollidingEntities(entity, box, null);
@@ -3215,7 +3218,7 @@ index a98ab20814cc29a25e9d29adfbb7e70d46768df2..6d8ff6c06af5545634f255ed17dc1e48
if (!state.getBlock().hasDynamicShape() && !fromState.getBlock().hasDynamicShape()) {
diff --git a/src/main/java/net/minecraft/world/phys/AABB.java b/src/main/java/net/minecraft/world/phys/AABB.java
-index b8443953de15066f32f629c0dd7e24bad750f558..67d595f75e0c3bffdb27b85b25ccd1f0bf1427d5 100644
+index 62752e28a68400f0e1a44f0196f0e51e3dd702b8..92394960fc76886f393cba02ac33c57739a4b383 100644
--- a/src/main/java/net/minecraft/world/phys/AABB.java
+++ b/src/main/java/net/minecraft/world/phys/AABB.java
@@ -25,6 +25,17 @@ public class AABB {
@@ -3236,21 +3239,21 @@ index b8443953de15066f32f629c0dd7e24bad750f558..67d595f75e0c3bffdb27b85b25ccd1f0
public AABB(BlockPos pos) {
this((double)pos.getX(), (double)pos.getY(), (double)pos.getZ(), (double)(pos.getX() + 1), (double)(pos.getY() + 1), (double)(pos.getZ() + 1));
}
-@@ -305,7 +316,7 @@ public class AABB {
+@@ -321,7 +332,7 @@ public class AABB {
}
@Nullable
-- private static Direction getDirection(AABB box, Vec3 intersectingVector, double[] traceDistanceResult, @Nullable Direction approachDirection, double deltaX, double deltaY, double deltaZ) {
-+ public static Direction getDirection(AABB box, Vec3 intersectingVector, double[] traceDistanceResult, @Nullable Direction approachDirection, double deltaX, double deltaY, double deltaZ) { // Paper - optimise collisions - public
- if (deltaX > 1.0E-7D) {
- approachDirection = clipPoint(traceDistanceResult, approachDirection, deltaX, deltaY, deltaZ, box.minX, box.minY, box.maxY, box.minZ, box.maxZ, Direction.WEST, intersectingVector.x, intersectingVector.y, intersectingVector.z);
- } else if (deltaX < -1.0E-7D) {
+- private static Direction getDirection(
++ public static Direction getDirection( // Paper - optimise collisions - public
+ AABB box, Vec3 intersectingVector, double[] traceDistanceResult, @Nullable Direction approachDirection, double deltaX, double deltaY, double deltaZ
+ ) {
+ if (deltaX > 1.0E-7) {
diff --git a/src/main/java/net/minecraft/world/phys/shapes/ArrayVoxelShape.java b/src/main/java/net/minecraft/world/phys/shapes/ArrayVoxelShape.java
-index 9d627b8e6bf3140b894d38b9a720896e2d776369..a232b9396a41c11579a4d691b05717b16473513e 100644
+index fc7f986812bdf74e0aea3bd09a1d53ba6def697f..0583d40a235aaecd9d6081486bbfb7355709a5ac 100644
--- a/src/main/java/net/minecraft/world/phys/shapes/ArrayVoxelShape.java
+++ b/src/main/java/net/minecraft/world/phys/shapes/ArrayVoxelShape.java
-@@ -15,7 +15,7 @@ public class ArrayVoxelShape extends VoxelShape {
- this(shape, (DoubleList)DoubleArrayList.wrap(Arrays.copyOf(xPoints, shape.getXSize() + 1)), (DoubleList)DoubleArrayList.wrap(Arrays.copyOf(yPoints, shape.getYSize() + 1)), (DoubleList)DoubleArrayList.wrap(Arrays.copyOf(zPoints, shape.getZSize() + 1)));
+@@ -20,7 +20,7 @@ public class ArrayVoxelShape extends VoxelShape {
+ );
}
- ArrayVoxelShape(DiscreteVoxelShape shape, DoubleList xPoints, DoubleList yPoints, DoubleList zPoints) {
@@ -3258,22 +3261,22 @@ index 9d627b8e6bf3140b894d38b9a720896e2d776369..a232b9396a41c11579a4d691b05717b1
super(shape);
int i = shape.getXSize() + 1;
int j = shape.getYSize() + 1;
-@@ -27,6 +27,7 @@ public class ArrayVoxelShape extends VoxelShape {
- } else {
- throw (IllegalArgumentException)Util.pauseInIde(new IllegalArgumentException("Lengths of point arrays must be consistent with the size of the VoxelShape."));
+@@ -34,6 +34,7 @@ public class ArrayVoxelShape extends VoxelShape {
+ new IllegalArgumentException("Lengths of point arrays must be consistent with the size of the VoxelShape.")
+ );
}
+ this.initCache(); // Paper - optimise collisions
}
@Override
-@@ -42,4 +43,5 @@ public class ArrayVoxelShape extends VoxelShape {
+@@ -49,4 +50,5 @@ public class ArrayVoxelShape extends VoxelShape {
throw new IllegalArgumentException();
}
}
+
}
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 c25f409d63a50c5de1434db1d6b298935f106221..6f532d9aa613ecb0f5695b108ec6d7ed3598ca82 100644
+index 31b570517c1047e8e1cd5280baf80977af2b6121..d8b80632f6186641ee2ddaef9eba7ba998b09136 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;
@@ -3297,7 +3300,7 @@ index c25f409d63a50c5de1434db1d6b298935f106221..6f532d9aa613ecb0f5695b108ec6d7ed
public BitSetDiscreteVoxelShape(int sizeX, int sizeY, int sizeZ) {
super(sizeX, sizeY, sizeZ);
-@@ -150,46 +150,106 @@ public final class BitSetDiscreteVoxelShape extends DiscreteVoxelShape {
+@@ -151,45 +151,106 @@ public final class BitSetDiscreteVoxelShape extends DiscreteVoxelShape {
}
protected static void forAllBoxes(DiscreteVoxelShape voxelSet, DiscreteVoxelShape.IntLineConsumer callback, boolean coalesce) {
@@ -3305,11 +3308,22 @@ index c25f409d63a50c5de1434db1d6b298935f106221..6f532d9aa613ecb0f5695b108ec6d7ed
+ // 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;
@@ -3339,21 +3353,10 @@ index c25f409d63a50c5de1434db1d6b298935f106221..6f532d9aa613ecb0f5695b108ec6d7ed
+ } 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) {
@@ -3368,17 +3371,17 @@ index c25f409d63a50c5de1434db1d6b298935f106221..6f532d9aa613ecb0f5695b108ec6d7ed
- int n = i;
- bitSetDiscreteVoxelShape.clearZStrip(k, l, j, i);
-
-- while(bitSetDiscreteVoxelShape.isZStripFull(k, l, m + 1, i)) {
+- while (bitSetDiscreteVoxelShape.isZStripFull(k, l, m + 1, i)) {
- bitSetDiscreteVoxelShape.clearZStrip(k, l, m + 1, i);
-- ++m;
+- 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) {
+- 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);
+
@@ -3408,7 +3411,7 @@ index c25f409d63a50c5de1434db1d6b298935f106221..6f532d9aa613ecb0f5695b108ec6d7ed
+ }
}
-- ++n;
+- n++;
+ ++endY;
+
+ // passed, so we can clear it
@@ -3426,13 +3429,12 @@ index c25f409d63a50c5de1434db1d6b298935f106221..6f532d9aa613ecb0f5695b108ec6d7ed
}
}
}
--
+ // Paper end - optimise collisions
}
private boolean isZStripFull(int z1, int z2, int x, int y) {
diff --git a/src/main/java/net/minecraft/world/phys/shapes/CubeVoxelShape.java b/src/main/java/net/minecraft/world/phys/shapes/CubeVoxelShape.java
-index 68e89dbd79171627046e89699057964e44c40e7d..110405e6e70d980d3e09f04d79562b32a7413071 100644
+index 32632368f06b79f53342fde060bbcd1b7c64767a..b9af1d14c7815c99273bce8165cf384d669c1a75 100644
--- a/src/main/java/net/minecraft/world/phys/shapes/CubeVoxelShape.java
+++ b/src/main/java/net/minecraft/world/phys/shapes/CubeVoxelShape.java
@@ -7,6 +7,7 @@ import net.minecraft.util.Mth;
@@ -3444,7 +3446,7 @@ index 68e89dbd79171627046e89699057964e44c40e7d..110405e6e70d980d3e09f04d79562b32
@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 b27ed92b2a87d4c20c1aa300202adfab896c99ea..d0a4547f95ee24283af77cfa130979d05915292f 100644
+index 87a8f12dc3d47fb093115030e0222f065f1dcb1c..44b62f1f6685084c0cff02bd31eb5a7c2ef9eead 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 {
@@ -3535,12 +3537,12 @@ index 7ec02a7849437a18860aa0df7d9ddd71b2447d4c..5e45e49ab09344cb95736f4124b1c6e0
public OffsetDoubleList(DoubleList oldList, double offset) {
this.delegate = oldList;
diff --git a/src/main/java/net/minecraft/world/phys/shapes/Shapes.java b/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
-index 9176735c08a75854209f24113b0e78332249dc4d..17785f7c709073a01928e8e6a57702f8357900f4 100644
+index d88f69275ffee4669dd6d31e2669c41f66a1919d..ce8fff01475bdfe9094c237fc5f294f3958edb42 100644
--- a/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
+++ b/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
-@@ -16,13 +16,43 @@ public final class Shapes {
- public static final double EPSILON = 1.0E-7D;
- public static final double BIG_EPSILON = 1.0E-6D;
+@@ -16,9 +16,15 @@ public final class Shapes {
+ public static final double EPSILON = 1.0E-7;
+ public static final double BIG_EPSILON = 1.0E-6;
private static final VoxelShape BLOCK = Util.make(() -> {
- DiscreteVoxelShape discreteVoxelShape = new BitSetDiscreteVoxelShape(1, 1, 1);
- discreteVoxelShape.fill(0, 0, 0);
@@ -3555,8 +3557,11 @@ index 9176735c08a75854209f24113b0e78332249dc4d..17785f7c709073a01928e8e6a57702f8
+ );
+ // Paper end - optimise collisions - force arrayvoxelshape
});
- public static final VoxelShape INFINITY = box(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
- private static final VoxelShape EMPTY = new ArrayVoxelShape(new BitSetDiscreteVoxelShape(0, 0, 0), (DoubleList)(new DoubleArrayList(new double[]{0.0D})), (DoubleList)(new DoubleArrayList(new double[]{0.0D})), (DoubleList)(new DoubleArrayList(new double[]{0.0D})));
+ public static final VoxelShape INFINITY = box(
+ Double.NEGATIVE_INFINITY,
+@@ -35,6 +41,30 @@ public final class Shapes {
+ new DoubleArrayList(new double[]{0.0})
+ );
+ // Paper start - optimise collisions - force arrayvoxelshape
+ private static final DoubleArrayList[] PARTS_BY_BITS = new DoubleArrayList[] {
@@ -3585,16 +3590,22 @@ index 9176735c08a75854209f24113b0e78332249dc4d..17785f7c709073a01928e8e6a57702f8
public static VoxelShape empty() {
return EMPTY;
}
-@@ -41,22 +71,39 @@ public final class Shapes {
+@@ -53,35 +83,39 @@ public final class Shapes {
public static VoxelShape create(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
- if (!(maxX - minX < 1.0E-7D) && !(maxY - minY < 1.0E-7D) && !(maxZ - minZ < 1.0E-7D)) {
+ if (!(maxX - minX < 1.0E-7) && !(maxY - minY < 1.0E-7) && !(maxZ - minZ < 1.0E-7)) {
- int i = findBits(minX, maxX);
- int j = findBits(minY, maxY);
- int k = findBits(minZ, maxZ);
-- if (i >= 0 && j >= 0 && k >= 0) {
-- if (i == 0 && j == 0 && k == 0) {
-- return block();
+- if (i < 0 || j < 0 || k < 0) {
+- return new ArrayVoxelShape(
+- BLOCK.shape,
+- DoubleArrayList.wrap(new double[]{minX, maxX}),
+- DoubleArrayList.wrap(new double[]{minY, maxY}),
+- DoubleArrayList.wrap(new double[]{minZ, maxZ})
+- );
+- } else if (i == 0 && j == 0 && k == 0) {
+- return block();
+ // Paper start - optimise collisions
+ // force ArrayVoxelShape in every case
+ final int bitsX = findBits(minX, maxX);
@@ -3603,12 +3614,7 @@ index 9176735c08a75854209f24113b0e78332249dc4d..17785f7c709073a01928e8e6a57702f8
+ if (bitsX >= 0 && bitsY >= 0 && bitsZ >= 0) {
+ if (bitsX == 0 && bitsY == 0 && bitsZ == 0) {
+ return BLOCK;
- } else {
-- int l = 1 << i;
-- int m = 1 << j;
-- int n = 1 << k;
-- BitSetDiscreteVoxelShape bitSetDiscreteVoxelShape = BitSetDiscreteVoxelShape.withFilledBounds(l, m, n, (int)Math.round(minX * (double)l), (int)Math.round(minY * (double)m), (int)Math.round(minZ * (double)n), (int)Math.round(maxX * (double)l), (int)Math.round(maxY * (double)m), (int)Math.round(maxZ * (double)n));
-- return new CubeVoxelShape(bitSetDiscreteVoxelShape);
++ } else {
+ final int sizeX = 1 << bitsX;
+ final int sizeY = 1 << bitsY;
+ final int sizeZ = 1 << bitsZ;
@@ -3623,21 +3629,34 @@ index 9176735c08a75854209f24113b0e78332249dc4d..17785f7c709073a01928e8e6a57702f8
+ PARTS_BY_BITS[bitsY],
+ PARTS_BY_BITS[bitsZ]
+ );
- }
++ }
} else {
-- return new ArrayVoxelShape(BLOCK.shape, (DoubleList)DoubleArrayList.wrap(new double[]{minX, maxX}), (DoubleList)DoubleArrayList.wrap(new double[]{minY, maxY}), (DoubleList)DoubleArrayList.wrap(new double[]{minZ, maxZ}));
+- int l = 1 << i;
+- int m = 1 << j;
+- int n = 1 << k;
+- BitSetDiscreteVoxelShape bitSetDiscreteVoxelShape = BitSetDiscreteVoxelShape.withFilledBounds(
+- l,
+- m,
+- n,
+- (int)Math.round(minX * (double)l),
+- (int)Math.round(minY * (double)m),
+- (int)Math.round(minZ * (double)n),
+- (int)Math.round(maxX * (double)l),
+- (int)Math.round(maxY * (double)m),
+- (int)Math.round(maxZ * (double)n)
+ return new ArrayVoxelShape(
+ BLOCK.shape,
+ minX == 0.0 && maxX == 1.0 ? io.papermc.paper.util.CollisionUtil.ZERO_ONE : DoubleArrayList.wrap(new double[] { minX, maxX }),
+ minY == 0.0 && maxY == 1.0 ? io.papermc.paper.util.CollisionUtil.ZERO_ONE : DoubleArrayList.wrap(new double[] { minY, maxY }),
+ minZ == 0.0 && maxZ == 1.0 ? io.papermc.paper.util.CollisionUtil.ZERO_ONE : DoubleArrayList.wrap(new double[] { minZ, maxZ })
-+ );
+ );
+- return new CubeVoxelShape(bitSetDiscreteVoxelShape);
}
+ // Paper end - optimise collisions
} else {
return empty();
}
-@@ -95,67 +142,53 @@ public final class Shapes {
+@@ -120,79 +154,53 @@ public final class Shapes {
}
public static VoxelShape or(VoxelShape first, VoxelShape... others) {
@@ -3699,9 +3718,17 @@ index 9176735c08a75854209f24113b0e78332249dc4d..17785f7c709073a01928e8e6a57702f8
- } else {
- IndexMerger indexMerger = createIndexMerger(1, one.getCoords(Direction.Axis.X), two.getCoords(Direction.Axis.X), bl, bl2);
- IndexMerger indexMerger2 = createIndexMerger(indexMerger.size() - 1, one.getCoords(Direction.Axis.Y), two.getCoords(Direction.Axis.Y), bl, bl2);
-- IndexMerger indexMerger3 = createIndexMerger((indexMerger.size() - 1) * (indexMerger2.size() - 1), one.getCoords(Direction.Axis.Z), two.getCoords(Direction.Axis.Z), bl, bl2);
-- BitSetDiscreteVoxelShape bitSetDiscreteVoxelShape = BitSetDiscreteVoxelShape.join(one.shape, two.shape, indexMerger, indexMerger2, indexMerger3, function);
-- return (VoxelShape)(indexMerger instanceof DiscreteCubeMerger && indexMerger2 instanceof DiscreteCubeMerger && indexMerger3 instanceof DiscreteCubeMerger ? new CubeVoxelShape(bitSetDiscreteVoxelShape) : new ArrayVoxelShape(bitSetDiscreteVoxelShape, indexMerger.getList(), indexMerger2.getList(), indexMerger3.getList()));
+- IndexMerger indexMerger3 = createIndexMerger(
+- (indexMerger.size() - 1) * (indexMerger2.size() - 1), one.getCoords(Direction.Axis.Z), two.getCoords(Direction.Axis.Z), bl, bl2
+- );
+- BitSetDiscreteVoxelShape bitSetDiscreteVoxelShape = BitSetDiscreteVoxelShape.join(
+- one.shape, two.shape, indexMerger, indexMerger2, indexMerger3, function
+- );
+- return (VoxelShape)(indexMerger instanceof DiscreteCubeMerger
+- && indexMerger2 instanceof DiscreteCubeMerger
+- && indexMerger3 instanceof DiscreteCubeMerger
+- ? new CubeVoxelShape(bitSetDiscreteVoxelShape)
+- : new ArrayVoxelShape(bitSetDiscreteVoxelShape, indexMerger.getList(), indexMerger2.getList(), indexMerger3.getList()));
- }
- }
+ return io.papermc.paper.util.CollisionUtil.joinUnoptimized(one, two, function); // Paper - optimise collisions
@@ -3720,19 +3747,23 @@ index 9176735c08a75854209f24113b0e78332249dc4d..17785f7c709073a01928e8e6a57702f8
- boolean bl3 = predicate.apply(true, false);
- boolean bl4 = predicate.apply(false, true);
-
-- for(Direction.Axis axis : AxisCycle.AXIS_VALUES) {
-- if (shape1.max(axis) < shape2.min(axis) - 1.0E-7D) {
+- for (Direction.Axis axis : AxisCycle.AXIS_VALUES) {
+- if (shape1.max(axis) < shape2.min(axis) - 1.0E-7) {
- return bl3 || bl4;
- }
-
-- if (shape2.max(axis) < shape1.min(axis) - 1.0E-7D) {
+- if (shape2.max(axis) < shape1.min(axis) - 1.0E-7) {
- return bl3 || bl4;
- }
- }
-
- IndexMerger indexMerger = createIndexMerger(1, shape1.getCoords(Direction.Axis.X), shape2.getCoords(Direction.Axis.X), bl3, bl4);
-- IndexMerger indexMerger2 = createIndexMerger(indexMerger.size() - 1, shape1.getCoords(Direction.Axis.Y), shape2.getCoords(Direction.Axis.Y), bl3, bl4);
-- IndexMerger indexMerger3 = createIndexMerger((indexMerger.size() - 1) * (indexMerger2.size() - 1), shape1.getCoords(Direction.Axis.Z), shape2.getCoords(Direction.Axis.Z), bl3, bl4);
+- IndexMerger indexMerger2 = createIndexMerger(
+- indexMerger.size() - 1, shape1.getCoords(Direction.Axis.Y), shape2.getCoords(Direction.Axis.Y), bl3, bl4
+- );
+- IndexMerger indexMerger3 = createIndexMerger(
+- (indexMerger.size() - 1) * (indexMerger2.size() - 1), shape1.getCoords(Direction.Axis.Z), shape2.getCoords(Direction.Axis.Z), bl3, bl4
+- );
- return joinIsNotEmpty(indexMerger, indexMerger2, indexMerger3, shape1.shape, shape2.shape, predicate);
- }
- } else {
@@ -3742,8 +3773,8 @@ index 9176735c08a75854209f24113b0e78332249dc4d..17785f7c709073a01928e8e6a57702f8
+ return io.papermc.paper.util.CollisionUtil.isJoinNonEmpty(shape1, shape2, predicate); // Paper - optimise collisions
}
- private static boolean joinIsNotEmpty(IndexMerger mergedX, IndexMerger mergedY, IndexMerger mergedZ, DiscreteVoxelShape shape1, DiscreteVoxelShape shape2, BooleanOp predicate) {
-@@ -181,69 +214,119 @@ public final class Shapes {
+ private static boolean joinIsNotEmpty(
+@@ -220,69 +228,119 @@ public final class Shapes {
}
public static boolean blockOccudes(VoxelShape shape, VoxelShape neighbor, Direction direction) {
@@ -3758,15 +3789,8 @@ index 9176735c08a75854209f24113b0e78332249dc4d..17785f7c709073a01928e8e6a57702f8
+ }
+
+ if (shape.isEmpty() | neighbor.isEmpty()) {
- return false;
-- } else {
-- Direction.Axis axis = direction.getAxis();
-- Direction.AxisDirection axisDirection = direction.getAxisDirection();
-- VoxelShape voxelShape = axisDirection == Direction.AxisDirection.POSITIVE ? shape : neighbor;
-- VoxelShape voxelShape2 = axisDirection == Direction.AxisDirection.POSITIVE ? neighbor : shape;
-- BooleanOp booleanOp = axisDirection == Direction.AxisDirection.POSITIVE ? BooleanOp.ONLY_FIRST : BooleanOp.ONLY_SECOND;
-- return DoubleMath.fuzzyEquals(voxelShape.max(axis), 1.0D, 1.0E-7D) && DoubleMath.fuzzyEquals(voxelShape2.min(axis), 0.0D, 1.0E-7D) && !joinIsNotEmpty(new SliceShape(voxelShape, axis, voxelShape.shape.getSize(axis) - 1), new SliceShape(voxelShape2, axis, 0), booleanOp);
- }
++ return false;
++ }
+
+ // we optimise getOpposite, so we can use it
+ // secondly, use our cache to retrieve sliced shape
@@ -3776,8 +3800,17 @@ index 9176735c08a75854209f24113b0e78332249dc4d..17785f7c709073a01928e8e6a57702f8
+ }
+ final VoxelShape newSecond = neighbor.getFaceShapeClamped(direction.getOpposite());
+ if (newSecond.isEmpty()) {
-+ return false;
-+ }
+ return false;
+- } else {
+- Direction.Axis axis = direction.getAxis();
+- Direction.AxisDirection axisDirection = direction.getAxisDirection();
+- VoxelShape voxelShape = axisDirection == Direction.AxisDirection.POSITIVE ? shape : neighbor;
+- VoxelShape voxelShape2 = axisDirection == Direction.AxisDirection.POSITIVE ? neighbor : shape;
+- BooleanOp booleanOp = axisDirection == Direction.AxisDirection.POSITIVE ? BooleanOp.ONLY_FIRST : BooleanOp.ONLY_SECOND;
+- return DoubleMath.fuzzyEquals(voxelShape.max(axis), 1.0, 1.0E-7)
+- && DoubleMath.fuzzyEquals(voxelShape2.min(axis), 0.0, 1.0E-7)
+- && !joinIsNotEmpty(new SliceShape(voxelShape, axis, voxelShape.shape.getSize(axis) - 1), new SliceShape(voxelShape2, axis, 0), booleanOp);
+ }
+
+ return !joinIsNotEmpty(newFirst, newSecond, BooleanOp.ONLY_FIRST);
+ // Paper end - optimise collisions
@@ -3791,10 +3824,10 @@ index 9176735c08a75854209f24113b0e78332249dc4d..17785f7c709073a01928e8e6a57702f8
- boolean bl;
- int i;
- if (direction.getAxisDirection() == Direction.AxisDirection.POSITIVE) {
-- bl = DoubleMath.fuzzyEquals(shape.max(axis), 1.0D, 1.0E-7D);
+- bl = DoubleMath.fuzzyEquals(shape.max(axis), 1.0, 1.0E-7);
- i = shape.shape.getSize(axis) - 1;
- } else {
-- bl = DoubleMath.fuzzyEquals(shape.min(axis), 0.0D, 1.0E-7D);
+- bl = DoubleMath.fuzzyEquals(shape.min(axis), 0.0, 1.0E-7);
- i = 0;
- }
+ return shape.getFaceShapeClamped(direction); // Paper - optimise collisions
@@ -3828,7 +3861,7 @@ index 9176735c08a75854209f24113b0e78332249dc4d..17785f7c709073a01928e8e6a57702f8
- Direction.AxisDirection axisDirection = direction.getAxisDirection();
- VoxelShape voxelShape = axisDirection == Direction.AxisDirection.POSITIVE ? one : two;
- VoxelShape voxelShape2 = axisDirection == Direction.AxisDirection.POSITIVE ? two : one;
-- if (!DoubleMath.fuzzyEquals(voxelShape.max(axis), 1.0D, 1.0E-7D)) {
+- if (!DoubleMath.fuzzyEquals(voxelShape.max(axis), 1.0, 1.0E-7)) {
- voxelShape = empty();
- }
+ // Paper start - optimise collisions
@@ -3837,14 +3870,18 @@ index 9176735c08a75854209f24113b0e78332249dc4d..17785f7c709073a01928e8e6a57702f8
+ return true;
+ }
-- if (!DoubleMath.fuzzyEquals(voxelShape2.min(axis), 0.0D, 1.0E-7D)) {
+- if (!DoubleMath.fuzzyEquals(voxelShape2.min(axis), 0.0, 1.0E-7)) {
- voxelShape2 = empty();
- }
+ if (one.isEmpty() & two.isEmpty()) {
+ return false;
+ }
-- return !joinIsNotEmpty(block(), joinUnoptimized(new SliceShape(voxelShape, axis, voxelShape.shape.getSize(axis) - 1), new SliceShape(voxelShape2, axis, 0), BooleanOp.OR), BooleanOp.ONLY_FIRST);
+- return !joinIsNotEmpty(
+- block(),
+- joinUnoptimized(new SliceShape(voxelShape, axis, voxelShape.shape.getSize(axis) - 1), new SliceShape(voxelShape2, axis, 0), BooleanOp.OR),
+- BooleanOp.ONLY_FIRST
+- );
- } else {
+ // we optimise getOpposite, so we can use it
+ // secondly, use our cache to retrieve sliced shape
@@ -3876,17 +3913,13 @@ index 9176735c08a75854209f24113b0e78332249dc4d..17785f7c709073a01928e8e6a57702f8
}
public static boolean faceShapeOccludes(VoxelShape one, VoxelShape two) {
-- if (one != block() && two != block()) {
-- if (one.isEmpty() && two.isEmpty()) {
-- return false;
-- } else {
-- return !joinIsNotEmpty(block(), joinUnoptimized(one, two, BooleanOp.OR), BooleanOp.ONLY_FIRST);
-- }
-- } else {
+- return one == block()
+- || two == block()
+- || (!one.isEmpty() || !two.isEmpty()) && !joinIsNotEmpty(block(), joinUnoptimized(one, two, BooleanOp.OR), BooleanOp.ONLY_FIRST);
+ // Paper start - optimise collisions
+ if (one.occludesFullBlockIfCached() || two.occludesFullBlockIfCached()) {
- return true;
- }
++ return true;
++ }
+
+ final boolean s1Empty = one.isEmpty();
+ final boolean s2Empty = two.isEmpty();
@@ -3908,7 +3941,7 @@ index 9176735c08a75854209f24113b0e78332249dc4d..17785f7c709073a01928e8e6a57702f8
@VisibleForTesting
diff --git a/src/main/java/net/minecraft/world/phys/shapes/SliceShape.java b/src/main/java/net/minecraft/world/phys/shapes/SliceShape.java
-index cf469f9daa81da8bc330c9cac7e813db87f9f9af..d9256710e815a5cb55409a80d59df2029b98c0d7 100644
+index 53aa193f33a1a15376a59b8d6dd8cbc6cbec168b..a745ff8d115e1d0da6138e4f06726e0737bb1600 100644
--- a/src/main/java/net/minecraft/world/phys/shapes/SliceShape.java
+++ b/src/main/java/net/minecraft/world/phys/shapes/SliceShape.java
@@ -12,6 +12,7 @@ public class SliceShape extends VoxelShape {
@@ -3920,10 +3953,10 @@ index cf469f9daa81da8bc330c9cac7e813db87f9f9af..d9256710e815a5cb55409a80d59df202
private static DiscreteVoxelShape makeSlice(DiscreteVoxelShape voxelSet, Direction.Axis axis, int sliceWidth) {
diff --git a/src/main/java/net/minecraft/world/phys/shapes/VoxelShape.java b/src/main/java/net/minecraft/world/phys/shapes/VoxelShape.java
-index 15e2dfa9a17b4f19768c0cde0ad8031f0122cd33..6bd6385ad82481a099f3556ed2dbd3744888fc34 100644
+index 80899dc599f05198cc58524355b66791dc418141..6ed187fa64dcbd01927c5180739dc8aaaf1fbe72 100644
--- a/src/main/java/net/minecraft/world/phys/shapes/VoxelShape.java
+++ b/src/main/java/net/minecraft/world/phys/shapes/VoxelShape.java
-@@ -16,30 +16,438 @@ import net.minecraft.world.phys.BlockHitResult;
+@@ -16,37 +16,438 @@ import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
public abstract class VoxelShape {
@@ -3937,7 +3970,7 @@ index 15e2dfa9a17b4f19768c0cde0ad8031f0122cd33..6bd6385ad82481a099f3556ed2dbd374
+ private double offsetX;
+ private double offsetY;
+ private double offsetZ;
-+ private AABB singleAABBRepresentation;
++ @Nullable private AABB singleAABBRepresentation;
+ private double[] rootCoordinatesX;
+ private double[] rootCoordinatesY;
+ private double[] rootCoordinatesZ;
@@ -4335,7 +4368,14 @@ index 15e2dfa9a17b4f19768c0cde0ad8031f0122cd33..6bd6385ad82481a099f3556ed2dbd374
- if (this.isEmpty()) {
- throw (UnsupportedOperationException)Util.pauseInIde(new UnsupportedOperationException("No bounds for empty shape."));
- } else {
-- return new AABB(this.min(Direction.Axis.X), this.min(Direction.Axis.Y), this.min(Direction.Axis.Z), this.max(Direction.Axis.X), this.max(Direction.Axis.Y), this.max(Direction.Axis.Z));
+- return new AABB(
+- this.min(Direction.Axis.X),
+- this.min(Direction.Axis.Y),
+- this.min(Direction.Axis.Z),
+- this.max(Direction.Axis.X),
+- this.max(Direction.Axis.Y),
+- this.max(Direction.Axis.Z)
+- );
+ // Paper start - optimise collisions
+ if (this.isEmpty) {
+ throw Util.pauseInIde(new UnsupportedOperationException("No bounds for empty shape."));
@@ -4372,7 +4412,7 @@ index 15e2dfa9a17b4f19768c0cde0ad8031f0122cd33..6bd6385ad82481a099f3556ed2dbd374
}
public VoxelShape singleEncompassing() {
-@@ -53,19 +461,106 @@ public abstract class VoxelShape {
+@@ -69,26 +470,106 @@ public abstract class VoxelShape {
protected abstract DoubleList getCoords(Direction.Axis axis);
public boolean isEmpty() {
@@ -4390,14 +4430,20 @@ index 15e2dfa9a17b4f19768c0cde0ad8031f0122cd33..6bd6385ad82481a099f3556ed2dbd374
+ // Paper end - optimise collisions
+
public VoxelShape move(double x, double y, double z) {
-- return (VoxelShape)(this.isEmpty() ? Shapes.empty() : new ArrayVoxelShape(this.shape, (DoubleList)(new OffsetDoubleList(this.getCoords(Direction.Axis.X), x)), (DoubleList)(new OffsetDoubleList(this.getCoords(Direction.Axis.Y), y)), (DoubleList)(new OffsetDoubleList(this.getCoords(Direction.Axis.Z), z))));
+- return (VoxelShape)(this.isEmpty()
+- ? Shapes.empty()
+- : new ArrayVoxelShape(
+ // Paper start - optimise collisions
+ if (this.isEmpty) {
+ return Shapes.empty();
+ }
+
+ final ArrayVoxelShape ret = new ArrayVoxelShape(
-+ this.shape,
+ this.shape,
+- new OffsetDoubleList(this.getCoords(Direction.Axis.X), x),
+- new OffsetDoubleList(this.getCoords(Direction.Axis.Y), y),
+- new OffsetDoubleList(this.getCoords(Direction.Axis.Z), z)
+- ));
+ offsetList(this.getCoords(Direction.Axis.X), x),
+ offsetList(this.getCoords(Direction.Axis.Y), y),
+ offsetList(this.getCoords(Direction.Axis.Z), z)
@@ -4486,8 +4532,8 @@ index 15e2dfa9a17b4f19768c0cde0ad8031f0122cd33..6bd6385ad82481a099f3556ed2dbd374
}
public void forAllEdges(Shapes.DoubleLineConsumer consumer) {
-@@ -83,12 +578,43 @@ public abstract class VoxelShape {
- }, true);
+@@ -128,12 +609,43 @@ public abstract class VoxelShape {
+ );
}
+ // Paper start - optimise collisions
@@ -4535,7 +4581,7 @@ index 15e2dfa9a17b4f19768c0cde0ad8031f0122cd33..6bd6385ad82481a099f3556ed2dbd374
}
public double min(Direction.Axis axis, double from, double to) {
-@@ -115,37 +641,85 @@ public abstract class VoxelShape {
+@@ -160,43 +672,85 @@ public abstract class VoxelShape {
}) - 1;
}
@@ -4568,11 +4614,18 @@ index 15e2dfa9a17b4f19768c0cde0ad8031f0122cd33..6bd6385ad82481a099f3556ed2dbd374
return null;
- } else {
- Vec3 vec3 = end.subtract(start);
-- if (vec3.lengthSqr() < 1.0E-7D) {
+- if (vec3.lengthSqr() < 1.0E-7) {
- return null;
- } else {
-- Vec3 vec32 = start.add(vec3.scale(0.001D));
-- return this.shape.isFullWide(this.findIndex(Direction.Axis.X, vec32.x - (double)pos.getX()), this.findIndex(Direction.Axis.Y, vec32.y - (double)pos.getY()), this.findIndex(Direction.Axis.Z, vec32.z - (double)pos.getZ())) ? new BlockHitResult(vec32, Direction.getNearest(vec3.x, vec3.y, vec3.z).getOpposite(), pos, true) : AABB.clip(this.toAabbs(), start, end, pos);
+- Vec3 vec32 = start.add(vec3.scale(0.001));
+- return this.shape
+- .isFullWide(
+- this.findIndex(Direction.Axis.X, vec32.x - (double)pos.getX()),
+- this.findIndex(Direction.Axis.Y, vec32.y - (double)pos.getY()),
+- this.findIndex(Direction.Axis.Z, vec32.z - (double)pos.getZ())
+- )
+- ? new BlockHitResult(vec32, Direction.getNearest(vec3.x, vec3.y, vec3.z).getOpposite(), pos, true)
+- : AABB.clip(this.toAabbs(), start, end, pos);
+ }
+
+ final Vec3 directionOpposite = end.subtract(start);
@@ -4615,10 +4668,10 @@ index 15e2dfa9a17b4f19768c0cde0ad8031f0122cd33..6bd6385ad82481a099f3556ed2dbd374
- if (vec3s[0] == null || target.distanceToSqr(d, e, f) < target.distanceToSqr(vec3s[0])) {
- vec3s[0] = new Vec3(d, e, f);
- }
-+ }
-
- });
- return Optional.of(vec3s[0]);
+ }
++
+ Vec3 ret = null;
+ double retDistance = Double.MAX_VALUE;
+
@@ -4634,14 +4687,14 @@ index 15e2dfa9a17b4f19768c0cde0ad8031f0122cd33..6bd6385ad82481a099f3556ed2dbd374
+ ret = new Vec3(x, y, z);
+ retDistance = dist;
+ }
- }
++ }
+
+ return Optional.ofNullable(ret);
+ // Paper end - optimise collisions
}
public VoxelShape getFaceShape(Direction facing) {
-@@ -180,7 +754,28 @@ public abstract class VoxelShape {
+@@ -233,7 +787,28 @@ public abstract class VoxelShape {
}
public double collide(Direction.Axis axis, AABB box, double maxDist) {