deep dark

This commit is contained in:
ItsBlackGear 2022-07-17 05:03:50 -04:00
parent 2a07f32d75
commit 9557d06203
8 changed files with 251 additions and 18 deletions

View file

@ -116,7 +116,7 @@ public class SculkVeinBlock extends MultifaceBlock implements SculkSpreadable, S
if (blockState.is(replaceable)) {
BlockState sculk = WBBlocks.SCULK.get().defaultBlockState();
level.setBlock(blockPos, sculk, 3);
Block.pushEntitiesUp(blockState, sculk, (ServerLevel)level, pos);
if (level instanceof ServerLevel server) Block.pushEntitiesUp(blockState, sculk, server, pos);
level.playSound(null, blockPos, WBSoundEvents.BLOCK_SCULK_SPREAD, SoundSource.BLOCKS, 1.0F, 1.0F);
this.allGrowTypeGrower.grow(sculk, level, blockPos, spreadManager.isWorldGen());
Direction opposite = direction.getOpposite();

View file

@ -40,7 +40,7 @@ public class WBBiomes {
generation.addFeature(GenerationStep.Decoration.VEGETAL_DECORATION, VegetationPlacements.PATCH_DEAD_BUSH);
generation.addFeature(GenerationStep.Decoration.VEGETAL_DECORATION, VegetationPlacements.PATCH_WATERLILY);
generation.addFeature(GenerationStep.Decoration.VEGETAL_DECORATION, AquaticPlacements.SEAGRASS_SWAMP);
return new Biome.BiomeBuilder().biomeCategory(Biome.BiomeCategory.SWAMP).precipitation(Biome.Precipitation.RAIN).temperature(0.8F).downfall(0.9f).specialEffects(new BiomeSpecialEffects.Builder().waterColor(3832426).waterFogColor(5077600).fogColor(12638463).skyColor(calculateSkyColor(0.8f)).foliageColorOverride(9285927).grassColorModifier(BiomeSpecialEffects.GrassColorModifier.SWAMP).ambientMoodSound(AmbientMoodSettings.LEGACY_CAVE_SETTINGS).build()).mobSpawnSettings(spawn.build()).generationSettings(generation.build()).build();
return new Biome.BiomeBuilder().biomeCategory(Biome.BiomeCategory.SWAMP).precipitation(Biome.Precipitation.RAIN).temperature(0.8F).downfall(0.9F).specialEffects(new BiomeSpecialEffects.Builder().waterColor(3832426).waterFogColor(5077600).fogColor(12638463).skyColor(calculateSkyColor(0.8f)).foliageColorOverride(9285927).grassColorModifier(BiomeSpecialEffects.GrassColorModifier.SWAMP).ambientMoodSound(AmbientMoodSettings.LEGACY_CAVE_SETTINGS).build()).mobSpawnSettings(spawn.build()).generationSettings(generation.build()).build();
}
// Deep Dark

View file

@ -5,9 +5,13 @@ import com.cursedcauldron.wildbackport.common.worldgen.features.GrassDiskConfigu
import com.cursedcauldron.wildbackport.common.worldgen.features.GrassDiskFeature;
import com.cursedcauldron.wildbackport.common.worldgen.features.RootedTreeConfig;
import com.cursedcauldron.wildbackport.common.worldgen.features.RootedTreeFeature;
import com.cursedcauldron.wildbackport.common.worldgen.features.SculkGrowthFeature;
import com.cursedcauldron.wildbackport.common.worldgen.features.SculkPatchConfiguration;
import com.cursedcauldron.wildbackport.common.worldgen.features.SculkPatchFeature;
import com.cursedcauldron.wildbackport.core.api.CoreRegistry;
import net.minecraft.core.Registry;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.configurations.GlowLichenConfiguration;
import java.util.function.Supplier;
@ -16,6 +20,8 @@ import java.util.function.Supplier;
public class WBFeatures {
public static final CoreRegistry<Feature<?>> FEATURES = CoreRegistry.create(Registry.FEATURE, WildBackport.MOD_ID);
public static final Supplier<Feature<RootedTreeConfig>> TREE = FEATURES.register("tree", () -> new RootedTreeFeature(RootedTreeConfig.CODEC));
public static final Supplier<Feature<GrassDiskConfiguration>> DISK = FEATURES.register("disk", () -> new GrassDiskFeature(GrassDiskConfiguration.CODEC));
public static final Supplier<Feature<RootedTreeConfig>> TREE = FEATURES.register("tree", () -> new RootedTreeFeature(RootedTreeConfig.CODEC));
public static final Supplier<Feature<GrassDiskConfiguration>> DISK = FEATURES.register("disk", () -> new GrassDiskFeature(GrassDiskConfiguration.CODEC));
public static final Supplier<Feature<SculkPatchConfiguration>> SCULK_PATCH = FEATURES.register("sculk_patch", () -> new SculkPatchFeature(SculkPatchConfiguration.CODEC));
public static final Supplier<Feature<GlowLichenConfiguration>> SCULK_GROWTH = FEATURES.register("sculk_growth", () -> new SculkGrowthFeature(GlowLichenConfiguration.CODEC));
}

View file

@ -12,6 +12,7 @@ import com.cursedcauldron.wildbackport.common.worldgen.decorator.MangroveRootPla
import com.cursedcauldron.wildbackport.common.worldgen.decorator.WeightedLeaveVineDecorator;
import com.cursedcauldron.wildbackport.common.worldgen.features.GrassDiskConfiguration;
import com.cursedcauldron.wildbackport.common.worldgen.features.RootedTreeConfig;
import com.cursedcauldron.wildbackport.common.worldgen.features.SculkPatchConfiguration;
import com.cursedcauldron.wildbackport.common.worldgen.placers.MangroveRootPlacer;
import com.cursedcauldron.wildbackport.common.worldgen.placers.UpwardBranchingTrunk;
import net.minecraft.core.BlockPos;
@ -31,6 +32,7 @@ import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.WeightedPlacedFeature;
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.GlowLichenConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.RandomFeatureConfiguration;
import net.minecraft.world.level.levelgen.feature.featuresize.TwoLayersFeatureSize;
import net.minecraft.world.level.levelgen.feature.foliageplacers.RandomSpreadFoliagePlacer;
@ -60,7 +62,7 @@ public class WBWorldGeneration {
// Mangrove Swamp
//TODO: fix mangroves not generating moss
public static final Holder<ConfiguredFeature<RootedTreeConfig, ?>> MANGROVE = config("mangrove", WBFeatures.TREE.get(), new RootedTreeConfig.Builder(
public static final Holder<ConfiguredFeature<RootedTreeConfig, ?>> MANGROVE = config("mangrove", WBFeatures.TREE.get(), new RootedTreeConfig.Builder(
BlockStateProvider.simple(WBBlocks.MANGROVE_LOG.get()),
new UpwardBranchingTrunk(2, 1, 4, UniformInt.of(1, 4), 0.5F, UniformInt.of(0, 1), Registry.BLOCK.getOrCreateTag(WBBlockTags.MANGROVE_LOGS_CAN_GROW_THROUGH)),
BlockStateProvider.simple(WBBlocks.MANGROVE_LEAVES.get()),
@ -73,7 +75,7 @@ public class WBWorldGeneration {
new BeehiveDecorator(0.01F)
)).ignoreVines().build());
public static final Holder<ConfiguredFeature<RootedTreeConfig, ?>> TALL_MANGROVE = config("tall_mangrove", WBFeatures.TREE.get(), new RootedTreeConfig.Builder(
public static final Holder<ConfiguredFeature<RootedTreeConfig, ?>> TALL_MANGROVE = config("tall_mangrove", WBFeatures.TREE.get(), new RootedTreeConfig.Builder(
BlockStateProvider.simple(WBBlocks.MANGROVE_LOG.get()),
new UpwardBranchingTrunk(4, 1, 9, UniformInt.of(1, 6), 0.5F, UniformInt.of(0, 1), Registry.BLOCK.getOrCreateTag(WBBlockTags.MANGROVE_LOGS_CAN_GROW_THROUGH)),
BlockStateProvider.simple(WBBlocks.MANGROVE_LEAVES.get()),
@ -86,17 +88,34 @@ public class WBWorldGeneration {
new BeehiveDecorator(0.01F)
)).ignoreVines().build());
public static final Holder<PlacedFeature> MANGROVE_CHECKED = place("mangrove_checked", MANGROVE, PlacementUtils.filteredByBlockSurvival(WBBlocks.MANGROVE_PROPAGULE.get()));
public static final Holder<PlacedFeature> TALL_MANGROVE_CHECKED = place("tall_mangrove_checked", TALL_MANGROVE, PlacementUtils.filteredByBlockSurvival(WBBlocks.MANGROVE_PROPAGULE.get()));
public static final Holder<PlacedFeature> MANGROVE_CHECKED = place("mangrove_checked", MANGROVE, PlacementUtils.filteredByBlockSurvival(WBBlocks.MANGROVE_PROPAGULE.get()));
public static final Holder<PlacedFeature> TALL_MANGROVE_CHECKED = place("tall_mangrove_checked", TALL_MANGROVE, PlacementUtils.filteredByBlockSurvival(WBBlocks.MANGROVE_PROPAGULE.get()));
public static final Holder<ConfiguredFeature<RandomFeatureConfiguration, ?>> MANGROVE_VEGETATION = config("mangrove_vegetation", Feature.RANDOM_SELECTOR, new RandomFeatureConfiguration(List.of(new WeightedPlacedFeature(TALL_MANGROVE_CHECKED, 0.85F)), MANGROVE_CHECKED));
public static final Holder<PlacedFeature> TREES_MANGROVE = place("trees_mangrove", MANGROVE_VEGETATION, CountPlacement.of(25), InSquarePlacement.spread(), SurfaceWaterDepthFilter.forMaxDepth(5), PlacementUtils.HEIGHTMAP_OCEAN_FLOOR, BiomeFilter.biome(), BlockPredicateFilter.forPredicate(BlockPredicate.wouldSurvive(WBBlocks.MANGROVE_PROPAGULE.get().defaultBlockState(), BlockPos.ZERO)));
public static final Holder<ConfiguredFeature<RandomFeatureConfiguration, ?>> MANGROVE_VEGETATION = config("mangrove_vegetation", Feature.RANDOM_SELECTOR, new RandomFeatureConfiguration(List.of(
new WeightedPlacedFeature(TALL_MANGROVE_CHECKED, 0.85F)),
MANGROVE_CHECKED
));
public static final Holder<PlacedFeature> TREES_MANGROVE = place("trees_mangrove", MANGROVE_VEGETATION, CountPlacement.of(25), InSquarePlacement.spread(), SurfaceWaterDepthFilter.forMaxDepth(5), PlacementUtils.HEIGHTMAP_OCEAN_FLOOR, BiomeFilter.biome(), BlockPredicateFilter.forPredicate(BlockPredicate.wouldSurvive(WBBlocks.MANGROVE_PROPAGULE.get().defaultBlockState(), BlockPos.ZERO)));
public static final Holder<ConfiguredFeature<GrassDiskConfiguration, ?>> DISK_GRASS_CONFIG = config("disk_grass", WBFeatures.DISK.get(), new GrassDiskConfiguration(new PredicatedStateProvider(BlockStateProvider.simple(Blocks.DIRT), List.of(new PredicatedStateProvider.Rule(BlockPredicate.not(BlockPredicate.allOf(BlockPredicate.solid(Direction.UP.getNormal()), BlockPredicate.matchesFluid(Fluids.WATER, Direction.UP.getNormal()))), BlockStateProvider.simple(Blocks.GRASS_BLOCK)))), BlockPredicate.matchesBlocks(List.of(Blocks.DIRT, WBBlocks.MUD.get())), UniformInt.of(2, 6), 2));
public static final Holder<PlacedFeature> DISK_GRASS = place("disk_grass", DISK_GRASS_CONFIG, CountPlacement.of(1), InSquarePlacement.spread(), PlacementUtils.HEIGHTMAP_TOP_SOLID, RandomOffsetPlacement.vertical(ConstantInt.of(-1)), BlockPredicateFilter.forPredicate(BlockPredicate.matchesBlock(WBBlocks.MUD.get(), Vec3i.ZERO)), BiomeFilter.biome());
public static final Holder<ConfiguredFeature<GrassDiskConfiguration, ?>> DISK_GRASS_CONFIG = config("disk_grass", WBFeatures.DISK.get(), new GrassDiskConfiguration(
new PredicatedStateProvider(BlockStateProvider.simple(Blocks.DIRT), List.of(new PredicatedStateProvider.Rule(BlockPredicate.not(BlockPredicate.allOf(BlockPredicate.solid(Direction.UP.getNormal()), BlockPredicate.matchesFluid(Fluids.WATER, Direction.UP.getNormal()))), BlockStateProvider.simple(Blocks.GRASS_BLOCK)))),
BlockPredicate.matchesBlocks(List.of(Blocks.DIRT, WBBlocks.MUD.get())),
UniformInt.of(2, 6),
2
));
public static final Holder<PlacedFeature> DISK_GRASS = place("disk_grass", DISK_GRASS_CONFIG, CountPlacement.of(1), InSquarePlacement.spread(), PlacementUtils.HEIGHTMAP_TOP_SOLID, RandomOffsetPlacement.vertical(ConstantInt.of(-1)), BlockPredicateFilter.forPredicate(BlockPredicate.matchesBlock(WBBlocks.MUD.get(), Vec3i.ZERO)), BiomeFilter.biome());
// Deep Dark
public static final Holder<ConfiguredFeature<SculkPatchConfiguration, ?>> SCULK_PATCH_DEEP_DARK_CONFIG = config("sculk_patch_deep_dark", WBFeatures.SCULK_PATCH.get(), new SculkPatchConfiguration(10, 32, 64, 0, 1, ConstantInt.of(0), 0.5F));
public static final Holder<PlacedFeature> SCULK_PATCH_DEEP_DARK = place("sculk_patch_deep_dark", SCULK_PATCH_DEEP_DARK_CONFIG, CountPlacement.of(ConstantInt.of(256)), InSquarePlacement.spread(), PlacementUtils.RANGE_BOTTOM_TO_MAX_TERRAIN_HEIGHT, BiomeFilter.biome());
public static final Holder<ConfiguredFeature<SculkPatchConfiguration, ?>> SCULK_PATCH_ANCIENT_CITY_CONFIG = config("sculk_patch_ancient_city", WBFeatures.SCULK_PATCH.get(), new SculkPatchConfiguration(10, 32, 64, 0, 1, UniformInt.of(1, 3), 0.5F));
public static final Holder<PlacedFeature> SCULK_PATCH_ANCIENT_CITY = place("sculk_patch_ancient_city", SCULK_PATCH_ANCIENT_CITY_CONFIG);
public static final Holder<ConfiguredFeature<GlowLichenConfiguration, ?>> SCULK_VEIN_CONFIG = config("sculk_vein", WBFeatures.SCULK_GROWTH.get(), new GlowLichenConfiguration(20, true, true, true, 1.0F, HolderSet.direct(Block::builtInRegistryHolder, Blocks.STONE, Blocks.ANDESITE, Blocks.DIORITE, Blocks.GRANITE, Blocks.DRIPSTONE_BLOCK, Blocks.CALCITE, Blocks.TUFF, Blocks.DEEPSLATE)));
public static final Holder<PlacedFeature> SCULK_VEIN = place("sculk_vein", SCULK_VEIN_CONFIG, CountPlacement.of(UniformInt.of(204, 250)), InSquarePlacement.spread(), PlacementUtils.RANGE_BOTTOM_TO_MAX_TERRAIN_HEIGHT, BiomeFilter.biome());
// Registry
public static <FC extends FeatureConfiguration, F extends Feature<FC>> Holder<ConfiguredFeature<FC, ?>> config(String key, F feature, FC configuration) {

View file

@ -5,8 +5,6 @@ import com.cursedcauldron.wildbackport.common.registry.entity.WBEntities;
import com.cursedcauldron.wildbackport.common.registry.worldgen.WBWorldGeneration;
import com.cursedcauldron.wildbackport.core.api.worldgen.BiomeModifier;
import com.cursedcauldron.wildbackport.core.api.worldgen.BiomeWriter;
import net.minecraft.data.worldgen.placement.MiscOverworldPlacements;
import net.minecraft.data.worldgen.placement.VegetationPlacements;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.MobCategory;
import net.minecraft.world.level.levelgen.GenerationStep;
@ -16,18 +14,20 @@ import net.minecraft.world.level.levelgen.GenerationStep;
public class WorldGenerator {
public static void setup() {
BiomeModifier.add(WorldGenerator::mangroveSwamp, WBBiomes.MANGROVE_SWAMP);
BiomeModifier.add(WorldGenerator::deepDark, WBBiomes.DEEP_DARK);
}
public static void mangroveSwamp(BiomeWriter writer) {
writer.addFeature(GenerationStep.Decoration.UNDERGROUND_ORES, WBWorldGeneration.DISK_GRASS);
writer.addFeature(GenerationStep.Decoration.VEGETAL_DECORATION, WBWorldGeneration.TREES_MANGROVE);
// writer.addFeature(GenerationStep.Decoration.VEGETAL_DECORATION, VegetationPlacements.PATCH_GRASS_NORMAL);
// writer.addFeature(GenerationStep.Decoration.VEGETAL_DECORATION, VegetationPlacements.PATCH_DEAD_BUSH);
// writer.addFeature(GenerationStep.Decoration.VEGETAL_DECORATION, VegetationPlacements.PATCH_WATERLILY);
writer.addSpawn(MobCategory.MONSTER, EntityType.SLIME, 1, 1, 1);
writer.addSpawn(MobCategory.CREATURE, WBEntities.FROG.get(), 10, 2, 5);
writer.addSpawn(MobCategory.WATER_AMBIENT, EntityType.TROPICAL_FISH, 25, 8, 8);
}
public static void deepDark(BiomeWriter writer) {
writer.addFeature(GenerationStep.Decoration.UNDERGROUND_DECORATION, WBWorldGeneration.SCULK_VEIN);
writer.addFeature(GenerationStep.Decoration.UNDERGROUND_DECORATION, WBWorldGeneration.SCULK_PATCH_DEEP_DARK);
}
}

View file

@ -0,0 +1,101 @@
package com.cursedcauldron.wildbackport.common.worldgen.features;
import com.cursedcauldron.wildbackport.common.blocks.SculkVeinBlock;
import com.cursedcauldron.wildbackport.common.registry.WBBlocks;
import com.google.common.collect.Lists;
import com.mojang.serialization.Codec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
import net.minecraft.world.level.levelgen.feature.configurations.GlowLichenConfiguration;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
public class SculkGrowthFeature extends Feature<GlowLichenConfiguration> {
public SculkGrowthFeature(Codec<GlowLichenConfiguration> codec) {
super(codec);
}
@Override
public boolean place(FeaturePlaceContext<GlowLichenConfiguration> context) {
WorldGenLevel level = context.level();
BlockPos pos = context.origin();
Random random = context.random();
GlowLichenConfiguration config = context.config();
if (!isNotAirOrWater(level.getBlockState(pos))) {
List<Direction> directions = getShuffledDirections(config, random);
if (placeGrowthIfPossible(level, pos, level.getBlockState(pos), config, random, directions)) {
return true;
} else {
BlockPos.MutableBlockPos mutable = pos.mutable();
for (Direction direction : directions) {
mutable.set(pos);
List<Direction> filteredDirections = getShuffledDirectionsExcept(config, random, direction.getOpposite());
for (int i = 0; i < config.searchRange; i++) {
mutable.setWithOffset(pos, direction);
BlockState state = level.getBlockState(mutable);
if (isNotAirOrWater(state) && !state.is(WBBlocks.SCULK_VEIN.get())) {
break;
}
if (placeGrowthIfPossible(level, mutable, state, config, random, filteredDirections)) {
return true;
}
}
}
}
}
return false;
}
public static boolean placeGrowthIfPossible(WorldGenLevel level, BlockPos pos, BlockState state, GlowLichenConfiguration config, Random random, List<Direction> directions) {
BlockPos.MutableBlockPos mutable = pos.mutable();
for (Direction direction : directions) {
BlockState blockState = level.getBlockState(mutable.setWithOffset(pos, direction));
if (blockState.is(config.canBePlacedOn)) {
SculkVeinBlock veinBlock = (SculkVeinBlock) WBBlocks.SCULK_VEIN.get();
BlockState veinState = veinBlock.getStateForPlacement(state, level, pos, direction);
if (veinState == null) {
return false;
}
level.setBlock(pos, veinState, 3);
level.getChunk(pos).markPosForPostprocessing(pos);
if (random.nextFloat() < config.chanceOfSpreading) {
veinBlock.allGrowTypeGrower.grow(veinState, level, pos, direction, random, true);
}
return true;
}
}
return false;
}
public static List<Direction> getShuffledDirections(GlowLichenConfiguration config, Random random) {
List<Direction> list = Lists.newArrayList(config.validDirections);
Collections.shuffle(list, random);
return list;
}
public static List<Direction> getShuffledDirectionsExcept(GlowLichenConfiguration config, Random random, Direction except) {
List<Direction> list = config.validDirections.stream().filter(direction -> direction != except).collect(Collectors.toList());
Collections.shuffle(list, random);
return list;
}
private static boolean isNotAirOrWater(BlockState state) {
return !state.isAir() && !state.is(Blocks.WATER);
}
}

View file

@ -0,0 +1,26 @@
package com.cursedcauldron.wildbackport.common.worldgen.features;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.util.valueproviders.IntProvider;
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
public record SculkPatchConfiguration(int chargeCount, int amountPerCharge, int spreadAttempts, int growthRounds, int spreadRounds, IntProvider extraRareGrowths, float catalystChance) implements FeatureConfiguration {
public static final Codec<SculkPatchConfiguration> CODEC = RecordCodecBuilder.create(instance -> {
return instance.group(Codec.intRange(1, 32).fieldOf("charge_count").forGetter(config -> {
return config.chargeCount;
}), Codec.intRange(1, 500).fieldOf("amount_per_charge").forGetter(config -> {
return config.amountPerCharge;
}), Codec.intRange(1, 64).fieldOf("spread_attempts").forGetter(config -> {
return config.spreadAttempts;
}), Codec.intRange(0, 8).fieldOf("growth_rounds").forGetter(config -> {
return config.growthRounds;
}), Codec.intRange(0, 8).fieldOf("spread_rounds").forGetter(config -> {
return config.spreadRounds;
}), IntProvider.CODEC.fieldOf("extra_rare_growths").forGetter(config -> {
return config.extraRareGrowths;
}), Codec.floatRange(0.0F, 1.0F).fieldOf("catalyst_chance").forGetter(config -> {
return config.catalystChance;
})).apply(instance, SculkPatchConfiguration::new);
});
}

View file

@ -0,0 +1,81 @@
package com.cursedcauldron.wildbackport.common.worldgen.features;
import com.cursedcauldron.wildbackport.common.blocks.SculkShriekerBlock;
import com.cursedcauldron.wildbackport.common.blocks.SculkSpreadManager;
import com.cursedcauldron.wildbackport.common.blocks.SculkSpreadable;
import com.cursedcauldron.wildbackport.common.registry.WBBlocks;
import com.cursedcauldron.wildbackport.common.utils.DirectionUtils;
import com.mojang.serialization.Codec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
import java.util.Random;
//<>
public class SculkPatchFeature extends Feature<SculkPatchConfiguration> {
public SculkPatchFeature(Codec<SculkPatchConfiguration> codec) {
super(codec);
}
@Override
public boolean place(FeaturePlaceContext<SculkPatchConfiguration> context) {
WorldGenLevel level = context.level();
BlockPos pos = context.origin();
if (!this.canSpreadFrom(level, pos)) {
return false;
} else {
SculkPatchConfiguration config = context.config();
Random random = context.random();
SculkSpreadManager spreader = SculkSpreadManager.createWorldGen();
int rounds = config.spreadRounds() + config.growthRounds();
for (int i = 0; i < rounds; i++) {
for (int count = 0; count < config.chargeCount(); count++) {
spreader.spread(pos, config.amountPerCharge());
}
boolean spreadable = i < config.spreadRounds();
for (int attempts = 0; attempts < config.spreadAttempts(); attempts++) {
spreader.tick(level, pos, random, spreadable);
}
spreader.clearCursors();
}
BlockPos catalystPos = pos.below();
if (random.nextFloat() <= config.catalystChance() && level.getBlockState(catalystPos).isCollisionShapeFullBlock(level, catalystPos)) {
level.setBlock(pos, WBBlocks.SCULK_CATALYST.get().defaultBlockState(), 3);
}
int extraRareGrowths = config.extraRareGrowths().sample(random);
for (int i = 0; i < extraRareGrowths; i++) {
BlockPos shriekPos = pos.offset(random.nextInt(5) - 2, 0, random.nextInt(5) - 2);
if (level.getBlockState(shriekPos).isAir() && level.getBlockState(shriekPos.below()).isFaceSturdy(level, shriekPos.below(), Direction.UP)) {
level.setBlock(shriekPos, WBBlocks.SCULK_SHRIEKER.get().defaultBlockState().setValue(SculkShriekerBlock.CAN_SUMMON, true), 3);
}
}
return true;
}
}
private boolean canSpreadFrom(LevelAccessor level, BlockPos pos) {
BlockState state = level.getBlockState(pos);
if (state.getBlock() instanceof SculkSpreadable) {
return true;
} else {
return (state.isAir() || (state.is(Blocks.WATER) && state.getFluidState().isSource())) && DirectionUtils.stream().map(pos::relative).anyMatch(position -> {
return level.getBlockState(position).isCollisionShapeFullBlock(level, position);
});
}
}
}