108 lines
4.1 KiB
Java
108 lines
4.1 KiB
Java
package net.minecraft.world.entity.vehicle;
|
|
|
|
import java.util.function.Function;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.tags.BlockTags;
|
|
import net.minecraft.world.entity.EntityType;
|
|
import net.minecraft.world.entity.LivingEntity;
|
|
import net.minecraft.world.entity.Pose;
|
|
import net.minecraft.world.level.BlockGetter;
|
|
import net.minecraft.world.level.CollisionGetter;
|
|
import net.minecraft.world.level.block.TrapDoorBlock;
|
|
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.Shapes;
|
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
public class DismountHelper {
|
|
public static int[][] offsetsForDirection(Direction direction) {
|
|
Direction direction2 = direction.getClockWise();
|
|
Direction direction3 = direction2.getOpposite();
|
|
Direction direction4 = direction.getOpposite();
|
|
return new int[][]{
|
|
{direction2.getStepX(), direction2.getStepZ()},
|
|
{direction3.getStepX(), direction3.getStepZ()},
|
|
{direction4.getStepX() + direction2.getStepX(), direction4.getStepZ() + direction2.getStepZ()},
|
|
{direction4.getStepX() + direction3.getStepX(), direction4.getStepZ() + direction3.getStepZ()},
|
|
{direction.getStepX() + direction2.getStepX(), direction.getStepZ() + direction2.getStepZ()},
|
|
{direction.getStepX() + direction3.getStepX(), direction.getStepZ() + direction3.getStepZ()},
|
|
{direction4.getStepX(), direction4.getStepZ()},
|
|
{direction.getStepX(), direction.getStepZ()}
|
|
};
|
|
}
|
|
|
|
public static boolean isBlockFloorValid(double distance) {
|
|
return !Double.isInfinite(distance) && distance < 1.0;
|
|
}
|
|
|
|
public static boolean canDismountTo(CollisionGetter level, LivingEntity passenger, AABB boundingBox) {
|
|
for (VoxelShape voxelShape : level.getBlockCollisions(passenger, boundingBox)) {
|
|
if (!voxelShape.isEmpty()) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return level.getWorldBorder().isWithinBounds(boundingBox);
|
|
}
|
|
|
|
public static boolean canDismountTo(CollisionGetter level, Vec3 offset, LivingEntity passenger, Pose pose) {
|
|
return canDismountTo(level, passenger, passenger.getLocalBoundsForPose(pose).move(offset));
|
|
}
|
|
|
|
public static VoxelShape nonClimbableShape(BlockGetter level, BlockPos pos) {
|
|
BlockState blockState = level.getBlockState(pos);
|
|
return !blockState.is(BlockTags.CLIMBABLE) && (!(blockState.getBlock() instanceof TrapDoorBlock) || !blockState.getValue(TrapDoorBlock.OPEN))
|
|
? blockState.getCollisionShape(level, pos)
|
|
: Shapes.empty();
|
|
}
|
|
|
|
public static double findCeilingFrom(BlockPos pos, int ceiling, Function<BlockPos, VoxelShape> shapeForPos) {
|
|
BlockPos.MutableBlockPos mutableBlockPos = pos.mutable();
|
|
int i = 0;
|
|
|
|
while (i < ceiling) {
|
|
VoxelShape voxelShape = (VoxelShape)shapeForPos.apply(mutableBlockPos);
|
|
if (!voxelShape.isEmpty()) {
|
|
return pos.getY() + i + voxelShape.min(Direction.Axis.Y);
|
|
}
|
|
|
|
i++;
|
|
mutableBlockPos.move(Direction.UP);
|
|
}
|
|
|
|
return Double.POSITIVE_INFINITY;
|
|
}
|
|
|
|
@Nullable
|
|
public static Vec3 findSafeDismountLocation(EntityType<?> entityType, CollisionGetter level, BlockPos pos, boolean onlySafePositions) {
|
|
if (onlySafePositions && entityType.isBlockDangerous(level.getBlockState(pos))) {
|
|
return null;
|
|
} else {
|
|
double d = level.getBlockFloorHeight(nonClimbableShape(level, pos), () -> nonClimbableShape(level, pos.below()));
|
|
if (!isBlockFloorValid(d)) {
|
|
return null;
|
|
} else if (onlySafePositions && d <= 0.0 && entityType.isBlockDangerous(level.getBlockState(pos.below()))) {
|
|
return null;
|
|
} else {
|
|
Vec3 vec3 = Vec3.upFromBottomCenterOf(pos, d);
|
|
AABB aABB = entityType.getDimensions().makeBoundingBox(vec3);
|
|
|
|
for (VoxelShape voxelShape : level.getBlockCollisions(null, aABB)) {
|
|
if (!voxelShape.isEmpty()) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
if (entityType != EntityType.PLAYER
|
|
|| !level.getBlockState(pos).is(BlockTags.INVALID_SPAWN_INSIDE) && !level.getBlockState(pos.above()).is(BlockTags.INVALID_SPAWN_INSIDE)) {
|
|
return !level.getWorldBorder().isWithinBounds(aABB) ? null : vec3;
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|