diff --git a/src/main/java/org/betterx/bclib/api/features/BCLFeature.java b/src/main/java/org/betterx/bclib/api/features/BCLFeature.java index 2989dd39..7e297bd5 100644 --- a/src/main/java/org/betterx/bclib/api/features/BCLFeature.java +++ b/src/main/java/org/betterx/bclib/api/features/BCLFeature.java @@ -27,7 +27,7 @@ public class BCLFeature { BCLib.makeID("scatter_on_solid"), new ScatterFeature<>(ScatterFeatureConfig.OnSolid.CODEC)); - public static final Feature RANDOM_SELECT = register( + public static final Feature RANDOM_SELECTOR = register( BCLib.makeID("random_select"), new WeightedRandomSelectorFeature()); public static final Feature TEMPLATE = register(BCLib.makeID("template"), diff --git a/src/main/java/org/betterx/bclib/api/features/WeightedRandomSelectorFeature.java b/src/main/java/org/betterx/bclib/api/features/WeightedRandomSelectorFeature.java index 8fdd780b..521c4218 100644 --- a/src/main/java/org/betterx/bclib/api/features/WeightedRandomSelectorFeature.java +++ b/src/main/java/org/betterx/bclib/api/features/WeightedRandomSelectorFeature.java @@ -26,14 +26,13 @@ public class WeightedRandomSelectorFeature extends Feature w.chance).reduce(0.0f, (p, c) -> p + c); float bar = random.nextFloat() * totalWeight; - + for (WeightedPlacedFeature f : cfg.features) { selected = f.feature.value(); bar -= f.chance; if (bar < 0) break; } } - return selected.place(level, generator, random, pos); } } diff --git a/src/main/java/org/betterx/bclib/api/features/placement/Is.java b/src/main/java/org/betterx/bclib/api/features/placement/Is.java index ae853500..c54ef570 100644 --- a/src/main/java/org/betterx/bclib/api/features/placement/Is.java +++ b/src/main/java/org/betterx/bclib/api/features/placement/Is.java @@ -1,6 +1,8 @@ package org.betterx.bclib.api.features.placement; import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Vec3i; import net.minecraft.util.RandomSource; import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate; @@ -11,29 +13,40 @@ 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 Is extends PlacementFilter { public static final Codec CODEC = RecordCodecBuilder.create((instance) -> instance .group( BlockPredicate.CODEC .fieldOf("predicate") - .forGetter(cfg -> cfg.predicate) + .forGetter(cfg -> cfg.predicate), + Vec3i.CODEC + .optionalFieldOf("offset") + .forGetter(cfg -> cfg.offset) ) .apply(instance, Is::new)); private final BlockPredicate predicate; + private final Optional offset; - public Is(BlockPredicate predicate) { + public Is(BlockPredicate predicate, Optional offset) { this.predicate = predicate; + this.offset = offset; } public static Is simple(BlockPredicate predicate) { - return new Is(predicate); + return new Is(predicate, Optional.empty()); + } + + public static Is below(BlockPredicate predicate) { + return new Is(predicate, Optional.of(Direction.DOWN.getNormal())); } @Override protected boolean shouldPlace(PlacementContext ctx, RandomSource random, BlockPos pos) { WorldGenLevel level = ctx.getLevel(); - return predicate.test(level, pos); + return predicate.test(level, offset.map(v -> pos.offset(v.getX(), v.getY(), v.getZ())).orElse(pos)); } @Override diff --git a/src/main/java/org/betterx/bclib/api/features/placement/OnEveryLayer.java b/src/main/java/org/betterx/bclib/api/features/placement/OnEveryLayer.java index dacd07d9..74656fa5 100644 --- a/src/main/java/org/betterx/bclib/api/features/placement/OnEveryLayer.java +++ b/src/main/java/org/betterx/bclib/api/features/placement/OnEveryLayer.java @@ -10,24 +10,40 @@ import net.minecraft.world.level.levelgen.placement.PlacementModifier; import net.minecraft.world.level.levelgen.placement.PlacementModifierType; import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; import org.betterx.bclib.util.BlocksHelper; +import java.util.Optional; import java.util.stream.Stream; public class OnEveryLayer extends PlacementModifier { - private static OnEveryLayer INSTANCE = new OnEveryLayer(); - public static final Codec CODEC = Codec.unit(() -> INSTANCE); + private static OnEveryLayer INSTANCE = new OnEveryLayer(Optional.empty(), Optional.empty()); + private static OnEveryLayer INSTANCE_MIN_4 = new OnEveryLayer(Optional.of(4), Optional.empty()); + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance + .group( + Codec.INT.optionalFieldOf("min").forGetter(o -> o.minHeight), + Codec.INT.optionalFieldOf("max").forGetter(o -> o.maxHeight) + ).apply(instance, OnEveryLayer::new)); - private OnEveryLayer() { + private final Optional minHeight; + private final Optional maxHeight; + private OnEveryLayer(Optional minHeight, Optional maxHeight) { + this.minHeight = minHeight; + + this.maxHeight = maxHeight; } public static OnEveryLayer simple() { return INSTANCE; } + public static OnEveryLayer min4() { + return INSTANCE_MIN_4; + } + @Override public Stream getPositions(PlacementContext ctx, RandomSource random, @@ -37,10 +53,14 @@ public class OnEveryLayer final int z = pos.getZ(); final int x = pos.getX(); - int y = ctx.getHeight(Heightmap.Types.MOTION_BLOCKING, x, z); + final int levelHeight = ctx.getHeight(Heightmap.Types.MOTION_BLOCKING, x, z); + final int minLevelHeight = ctx.getMinBuildHeight(); + int y = maxHeight.map(h -> Math.min(levelHeight, h)).orElse(levelHeight); + final int minHeight = this.minHeight.map(h -> Math.max(minLevelHeight, h)).orElse(minLevelHeight); + int layerY; do { - layerY = OnEveryLayer.findOnGroundYPosition(ctx, x, y, z); + layerY = OnEveryLayer.findOnGroundYPosition(ctx, x, y, z, minHeight); if (layerY != Integer.MAX_VALUE) { builder.add(new BlockPos(x, layerY, z)); y = layerY - 1; @@ -55,10 +75,10 @@ public class OnEveryLayer return PlacementModifiers.ON_EVERY_LAYER; } - private static int findOnGroundYPosition(PlacementContext ctx, int x, int startY, int z) { + private static int findOnGroundYPosition(PlacementContext ctx, int x, int startY, int z, int minHeight) { BlockPos.MutableBlockPos mPos = new BlockPos.MutableBlockPos(x, startY, z); BlockState nowState = ctx.getBlockState(mPos); - for (int y = startY; y >= ctx.getMinBuildHeight() + 1; --y) { + for (int y = startY; y >= minHeight + 1; --y) { mPos.setY(y - 1); BlockState belowState = ctx.getBlockState(mPos); if (BlocksHelper.isTerrain(belowState) && BlocksHelper.isFreeOrFluid(nowState) && !belowState.is(Blocks.BEDROCK)) { diff --git a/src/main/java/org/betterx/bclib/api/tag/CommonBlockTags.java b/src/main/java/org/betterx/bclib/api/tag/CommonBlockTags.java index 7fa3f908..e802519f 100644 --- a/src/main/java/org/betterx/bclib/api/tag/CommonBlockTags.java +++ b/src/main/java/org/betterx/bclib/api/tag/CommonBlockTags.java @@ -58,6 +58,7 @@ public class CommonBlockTags { TagAPI.BLOCKS.addOtherTags(TERRAIN, BlockTags.DRIPSTONE_REPLACEABLE, BlockTags.BASE_STONE_OVERWORLD, + BlockTags.NYLIUM, NETHER_STONES, NETHER_ORES, SOUL_GROUND,