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 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 new file mode 100644
index 0000000000000000000000000000000000000000..7ef9775d351446637dd70e79497164913845c729 index 0000000000000000000000000000000000000000..a009068a2ac9c1671978cfd942b83c5b414b3c7a
--- /dev/null --- /dev/null
+++ b/src/main/java/me/jellysquid/mods/lithium/common/entity/LithiumEntityCollisions.java +++ 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; +package me.jellysquid.mods.lithium.common.entity;
+ +
+import dev.tr7zw.yatopia.EntityFilter; +import dev.tr7zw.yatopia.EntityFilter;
@ -228,27 +228,13 @@ index 0000000000000000000000000000000000000000..7ef9775d351446637dd70e7949716491
+ public static Producer<AxisAlignedBB> getBlockCollisionProducerAABB(ICollisionAccess world, Entity entity, AxisAlignedBB box) { + public static Producer<AxisAlignedBB> getBlockCollisionProducerAABB(ICollisionAccess world, Entity entity, AxisAlignedBB box) {
+ final ChunkAwareBlockCollisionSweeper sweeper = new ChunkAwareBlockCollisionSweeper(world, entity, box); + final ChunkAwareBlockCollisionSweeper sweeper = new ChunkAwareBlockCollisionSweeper(world, entity, box);
+ +
+ return new Producer<AxisAlignedBB>() { + return consumer -> {
+ private boolean skipWorldBorderCheck = entity == null; + VoxelShape shape = sweeper.getNextCollidedShape();
+
+ @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) { + if (shape != null) {
+ consumer.accept(shape.getBoundingBox()); + consumer.accept(shape.getBoundingBox());
+ return true; + return true;
+ } + }
+ return false; + return false;
+ }
+ }; + };
+ } + }
+ +
@ -264,7 +250,7 @@ index 0000000000000000000000000000000000000000..7ef9775d351446637dd70e7949716491
+ +
+ final ChunkAwareBlockCollisionSweeper sweeper = new ChunkAwareBlockCollisionSweeper(world, entity, box); + final ChunkAwareBlockCollisionSweeper sweeper = new ChunkAwareBlockCollisionSweeper(world, entity, box);
+ +
+ VoxelShape shape = sweeper.step(); + VoxelShape shape = sweeper.getNextCollidedShape();
+ return shape != null; + return shape != null;
+ } + }
+ +
@ -351,7 +337,7 @@ index 0000000000000000000000000000000000000000..7ef9775d351446637dd70e7949716491
+ * + *
+ * @return True if the {@param box} is fully within the {@param border}, otherwise false. + * @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 wboxMinX = Math.floor(border.getMinX());
+ double wboxMinZ = Math.floor(border.getMinZ()); + 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; + 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(); + WorldBorder border = world.getWorldBorder();
+ +
+ boolean isInsideBorder = isBoxFullyWithinWorldBorder(border, entity.getBoundingBox().shrink(EPSILON)); + boolean isInsideBorder = isWithinWorldBorder(border, entity.getBoundingBox().shrink(EPSILON));
+ boolean isCrossingBorder = isBoxFullyWithinWorldBorder(border, entity.getBoundingBox().grow(EPSILON)); + boolean isCrossingBorder = isWithinWorldBorder(border, entity.getBoundingBox().grow(EPSILON));
+ +
+ return !isInsideBorder && isCrossingBorder; + 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 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 new file mode 100644
index 0000000000000000000000000000000000000000..b9d279d1a9703c17221d4219b86b8f31bdcc2895 index 0000000000000000000000000000000000000000..508fe7cf5281cff7528b90e584c17e73fc5a2388
--- /dev/null --- /dev/null
+++ b/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
@@ -0,0 +1,247 @@ @@ -0,0 +1,279 @@
+package me.jellysquid.mods.lithium.common.entity.movement; +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.AxisAlignedBB;
+import net.minecraft.server.BlockPosition; +import net.minecraft.server.BlockPosition;
+import net.minecraft.server.Blocks; +import net.minecraft.server.Blocks;
@ -422,6 +409,8 @@ index 0000000000000000000000000000000000000000..b9d279d1a9703c17221d4219b86b8f31
+ private final ICollisionAccess view; + private final ICollisionAccess view;
+ private final VoxelShapeCollision context; + private final VoxelShapeCollision context;
+ +
+ private final Entity entity;
+
+ //limits of the area without extension for oversized blocks + //limits of the area without extension for oversized blocks
+ private final int minX, minY, minZ, maxX, maxY, maxZ; + private final int minX, minY, minZ, maxX, maxY, maxZ;
+ +
@ -437,6 +426,7 @@ index 0000000000000000000000000000000000000000..b9d279d1a9703c17221d4219b86b8f31
+ private boolean sectionOversizedBlocks; + private boolean sectionOversizedBlocks;
+ private IChunkAccess cachedChunk; + private IChunkAccess cachedChunk;
+ private ChunkSection cachedChunkSection; + private ChunkSection cachedChunkSection;
+ private boolean needEntityCollisionCheck;
+ +
+ public ChunkAwareBlockCollisionSweeper(ICollisionAccess view, Entity entity, AxisAlignedBB box) { + public ChunkAwareBlockCollisionSweeper(ICollisionAccess view, Entity entity, AxisAlignedBB box) {
+ this.box = box; + this.box = box;
@ -444,6 +434,8 @@ index 0000000000000000000000000000000000000000..b9d279d1a9703c17221d4219b86b8f31
+ // todo: ivan, make obfhelpers + // todo: ivan, make obfhelpers
+ this.context = entity == null ? VoxelShapeCollision.a() : VoxelShapeCollision.a(entity); + this.context = entity == null ? VoxelShapeCollision.a() : VoxelShapeCollision.a(entity);
+ this.view = view; + this.view = view;
+ this.entity = entity;
+ this.needEntityCollisionCheck = entity != null;
+ +
+ this.minX = MathHelper.floor(box.minX - EPSILON); + this.minX = MathHelper.floor(box.minX - EPSILON);
+ this.maxX = MathHelper.floor(box.maxX + EPSILON); + this.maxX = MathHelper.floor(box.maxX + EPSILON);
@ -517,17 +509,33 @@ index 0000000000000000000000000000000000000000..b9d279d1a9703c17221d4219b86b8f31
+ return true; + 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 + * 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 + * @return null if no VoxelShape is left in the area, otherwise the next VoxelShape
+ */ + */
+ public VoxelShape step() { + private VoxelShape getNextBlockCollision() {
+ while (true) { + while (true) {
+ if (this.cIterated >= this.cTotalSize) { + if (this.cIterated >= this.cTotalSize) {
+ if (!this.nextSection()) { + if (!this.nextSection()) {
+ return null; + break;
+ } + }
+ } + }
+ this.cIterated++; + 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) 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 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 --- a/src/main/java/net/minecraft/server/BlockBase.java
+++ b/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 { @@ -345,6 +345,8 @@ 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;
} }
+ // Yatiopia end
// Tuinity end // Tuinity end
+ public final boolean shapeExceedsCubeUncached() { return this.a == null || this.a.c; } // Yatopia - uncached shapeExceedsCube due to collisions stuff
+
// Tuinity start // Tuinity start
@@ -356,8 +357,6 @@ public abstract class BlockBase { protected boolean isTicking;
if (!this.getBlock().o()) { protected Fluid fluid;
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) {
diff --git a/src/main/java/net/minecraft/server/ChunkSection.java b/src/main/java/net/minecraft/server/ChunkSection.java 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 --- a/src/main/java/net/minecraft/server/ChunkSection.java
+++ b/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; @@ -4,7 +4,7 @@ import java.util.function.Predicate;
@ -77,31 +36,27 @@ index cebd808e273dbdb88feb16920dd7a2f60390b34f..478af91f52272424da61d62653429829
short tickingBlockCount; // Paper - private -> package-private short tickingBlockCount; // Paper - private -> package-private
private short e; private short e;
final DataPaletteBlock<IBlockData> blockIds; // Paper - package-private 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 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()) { if (!iblockdata1.isAir()) {
--this.nonEmptyBlockCount; --this.nonEmptyBlockCount;
+ if(iblockdata1.shapeExceedsCube()){ //Yatopia - lithium oversized blocks count + if (iblockdata1.shapeExceedsCubeUncached()) this.oversizedBlockCount--; // Yatopia
+ --this.oversizedBlockCount;
+ } // Yatopia end
if (iblockdata1.isTicking()) { if (iblockdata1.isTicking()) {
--this.tickingBlockCount; --this.tickingBlockCount;
// Paper start // Paper start
@@ -81,6 +85,9 @@ public class ChunkSection { @@ -81,6 +83,7 @@ public class ChunkSection {
if (!iblockdata.isAir()) { if (!iblockdata.isAir()) {
++this.nonEmptyBlockCount; ++this.nonEmptyBlockCount;
+ if(iblockdata.shapeExceedsCube()){ //Yatopia - lithium oversized blocks count + if (iblockdata.shapeExceedsCubeUncached()) this.oversizedBlockCount++; // Yatopia
+ ++this.oversizedBlockCount;
+ } // Yatopia end
if (iblockdata.isTicking()) { if (iblockdata.isTicking()) {
++this.tickingBlockCount; ++this.tickingBlockCount;
// Paper start // Paper start
@@ -126,10 +133,12 @@ public class ChunkSection { @@ -126,10 +129,12 @@ public class ChunkSection {
// Paper start // Paper start
this.tickingList.clear(); this.tickingList.clear();
// Paper end // Paper end
@ -110,11 +65,11 @@ index cebd808e273dbdb88feb16920dd7a2f60390b34f..478af91f52272424da61d62653429829
this.tickingBlockCount = 0; this.tickingBlockCount = 0;
this.e = 0; this.e = 0;
this.blockIds.forEachLocation((iblockdata, location) -> { // Paper this.blockIds.forEachLocation((iblockdata, location) -> { // Paper
+ if (iblockdata.shapeExceedsCube()) this.oversizedBlockCount += location; // Yatopia + if (iblockdata.shapeExceedsCubeUncached()) this.oversizedBlockCount += location; // Yatopia
Fluid fluid = iblockdata.getFluid(); Fluid fluid = iblockdata.getFluid();
if (!iblockdata.isAir()) { if (!iblockdata.isAir()) {
@@ -173,4 +182,11 @@ public class ChunkSection { @@ -173,4 +178,11 @@ public class ChunkSection {
public boolean a(Predicate<IBlockData> predicate) { public boolean a(Predicate<IBlockData> predicate) {
return this.blockIds.contains(predicate); return this.blockIds.contains(predicate);
} }