144 lines
4.6 KiB
Java
144 lines
4.6 KiB
Java
package net.minecraft.world.level.levelgen.feature;
|
|
|
|
import com.google.common.collect.ImmutableList;
|
|
import com.mojang.serialization.Codec;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.util.RandomSource;
|
|
import net.minecraft.world.level.LevelAccessor;
|
|
import net.minecraft.world.level.WorldGenLevel;
|
|
import net.minecraft.world.level.block.Block;
|
|
import net.minecraft.world.level.block.Blocks;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.level.levelgen.feature.configurations.ColumnFeatureConfiguration;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
public class BasaltColumnsFeature extends Feature<ColumnFeatureConfiguration> {
|
|
private static final ImmutableList<Block> CANNOT_PLACE_ON = ImmutableList.of(
|
|
Blocks.LAVA,
|
|
Blocks.BEDROCK,
|
|
Blocks.MAGMA_BLOCK,
|
|
Blocks.SOUL_SAND,
|
|
Blocks.NETHER_BRICKS,
|
|
Blocks.NETHER_BRICK_FENCE,
|
|
Blocks.NETHER_BRICK_STAIRS,
|
|
Blocks.NETHER_WART,
|
|
Blocks.CHEST,
|
|
Blocks.SPAWNER
|
|
);
|
|
private static final int CLUSTERED_REACH = 5;
|
|
private static final int CLUSTERED_SIZE = 50;
|
|
private static final int UNCLUSTERED_REACH = 8;
|
|
private static final int UNCLUSTERED_SIZE = 15;
|
|
|
|
public BasaltColumnsFeature(Codec<ColumnFeatureConfiguration> codec) {
|
|
super(codec);
|
|
}
|
|
|
|
@Override
|
|
public boolean place(FeaturePlaceContext<ColumnFeatureConfiguration> context) {
|
|
int i = context.chunkGenerator().getSeaLevel();
|
|
BlockPos blockPos = context.origin();
|
|
WorldGenLevel worldGenLevel = context.level();
|
|
RandomSource randomSource = context.random();
|
|
ColumnFeatureConfiguration columnFeatureConfiguration = context.config();
|
|
if (!canPlaceAt(worldGenLevel, i, blockPos.mutable())) {
|
|
return false;
|
|
} else {
|
|
int j = columnFeatureConfiguration.height().sample(randomSource);
|
|
boolean bl = randomSource.nextFloat() < 0.9F;
|
|
int k = Math.min(j, bl ? 5 : 8);
|
|
int l = bl ? 50 : 15;
|
|
boolean bl2 = false;
|
|
|
|
for (BlockPos blockPos2 : BlockPos.randomBetweenClosed(
|
|
randomSource, l, blockPos.getX() - k, blockPos.getY(), blockPos.getZ() - k, blockPos.getX() + k, blockPos.getY(), blockPos.getZ() + k
|
|
)) {
|
|
int m = j - blockPos2.distManhattan(blockPos);
|
|
if (m >= 0) {
|
|
bl2 |= this.placeColumn(worldGenLevel, i, blockPos2, m, columnFeatureConfiguration.reach().sample(randomSource));
|
|
}
|
|
}
|
|
|
|
return bl2;
|
|
}
|
|
}
|
|
|
|
private boolean placeColumn(LevelAccessor level, int seaLevel, BlockPos pos, int distance, int reach) {
|
|
boolean bl = false;
|
|
|
|
for (BlockPos blockPos : BlockPos.betweenClosed(pos.getX() - reach, pos.getY(), pos.getZ() - reach, pos.getX() + reach, pos.getY(), pos.getZ() + reach)) {
|
|
int i = blockPos.distManhattan(pos);
|
|
BlockPos blockPos2 = isAirOrLavaOcean(level, seaLevel, blockPos)
|
|
? findSurface(level, seaLevel, blockPos.mutable(), i)
|
|
: findAir(level, blockPos.mutable(), i);
|
|
if (blockPos2 != null) {
|
|
int j = distance - i / 2;
|
|
|
|
for (BlockPos.MutableBlockPos mutableBlockPos = blockPos2.mutable(); j >= 0; j--) {
|
|
if (isAirOrLavaOcean(level, seaLevel, mutableBlockPos)) {
|
|
this.setBlock(level, mutableBlockPos, Blocks.BASALT.defaultBlockState());
|
|
mutableBlockPos.move(Direction.UP);
|
|
bl = true;
|
|
} else {
|
|
if (!level.getBlockState(mutableBlockPos).is(Blocks.BASALT)) {
|
|
break;
|
|
}
|
|
|
|
mutableBlockPos.move(Direction.UP);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return bl;
|
|
}
|
|
|
|
@Nullable
|
|
private static BlockPos findSurface(LevelAccessor level, int seaLevel, BlockPos.MutableBlockPos pos, int distance) {
|
|
while (pos.getY() > level.getMinY() + 1 && distance > 0) {
|
|
distance--;
|
|
if (canPlaceAt(level, seaLevel, pos)) {
|
|
return pos;
|
|
}
|
|
|
|
pos.move(Direction.DOWN);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private static boolean canPlaceAt(LevelAccessor level, int seaLevel, BlockPos.MutableBlockPos pos) {
|
|
if (!isAirOrLavaOcean(level, seaLevel, pos)) {
|
|
return false;
|
|
} else {
|
|
BlockState blockState = level.getBlockState(pos.move(Direction.DOWN));
|
|
pos.move(Direction.UP);
|
|
return !blockState.isAir() && !CANNOT_PLACE_ON.contains(blockState.getBlock());
|
|
}
|
|
}
|
|
|
|
@Nullable
|
|
private static BlockPos findAir(LevelAccessor level, BlockPos.MutableBlockPos pos, int distance) {
|
|
while (pos.getY() <= level.getMaxY() && distance > 0) {
|
|
distance--;
|
|
BlockState blockState = level.getBlockState(pos);
|
|
if (CANNOT_PLACE_ON.contains(blockState.getBlock())) {
|
|
return null;
|
|
}
|
|
|
|
if (blockState.isAir()) {
|
|
return pos;
|
|
}
|
|
|
|
pos.move(Direction.UP);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private static boolean isAirOrLavaOcean(LevelAccessor level, int seaLevel, BlockPos pos) {
|
|
BlockState blockState = level.getBlockState(pos);
|
|
return blockState.isAir() || blockState.is(Blocks.LAVA) && pos.getY() <= seaLevel;
|
|
}
|
|
}
|