Some Feature related fixes
This commit is contained in:
parent
6adf6486ac
commit
7b9936af05
16 changed files with 310 additions and 57 deletions
|
@ -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<FC extends FeatureConfiguration, F extends Featur
|
|||
return modifier(InSquarePlacement.spread());
|
||||
}
|
||||
|
||||
public BCLFeatureBuilder stencil() {
|
||||
return modifier(Stencil.all());
|
||||
}
|
||||
|
||||
public BCLFeatureBuilder stencilOneIn4() {
|
||||
return modifier(Stencil.oneIn4());
|
||||
}
|
||||
|
||||
/**
|
||||
* Select random height that is 10 above min Build height and 10 below max generation height
|
||||
*
|
||||
|
@ -177,10 +186,38 @@ public class BCLFeatureBuilder<FC extends FeatureConfiguration, F extends Featur
|
|||
return modifier(IsEmptyAboveSampledFilter.emptyAbove4());
|
||||
}
|
||||
|
||||
public BCLFeatureBuilder isEmptyAbove() {
|
||||
return modifier(IsEmptyAboveSampledFilter.emptyAbove());
|
||||
}
|
||||
|
||||
public BCLFeatureBuilder isEmptyAbove(int d1, int d2) {
|
||||
return modifier(new IsEmptyAboveSampledFilter(d1, d2));
|
||||
}
|
||||
|
||||
public BCLFeatureBuilder onEveryLayer() {
|
||||
return modifier(OnEveryLayer.simple());
|
||||
}
|
||||
|
||||
public BCLFeatureBuilder spreadHorizontal(IntProvider p) {
|
||||
return modifier(RandomOffsetPlacement.horizontal(p));
|
||||
}
|
||||
|
||||
public BCLFeatureBuilder spreadVertical(IntProvider p) {
|
||||
return modifier(RandomOffsetPlacement.horizontal(p));
|
||||
}
|
||||
|
||||
public BCLFeatureBuilder spread(IntProvider horizontal, IntProvider vertical) {
|
||||
return modifier(RandomOffsetPlacement.of(horizontal, vertical));
|
||||
}
|
||||
|
||||
public BCLFeatureBuilder offset(Direction dir) {
|
||||
return modifier(Offset.inDirection(dir));
|
||||
}
|
||||
|
||||
public BCLFeatureBuilder offset(Vec3i dir) {
|
||||
return modifier(new Offset(dir));
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast a downward ray with max {@code distance} length to find the next solid Block.
|
||||
*
|
||||
|
@ -192,6 +229,22 @@ public class BCLFeatureBuilder<FC extends FeatureConfiguration, F extends Featur
|
|||
return modifier(FindSolidInDirection.down(distance));
|
||||
}
|
||||
|
||||
public BCLFeatureBuilder noiseBasedCount(float noiseLevel, int belowNoiseCount, int aboveNoiseCount) {
|
||||
return modifier(NoiseThresholdCountPlacement.of(noiseLevel, belowNoiseCount, aboveNoiseCount));
|
||||
}
|
||||
|
||||
public BCLFeatureBuilder extendDown(int min, int max) {
|
||||
return modifier(new Extend(Direction.DOWN, UniformInt.of(min, max)));
|
||||
}
|
||||
|
||||
public BCLFeatureBuilder inBasinOf(BlockPredicate... predicates) {
|
||||
return modifier(new IsBasin(BlockPredicate.anyOf(predicates)));
|
||||
}
|
||||
|
||||
public BCLFeatureBuilder is(BlockPredicate... predicates) {
|
||||
return modifier(new Is(BlockPredicate.anyOf(predicates)));
|
||||
}
|
||||
|
||||
public BCLFeatureBuilder findSolidCeil(int distance) {
|
||||
return modifier(FindSolidInDirection.up(distance));
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ public class CommonBlockTags {
|
|||
TagAPI.BLOCKS.add(SOUL_GROUND, Blocks.SOUL_SAND, Blocks.SOUL_SOIL);
|
||||
|
||||
TagAPI.BLOCKS.add(IS_OBSIDIAN, Blocks.OBSIDIAN, Blocks.CRYING_OBSIDIAN);
|
||||
TagAPI.BLOCKS.add(TERRAIN, Blocks.MAGMA_BLOCK);
|
||||
|
||||
TagAPI.BLOCKS.addOtherTags(TERRAIN,
|
||||
BlockTags.DRIPSTONE_REPLACEABLE,
|
||||
|
|
|
@ -28,11 +28,11 @@ public abstract class BiomeSourceMixin implements BiomeSourceAccessor {
|
|||
|
||||
@Inject(method = "<init>(Ljava/util/List;)V", at = @At("TAIL"))
|
||||
public void bcl_init(List list, CallbackInfo ci) {
|
||||
System.out.println("new BiomeSource (" + Integer.toHexString(hashCode()) + ", biomes=" + possibleBiomes().size() + ")");
|
||||
if (possibleBiomes().size() == 27) {
|
||||
System.out.println("Nether????");
|
||||
} else if (possibleBiomes().size() == 2) {
|
||||
System.out.println("Datapack Nether???");
|
||||
}
|
||||
// System.out.println("new BiomeSource (" + Integer.toHexString(hashCode()) + ", biomes=" + possibleBiomes().size() + ")");
|
||||
// if (possibleBiomes().size() == 27) {
|
||||
// System.out.println("Nether????");
|
||||
// } else if (possibleBiomes().size() == 2) {
|
||||
// System.out.println("Datapack Nether???");
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -229,13 +229,39 @@ public class BlocksHelper {
|
|||
return false;
|
||||
}
|
||||
|
||||
public static boolean findSurroundingSurface(LevelAccessor level,
|
||||
MutableBlockPos startPos,
|
||||
Direction dir,
|
||||
int length,
|
||||
Predicate<BlockState> 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<BlockState> 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;
|
||||
|
|
|
@ -110,13 +110,13 @@ public class ScatterFeature<FC extends ScatterFeatureConfig>
|
|||
|
||||
|
||||
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,
|
||||
|
|
|
@ -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<T extends ScatterFeatureConfig> extends Function14<BlockState, BlockState, BlockState, Optional<BlockState>, Float, Float, Float, Float, Integer, Integer, Float, Float, Float, Boolean, T> {
|
||||
public interface Instancer<T extends ScatterFeatureConfig> extends Function15<BlockState, BlockState, BlockState, Optional<BlockState>, 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<T> instancer;
|
||||
|
||||
public Builder(Instancer<T> instancer) {
|
||||
|
@ -251,6 +263,11 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration {
|
|||
}
|
||||
|
||||
public Builder<T> spread(float maxSpread, float sizeVariation) {
|
||||
return spread(maxSpread, sizeVariation, ConstantInt.of((int) Math.min(16, 4 * maxSpread * maxSpread)));
|
||||
}
|
||||
|
||||
public Builder<T> 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<OnSolid> startOnSolid() {
|
||||
return Builder.start(OnSolid::new);
|
||||
}
|
||||
|
|
|
@ -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<T extends FeatureConfiguration> 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;
|
||||
}
|
||||
|
|
|
@ -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<BlockPos> getPositions(PlacementContext placementContext,
|
||||
RandomSource random,
|
||||
BlockPos blockPos) {
|
||||
var builder = Stream.<BlockPos>builder();
|
||||
final int count = length.sample(random);
|
||||
List<BlockPos> 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
|
||||
|
|
|
@ -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<FindSolidInDirection> 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,
|
||||
|
|
|
@ -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<Is> 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<Is> type() {
|
||||
return PlacementModifiers.IS;
|
||||
}
|
||||
}
|
|
@ -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<IsBasin> 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<BlockState> blocks;
|
||||
private final BlockPredicate predicate;
|
||||
|
||||
public IsBasin(List<BlockState> 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
|
||||
|
|
|
@ -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<IsEmptyAboveSampledFilter> 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;
|
||||
|
|
|
@ -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<Direction, Offset> DIRECTIONS = Maps.newHashMap();
|
||||
public static final Codec<Offset> 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<BlockPos> 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()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<OnEveryLayer> CODEC = Codec.unit(() -> INSTANCE);
|
||||
|
||||
|
||||
private OnEveryLayer() {
|
||||
|
||||
}
|
||||
|
||||
public static OnEveryLayer simple() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<BlockPos> getPositions(PlacementContext ctx,
|
||||
RandomSource random,
|
||||
BlockPos pos) {
|
||||
|
||||
Stream.Builder<BlockPos> 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<OnEveryLayer> 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);
|
||||
}
|
||||
}
|
|
@ -29,6 +29,10 @@ public class PlacementModifiers {
|
|||
"is_basin",
|
||||
IsBasin.CODEC);
|
||||
|
||||
public static final PlacementModifierType<Is> IS = register(
|
||||
"is",
|
||||
Is.CODEC);
|
||||
|
||||
public static final PlacementModifierType<Offset> OFFSET = register(
|
||||
"offset",
|
||||
Offset.CODEC);
|
||||
|
@ -37,6 +41,10 @@ public class PlacementModifiers {
|
|||
"extend",
|
||||
Extend.CODEC);
|
||||
|
||||
public static final PlacementModifierType<OnEveryLayer> ON_EVERY_LAYER = register(
|
||||
"on_every_layer",
|
||||
OnEveryLayer.CODEC);
|
||||
|
||||
|
||||
private static <P extends PlacementModifier> PlacementModifierType<P> register(String path, Codec<P> codec) {
|
||||
return register(BCLib.makeID(path), codec);
|
||||
|
|
|
@ -20,23 +20,29 @@ public class Stencil extends PlacementModifier {
|
|||
private static final Boolean[] BN_STENCIL;
|
||||
private final List<Boolean> stencil;
|
||||
private static final Stencil DEFAULT;
|
||||
private static final Stencil DEFAULT4;
|
||||
private final int selectOneIn;
|
||||
|
||||
private static List<Boolean> 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<Boolean> stencil) {
|
||||
public Stencil(List<Boolean> 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<BlockPos> 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)
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue