diff options
Diffstat (limited to 'patches/server/1015-Collision-optimisations.patch')
-rw-r--r-- | patches/server/1015-Collision-optimisations.patch | 313 |
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) { |