Some more changes to placements

This commit is contained in:
Frank 2022-06-17 23:32:19 +02:00
parent d3b6fa7d80
commit c4875b992a
10 changed files with 948 additions and 4 deletions

View file

@ -16,7 +16,6 @@ import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.resources.RegistryOps;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.BiomeTags;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.Climate;
@ -148,9 +147,10 @@ public class BCLibNetherBiomeSource extends BCLBiomeSource {
private static boolean isValidNetherBiome(Holder<Biome> biome, ResourceLocation location) {
return NetherBiomes.canGenerateInNether(biome.unwrapKey().get()) ||
biome.is(BiomeTags.IS_NETHER) ||
BiomeAPI.wasRegisteredAsNetherBiome(location);
return biome.unwrapKey().get().location().toString().equals("betternether:bone_reef");
// return NetherBiomes.canGenerateInNether(biome.unwrapKey().get()) ||
// biome.is(BiomeTags.IS_NETHER) ||
// BiomeAPI.wasRegisteredAsNetherBiome(location);
}
private static boolean isValidNonVanillaNetherBiome(Holder<Biome> biome, ResourceLocation location) {

View file

@ -595,6 +595,16 @@ public class BCLBiomeBuilder {
return feature(feature.getDecoration(), feature.getPlacedFeature());
}
/**
* Adds new feature to the biome.
*
* @param feature {@link BCLFeature}.
* @return same {@link BCLBiomeBuilder} instance.
*/
public BCLBiomeBuilder feature(org.betterx.bclib.api.v3.levelgen.features.BCLFeature feature) {
return feature(feature.decoration, feature.placedFeature);
}
/**
* Adds new structure feature into the biome.
*

View file

@ -4,6 +4,8 @@ import org.betterx.bclib.api.v2.levelgen.features.config.PlaceFacingBlockConfig;
import org.betterx.bclib.api.v2.levelgen.features.config.ScatterFeatureConfig;
import org.betterx.bclib.api.v2.levelgen.features.features.ScatterFeature;
import net.minecraft.data.worldgen.features.FeatureUtils;
import net.minecraft.data.worldgen.placement.PlacementUtils;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.valueproviders.UniformInt;
import net.minecraft.world.level.block.Block;
@ -19,6 +21,12 @@ import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvi
import net.minecraft.world.level.levelgen.feature.stateproviders.RandomizedIntStateProvider;
public class FastFeatures {
public static RandomPatchConfiguration grassPatch(BlockStateProvider stateProvider, int tries) {
return FeatureUtils.simpleRandomPatchConfiguration(
tries,
PlacementUtils.onlyWhenEmpty(Feature.SIMPLE_BLOCK, new SimpleBlockConfiguration(stateProvider))
);
}
public static BCLFeature<ScatterFeature<ScatterFeatureConfig.OnSolid>, ScatterFeatureConfig.OnSolid> vine(

View file

@ -0,0 +1,49 @@
package org.betterx.bclib.api.v3.levelgen.features;
import net.minecraft.core.Holder;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
import java.util.HashMap;
import java.util.Map;
public class BCLConfigureFeature<F extends Feature<FC>, FC extends FeatureConfiguration> {
private static final Map<Holder<ConfiguredFeature<?, ?>>, BCLConfigureFeature<?, ?>> KNOWN = new HashMap<>();
public final ResourceLocation id;
public final Holder<ConfiguredFeature<FC, F>> configuredFeature;
public final boolean registered;
BCLConfigureFeature(ResourceLocation id, Holder<ConfiguredFeature<FC, F>> configuredFeature, boolean registered) {
this.id = id;
this.configuredFeature = configuredFeature;
this.registered = registered;
}
public F getFeature() {
return configuredFeature.value().feature();
}
public FC getConfiguration() {
return configuredFeature.value().config();
}
public BCLPlacedFeatureBuilder<F, FC> place() {
return place(this.id);
}
BCLPlacedFeatureBuilder<F, FC> place(ResourceLocation id) {
return BCLPlacedFeatureBuilder.place(id, this);
}
static <F extends Feature<FC>, FC extends FeatureConfiguration> BCLConfigureFeature<F, FC> create(Holder<ConfiguredFeature<FC, F>> registeredFeature) {
return (BCLConfigureFeature<F, FC>) KNOWN.computeIfAbsent(
(Holder<ConfiguredFeature<?, ?>>) (Object) registeredFeature,
holder -> new BCLConfigureFeature<>(holder.unwrapKey().orElseThrow()
.location(), registeredFeature, false)
);
}
}

View file

@ -0,0 +1,36 @@
package org.betterx.bclib.api.v3.levelgen.features;
import org.betterx.bclib.api.v2.levelgen.features.config.*;
import net.minecraft.core.Holder;
import net.minecraft.world.level.levelgen.GenerationStep;
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.NoneFeatureConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.RandomFeatureConfiguration;
import net.minecraft.world.level.levelgen.placement.PlacedFeature;
public class BCLFeature<F extends Feature<FC>, FC extends FeatureConfiguration> {
public static final Feature<PlaceFacingBlockConfig> PLACE_BLOCK = org.betterx.bclib.api.v2.levelgen.features.BCLFeature.PLACE_BLOCK;
public static final Feature<ScatterFeatureConfig.OnSolid> SCATTER_ON_SOLID = org.betterx.bclib.api.v2.levelgen.features.BCLFeature.SCATTER_ON_SOLID;
public static final Feature<ScatterFeatureConfig.ExtendTop> SCATTER_EXTEND_TOP = org.betterx.bclib.api.v2.levelgen.features.BCLFeature.SCATTER_EXTEND_TOP;
public static final Feature<ScatterFeatureConfig.ExtendBottom> SCATTER_EXTEND_BOTTOM = org.betterx.bclib.api.v2.levelgen.features.BCLFeature.SCATTER_EXTEND_BOTTOM;
public static final Feature<RandomFeatureConfiguration> RANDOM_SELECTOR = org.betterx.bclib.api.v2.levelgen.features.BCLFeature.RANDOM_SELECTOR;
public static final Feature<TemplateFeatureConfig> TEMPLATE = org.betterx.bclib.api.v2.levelgen.features.BCLFeature.TEMPLATE;
public static final Feature<NoneFeatureConfiguration> MARK_POSTPROCESSING = org.betterx.bclib.api.v2.levelgen.features.BCLFeature.MARK_POSTPROCESSING;
public static final Feature<SequenceFeatureConfig> SEQUENCE = org.betterx.bclib.api.v2.levelgen.features.BCLFeature.SEQUENCE;
public static final Feature<ConditionFeatureConfig> CONDITION = org.betterx.bclib.api.v2.levelgen.features.BCLFeature.CONDITION;
public final BCLConfigureFeature<F, FC> configuredFeature;
public final Holder<PlacedFeature> placedFeature;
public final GenerationStep.Decoration decoration;
BCLFeature(
BCLConfigureFeature<F, FC> configuredFeature,
Holder<PlacedFeature> placed,
GenerationStep.Decoration decoration
) {
this.configuredFeature = configuredFeature;
this.placedFeature = placed;
this.decoration = decoration;
}
}

View file

@ -0,0 +1,289 @@
package org.betterx.bclib.api.v3.levelgen.features;
import org.betterx.bclib.api.v2.levelgen.features.BCLFeature;
import org.betterx.bclib.api.v2.poi.BCLPoiType;
import net.minecraft.core.Holder;
import net.minecraft.data.BuiltinRegistries;
import net.minecraft.resources.ResourceLocation;
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.block.state.properties.IntegerProperty;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.configurations.*;
import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider;
import net.minecraft.world.level.levelgen.feature.stateproviders.WeightedStateProvider;
import net.minecraft.world.level.levelgen.placement.PlacedFeature;
import java.util.Collection;
import java.util.Set;
import java.util.function.BiFunction;
import org.jetbrains.annotations.NotNull;
public abstract class BCLFeatureBuilder<F extends Feature<FC>, FC extends FeatureConfiguration> {
public static class NetherForrestVegetation<FF extends Feature<NetherForestVegetationConfig>> extends BCLFeatureBuilder<FF, NetherForestVegetationConfig> {
private SimpleWeightedRandomList.Builder<BlockState> blocks;
private WeightedStateProvider stateProvider;
private int spreadWidth = 8;
private int spreadHeight = 4;
private NetherForrestVegetation(ResourceLocation featureID, FF feature) {
super(featureID, feature);
}
public NetherForrestVegetation spreadWidth(int v) {
spreadWidth = v;
return this;
}
public NetherForrestVegetation spreadHeight(int v) {
spreadHeight = v;
return this;
}
public NetherForrestVegetation addAllStates(Block block, int weight) {
Set<BlockState> states = BCLPoiType.getBlockStates(block);
states.forEach(s -> add(block.defaultBlockState(), Math.max(1, weight / states.size())));
return this;
}
public NetherForrestVegetation addAllStatesFor(IntegerProperty prop, Block block, int weight) {
Collection<Integer> values = prop.getPossibleValues();
values.forEach(s -> add(block.defaultBlockState().setValue(prop, s), Math.max(1, weight / values.size())));
return this;
}
public NetherForrestVegetation add(Block block, int weight) {
return add(block.defaultBlockState(), weight);
}
public NetherForrestVegetation add(BlockState state, int weight) {
if (stateProvider != null) {
throw new IllegalStateException("You can not add new state once a WeightedStateProvider was built. (" + state + ", " + weight + ")");
}
if (blocks == null) {
blocks = SimpleWeightedRandomList.<BlockState>builder();
}
blocks.add(state, weight);
return this;
}
public NetherForrestVegetation provider(WeightedStateProvider provider) {
if (blocks != null) {
throw new IllegalStateException(
"You can not set a WeightedStateProvider after states were added manually.");
}
stateProvider = provider;
return this;
}
@Override
public NetherForestVegetationConfig createConfiguration() {
if (stateProvider == null && blocks == null) {
throw new IllegalStateException("NetherForestVegetationConfig needs at least one BlockState");
}
if (stateProvider == null) stateProvider = new WeightedStateProvider(blocks.build());
return new NetherForestVegetationConfig(stateProvider, spreadWidth, spreadHeight);
}
}
public static class RandomPatch<FF extends Feature<RandomPatchConfiguration>> extends BCLFeatureBuilder<FF, RandomPatchConfiguration> {
private int tries = 96;
private int xzSpread = 7;
private int ySpread = 3;
private final Holder<PlacedFeature> featureToPlace;
private RandomPatch(
@NotNull ResourceLocation featureID,
@NotNull FF feature,
@NotNull Holder<PlacedFeature> featureToPlace
) {
super(featureID, feature);
this.featureToPlace = featureToPlace;
}
public RandomPatch tries(int v) {
tries = v;
return this;
}
public RandomPatch spreadXZ(int v) {
xzSpread = v;
return this;
}
public RandomPatch spreadY(int v) {
ySpread = v;
return this;
}
@Override
public RandomPatchConfiguration createConfiguration() {
return new RandomPatchConfiguration(tries, xzSpread, ySpread, featureToPlace);
}
}
public static class WithConfiguration<F extends Feature<FC>, FC extends FeatureConfiguration> extends BCLFeatureBuilder<F, FC> {
private FC configuration;
private WithConfiguration(@NotNull ResourceLocation featureID, @NotNull F feature) {
super(featureID, feature);
}
public WithConfiguration configuration(FC config) {
this.configuration = config;
return this;
}
@Override
public FC createConfiguration() {
if (configuration == null) return (FC) NoneFeatureConfiguration.NONE;
return configuration;
}
}
public static class ForSimpleBlock<FF extends Feature<SimpleBlockConfiguration>> extends BCLFeatureBuilder<FF, SimpleBlockConfiguration> {
private final BlockStateProvider provider;
private ForSimpleBlock(
@NotNull ResourceLocation featureID,
@NotNull FF feature,
@NotNull BlockStateProvider provider
) {
super(featureID, feature);
this.provider = provider;
}
@Override
public SimpleBlockConfiguration createConfiguration() {
return new SimpleBlockConfiguration(provider);
}
}
private final ResourceLocation featureID;
private final F feature;
private BCLFeatureBuilder(ResourceLocation featureID, F feature) {
this.featureID = featureID;
this.feature = feature;
}
/**
* Starts a new {@link BCLFeature} builder.
*
* @param featureID {@link ResourceLocation} feature identifier.
* @param feature {@link Feature} to construct.
* @return {@link org.betterx.bclib.api.v2.levelgen.features.BCLFeatureBuilder} instance.
*/
public static <F extends Feature<FC>, FC extends FeatureConfiguration> WithConfiguration<F, FC> start(
ResourceLocation featureID,
F feature
) {
return new WithConfiguration(featureID, feature);
}
public static ForSimpleBlock start(
ResourceLocation featureID,
Block block
) {
return start(featureID, BlockStateProvider.simple(block));
}
public static ForSimpleBlock start(
ResourceLocation featureID,
BlockState state
) {
return start(featureID, BlockStateProvider.simple(state));
}
public static ForSimpleBlock start(
ResourceLocation featureID,
BlockStateProvider provider
) {
ForSimpleBlock builder = new ForSimpleBlock(
featureID,
Feature.SIMPLE_BLOCK,
provider
);
return builder;
}
public static RandomPatch startRandomPatch(
ResourceLocation featureID,
Holder<PlacedFeature> featureToPlace
) {
RandomPatch builder = new RandomPatch(
featureID,
Feature.RANDOM_PATCH,
featureToPlace
);
return builder;
}
public static NetherForrestVegetation startNetherVegetation(
ResourceLocation featureID
) {
NetherForrestVegetation builder = new NetherForrestVegetation(
featureID,
Feature.NETHER_FOREST_VEGETATION
);
return builder;
}
public abstract FC createConfiguration();
protected BCLConfigureFeature<F, FC> buildAndRegister(BiFunction<ResourceLocation, ConfiguredFeature<FC, F>, Holder<ConfiguredFeature<FC, F>>> holderBuilder) {
FC config = createConfiguration();
if (config == null) {
throw new IllegalStateException("Feature configuration for " + featureID + " can not be null!");
}
ConfiguredFeature<FC, F> cFeature = new ConfiguredFeature<FC, F>(feature, config);
Holder<ConfiguredFeature<FC, F>> holder = holderBuilder.apply(featureID, cFeature);
return new BCLConfigureFeature<>(featureID, holder, true);
}
public BCLConfigureFeature<F, FC> buildAndRegister() {
return buildAndRegister(BCLFeatureBuilder::register);
}
public BCLConfigureFeature<F, FC> build() {
return buildAndRegister((id, cFeature) -> Holder.direct(cFeature));
}
public BCLInlinePlacedBuilder<F, FC> inlinePlace() {
BCLConfigureFeature<F, FC> f = build();
return BCLInlinePlacedBuilder.place(f);
}
public Holder<PlacedFeature> inlinePlace(BCLInlinePlacedBuilder<F, FC> placer) {
BCLConfigureFeature<F, FC> f = build();
return placer.build(f);
}
/**
* Internally used by the builder. Normally you should not have to call this method directly as it is
* handled by {@link #buildAndRegister()}
*
* @param id The ID to register this feature with
* @param cFeature The configured Feature
* @param <F> The Feature Class
* @param <FC> The FeatureConfiguration Class
* @return The Holder for the new Feature
*/
public static <F extends Feature<FC>, FC extends FeatureConfiguration> Holder<ConfiguredFeature<FC, F>> register(
ResourceLocation id,
ConfiguredFeature<FC, F> cFeature
) {
return (Holder<ConfiguredFeature<FC, F>>) (Object) BuiltinRegistries.register(
BuiltinRegistries.CONFIGURED_FEATURE,
id,
cFeature
);
}
}

View file

@ -0,0 +1,83 @@
package org.betterx.bclib.api.v3.levelgen.features;
import net.minecraft.core.Holder;
import net.minecraft.data.worldgen.placement.PlacementUtils;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
import net.minecraft.world.level.levelgen.placement.PlacedFeature;
import net.minecraft.world.level.levelgen.placement.PlacementModifier;
public class BCLInlinePlacedBuilder<F extends Feature<FC>, FC extends FeatureConfiguration> extends CommonPlacedFeatureBuilder<F, FC, BCLInlinePlacedBuilder<F, FC>> {
private final BCLConfigureFeature<F, FC> cFeature;
private BCLInlinePlacedBuilder(BCLConfigureFeature<F, FC> cFeature) {
this.cFeature = cFeature;
}
/**
* Starts a new {@link BCLFeature} builder.
*
* @param holder {@link Feature} the configured Feature to start from.
* @return {@link CommonPlacedFeatureBuilder} instance.
*/
public static <F extends Feature<FC>, FC extends FeatureConfiguration> BCLInlinePlacedBuilder<F, FC> place(
ResourceLocation featureID,
Holder<ConfiguredFeature<FC, F>> holder
) {
return place(BCLConfigureFeature.create(holder));
}
/**
* Starts a new {@link BCLFeature} builder.
*
* @param cFeature {@link Feature} the configured Feature to start from.
* @return {@link CommonPlacedFeatureBuilder} instance.
*/
static <F extends Feature<FC>, FC extends FeatureConfiguration> BCLInlinePlacedBuilder<F, FC> place(
BCLConfigureFeature<F, FC> cFeature
) {
return new BCLInlinePlacedBuilder(cFeature);
}
/**
* Builds a new inline (not registered) {@link PlacedFeature}.
*
* @return created {@link PlacedFeature} instance.
*/
public Holder<PlacedFeature> build() {
return build(cFeature);
}
/**
* Builds a new inline (not registered) {@link PlacedFeature}.
*
* @return created {@link PlacedFeature} instance.
*/
public Holder<PlacedFeature> build(BCLConfigureFeature feature) {
return build(feature.configuredFeature);
}
/**
* Builds a new inline (not registered) {@link PlacedFeature}.
*
* @return created {@link PlacedFeature} instance.
*/
public Holder<PlacedFeature> build(Holder<ConfiguredFeature<FC, F>> feature) {
PlacementModifier[] modifiers = modifications.toArray(new PlacementModifier[modifications.size()]);
return PlacementUtils.inlinePlaced(feature, modifiers);
}
/**
* Builds a new inline (not registered) {@link PlacedFeature}.
*
* @return created {@link PlacedFeature} instance.
*/
public Holder<PlacedFeature> build(F feature, FC configuration) {
PlacementModifier[] modifiers = modifications.toArray(new PlacementModifier[modifications.size()]);
return PlacementUtils.inlinePlaced(feature, configuration, modifiers);
}
}

View file

@ -0,0 +1,88 @@
package org.betterx.bclib.api.v3.levelgen.features;
import net.minecraft.core.Holder;
import net.minecraft.data.worldgen.placement.PlacementUtils;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.levelgen.GenerationStep;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
import net.minecraft.world.level.levelgen.placement.PlacedFeature;
public class BCLPlacedFeatureBuilder<F extends Feature<FC>, FC extends FeatureConfiguration> extends CommonPlacedFeatureBuilder<F, FC, BCLPlacedFeatureBuilder<F, FC>> {
private final ResourceLocation featureID;
private GenerationStep.Decoration decoration = GenerationStep.Decoration.VEGETAL_DECORATION;
private final BCLConfigureFeature<F, FC> cFeature;
private BCLPlacedFeatureBuilder(ResourceLocation featureID, BCLConfigureFeature<F, FC> cFeature) {
this.featureID = featureID;
this.cFeature = cFeature;
}
/**
* Set generation step for the feature. Default is {@code VEGETAL_DECORATION}.
*
* @param decoration {@link GenerationStep.Decoration} step.
* @return same {@link CommonPlacedFeatureBuilder} instance.
*/
public BCLPlacedFeatureBuilder<F, FC> decoration(GenerationStep.Decoration decoration) {
this.decoration = decoration;
return this;
}
/**
* Starts a new {@link BCLFeature} builder.
*
* @param featureID {@link ResourceLocation} feature identifier.
* @param holder {@link Feature} the configured Feature to start from.
* @return {@link CommonPlacedFeatureBuilder} instance.
*/
public static <F extends Feature<FC>, FC extends FeatureConfiguration> BCLPlacedFeatureBuilder<F, FC> place(
ResourceLocation featureID,
Holder<ConfiguredFeature<FC, F>> holder
) {
return place(featureID, BCLConfigureFeature.create(holder));
}
/**
* Starts a new {@link BCLFeature} builder.
*
* @param featureID {@link ResourceLocation} feature identifier.
* @param cFeature {@link Feature} the configured Feature to start from.
* @return {@link CommonPlacedFeatureBuilder} instance.
*/
static <F extends Feature<FC>, FC extends FeatureConfiguration> BCLPlacedFeatureBuilder<F, FC> place(
ResourceLocation featureID,
BCLConfigureFeature<F, FC> cFeature
) {
return new BCLPlacedFeatureBuilder(featureID, cFeature);
}
/**
* Builds a new {@link BCLFeature} instance.
*
* @return created {@link BCLFeature} instance.
*/
protected Holder<PlacedFeature> build() {
Holder<PlacedFeature> p = PlacementUtils.register(
featureID.toString(),
cFeature.configuredFeature,
modifications
);
return p;
}
/**
* Builds a new {@link BCLFeature} instance.
* Features will be registered during this process.
*
* @return created {@link BCLFeature} instance.
*/
public BCLFeature<F, FC> buildAndRegister() {
Holder<PlacedFeature> p = build();
return new BCLFeature(cFeature, p, decoration);
}
}

View file

@ -0,0 +1,375 @@
package org.betterx.bclib.api.v3.levelgen.features;
import org.betterx.bclib.api.v2.levelgen.features.config.PlaceFacingBlockConfig;
import org.betterx.bclib.api.v2.levelgen.features.placement.*;
import org.betterx.bclib.api.v2.tag.CommonBlockTags;
import net.minecraft.core.Direction;
import net.minecraft.core.Holder;
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.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 java.util.LinkedList;
import java.util.List;
import java.util.Optional;
abstract class CommonPlacedFeatureBuilder<F extends Feature<FC>, FC extends FeatureConfiguration, T extends CommonPlacedFeatureBuilder<F, FC, ?>> {
protected final List<PlacementModifier> modifications = new LinkedList<>();
/**
* Add feature placement modifier. Used as a condition for feature how to generate.
*
* @param modifiers {@link PlacementModifier}s to add.
* @return same {@link CommonPlacedFeatureBuilder} instance.
*/
public T modifier(PlacementModifier... modifiers) {
for (var m : modifiers)
modifications.add(m);
return (T) this;
}
/**
* Add feature placement modifier. Used as a condition for feature how to generate.
*
* @param modifiers {@link PlacementModifier}s to add.
* @return same {@link CommonPlacedFeatureBuilder} instance.
*/
public T modifier(List<PlacementModifier> modifiers) {
modifications.addAll(modifiers);
return (T) this;
}
/**
* Generate feature in certain iterations (per chunk).
*
* @param count how many times feature will be generated in chunk.
* @return same {@link CommonPlacedFeatureBuilder} instance.
*/
public T count(int count) {
return modifier(CountPlacement.of(count));
}
/**
* Generate feature in certain iterations (per chunk). Count can be between 0 and max value.
*
* @param count maximum amount of iterations per chunk.
* @return same {@link CommonPlacedFeatureBuilder} instance.
*/
public T countMax(int count) {
return modifier(CountPlacement.of(UniformInt.of(0, count)));
}
public T countRange(int min, int max) {
return modifier(CountPlacement.of(UniformInt.of(min, max)));
}
/**
* Generate points in a stencil pattern
*
* @return same {@link CommonPlacedFeatureBuilder} instance.
*/
public T stencil() {
return modifier(Stencil.all());
}
/**
* Generate points in a stencil pattern and selecting (on average) only every 4th
*
* @return same {@link CommonPlacedFeatureBuilder} instance.
*/
public T stencilOneIn4() {
return modifier(Stencil.oneIn4());
}
/**
* Generate points for every xz-Coordinate in a chunk. Be carefuller, this is quite expensive!
*
* @return same {@link CommonPlacedFeatureBuilder} instance.
*/
public T all() {
return modifier(All.simple());
}
/**
* Generate feature in certain iterations (per chunk).
* Feature will be generated on all layers (example - Nether plants).
*
* @param count how many times feature will be generated in chunk layers.
* @return same {@link CommonPlacedFeatureBuilder} instance.
*/
@SuppressWarnings("deprecation")
public T onEveryLayer(int count) {
return modifier(CountOnEveryLayerPlacement.of(count));
}
/**
* Generate feature in certain iterations (per chunk). Count can be between 0 and max value.
* Feature will be generated on all layers (example - Nether plants).
*
* @param count maximum amount of iterations per chunk layers.
* @return same {@link CommonPlacedFeatureBuilder} instance.
*/
@SuppressWarnings("deprecation")
public T onEveryLayerMax(int count) {
return modifier(CountOnEveryLayerPlacement.of(UniformInt.of(0, count)));
}
public T onEveryLayer() {
return modifier(OnEveryLayer.simple());
}
public T onEveryLayerMin4() {
return modifier(OnEveryLayer.min4());
}
public T underEveryLayer() {
return modifier(UnderEveryLayer.simple());
}
public T underEveryLayerMin4() {
return modifier(UnderEveryLayer.min4());
}
/**
* Will place feature once every n-th attempts (in average).
*
* @param n amount of attempts.
* @return same {@link CommonPlacedFeatureBuilder} instance.
*/
public T onceEvery(int n) {
return modifier(RarityFilter.onAverageOnceEvery(n));
}
/**
* Restricts feature generation only to biome where feature was added.
*
* @return same {@link CommonPlacedFeatureBuilder} instance.
*/
public T onlyInBiome() {
return modifier(BiomeFilter.biome());
}
/**
* Randomize the xz-Coordinates
*
* @return same {@link CommonPlacedFeatureBuilder} instance.
*/
public T squarePlacement() {
return modifier(InSquarePlacement.spread());
}
/**
* Select random height that is 10 above min Build height and 10 below max generation height
*
* @return The instance it was called on
*/
public T randomHeight10FromFloorCeil() {
return modifier(PlacementUtils.RANGE_10_10);
}
/**
* Select random height that is 4 above min Build height and 10 below max generation height
*
* @return The instance it was called on
*/
public T randomHeight4FromFloorCeil() {
return modifier(PlacementUtils.RANGE_4_4);
}
/**
* Select random height that is 8 above min Build height and 10 below max generation height
*
* @return The instance it was called on
*/
public T randomHeight8FromFloorCeil() {
return modifier(PlacementUtils.RANGE_8_8);
}
/**
* Select random height that is above min Build height and 10 below max generation height
*
* @return The instance it was called on
*/
public T randomHeight() {
return modifier(PlacementUtils.FULL_RANGE);
}
public T isEmptyAbove4() {
return modifier(IsEmptyAboveSampledFilter.emptyAbove4());
}
public T isEmptyAbove2() {
return modifier(IsEmptyAboveSampledFilter.emptyAbove2());
}
public T isEmptyAbove() {
return modifier(IsEmptyAboveSampledFilter.emptyAbove());
}
public T isEmptyBelow4() {
return modifier(IsEmptyAboveSampledFilter.emptyBelow4());
}
public T isEmptyBelow2() {
return modifier(IsEmptyAboveSampledFilter.emptyBelow2());
}
public T isEmptyBelow() {
return modifier(IsEmptyAboveSampledFilter.emptyBelow());
}
public T isEmptyAbove(int d1, int d2) {
return modifier(new IsEmptyAboveSampledFilter(d1, d2));
}
public T spreadHorizontal(IntProvider p) {
return modifier(RandomOffsetPlacement.horizontal(p));
}
public T spreadVertical(IntProvider p) {
return modifier(RandomOffsetPlacement.horizontal(p));
}
public T spread(IntProvider horizontal, IntProvider vertical) {
return modifier(RandomOffsetPlacement.of(horizontal, vertical));
}
public T offset(Direction dir) {
return modifier(Offset.inDirection(dir));
}
public T offset(Vec3i dir) {
return modifier(new Offset(dir));
}
/**
* Cast a downward ray with max {@code distance} length to find the next solid Block.
*
* @param distance The maximum search Distance
* @return The instance it was called on
* @see #findSolidSurface(Direction, int) for Details
*/
public T findSolidFloor(int distance) {
return modifier(FindSolidInDirection.down(distance));
}
public T noiseBasedCount(float noiseLevel, int belowNoiseCount, int aboveNoiseCount) {
return modifier(NoiseThresholdCountPlacement.of(noiseLevel, belowNoiseCount, aboveNoiseCount));
}
public T extendDown(int min, int max) {
return modifier(new Extend(Direction.DOWN, UniformInt.of(min, max)));
}
public T inBasinOf(BlockPredicate... predicates) {
return modifier(new IsBasin(BlockPredicate.anyOf(predicates)));
}
public T inOpenBasinOf(BlockPredicate... predicates) {
return modifier(IsBasin.openTop(BlockPredicate.anyOf(predicates)));
}
public T is(BlockPredicate... predicates) {
return modifier(new Is(BlockPredicate.anyOf(predicates), Optional.empty()));
}
public T isAbove(BlockPredicate... predicates) {
return modifier(new Is(BlockPredicate.anyOf(predicates), Optional.of(Direction.DOWN.getNormal())));
}
public T isUnder(BlockPredicate... predicates) {
return modifier(new Is(BlockPredicate.anyOf(predicates), Optional.of(Direction.UP.getNormal())));
}
public T findSolidCeil(int distance) {
return modifier(FindSolidInDirection.up(distance));
}
public T hasMinimumDownwardSpace() {
return modifier(MinEmptyFilter.down());
}
public T hasMinimumUpwardSpace() {
return modifier(MinEmptyFilter.up());
}
/**
* Cast a ray with max {@code distance} length to find the next solid Block. The ray will travel through replaceable
* Blocks (see {@link Material#isReplaceable()}) and will be accepted if it hits a block with the
* {@link CommonBlockTags#TERRAIN}-tag
*
* @param dir The direction the ray is cast
* @param distance The maximum search Distance
* @return The instance it was called on
* @see #findSolidSurface(Direction, int) for Details
*/
public T findSolidSurface(Direction dir, int distance) {
return modifier(new FindSolidInDirection(dir, distance));
}
public T findSolidSurface(List<Direction> dir, int distance, boolean randomSelect) {
return modifier(new FindSolidInDirection(dir, distance, randomSelect));
}
public T heightmap() {
return modifier(PlacementUtils.HEIGHTMAP);
}
public T heightmapTopSolid() {
return modifier(PlacementUtils.HEIGHTMAP_TOP_SOLID);
}
public T heightmapWorldSurface() {
return modifier(PlacementUtils.HEIGHTMAP_WORLD_SURFACE);
}
public T onlyWhenEmpty() {
return modifier(BlockPredicateFilter.forPredicate(BlockPredicate.ONLY_IN_AIR_PREDICATE));
}
public T filtered(BlockPredicate predicate) {
return modifier(BlockPredicateFilter.forPredicate(predicate));
}
public T vanillaNetherGround(int countPerLayer) {
return (T) this.onEveryLayer(countPerLayer).onlyInBiome();
}
public T betterNetherGround(int countPerLayer) {
return (T) this.count(countPerLayer).squarePlacement().onEveryLayerMin4().onlyInBiome();
}
public T betterNetherCeiling(int countPerLayer) {
return (T) this.count(countPerLayer).squarePlacement().underEveryLayerMin4().onlyInBiome();
}
public T betterNetherWall(int countPerLayer) {
return (T) this.count(countPerLayer)
.squarePlacement()
.randomHeight4FromFloorCeil()
.modifier(new FindSolidInDirection(PlaceFacingBlockConfig.HORIZONTAL, 12, false))
.onlyInBiome();
}
/**
* Builds a new inline (not registered) {@link PlacedFeature}.
*
* @return created {@link PlacedFeature} instance.
*/
abstract Holder<PlacedFeature> build();
public BCLFeatureBuilder.RandomPatch inRandomPatch(ResourceLocation id) {
return BCLFeatureBuilder.startRandomPatch(id, build());
}
}

View file

@ -0,0 +1,6 @@
package org.betterx.bclib.api.v3.levelgen.features;
import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
public interface UserGrowableFeature<FC extends FeatureConfiguration> extends org.betterx.bclib.api.v2.levelgen.features.UserGrowableFeature<FC> {
}