Fixed ScatterFeature

This commit is contained in:
Frank 2022-06-03 16:40:17 +02:00
parent 51bd560fa0
commit 0149b17a1a
6 changed files with 170 additions and 146 deletions

View file

@ -260,6 +260,10 @@ public class BCLFeatureBuilder<FC extends FeatureConfiguration, F extends Featur
return modifier(new IsBasin(BlockPredicate.anyOf(predicates)));
}
public BCLFeatureBuilder inOpenBasinOf(BlockPredicate... predicates) {
return modifier(IsBasin.openTop(BlockPredicate.anyOf(predicates)));
}
public BCLFeatureBuilder is(BlockPredicate... predicates) {
return modifier(new Is(BlockPredicate.anyOf(predicates)));
}

View file

@ -12,7 +12,6 @@ import net.minecraft.util.valueproviders.ConstantInt;
import net.minecraft.util.valueproviders.UniformInt;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.GenerationStep;
import net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate;
@ -23,6 +22,7 @@ import net.minecraft.world.level.levelgen.placement.*;
import com.mojang.serialization.Codec;
import org.betterx.bclib.api.features.config.ScatterFeatureConfig;
import org.betterx.bclib.api.tag.CommonBlockTags;
import org.betterx.bclib.util.BlocksHelper;
import java.util.ArrayList;
@ -40,21 +40,21 @@ public class ScatterFeature<FC extends ScatterFeatureConfig>
Feature<T> inlineFeature) {
List<Holder<PlacedFeature>> set = new ArrayList<>(2);
if (cfg.floorChance > 0) set.add(PlacementUtils.inlinePlaced(inlineFeature,
cfg,
EnvironmentScanPlacement.scanningFor(Direction.DOWN,
BlockPredicate.solid(),
BlockPredicate.ONLY_IN_AIR_PREDICATE,
12),
RandomOffsetPlacement.vertical(ConstantInt.of(1))));
cfg,
EnvironmentScanPlacement.scanningFor(Direction.DOWN,
BlockPredicate.matchesTag(CommonBlockTags.TERRAIN),
BlockPredicate.ONLY_IN_AIR_PREDICATE,
12),
RandomOffsetPlacement.vertical(ConstantInt.of(1))));
if (cfg.floorChance < 1) {
set.add(PlacementUtils.inlinePlaced(inlineFeature,
cfg,
EnvironmentScanPlacement.scanningFor(Direction.UP,
BlockPredicate.solid(),
BlockPredicate.ONLY_IN_AIR_PREDICATE,
12),
RandomOffsetPlacement.vertical(ConstantInt.of(-1))));
cfg,
EnvironmentScanPlacement.scanningFor(Direction.UP,
BlockPredicate.matchesTag(CommonBlockTags.TERRAIN),
BlockPredicate.ONLY_IN_AIR_PREDICATE,
12),
RandomOffsetPlacement.vertical(ConstantInt.of(-1))));
}
SimpleRandomFeatureConfiguration configuration = new SimpleRandomFeatureConfiguration(HolderSet.direct(set));
@ -112,21 +112,21 @@ public class ScatterFeature<FC extends ScatterFeatureConfig>
for (int i = 0; i < tryCount; i++) {
int x = origin.getX() + (int) (random.nextGaussian() * config.maxSpread);
int z = origin.getZ() + (int) (random.nextGaussian() * config.maxSpread);
POS.set(x, origin.getY(), z);
POS.set(x, basePos.getY(), z);
if (BlocksHelper.findSurroundingSurface(level, POS, surfaceDirection, 4, config::isValidBase)) {
int myHeight;
if (config.growWhileFree) {
myHeight = BlocksHelper.blockCount(level,
POS,
direction,
config.maxHeight,
state -> state.getMaterial().isReplaceable());
POS,
direction,
config.maxHeight,
BlocksHelper::isFree
);
} else {
myHeight = centerHeight;
}
POS.move(direction, 1);
int dx = x - POS.getX();
int dz = z - POS.getZ();
float sizeFactor = (1 - (float) (Math.sqrt(dx * dx + dz * dz) / distNormalizer));
@ -134,15 +134,19 @@ public class ScatterFeature<FC extends ScatterFeatureConfig>
myHeight = (int) Math.min(Math.max(
config.minHeight,
config.minHeight + sizeFactor * (myHeight - config.minHeight)
), config.maxHeight);
), config.maxHeight);
BlockState baseState = level.getBlockState(POS.relative(direction.getOpposite()));
if (!config.isValidBase(baseState)) {
System.out.println("Starting from " + baseState + " at " + POS.relative(direction.getOpposite()));
}
buildPillarWithBase(level,
POS,
POS.relative(direction.getOpposite()),
direction,
myHeight,
config,
random);
POS,
POS.relative(direction.getOpposite()),
direction,
myHeight,
config,
random);
}
}
}
@ -155,7 +159,7 @@ public class ScatterFeature<FC extends ScatterFeatureConfig>
int height,
ScatterFeatureConfig config,
RandomSource random) {
if (BlocksHelper.isFreeSpace(level, origin, direction, height, (state) -> state.is(Blocks.AIR))) {
if (BlocksHelper.isFreeSpace(level, origin, direction, height, BlocksHelper::isFree)) {
createPatchOfBaseBlocks(level, random, basePos, config);
buildPillar(level, origin, direction, height, config, random);
}
@ -170,6 +174,10 @@ public class ScatterFeature<FC extends ScatterFeatureConfig>
final BlockPos.MutableBlockPos POS = origin.mutable();
buildBaseToTipColumn(height, (blockState) -> {
BlockState previous = level.getBlockState(POS);
if (!BlocksHelper.isFree(previous)) {
System.out.println("Replaced " + previous + " with " + blockState + " at " + POS);
}
BlocksHelper.setWithoutUpdate(level, POS, blockState);
POS.move(direction);
}, config, random);
@ -181,16 +189,6 @@ public class ScatterFeature<FC extends ScatterFeatureConfig>
RandomSource random) {
for (int size = 0; size < totalHeight; size++) {
consumer.accept(config.createBlock(size, totalHeight - 1, random));
// Block s = config.createBlock(size, totalHeight - 1, random).getBlock();
// if (size == 0) s = Blocks.YELLOW_CONCRETE;
// else if (size == 1) s = Blocks.LIME_CONCRETE;
// else if (size == 2) s = Blocks.CYAN_CONCRETE;
// else if (size == 3) s = Blocks.LIGHT_BLUE_CONCRETE;
// else if (size == 4) s = Blocks.BLUE_CONCRETE;
// else if (size == 5) s = Blocks.PURPLE_CONCRETE;
// else if (size == 6) s = Blocks.MAGENTA_CONCRETE;
// else s = Blocks.GRAY_CONCRETE;
// consumer.accept(s.defaultBlockState());
}
}

View file

@ -81,81 +81,81 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration {
public static <T extends ScatterFeatureConfig> Codec<T> buildCodec(Instancer<T> instancer) {
return RecordCodecBuilder.create((instance) -> instance
.group(BlockState.CODEC
.fieldOf("cluster_block")
.forGetter((T cfg) -> cfg.clusterBlock),
BlockState.CODEC
.optionalFieldOf("tip_block")
.orElse(Optional.empty())
.forGetter((T cfg) -> cfg.tipBlock == cfg.clusterBlock
? Optional.empty()
: Optional.of(cfg.tipBlock)),
BlockState.CODEC
.optionalFieldOf("bottom_block")
.orElse(Optional.empty())
.forGetter((T cfg) -> cfg.bottomBlock == cfg.clusterBlock
? Optional.empty()
: Optional.of(cfg.bottomBlock)),
BlockState.CODEC
.optionalFieldOf("base_state")
.forGetter((T cfg) -> cfg.baseState),
Codec
.floatRange(0.0F, 1.0F)
.fieldOf("baseReplaceChance")
.orElse(1.0F)
.forGetter((T cfg) -> cfg.baseReplaceChance),
Codec
.floatRange(0.0F, 1.0F)
.fieldOf("chance_of_directional_spread")
.orElse(0.7F)
.forGetter((T cfg) -> cfg.chanceOfDirectionalSpread),
Codec
.floatRange(0.0F, 1.0F)
.fieldOf("chance_of_spread_radius2")
.orElse(0.5F)
.forGetter((T cfg) -> cfg.chanceOfSpreadRadius2),
Codec
.floatRange(0.0F, 1.0F)
.fieldOf("chance_of_spread_radius3")
.orElse(0.5F)
.forGetter((T cfg) -> cfg.chanceOfSpreadRadius3),
Codec
.intRange(1, 20)
.fieldOf("min_height")
.orElse(2)
.forGetter((T cfg) -> cfg.minHeight),
Codec
.intRange(1, 20)
.fieldOf("max_height")
.orElse(7)
.forGetter((T cfg) -> cfg.maxHeight),
Codec
.floatRange(0, 10)
.fieldOf("max_spread")
.orElse(2f)
.forGetter((T cfg) -> cfg.maxSpread),
Codec
.floatRange(0, 1)
.fieldOf("size_variation")
.orElse(0.7f)
.forGetter((T cfg) -> cfg.sizeVariation),
Codec
.floatRange(0, 1)
.fieldOf("floor_chance")
.orElse(0.5f)
.forGetter((T cfg) -> cfg.floorChance),
Codec
.BOOL
.fieldOf("grow_while_empty")
.orElse(false)
.forGetter((T cfg) -> cfg.growWhileFree),
IntProvider.codec(0, 64)
.fieldOf("length")
.orElse(UniformInt.of(0, 3))
.forGetter(cfg -> cfg.spreadCount)
)
.apply(instance, instancer)
);
.group(BlockState.CODEC
.fieldOf("cluster_block")
.forGetter((T cfg) -> cfg.clusterBlock),
BlockState.CODEC
.optionalFieldOf("tip_block")
.orElse(Optional.empty())
.forGetter((T cfg) -> cfg.tipBlock == cfg.clusterBlock
? Optional.empty()
: Optional.of(cfg.tipBlock)),
BlockState.CODEC
.optionalFieldOf("bottom_block")
.orElse(Optional.empty())
.forGetter((T cfg) -> cfg.bottomBlock == cfg.clusterBlock
? Optional.empty()
: Optional.of(cfg.bottomBlock)),
BlockState.CODEC
.optionalFieldOf("base_state")
.forGetter((T cfg) -> cfg.baseState),
Codec
.floatRange(0.0F, 1.0F)
.fieldOf("baseReplaceChance")
.orElse(1.0F)
.forGetter((T cfg) -> cfg.baseReplaceChance),
Codec
.floatRange(0.0F, 1.0F)
.fieldOf("chance_of_directional_spread")
.orElse(0.7F)
.forGetter((T cfg) -> cfg.chanceOfDirectionalSpread),
Codec
.floatRange(0.0F, 1.0F)
.fieldOf("chance_of_spread_radius2")
.orElse(0.5F)
.forGetter((T cfg) -> cfg.chanceOfSpreadRadius2),
Codec
.floatRange(0.0F, 1.0F)
.fieldOf("chance_of_spread_radius3")
.orElse(0.5F)
.forGetter((T cfg) -> cfg.chanceOfSpreadRadius3),
Codec
.intRange(1, 20)
.fieldOf("min_height")
.orElse(2)
.forGetter((T cfg) -> cfg.minHeight),
Codec
.intRange(1, 20)
.fieldOf("max_height")
.orElse(7)
.forGetter((T cfg) -> cfg.maxHeight),
Codec
.floatRange(0, 10)
.fieldOf("max_spread")
.orElse(2f)
.forGetter((T cfg) -> cfg.maxSpread),
Codec
.floatRange(0, 1)
.fieldOf("size_variation")
.orElse(0.7f)
.forGetter((T cfg) -> cfg.sizeVariation),
Codec
.floatRange(0, 1)
.fieldOf("floor_chance")
.orElse(0.5f)
.forGetter((T cfg) -> cfg.floorChance),
Codec
.BOOL
.fieldOf("grow_while_empty")
.orElse(false)
.forGetter((T cfg) -> cfg.growWhileFree),
IntProvider.codec(0, 64)
.fieldOf("length")
.orElse(UniformInt.of(0, 3))
.forGetter(cfg -> cfg.spreadCount)
)
.apply(instance, instancer)
);
}
public static class Builder<T extends ScatterFeatureConfig> {
@ -244,10 +244,10 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration {
float chanceOfSpreadRadius2,
float chanceOfSpreadRadius3) {
return generateBaseBlock(baseState,
1,
chanceOfDirectionalSpread,
chanceOfSpreadRadius2,
chanceOfSpreadRadius3);
1,
chanceOfDirectionalSpread,
chanceOfSpreadRadius2,
chanceOfSpreadRadius3);
}
public Builder<T> generateBaseBlock(BlockState baseState,
@ -309,7 +309,7 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration {
this.floorChance,
this.growWhileFree,
this.spreadCount
);
);
}
}
@ -332,20 +332,20 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration {
boolean growWhileFree,
IntProvider spreadCount) {
super(clusterBlock,
tipBlock,
bottomBlock,
baseState,
baseReplaceChance,
chanceOfDirectionalSpread,
chanceOfSpreadRadius2,
chanceOfSpreadRadius3,
minHeight,
maxHeight,
maxSpread,
sizeVariation,
floorChance,
growWhileFree,
spreadCount);
tipBlock,
bottomBlock,
baseState,
baseReplaceChance,
chanceOfDirectionalSpread,
chanceOfSpreadRadius2,
chanceOfSpreadRadius3,
minHeight,
maxHeight,
maxSpread,
sizeVariation,
floorChance,
growWhileFree,
spreadCount);
}

View file

@ -11,29 +11,46 @@ import net.minecraft.world.level.levelgen.placement.PlacementModifierType;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import java.util.Optional;
public class IsBasin extends PlacementFilter {
public static final Codec<IsBasin> CODEC = RecordCodecBuilder.create((instance) -> instance
.group(
BlockPredicate.CODEC
.fieldOf("predicate")
.forGetter(cfg -> cfg.predicate)
.forGetter(cfg -> cfg.predicate),
BlockPredicate.CODEC
.optionalFieldOf("top_predicate")
.orElse(Optional.empty())
.forGetter(cfg -> cfg.topPredicate)
)
.apply(instance, IsBasin::new));
private final BlockPredicate predicate;
private final Optional<BlockPredicate> topPredicate;
public IsBasin(BlockPredicate predicate) {
this(predicate, Optional.empty());
}
public IsBasin(BlockPredicate predicate, Optional<BlockPredicate> topPredicate) {
this.predicate = predicate;
this.topPredicate = topPredicate;
}
public static IsBasin simple(BlockPredicate predicate) {
return new IsBasin(predicate);
}
public static IsBasin openTop(BlockPredicate predicate) {
return new IsBasin(predicate, Optional.of(BlockPredicate.ONLY_IN_AIR_PREDICATE));
}
@Override
protected boolean shouldPlace(PlacementContext ctx, RandomSource random, BlockPos pos) {
WorldGenLevel level = ctx.getLevel();
if (topPredicate.isPresent() && !topPredicate.get().test(level, pos.above())) return false;
return predicate.test(level, pos.below())
&& predicate.test(level, pos.west())
&& predicate.test(level, pos.east())

View file

@ -53,7 +53,7 @@ public class MinEmptyFilter extends PlacementFilter {
pos.relative(direction),
direction,
distance - 1,
state -> state.getMaterial().isReplaceable()
BlocksHelper::isFree
);
}

View file

@ -251,21 +251,28 @@ public class BlocksHelper {
Direction dir,
int length,
Predicate<BlockState> surface) {
BlockState beforeState = null;
BlockState nowState;
for (int len = 0; len < length; len++) {
if (surface.test(level.getBlockState(startPos))) {
nowState = level.getBlockState(startPos);
if (surface.test(nowState)) {
if (len == 0) { //we started inside of the surface
beforeState = nowState;
for (int lenUp = 0; lenUp < length; lenUp++) {
startPos.move(dir, -1);
if (BlocksHelper.isFree(level.getBlockState(startPos))) {
startPos.move(dir, 1);
return true;
nowState = level.getBlockState(startPos);
if (BlocksHelper.isFree(nowState)) {
return surface.test(beforeState);
}
beforeState = nowState;
}
return false;
} else {
startPos.move(dir, -1);
return BlocksHelper.isFree(beforeState);
}
return true;
}
beforeState = nowState;
startPos.move(dir, 1);
}
return false;
@ -279,11 +286,10 @@ public class BlocksHelper {
Predicate<BlockState> freeSurface) {
MutableBlockPos POS = startPos.mutable();
for (int len = 0; len < length; len++) {
POS.move(dir, 1);
if (!freeSurface.test(level.getBlockState(POS))) {
return false;
}
POS.move(dir, 1);
}
return true;
}
@ -294,12 +300,11 @@ public class BlocksHelper {
int length,
Predicate<BlockState> freeSurface) {
MutableBlockPos POS = startPos.mutable();
for (int len = 1; len < length; len++) {
POS.move(dir, 1);
for (int len = 0; len < length; len++) {
if (!freeSurface.test(level.getBlockState(POS))) {
return len - 1;
return len;
}
POS.move(dir, 1);
}
return length;
}