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))); return modifier(new IsBasin(BlockPredicate.anyOf(predicates)));
} }
public BCLFeatureBuilder inOpenBasinOf(BlockPredicate... predicates) {
return modifier(IsBasin.openTop(BlockPredicate.anyOf(predicates)));
}
public BCLFeatureBuilder is(BlockPredicate... predicates) { public BCLFeatureBuilder is(BlockPredicate... predicates) {
return modifier(new Is(BlockPredicate.anyOf(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.util.valueproviders.UniformInt;
import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.WorldGenLevel; 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.block.state.BlockState;
import net.minecraft.world.level.levelgen.GenerationStep; import net.minecraft.world.level.levelgen.GenerationStep;
import net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate; 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 com.mojang.serialization.Codec;
import org.betterx.bclib.api.features.config.ScatterFeatureConfig; import org.betterx.bclib.api.features.config.ScatterFeatureConfig;
import org.betterx.bclib.api.tag.CommonBlockTags;
import org.betterx.bclib.util.BlocksHelper; import org.betterx.bclib.util.BlocksHelper;
import java.util.ArrayList; import java.util.ArrayList;
@ -40,21 +40,21 @@ public class ScatterFeature<FC extends ScatterFeatureConfig>
Feature<T> inlineFeature) { Feature<T> inlineFeature) {
List<Holder<PlacedFeature>> set = new ArrayList<>(2); List<Holder<PlacedFeature>> set = new ArrayList<>(2);
if (cfg.floorChance > 0) set.add(PlacementUtils.inlinePlaced(inlineFeature, if (cfg.floorChance > 0) set.add(PlacementUtils.inlinePlaced(inlineFeature,
cfg, cfg,
EnvironmentScanPlacement.scanningFor(Direction.DOWN, EnvironmentScanPlacement.scanningFor(Direction.DOWN,
BlockPredicate.solid(), BlockPredicate.matchesTag(CommonBlockTags.TERRAIN),
BlockPredicate.ONLY_IN_AIR_PREDICATE, BlockPredicate.ONLY_IN_AIR_PREDICATE,
12), 12),
RandomOffsetPlacement.vertical(ConstantInt.of(1)))); RandomOffsetPlacement.vertical(ConstantInt.of(1))));
if (cfg.floorChance < 1) { if (cfg.floorChance < 1) {
set.add(PlacementUtils.inlinePlaced(inlineFeature, set.add(PlacementUtils.inlinePlaced(inlineFeature,
cfg, cfg,
EnvironmentScanPlacement.scanningFor(Direction.UP, EnvironmentScanPlacement.scanningFor(Direction.UP,
BlockPredicate.solid(), BlockPredicate.matchesTag(CommonBlockTags.TERRAIN),
BlockPredicate.ONLY_IN_AIR_PREDICATE, BlockPredicate.ONLY_IN_AIR_PREDICATE,
12), 12),
RandomOffsetPlacement.vertical(ConstantInt.of(-1)))); RandomOffsetPlacement.vertical(ConstantInt.of(-1))));
} }
SimpleRandomFeatureConfiguration configuration = new SimpleRandomFeatureConfiguration(HolderSet.direct(set)); SimpleRandomFeatureConfiguration configuration = new SimpleRandomFeatureConfiguration(HolderSet.direct(set));
@ -112,21 +112,21 @@ public class ScatterFeature<FC extends ScatterFeatureConfig>
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, basePos.getY(), z);
if (BlocksHelper.findSurroundingSurface(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,
POS, POS,
direction, direction,
config.maxHeight, config.maxHeight,
state -> state.getMaterial().isReplaceable()); BlocksHelper::isFree
);
} else { } else {
myHeight = centerHeight; myHeight = centerHeight;
} }
POS.move(direction, 1);
int dx = x - POS.getX(); int dx = x - POS.getX();
int dz = z - POS.getZ(); int dz = z - POS.getZ();
float sizeFactor = (1 - (float) (Math.sqrt(dx * dx + dz * dz) / distNormalizer)); 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( myHeight = (int) Math.min(Math.max(
config.minHeight, config.minHeight,
config.minHeight + sizeFactor * (myHeight - 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, buildPillarWithBase(level,
POS, POS,
POS.relative(direction.getOpposite()), POS.relative(direction.getOpposite()),
direction, direction,
myHeight, myHeight,
config, config,
random); random);
} }
} }
} }
@ -155,7 +159,7 @@ public class ScatterFeature<FC extends ScatterFeatureConfig>
int height, int height,
ScatterFeatureConfig config, ScatterFeatureConfig config,
RandomSource random) { 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); createPatchOfBaseBlocks(level, random, basePos, config);
buildPillar(level, origin, direction, height, config, random); buildPillar(level, origin, direction, height, config, random);
} }
@ -170,6 +174,10 @@ public class ScatterFeature<FC extends ScatterFeatureConfig>
final BlockPos.MutableBlockPos POS = origin.mutable(); final BlockPos.MutableBlockPos POS = origin.mutable();
buildBaseToTipColumn(height, (blockState) -> { 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); BlocksHelper.setWithoutUpdate(level, POS, blockState);
POS.move(direction); POS.move(direction);
}, config, random); }, config, random);
@ -181,16 +189,6 @@ public class ScatterFeature<FC extends ScatterFeatureConfig>
RandomSource random) { RandomSource random) {
for (int size = 0; size < totalHeight; size++) { for (int size = 0; size < totalHeight; size++) {
consumer.accept(config.createBlock(size, totalHeight - 1, random)); 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) { public static <T extends ScatterFeatureConfig> Codec<T> buildCodec(Instancer<T> instancer) {
return RecordCodecBuilder.create((instance) -> instance return RecordCodecBuilder.create((instance) -> instance
.group(BlockState.CODEC .group(BlockState.CODEC
.fieldOf("cluster_block") .fieldOf("cluster_block")
.forGetter((T cfg) -> cfg.clusterBlock), .forGetter((T cfg) -> cfg.clusterBlock),
BlockState.CODEC BlockState.CODEC
.optionalFieldOf("tip_block") .optionalFieldOf("tip_block")
.orElse(Optional.empty()) .orElse(Optional.empty())
.forGetter((T cfg) -> cfg.tipBlock == cfg.clusterBlock .forGetter((T cfg) -> cfg.tipBlock == cfg.clusterBlock
? Optional.empty() ? Optional.empty()
: Optional.of(cfg.tipBlock)), : Optional.of(cfg.tipBlock)),
BlockState.CODEC BlockState.CODEC
.optionalFieldOf("bottom_block") .optionalFieldOf("bottom_block")
.orElse(Optional.empty()) .orElse(Optional.empty())
.forGetter((T cfg) -> cfg.bottomBlock == cfg.clusterBlock .forGetter((T cfg) -> cfg.bottomBlock == cfg.clusterBlock
? Optional.empty() ? Optional.empty()
: Optional.of(cfg.bottomBlock)), : Optional.of(cfg.bottomBlock)),
BlockState.CODEC BlockState.CODEC
.optionalFieldOf("base_state") .optionalFieldOf("base_state")
.forGetter((T cfg) -> cfg.baseState), .forGetter((T cfg) -> cfg.baseState),
Codec Codec
.floatRange(0.0F, 1.0F) .floatRange(0.0F, 1.0F)
.fieldOf("baseReplaceChance") .fieldOf("baseReplaceChance")
.orElse(1.0F) .orElse(1.0F)
.forGetter((T cfg) -> cfg.baseReplaceChance), .forGetter((T cfg) -> cfg.baseReplaceChance),
Codec Codec
.floatRange(0.0F, 1.0F) .floatRange(0.0F, 1.0F)
.fieldOf("chance_of_directional_spread") .fieldOf("chance_of_directional_spread")
.orElse(0.7F) .orElse(0.7F)
.forGetter((T cfg) -> cfg.chanceOfDirectionalSpread), .forGetter((T cfg) -> cfg.chanceOfDirectionalSpread),
Codec Codec
.floatRange(0.0F, 1.0F) .floatRange(0.0F, 1.0F)
.fieldOf("chance_of_spread_radius2") .fieldOf("chance_of_spread_radius2")
.orElse(0.5F) .orElse(0.5F)
.forGetter((T cfg) -> cfg.chanceOfSpreadRadius2), .forGetter((T cfg) -> cfg.chanceOfSpreadRadius2),
Codec Codec
.floatRange(0.0F, 1.0F) .floatRange(0.0F, 1.0F)
.fieldOf("chance_of_spread_radius3") .fieldOf("chance_of_spread_radius3")
.orElse(0.5F) .orElse(0.5F)
.forGetter((T cfg) -> cfg.chanceOfSpreadRadius3), .forGetter((T cfg) -> cfg.chanceOfSpreadRadius3),
Codec Codec
.intRange(1, 20) .intRange(1, 20)
.fieldOf("min_height") .fieldOf("min_height")
.orElse(2) .orElse(2)
.forGetter((T cfg) -> cfg.minHeight), .forGetter((T cfg) -> cfg.minHeight),
Codec Codec
.intRange(1, 20) .intRange(1, 20)
.fieldOf("max_height") .fieldOf("max_height")
.orElse(7) .orElse(7)
.forGetter((T cfg) -> cfg.maxHeight), .forGetter((T cfg) -> cfg.maxHeight),
Codec Codec
.floatRange(0, 10) .floatRange(0, 10)
.fieldOf("max_spread") .fieldOf("max_spread")
.orElse(2f) .orElse(2f)
.forGetter((T cfg) -> cfg.maxSpread), .forGetter((T cfg) -> cfg.maxSpread),
Codec Codec
.floatRange(0, 1) .floatRange(0, 1)
.fieldOf("size_variation") .fieldOf("size_variation")
.orElse(0.7f) .orElse(0.7f)
.forGetter((T cfg) -> cfg.sizeVariation), .forGetter((T cfg) -> cfg.sizeVariation),
Codec Codec
.floatRange(0, 1) .floatRange(0, 1)
.fieldOf("floor_chance") .fieldOf("floor_chance")
.orElse(0.5f) .orElse(0.5f)
.forGetter((T cfg) -> cfg.floorChance), .forGetter((T cfg) -> cfg.floorChance),
Codec Codec
.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) IntProvider.codec(0, 64)
.fieldOf("length") .fieldOf("length")
.orElse(UniformInt.of(0, 3)) .orElse(UniformInt.of(0, 3))
.forGetter(cfg -> cfg.spreadCount) .forGetter(cfg -> cfg.spreadCount)
) )
.apply(instance, instancer) .apply(instance, instancer)
); );
} }
public static class Builder<T extends ScatterFeatureConfig> { public static class Builder<T extends ScatterFeatureConfig> {
@ -244,10 +244,10 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration {
float chanceOfSpreadRadius2, float chanceOfSpreadRadius2,
float chanceOfSpreadRadius3) { float chanceOfSpreadRadius3) {
return generateBaseBlock(baseState, return generateBaseBlock(baseState,
1, 1,
chanceOfDirectionalSpread, chanceOfDirectionalSpread,
chanceOfSpreadRadius2, chanceOfSpreadRadius2,
chanceOfSpreadRadius3); chanceOfSpreadRadius3);
} }
public Builder<T> generateBaseBlock(BlockState baseState, public Builder<T> generateBaseBlock(BlockState baseState,
@ -309,7 +309,7 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration {
this.floorChance, this.floorChance,
this.growWhileFree, this.growWhileFree,
this.spreadCount this.spreadCount
); );
} }
} }
@ -332,20 +332,20 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration {
boolean growWhileFree, boolean growWhileFree,
IntProvider spreadCount) { IntProvider spreadCount) {
super(clusterBlock, super(clusterBlock,
tipBlock, tipBlock,
bottomBlock, bottomBlock,
baseState, baseState,
baseReplaceChance, baseReplaceChance,
chanceOfDirectionalSpread, chanceOfDirectionalSpread,
chanceOfSpreadRadius2, chanceOfSpreadRadius2,
chanceOfSpreadRadius3, chanceOfSpreadRadius3,
minHeight, minHeight,
maxHeight, maxHeight,
maxSpread, maxSpread,
sizeVariation, sizeVariation,
floorChance, floorChance,
growWhileFree, growWhileFree,
spreadCount); spreadCount);
} }

View file

@ -11,29 +11,46 @@ 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.Optional;
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(
BlockPredicate.CODEC BlockPredicate.CODEC
.fieldOf("predicate") .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)); .apply(instance, IsBasin::new));
private final BlockPredicate predicate; private final BlockPredicate predicate;
private final Optional<BlockPredicate> topPredicate;
public IsBasin(BlockPredicate predicate) { public IsBasin(BlockPredicate predicate) {
this(predicate, Optional.empty());
}
public IsBasin(BlockPredicate predicate, Optional<BlockPredicate> topPredicate) {
this.predicate = predicate; this.predicate = predicate;
this.topPredicate = topPredicate;
} }
public static IsBasin simple(BlockPredicate predicate) { public static IsBasin simple(BlockPredicate predicate) {
return new IsBasin(predicate); return new IsBasin(predicate);
} }
public static IsBasin openTop(BlockPredicate predicate) {
return new IsBasin(predicate, Optional.of(BlockPredicate.ONLY_IN_AIR_PREDICATE));
}
@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 (topPredicate.isPresent() && !topPredicate.get().test(level, pos.above())) return false;
return predicate.test(level, pos.below()) return predicate.test(level, pos.below())
&& predicate.test(level, pos.west()) && predicate.test(level, pos.west())
&& predicate.test(level, pos.east()) && predicate.test(level, pos.east())

View file

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

View file

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