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.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 { public static final Feature NO_OP = register("no_op", new NoOpFeature(NoneFeatureConfiguration.CODEC)); public static final Feature TREE = register("tree", new TreeFeature(TreeConfiguration.CODEC)); public static final Feature FLOWER = register("flower", new RandomPatchFeature(RandomPatchConfiguration.CODEC)); public static final Feature NO_BONEMEAL_FLOWER = register( "no_bonemeal_flower", new RandomPatchFeature(RandomPatchConfiguration.CODEC) ); public static final Feature RANDOM_PATCH = register("random_patch", new RandomPatchFeature(RandomPatchConfiguration.CODEC)); public static final Feature BLOCK_PILE = register("block_pile", new BlockPileFeature(BlockPileConfiguration.CODEC)); public static final Feature SPRING = register("spring_feature", new SpringFeature(SpringConfiguration.CODEC)); public static final Feature CHORUS_PLANT = register("chorus_plant", new ChorusPlantFeature(NoneFeatureConfiguration.CODEC)); public static final Feature REPLACE_SINGLE_BLOCK = register( "replace_single_block", new ReplaceBlockFeature(ReplaceBlockConfiguration.CODEC) ); public static final Feature VOID_START_PLATFORM = register( "void_start_platform", new VoidStartPlatformFeature(NoneFeatureConfiguration.CODEC) ); public static final Feature DESERT_WELL = register("desert_well", new DesertWellFeature(NoneFeatureConfiguration.CODEC)); public static final Feature FOSSIL = register("fossil", new FossilFeature(FossilFeatureConfiguration.CODEC)); public static final Feature HUGE_RED_MUSHROOM = register( "huge_red_mushroom", new HugeRedMushroomFeature(HugeMushroomFeatureConfiguration.CODEC) ); public static final Feature HUGE_BROWN_MUSHROOM = register( "huge_brown_mushroom", new HugeBrownMushroomFeature(HugeMushroomFeatureConfiguration.CODEC) ); public static final Feature ICE_SPIKE = register("ice_spike", new IceSpikeFeature(NoneFeatureConfiguration.CODEC)); public static final Feature GLOWSTONE_BLOB = register("glowstone_blob", new GlowstoneFeature(NoneFeatureConfiguration.CODEC)); public static final Feature FREEZE_TOP_LAYER = register("freeze_top_layer", new SnowAndFreezeFeature(NoneFeatureConfiguration.CODEC)); public static final Feature VINES = register("vines", new VinesFeature(NoneFeatureConfiguration.CODEC)); public static final Feature BLOCK_COLUMN = register("block_column", new BlockColumnFeature(BlockColumnConfiguration.CODEC)); public static final Feature VEGETATION_PATCH = register( "vegetation_patch", new VegetationPatchFeature(VegetationPatchConfiguration.CODEC) ); public static final Feature WATERLOGGED_VEGETATION_PATCH = register( "waterlogged_vegetation_patch", new WaterloggedVegetationPatchFeature(VegetationPatchConfiguration.CODEC) ); public static final Feature ROOT_SYSTEM = register("root_system", new RootSystemFeature(RootSystemConfiguration.CODEC)); public static final Feature MULTIFACE_GROWTH = register( "multiface_growth", new MultifaceGrowthFeature(MultifaceGrowthConfiguration.CODEC) ); public static final Feature UNDERWATER_MAGMA = register( "underwater_magma", new UnderwaterMagmaFeature(UnderwaterMagmaConfiguration.CODEC) ); public static final Feature MONSTER_ROOM = register("monster_room", new MonsterRoomFeature(NoneFeatureConfiguration.CODEC)); public static final Feature BLUE_ICE = register("blue_ice", new BlueIceFeature(NoneFeatureConfiguration.CODEC)); public static final Feature ICEBERG = register("iceberg", new IcebergFeature(BlockStateConfiguration.CODEC)); public static final Feature FOREST_ROCK = register("forest_rock", new BlockBlobFeature(BlockStateConfiguration.CODEC)); public static final Feature DISK = register("disk", new DiskFeature(DiskConfiguration.CODEC)); public static final Feature LAKE = register("lake", new LakeFeature(LakeFeature.Configuration.CODEC)); public static final Feature ORE = register("ore", new OreFeature(OreConfiguration.CODEC)); public static final Feature END_PLATFORM = register("end_platform", new EndPlatformFeature(NoneFeatureConfiguration.CODEC)); public static final Feature END_SPIKE = register("end_spike", new SpikeFeature(SpikeConfiguration.CODEC)); public static final Feature END_ISLAND = register("end_island", new EndIslandFeature(NoneFeatureConfiguration.CODEC)); public static final Feature END_GATEWAY = register("end_gateway", new EndGatewayFeature(EndGatewayConfiguration.CODEC)); public static final SeagrassFeature SEAGRASS = register("seagrass", new SeagrassFeature(ProbabilityFeatureConfiguration.CODEC)); public static final Feature KELP = register("kelp", new KelpFeature(NoneFeatureConfiguration.CODEC)); public static final Feature CORAL_TREE = register("coral_tree", new CoralTreeFeature(NoneFeatureConfiguration.CODEC)); public static final Feature CORAL_MUSHROOM = register("coral_mushroom", new CoralMushroomFeature(NoneFeatureConfiguration.CODEC)); public static final Feature CORAL_CLAW = register("coral_claw", new CoralClawFeature(NoneFeatureConfiguration.CODEC)); public static final Feature SEA_PICKLE = register("sea_pickle", new SeaPickleFeature(CountConfiguration.CODEC)); public static final Feature SIMPLE_BLOCK = register("simple_block", new SimpleBlockFeature(SimpleBlockConfiguration.CODEC)); public static final Feature BAMBOO = register("bamboo", new BambooFeature(ProbabilityFeatureConfiguration.CODEC)); public static final Feature HUGE_FUNGUS = register("huge_fungus", new HugeFungusFeature(HugeFungusConfiguration.CODEC)); public static final Feature NETHER_FOREST_VEGETATION = register( "nether_forest_vegetation", new NetherForestVegetationFeature(NetherForestVegetationConfig.CODEC) ); public static final Feature WEEPING_VINES = register("weeping_vines", new WeepingVinesFeature(NoneFeatureConfiguration.CODEC)); public static final Feature TWISTING_VINES = register("twisting_vines", new TwistingVinesFeature(TwistingVinesConfig.CODEC)); public static final Feature BASALT_COLUMNS = register("basalt_columns", new BasaltColumnsFeature(ColumnFeatureConfiguration.CODEC)); public static final Feature DELTA_FEATURE = register("delta_feature", new DeltaFeature(DeltaFeatureConfiguration.CODEC)); public static final Feature REPLACE_BLOBS = register( "netherrack_replace_blobs", new ReplaceBlobsFeature(ReplaceSphereConfiguration.CODEC) ); public static final Feature 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 BASALT_PILLAR = register("basalt_pillar", new BasaltPillarFeature(NoneFeatureConfiguration.CODEC)); public static final Feature SCATTERED_ORE = register("scattered_ore", new ScatteredOreFeature(OreConfiguration.CODEC)); public static final Feature RANDOM_SELECTOR = register( "random_selector", new RandomSelectorFeature(RandomFeatureConfiguration.CODEC) ); public static final Feature SIMPLE_RANDOM_SELECTOR = register( "simple_random_selector", new SimpleRandomSelectorFeature(SimpleRandomFeatureConfiguration.CODEC) ); public static final Feature RANDOM_BOOLEAN_SELECTOR = register( "random_boolean_selector", new RandomBooleanSelectorFeature(RandomBooleanFeatureConfiguration.CODEC) ); public static final Feature GEODE = register("geode", new GeodeFeature(GeodeConfiguration.CODEC)); public static final Feature DRIPSTONE_CLUSTER = register( "dripstone_cluster", new DripstoneClusterFeature(DripstoneClusterConfiguration.CODEC) ); public static final Feature LARGE_DRIPSTONE = register( "large_dripstone", new LargeDripstoneFeature(LargeDripstoneConfiguration.CODEC) ); public static final Feature POINTED_DRIPSTONE = register( "pointed_dripstone", new PointedDripstoneFeature(PointedDripstoneConfiguration.CODEC) ); public static final Feature SCULK_PATCH = register("sculk_patch", new SculkPatchFeature(SculkPatchConfiguration.CODEC)); private final MapCodec>> configuredCodec; private static > F register(String key, F value) { return Registry.register(BuiltInRegistries.FEATURE, key, value); } public Feature(Codec codec) { this.configuredCodec = codec.fieldOf("config").xmap(featureConfiguration -> new ConfiguredFeature<>(this, featureConfiguration), ConfiguredFeature::config); } public MapCodec>> configuredCodec() { return this.configuredCodec; } protected void setBlock(LevelWriter level, BlockPos pos, BlockState state) { level.setBlock(pos, state, 3); } public static Predicate isReplaceable(TagKey blockTag) { return blockState -> !blockState.is(blockTag); } protected void safeSetBlock(WorldGenLevel level, BlockPos pos, BlockState state, Predicate 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 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 adjacentStateAccessor, BlockPos pos, Predicate 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 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); } } }