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;
|
package org.betterx.bclib.api.features;
|
||||||
|
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.core.Vec3i;
|
||||||
import net.minecraft.data.worldgen.placement.PlacementUtils;
|
import net.minecraft.data.worldgen.placement.PlacementUtils;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.util.valueproviders.IntProvider;
|
||||||
import net.minecraft.util.valueproviders.UniformInt;
|
import net.minecraft.util.valueproviders.UniformInt;
|
||||||
import net.minecraft.world.level.levelgen.GenerationStep.Decoration;
|
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.Feature;
|
||||||
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
|
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
|
||||||
import net.minecraft.world.level.levelgen.placement.*;
|
import net.minecraft.world.level.levelgen.placement.*;
|
||||||
import net.minecraft.world.level.material.Material;
|
import net.minecraft.world.level.material.Material;
|
||||||
|
|
||||||
import org.betterx.bclib.world.features.BCLFeature;
|
import org.betterx.bclib.world.features.BCLFeature;
|
||||||
import org.betterx.bclib.world.features.placement.FindSolidInDirection;
|
import org.betterx.bclib.world.features.placement.*;
|
||||||
import org.betterx.bclib.world.features.placement.IsEmptyAboveSampledFilter;
|
|
||||||
import org.betterx.bclib.world.features.placement.MinEmptyFilter;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -137,6 +138,14 @@ public class BCLFeatureBuilder<FC extends FeatureConfiguration, F extends Featur
|
||||||
return modifier(InSquarePlacement.spread());
|
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
|
* 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());
|
return modifier(IsEmptyAboveSampledFilter.emptyAbove4());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BCLFeatureBuilder isEmptyAbove() {
|
||||||
|
return modifier(IsEmptyAboveSampledFilter.emptyAbove());
|
||||||
|
}
|
||||||
|
|
||||||
public BCLFeatureBuilder isEmptyAbove(int d1, int d2) {
|
public BCLFeatureBuilder isEmptyAbove(int d1, int d2) {
|
||||||
return modifier(new IsEmptyAboveSampledFilter(d1, 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.
|
* 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));
|
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) {
|
public BCLFeatureBuilder findSolidCeil(int distance) {
|
||||||
return modifier(FindSolidInDirection.up(distance));
|
return modifier(FindSolidInDirection.up(distance));
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,8 @@ public class CommonBlockTags {
|
||||||
TagAPI.BLOCKS.add(SOUL_GROUND, Blocks.SOUL_SAND, Blocks.SOUL_SOIL);
|
TagAPI.BLOCKS.add(SOUL_GROUND, Blocks.SOUL_SAND, Blocks.SOUL_SOIL);
|
||||||
|
|
||||||
TagAPI.BLOCKS.add(IS_OBSIDIAN, Blocks.OBSIDIAN, Blocks.CRYING_OBSIDIAN);
|
TagAPI.BLOCKS.add(IS_OBSIDIAN, Blocks.OBSIDIAN, Blocks.CRYING_OBSIDIAN);
|
||||||
|
TagAPI.BLOCKS.add(TERRAIN, Blocks.MAGMA_BLOCK);
|
||||||
|
|
||||||
TagAPI.BLOCKS.addOtherTags(TERRAIN,
|
TagAPI.BLOCKS.addOtherTags(TERRAIN,
|
||||||
BlockTags.DRIPSTONE_REPLACEABLE,
|
BlockTags.DRIPSTONE_REPLACEABLE,
|
||||||
BlockTags.BASE_STONE_OVERWORLD,
|
BlockTags.BASE_STONE_OVERWORLD,
|
||||||
|
|
|
@ -28,11 +28,11 @@ public abstract class BiomeSourceMixin implements BiomeSourceAccessor {
|
||||||
|
|
||||||
@Inject(method = "<init>(Ljava/util/List;)V", at = @At("TAIL"))
|
@Inject(method = "<init>(Ljava/util/List;)V", at = @At("TAIL"))
|
||||||
public void bcl_init(List list, CallbackInfo ci) {
|
public void bcl_init(List list, CallbackInfo ci) {
|
||||||
System.out.println("new BiomeSource (" + Integer.toHexString(hashCode()) + ", biomes=" + possibleBiomes().size() + ")");
|
// System.out.println("new BiomeSource (" + Integer.toHexString(hashCode()) + ", biomes=" + possibleBiomes().size() + ")");
|
||||||
if (possibleBiomes().size() == 27) {
|
// if (possibleBiomes().size() == 27) {
|
||||||
System.out.println("Nether????");
|
// System.out.println("Nether????");
|
||||||
} else if (possibleBiomes().size() == 2) {
|
// } else if (possibleBiomes().size() == 2) {
|
||||||
System.out.println("Datapack Nether???");
|
// System.out.println("Datapack Nether???");
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -229,13 +229,39 @@ public class BlocksHelper {
|
||||||
return false;
|
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,
|
public static boolean isFreeSpace(LevelAccessor level,
|
||||||
BlockPos startPos,
|
BlockPos startPos,
|
||||||
Direction dir,
|
Direction dir,
|
||||||
int length,
|
int length,
|
||||||
Predicate<BlockState> freeSurface) {
|
Predicate<BlockState> freeSurface) {
|
||||||
MutableBlockPos POS = startPos.mutable();
|
MutableBlockPos POS = startPos.mutable();
|
||||||
for (int len = 1; len < length; len++) {
|
for (int len = 0; len < length; len++) {
|
||||||
POS.move(dir, 1);
|
POS.move(dir, 1);
|
||||||
if (!freeSurface.test(level.getBlockState(POS))) {
|
if (!freeSurface.test(level.getBlockState(POS))) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -110,13 +110,13 @@ public class ScatterFeature<FC extends ScatterFeatureConfig>
|
||||||
|
|
||||||
|
|
||||||
final double distNormalizer = (config.maxSpread * Math.sqrt(2));
|
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++) {
|
for (int i = 0; i < tryCount; i++) {
|
||||||
int x = origin.getX() + (int) (random.nextGaussian() * config.maxSpread);
|
int x = origin.getX() + (int) (random.nextGaussian() * config.maxSpread);
|
||||||
int z = origin.getZ() + (int) (random.nextGaussian() * config.maxSpread);
|
int z = origin.getZ() + (int) (random.nextGaussian() * config.maxSpread);
|
||||||
POS.set(x, origin.getY(), z);
|
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;
|
int myHeight;
|
||||||
if (config.growWhileFree) {
|
if (config.growWhileFree) {
|
||||||
myHeight = BlocksHelper.blockCount(level,
|
myHeight = BlocksHelper.blockCount(level,
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
package org.betterx.bclib.world.features;
|
package org.betterx.bclib.world.features;
|
||||||
|
|
||||||
import net.minecraft.util.RandomSource;
|
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.Block;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
|
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.Codec;
|
||||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
import org.betterx.bclib.BCLib;
|
import org.betterx.bclib.BCLib;
|
||||||
|
@ -14,7 +17,7 @@ import org.betterx.bclib.api.tag.CommonBlockTags;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public abstract class ScatterFeatureConfig implements FeatureConfiguration {
|
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;
|
public final BlockState clusterBlock;
|
||||||
|
@ -31,6 +34,8 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration {
|
||||||
public final float sizeVariation;
|
public final float sizeVariation;
|
||||||
public final float floorChance;
|
public final float floorChance;
|
||||||
|
|
||||||
|
public final IntProvider spreadCount;
|
||||||
|
|
||||||
public final boolean growWhileFree;
|
public final boolean growWhileFree;
|
||||||
|
|
||||||
public ScatterFeatureConfig(BlockState clusterBlock,
|
public ScatterFeatureConfig(BlockState clusterBlock,
|
||||||
|
@ -46,7 +51,8 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration {
|
||||||
float maxSpread,
|
float maxSpread,
|
||||||
float sizeVariation,
|
float sizeVariation,
|
||||||
float floorChance,
|
float floorChance,
|
||||||
boolean growWhileFree) {
|
boolean growWhileFree,
|
||||||
|
IntProvider spreadCount) {
|
||||||
this.clusterBlock = clusterBlock;
|
this.clusterBlock = clusterBlock;
|
||||||
this.tipBlock = tipBlock == null ? clusterBlock : tipBlock;
|
this.tipBlock = tipBlock == null ? clusterBlock : tipBlock;
|
||||||
this.bottomBlock = bottomBlock == null ? clusterBlock : bottomBlock;
|
this.bottomBlock = bottomBlock == null ? clusterBlock : bottomBlock;
|
||||||
|
@ -61,6 +67,7 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration {
|
||||||
this.sizeVariation = sizeVariation;
|
this.sizeVariation = sizeVariation;
|
||||||
this.floorChance = floorChance;
|
this.floorChance = floorChance;
|
||||||
this.growWhileFree = growWhileFree;
|
this.growWhileFree = growWhileFree;
|
||||||
|
this.spreadCount = spreadCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -137,7 +144,11 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration {
|
||||||
.BOOL
|
.BOOL
|
||||||
.fieldOf("grow_while_empty")
|
.fieldOf("grow_while_empty")
|
||||||
.orElse(false)
|
.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)
|
.apply(instance, instancer)
|
||||||
);
|
);
|
||||||
|
@ -158,6 +169,7 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration {
|
||||||
private float sizeVariation = 0;
|
private float sizeVariation = 0;
|
||||||
private float floorChance = 0.5f;
|
private float floorChance = 0.5f;
|
||||||
private boolean growWhileFree = false;
|
private boolean growWhileFree = false;
|
||||||
|
public IntProvider spreadCount = ConstantInt.of(0);
|
||||||
private final Instancer<T> instancer;
|
private final Instancer<T> instancer;
|
||||||
|
|
||||||
public Builder(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) {
|
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.maxSpread = maxSpread;
|
||||||
this.sizeVariation = sizeVariation;
|
this.sizeVariation = sizeVariation;
|
||||||
return this;
|
return this;
|
||||||
|
@ -286,7 +303,8 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration {
|
||||||
this.maxSpread,
|
this.maxSpread,
|
||||||
this.sizeVariation,
|
this.sizeVariation,
|
||||||
this.floorChance,
|
this.floorChance,
|
||||||
this.growWhileFree
|
this.growWhileFree,
|
||||||
|
this.spreadCount
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -307,7 +325,8 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration {
|
||||||
float maxSpread,
|
float maxSpread,
|
||||||
float sizeVariation,
|
float sizeVariation,
|
||||||
float floorChance,
|
float floorChance,
|
||||||
boolean growWhileFree) {
|
boolean growWhileFree,
|
||||||
|
IntProvider spreadCount) {
|
||||||
super(clusterBlock,
|
super(clusterBlock,
|
||||||
tipBlock,
|
tipBlock,
|
||||||
bottomBlock,
|
bottomBlock,
|
||||||
|
@ -321,9 +340,11 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration {
|
||||||
maxSpread,
|
maxSpread,
|
||||||
sizeVariation,
|
sizeVariation,
|
||||||
floorChance,
|
floorChance,
|
||||||
growWhileFree);
|
growWhileFree,
|
||||||
|
spreadCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static Builder<OnSolid> startOnSolid() {
|
public static Builder<OnSolid> startOnSolid() {
|
||||||
return Builder.start(OnSolid::new);
|
return Builder.start(OnSolid::new);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package org.betterx.bclib.world.features;
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
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.Feature;
|
||||||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
||||||
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
|
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
|
||||||
|
@ -37,14 +36,6 @@ public abstract class SurfaceFeature<T extends FeatureConfiguration> extends Fea
|
||||||
minHeight(ctx),
|
minHeight(ctx),
|
||||||
this::isValidSurface);
|
this::isValidSurface);
|
||||||
if (pos.isPresent()) {
|
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);
|
generate(pos.get(), ctx);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,6 @@ import net.minecraft.world.level.levelgen.placement.PlacementModifierType;
|
||||||
import com.mojang.serialization.Codec;
|
import com.mojang.serialization.Codec;
|
||||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class Extend extends PlacementModifier {
|
public class Extend extends PlacementModifier {
|
||||||
|
@ -42,12 +40,13 @@ public class Extend extends PlacementModifier {
|
||||||
public Stream<BlockPos> getPositions(PlacementContext placementContext,
|
public Stream<BlockPos> getPositions(PlacementContext placementContext,
|
||||||
RandomSource random,
|
RandomSource random,
|
||||||
BlockPos blockPos) {
|
BlockPos blockPos) {
|
||||||
|
var builder = Stream.<BlockPos>builder();
|
||||||
final int count = length.sample(random);
|
final int count = length.sample(random);
|
||||||
List<BlockPos> pos = new ArrayList<>(count);
|
builder.add(blockPos);
|
||||||
for (int y = 0; y < count; y++) {
|
for (int y = 1; y < count + 1; y++) {
|
||||||
pos.add(blockPos.relative(direction, y + 1));
|
builder.add(blockPos.relative(direction, y));
|
||||||
}
|
}
|
||||||
return pos.stream();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -16,8 +16,8 @@ import java.util.stream.Stream;
|
||||||
|
|
||||||
public class FindSolidInDirection extends PlacementModifier {
|
public class FindSolidInDirection extends PlacementModifier {
|
||||||
|
|
||||||
protected static final FindSolidInDirection DOWN = new FindSolidInDirection(Direction.DOWN, 12);
|
protected static final FindSolidInDirection DOWN = new FindSolidInDirection(Direction.DOWN, 6);
|
||||||
protected static final FindSolidInDirection UP = new FindSolidInDirection(Direction.UP, 12);
|
protected static final FindSolidInDirection UP = new FindSolidInDirection(Direction.UP, 6);
|
||||||
public static final Codec<FindSolidInDirection> CODEC = RecordCodecBuilder.create((instance) -> instance
|
public static final Codec<FindSolidInDirection> CODEC = RecordCodecBuilder.create((instance) -> instance
|
||||||
.group(
|
.group(
|
||||||
Direction.CODEC.fieldOf("dir").orElse(Direction.DOWN).forGetter((p) -> p.direction),
|
Direction.CODEC.fieldOf("dir").orElse(Direction.DOWN).forGetter((p) -> p.direction),
|
||||||
|
@ -54,7 +54,7 @@ public class FindSolidInDirection extends PlacementModifier {
|
||||||
RandomSource randomSource,
|
RandomSource randomSource,
|
||||||
BlockPos blockPos) {
|
BlockPos blockPos) {
|
||||||
BlockPos.MutableBlockPos POS = blockPos.mutable();
|
BlockPos.MutableBlockPos POS = blockPos.mutable();
|
||||||
if (BlocksHelper.findSurface(placementContext.getLevel(),
|
if (BlocksHelper.findSurroundingSurface(placementContext.getLevel(),
|
||||||
POS,
|
POS,
|
||||||
direction,
|
direction,
|
||||||
maxSearchDistance,
|
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;
|
package org.betterx.bclib.world.features.placement;
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.util.ExtraCodecs;
|
|
||||||
import net.minecraft.util.RandomSource;
|
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.PlacementContext;
|
||||||
import net.minecraft.world.level.levelgen.placement.PlacementFilter;
|
import net.minecraft.world.level.levelgen.placement.PlacementFilter;
|
||||||
import net.minecraft.world.level.levelgen.placement.PlacementModifierType;
|
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.Codec;
|
||||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class IsBasin extends PlacementFilter {
|
public class IsBasin extends PlacementFilter {
|
||||||
public static final Codec<IsBasin> CODEC = RecordCodecBuilder.create((instance) -> instance
|
public static final Codec<IsBasin> CODEC = RecordCodecBuilder.create((instance) -> instance
|
||||||
.group(
|
.group(
|
||||||
ExtraCodecs.nonEmptyList(BlockState.CODEC.listOf())
|
BlockPredicate.CODEC
|
||||||
.fieldOf("blocks")
|
.fieldOf("predicate")
|
||||||
.forGetter(cfg -> cfg.blocks)
|
.forGetter(cfg -> cfg.predicate)
|
||||||
)
|
)
|
||||||
.apply(instance, IsBasin::new));
|
.apply(instance, IsBasin::new));
|
||||||
|
|
||||||
private final List<BlockState> blocks;
|
private final BlockPredicate predicate;
|
||||||
|
|
||||||
public IsBasin(List<BlockState> blocks) {
|
public IsBasin(BlockPredicate predicate) {
|
||||||
this.blocks = blocks;
|
this.predicate = predicate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IsBasin simple(BlockPredicate predicate) {
|
||||||
|
|
||||||
|
return new IsBasin(predicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean shouldPlace(PlacementContext ctx, RandomSource random, BlockPos pos) {
|
protected boolean shouldPlace(PlacementContext ctx, RandomSource random, BlockPos pos) {
|
||||||
BlockState bs = ctx.getLevel().getBlockState(pos);
|
WorldGenLevel level = ctx.getLevel();
|
||||||
return blocks.stream().map(b -> b.getBlock()).anyMatch(b -> bs.is(b));
|
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
|
@Override
|
||||||
|
|
|
@ -15,6 +15,7 @@ import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
*/
|
*/
|
||||||
public class IsEmptyAboveSampledFilter extends PlacementFilter {
|
public class IsEmptyAboveSampledFilter extends PlacementFilter {
|
||||||
private static final IsEmptyAboveSampledFilter DEFAULT = new IsEmptyAboveSampledFilter(4, 2);
|
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
|
public static final Codec<IsEmptyAboveSampledFilter> CODEC = RecordCodecBuilder.create((instance) -> instance
|
||||||
.group(
|
.group(
|
||||||
Codec.intRange(1, 32).fieldOf("d1").orElse(2).forGetter((p) -> p.distance1),
|
Codec.intRange(1, 32).fieldOf("d1").orElse(2).forGetter((p) -> p.distance1),
|
||||||
|
@ -26,6 +27,10 @@ public class IsEmptyAboveSampledFilter extends PlacementFilter {
|
||||||
return DEFAULT;
|
return DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static PlacementFilter emptyAbove() {
|
||||||
|
return DEFAULT1;
|
||||||
|
}
|
||||||
|
|
||||||
public IsEmptyAboveSampledFilter(int d1, int d2) {
|
public IsEmptyAboveSampledFilter(int d1, int d2) {
|
||||||
this.distance1 = d1;
|
this.distance1 = d1;
|
||||||
this.distance2 = d2;
|
this.distance2 = d2;
|
||||||
|
@ -38,7 +43,8 @@ public class IsEmptyAboveSampledFilter extends PlacementFilter {
|
||||||
@Override
|
@Override
|
||||||
protected boolean shouldPlace(PlacementContext ctx, RandomSource random, BlockPos pos) {
|
protected boolean shouldPlace(PlacementContext ctx, RandomSource random, BlockPos pos) {
|
||||||
WorldGenLevel level = ctx.getLevel();
|
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 true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1,18 +1,22 @@
|
||||||
package org.betterx.bclib.world.features.placement;
|
package org.betterx.bclib.world.features.placement;
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.core.Vec3i;
|
import net.minecraft.core.Vec3i;
|
||||||
import net.minecraft.util.RandomSource;
|
import net.minecraft.util.RandomSource;
|
||||||
import net.minecraft.world.level.levelgen.placement.PlacementContext;
|
import net.minecraft.world.level.levelgen.placement.PlacementContext;
|
||||||
import net.minecraft.world.level.levelgen.placement.PlacementModifier;
|
import net.minecraft.world.level.levelgen.placement.PlacementModifier;
|
||||||
import net.minecraft.world.level.levelgen.placement.PlacementModifierType;
|
import net.minecraft.world.level.levelgen.placement.PlacementModifierType;
|
||||||
|
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
import com.mojang.serialization.Codec;
|
import com.mojang.serialization.Codec;
|
||||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class Offset extends PlacementModifier {
|
public class Offset extends PlacementModifier {
|
||||||
|
private static Map<Direction, Offset> DIRECTIONS = Maps.newHashMap();
|
||||||
public static final Codec<Offset> CODEC = RecordCodecBuilder.create((instance) -> instance
|
public static final Codec<Offset> CODEC = RecordCodecBuilder.create((instance) -> instance
|
||||||
.group(
|
.group(
|
||||||
Vec3i.CODEC
|
Vec3i.CODEC
|
||||||
|
@ -27,6 +31,10 @@ public class Offset extends PlacementModifier {
|
||||||
this.offset = offset;
|
this.offset = offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Offset inDirection(Direction dir) {
|
||||||
|
return DIRECTIONS.get(dir);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<BlockPos> getPositions(PlacementContext placementContext,
|
public Stream<BlockPos> getPositions(PlacementContext placementContext,
|
||||||
RandomSource randomSource,
|
RandomSource randomSource,
|
||||||
|
@ -38,4 +46,9 @@ public class Offset extends PlacementModifier {
|
||||||
public PlacementModifierType<?> type() {
|
public PlacementModifierType<?> type() {
|
||||||
return PlacementModifiers.OFFSET;
|
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",
|
"is_basin",
|
||||||
IsBasin.CODEC);
|
IsBasin.CODEC);
|
||||||
|
|
||||||
|
public static final PlacementModifierType<Is> IS = register(
|
||||||
|
"is",
|
||||||
|
Is.CODEC);
|
||||||
|
|
||||||
public static final PlacementModifierType<Offset> OFFSET = register(
|
public static final PlacementModifierType<Offset> OFFSET = register(
|
||||||
"offset",
|
"offset",
|
||||||
Offset.CODEC);
|
Offset.CODEC);
|
||||||
|
@ -37,6 +41,10 @@ public class PlacementModifiers {
|
||||||
"extend",
|
"extend",
|
||||||
Extend.CODEC);
|
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) {
|
private static <P extends PlacementModifier> PlacementModifierType<P> register(String path, Codec<P> codec) {
|
||||||
return register(BCLib.makeID(path), codec);
|
return register(BCLib.makeID(path), codec);
|
||||||
|
|
|
@ -20,23 +20,29 @@ public class Stencil extends PlacementModifier {
|
||||||
private static final Boolean[] BN_STENCIL;
|
private static final Boolean[] BN_STENCIL;
|
||||||
private final List<Boolean> stencil;
|
private final List<Boolean> stencil;
|
||||||
private static final Stencil DEFAULT;
|
private static final Stencil DEFAULT;
|
||||||
|
private static final Stencil DEFAULT4;
|
||||||
|
private final int selectOneIn;
|
||||||
|
|
||||||
private static List<Boolean> convert(Boolean[] s) {
|
private static List<Boolean> convert(Boolean[] s) {
|
||||||
return Arrays.stream(s).toList();
|
return Arrays.stream(s).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Stencil(Boolean[] stencil) {
|
public Stencil(Boolean[] stencil, int selectOneIn) {
|
||||||
this(convert(stencil));
|
this(convert(stencil), selectOneIn);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Stencil(List<Boolean> stencil) {
|
public Stencil(List<Boolean> stencil, int selectOneIn) {
|
||||||
this.stencil = stencil;
|
this.stencil = stencil;
|
||||||
|
this.selectOneIn = selectOneIn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Stencil basic() {
|
public static Stencil all() {
|
||||||
return DEFAULT;
|
return DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Stencil oneIn4() {
|
||||||
|
return DEFAULT4;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<BlockPos> getPositions(PlacementContext placementContext,
|
public Stream<BlockPos> getPositions(PlacementContext placementContext,
|
||||||
|
@ -319,13 +325,18 @@ public class Stencil extends PlacementModifier {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFAULT = new Stencil(BN_STENCIL);
|
DEFAULT = new Stencil(BN_STENCIL, 1);
|
||||||
|
DEFAULT4 = new Stencil(BN_STENCIL, 4);
|
||||||
CODEC = RecordCodecBuilder.create((instance) -> instance
|
CODEC = RecordCodecBuilder.create((instance) -> instance
|
||||||
.group(
|
.group(
|
||||||
ExtraCodecs.nonEmptyList(Codec.BOOL.listOf())
|
ExtraCodecs.nonEmptyList(Codec.BOOL.listOf())
|
||||||
.fieldOf("structures")
|
.fieldOf("structures")
|
||||||
.orElse(convert(BN_STENCIL))
|
.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)
|
.apply(instance, Stencil::new)
|
||||||
);
|
);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue