From f36b2a2c05168418caebfa2126ff1f5a91c92037 Mon Sep 17 00:00:00 2001 From: Aikar Date: Sat, 9 May 2020 19:18:26 -0400 Subject: [PATCH] Remove some Streams usage in Entity Collision While there is more down the collision system, remove some of the wrapping Spliterator stuff as even this wrapper stream has shown up in profiling. With other collision optimizations, we might also even avoid inner streams too. --- ...ptimize-Collision-to-not-load-chunks.patch | 5 +- ...me-Streams-usage-in-Entity-Collision.patch | 177 ++++++++++++++++++ 2 files changed, 180 insertions(+), 2 deletions(-) create mode 100644 Spigot-Server-Patches/Remove-some-Streams-usage-in-Entity-Collision.patch diff --git a/Spigot-Server-Patches/Optimize-Collision-to-not-load-chunks.patch b/Spigot-Server-Patches/Optimize-Collision-to-not-load-chunks.patch index 36a90f6cf0..4664585ead 100644 --- a/Spigot-Server-Patches/Optimize-Collision-to-not-load-chunks.patch +++ b/Spigot-Server-Patches/Optimize-Collision-to-not-load-chunks.patch @@ -40,12 +40,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start - ensure we don't load chunks + //int k2 = k1 >> 4; + //int l2 = i2 >> 4; -+ //boolean far = entity != null && MCUtil.distance(entity.locX(), entity.locY(), entity.locZ(), x, y, z) > 8; ++ boolean far = entity != null && MCUtil.distance(entity.locX(), entity.locY(), entity.locZ(), x, y, z) > 1; + blockposition_mutableblockposition.setValues(x, y, z); // Paper - moved up ++ + IBlockData iblockdata = ICollisionAccess.this.getTypeIfLoaded(blockposition_mutableblockposition); + if (iblockdata == null) { + if (!(entity instanceof EntityPlayer) || entity.world.paperConfig.preventMovingIntoUnloadedChunks) { -+ VoxelShape voxelshape3 = VoxelShapes.a(new AxisAlignedBB(new BlockPosition(x, y, z))); ++ VoxelShape voxelshape3 = VoxelShapes.of(far ? entity.getBoundingBox() : new AxisAlignedBB(new BlockPosition(x, y, z))); + consumer.accept(voxelshape3); + return true; + } diff --git a/Spigot-Server-Patches/Remove-some-Streams-usage-in-Entity-Collision.patch b/Spigot-Server-Patches/Remove-some-Streams-usage-in-Entity-Collision.patch new file mode 100644 index 0000000000..30f5ed9598 --- /dev/null +++ b/Spigot-Server-Patches/Remove-some-Streams-usage-in-Entity-Collision.patch @@ -0,0 +1,177 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sat, 9 May 2020 18:36:27 -0400 +Subject: [PATCH] Remove some Streams usage in Entity Collision + +While there is more down the collision system, remove some of the wrapping +Spliterator stuff as even this wrapper stream has shown up in profiling. + +With other collision optimizations, we might also even avoid inner streams too. + +diff --git a/src/main/java/net/minecraft/server/GeneratorAccess.java b/src/main/java/net/minecraft/server/GeneratorAccess.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/GeneratorAccess.java ++++ b/src/main/java/net/minecraft/server/GeneratorAccess.java +@@ -0,0 +0,0 @@ public interface GeneratorAccess extends IEntityAccess, IWorldReader, VirtualLev + this.a((EntityHuman) null, i, blockposition, j); + } + ++ @Override default java.util.List getEntityCollisions(@Nullable Entity entity, AxisAlignedBB axisalignedbb, Set set, boolean returnFast) {return IEntityAccess.super.getEntityCollisions(entity, axisalignedbb, set, returnFast); } // Paper + @Override + default Stream b(@Nullable Entity entity, AxisAlignedBB axisalignedbb, Set set) { + return IEntityAccess.super.b(entity, axisalignedbb, set); +diff --git a/src/main/java/net/minecraft/server/ICollisionAccess.java b/src/main/java/net/minecraft/server/ICollisionAccess.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/ICollisionAccess.java ++++ b/src/main/java/net/minecraft/server/ICollisionAccess.java +@@ -0,0 +0,0 @@ public interface ICollisionAccess extends IBlockAccess { + } + + default boolean a(@Nullable Entity entity, AxisAlignedBB axisalignedbb, Set set) { +- return this.c(entity, axisalignedbb, set).allMatch(VoxelShape::isEmpty); ++ // Paper start - reduce stream usage ++ java.util.List blockCollisions = getBlockCollision(entity, axisalignedbb, true); ++ for (int i = 0; i < blockCollisions.size(); i++) { ++ VoxelShape blockCollision = blockCollisions.get(i); ++ if (!blockCollision.isEmpty()) { ++ return false; ++ } ++ } ++ return getEntityCollisions(entity, axisalignedbb, set, true).isEmpty(); ++ // Paper end + } + ++ default java.util.List getEntityCollisions(@Nullable Entity entity, AxisAlignedBB axisalignedbb, Set set, boolean returnFast) { return java.util.Collections.emptyList(); } // Paper + default Stream b(@Nullable Entity entity, AxisAlignedBB axisalignedbb, Set set) { + return Stream.empty(); + } + + default Stream c(@Nullable Entity entity, AxisAlignedBB axisalignedbb, Set set) { +- return Streams.concat(new Stream[]{this.b(entity, axisalignedbb), this.b(entity, axisalignedbb, set)}); ++ // Paper start - reduce stream usage ++ java.util.List blockCollisions = getBlockCollision(entity, axisalignedbb, false); ++ java.util.List entityCollisions = getEntityCollisions(entity, axisalignedbb, set, false); ++ return Stream.concat(blockCollisions.stream(), entityCollisions.stream()); ++ // Paper end + } + + default Stream b(@Nullable final Entity entity, AxisAlignedBB axisalignedbb) { ++ // Paper start - reduce stream usage ++ java.util.List collision = getBlockCollision(entity, axisalignedbb, false); ++ return !collision.isEmpty() ? collision.stream() : Stream.empty(); ++ } ++ ++ default java.util.List getBlockCollision(@Nullable final Entity entity, AxisAlignedBB axisalignedbb, boolean returnFast) { ++ // Paper end + int i = MathHelper.floor(axisalignedbb.minX - 1.0E-7D) - 1; + int j = MathHelper.floor(axisalignedbb.maxX + 1.0E-7D) + 1; + int k = MathHelper.floor(axisalignedbb.minY - 1.0E-7D) - 1; +@@ -0,0 +0,0 @@ public interface ICollisionAccess extends IBlockAccess { + final BlockPosition.MutableBlockPosition blockposition_mutableblockposition = new BlockPosition.MutableBlockPosition(); + final VoxelShape voxelshape = VoxelShapes.a(axisalignedbb); + +- return StreamSupport.stream(new AbstractSpliterator(Long.MAX_VALUE, 1280) { +- boolean a = entity == null; +- +- public boolean tryAdvance(Consumer consumer) { +- if (!this.a) { +- this.a = true; ++ // Paper start - reduce stream usage (this part done by Aikar) ++ java.util.List collisions = new java.util.ArrayList<>(); ++ if (true) {//return StreamSupport.stream(new AbstractSpliterator(Long.MAX_VALUE, 1280) { ++ if (true) { //public boolean tryAdvance(Consumer consumer) {*/ // Paper ++ if (entity != null) { ++ // Paper end + VoxelShape voxelshape1 = ICollisionAccess.this.getWorldBorder().a(); + boolean flag = VoxelShapes.c(voxelshape1, VoxelShapes.a(entity.getBoundingBox().shrink(1.0E-7D)), OperatorBoolean.AND); + boolean flag1 = VoxelShapes.c(voxelshape1, VoxelShapes.a(entity.getBoundingBox().g(1.0E-7D)), OperatorBoolean.AND); + + if (!flag && flag1) { +- consumer.accept(voxelshape1); +- return true; ++ collisions.add(voxelshape1);// Paper ++ if (returnFast) return collisions; + } + } + +@@ -0,0 +0,0 @@ public interface ICollisionAccess extends IBlockAccess { + IBlockData iblockdata = ICollisionAccess.this.getTypeIfLoaded(blockposition_mutableblockposition); + if (iblockdata == null) { + if (!(entity instanceof EntityPlayer) || entity.world.paperConfig.preventMovingIntoUnloadedChunks) { +- VoxelShape voxelshape3 = VoxelShapes.of(far ? entity.getBoundingBox() : new AxisAlignedBB(new BlockPosition(x, y, z))); +- consumer.accept(voxelshape3); +- return true; ++ collisions.add(VoxelShapes.of(far ? entity.getBoundingBox() : new AxisAlignedBB(new BlockPosition(x, y, z)))); ++ if (returnFast) return collisions; + } + } else { + //blockposition_mutableblockposition.d(k1, l1, i2); // moved up +@@ -0,0 +0,0 @@ public interface ICollisionAccess extends IBlockAccess { + + if (voxelshape2 == VoxelShapes.fullCube()) { + if (axisalignedbb.intersects(x, y, z, x + 1.0D, y + 1.0D, z + 1.0D)) { +- consumer.accept(voxelshape2.offset(x, y, z)); +- return true; ++ collisions.add(voxelshape2.offset(x, y, z)); ++ if (returnFast) return collisions; + } + } else { + VoxelShape shape = voxelshape2.offset(x, y, z); + if (VoxelShapes.applyOperation(shape, voxelshape, OperatorBoolean.AND)) { +- consumer.accept(shape); +- return true; ++ collisions.add(shape); ++ if (returnFast) return collisions; + } + // Paper end + } +@@ -0,0 +0,0 @@ public interface ICollisionAccess extends IBlockAccess { + } + } + +- return false; ++ //return false; // Paper + } +- }, false); ++ } //}, false); ++ return collisions; // Paper + } + } +diff --git a/src/main/java/net/minecraft/server/IEntityAccess.java b/src/main/java/net/minecraft/server/IEntityAccess.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/IEntityAccess.java ++++ b/src/main/java/net/minecraft/server/IEntityAccess.java +@@ -0,0 +0,0 @@ public interface IEntityAccess { + // Paper start - remove streams from entity collision + if (axisalignedbb.getAverageSideLength() < 1.0E-7D) { + return Stream.empty(); +- + } ++ return getEntityCollisions(entity, axisalignedbb, set, false).stream(); ++ } ++ default List getEntityCollisions(@Nullable Entity entity, AxisAlignedBB axisalignedbb, Set set, boolean returnFast) { + AxisAlignedBB selection = axisalignedbb.grow(1.0E-7D); + List entities = entity != null && entity.hardCollides() ? getEntities(entity, selection) : getHardCollidingEntities(entity, selection); + List shapes = new java.util.ArrayList<>(); +@@ -0,0 +0,0 @@ public interface IEntityAccess { + + if (otherEntityBox != null && selection.intersects(otherEntityBox)) { + shapes.add(VoxelShapes.of(otherEntityBox)); ++ if (returnFast) return shapes; + } + + if (entity != null) { +@@ -0,0 +0,0 @@ public interface IEntityAccess { + + if (otherEntityHardBox != null && selection.intersects(otherEntityHardBox)) { + shapes.add(VoxelShapes.of(otherEntityHardBox)); ++ if (returnFast) return shapes; + } + } + } + +- return shapes.stream(); ++ return shapes; + // Paper end + } +