Configured Features
A ConfiguredFeature is a feature paired
with a configuration. The feature is the algorithm (an ore vein, a tree, a geode) and the configuration would be its
parameters such as which ore, how big, etc.
Configured features are not placed in the world on their own. A configured feature describes what to generate and a placed feature formally wraps it with the placement rules that decide where and/or how often it should appear.
To use a configured feature in a biome, wrap it in a placed feature.
Referencing Built-in Configured Features
Section titled “Referencing Built-in Configured Features”The ConfiguredFeatures catalog holds
typed references to every configured feature vanilla registrar.
Example Usage
Section titled “Example Usage”import me.outspending.biomesapi.wrapper.worldgen.feature.ConfiguredFeature;
import me.outspending.biomesapi.wrapper.worldgen.feature.ConfiguredFeatures;
// a reference straight from the catalog
ConfiguredFeature largeDiamonds = ConfiguredFeatures.ORE_DIAMOND_LARGE;
// or by key
ConfiguredFeature byKey = ConfiguredFeature.reference(ResourceKey.minecraft("ore_diamond_large")); Authoring Configured Features
Section titled “Authoring Configured Features”To author your own configured features, you can extend the CustomFeature class.
And pair it with your own configuration context.
Example Usage
Section titled “Example Usage”import me.outspending.biomesapi.wrapper.worldgen.feature.custom.CustomFeature;
import me.outspending.biomesapi.wrapper.worldgen.feature.custom.PlacementContext;
import org.bukkit.Material;
import org.bukkit.util.BlockVector;
import org.jetbrains.annotations.NotNull;
import java.util.Random;
public class PillarFeature extends CustomFeature<@NotNull PillarFeature.PillarConfig> {
public PillarFeature() {
super(PillarConfig::defaults);
}
@Override
public boolean place(PlacementContext<@NotNull PillarConfig> context) {
PillarConfig config = context.config();
Random random = context.random();
BlockVector origin = context.origin();
int height = config.minHeight() + random.nextInt(config.maxHeight() - config.minHeight() + 1);
for (int y = 0; y < height; y++) {
BlockVector pos = new BlockVector(origin.getBlockX(), origin.getBlockY() + y, origin.getBlockZ());
context.setBlock(pos, config.pillarBlock().createBlockData());
}
BlockVector cap = new BlockVector(origin.getBlockX(), origin.getBlockY() + height, origin.getBlockZ());
context.setBlock(cap, config.capBlock().createBlockData());
return true;
}
public record PillarConfig(Material pillarBlock, Material capBlock, int minHeight, int maxHeight) {
public static PillarConfig defaults() {
return new PillarConfig(Material.OBSIDIAN, Material.GLOWSTONE, 4, 9);
}
}
} import me.outspending.biomesapi.biome.CustomBiome;
import me.outspending.biomesapi.registry.ResourceKey;
import me.outspending.biomesapi.registry.dimension.DimensionEditor;
import me.outspending.biomesapi.worldgen.PillarFeature;
import me.outspending.biomesapi.wrapper.worldgen.BiomeGenerationSettings;
import me.outspending.biomesapi.wrapper.worldgen.GenerationStep;
import me.outspending.biomesapi.wrapper.worldgen.HeightmapType;
import me.outspending.biomesapi.wrapper.worldgen.feature.ConfiguredFeature;
import me.outspending.biomesapi.wrapper.worldgen.feature.custom.CustomFeature;
import me.outspending.biomesapi.wrapper.worldgen.placement.PlacedFeature;
import me.outspending.biomesapi.wrapper.worldgen.placement.PlacedFeatures;
import me.outspending.biomesapi.wrapper.worldgen.placement.PlacementModifier;
import org.bukkit.Material;
import org.bukkit.plugin.java.JavaPlugin;
public class ExamplePlugin extends JavaPlugin {
@Override
public void onEnable() {
ResourceKey pillar = ResourceKey.of("example", "pillar");
CustomFeature.register(pillar, new PillarFeature());
ConfiguredFeature tallFeature = ConfiguredFeature.customFeature(pillar, new PillarFeature.PillarConfig(Material.OBSIDIAN, Material.GLOWSTONE, 10, 15));
ConfiguredFeature shortFeature = ConfiguredFeature.customFeature(pillar, new PillarFeature.PillarConfig(Material.BLACKSTONE, Material.SHROOMLIGHT, 3, 5));
PlacedFeature tallPlaced = PlacedFeature.builder()
.feature(tallFeature)
.modifier(PlacementModifier.count(2))
.modifier(PlacementModifier.inSquare())
.modifier(PlacementModifier.heightmap(HeightmapType.WORLD_SURFACE))
.modifier(PlacementModifier.biomeFilter())
.build();
PlacedFeature shortPlaced = PlacedFeature.builder()
.feature(shortFeature)
.modifier(PlacementModifier.count(4))
.modifier(PlacementModifier.inSquare())
.modifier(PlacementModifier.heightmap(HeightmapType.WORLD_SURFACE))
.modifier(PlacementModifier.biomeFilter())
.build();
BiomeGenerationSettings generation = BiomeGenerationSettings.builder()
.addFeature(GenerationStep.VEGETAL_DECORATION, PlacedFeatures.TREES_PLAINS)
.addFeature(GenerationStep.VEGETAL_DECORATION, PlacedFeatures.FALLEN_OAK_TREE)
.addFeature(GenerationStep.VEGETAL_DECORATION, tallPlaced)
.addFeature(GenerationStep.VEGETAL_DECORATION, shortPlaced)
.build();
ResourceKey myBiomeKey = ResourceKey.of("example", "my_biome");
CustomBiome.builder(myBiomeKey)
.fogColor("#DB00FD")
.skyColor("#2F46FF")
.waterColor("#00FFD0")
.grassColor("#D1D13A")
.foliageColor("#FF6A00")
.setGenerationSettings(generation)
.register();
DimensionEditor dimensionEditor = DimensionEditor.create();
ResourceKey overworldKey = ResourceKey.of("minecraft", "overworld");
ResourceKey plains = ResourceKey.of("minecraft", "plains");
dimensionEditor.replaceInDimension(overworldKey, plains, myBiomeKey);
dimensionEditor.apply(); // Applies to all loaded worlds
}
}