minecraft-src/net/minecraft/world/level/levelgen/feature/RootSystemFeature.java
2025-07-04 01:41:11 +03:00

126 lines
4.6 KiB
Java

package net.minecraft.world.level.levelgen.feature;
import com.mojang.serialization.Codec;
import java.util.function.Predicate;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.tags.FluidTags;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.levelgen.feature.configurations.RootSystemConfiguration;
public class RootSystemFeature extends Feature<RootSystemConfiguration> {
public RootSystemFeature(Codec<RootSystemConfiguration> codec) {
super(codec);
}
@Override
public boolean place(FeaturePlaceContext<RootSystemConfiguration> context) {
WorldGenLevel worldGenLevel = context.level();
BlockPos blockPos = context.origin();
if (!worldGenLevel.getBlockState(blockPos).isAir()) {
return false;
} else {
RandomSource randomSource = context.random();
BlockPos blockPos2 = context.origin();
RootSystemConfiguration rootSystemConfiguration = context.config();
BlockPos.MutableBlockPos mutableBlockPos = blockPos2.mutable();
if (placeDirtAndTree(worldGenLevel, context.chunkGenerator(), rootSystemConfiguration, randomSource, mutableBlockPos, blockPos2)) {
placeRoots(worldGenLevel, rootSystemConfiguration, randomSource, blockPos2, mutableBlockPos);
}
return true;
}
}
private static boolean spaceForTree(WorldGenLevel level, RootSystemConfiguration config, BlockPos pos) {
BlockPos.MutableBlockPos mutableBlockPos = pos.mutable();
for (int i = 1; i <= config.requiredVerticalSpaceForTree; i++) {
mutableBlockPos.move(Direction.UP);
BlockState blockState = level.getBlockState(mutableBlockPos);
if (!isAllowedTreeSpace(blockState, i, config.allowedVerticalWaterForTree)) {
return false;
}
}
return true;
}
private static boolean isAllowedTreeSpace(BlockState state, int y, int allowedVerticalWater) {
if (state.isAir()) {
return true;
} else {
int i = y + 1;
return i <= allowedVerticalWater && state.getFluidState().is(FluidTags.WATER);
}
}
private static boolean placeDirtAndTree(
WorldGenLevel level,
ChunkGenerator chunkGenerator,
RootSystemConfiguration config,
RandomSource random,
BlockPos.MutableBlockPos mutablePos,
BlockPos basePos
) {
for (int i = 0; i < config.rootColumnMaxHeight; i++) {
mutablePos.move(Direction.UP);
if (config.allowedTreePosition.test(level, mutablePos) && spaceForTree(level, config, mutablePos)) {
BlockPos blockPos = mutablePos.below();
if (level.getFluidState(blockPos).is(FluidTags.LAVA) || !level.getBlockState(blockPos).isSolid()) {
return false;
}
if (config.treeFeature.value().place(level, chunkGenerator, random, mutablePos)) {
placeDirt(basePos, basePos.getY() + i, level, config, random);
return true;
}
}
}
return false;
}
private static void placeDirt(BlockPos pos, int maxY, WorldGenLevel level, RootSystemConfiguration config, RandomSource random) {
int i = pos.getX();
int j = pos.getZ();
BlockPos.MutableBlockPos mutableBlockPos = pos.mutable();
for (int k = pos.getY(); k < maxY; k++) {
placeRootedDirt(level, config, random, i, j, mutableBlockPos.set(i, k, j));
}
}
private static void placeRootedDirt(WorldGenLevel level, RootSystemConfiguration config, RandomSource random, int x, int z, BlockPos.MutableBlockPos pos) {
int i = config.rootRadius;
Predicate<BlockState> predicate = blockState -> blockState.is(config.rootReplaceable);
for (int j = 0; j < config.rootPlacementAttempts; j++) {
pos.setWithOffset(pos, random.nextInt(i) - random.nextInt(i), 0, random.nextInt(i) - random.nextInt(i));
if (predicate.test(level.getBlockState(pos))) {
level.setBlock(pos, config.rootStateProvider.getState(random, pos), 2);
}
pos.setX(x);
pos.setZ(z);
}
}
private static void placeRoots(WorldGenLevel level, RootSystemConfiguration config, RandomSource random, BlockPos basePos, BlockPos.MutableBlockPos mutablePos) {
int i = config.hangingRootRadius;
int j = config.hangingRootsVerticalSpan;
for (int k = 0; k < config.hangingRootPlacementAttempts; k++) {
mutablePos.setWithOffset(basePos, random.nextInt(i) - random.nextInt(i), random.nextInt(j) - random.nextInt(j), random.nextInt(i) - random.nextInt(i));
if (level.isEmptyBlock(mutablePos)) {
BlockState blockState = config.hangingRootStateProvider.getState(random, mutablePos);
if (blockState.canSurvive(level, mutablePos) && level.getBlockState(mutablePos.above()).isFaceSturdy(level, mutablePos, Direction.DOWN)) {
level.setBlock(mutablePos, blockState, 2);
}
}
}
}
}