Fix oversized block collisions

We went thru a bunch of effort for this fix, but its finally been patched.
In the meantime I ported jellysquid's latest changes to entity collisions which also work completely fine.

Thanks to Simon ( @smonnnn ) who is also going to be the co-author of this commit cuz he was the one to properly implement the problematic patch .
These changes should lower your mspt.

Fixes #165 
Fixes #178 

Co-authored-by: Simon L <slooij1@gmail.com>
This commit is contained in:
Ivan Pekov 2020-08-31 21:35:20 +03:00 committed by GitHub
parent 71c51a9aa2
commit 339da44a99
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 64 additions and 91 deletions

View File

@ -178,10 +178,10 @@ index 0000000000000000000000000000000000000000..20f80ae80de91615ea02f0771f7c020c
+}
diff --git a/src/main/java/me/jellysquid/mods/lithium/common/entity/LithiumEntityCollisions.java b/src/main/java/me/jellysquid/mods/lithium/common/entity/LithiumEntityCollisions.java
new file mode 100644
index 0000000000000000000000000000000000000000..7ef9775d351446637dd70e79497164913845c729
index 0000000000000000000000000000000000000000..a009068a2ac9c1671978cfd942b83c5b414b3c7a
--- /dev/null
+++ b/src/main/java/me/jellysquid/mods/lithium/common/entity/LithiumEntityCollisions.java
@@ -0,0 +1,193 @@
@@ -0,0 +1,179 @@
+package me.jellysquid.mods.lithium.common.entity;
+
+import dev.tr7zw.yatopia.EntityFilter;
@ -228,27 +228,13 @@ index 0000000000000000000000000000000000000000..7ef9775d351446637dd70e7949716491
+ public static Producer<AxisAlignedBB> getBlockCollisionProducerAABB(ICollisionAccess world, Entity entity, AxisAlignedBB box) {
+ final ChunkAwareBlockCollisionSweeper sweeper = new ChunkAwareBlockCollisionSweeper(world, entity, box);
+
+ return new Producer<AxisAlignedBB>() {
+ private boolean skipWorldBorderCheck = entity == null;
+
+ @Override
+ public boolean computeNext(Consumer<? super AxisAlignedBB> consumer) {
+ if (!this.skipWorldBorderCheck) {
+ this.skipWorldBorderCheck = true;
+
+ if (canEntityCollideWithWorldBorder(world, entity)) {
+ consumer.accept(world.getWorldBorder().asVoxelShape().getBoundingBox());
+ return true;
+ }
+ }
+
+ VoxelShape shape = sweeper.step();
+ if (shape != null) {
+ consumer.accept(shape.getBoundingBox());
+ return true;
+ }
+ return false;
+ return consumer -> {
+ VoxelShape shape = sweeper.getNextCollidedShape();
+ if (shape != null) {
+ consumer.accept(shape.getBoundingBox());
+ return true;
+ }
+ return false;
+ };
+ }
+
@ -264,7 +250,7 @@ index 0000000000000000000000000000000000000000..7ef9775d351446637dd70e7949716491
+
+ final ChunkAwareBlockCollisionSweeper sweeper = new ChunkAwareBlockCollisionSweeper(world, entity, box);
+
+ VoxelShape shape = sweeper.step();
+ VoxelShape shape = sweeper.getNextCollidedShape();
+ return shape != null;
+ }
+
@ -351,7 +337,7 @@ index 0000000000000000000000000000000000000000..7ef9775d351446637dd70e7949716491
+ *
+ * @return True if the {@param box} is fully within the {@param border}, otherwise false.
+ */
+ public static boolean isBoxFullyWithinWorldBorder(WorldBorder border, AxisAlignedBB box) {
+ public static boolean isWithinWorldBorder(WorldBorder border, AxisAlignedBB box) {
+ double wboxMinX = Math.floor(border.getMinX());
+ double wboxMinZ = Math.floor(border.getMinZ());
+
@ -362,11 +348,11 @@ index 0000000000000000000000000000000000000000..7ef9775d351446637dd70e7949716491
+ box.maxX >= wboxMinX && box.maxX < wboxMaxX && box.maxZ >= wboxMinZ && box.maxZ < wboxMaxZ;
+ }
+
+ private static boolean canEntityCollideWithWorldBorder(ICollisionAccess world, Entity entity) {
+ public static boolean canEntityCollideWithWorldBorder(ICollisionAccess world, Entity entity) {
+ WorldBorder border = world.getWorldBorder();
+
+ boolean isInsideBorder = isBoxFullyWithinWorldBorder(border, entity.getBoundingBox().shrink(EPSILON));
+ boolean isCrossingBorder = isBoxFullyWithinWorldBorder(border, entity.getBoundingBox().grow(EPSILON));
+ boolean isInsideBorder = isWithinWorldBorder(border, entity.getBoundingBox().shrink(EPSILON));
+ boolean isCrossingBorder = isWithinWorldBorder(border, entity.getBoundingBox().grow(EPSILON));
+
+ return !isInsideBorder && isCrossingBorder;
+ }
@ -377,12 +363,13 @@ index 0000000000000000000000000000000000000000..7ef9775d351446637dd70e7949716491
+}
diff --git a/src/main/java/me/jellysquid/mods/lithium/common/entity/movement/ChunkAwareBlockCollisionSweeper.java b/src/main/java/me/jellysquid/mods/lithium/common/entity/movement/ChunkAwareBlockCollisionSweeper.java
new file mode 100644
index 0000000000000000000000000000000000000000..b9d279d1a9703c17221d4219b86b8f31bdcc2895
index 0000000000000000000000000000000000000000..508fe7cf5281cff7528b90e584c17e73fc5a2388
--- /dev/null
+++ b/src/main/java/me/jellysquid/mods/lithium/common/entity/movement/ChunkAwareBlockCollisionSweeper.java
@@ -0,0 +1,247 @@
@@ -0,0 +1,279 @@
+package me.jellysquid.mods.lithium.common.entity.movement;
+
+import me.jellysquid.mods.lithium.common.entity.LithiumEntityCollisions;
+import net.minecraft.server.AxisAlignedBB;
+import net.minecraft.server.BlockPosition;
+import net.minecraft.server.Blocks;
@ -422,6 +409,8 @@ index 0000000000000000000000000000000000000000..b9d279d1a9703c17221d4219b86b8f31
+ private final ICollisionAccess view;
+ private final VoxelShapeCollision context;
+
+ private final Entity entity;
+
+ //limits of the area without extension for oversized blocks
+ private final int minX, minY, minZ, maxX, maxY, maxZ;
+
@ -437,6 +426,7 @@ index 0000000000000000000000000000000000000000..b9d279d1a9703c17221d4219b86b8f31
+ private boolean sectionOversizedBlocks;
+ private IChunkAccess cachedChunk;
+ private ChunkSection cachedChunkSection;
+ private boolean needEntityCollisionCheck;
+
+ public ChunkAwareBlockCollisionSweeper(ICollisionAccess view, Entity entity, AxisAlignedBB box) {
+ this.box = box;
@ -444,6 +434,8 @@ index 0000000000000000000000000000000000000000..b9d279d1a9703c17221d4219b86b8f31
+ // todo: ivan, make obfhelpers
+ this.context = entity == null ? VoxelShapeCollision.a() : VoxelShapeCollision.a(entity);
+ this.view = view;
+ this.entity = entity;
+ this.needEntityCollisionCheck = entity != null;
+
+ this.minX = MathHelper.floor(box.minX - EPSILON);
+ this.maxX = MathHelper.floor(box.maxX + EPSILON);
@ -517,17 +509,33 @@ index 0000000000000000000000000000000000000000..b9d279d1a9703c17221d4219b86b8f31
+ return true;
+ }
+
+ public VoxelShape getNextCollidedShape() {
+ VoxelShape shape = null;
+
+ if (this.needEntityCollisionCheck) {
+ shape = this.getNextEntityCollision();
+
+ this.needEntityCollisionCheck = false;
+ }
+
+ if (shape == null) {
+ shape = this.getNextBlockCollision();
+ }
+
+ return shape;
+ }
+
+
+ /**
+ * Advances the sweep forward until finding a block with a box-colliding VoxelShape
+ *
+ * @return null if no VoxelShape is left in the area, otherwise the next VoxelShape
+ */
+ public VoxelShape step() {
+ private VoxelShape getNextBlockCollision() {
+ while (true) {
+ if (this.cIterated >= this.cTotalSize) {
+ if (!this.nextSection()) {
+ return null;
+ break;
+ }
+ }
+ this.cIterated++;
@ -578,6 +586,16 @@ index 0000000000000000000000000000000000000000..b9d279d1a9703c17221d4219b86b8f31
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private VoxelShape getNextEntityCollision() {
+ if (LithiumEntityCollisions.canEntityCollideWithWorldBorder(this.view, this.entity)) {
+ return this.view.getWorldBorder().asVoxelShape();
+ }
+
+ return null;
+ }
+
+ /**

View File

@ -7,61 +7,20 @@ Original code by JellySquid, licensed under LGPLv3
you can find the original code on https://github.com/jellysquid3/lithium-fabric/ (Yarn mappings)
diff --git a/src/main/java/net/minecraft/server/BlockBase.java b/src/main/java/net/minecraft/server/BlockBase.java
index 1d02880e5818d22c13d67d3f44844a2cca51c164..4ece27e3e6885246bc8b54b9277e01211db4f989 100644
index 1d02880e5818d22c13d67d3f44844a2cca51c164..13f541390040d07229de0fbb1cfa4bcfe7d0794f 100644
--- a/src/main/java/net/minecraft/server/BlockBase.java
+++ b/src/main/java/net/minecraft/server/BlockBase.java
@@ -339,10 +339,11 @@ public abstract class BlockBase {
// Paper end
// Tuinity start - micro the hell out of this call
- protected boolean shapeExceedsCube = true;
+ protected boolean shapeExceedsCube = this.shapeExceedsCube(); // Yatopia start - re add this function or collisions break
public final boolean shapeExceedsCube() {
- return this.shapeExceedsCube;
+ return this.a == null || this.a.c;
@@ -345,6 +345,8 @@ public abstract class BlockBase {
}
+ // Yatiopia end
// Tuinity end
+ public final boolean shapeExceedsCubeUncached() { return this.a == null || this.a.c; } // Yatopia - uncached shapeExceedsCube due to collisions stuff
+
// Tuinity start
@@ -356,8 +357,6 @@ public abstract class BlockBase {
if (!this.getBlock().o()) {
this.a = new BlockBase.BlockData.Cache(this.p());
}
- this.shapeExceedsCube = this.a == null || this.a.c; // Tuinity - moved from actual method to here
-
}
public Block getBlock() {
@@ -607,7 +606,25 @@ public abstract class BlockBase {
}
public IBlockData updateState(EnumDirection enumdirection, IBlockData iblockdata, GeneratorAccess generatoraccess, BlockPosition blockposition, BlockPosition blockposition1) {
- return this.getBlock().updateState(this.p(), enumdirection, iblockdata, generatoraccess, blockposition, blockposition1);
+ // Yatopia start
+ IBlockData updated = this.getBlock().updateState(this.p(), enumdirection, iblockdata, generatoraccess, blockposition, blockposition1);
+ if (updated.shapeExceedsCube()) {
+ IChunkAccess chunk = generatoraccess.getChunkIfLoadedImmediately(blockposition1.getX() >> 4, blockposition1.getZ() >> 4);
+ if (chunk != null) {
+ ChunkSection section = chunk.getSections()[blockposition1.getY() >> 4];
+ if (section != null) section.oversizedBlockCount++;
+ }
+ } else {
+ if (iblockdata.shapeExceedsCube()) {
+ IChunkAccess chunk = generatoraccess.getChunkIfLoadedImmediately(blockposition.getX() >> 4, blockposition.getZ() >> 4);
+ if (chunk != null) {
+ ChunkSection section = chunk.getSections()[blockposition.getY() >> 4];
+ if (section != null) section.oversizedBlockCount--;
+ }
+ }
+ }
+ return updated;
+ // Yatopia end
}
public boolean a(IBlockAccess iblockaccess, BlockPosition blockposition, PathMode pathmode) {
protected boolean isTicking;
protected Fluid fluid;
diff --git a/src/main/java/net/minecraft/server/ChunkSection.java b/src/main/java/net/minecraft/server/ChunkSection.java
index cebd808e273dbdb88feb16920dd7a2f60390b34f..478af91f52272424da61d626534298290d6385f5 100644
index cebd808e273dbdb88feb16920dd7a2f60390b34f..d210ac3d5775491e9beb885dde608f5e8fda8eb2 100644
--- a/src/main/java/net/minecraft/server/ChunkSection.java
+++ b/src/main/java/net/minecraft/server/ChunkSection.java
@@ -4,7 +4,7 @@ import java.util.function.Predicate;
@ -77,31 +36,27 @@ index cebd808e273dbdb88feb16920dd7a2f60390b34f..478af91f52272424da61d62653429829
short tickingBlockCount; // Paper - private -> package-private
private short e;
final DataPaletteBlock<IBlockData> blockIds; // Paper - package-private
+ short oversizedBlockCount = 0; // Yatopia
+ private short oversizedBlockCount = 0; // Yatopia
final com.destroystokyo.paper.util.maplist.IBlockDataList tickingList = new com.destroystokyo.paper.util.maplist.IBlockDataList(); // Paper
@@ -67,6 +68,9 @@ public class ChunkSection {
@@ -67,6 +68,7 @@ public class ChunkSection {
if (!iblockdata1.isAir()) {
--this.nonEmptyBlockCount;
+ if(iblockdata1.shapeExceedsCube()){ //Yatopia - lithium oversized blocks count
+ --this.oversizedBlockCount;
+ } // Yatopia end
+ if (iblockdata1.shapeExceedsCubeUncached()) this.oversizedBlockCount--; // Yatopia
if (iblockdata1.isTicking()) {
--this.tickingBlockCount;
// Paper start
@@ -81,6 +85,9 @@ public class ChunkSection {
@@ -81,6 +83,7 @@ public class ChunkSection {
if (!iblockdata.isAir()) {
++this.nonEmptyBlockCount;
+ if(iblockdata.shapeExceedsCube()){ //Yatopia - lithium oversized blocks count
+ ++this.oversizedBlockCount;
+ } // Yatopia end
+ if (iblockdata.shapeExceedsCubeUncached()) this.oversizedBlockCount++; // Yatopia
if (iblockdata.isTicking()) {
++this.tickingBlockCount;
// Paper start
@@ -126,10 +133,12 @@ public class ChunkSection {
@@ -126,10 +129,12 @@ public class ChunkSection {
// Paper start
this.tickingList.clear();
// Paper end
@ -110,11 +65,11 @@ index cebd808e273dbdb88feb16920dd7a2f60390b34f..478af91f52272424da61d62653429829
this.tickingBlockCount = 0;
this.e = 0;
this.blockIds.forEachLocation((iblockdata, location) -> { // Paper
+ if (iblockdata.shapeExceedsCube()) this.oversizedBlockCount += location; // Yatopia
+ if (iblockdata.shapeExceedsCubeUncached()) this.oversizedBlockCount += location; // Yatopia
Fluid fluid = iblockdata.getFluid();
if (!iblockdata.isAir()) {
@@ -173,4 +182,11 @@ public class ChunkSection {
@@ -173,4 +178,11 @@ public class ChunkSection {
public boolean a(Predicate<IBlockData> predicate) {
return this.blockIds.contains(predicate);
}