minecraft-src/net/minecraft/world/level/BlockCollisions.java
2025-07-04 03:45:38 +03:00

113 lines
4 KiB
Java

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<T> extends AbstractIterator<T> {
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<BlockPos.MutableBlockPos, VoxelShape, T> resultProvider;
public BlockCollisions(
CollisionGetter collisionGetter,
@Nullable Entity entity,
AABB box,
boolean onlySuffocatingBlocks,
BiFunction<BlockPos.MutableBlockPos, VoxelShape, T> resultProvider
) {
this(collisionGetter, entity == null ? CollisionContext.empty() : CollisionContext.of(entity), box, onlySuffocatingBlocks, resultProvider);
}
public BlockCollisions(
CollisionGetter collisionGetter,
CollisionContext context,
AABB box,
boolean onlySuffocatingBlocks,
BiFunction<BlockPos.MutableBlockPos, VoxelShape, T> 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();
}
}