User Tools

Site Tools


tutorial:biomes

This is an old revision of the document!


Adding a Biome

NOTE: There is a ongoing pull request on Fabric API that adds biome API for 1.16.2. Please use this tutorial as a workaround until it gets merged.

Introduction

There are 3 steps that are required to add a biome to the world.

  • Creating a biome
  • Registering a biome
  • Adding a biome to a climate zone in the world

In this tutorial, we will add new biome called obsiland biome, whose surface is covered with obsidians.

Creating a Biome

To create a biome, use Biome.Builder and configure properties. Missing one property will likely cause the game to crash. It is recommended to look at vanilla biomes (created in DefaultBiomeCreator) as examples.

public class ExampleMod implements ModInitializer {
  // SurfaceBuilder defines how the surface of your biome looks.
  // We use custom surface builder for our biome to cover surface with obsidians.
  private static final ConfiguredSurfaceBuilder<TernarySurfaceConfig> OBSIDIAN_SURFACE_BUILDER = SurfaceBuilder.DEFAULT
    .method_30478(new TernarySurfaceConfig(
      Blocks.OBSIDIAN.getDefaultState(),
      Blocks.DIRT.getDefaultState(),
      Blocks.GRAVEL.getDefaultState()));
 
  private static final Biome OBSILAND = createObsiland();
 
  private static Biome createObsiland() {
    // We specify what entities spawn and what features generate in the biome.
    // Aside from some structures, trees, rocks, plants and
    //   custom entities, these are mostly the same for each biome.
    // Vanilla configured features for biomes are defined in DefaultBiomeFeatures.
 
    SpawnSettings.Builder spawnSettings = new SpawnSettings.Builder();
    DefaultBiomeFeatures.addFarmAnimals(spawnSettings);
    DefaultBiomeFeatures.addMonsters(spawnSettings, 95, 5, 100);
 
    GenerationSettings.Builder generationSettings = new GenerationSettings.Builder();
    generationSettings.surfaceBuilder(OBSIDIAN_SURFACE_BUILDER);
    DefaultBiomeFeatures.addDefaultUndergroundStructures(generationSettings);
    DefaultBiomeFeatures.addLandCarvers(generationSettings);
    DefaultBiomeFeatures.addDefaultLakes(generationSettings);
    DefaultBiomeFeatures.addDungeons(generationSettings);
    DefaultBiomeFeatures.addMineables(generationSettings);
    DefaultBiomeFeatures.addDefaultOres(generationSettings);
    DefaultBiomeFeatures.addDefaultDisks(generationSettings);
    DefaultBiomeFeatures.addSprings(generationSettings);
    DefaultBiomeFeatures.addFrozenTopLayer(generationSettings);
 
    return (new Biome.Builder())
      .precipitation(Biome.Precipitation.RAIN)
      .category(Biome.Category.NONE)
      .depth(0.125F)
      .scale(0.05F)
      .temperature(0.8F)
      .downfall(0.4F)
      .effects((new BiomeEffects.Builder())
        .waterColor(0x3f76e4)
        .waterFogColor(0x050533)
        .fogColor(0xc0d8ff)
        .skyColor(0x77adff)
        .build())
      .spawnSettings(spawnSettings.build())
      .generationSettings(generationSettings.build())
      .build();
  }
}

Registering Biomes

We register our biome at the entrypoint onInitialize. If you use your own surface builder, you will also have to register it.

public class ExampleMod implements ModInitializer {
  public static final RegistryKey<Biome> OBSILAND_KEY = RegistryKey.of(Registry.BIOME_KEY, new Identifier("tutorial", "obsiland"));
 
  @Override
  public void onInitialize() {
    Registry.register(BuiltinRegistries.CONFIGURED_SURFACE_BUILDER, new Identifier("tutorial", "obsidian"), OBSIDIAN_SURFACE_BUILDER);
 
    Registry.register(BuiltinRegistries.BIOME, OBSILAND_KEY.getValue(), OBSILAND);
    BuiltinBiomesAccessor.getRawIdMap().put(BuiltinRegistries.BIOME.getRawId(OBSILAND), OBSILAND_KEY);
  }
}
@Mixin(BuiltinBiomes.class)
public interface BuiltinBiomesAccessor {
  @Accessor("BY_RAW_ID")
  public static Int2ObjectMap<RegistryKey<Biome>> getRawIdMap() {
    throw new AssertionError();
  }
}

You should also give your biome a language entry in your en_us.json file:

src/main/resources/assets/modid/lang/en_us.json
{
  "biome.tutorial.obsiland": "Obsiland"
}

Adding a biome to a climate zone in the world

The vanilla biomes used in the overworld is defined in VanillaLayeredBiomeSource.BIOMES. We have to add our biome to it first.

public class ExampleMod implements ModInitializer {
  @Override
  public void onInitialize() {
    [...]
 
    // We have to copy existing List because it is immutable.
    List<RegistryKey<Biome>> biomes = new ArrayList<>(VanillaLayeredBiomeSourceAccessor.getBiomes());
    biomes.add(OBSILAND_KEY);
    VanillaLayeredBiomeSourceAccessor.setBiomes(biomes);
  }
}
@Mixin(VanillaLayeredBiomeSource.class)
public interface VanillaLayeredBiomeSourceAccessor {
  @Accessor("BIOMES")
  public static List<RegistryKey<Biome>> getBiomes() {
    throw new AssertionError();
  }
 
  @Accessor("BIOMES")
  public static void setBiomes(List<RegistryKey<Biome>> biomes) {
    throw new AssertionError();
  }
}

Secondly, we need to specify the climate to which the biome is added. In this tutorial, we will add the custom biome to the temperate climate as an example. We modify SetBaseBiomesLayer.TEMPERATE_BIOMES to accomplish this.

public class ExampleMod implements ModInitializer {
  @Override
  public void onInitialize() {
    [...]
 
    // SetBaseBiomesLayer.TEMPERATE_BIOMES is an array of raw biome IDs.
    // We have to get the raw id of our biome and append it to TEMPERATE_BIOMES.
    SetBaseBiomesLayerAccessor.setTemperateBiomes(
      ArrayUtils.add(SetBaseBiomesLayerAccessor.getTemperateBiomes(), BuiltinRegistries.BIOME.getRawId(OBSILAND)));
  }
}
@Mixin(SetBaseBiomesLayer.class)
public interface SetBaseBiomesLayerAccessor {
  @Accessor("TEMPERATE_BIOMES")
  public static int[] getTemperateBiomes() {
    throw new AssertionError();
  }
 
  @Accessor("TEMPERATE_BIOMES")
  public static void setTemperateBiomes(int[] biomes) {
    throw new AssertionError();
  }
}

Result

Congratulations! Your biome should now be generating in the world! You can use below command to find your biome in the world.

/locatebiome tutorial:obsiland

tutorial/biomes.1599252129.txt.gz · Last modified: 2020/09/04 20:42 by siglong