User Tools

Site Tools


Sidebar

Setup

Basics

Items

Blocks and Block Entities

Fluids

Entities

World Generation

Miscellaneous

Events

Mixins

Advanced

Tutorials for Minecraft 1.15

Tutorials for Minecraft 1.14

Documentation

tutorial:features

Adding Features

Rocks, trees, ores, and ponds are all examples of features. They are simple generation additions to the world which generate depending on how they are configured. In this tutorial, we'll look at generating a simple stone spiral feature in the plain biomes randomly.

There are 3 steps that are required to add a feature to a biome.

  • Create a feature
  • Configure a feature
  • Add a configured feature to a biome

Creating a feature

A simple Feature looks like this:

public class StoneSpiralFeature extends Feature<DefaultFeatureConfig> {
  public StoneSpiralFeature(Codec<DefaultFeatureConfig> config) {
    super(config);
  }
 
  @Override
  public boolean generate(StructureWorldAccess world, ChunkGenerator generator, Random random, BlockPos pos,
      DefaultFeatureConfig config) {
    BlockPos topPos = world.getTopPosition(Heightmap.Type.WORLD_SURFACE, pos);
    Direction offset = Direction.NORTH;
 
    for (int y = 1; y <= 15; y++) {
      offset = offset.rotateYClockwise();
      world.setBlockState(topPos.up(y).offset(offset), Blocks.STONE.getDefaultState(), 3);
    }
 
    return true;
  }
}

The Feature<DefaultFeatureConfig> constructor takes in a Codec<DefaultFeatureConfig>. You can pass in DefaultFeatureConfig.CODEC for default config features, either directly in the super call in the constructor or when you instantiate the feature.

generate is called when the chunk decides to generate the feature. If the feature is configured to spawn every chunk, this would be called for each chunk being generated as well. In the case of the feature being configured to spawn at a certain rate per biome, generate would only be called in instances where the world wants to spawn the structure.

In our implementation, we'll build a simple 15-block tall spiral of stone starting at the top block in the world.

Features can be registered like most other content in the game, and there aren't any special builders or mechanics you'll have to worry about.

public class ExampleMod implements ModInitializer {
  private static final Feature<DefaultFeatureConfig> STONE_SPIRAL = new StoneSpiralFeature(DefaultFeatureConfig.CODEC);
 
  @Override
  public void onInitialize() {
    Registry.register(Registry.FEATURE, new Identifier("tutorial", "stone_spiral"), STONE_SPIRAL);
  }
}

Configuring a feature

We need to give a configuration to a feature. Make sure to register configured feature as well as feature.

public class ExampleMod implements ModInitializer {
  public static final ConfiguredFeature<?, ?> STONE_SPIRAL_CONFIGURED = STONE_SPIRAL.configure(FeatureConfig.DEFAULT)
      .decorate(Decorator.CHANCE.configure(new ChanceDecoratorConfig(100)));
 
  @Override
  public void onInitialize() {
    [...]
 
    Registry.register(BuiltinRegistries.CONFIGURED_FEATURE, new Identifier("tutorial", "stone_spiral"), STONE_SPIRAL_CONFIGURED);
  }
}

The Decorator represents how the world chooses to place your feature. To choose the correct Decorator, check out vanilla features with a similar style to your own. The decorator config branches off this; in the case of CHANCE, you would pass in an instance of ChanceDecoratorConfig.

Adding a configured feature to a biome

Vanilla features generated in the plain biomes are listed in DefaultBiomeFeatures.addPlainsFeatures. We modify this method to add our feature to the plain biomes.

@Mixin(DefaultBiomeFeatures.class)
public class DefaultBiomeFeaturesMixin {
  @Inject(method = "addPlainsFeatures(Lnet/minecraft/world/biome/GenerationSettings$Builder;)V", at = @At("TAIL"))
  private static void addPlainsFeatures(GenerationSettings.Builder builder, CallbackInfo ci) {
    builder.feature(GenerationStep.Feature.TOP_LAYER_MODIFICATION, ExampleMod.STONE_SPIRAL_CONFIGURED);
  }
}

The first argument of feature helps determine when the structure is generated. For above-ground houses you may go with SURFACE_STRUCTURES, and for caves, you might go with RAW_GENERATION.

Result

tutorial/features.txt · Last modified: 2020/09/06 10:42 by siglong