tutorial:biomes
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision | ||
tutorial:biome [2020/03/26 06:25] – 1.15.2 valoeghese | tutorial:biomes [2020/10/17 02:18] – updated mappings hydos | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Adding | + | ====== Adding |
+ | **NOTE:** There is [[https:// | ||
+ | Please use this tutorial as a workaround until it gets merged. | ||
==== Introduction ==== | ==== Introduction ==== | ||
- | + | There are 3 steps that are required | |
- | This wiki tutorial is focused on registering and adding biomes | + | |
- | + | ||
- | To add a biome, we will first need to create and register the biome, then add it to the world using helper methods from Fabric API. | + | |
- | This tutorial will go over: | + | |
* Creating a biome | * Creating a biome | ||
* Registering a biome | * Registering a biome | ||
* Adding a biome to a climate zone in the world | * Adding a biome to a climate zone in the world | ||
- | * Allowing the player to spawn in the biome | ||
- | We will also briefly go over other helpful | + | In this tutorial, we will add new biome called obsiland biome, whose surface is covered with obsidians. |
==== Creating a Biome ==== | ==== Creating a Biome ==== | ||
- | To create a biome, | + | To create a biome, |
- | * The basic properties of the biome | + | Missing one property will likely cause the game to crash. |
- | * What features | + | It is recommended to look at vanilla biomes |
- | * What entities spawn here | + | |
- | We need to pass a '' | + | <code java> |
+ | public class ExampleMod implements ModInitializer { | ||
+ | // SurfaceBuilder defines how the surface | ||
+ | // We use custom surface builder for our biome to cover surface with obsidians. | ||
+ | private static final ConfiguredSurfaceBuilder< | ||
+ | .withConfig(new TernarySurfaceConfig( | ||
+ | Blocks.OBSIDIAN.getDefaultState(), | ||
+ | Blocks.DIRT.getDefaultState(), | ||
+ | Blocks.GRAVEL.getDefaultState())); | ||
- | Some important settings are depth (height), scale (hill size), and precipitation (weather) | + | private static final Biome OBSILAND = createObsiland(); |
- | <code java [enable_line_numbers=" | + | private static |
- | public class MyBiome extends | + | |
- | { | + | |
- | | + | // |
- | | + | // Vanilla configured features for biomes are defined in DefaultBiomeFeatures. |
- | | + | |
- | | + | |
- | } | + | |
- | </code> | + | |
- | We then need to specify the features and entities that spawn 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 through methods in '' | + | SpawnSettings.Builder spawnSettings = new SpawnSettings.Builder(); |
+ | | ||
+ | DefaultBiomeFeatures.addMonsters(spawnSettings, | ||
- | <code java [enable_line_numbers=" | + | GenerationSettings.Builder generationSettings |
- | public class MyBiome extends Biome | + | |
- | { | + | |
- | public MyBiome() | + | DefaultBiomeFeatures.addLandCarvers(generationSettings); |
- | { | + | DefaultBiomeFeatures.addDefaultLakes(generationSettings); |
- | super(new Biome.Settings().configureSurfaceBuilder(SurfaceBuilder.DEFAULT, | + | DefaultBiomeFeatures.addDungeons(generationSettings); |
- | + | DefaultBiomeFeatures.addMineables(generationSettings); | |
- | this.addStructureFeature(Feature.MINESHAFT.configure(new MineshaftFeatureConfig(0.004D, | + | DefaultBiomeFeatures.addDefaultOres(generationSettings); |
- | this.addStructureFeature(Feature.STRONGHOLD.configure(FeatureConfig.DEFAULT)); | + | DefaultBiomeFeatures.addDefaultDisks(generationSettings); |
- | | + | DefaultBiomeFeatures.addSprings(generationSettings); |
- | | + | DefaultBiomeFeatures.addFrozenTopLayer(generationSettings); |
- | | + | |
- | | + | return |
- | DefaultBiomeFeatures.addDungeons(this); | + | .precipitation(Biome.Precipitation.RAIN) |
- | | + | .category(Biome.Category.NONE) |
- | DefaultBiomeFeatures.addDefaultFlowers(this); | + | .depth(0.125F) |
- | DefaultBiomeFeatures.addDefaultGrass(this); | + | |
- | | + | .temperature(0.8F) |
- | DefaultBiomeFeatures.addDefaultOres(this); | + | |
- | DefaultBiomeFeatures.addDefaultDisks(this); | + | .effects((new BiomeEffects.Builder()) |
- | | + | .waterColor(0x3f76e4) |
- | | + | |
- | DefaultBiomeFeatures.addFrozenTopLayer(this); | + | .fogColor(0xc0d8ff) |
- | | + | .skyColor(0x77adff) |
- | this.addSpawn(EntityCategory.CREATURE, | + | .build()) |
- | this.addSpawn(EntityCategory.CREATURE, | + | .spawnSettings(spawnSettings.build()) |
- | this.addSpawn(EntityCategory.CREATURE, new Biome.SpawnEntry(EntityType.COW, 8, 4, 4)); | + | .generationSettings(generationSettings.build()) |
- | this.addSpawn(EntityCategory.AMBIENT, new Biome.SpawnEntry(EntityType.BAT, 10, 8, 8)); | + | .build(); |
- | this.addSpawn(EntityCategory.MONSTER, | + | } |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | this.addSpawn(EntityCategory.MONSTER, new Biome.SpawnEntry(EntityType.SLIME, | + | |
- | this.addSpawn(EntityCategory.MONSTER, new Biome.SpawnEntry(EntityType.ENDERMAN, | + | |
- | this.addSpawn(EntityCategory.MONSTER, | + | |
- | } | + | |
} | } | ||
</ | </ | ||
==== Registering Biomes ==== | ==== Registering Biomes ==== | ||
+ | We register our biome at the entrypoint '' | ||
+ | If you use your own surface builder, you will also have to register it. | ||
- | To register your biome, we will create a field which holds a biome instance, and add our biome to '' | + | <code java> |
+ | public class ExampleMod implements ModInitializer { | ||
+ | public static final RegistryKey< | ||
- | <code java [enable_line_numbers=" | + | @Override |
- | public | + | public |
- | { | + | Registry.register(BuiltinRegistries.CONFIGURED_SURFACE_BUILDER, new Identifier(" |
- | | + | |
+ | Registry.register(BuiltinRegistries.BIOME, | ||
+ | BuiltinBiomesAccessor.getRawIdMap().put(BuiltinRegistries.BIOME.getRawId(OBSILAND), | ||
+ | } | ||
} | } | ||
</ | </ | ||
- | You should also give your biome a language entry in your '' | + | < |
- | + | @Mixin(BuiltinBiomes.class) | |
- | < | + | public interface BuiltinBiomesAccessor |
- | { | + | |
- | "biome.tutorial.my_biome": " | + | public static Int2ObjectMap< |
+ | throw new AssertionError(); | ||
+ | } | ||
} | } | ||
</ | </ | ||
- | ==== Adding a biome to the world generator ==== | + | You should also give your biome a language entry in your '' |
- | + | ||
- | To make your biome spawn in the world, we will use the helper methods provided by the Fabric-Biomes API module. The code for this should ideally be run during mod initialization. | + | |
- | + | ||
- | We need to specify the climate to which the biome is added, the biome which we are adding, and the weight of the biome (a double value). The weight is a measurement of the chance the biome has to spawn. A higher weight corresponds to a higher chance for the biome to spawn, proportional to the weights of other biomes. The Javadoc comments of each climate give the vanilla biome weights | + | |
- | + | ||
- | In this tutorial, we will add the custom biome to the '' | + | |
- | < | + | < |
- | public class ExampleMod implements ModInitializer | + | |
{ | { | ||
- | @Override | + | "biome.tutorial.obsiland": |
- | public void onInitialize() | + | |
- | { | + | |
- | OverworldBiomes.addContinentalBiome(OverworldClimate.TEMPERATE, TutorialBiomes.MY_BIOME, | + | |
- | OverworldBiomes.addContinentalBiome(OverworldClimate.COOL, | + | |
- | } | + | |
} | } | ||
</ | </ | ||
- | To make the player able to spawn in the biome, we will use another method from the fabric-biomes | + | ==== Adding a biome to a climate zone in the world ==== |
+ | The vanilla | ||
+ | We have to add our biome to it first. | ||
- | <code java [enable_line_numbers=" | + | <code java> |
- | FabricBiomes.addSpawnBiome(TutorialBiomes.MY_BIOME); | + | public class ExampleMod implements ModInitializer { |
- | </ | + | @Override |
+ | public void onInitialize() { | ||
+ | [...] | ||
- | **Congratulations!** Your biome should now be generating in the world! | + | // We have to copy existing List because it is immutable. |
- | + | List<RegistryKey< | |
- | ==== Other useful biome methods ==== | + | |
- | + | VanillaLayeredBiomeSourceAccessor.setBiomes(biomes); | |
- | There are other useful methods in the fabric biomes api that you may want to use, that add extra functionality. | + | } |
- | + | } | |
- | * **Setting the river biome** | + | |
- | + | ||
- | For example, setting your biome not to generate a river: | + | |
- | + | ||
- | <code java [enable_line_numbers=" | + | |
- | OverworldBiomes.setRiverBiome(TutorialBiomes.MY_BIOME, null); | + | |
</ | </ | ||
- | * **Adding biome variants** | + | <code java> |
+ | @Mixin(VanillaLayeredBiomeSource.class) | ||
+ | public interface VanillaLayeredBiomeSourceAccessor { | ||
+ | @Accessor(" | ||
+ | public static List< | ||
+ | throw new AssertionError(); | ||
+ | } | ||
- | The third number is the chance | + | @Accessor(" |
- | For example, setting your biome to be a variant of plains, 33% of the time: | + | |
- | + | throw new AssertionError(); | |
- | <code java [enable_line_numbers=" | + | } |
- | OverworldBiomes.addBiomeVariant(Biomes.PLAINS, | + | } |
</ | </ | ||
- | === The following methods take a weight value which specifies how common | + | 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 '' | ||
- | * **Adding hills biomes** | + | <code java> |
+ | public class ExampleMod implements ModInitializer { | ||
+ | @Override | ||
+ | public void onInitialize() { | ||
+ | [...] | ||
- | For example, setting mountains | + | // 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. | |
- | <code java [enable_line_numbers=" | + | |
- | OverworldBiomes.addHillsBiome(TutorialBiomes.MY_BIOME, Biomes.MOUNTAINS, 1); | + | |
+ | } | ||
+ | } | ||
</ | </ | ||
- | * **Adding biome edges** | + | <code java> |
+ | @Mixin(SetBaseBiomesLayer.class) | ||
+ | public interface SetBaseBiomesLayerAccessor { | ||
+ | @Accessor(" | ||
+ | public static int[] getTemperateBiomes() { | ||
+ | throw new AssertionError(); | ||
+ | } | ||
- | For example, making forest generate on the edge of your biome: | + | @Accessor("TEMPERATE_BIOMES") |
- | + | public static void setTemperateBiomes(int[] biomes) { | |
- | <code java [enable_line_numbers="false"]> | + | throw new AssertionError(); |
- | OverworldBiomes.addEdgeBiome(TutorialBiomes.MY_BIOME, | + | } |
+ | } | ||
</ | </ | ||
- | | + | ==== Result ==== |
- | + | **Congratulations!** Your biome should now be generating in the world! | |
- | For example, making stone beach generate on the shore of your biome: | + | You can use below command to find your biome in the world. |
- | < | + | < |
- | OverworldBiomes.addShoreBiome(TutorialBiomes.MY_BIOME, | + | / |
</ | </ | ||
+ | {{tutorial: |
tutorial/biomes.txt · Last modified: 2022/08/16 20:50 by mineblock11