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

252 lines
17 KiB
Java

package net.minecraft.world.level.levelgen.feature;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.tags.BlockTags;
import net.minecraft.tags.TagKey;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.LevelSimulatedReader;
import net.minecraft.world.level.LevelWriter;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.levelgen.feature.configurations.BlockColumnConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.BlockPileConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.BlockStateConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.ColumnFeatureConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.CountConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.DeltaFeatureConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.DiskConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.DripstoneClusterConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.EndGatewayConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.FallenTreeConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.GeodeConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.HugeMushroomFeatureConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.LargeDripstoneConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.LayerConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.MultifaceGrowthConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.NetherForestVegetationConfig;
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.OreConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.PointedDripstoneConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.ProbabilityFeatureConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.RandomBooleanFeatureConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.RandomFeatureConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.RandomPatchConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.ReplaceBlockConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.ReplaceSphereConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.RootSystemConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.SculkPatchConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.SimpleBlockConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.SimpleRandomFeatureConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.SpikeConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.SpringConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.TreeConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.TwistingVinesConfig;
import net.minecraft.world.level.levelgen.feature.configurations.UnderwaterMagmaConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.VegetationPatchConfiguration;
public abstract class Feature<FC extends FeatureConfiguration> {
public static final Feature<NoneFeatureConfiguration> NO_OP = register("no_op", new NoOpFeature(NoneFeatureConfiguration.CODEC));
public static final Feature<TreeConfiguration> TREE = register("tree", new TreeFeature(TreeConfiguration.CODEC));
public static final Feature<FallenTreeConfiguration> FALLEN_TREE = register("fallen_tree", new FallenTreeFeature(FallenTreeConfiguration.CODEC));
public static final Feature<RandomPatchConfiguration> FLOWER = register("flower", new RandomPatchFeature(RandomPatchConfiguration.CODEC));
public static final Feature<RandomPatchConfiguration> NO_BONEMEAL_FLOWER = register(
"no_bonemeal_flower", new RandomPatchFeature(RandomPatchConfiguration.CODEC)
);
public static final Feature<RandomPatchConfiguration> RANDOM_PATCH = register("random_patch", new RandomPatchFeature(RandomPatchConfiguration.CODEC));
public static final Feature<BlockPileConfiguration> BLOCK_PILE = register("block_pile", new BlockPileFeature(BlockPileConfiguration.CODEC));
public static final Feature<SpringConfiguration> SPRING = register("spring_feature", new SpringFeature(SpringConfiguration.CODEC));
public static final Feature<NoneFeatureConfiguration> CHORUS_PLANT = register("chorus_plant", new ChorusPlantFeature(NoneFeatureConfiguration.CODEC));
public static final Feature<ReplaceBlockConfiguration> REPLACE_SINGLE_BLOCK = register(
"replace_single_block", new ReplaceBlockFeature(ReplaceBlockConfiguration.CODEC)
);
public static final Feature<NoneFeatureConfiguration> VOID_START_PLATFORM = register(
"void_start_platform", new VoidStartPlatformFeature(NoneFeatureConfiguration.CODEC)
);
public static final Feature<NoneFeatureConfiguration> DESERT_WELL = register("desert_well", new DesertWellFeature(NoneFeatureConfiguration.CODEC));
public static final Feature<FossilFeatureConfiguration> FOSSIL = register("fossil", new FossilFeature(FossilFeatureConfiguration.CODEC));
public static final Feature<HugeMushroomFeatureConfiguration> HUGE_RED_MUSHROOM = register(
"huge_red_mushroom", new HugeRedMushroomFeature(HugeMushroomFeatureConfiguration.CODEC)
);
public static final Feature<HugeMushroomFeatureConfiguration> HUGE_BROWN_MUSHROOM = register(
"huge_brown_mushroom", new HugeBrownMushroomFeature(HugeMushroomFeatureConfiguration.CODEC)
);
public static final Feature<NoneFeatureConfiguration> ICE_SPIKE = register("ice_spike", new IceSpikeFeature(NoneFeatureConfiguration.CODEC));
public static final Feature<NoneFeatureConfiguration> GLOWSTONE_BLOB = register("glowstone_blob", new GlowstoneFeature(NoneFeatureConfiguration.CODEC));
public static final Feature<NoneFeatureConfiguration> FREEZE_TOP_LAYER = register("freeze_top_layer", new SnowAndFreezeFeature(NoneFeatureConfiguration.CODEC));
public static final Feature<NoneFeatureConfiguration> VINES = register("vines", new VinesFeature(NoneFeatureConfiguration.CODEC));
public static final Feature<BlockColumnConfiguration> BLOCK_COLUMN = register("block_column", new BlockColumnFeature(BlockColumnConfiguration.CODEC));
public static final Feature<VegetationPatchConfiguration> VEGETATION_PATCH = register(
"vegetation_patch", new VegetationPatchFeature(VegetationPatchConfiguration.CODEC)
);
public static final Feature<VegetationPatchConfiguration> WATERLOGGED_VEGETATION_PATCH = register(
"waterlogged_vegetation_patch", new WaterloggedVegetationPatchFeature(VegetationPatchConfiguration.CODEC)
);
public static final Feature<RootSystemConfiguration> ROOT_SYSTEM = register("root_system", new RootSystemFeature(RootSystemConfiguration.CODEC));
public static final Feature<MultifaceGrowthConfiguration> MULTIFACE_GROWTH = register(
"multiface_growth", new MultifaceGrowthFeature(MultifaceGrowthConfiguration.CODEC)
);
public static final Feature<UnderwaterMagmaConfiguration> UNDERWATER_MAGMA = register(
"underwater_magma", new UnderwaterMagmaFeature(UnderwaterMagmaConfiguration.CODEC)
);
public static final Feature<NoneFeatureConfiguration> MONSTER_ROOM = register("monster_room", new MonsterRoomFeature(NoneFeatureConfiguration.CODEC));
public static final Feature<NoneFeatureConfiguration> BLUE_ICE = register("blue_ice", new BlueIceFeature(NoneFeatureConfiguration.CODEC));
public static final Feature<BlockStateConfiguration> ICEBERG = register("iceberg", new IcebergFeature(BlockStateConfiguration.CODEC));
public static final Feature<BlockStateConfiguration> FOREST_ROCK = register("forest_rock", new BlockBlobFeature(BlockStateConfiguration.CODEC));
public static final Feature<DiskConfiguration> DISK = register("disk", new DiskFeature(DiskConfiguration.CODEC));
public static final Feature<LakeFeature.Configuration> LAKE = register("lake", new LakeFeature(LakeFeature.Configuration.CODEC));
public static final Feature<OreConfiguration> ORE = register("ore", new OreFeature(OreConfiguration.CODEC));
public static final Feature<NoneFeatureConfiguration> END_PLATFORM = register("end_platform", new EndPlatformFeature(NoneFeatureConfiguration.CODEC));
public static final Feature<SpikeConfiguration> END_SPIKE = register("end_spike", new SpikeFeature(SpikeConfiguration.CODEC));
public static final Feature<NoneFeatureConfiguration> END_ISLAND = register("end_island", new EndIslandFeature(NoneFeatureConfiguration.CODEC));
public static final Feature<EndGatewayConfiguration> END_GATEWAY = register("end_gateway", new EndGatewayFeature(EndGatewayConfiguration.CODEC));
public static final SeagrassFeature SEAGRASS = register("seagrass", new SeagrassFeature(ProbabilityFeatureConfiguration.CODEC));
public static final Feature<NoneFeatureConfiguration> KELP = register("kelp", new KelpFeature(NoneFeatureConfiguration.CODEC));
public static final Feature<NoneFeatureConfiguration> CORAL_TREE = register("coral_tree", new CoralTreeFeature(NoneFeatureConfiguration.CODEC));
public static final Feature<NoneFeatureConfiguration> CORAL_MUSHROOM = register("coral_mushroom", new CoralMushroomFeature(NoneFeatureConfiguration.CODEC));
public static final Feature<NoneFeatureConfiguration> CORAL_CLAW = register("coral_claw", new CoralClawFeature(NoneFeatureConfiguration.CODEC));
public static final Feature<CountConfiguration> SEA_PICKLE = register("sea_pickle", new SeaPickleFeature(CountConfiguration.CODEC));
public static final Feature<SimpleBlockConfiguration> SIMPLE_BLOCK = register("simple_block", new SimpleBlockFeature(SimpleBlockConfiguration.CODEC));
public static final Feature<ProbabilityFeatureConfiguration> BAMBOO = register("bamboo", new BambooFeature(ProbabilityFeatureConfiguration.CODEC));
public static final Feature<HugeFungusConfiguration> HUGE_FUNGUS = register("huge_fungus", new HugeFungusFeature(HugeFungusConfiguration.CODEC));
public static final Feature<NetherForestVegetationConfig> NETHER_FOREST_VEGETATION = register(
"nether_forest_vegetation", new NetherForestVegetationFeature(NetherForestVegetationConfig.CODEC)
);
public static final Feature<NoneFeatureConfiguration> WEEPING_VINES = register("weeping_vines", new WeepingVinesFeature(NoneFeatureConfiguration.CODEC));
public static final Feature<TwistingVinesConfig> TWISTING_VINES = register("twisting_vines", new TwistingVinesFeature(TwistingVinesConfig.CODEC));
public static final Feature<ColumnFeatureConfiguration> BASALT_COLUMNS = register("basalt_columns", new BasaltColumnsFeature(ColumnFeatureConfiguration.CODEC));
public static final Feature<DeltaFeatureConfiguration> DELTA_FEATURE = register("delta_feature", new DeltaFeature(DeltaFeatureConfiguration.CODEC));
public static final Feature<ReplaceSphereConfiguration> REPLACE_BLOBS = register(
"netherrack_replace_blobs", new ReplaceBlobsFeature(ReplaceSphereConfiguration.CODEC)
);
public static final Feature<LayerConfiguration> FILL_LAYER = register("fill_layer", new FillLayerFeature(LayerConfiguration.CODEC));
public static final BonusChestFeature BONUS_CHEST = register("bonus_chest", new BonusChestFeature(NoneFeatureConfiguration.CODEC));
public static final Feature<NoneFeatureConfiguration> BASALT_PILLAR = register("basalt_pillar", new BasaltPillarFeature(NoneFeatureConfiguration.CODEC));
public static final Feature<OreConfiguration> SCATTERED_ORE = register("scattered_ore", new ScatteredOreFeature(OreConfiguration.CODEC));
public static final Feature<RandomFeatureConfiguration> RANDOM_SELECTOR = register(
"random_selector", new RandomSelectorFeature(RandomFeatureConfiguration.CODEC)
);
public static final Feature<SimpleRandomFeatureConfiguration> SIMPLE_RANDOM_SELECTOR = register(
"simple_random_selector", new SimpleRandomSelectorFeature(SimpleRandomFeatureConfiguration.CODEC)
);
public static final Feature<RandomBooleanFeatureConfiguration> RANDOM_BOOLEAN_SELECTOR = register(
"random_boolean_selector", new RandomBooleanSelectorFeature(RandomBooleanFeatureConfiguration.CODEC)
);
public static final Feature<GeodeConfiguration> GEODE = register("geode", new GeodeFeature(GeodeConfiguration.CODEC));
public static final Feature<DripstoneClusterConfiguration> DRIPSTONE_CLUSTER = register(
"dripstone_cluster", new DripstoneClusterFeature(DripstoneClusterConfiguration.CODEC)
);
public static final Feature<LargeDripstoneConfiguration> LARGE_DRIPSTONE = register(
"large_dripstone", new LargeDripstoneFeature(LargeDripstoneConfiguration.CODEC)
);
public static final Feature<PointedDripstoneConfiguration> POINTED_DRIPSTONE = register(
"pointed_dripstone", new PointedDripstoneFeature(PointedDripstoneConfiguration.CODEC)
);
public static final Feature<SculkPatchConfiguration> SCULK_PATCH = register("sculk_patch", new SculkPatchFeature(SculkPatchConfiguration.CODEC));
private final MapCodec<ConfiguredFeature<FC, Feature<FC>>> configuredCodec;
private static <C extends FeatureConfiguration, F extends Feature<C>> F register(String key, F value) {
return Registry.register(BuiltInRegistries.FEATURE, key, value);
}
public Feature(Codec<FC> codec) {
this.configuredCodec = codec.fieldOf("config").xmap(featureConfiguration -> new ConfiguredFeature<>(this, featureConfiguration), ConfiguredFeature::config);
}
public MapCodec<ConfiguredFeature<FC, Feature<FC>>> configuredCodec() {
return this.configuredCodec;
}
protected void setBlock(LevelWriter level, BlockPos pos, BlockState state) {
level.setBlock(pos, state, 3);
}
public static Predicate<BlockState> isReplaceable(TagKey<Block> blockTag) {
return blockState -> !blockState.is(blockTag);
}
protected void safeSetBlock(WorldGenLevel level, BlockPos pos, BlockState state, Predicate<BlockState> oldState) {
if (oldState.test(level.getBlockState(pos))) {
level.setBlock(pos, state, 2);
}
}
/**
* Places the given feature at the given location.
* During world generation, features are provided with a 3x3 region of chunks, centered on the chunk being generated, that they can safely generate into.
*
* @param context A context object with a reference to the level and the position the feature is being placed at
*/
public abstract boolean place(FeaturePlaceContext<FC> context);
public boolean place(FC config, WorldGenLevel level, ChunkGenerator chunkGenerator, RandomSource random, BlockPos origin) {
return level.ensureCanWrite(origin) ? this.place(new FeaturePlaceContext<>(Optional.empty(), level, chunkGenerator, random, origin, config)) : false;
}
protected static boolean isStone(BlockState state) {
return state.is(BlockTags.BASE_STONE_OVERWORLD);
}
public static boolean isDirt(BlockState state) {
return state.is(BlockTags.DIRT);
}
public static boolean isGrassOrDirt(LevelSimulatedReader level, BlockPos pos) {
return level.isStateAtPosition(pos, Feature::isDirt);
}
/**
* @return {@code true} if any of the six adjacent blocks to the block at {@code pos} return {@code true} to the given filter.
*
* @param adjacentStateAccessor An accessor for the adjacent blocks. Essentially {@code level::getBlockState}.
*/
public static boolean checkNeighbors(Function<BlockPos, BlockState> adjacentStateAccessor, BlockPos pos, Predicate<BlockState> filter) {
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
for (Direction direction : Direction.values()) {
mutableBlockPos.setWithOffset(pos, direction);
if (filter.test((BlockState)adjacentStateAccessor.apply(mutableBlockPos))) {
return true;
}
}
return false;
}
/**
* @return {@code true} if any of the six adjacent blocks to the block at {@code pos} are air.
*
* @param adjacentStateAccessor An accessor for the adjacent blocks. Essentially {@code level::getBlockState}.
*/
public static boolean isAdjacentToAir(Function<BlockPos, BlockState> adjacentStateAccessor, BlockPos pos) {
return checkNeighbors(adjacentStateAccessor, pos, BlockBehaviour.BlockStateBase::isAir);
}
/**
* If the above two blocks are not air, marks them for post-processing.
* This is used to prevent floating grass during the generation of features that carve blocks out of the terrain, after other plant-like blocks have generated (such as lake features).
*/
protected void markAboveForPostProcessing(WorldGenLevel level, BlockPos basePos) {
BlockPos.MutableBlockPos mutableBlockPos = basePos.mutable();
for (int i = 0; i < 2; i++) {
mutableBlockPos.move(Direction.UP);
if (level.getBlockState(mutableBlockPos).isAir()) {
return;
}
level.getChunk(mutableBlockPos).markPosForPostprocessing(mutableBlockPos);
}
}
}