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.TagKey; import net.minecraft.util.RandomSource; 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.BlockBlobConfiguration; 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.CompositeFeatureConfiguration; 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.EndGatewayConfiguration; import net.minecraft.world.level.levelgen.feature.configurations.EndSpikeConfiguration; 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.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.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.SpeleothemClusterConfiguration; import net.minecraft.world.level.levelgen.feature.configurations.SpeleothemConfiguration; 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.TemplateFeatureConfiguration; 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; import net.minecraft.world.level.levelgen.feature.configurations.WeightedRandomFeatureConfiguration; 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 FALLEN_TREE = register("fallen_tree", new FallenTreeFeature(FallenTreeConfiguration.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 SPIKE = register("spike", new SpikeFeature(SpikeConfiguration.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 BLOCK_BLOB = register("block_blob", new BlockBlobFeature(BlockBlobConfiguration.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 EndSpikeFeature(EndSpikeConfiguration.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)); @Deprecated public static final Feature RANDOM_SELECTOR = register( "random_selector", new RandomSelectorFeature(RandomFeatureConfiguration.CODEC) ); public static final Feature WEIGHTED_RANDOM_SELECTOR = register( "weighted_random_selector", new WeightedRandomSelectorFeature(WeightedRandomFeatureConfiguration.CODEC) ); public static final Feature SIMPLE_RANDOM_SELECTOR = register( "simple_random_selector", new SimpleRandomSelectorFeature(CompositeFeatureConfiguration.CODEC) ); public static final Feature RANDOM_BOOLEAN_SELECTOR = register( "random_boolean_selector", new RandomBooleanSelectorFeature(RandomBooleanFeatureConfiguration.CODEC) ); public static final Feature SEQUENCE = register("sequence", new SequenceFeature(CompositeFeatureConfiguration.CODEC)); public static final Feature TEMPLATE = register("template", new TemplateFeature(TemplateFeatureConfiguration.CODEC)); public static final Feature GEODE = register("geode", new GeodeFeature(GeodeConfiguration.CODEC)); public static final Feature SPELEOTHEM_CLUSTER = register( "speleothem_cluster", new SpeleothemClusterFeature(SpeleothemClusterConfiguration.CODEC) ); public static final Feature LARGE_DRIPSTONE = register( "large_dripstone", new LargeDripstoneFeature(LargeDripstoneConfiguration.CODEC) ); public static final Feature SPELEOTHEM = register("speleothem", new SpeleothemFeature(SpeleothemConfiguration.CODEC)); public static final Feature SCULK_PATCH = register("sculk_patch", new SculkPatchFeature(SculkPatchConfiguration.CODEC)); private final MapCodec>> configuredCodec; private static > F register(final String name, final F feature) { return Registry.register(BuiltInRegistries.FEATURE, name, feature); } public Feature(final Codec codec) { this.configuredCodec = codec.fieldOf("config").xmap(c -> new ConfiguredFeature<>(this, c), ConfiguredFeature::config); } public MapCodec>> configuredCodec() { return this.configuredCodec; } protected void setBlock(final LevelWriter level, final BlockPos pos, final BlockState blockState) { level.setBlock(pos, blockState, 3); } public static Predicate isReplaceable(final TagKey cannotReplaceTag) { return s -> !s.is(cannotReplaceTag); } protected void safeSetBlock(final WorldGenLevel level, final BlockPos pos, final BlockState state, final Predicate canReplace) { if (canReplace.test(level.getBlockState(pos))) { level.setBlock(pos, state, 2); } } public abstract boolean place(final FeaturePlaceContext context); public boolean place(final FC config, final WorldGenLevel level, final ChunkGenerator chunkGenerator, final RandomSource random, final BlockPos origin) { return level.ensureCanWrite(origin) ? this.place(new FeaturePlaceContext<>(Optional.empty(), level, chunkGenerator, random, origin, config)) : false; } public static boolean checkNeighbors(final Function blockGetter, final BlockPos pos, final Predicate predicate) { BlockPos.MutableBlockPos neighborPos = new BlockPos.MutableBlockPos(); for (Direction direction : Direction.values()) { neighborPos.setWithOffset(pos, direction); if (predicate.test((BlockState)blockGetter.apply(neighborPos))) { return true; } } return false; } public static boolean isAdjacentToAir(final Function blockGetter, final BlockPos pos) { return checkNeighbors(blockGetter, pos, BlockBehaviour.BlockStateBase::isAir); } protected void markAboveForPostProcessing(final WorldGenLevel level, final BlockPos placePos) { BlockPos.MutableBlockPos pos = placePos.mutable(); for (int i = 0; i < 2; i++) { pos.move(Direction.UP); if (level.getBlockState(pos).isAir()) { return; } level.getChunk(pos).markPosForPostProcessing(pos); } } }