package net.minecraft.world.level; import com.google.common.collect.AbstractIterator; import java.util.function.BiFunction; import net.minecraft.core.BlockPos; import net.minecraft.core.Cursor3D; import net.minecraft.core.SectionPos; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; 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.shapes.BooleanOp; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; import org.jetbrains.annotations.Nullable; public class BlockCollisions extends AbstractIterator { private final AABB box; private final CollisionContext context; private final Cursor3D cursor; private final BlockPos.MutableBlockPos pos; private final VoxelShape entityShape; private final CollisionGetter collisionGetter; private final boolean onlySuffocatingBlocks; @Nullable private BlockGetter cachedBlockGetter; private long cachedBlockGetterPos; private final BiFunction resultProvider; public BlockCollisions( CollisionGetter collisionGetter, @Nullable Entity entity, AABB box, boolean onlySuffocatingBlocks, BiFunction resultProvider ) { this(collisionGetter, entity == null ? CollisionContext.empty() : CollisionContext.of(entity), box, onlySuffocatingBlocks, resultProvider); } public BlockCollisions( CollisionGetter collisionGetter, CollisionContext context, AABB box, boolean onlySuffocatingBlocks, BiFunction resultProvider ) { this.context = context; this.pos = new BlockPos.MutableBlockPos(); this.entityShape = Shapes.create(box); this.collisionGetter = collisionGetter; this.box = box; this.onlySuffocatingBlocks = onlySuffocatingBlocks; this.resultProvider = resultProvider; int i = Mth.floor(box.minX - 1.0E-7) - 1; int j = Mth.floor(box.maxX + 1.0E-7) + 1; int k = Mth.floor(box.minY - 1.0E-7) - 1; int l = Mth.floor(box.maxY + 1.0E-7) + 1; int m = Mth.floor(box.minZ - 1.0E-7) - 1; int n = Mth.floor(box.maxZ + 1.0E-7) + 1; this.cursor = new Cursor3D(i, k, m, j, l, n); } @Nullable private BlockGetter getChunk(int x, int z) { int i = SectionPos.blockToSectionCoord(x); int j = SectionPos.blockToSectionCoord(z); long l = ChunkPos.asLong(i, j); if (this.cachedBlockGetter != null && this.cachedBlockGetterPos == l) { return this.cachedBlockGetter; } else { BlockGetter blockGetter = this.collisionGetter.getChunkForCollisions(i, j); this.cachedBlockGetter = blockGetter; this.cachedBlockGetterPos = l; return blockGetter; } } @Override protected T computeNext() { while (this.cursor.advance()) { int i = this.cursor.nextX(); int j = this.cursor.nextY(); int k = this.cursor.nextZ(); int l = this.cursor.getNextType(); if (l != 3) { BlockGetter blockGetter = this.getChunk(i, k); if (blockGetter != null) { this.pos.set(i, j, k); BlockState blockState = blockGetter.getBlockState(this.pos); if ((!this.onlySuffocatingBlocks || blockState.isSuffocating(blockGetter, this.pos)) && (l != 1 || blockState.hasLargeCollisionShape()) && (l != 2 || blockState.is(Blocks.MOVING_PISTON))) { VoxelShape voxelShape = this.context.getCollisionShape(blockState, this.collisionGetter, this.pos); if (voxelShape == Shapes.block()) { if (this.box.intersects(i, j, k, i + 1.0, j + 1.0, k + 1.0)) { return (T)this.resultProvider.apply(this.pos, voxelShape.move(this.pos)); } } else { VoxelShape voxelShape2 = voxelShape.move(this.pos); if (!voxelShape2.isEmpty() && Shapes.joinIsNotEmpty(voxelShape2, this.entityShape, BooleanOp.AND)) { return (T)this.resultProvider.apply(this.pos, voxelShape2); } } } } } } return this.endOfData(); } }