130 lines
4.5 KiB
Java
130 lines
4.5 KiB
Java
package net.minecraft.world.level.levelgen.feature;
|
|
|
|
import java.util.function.Consumer;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.tags.BlockTags;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.world.level.LevelAccessor;
|
|
import net.minecraft.world.level.WorldGenLevel;
|
|
import net.minecraft.world.level.block.Blocks;
|
|
import net.minecraft.world.level.block.PointedDripstoneBlock;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.level.block.state.properties.DripstoneThickness;
|
|
|
|
public class DripstoneUtils {
|
|
/**
|
|
* The formula used to control dripstone columns radius.
|
|
* @see <a href="https://twitter.com/henrikkniberg/status/1334180031900360707">This tweet by Henrik.</a>
|
|
*/
|
|
protected static double getDripstoneHeight(double radius, double maxRadius, double scale, double minRadius) {
|
|
if (radius < minRadius) {
|
|
radius = minRadius;
|
|
}
|
|
|
|
double d = 0.384;
|
|
double e = radius / maxRadius * 0.384;
|
|
double f = 0.75 * Math.pow(e, 1.3333333333333333);
|
|
double g = Math.pow(e, 0.6666666666666666);
|
|
double h = 0.3333333333333333 * Math.log(e);
|
|
double i = scale * (f - g - h);
|
|
i = Math.max(i, 0.0);
|
|
return i / 0.384 * maxRadius;
|
|
}
|
|
|
|
protected static boolean isCircleMostlyEmbeddedInStone(WorldGenLevel level, BlockPos pos, int radius) {
|
|
if (isEmptyOrWaterOrLava(level, pos)) {
|
|
return false;
|
|
} else {
|
|
float f = 6.0F;
|
|
float g = 6.0F / radius;
|
|
|
|
for (float h = 0.0F; h < (float) (Math.PI * 2); h += g) {
|
|
int i = (int)(Mth.cos(h) * radius);
|
|
int j = (int)(Mth.sin(h) * radius);
|
|
if (isEmptyOrWaterOrLava(level, pos.offset(i, 0, j))) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
protected static boolean isEmptyOrWater(LevelAccessor level, BlockPos pos) {
|
|
return level.isStateAtPosition(pos, DripstoneUtils::isEmptyOrWater);
|
|
}
|
|
|
|
protected static boolean isEmptyOrWaterOrLava(LevelAccessor level, BlockPos pos) {
|
|
return level.isStateAtPosition(pos, DripstoneUtils::isEmptyOrWaterOrLava);
|
|
}
|
|
|
|
protected static void buildBaseToTipColumn(Direction direction, int height, boolean mergeTip, Consumer<BlockState> blockSetter) {
|
|
if (height >= 3) {
|
|
blockSetter.accept(createPointedDripstone(direction, DripstoneThickness.BASE));
|
|
|
|
for (int i = 0; i < height - 3; i++) {
|
|
blockSetter.accept(createPointedDripstone(direction, DripstoneThickness.MIDDLE));
|
|
}
|
|
}
|
|
|
|
if (height >= 2) {
|
|
blockSetter.accept(createPointedDripstone(direction, DripstoneThickness.FRUSTUM));
|
|
}
|
|
|
|
if (height >= 1) {
|
|
blockSetter.accept(createPointedDripstone(direction, mergeTip ? DripstoneThickness.TIP_MERGE : DripstoneThickness.TIP));
|
|
}
|
|
}
|
|
|
|
protected static void growPointedDripstone(LevelAccessor level, BlockPos pos, Direction direction, int height, boolean mergeTip) {
|
|
if (isDripstoneBase(level.getBlockState(pos.relative(direction.getOpposite())))) {
|
|
BlockPos.MutableBlockPos mutableBlockPos = pos.mutable();
|
|
buildBaseToTipColumn(direction, height, mergeTip, blockState -> {
|
|
if (blockState.is(Blocks.POINTED_DRIPSTONE)) {
|
|
blockState = blockState.setValue(PointedDripstoneBlock.WATERLOGGED, level.isWaterAt(mutableBlockPos));
|
|
}
|
|
|
|
level.setBlock(mutableBlockPos, blockState, 2);
|
|
mutableBlockPos.move(direction);
|
|
});
|
|
}
|
|
}
|
|
|
|
protected static boolean placeDripstoneBlockIfPossible(LevelAccessor level, BlockPos pos) {
|
|
BlockState blockState = level.getBlockState(pos);
|
|
if (blockState.is(BlockTags.DRIPSTONE_REPLACEABLE)) {
|
|
level.setBlock(pos, Blocks.DRIPSTONE_BLOCK.defaultBlockState(), 2);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private static BlockState createPointedDripstone(Direction direction, DripstoneThickness dripstoneThickness) {
|
|
return Blocks.POINTED_DRIPSTONE
|
|
.defaultBlockState()
|
|
.setValue(PointedDripstoneBlock.TIP_DIRECTION, direction)
|
|
.setValue(PointedDripstoneBlock.THICKNESS, dripstoneThickness);
|
|
}
|
|
|
|
public static boolean isDripstoneBaseOrLava(BlockState state) {
|
|
return isDripstoneBase(state) || state.is(Blocks.LAVA);
|
|
}
|
|
|
|
public static boolean isDripstoneBase(BlockState state) {
|
|
return state.is(Blocks.DRIPSTONE_BLOCK) || state.is(BlockTags.DRIPSTONE_REPLACEABLE);
|
|
}
|
|
|
|
public static boolean isEmptyOrWater(BlockState state) {
|
|
return state.isAir() || state.is(Blocks.WATER);
|
|
}
|
|
|
|
public static boolean isNeitherEmptyNorWater(BlockState state) {
|
|
return !state.isAir() && !state.is(Blocks.WATER);
|
|
}
|
|
|
|
public static boolean isEmptyOrWaterOrLava(BlockState state) {
|
|
return state.isAir() || state.is(Blocks.WATER) || state.is(Blocks.LAVA);
|
|
}
|
|
}
|