Some more changes to placements
This commit is contained in:
parent
d3b6fa7d80
commit
c4875b992a
10 changed files with 948 additions and 4 deletions
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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> {
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue