Placed Feature Checklist

Placed Features are small structures that can generate up to once per chunk. While they don’t have the flexibility of actual Structures, they can be used to add some simple features to a Minecraft World.

Checklist


  1. Implement the Feature
  2. Register the Feature
  3. Add a Configured Feature
  4. Add a Placed Feature
  5. Add a Biome Modifier

Implement the Feature


The simplest feature can be implemented by extending Feature<NoneFeatureConfiguration>. This will create a simple structure with no configuration options. If you want configuration options you will need to either use a configuration that already exists, or create your own by implementing the FeatureConfiguration interface.

Apart from the constructor, you will need an override for the place() method. This will accept a FeaturePlaceContext which will hold the level, origin of your feature, and any configurations you may have set up. In this method you can place any blocks, entities, or anything you need for your feature.

An example of a bare bones implementation with no configuration options is as follows. I’ve cut most of the methods to keep the focus on the minimum needed to implement a new Feature:

@SuppressWarnings("deprecation")
public class PeacemakerLair extends Feature<NoneFeatureConfiguration> {

    /**
     * Construction
     * @param config The configuration for the feature.
     */
    public PeacemakerLair(Codec<NoneFeatureConfiguration> config) {
        super(config);
    }

    /**
     * Try and place a Peacemaker Lair.
     * @param config The configuration for the feature.
     * @return True if the feature was successfully placed.
     */
    @Override
    public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> config) {
        WorldGenLevel level = config.level();
        BlockPos origin = config.origin();
        RandomSource random = config.random();
        Predicate<BlockState> replaceable = Feature.isReplaceable(BlockTags.FEATURES_CANNOT_REPLACE);

        RoomBounds bounds = new RoomBounds(random);
        if (!canGenerate(level, origin, bounds)) {
            return false;
        }

        carveAndBuild(level, origin, bounds, random, replaceable);
        placeChests(level, origin, bounds, random, replaceable);

        spawnPeacemakerButterflies(level, origin, bounds, random);
        spawnPeacemakerCow(level, origin);

        return true;
    }
}

Register the Feature


As with all things Minecraft, the Feature will need to be registered. You will need a custom codec if your feature has any configuration options, otherwise you can just use NoneFeatureConfiguration.CODEC. Here’s a simple example of a FeatureRegistry:

public class FeatureRegistry {

    // An instance of a deferred registry we use to register blocks.
    public static final DeferredRegister<Feature<?>> FEATURES;

    // Peacemaker Lair
    public static final DeferredHolder<Feature<?>, Feature<NoneFeatureConfiguration>> PEACEMAKER_LAIR;

    static {
        FEATURES = DeferredRegister.create(BuiltInRegistries.FEATURE, ButterfliesMod.MOD_ID);

        PEACEMAKER_LAIR = FEATURES.register("peacemaker_lair", () -> new PeacemakerLair(NoneFeatureConfiguration.CODEC));
    }
}

Add a Configured Feature


You can now create a Configured Feature using this feature class. This is a JSON file that goes under resources/data/<MOD_ID>/worldgen/configured_feature/. The type is the Resource Location where your feature is registered, and the config object sets any configuration options the feature might have. If there is no configuration, this JSON is extremely simple:

{
    "type": "butterflies:peacemaker_lair",
    "config": {}
}

Add a Placed Feature


This one goes under resources/data/<MOD_ID>/worldgen/placed_feature/, and describes where features can be placed. The feature is the Resource Location of your configured feature, then you can add placement rules under the placement array. There are too many options to go into here, but they can be found on the Minecraft Wiki.

This example is the one I used for the Peacemaker Lairs:

{
  "feature": "butterflies:peacemaker_lair",
  "placement": [
    {
      "type": "minecraft:count",
      "count": 4
    },
    {
      "type": "minecraft:in_square"
    },
    {
      "type": "minecraft:height_range",
      "height": {
        "type": "minecraft:uniform",
        "max_inclusive": {
          "below_top": 0
        },
        "min_inclusive": {
          "absolute": 0
        }
      }
    },
    {
      "type": "minecraft:biome"
    }
  ]
}

Add a Biome Modifier


Biome modifiers go under resources/data/<MOD_ID>/forge/biome_modifier/ (or resources/data/<MOD_ID>/neoforge/biome_modifier/. These can be used to add features to biomes using the forge:add_features type (or neoforge:add_features). A good reference for Biome Modifiers can be found on the Gemwire wiki.

The one used for Peacemaker Lairs allows them to generate on the overworld during the underground_structures phase of terrain generation:

{
  "type": "forge:add_features",
  "biomes": "#minecraft:is_overworld",
  "features": "butterflies:peacemaker_lair",
  "step": "underground_structures"
}