From c4aa0cc0aabfc624940a3da87adc31c15fe5379a Mon Sep 17 00:00:00 2001 From: Spottedleaf Date: Mon, 4 Sep 2023 16:25:32 -0700 Subject: [PATCH] Move findSupportingBlock to LevelMixin This allows us to assume that the getChunkForCollisions method routes to getChunk(x, z, FULL, false) which allows us to avoid the indirection caused by different implementations of that method on different implementations of CollisionGetter. --- .../collisions/CollisionGetterMixin.java | 130 ------------------ .../moonrise/mixin/collisions/LevelMixin.java | 115 +++++++++++++++- src/main/resources/moonrise.mixins.json | 1 - 3 files changed, 113 insertions(+), 133 deletions(-) delete mode 100644 src/main/java/ca/spottedleaf/moonrise/mixin/collisions/CollisionGetterMixin.java diff --git a/src/main/java/ca/spottedleaf/moonrise/mixin/collisions/CollisionGetterMixin.java b/src/main/java/ca/spottedleaf/moonrise/mixin/collisions/CollisionGetterMixin.java deleted file mode 100644 index 094eca3..0000000 --- a/src/main/java/ca/spottedleaf/moonrise/mixin/collisions/CollisionGetterMixin.java +++ /dev/null @@ -1,130 +0,0 @@ -package ca.spottedleaf.moonrise.mixin.collisions; - -import ca.spottedleaf.moonrise.patches.collisions.CollisionUtil; -import ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState; -import ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape; -import net.minecraft.core.BlockPos; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.CollisionGetter; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import net.minecraft.world.phys.shapes.VoxelShape; -import org.jetbrains.annotations.Nullable; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; -import java.util.Optional; - -@Mixin(CollisionGetter.class) -public interface CollisionGetterMixin extends BlockGetter { - - @Shadow - @Nullable - BlockGetter getChunkForCollisions(final int chunkX, final int chunkZ); - - /** - * @reason Route to faster logic - * @author Spottedleaf - */ - @Overwrite - default Optional findSupportingBlock(final Entity entity, final AABB aabb) { - final int minBlockX = Mth.floor(aabb.minX - CollisionUtil.COLLISION_EPSILON) - 1; - final int maxBlockX = Mth.floor(aabb.maxX + CollisionUtil.COLLISION_EPSILON) + 1; - - final int minBlockY = Mth.floor(aabb.minY - CollisionUtil.COLLISION_EPSILON) - 1; - final int maxBlockY = Mth.floor(aabb.maxY + CollisionUtil.COLLISION_EPSILON) + 1; - - final int minBlockZ = Mth.floor(aabb.minZ - CollisionUtil.COLLISION_EPSILON) - 1; - final int maxBlockZ = Mth.floor(aabb.maxZ + CollisionUtil.COLLISION_EPSILON) + 1; - - CollisionUtil.LazyEntityCollisionContext collisionContext = null; - - final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); - BlockPos selected = null; - double selectedDistance = Double.MAX_VALUE; - - final Vec3 entityPos = entity.position(); - - BlockGetter lastChunk = null; - int lastChunkX = Integer.MIN_VALUE; - int lastChunkZ = Integer.MIN_VALUE; - - for (int currZ = minBlockZ; currZ <= maxBlockZ; ++currZ) { - pos.setZ(currZ); - for (int currX = minBlockX; currX <= maxBlockX; ++currX) { - pos.setX(currX); - - final int newChunkX = currX >> 4; - final int newChunkZ = currZ >> 4; - - final int chunkDiff = ((newChunkX ^ lastChunkX) | (newChunkZ ^ lastChunkZ)); - - if (chunkDiff != 0) { - lastChunk = this.getChunkForCollisions(newChunkX, newChunkZ); - } - - if (lastChunk == null) { - continue; - } - for (int currY = minBlockY; currY <= maxBlockY; ++currY) { - int edgeCount = ((currX == minBlockX || currX == maxBlockX) ? 1 : 0) + - ((currY == minBlockY || currY == maxBlockY) ? 1 : 0) + - ((currZ == minBlockZ || currZ == maxBlockZ) ? 1 : 0); - if (edgeCount == 3) { - continue; - } - - pos.setY(currY); - - final double distance = pos.distToCenterSqr(entityPos); - if (distance > selectedDistance || (distance == selectedDistance && selected.compareTo(pos) >= 0)) { - continue; - } - - final BlockState state = lastChunk.getBlockState(pos); - if (((CollisionBlockState)state).emptyCollisionShape()) { - continue; - } - - if ((edgeCount != 1 || state.hasLargeCollisionShape()) && (edgeCount != 2 || state.getBlock() == Blocks.MOVING_PISTON)) { - if (collisionContext == null) { - collisionContext = new CollisionUtil.LazyEntityCollisionContext(entity); - } - final VoxelShape blockCollision = state.getCollisionShape(lastChunk, pos, collisionContext); - if (blockCollision.isEmpty()) { - continue; - } - - AABB singleAABB = ((CollisionVoxelShape)blockCollision).getSingleAABBRepresentation(); - if (singleAABB != null) { - singleAABB = singleAABB.move((double)currX, (double)currY, (double)currZ); - if (!CollisionUtil.voxelShapeIntersect(aabb, singleAABB)) { - continue; - } - - selected = pos.immutable(); - selectedDistance = distance; - continue; - } - - final VoxelShape blockCollisionOffset = blockCollision.move((double)currX, (double)currY, (double)currZ); - - if (!CollisionUtil.voxelShapeIntersectNoEmpty(blockCollisionOffset, aabb)) { - continue; - } - - selected = pos.immutable(); - selectedDistance = distance; - continue; - } - } - } - } - - return Optional.ofNullable(selected); - } -} diff --git a/src/main/java/ca/spottedleaf/moonrise/mixin/collisions/LevelMixin.java b/src/main/java/ca/spottedleaf/moonrise/mixin/collisions/LevelMixin.java index 50c7647..e3a21c8 100644 --- a/src/main/java/ca/spottedleaf/moonrise/mixin/collisions/LevelMixin.java +++ b/src/main/java/ca/spottedleaf/moonrise/mixin/collisions/LevelMixin.java @@ -1,7 +1,10 @@ package ca.spottedleaf.moonrise.mixin.collisions; import ca.spottedleaf.moonrise.common.util.WorldUtil; +import ca.spottedleaf.moonrise.patches.chunk_getblock.GetBlockChunk; import ca.spottedleaf.moonrise.patches.collisions.CollisionUtil; +import ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState; +import ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape; import ca.spottedleaf.moonrise.patches.collisions.slices.EntityLookup; import ca.spottedleaf.moonrise.patches.collisions.world.CollisionEntityGetter; import ca.spottedleaf.moonrise.patches.collisions.world.CollisionLevel; @@ -14,7 +17,11 @@ import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.ClipContext; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkSource; +import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; @@ -460,13 +467,117 @@ public abstract class LevelMixin implements CollisionLevel, CollisionEntityGette rest[i - 1] = inflateAABBToVoxel(aabbs.get(i), expandByX, expandByY, expandByZ); } - // use optimized join + // use optimized implementation of ORing the shapes together final VoxelShape joined = Shapes.or(first, rest); // find free space - // don't need optimized join, as closestPointTo uses toAabbs() + // can use unoptimized join here (instead of join()), as closestPointTo uses toAabbs() final VoxelShape freeSpace = Shapes.joinUnoptimized(boundsShape, joined, BooleanOp.ONLY_FIRST); return freeSpace.closestPointTo(fromPosition); } + + /** + * @reason Route to faster logic + * @author Spottedleaf + */ + @Override + public final Optional findSupportingBlock(final Entity entity, final AABB aabb) { + final int minBlockX = Mth.floor(aabb.minX - CollisionUtil.COLLISION_EPSILON) - 1; + final int maxBlockX = Mth.floor(aabb.maxX + CollisionUtil.COLLISION_EPSILON) + 1; + + final int minBlockY = Mth.floor(aabb.minY - CollisionUtil.COLLISION_EPSILON) - 1; + final int maxBlockY = Mth.floor(aabb.maxY + CollisionUtil.COLLISION_EPSILON) + 1; + + final int minBlockZ = Mth.floor(aabb.minZ - CollisionUtil.COLLISION_EPSILON) - 1; + final int maxBlockZ = Mth.floor(aabb.maxZ + CollisionUtil.COLLISION_EPSILON) + 1; + + CollisionUtil.LazyEntityCollisionContext collisionContext = null; + + final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); + BlockPos selected = null; + double selectedDistance = Double.MAX_VALUE; + + final Vec3 entityPos = entity.position(); + + LevelChunk lastChunk = null; + int lastChunkX = Integer.MIN_VALUE; + int lastChunkZ = Integer.MIN_VALUE; + + final ChunkSource chunkSource = this.getChunkSource(); + + for (int currZ = minBlockZ; currZ <= maxBlockZ; ++currZ) { + pos.setZ(currZ); + for (int currX = minBlockX; currX <= maxBlockX; ++currX) { + pos.setX(currX); + + final int newChunkX = currX >> 4; + final int newChunkZ = currZ >> 4; + + final int chunkDiff = ((newChunkX ^ lastChunkX) | (newChunkZ ^ lastChunkZ)); + + if (chunkDiff != 0) { + lastChunk = (LevelChunk)chunkSource.getChunk(newChunkX, newChunkZ, ChunkStatus.FULL, false); + } + + if (lastChunk == null) { + continue; + } + for (int currY = minBlockY; currY <= maxBlockY; ++currY) { + int edgeCount = ((currX == minBlockX || currX == maxBlockX) ? 1 : 0) + + ((currY == minBlockY || currY == maxBlockY) ? 1 : 0) + + ((currZ == minBlockZ || currZ == maxBlockZ) ? 1 : 0); + if (edgeCount == 3) { + continue; + } + + pos.setY(currY); + + final double distance = pos.distToCenterSqr(entityPos); + if (distance > selectedDistance || (distance == selectedDistance && selected.compareTo(pos) >= 0)) { + continue; + } + + final BlockState state = ((GetBlockChunk)lastChunk).getBlock(currX, currY, currZ); + if (((CollisionBlockState)state).emptyCollisionShape()) { + continue; + } + + if ((edgeCount != 1 || state.hasLargeCollisionShape()) && (edgeCount != 2 || state.getBlock() == Blocks.MOVING_PISTON)) { + if (collisionContext == null) { + collisionContext = new CollisionUtil.LazyEntityCollisionContext(entity); + } + final VoxelShape blockCollision = state.getCollisionShape(lastChunk, pos, collisionContext); + if (blockCollision.isEmpty()) { + continue; + } + + // avoid VoxelShape#move by shifting the entity collision shape instead + final AABB shiftedAABB = aabb.move(-(double)currX, -(double)currY, -(double)currZ); + + final AABB singleAABB = ((CollisionVoxelShape)blockCollision).getSingleAABBRepresentation(); + if (singleAABB != null) { + if (!CollisionUtil.voxelShapeIntersect(singleAABB, shiftedAABB)) { + continue; + } + + selected = pos.immutable(); + selectedDistance = distance; + continue; + } + + if (!CollisionUtil.voxelShapeIntersectNoEmpty(blockCollision, shiftedAABB)) { + continue; + } + + selected = pos.immutable(); + selectedDistance = distance; + continue; + } + } + } + } + + return Optional.ofNullable(selected); + } } diff --git a/src/main/resources/moonrise.mixins.json b/src/main/resources/moonrise.mixins.json index 714b4b5..a42ca94 100644 --- a/src/main/resources/moonrise.mixins.json +++ b/src/main/resources/moonrise.mixins.json @@ -13,7 +13,6 @@ "collisions.BitSetDiscreteVoxelShapeMixin", "collisions.BlockMixin", "collisions.BlockStateBaseMixin", - "collisions.CollisionGetterMixin", "collisions.CubeVoxelShapeMixin", "collisions.DirectionMixin", "collisions.DiscreteVoxelShapeMixin",