diff --git a/src/main/java/org/betterx/bclib/api/features/BCLFeatureBuilder.java b/src/main/java/org/betterx/bclib/api/features/BCLFeatureBuilder.java index 07efa707..a7f961eb 100644 --- a/src/main/java/org/betterx/bclib/api/features/BCLFeatureBuilder.java +++ b/src/main/java/org/betterx/bclib/api/features/BCLFeatureBuilder.java @@ -260,6 +260,10 @@ public class BCLFeatureBuilder Feature inlineFeature) { List> set = new ArrayList<>(2); if (cfg.floorChance > 0) set.add(PlacementUtils.inlinePlaced(inlineFeature, - cfg, - EnvironmentScanPlacement.scanningFor(Direction.DOWN, - BlockPredicate.solid(), - BlockPredicate.ONLY_IN_AIR_PREDICATE, - 12), - RandomOffsetPlacement.vertical(ConstantInt.of(1)))); + cfg, + EnvironmentScanPlacement.scanningFor(Direction.DOWN, + BlockPredicate.matchesTag(CommonBlockTags.TERRAIN), + BlockPredicate.ONLY_IN_AIR_PREDICATE, + 12), + RandomOffsetPlacement.vertical(ConstantInt.of(1)))); if (cfg.floorChance < 1) { set.add(PlacementUtils.inlinePlaced(inlineFeature, - cfg, - EnvironmentScanPlacement.scanningFor(Direction.UP, - BlockPredicate.solid(), - BlockPredicate.ONLY_IN_AIR_PREDICATE, - 12), - RandomOffsetPlacement.vertical(ConstantInt.of(-1)))); + cfg, + EnvironmentScanPlacement.scanningFor(Direction.UP, + BlockPredicate.matchesTag(CommonBlockTags.TERRAIN), + BlockPredicate.ONLY_IN_AIR_PREDICATE, + 12), + RandomOffsetPlacement.vertical(ConstantInt.of(-1)))); } SimpleRandomFeatureConfiguration configuration = new SimpleRandomFeatureConfiguration(HolderSet.direct(set)); @@ -112,21 +112,21 @@ public class ScatterFeature for (int i = 0; i < tryCount; i++) { int x = origin.getX() + (int) (random.nextGaussian() * config.maxSpread); int z = origin.getZ() + (int) (random.nextGaussian() * config.maxSpread); - POS.set(x, origin.getY(), z); + POS.set(x, basePos.getY(), z); if (BlocksHelper.findSurroundingSurface(level, POS, surfaceDirection, 4, config::isValidBase)) { int myHeight; if (config.growWhileFree) { myHeight = BlocksHelper.blockCount(level, - POS, - direction, - config.maxHeight, - state -> state.getMaterial().isReplaceable()); + POS, + direction, + config.maxHeight, + BlocksHelper::isFree + ); } else { myHeight = centerHeight; } - POS.move(direction, 1); int dx = x - POS.getX(); int dz = z - POS.getZ(); float sizeFactor = (1 - (float) (Math.sqrt(dx * dx + dz * dz) / distNormalizer)); @@ -134,15 +134,19 @@ public class ScatterFeature myHeight = (int) Math.min(Math.max( config.minHeight, config.minHeight + sizeFactor * (myHeight - config.minHeight) - ), config.maxHeight); + ), config.maxHeight); + BlockState baseState = level.getBlockState(POS.relative(direction.getOpposite())); + if (!config.isValidBase(baseState)) { + System.out.println("Starting from " + baseState + " at " + POS.relative(direction.getOpposite())); + } buildPillarWithBase(level, - POS, - POS.relative(direction.getOpposite()), - direction, - myHeight, - config, - random); + POS, + POS.relative(direction.getOpposite()), + direction, + myHeight, + config, + random); } } } @@ -155,7 +159,7 @@ public class ScatterFeature int height, ScatterFeatureConfig config, RandomSource random) { - if (BlocksHelper.isFreeSpace(level, origin, direction, height, (state) -> state.is(Blocks.AIR))) { + if (BlocksHelper.isFreeSpace(level, origin, direction, height, BlocksHelper::isFree)) { createPatchOfBaseBlocks(level, random, basePos, config); buildPillar(level, origin, direction, height, config, random); } @@ -170,6 +174,10 @@ public class ScatterFeature final BlockPos.MutableBlockPos POS = origin.mutable(); buildBaseToTipColumn(height, (blockState) -> { + BlockState previous = level.getBlockState(POS); + if (!BlocksHelper.isFree(previous)) { + System.out.println("Replaced " + previous + " with " + blockState + " at " + POS); + } BlocksHelper.setWithoutUpdate(level, POS, blockState); POS.move(direction); }, config, random); @@ -181,16 +189,6 @@ public class ScatterFeature RandomSource random) { for (int size = 0; size < totalHeight; size++) { consumer.accept(config.createBlock(size, totalHeight - 1, random)); -// Block s = config.createBlock(size, totalHeight - 1, random).getBlock(); -// if (size == 0) s = Blocks.YELLOW_CONCRETE; -// else if (size == 1) s = Blocks.LIME_CONCRETE; -// else if (size == 2) s = Blocks.CYAN_CONCRETE; -// else if (size == 3) s = Blocks.LIGHT_BLUE_CONCRETE; -// else if (size == 4) s = Blocks.BLUE_CONCRETE; -// else if (size == 5) s = Blocks.PURPLE_CONCRETE; -// else if (size == 6) s = Blocks.MAGENTA_CONCRETE; -// else s = Blocks.GRAY_CONCRETE; -// consumer.accept(s.defaultBlockState()); } } diff --git a/src/main/java/org/betterx/bclib/api/features/config/ScatterFeatureConfig.java b/src/main/java/org/betterx/bclib/api/features/config/ScatterFeatureConfig.java index 40b22eec..8aa7f888 100644 --- a/src/main/java/org/betterx/bclib/api/features/config/ScatterFeatureConfig.java +++ b/src/main/java/org/betterx/bclib/api/features/config/ScatterFeatureConfig.java @@ -81,81 +81,81 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration { public static Codec buildCodec(Instancer instancer) { return RecordCodecBuilder.create((instance) -> instance - .group(BlockState.CODEC - .fieldOf("cluster_block") - .forGetter((T cfg) -> cfg.clusterBlock), - BlockState.CODEC - .optionalFieldOf("tip_block") - .orElse(Optional.empty()) - .forGetter((T cfg) -> cfg.tipBlock == cfg.clusterBlock - ? Optional.empty() - : Optional.of(cfg.tipBlock)), - BlockState.CODEC - .optionalFieldOf("bottom_block") - .orElse(Optional.empty()) - .forGetter((T cfg) -> cfg.bottomBlock == cfg.clusterBlock - ? Optional.empty() - : Optional.of(cfg.bottomBlock)), - BlockState.CODEC - .optionalFieldOf("base_state") - .forGetter((T cfg) -> cfg.baseState), - Codec - .floatRange(0.0F, 1.0F) - .fieldOf("baseReplaceChance") - .orElse(1.0F) - .forGetter((T cfg) -> cfg.baseReplaceChance), - Codec - .floatRange(0.0F, 1.0F) - .fieldOf("chance_of_directional_spread") - .orElse(0.7F) - .forGetter((T cfg) -> cfg.chanceOfDirectionalSpread), - Codec - .floatRange(0.0F, 1.0F) - .fieldOf("chance_of_spread_radius2") - .orElse(0.5F) - .forGetter((T cfg) -> cfg.chanceOfSpreadRadius2), - Codec - .floatRange(0.0F, 1.0F) - .fieldOf("chance_of_spread_radius3") - .orElse(0.5F) - .forGetter((T cfg) -> cfg.chanceOfSpreadRadius3), - Codec - .intRange(1, 20) - .fieldOf("min_height") - .orElse(2) - .forGetter((T cfg) -> cfg.minHeight), - Codec - .intRange(1, 20) - .fieldOf("max_height") - .orElse(7) - .forGetter((T cfg) -> cfg.maxHeight), - Codec - .floatRange(0, 10) - .fieldOf("max_spread") - .orElse(2f) - .forGetter((T cfg) -> cfg.maxSpread), - Codec - .floatRange(0, 1) - .fieldOf("size_variation") - .orElse(0.7f) - .forGetter((T cfg) -> cfg.sizeVariation), - Codec - .floatRange(0, 1) - .fieldOf("floor_chance") - .orElse(0.5f) - .forGetter((T cfg) -> cfg.floorChance), - Codec - .BOOL - .fieldOf("grow_while_empty") - .orElse(false) - .forGetter((T cfg) -> cfg.growWhileFree), - IntProvider.codec(0, 64) - .fieldOf("length") - .orElse(UniformInt.of(0, 3)) - .forGetter(cfg -> cfg.spreadCount) - ) - .apply(instance, instancer) - ); + .group(BlockState.CODEC + .fieldOf("cluster_block") + .forGetter((T cfg) -> cfg.clusterBlock), + BlockState.CODEC + .optionalFieldOf("tip_block") + .orElse(Optional.empty()) + .forGetter((T cfg) -> cfg.tipBlock == cfg.clusterBlock + ? Optional.empty() + : Optional.of(cfg.tipBlock)), + BlockState.CODEC + .optionalFieldOf("bottom_block") + .orElse(Optional.empty()) + .forGetter((T cfg) -> cfg.bottomBlock == cfg.clusterBlock + ? Optional.empty() + : Optional.of(cfg.bottomBlock)), + BlockState.CODEC + .optionalFieldOf("base_state") + .forGetter((T cfg) -> cfg.baseState), + Codec + .floatRange(0.0F, 1.0F) + .fieldOf("baseReplaceChance") + .orElse(1.0F) + .forGetter((T cfg) -> cfg.baseReplaceChance), + Codec + .floatRange(0.0F, 1.0F) + .fieldOf("chance_of_directional_spread") + .orElse(0.7F) + .forGetter((T cfg) -> cfg.chanceOfDirectionalSpread), + Codec + .floatRange(0.0F, 1.0F) + .fieldOf("chance_of_spread_radius2") + .orElse(0.5F) + .forGetter((T cfg) -> cfg.chanceOfSpreadRadius2), + Codec + .floatRange(0.0F, 1.0F) + .fieldOf("chance_of_spread_radius3") + .orElse(0.5F) + .forGetter((T cfg) -> cfg.chanceOfSpreadRadius3), + Codec + .intRange(1, 20) + .fieldOf("min_height") + .orElse(2) + .forGetter((T cfg) -> cfg.minHeight), + Codec + .intRange(1, 20) + .fieldOf("max_height") + .orElse(7) + .forGetter((T cfg) -> cfg.maxHeight), + Codec + .floatRange(0, 10) + .fieldOf("max_spread") + .orElse(2f) + .forGetter((T cfg) -> cfg.maxSpread), + Codec + .floatRange(0, 1) + .fieldOf("size_variation") + .orElse(0.7f) + .forGetter((T cfg) -> cfg.sizeVariation), + Codec + .floatRange(0, 1) + .fieldOf("floor_chance") + .orElse(0.5f) + .forGetter((T cfg) -> cfg.floorChance), + Codec + .BOOL + .fieldOf("grow_while_empty") + .orElse(false) + .forGetter((T cfg) -> cfg.growWhileFree), + IntProvider.codec(0, 64) + .fieldOf("length") + .orElse(UniformInt.of(0, 3)) + .forGetter(cfg -> cfg.spreadCount) + ) + .apply(instance, instancer) + ); } public static class Builder { @@ -244,10 +244,10 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration { float chanceOfSpreadRadius2, float chanceOfSpreadRadius3) { return generateBaseBlock(baseState, - 1, - chanceOfDirectionalSpread, - chanceOfSpreadRadius2, - chanceOfSpreadRadius3); + 1, + chanceOfDirectionalSpread, + chanceOfSpreadRadius2, + chanceOfSpreadRadius3); } public Builder generateBaseBlock(BlockState baseState, @@ -309,7 +309,7 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration { this.floorChance, this.growWhileFree, this.spreadCount - ); + ); } } @@ -332,20 +332,20 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration { boolean growWhileFree, IntProvider spreadCount) { super(clusterBlock, - tipBlock, - bottomBlock, - baseState, - baseReplaceChance, - chanceOfDirectionalSpread, - chanceOfSpreadRadius2, - chanceOfSpreadRadius3, - minHeight, - maxHeight, - maxSpread, - sizeVariation, - floorChance, - growWhileFree, - spreadCount); + tipBlock, + bottomBlock, + baseState, + baseReplaceChance, + chanceOfDirectionalSpread, + chanceOfSpreadRadius2, + chanceOfSpreadRadius3, + minHeight, + maxHeight, + maxSpread, + sizeVariation, + floorChance, + growWhileFree, + spreadCount); } diff --git a/src/main/java/org/betterx/bclib/api/features/placement/IsBasin.java b/src/main/java/org/betterx/bclib/api/features/placement/IsBasin.java index c52d2ad3..5470331a 100644 --- a/src/main/java/org/betterx/bclib/api/features/placement/IsBasin.java +++ b/src/main/java/org/betterx/bclib/api/features/placement/IsBasin.java @@ -11,29 +11,46 @@ import net.minecraft.world.level.levelgen.placement.PlacementModifierType; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import java.util.Optional; + public class IsBasin extends PlacementFilter { public static final Codec CODEC = RecordCodecBuilder.create((instance) -> instance .group( BlockPredicate.CODEC .fieldOf("predicate") - .forGetter(cfg -> cfg.predicate) + .forGetter(cfg -> cfg.predicate), + BlockPredicate.CODEC + .optionalFieldOf("top_predicate") + .orElse(Optional.empty()) + .forGetter(cfg -> cfg.topPredicate) ) .apply(instance, IsBasin::new)); private final BlockPredicate predicate; + private final Optional topPredicate; public IsBasin(BlockPredicate predicate) { + this(predicate, Optional.empty()); + } + + public IsBasin(BlockPredicate predicate, Optional topPredicate) { this.predicate = predicate; + this.topPredicate = topPredicate; } public static IsBasin simple(BlockPredicate predicate) { - return new IsBasin(predicate); } + public static IsBasin openTop(BlockPredicate predicate) { + return new IsBasin(predicate, Optional.of(BlockPredicate.ONLY_IN_AIR_PREDICATE)); + } + @Override protected boolean shouldPlace(PlacementContext ctx, RandomSource random, BlockPos pos) { WorldGenLevel level = ctx.getLevel(); + if (topPredicate.isPresent() && !topPredicate.get().test(level, pos.above())) return false; + return predicate.test(level, pos.below()) && predicate.test(level, pos.west()) && predicate.test(level, pos.east()) diff --git a/src/main/java/org/betterx/bclib/api/features/placement/MinEmptyFilter.java b/src/main/java/org/betterx/bclib/api/features/placement/MinEmptyFilter.java index 6a174bc5..36757f3d 100644 --- a/src/main/java/org/betterx/bclib/api/features/placement/MinEmptyFilter.java +++ b/src/main/java/org/betterx/bclib/api/features/placement/MinEmptyFilter.java @@ -53,7 +53,7 @@ public class MinEmptyFilter extends PlacementFilter { pos.relative(direction), direction, distance - 1, - state -> state.getMaterial().isReplaceable() + BlocksHelper::isFree ); } diff --git a/src/main/java/org/betterx/bclib/util/BlocksHelper.java b/src/main/java/org/betterx/bclib/util/BlocksHelper.java index 4cd6916d..b2035e55 100644 --- a/src/main/java/org/betterx/bclib/util/BlocksHelper.java +++ b/src/main/java/org/betterx/bclib/util/BlocksHelper.java @@ -251,21 +251,28 @@ public class BlocksHelper { Direction dir, int length, Predicate surface) { + BlockState beforeState = null; + BlockState nowState; for (int len = 0; len < length; len++) { - if (surface.test(level.getBlockState(startPos))) { + nowState = level.getBlockState(startPos); + if (surface.test(nowState)) { if (len == 0) { //we started inside of the surface + beforeState = nowState; for (int lenUp = 0; lenUp < length; lenUp++) { startPos.move(dir, -1); - if (BlocksHelper.isFree(level.getBlockState(startPos))) { - startPos.move(dir, 1); - return true; + nowState = level.getBlockState(startPos); + if (BlocksHelper.isFree(nowState)) { + return surface.test(beforeState); } + beforeState = nowState; } return false; + } else { + startPos.move(dir, -1); + return BlocksHelper.isFree(beforeState); } - return true; } - + beforeState = nowState; startPos.move(dir, 1); } return false; @@ -279,11 +286,10 @@ public class BlocksHelper { Predicate freeSurface) { MutableBlockPos POS = startPos.mutable(); for (int len = 0; len < length; len++) { - POS.move(dir, 1); if (!freeSurface.test(level.getBlockState(POS))) { return false; } - + POS.move(dir, 1); } return true; } @@ -294,12 +300,11 @@ public class BlocksHelper { int length, Predicate freeSurface) { MutableBlockPos POS = startPos.mutable(); - for (int len = 1; len < length; len++) { - POS.move(dir, 1); + for (int len = 0; len < length; len++) { if (!freeSurface.test(level.getBlockState(POS))) { - return len - 1; + return len; } - + POS.move(dir, 1); } return length; }