More Feature Updates

This commit is contained in:
Frank 2022-06-03 12:37:34 +02:00
parent f82d8b6178
commit e7486c8aa4
7 changed files with 150 additions and 198 deletions

View file

@ -15,7 +15,6 @@ import net.minecraft.world.level.levelgen.placement.PlacedFeature;
import net.minecraft.world.level.levelgen.placement.PlacementModifier; import net.minecraft.world.level.levelgen.placement.PlacementModifier;
import org.betterx.bclib.BCLib; import org.betterx.bclib.BCLib;
import org.betterx.bclib.api.features.config.BlockPlaceFeatureConfig;
import org.betterx.bclib.api.features.config.ScatterFeatureConfig; import org.betterx.bclib.api.features.config.ScatterFeatureConfig;
import java.util.Map.Entry; import java.util.Map.Entry;
@ -25,11 +24,7 @@ public class BCLFeature {
public static final Feature<ScatterFeatureConfig.OnSolid> SCATTER_ON_SOLID = register( public static final Feature<ScatterFeatureConfig.OnSolid> SCATTER_ON_SOLID = register(
BCLib.makeID("scatter_on_solid"), BCLib.makeID("scatter_on_solid"),
new ScatterFeature<>(ScatterFeatureConfig.OnSolid.CODEC) new ScatterFeature<>(ScatterFeatureConfig.OnSolid.CODEC)
); );
public static final Feature<BlockPlaceFeatureConfig> PLACE_BLOCK = register(
BCLib.makeID("place_block"),
new BlockPlaceFeature<>(BlockPlaceFeatureConfig.CODEC)
);
private final Holder<PlacedFeature> placedFeature; private final Holder<PlacedFeature> placedFeature;
private final Decoration featureStep; private final Decoration featureStep;
private final Feature<?> feature; private final Feature<?> feature;
@ -67,12 +62,12 @@ public class BCLFeature {
Holder<ConfiguredFeature<?, ?>> configuredFeature; Holder<ConfiguredFeature<?, ?>> configuredFeature;
if (!BuiltinRegistries.CONFIGURED_FEATURE.containsKey(id)) { if (!BuiltinRegistries.CONFIGURED_FEATURE.containsKey(id)) {
configuredFeature = (Holder<ConfiguredFeature<?, ?>>) (Object) FeatureUtils.register(id.toString(), configuredFeature = (Holder<ConfiguredFeature<?, ?>>) (Object) FeatureUtils.register(id.toString(),
feature, feature,
configuration); configuration);
} else { } else {
configuredFeature = BuiltinRegistries.CONFIGURED_FEATURE configuredFeature = BuiltinRegistries.CONFIGURED_FEATURE
.getHolder(ResourceKey.create(BuiltinRegistries.CONFIGURED_FEATURE.key(), .getHolder(ResourceKey.create(BuiltinRegistries.CONFIGURED_FEATURE.key(),
id)) id))
.orElseThrow(); .orElseThrow();
} }
@ -80,7 +75,7 @@ public class BCLFeature {
return PlacementUtils.register(id.toString(), configuredFeature, modifiers); return PlacementUtils.register(id.toString(), configuredFeature, modifiers);
} else { } else {
return BuiltinRegistries.PLACED_FEATURE.getHolder(ResourceKey.create(BuiltinRegistries.PLACED_FEATURE.key(), return BuiltinRegistries.PLACED_FEATURE.getHolder(ResourceKey.create(BuiltinRegistries.PLACED_FEATURE.key(),
id)).orElseThrow(); id)).orElseThrow();
} }
} }

View file

@ -189,10 +189,26 @@ public class BCLFeatureBuilder<FC extends FeatureConfiguration, F extends Featur
return modifier(IsEmptyAboveSampledFilter.emptyAbove4()); return modifier(IsEmptyAboveSampledFilter.emptyAbove4());
} }
public BCLFeatureBuilder isEmptyAbove2() {
return modifier(IsEmptyAboveSampledFilter.emptyAbove2());
}
public BCLFeatureBuilder isEmptyAbove() { public BCLFeatureBuilder isEmptyAbove() {
return modifier(IsEmptyAboveSampledFilter.emptyAbove()); return modifier(IsEmptyAboveSampledFilter.emptyAbove());
} }
public BCLFeatureBuilder isEmptyBelow4() {
return modifier(IsEmptyAboveSampledFilter.emptyBelow4());
}
public BCLFeatureBuilder isEmptyBelow2() {
return modifier(IsEmptyAboveSampledFilter.emptyBelow2());
}
public BCLFeatureBuilder isEmptyBelow() {
return modifier(IsEmptyAboveSampledFilter.emptyBelow());
}
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));
} }

View file

@ -1,25 +0,0 @@
package org.betterx.bclib.api.features;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
import com.mojang.serialization.Codec;
import org.betterx.bclib.api.features.config.BlockPlaceFeatureConfig;
import org.betterx.bclib.util.BlocksHelper;
import java.util.Optional;
public class BlockPlaceFeature<FC extends BlockPlaceFeatureConfig> extends Feature<FC> {
public BlockPlaceFeature(Codec<FC> codec) {
super(codec);
}
@Override
public boolean place(FeaturePlaceContext<FC> ctx) {
Optional<BlockState> state = ctx.config().getRandomBlock(ctx.random());
if (state.isPresent())
BlocksHelper.setWithoutUpdate(ctx.level(), ctx.origin(), state.get());
return true;
}
}

View file

@ -68,7 +68,7 @@ public class ScatterFeature<FC extends ScatterFeatureConfig>
.modifier(RandomOffsetPlacement.of( .modifier(RandomOffsetPlacement.of(
ClampedNormalInt.of(0.0f, 2.0f, -6, 6), ClampedNormalInt.of(0.0f, 2.0f, -6, 6),
ClampedNormalInt.of(0.0f, 0.6f, -2, 2))) ClampedNormalInt.of(0.0f, 0.6f, -2, 2)))
.modifier(BiomeFilter.biome()) .onlyInBiome()
.buildAndRegister(configuration); .buildAndRegister(configuration);
} }

View file

@ -1,59 +0,0 @@
package org.betterx.bclib.api.features.config;
import net.minecraft.util.RandomSource;
import net.minecraft.util.random.SimpleWeightedRandomList;
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.serialization.Codec;
import com.mojang.serialization.DataResult;
import java.util.List;
import java.util.Optional;
public class BlockPlaceFeatureConfig implements FeatureConfiguration {
public static final Codec<BlockPlaceFeatureConfig> CODEC = SimpleWeightedRandomList
.wrappedCodec(BlockState.CODEC)
.comapFlatMap(BlockPlaceFeatureConfig::create, cfg -> cfg.weightedList)
.fieldOf("entries").codec();
private final SimpleWeightedRandomList<BlockState> weightedList;
private static DataResult<BlockPlaceFeatureConfig> create(SimpleWeightedRandomList<BlockState> simpleWeightedRandomList) {
if (simpleWeightedRandomList.isEmpty()) {
return DataResult.error("BlockPlaceFeatureConfig with no states");
}
return DataResult.success(new BlockPlaceFeatureConfig(simpleWeightedRandomList));
}
private static SimpleWeightedRandomList<BlockState> convert(List<BlockState> states) {
var builder = SimpleWeightedRandomList.<BlockState>builder();
for (BlockState s : states) builder.add(s, 1);
return builder.build();
}
public BlockPlaceFeatureConfig(Block block) {
this(block.defaultBlockState());
}
public BlockPlaceFeatureConfig(BlockState state) {
this(SimpleWeightedRandomList
.<BlockState>builder()
.add(state, 1)
.build());
}
public BlockPlaceFeatureConfig(List<BlockState> states) {
this(convert(states));
}
public BlockPlaceFeatureConfig(SimpleWeightedRandomList<BlockState> blocks) {
this.weightedList = blocks;
}
public Optional<BlockState> getRandomBlock(RandomSource random) {
return this.weightedList.getRandomValue(random);
}
}

View file

@ -17,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 Function15<BlockState, BlockState, BlockState, Optional<BlockState>, Float, Float, Float, Float, Integer, Integer, Float, Float, Float, Boolean, IntProvider, T> { public interface Instancer<T extends ScatterFeatureConfig> extends Function15<BlockState, Optional<BlockState>, Optional<BlockState>, Optional<BlockState>, Float, Float, Float, Float, Integer, Integer, Float, Float, Float, Boolean, IntProvider, T> {
} }
public final BlockState clusterBlock; public final BlockState clusterBlock;
@ -39,8 +39,8 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration {
public final boolean growWhileFree; public final boolean growWhileFree;
public ScatterFeatureConfig(BlockState clusterBlock, public ScatterFeatureConfig(BlockState clusterBlock,
BlockState tipBlock, Optional<BlockState> tipBlock,
BlockState bottomBlock, Optional<BlockState> bottomBlock,
Optional<BlockState> baseState, Optional<BlockState> baseState,
float baseReplaceChance, float baseReplaceChance,
float chanceOfDirectionalSpread, float chanceOfDirectionalSpread,
@ -54,8 +54,8 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration {
boolean growWhileFree, boolean growWhileFree,
IntProvider spreadCount) { IntProvider spreadCount) {
this.clusterBlock = clusterBlock; this.clusterBlock = clusterBlock;
this.tipBlock = tipBlock == null ? clusterBlock : tipBlock; this.tipBlock = tipBlock.orElse(clusterBlock);
this.bottomBlock = bottomBlock == null ? clusterBlock : bottomBlock; this.bottomBlock = bottomBlock.orElse(clusterBlock);
this.baseState = baseState; this.baseState = baseState;
this.baseReplaceChance = baseReplaceChance; this.baseReplaceChance = baseReplaceChance;
this.chanceOfDirectionalSpread = chanceOfDirectionalSpread; this.chanceOfDirectionalSpread = chanceOfDirectionalSpread;
@ -81,77 +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
.fieldOf("tip_block") .optionalFieldOf("tip_block")
.orElse(null) .orElse(Optional.empty())
.forGetter((T cfg) -> cfg.tipBlock), .forGetter((T cfg) -> cfg.tipBlock == cfg.clusterBlock
BlockState.CODEC ? Optional.empty()
.fieldOf("bottom_block") : Optional.of(cfg.tipBlock)),
.orElse(null) BlockState.CODEC
.forGetter((T cfg) -> cfg.bottomBlock), .optionalFieldOf("bottom_block")
BlockState.CODEC .orElse(Optional.empty())
.optionalFieldOf("base_state") .forGetter((T cfg) -> cfg.bottomBlock == cfg.clusterBlock
.forGetter((T cfg) -> cfg.baseState), ? Optional.empty()
Codec : Optional.of(cfg.bottomBlock)),
.floatRange(0.0F, 1.0F) BlockState.CODEC
.fieldOf("baseReplaceChance") .optionalFieldOf("base_state")
.orElse(1.0F) .forGetter((T cfg) -> cfg.baseState),
.forGetter((T cfg) -> cfg.baseReplaceChance), Codec
Codec .floatRange(0.0F, 1.0F)
.floatRange(0.0F, 1.0F) .fieldOf("baseReplaceChance")
.fieldOf("chance_of_directional_spread") .orElse(1.0F)
.orElse(0.7F) .forGetter((T cfg) -> cfg.baseReplaceChance),
.forGetter((T cfg) -> cfg.chanceOfDirectionalSpread), Codec
Codec .floatRange(0.0F, 1.0F)
.floatRange(0.0F, 1.0F) .fieldOf("chance_of_directional_spread")
.fieldOf("chance_of_spread_radius2") .orElse(0.7F)
.orElse(0.5F) .forGetter((T cfg) -> cfg.chanceOfDirectionalSpread),
.forGetter((T cfg) -> cfg.chanceOfSpreadRadius2), Codec
Codec .floatRange(0.0F, 1.0F)
.floatRange(0.0F, 1.0F) .fieldOf("chance_of_spread_radius2")
.fieldOf("chance_of_spread_radius3") .orElse(0.5F)
.orElse(0.5F) .forGetter((T cfg) -> cfg.chanceOfSpreadRadius2),
.forGetter((T cfg) -> cfg.chanceOfSpreadRadius3), Codec
Codec .floatRange(0.0F, 1.0F)
.intRange(1, 20) .fieldOf("chance_of_spread_radius3")
.fieldOf("min_height") .orElse(0.5F)
.orElse(2) .forGetter((T cfg) -> cfg.chanceOfSpreadRadius3),
.forGetter((T cfg) -> cfg.minHeight), Codec
Codec .intRange(1, 20)
.intRange(1, 20) .fieldOf("min_height")
.fieldOf("max_height") .orElse(2)
.orElse(7) .forGetter((T cfg) -> cfg.minHeight),
.forGetter((T cfg) -> cfg.maxHeight), Codec
Codec .intRange(1, 20)
.floatRange(0, 10) .fieldOf("max_height")
.fieldOf("max_spread") .orElse(7)
.orElse(2f) .forGetter((T cfg) -> cfg.maxHeight),
.forGetter((T cfg) -> cfg.maxSpread), Codec
Codec .floatRange(0, 10)
.floatRange(0, 1) .fieldOf("max_spread")
.fieldOf("size_variation") .orElse(2f)
.orElse(0.7f) .forGetter((T cfg) -> cfg.maxSpread),
.forGetter((T cfg) -> cfg.sizeVariation), Codec
Codec .floatRange(0, 1)
.floatRange(0, 1) .fieldOf("size_variation")
.fieldOf("floor_chance") .orElse(0.7f)
.orElse(0.5f) .forGetter((T cfg) -> cfg.sizeVariation),
.forGetter((T cfg) -> cfg.floorChance), Codec
Codec .floatRange(0, 1)
.BOOL .fieldOf("floor_chance")
.fieldOf("grow_while_empty") .orElse(0.5f)
.orElse(false) .forGetter((T cfg) -> cfg.floorChance),
.forGetter((T cfg) -> cfg.growWhileFree), Codec
IntProvider.codec(0, 64) .BOOL
.fieldOf("length") .fieldOf("grow_while_empty")
.orElse(UniformInt.of(0, 3)) .orElse(false)
.forGetter(cfg -> cfg.spreadCount) .forGetter((T cfg) -> cfg.growWhileFree),
) IntProvider.codec(0, 64)
.apply(instance, instancer) .fieldOf("length")
); .orElse(UniformInt.of(0, 3))
.forGetter(cfg -> cfg.spreadCount)
)
.apply(instance, instancer)
);
} }
public static class Builder<T extends ScatterFeatureConfig> { public static class Builder<T extends ScatterFeatureConfig> {
@ -240,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,
@ -291,8 +295,8 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration {
public T build() { public T build() {
return instancer.apply( return instancer.apply(
this.clusterBlock, this.clusterBlock,
this.tipBlock, Optional.of(this.tipBlock),
this.bottomBlock, Optional.of(this.bottomBlock),
this.baseState, this.baseState,
this.baseReplaceChance, this.baseReplaceChance,
this.chanceOfDirectionalSpread, this.chanceOfDirectionalSpread,
@ -305,7 +309,7 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration {
this.floorChance, this.floorChance,
this.growWhileFree, this.growWhileFree,
this.spreadCount this.spreadCount
); );
} }
} }
@ -313,8 +317,8 @@ public abstract class ScatterFeatureConfig implements FeatureConfiguration {
public static final Codec<OnSolid> CODEC = buildCodec(OnSolid::new); public static final Codec<OnSolid> CODEC = buildCodec(OnSolid::new);
public OnSolid(BlockState clusterBlock, public OnSolid(BlockState clusterBlock,
BlockState tipBlock, Optional<BlockState> tipBlock,
BlockState bottomBlock, Optional<BlockState> bottomBlock,
Optional<BlockState> baseState, Optional<BlockState> baseState,
float baseReplaceChance, float baseReplaceChance,
float chanceOfDirectionalSpread, float chanceOfDirectionalSpread,
@ -328,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

@ -16,21 +16,42 @@ 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); private static final IsEmptyAboveSampledFilter DEFAULT1 = new IsEmptyAboveSampledFilter(1, 1);
private static final IsEmptyAboveSampledFilter DEFAULT2 = new IsEmptyAboveSampledFilter(1, 2);
private static final IsEmptyAboveSampledFilter BELOW_DEFAULT = new IsEmptyAboveSampledFilter(-4, -2);
private static final IsEmptyAboveSampledFilter BELOW_DEFAULT1 = new IsEmptyAboveSampledFilter(-1, -1);
private static final IsEmptyAboveSampledFilter BELOW_DEFAULT2 = new IsEmptyAboveSampledFilter(-1, -2);
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(-32, 32).fieldOf("d1").orElse(4).forGetter((p) -> p.distance1),
Codec.intRange(1, 32).fieldOf("d2").orElse(4).forGetter((p) -> p.distance1) Codec.intRange(-32, 32).fieldOf("d2").orElse(2).forGetter((p) -> p.distance1)
) )
.apply(instance, IsEmptyAboveSampledFilter::new)); .apply(instance, IsEmptyAboveSampledFilter::new));
public static PlacementFilter emptyAbove4() { public static PlacementFilter emptyAbove4() {
return DEFAULT; return DEFAULT;
} }
public static PlacementFilter emptyAbove2() {
return DEFAULT2;
}
public static PlacementFilter emptyAbove() { public static PlacementFilter emptyAbove() {
return DEFAULT1; return DEFAULT1;
} }
public static PlacementFilter emptyBelow4() {
return BELOW_DEFAULT;
}
public static PlacementFilter emptyBelow2() {
return BELOW_DEFAULT2;
}
public static PlacementFilter emptyBelow() {
return BELOW_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;