From 7b9936af05324d458d1c06946dd9d4898f7dfd13 Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 3 Jun 2022 00:08:26 +0200 Subject: [PATCH] Some Feature related fixes --- .../bclib/api/features/BCLFeatureBuilder.java | 59 ++++++++++++++- .../bclib/api/tag/CommonBlockTags.java | 3 +- .../bclib/mixin/common/BiomeSourceMixin.java | 12 +-- .../org/betterx/bclib/util/BlocksHelper.java | 28 ++++++- .../bclib/world/features/ScatterFeature.java | 4 +- .../world/features/ScatterFeatureConfig.java | 35 +++++++-- .../bclib/world/features/SurfaceFeature.java | 9 --- .../world/features/placement/Extend.java | 11 ++- .../placement/FindSolidInDirection.java | 6 +- .../bclib/world/features/placement/Is.java | 43 +++++++++++ .../world/features/placement/IsBasin.java | 31 +++++--- .../placement/IsEmptyAboveSampledFilter.java | 8 +- .../world/features/placement/Offset.java | 13 ++++ .../features/placement/OnEveryLayer.java | 74 +++++++++++++++++++ .../placement/PlacementModifiers.java | 8 ++ .../world/features/placement/Stencil.java | 23 ++++-- 16 files changed, 310 insertions(+), 57 deletions(-) create mode 100644 src/main/java/org/betterx/bclib/world/features/placement/Is.java create mode 100644 src/main/java/org/betterx/bclib/world/features/placement/OnEveryLayer.java 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 7ea2db24..02392217 100644 --- a/src/main/java/org/betterx/bclib/api/features/BCLFeatureBuilder.java +++ b/src/main/java/org/betterx/bclib/api/features/BCLFeatureBuilder.java @@ -1,19 +1,20 @@ package org.betterx.bclib.api.features; import net.minecraft.core.Direction; +import net.minecraft.core.Vec3i; import net.minecraft.data.worldgen.placement.PlacementUtils; import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.valueproviders.IntProvider; import net.minecraft.util.valueproviders.UniformInt; import net.minecraft.world.level.levelgen.GenerationStep.Decoration; +import net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate; import net.minecraft.world.level.levelgen.feature.Feature; import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration; import net.minecraft.world.level.levelgen.placement.*; import net.minecraft.world.level.material.Material; import org.betterx.bclib.world.features.BCLFeature; -import org.betterx.bclib.world.features.placement.FindSolidInDirection; -import org.betterx.bclib.world.features.placement.IsEmptyAboveSampledFilter; -import org.betterx.bclib.world.features.placement.MinEmptyFilter; +import org.betterx.bclib.world.features.placement.*; import java.util.ArrayList; import java.util.List; @@ -137,6 +138,14 @@ public class BCLFeatureBuilder surface) { + for (int len = 0; len < length; len++) { + if (surface.test(level.getBlockState(startPos))) { + if (len == 0) { //we started inside of the surface + for (int lenUp = 0; lenUp < length; lenUp++) { + startPos.move(dir, -1); + if (!surface.test(level.getBlockState(startPos))) { + startPos.move(dir, 1); + return true; + } + } + return false; + } + return true; + } + + startPos.move(dir, 1); + } + return false; + } + + public static boolean isFreeSpace(LevelAccessor level, BlockPos startPos, Direction dir, int length, Predicate freeSurface) { MutableBlockPos POS = startPos.mutable(); - for (int len = 1; len < length; len++) { + for (int len = 0; len < length; len++) { POS.move(dir, 1); if (!freeSurface.test(level.getBlockState(POS))) { return false; diff --git a/src/main/java/org/betterx/bclib/world/features/ScatterFeature.java b/src/main/java/org/betterx/bclib/world/features/ScatterFeature.java index db4978c3..2655780a 100644 --- a/src/main/java/org/betterx/bclib/world/features/ScatterFeature.java +++ b/src/main/java/org/betterx/bclib/world/features/ScatterFeature.java @@ -110,13 +110,13 @@ public class ScatterFeature final double distNormalizer = (config.maxSpread * Math.sqrt(2)); - final int tryCount = (int) Math.min(16, 4 * config.maxSpread * config.maxSpread); + final int tryCount = config.spreadCount.sample(random); 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); - if (BlocksHelper.findSurface(level, POS, surfaceDirection, 4, config::isValidBase)) { + if (BlocksHelper.findSurroundingSurface(level, POS, surfaceDirection, 4, config::isValidBase)) { int myHeight; if (config.growWhileFree) { myHeight = BlocksHelper.blockCount(level, diff --git a/src/main/java/org/betterx/bclib/world/features/ScatterFeatureConfig.java b/src/main/java/org/betterx/bclib/world/features/ScatterFeatureConfig.java index ad5a6f62..3b66d1f7 100644 --- a/src/main/java/org/betterx/bclib/world/features/ScatterFeatureConfig.java +++ b/src/main/java/org/betterx/bclib/world/features/ScatterFeatureConfig.java @@ -1,11 +1,14 @@ package org.betterx.bclib.world.features; import net.minecraft.util.RandomSource; +import net.minecraft.util.valueproviders.ConstantInt; +import net.minecraft.util.valueproviders.IntProvider; +import net.minecraft.util.valueproviders.UniformInt; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration; -import com.mojang.datafixers.util.Function14; +import com.mojang.datafixers.util.Function15; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import org.betterx.bclib.BCLib; @@ -14,7 +17,7 @@ import org.betterx.bclib.api.tag.CommonBlockTags; import java.util.Optional; public abstract class ScatterFeatureConfig implements FeatureConfiguration { - public interface Instancer extends Function14, Float, Float, Float, Float, Integer, Integer, Float, Float, Float, Boolean, T> { + public interface Instancer extends Function15, Float, Float, Float, Float, Integer, Integer, Float, Float, Float, Boolean, IntProvider, T> { } public final BlockState clusterBlock; @@ -31,6 +34,8 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration { public final float sizeVariation; public final float floorChance; + public final IntProvider spreadCount; + public final boolean growWhileFree; public ScatterFeatureConfig(BlockState clusterBlock, @@ -46,7 +51,8 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration { float maxSpread, float sizeVariation, float floorChance, - boolean growWhileFree) { + boolean growWhileFree, + IntProvider spreadCount) { this.clusterBlock = clusterBlock; this.tipBlock = tipBlock == null ? clusterBlock : tipBlock; this.bottomBlock = bottomBlock == null ? clusterBlock : bottomBlock; @@ -61,6 +67,7 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration { this.sizeVariation = sizeVariation; this.floorChance = floorChance; this.growWhileFree = growWhileFree; + this.spreadCount = spreadCount; } @@ -137,7 +144,11 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration { .BOOL .fieldOf("grow_while_empty") .orElse(false) - .forGetter((T cfg) -> cfg.growWhileFree) + .forGetter((T cfg) -> cfg.growWhileFree), + IntProvider.codec(0, 64) + .fieldOf("length") + .orElse(UniformInt.of(0, 3)) + .forGetter(cfg -> cfg.spreadCount) ) .apply(instance, instancer) ); @@ -158,6 +169,7 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration { private float sizeVariation = 0; private float floorChance = 0.5f; private boolean growWhileFree = false; + public IntProvider spreadCount = ConstantInt.of(0); private final Instancer instancer; public Builder(Instancer instancer) { @@ -251,6 +263,11 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration { } public Builder spread(float maxSpread, float sizeVariation) { + return spread(maxSpread, sizeVariation, ConstantInt.of((int) Math.min(16, 4 * maxSpread * maxSpread))); + } + + public Builder spread(float maxSpread, float sizeVariation, IntProvider spreadCount) { + this.spreadCount = spreadCount; // this.maxSpread = maxSpread; this.sizeVariation = sizeVariation; return this; @@ -286,7 +303,8 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration { this.maxSpread, this.sizeVariation, this.floorChance, - this.growWhileFree + this.growWhileFree, + this.spreadCount ); } } @@ -307,7 +325,8 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration { float maxSpread, float sizeVariation, float floorChance, - boolean growWhileFree) { + boolean growWhileFree, + IntProvider spreadCount) { super(clusterBlock, tipBlock, bottomBlock, @@ -321,9 +340,11 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration { maxSpread, sizeVariation, floorChance, - growWhileFree); + growWhileFree, + spreadCount); } + public static Builder startOnSolid() { return Builder.start(OnSolid::new); } diff --git a/src/main/java/org/betterx/bclib/world/features/SurfaceFeature.java b/src/main/java/org/betterx/bclib/world/features/SurfaceFeature.java index 59c4d4c1..fffafc33 100644 --- a/src/main/java/org/betterx/bclib/world/features/SurfaceFeature.java +++ b/src/main/java/org/betterx/bclib/world/features/SurfaceFeature.java @@ -2,7 +2,6 @@ package org.betterx.bclib.world.features; import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.levelgen.feature.Feature; import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext; import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration; @@ -37,14 +36,6 @@ public abstract class SurfaceFeature extends Fea minHeight(ctx), this::isValidSurface); if (pos.isPresent()) { - int y2 = ctx.level().getHeight(Heightmap.Types.WORLD_SURFACE_WG, ctx.origin().getX(), ctx.origin().getZ()); - int y3 = ctx.level().getHeight(Heightmap.Types.WORLD_SURFACE, ctx.origin().getX(), ctx.origin().getZ()); - int y4 = ctx.level().getHeight(Heightmap.Types.OCEAN_FLOOR, ctx.origin().getX(), ctx.origin().getZ()); - int y5 = ctx.level().getHeight(Heightmap.Types.OCEAN_FLOOR_WG, ctx.origin().getX(), ctx.origin().getZ()); - System.out.println("Surfaces:" + pos - .get() - .getY() + ", " + y2 + ", " + y3 + ", " + y4 + ", " + y5 + ", " + ctx.origin().getY()); - generate(pos.get(), ctx); return true; } diff --git a/src/main/java/org/betterx/bclib/world/features/placement/Extend.java b/src/main/java/org/betterx/bclib/world/features/placement/Extend.java index ccf76dd9..d9dc25e5 100644 --- a/src/main/java/org/betterx/bclib/world/features/placement/Extend.java +++ b/src/main/java/org/betterx/bclib/world/features/placement/Extend.java @@ -12,8 +12,6 @@ import net.minecraft.world.level.levelgen.placement.PlacementModifierType; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; -import java.util.ArrayList; -import java.util.List; import java.util.stream.Stream; public class Extend extends PlacementModifier { @@ -42,12 +40,13 @@ public class Extend extends PlacementModifier { public Stream getPositions(PlacementContext placementContext, RandomSource random, BlockPos blockPos) { + var builder = Stream.builder(); final int count = length.sample(random); - List pos = new ArrayList<>(count); - for (int y = 0; y < count; y++) { - pos.add(blockPos.relative(direction, y + 1)); + builder.add(blockPos); + for (int y = 1; y < count + 1; y++) { + builder.add(blockPos.relative(direction, y)); } - return pos.stream(); + return builder.build(); } @Override diff --git a/src/main/java/org/betterx/bclib/world/features/placement/FindSolidInDirection.java b/src/main/java/org/betterx/bclib/world/features/placement/FindSolidInDirection.java index 98e973bc..fa4d4f4c 100644 --- a/src/main/java/org/betterx/bclib/world/features/placement/FindSolidInDirection.java +++ b/src/main/java/org/betterx/bclib/world/features/placement/FindSolidInDirection.java @@ -16,8 +16,8 @@ import java.util.stream.Stream; public class FindSolidInDirection extends PlacementModifier { - protected static final FindSolidInDirection DOWN = new FindSolidInDirection(Direction.DOWN, 12); - protected static final FindSolidInDirection UP = new FindSolidInDirection(Direction.UP, 12); + protected static final FindSolidInDirection DOWN = new FindSolidInDirection(Direction.DOWN, 6); + protected static final FindSolidInDirection UP = new FindSolidInDirection(Direction.UP, 6); public static final Codec CODEC = RecordCodecBuilder.create((instance) -> instance .group( Direction.CODEC.fieldOf("dir").orElse(Direction.DOWN).forGetter((p) -> p.direction), @@ -54,7 +54,7 @@ public class FindSolidInDirection extends PlacementModifier { RandomSource randomSource, BlockPos blockPos) { BlockPos.MutableBlockPos POS = blockPos.mutable(); - if (BlocksHelper.findSurface(placementContext.getLevel(), + if (BlocksHelper.findSurroundingSurface(placementContext.getLevel(), POS, direction, maxSearchDistance, diff --git a/src/main/java/org/betterx/bclib/world/features/placement/Is.java b/src/main/java/org/betterx/bclib/world/features/placement/Is.java new file mode 100644 index 00000000..3643874a --- /dev/null +++ b/src/main/java/org/betterx/bclib/world/features/placement/Is.java @@ -0,0 +1,43 @@ +package org.betterx.bclib.world.features.placement; + +import net.minecraft.core.BlockPos; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.WorldGenLevel; +import net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate; +import net.minecraft.world.level.levelgen.placement.PlacementContext; +import net.minecraft.world.level.levelgen.placement.PlacementFilter; +import net.minecraft.world.level.levelgen.placement.PlacementModifierType; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +public class Is extends PlacementFilter { + public static final Codec CODEC = RecordCodecBuilder.create((instance) -> instance + .group( + BlockPredicate.CODEC + .fieldOf("predicate") + .forGetter(cfg -> cfg.predicate) + ) + .apply(instance, Is::new)); + + private final BlockPredicate predicate; + + public Is(BlockPredicate predicate) { + this.predicate = predicate; + } + + public static Is simple(BlockPredicate predicate) { + return new Is(predicate); + } + + @Override + protected boolean shouldPlace(PlacementContext ctx, RandomSource random, BlockPos pos) { + WorldGenLevel level = ctx.getLevel(); + return predicate.test(level, pos); + } + + @Override + public PlacementModifierType type() { + return PlacementModifiers.IS; + } +} diff --git a/src/main/java/org/betterx/bclib/world/features/placement/IsBasin.java b/src/main/java/org/betterx/bclib/world/features/placement/IsBasin.java index 73e7f884..23df59ca 100644 --- a/src/main/java/org/betterx/bclib/world/features/placement/IsBasin.java +++ b/src/main/java/org/betterx/bclib/world/features/placement/IsBasin.java @@ -1,9 +1,9 @@ package org.betterx.bclib.world.features.placement; import net.minecraft.core.BlockPos; -import net.minecraft.util.ExtraCodecs; import net.minecraft.util.RandomSource; -import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.WorldGenLevel; +import net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate; import net.minecraft.world.level.levelgen.placement.PlacementContext; import net.minecraft.world.level.levelgen.placement.PlacementFilter; import net.minecraft.world.level.levelgen.placement.PlacementModifierType; @@ -11,27 +11,34 @@ import net.minecraft.world.level.levelgen.placement.PlacementModifierType; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; -import java.util.List; - public class IsBasin extends PlacementFilter { public static final Codec CODEC = RecordCodecBuilder.create((instance) -> instance .group( - ExtraCodecs.nonEmptyList(BlockState.CODEC.listOf()) - .fieldOf("blocks") - .forGetter(cfg -> cfg.blocks) + BlockPredicate.CODEC + .fieldOf("predicate") + .forGetter(cfg -> cfg.predicate) ) .apply(instance, IsBasin::new)); - private final List blocks; + private final BlockPredicate predicate; - public IsBasin(List blocks) { - this.blocks = blocks; + public IsBasin(BlockPredicate predicate) { + this.predicate = predicate; + } + + public static IsBasin simple(BlockPredicate predicate) { + + return new IsBasin(predicate); } @Override protected boolean shouldPlace(PlacementContext ctx, RandomSource random, BlockPos pos) { - BlockState bs = ctx.getLevel().getBlockState(pos); - return blocks.stream().map(b -> b.getBlock()).anyMatch(b -> bs.is(b)); + WorldGenLevel level = ctx.getLevel(); + return predicate.test(level, pos.below()) + && predicate.test(level, pos.west()) + && predicate.test(level, pos.east()) + && predicate.test(level, pos.north()) + && predicate.test(level, pos.south()); } @Override diff --git a/src/main/java/org/betterx/bclib/world/features/placement/IsEmptyAboveSampledFilter.java b/src/main/java/org/betterx/bclib/world/features/placement/IsEmptyAboveSampledFilter.java index ea36b026..5621c12a 100644 --- a/src/main/java/org/betterx/bclib/world/features/placement/IsEmptyAboveSampledFilter.java +++ b/src/main/java/org/betterx/bclib/world/features/placement/IsEmptyAboveSampledFilter.java @@ -15,6 +15,7 @@ import com.mojang.serialization.codecs.RecordCodecBuilder; */ public class IsEmptyAboveSampledFilter extends PlacementFilter { private static final IsEmptyAboveSampledFilter DEFAULT = new IsEmptyAboveSampledFilter(4, 2); + private static final IsEmptyAboveSampledFilter DEFAULT1 = new IsEmptyAboveSampledFilter(1, 1); public static final Codec CODEC = RecordCodecBuilder.create((instance) -> instance .group( Codec.intRange(1, 32).fieldOf("d1").orElse(2).forGetter((p) -> p.distance1), @@ -26,6 +27,10 @@ public class IsEmptyAboveSampledFilter extends PlacementFilter { return DEFAULT; } + public static PlacementFilter emptyAbove() { + return DEFAULT1; + } + public IsEmptyAboveSampledFilter(int d1, int d2) { this.distance1 = d1; this.distance2 = d2; @@ -38,7 +43,8 @@ public class IsEmptyAboveSampledFilter extends PlacementFilter { @Override protected boolean shouldPlace(PlacementContext ctx, RandomSource random, BlockPos pos) { WorldGenLevel level = ctx.getLevel(); - if (level.isEmptyBlock(pos.above(distance1)) && level.isEmptyBlock(pos.above(distance2))) { + if (level.isEmptyBlock(pos.above(distance1)) + && (distance1 == distance2 || level.isEmptyBlock(pos.above(distance2)))) { return true; } return false; diff --git a/src/main/java/org/betterx/bclib/world/features/placement/Offset.java b/src/main/java/org/betterx/bclib/world/features/placement/Offset.java index 3526d34c..15de0429 100644 --- a/src/main/java/org/betterx/bclib/world/features/placement/Offset.java +++ b/src/main/java/org/betterx/bclib/world/features/placement/Offset.java @@ -1,18 +1,22 @@ package org.betterx.bclib.world.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.levelgen.placement.PlacementContext; import net.minecraft.world.level.levelgen.placement.PlacementModifier; import net.minecraft.world.level.levelgen.placement.PlacementModifierType; +import com.google.common.collect.Maps; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import java.util.Map; import java.util.stream.Stream; public class Offset extends PlacementModifier { + private static Map DIRECTIONS = Maps.newHashMap(); public static final Codec CODEC = RecordCodecBuilder.create((instance) -> instance .group( Vec3i.CODEC @@ -27,6 +31,10 @@ public class Offset extends PlacementModifier { this.offset = offset; } + public static Offset inDirection(Direction dir) { + return DIRECTIONS.get(dir); + } + @Override public Stream getPositions(PlacementContext placementContext, RandomSource randomSource, @@ -38,4 +46,9 @@ public class Offset extends PlacementModifier { public PlacementModifierType type() { return PlacementModifiers.OFFSET; } + + static { + for (Direction d : Direction.values()) + DIRECTIONS.put(d, new Offset(d.getNormal())); + } } diff --git a/src/main/java/org/betterx/bclib/world/features/placement/OnEveryLayer.java b/src/main/java/org/betterx/bclib/world/features/placement/OnEveryLayer.java new file mode 100644 index 00000000..429c4083 --- /dev/null +++ b/src/main/java/org/betterx/bclib/world/features/placement/OnEveryLayer.java @@ -0,0 +1,74 @@ +package org.betterx.bclib.world.features.placement; + +import net.minecraft.core.BlockPos; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.levelgen.placement.PlacementContext; +import net.minecraft.world.level.levelgen.placement.PlacementModifier; +import net.minecraft.world.level.levelgen.placement.PlacementModifierType; + +import com.mojang.serialization.Codec; + +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 OnEveryLayer() { + + } + + public static OnEveryLayer simple() { + return INSTANCE; + } + + @Override + public Stream getPositions(PlacementContext ctx, + RandomSource random, + BlockPos pos) { + + Stream.Builder builder = Stream.builder(); + + final int z = pos.getZ(); + final int x = pos.getX(); + int y = ctx.getHeight(Heightmap.Types.MOTION_BLOCKING, x, z); + int layerY; + do { + layerY = OnEveryLayer.findOnGroundYPosition(ctx, x, y, z); + if (layerY != Integer.MAX_VALUE) { + builder.add(new BlockPos(x, layerY, z)); + y = layerY - 1; + } + + } while (layerY != Integer.MAX_VALUE); + return builder.build(); + } + + @Override + public PlacementModifierType type() { + return PlacementModifiers.ON_EVERY_LAYER; + } + + private static int findOnGroundYPosition(PlacementContext ctx, int x, int startY, int z) { + BlockPos.MutableBlockPos mPos = new BlockPos.MutableBlockPos(x, startY, z); + BlockState nowState = ctx.getBlockState(mPos); + for (int y = startY; y >= ctx.getMinBuildHeight() + 1; --y) { + mPos.setY(y - 1); + BlockState belowState = ctx.getBlockState(mPos); + if (!OnEveryLayer.isEmpty(belowState) && OnEveryLayer.isEmpty(nowState) && !belowState.is(Blocks.BEDROCK)) { + return mPos.getY() + 1; + } + nowState = belowState; + } + return Integer.MAX_VALUE; + } + + private static boolean isEmpty(BlockState blockState) { + return blockState.isAir() || blockState.is(Blocks.WATER) || blockState.is(Blocks.LAVA); + } +} diff --git a/src/main/java/org/betterx/bclib/world/features/placement/PlacementModifiers.java b/src/main/java/org/betterx/bclib/world/features/placement/PlacementModifiers.java index 4d5f5cff..517a912c 100644 --- a/src/main/java/org/betterx/bclib/world/features/placement/PlacementModifiers.java +++ b/src/main/java/org/betterx/bclib/world/features/placement/PlacementModifiers.java @@ -29,6 +29,10 @@ public class PlacementModifiers { "is_basin", IsBasin.CODEC); + public static final PlacementModifierType IS = register( + "is", + Is.CODEC); + public static final PlacementModifierType OFFSET = register( "offset", Offset.CODEC); @@ -37,6 +41,10 @@ public class PlacementModifiers { "extend", Extend.CODEC); + public static final PlacementModifierType ON_EVERY_LAYER = register( + "on_every_layer", + OnEveryLayer.CODEC); + private static

PlacementModifierType

register(String path, Codec

codec) { return register(BCLib.makeID(path), codec); diff --git a/src/main/java/org/betterx/bclib/world/features/placement/Stencil.java b/src/main/java/org/betterx/bclib/world/features/placement/Stencil.java index 4dedd640..467a97ca 100644 --- a/src/main/java/org/betterx/bclib/world/features/placement/Stencil.java +++ b/src/main/java/org/betterx/bclib/world/features/placement/Stencil.java @@ -20,23 +20,29 @@ public class Stencil extends PlacementModifier { private static final Boolean[] BN_STENCIL; private final List stencil; private static final Stencil DEFAULT; + private static final Stencil DEFAULT4; + private final int selectOneIn; private static List convert(Boolean[] s) { return Arrays.stream(s).toList(); } - public Stencil(Boolean[] stencil) { - this(convert(stencil)); + public Stencil(Boolean[] stencil, int selectOneIn) { + this(convert(stencil), selectOneIn); } - public Stencil(List stencil) { + public Stencil(List stencil, int selectOneIn) { this.stencil = stencil; + this.selectOneIn = selectOneIn; } - public static Stencil basic() { + public static Stencil all() { return DEFAULT; } + public static Stencil oneIn4() { + return DEFAULT4; + } @Override public Stream getPositions(PlacementContext placementContext, @@ -319,13 +325,18 @@ public class Stencil extends PlacementModifier { false }; - DEFAULT = new Stencil(BN_STENCIL); + DEFAULT = new Stencil(BN_STENCIL, 1); + DEFAULT4 = new Stencil(BN_STENCIL, 4); CODEC = RecordCodecBuilder.create((instance) -> instance .group( ExtraCodecs.nonEmptyList(Codec.BOOL.listOf()) .fieldOf("structures") .orElse(convert(BN_STENCIL)) - .forGetter((Stencil a) -> a.stencil) + .forGetter((Stencil a) -> a.stencil), + Codec.INT + .fieldOf("one_in") + .orElse(1) + .forGetter((Stencil a) -> a.selectOneIn) ) .apply(instance, Stencil::new) );