Skip to content

Commit 96fff51

Browse files
Wind292its-miromajp3cassiancc
authored
Data Generation - Features (FabricMC#346)
Co-authored-by: Miroma <136986257+its-miroma@users.noreply.github.com> Co-authored-by: Miroma <its.miroma@proton.me> Co-authored-by: jp3 <jp3@syn-2603-7083-4b41-8e69-0000-0000-0000-1986.res6.spectrum.com> Co-authored-by: Cassian <cassian@godsted.com>
1 parent 2221d9b commit 96fff51

File tree

12 files changed

+558
-15
lines changed

12 files changed

+558
-15
lines changed

.vitepress/sidebars/develop.ts

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -254,38 +254,51 @@ export default [
254254
link: "/develop/data-generation/translations",
255255
},
256256
{
257-
text: "develop.data_generation.block_models",
258-
link: "/develop/data-generation/block-models",
259-
},
260-
{
261-
text: "develop.data_generation.item_models",
262-
link: "/develop/data-generation/item-models",
257+
text: "develop.data_generation.models",
258+
items: [
259+
{
260+
text: "develop.data_generation.block_models",
261+
link: "/develop/data-generation/block-models",
262+
},
263+
{
264+
text: "develop.data_generation.item_models",
265+
link: "/develop/data-generation/item-models",
266+
},
267+
],
263268
},
264269
],
265270
},
266271
{
267272
text: "develop.data_generation.server",
268273
items: [
269-
{
270-
text: "develop.data_generation.tags",
271-
link: "/develop/data-generation/tags",
272-
},
273-
274274
{
275275
text: "develop.data_generation.advancements",
276276
link: "/develop/data-generation/advancements",
277277
},
278278
{
279-
text: "develop.data_generation.recipes",
280-
link: "/develop/data-generation/recipes",
279+
text: "develop.data_generation.enchantments",
280+
link: "/develop/data-generation/enchantments",
281281
},
282282
{
283283
text: "develop.data_generation.loot_tables",
284284
link: "/develop/data-generation/loot-tables",
285285
},
286286
{
287-
text: "develop.data_generation.enchantments",
288-
link: "/develop/data-generation/enchantments",
287+
text: "develop.data_generation.recipes",
288+
link: "/develop/data-generation/recipes",
289+
},
290+
{
291+
text: "develop.data_generation.tags",
292+
link: "/develop/data-generation/tags",
293+
},
294+
{
295+
text: "develop.data_generation.world_generation",
296+
items: [
297+
{
298+
text: "develop.data_generation.features",
299+
link: "/develop/data-generation/features",
300+
},
301+
],
289302
},
290303
],
291304
},
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
---
2+
title: Feature Generation
3+
description: A guide to generating features in the world with datagen.
4+
authors:
5+
- cassiancc
6+
- its-miroma
7+
- Wind292
8+
---
9+
10+
<!---->
11+
12+
::: info PREREQUISITES
13+
14+
Make sure you've completed the [datagen setup](./setup) process first.
15+
16+
:::
17+
18+
The generation for features of Minecraft worlds is broken down into 3 parts:
19+
20+
- **Configured Features**: this defines what a feature is; for example, a single tree
21+
- **Placement Features**: this defines how the features should be laid out, in which direction, relative location, and so on; for example, the placement of trees in a forest
22+
- **Biome Modifications**: this defines where the features are placed in the world; for example, the coordinates of the whole forest
23+
24+
::: info
25+
26+
Features in Minecraft are natural or generated patterns in the world, like trees, flowers, ores, or lakes. Features are different from structures (for example villages, temples...), which can be found with the `/locate` command.
27+
28+
:::
29+
30+
## Setup {#setup}
31+
32+
First, we need to make our provider. Create a class that extends `FabricDynamicRegistryProvider` and fill out the base methods:
33+
34+
@[code lang=java transcludeWith=:::datagen-world:provider](@/reference/latest/src/main/java/com/example/docs/worldgen/ExampleModWorldgenProvider.java)
35+
36+
Then add this provider to your `DataGeneratorEntrypoint` class within the `onInitializeDataGenerator` method:
37+
38+
@[code lang=java transclude={67-67}](@/reference/latest/src/client/java/com/example/docs/datagen/ExampleModDataGenerator.java)
39+
40+
Next, make a class for your configured features and a class for your placed features. These don't need to extend anything.
41+
42+
The configured feature class and placed feature class should both have a public method to register and define your features. Its argument, that we called `context`, should be a `BootstrapContext<ConfiguredFeature<?, ?>>` for the configured feature, or a `BootstrapContext<PlacedFeature>` for the placed feature.
43+
44+
In your `DataGeneratorEntrypoint` class, add the lines below to your `buildRegistry` method, replacing the method name with what you chose:
45+
46+
@[code lang=java transcludeWith=:::datagen-world:registries](@/reference/latest/src/client/java/com/example/docs/datagen/ExampleModDataGenerator.java)
47+
48+
If you don't already have the `buildRegistry` method, create it and annotate it with an `@Override`.
49+
50+
## Configured Features {#configured-features}
51+
52+
To make a feature naturally spawn in our world, we should start by defining a configured feature in our configured features class. Let's add a custom configured feature for a Diamond Ore vein.
53+
54+
First, register the key for the `ConfiguredFeature` in your configured feature class:
55+
56+
@[code lang=java transcludeWith=:::datagen-world:configured-key](@/reference/latest/src/main/java/com/example/docs/worldgen/ExampleModWorldConfiguredFeatures.java)
57+
58+
::: tip
59+
60+
The second argument to the `Identifier` (`diamond_block_vein` in this example) is what you would use to spawn in the structure with the `/place` command, which is helpful for debugging.
61+
62+
:::
63+
64+
### Ores {#ores}
65+
66+
Next, we'll make a `RuleTest` that controls which blocks your feature can replace. For example, this `RuleTest` allows the replacement of every block with the tag `DEEPSLATE_ORE_REPLACEABLES`:
67+
68+
@[code lang=java transcludeWith=:::datagen-world:ruletest](@/reference/latest/src/main/java/com/example/docs/worldgen/ExampleModWorldConfiguredFeatures.java)
69+
70+
Next, we need to create the `OreConfiguration`, which tells the game what to replace blocks with.
71+
72+
@[code lang=java transcludeWith=:::datagen-world:ore-feature-config](@/reference/latest/src/main/java/com/example/docs/worldgen/ExampleModWorldConfiguredFeatures.java)
73+
74+
You can have multiple cases in the list for different variants. For example, let's set a different variant for stone and deepslate:
75+
76+
@[code lang=java transcludeWith=:::datagen-world:multi-ore-feature-config](@/reference/latest/src/main/java/com/example/docs/worldgen/ExampleModWorldConfiguredFeatures.java)
77+
78+
Lastly, we need to register our configured feature to our game!
79+
80+
@[code lang=java transcludeWith=:::datagen-world:conf-feature-register](@/reference/latest/src/main/java/com/example/docs/worldgen/ExampleModWorldConfiguredFeatures.java)
81+
82+
### Trees {#trees}
83+
84+
To make a custom tree, you need to first create a `TreeConfiguration`:
85+
86+
@[code lang=java transcludeWith=:::datagen-world:tree-feature-config](@/reference/latest/src/main/java/com/example/docs/worldgen/ExampleModWorldConfiguredFeatures.java)
87+
88+
This is what each argument does:
89+
90+
1. Specifies the block type for the tree trunk; for example, diamond blocks
91+
2. Configures the trunk shape and height behavior using a trunk placer
92+
3. Specifies the block type for the tree leaves; for example, gold blocks
93+
4. Defines the foliage's shape and size using a foliage placer
94+
5. Controls how the tree trunk tapers at different heights, primarily for larger trunks
95+
96+
::: tip
97+
98+
We _highly_ recommend that you play around with these values to create a custom tree that **you** are happy with!
99+
100+
You can use the built-in placers for the Trunk and Foliage from the vanilla trees as a reference.
101+
102+
:::
103+
104+
Next, we need to register our tree by adding the following line to the `configure` method of `ExampleModWorldConfiguredFeatures`.
105+
106+
@[code lang=java transcludeWith=:::datagen-world:tree-register](@/reference/latest/src/main/java/com/example/docs/worldgen/ExampleModWorldConfiguredFeatures.java)
107+
108+
## Placement Features {#placement-features}
109+
110+
The next step in adding a feature to the game is creating its Placement Feature.
111+
112+
In your placed features class's `configure` method, create a variable like the one below:
113+
114+
@[code lang=java transcludeWith=:::datagen-world:conf-feature-register](@/reference/latest/src/main/java/com/example/docs/worldgen/ExampleModWorldPlacedFeatures.java)
115+
116+
In your placed features class, define the key for your placed feature.
117+
118+
@[code lang=java transcludeWith=:::datagen-world:placed-key](@/reference/latest/src/main/java/com/example/docs/worldgen/ExampleModWorldPlacedFeatures.java)
119+
120+
### Placement Modifiers {#placement-modifiers}
121+
122+
Next, we need to define our Placement Modifiers, which are attributes that you set when spawning the feature. These can be anything: from the spawn frequency, to the starting `y` level. You can have as few or as many modifiers as you like.
123+
124+
@[code lang=java transcludeWith=:::datagen-world:placement-modifier](@/reference/latest/src/main/java/com/example/docs/worldgen/ExampleModWorldPlacedFeatures.java)
125+
126+
The function of each modifier listed is as follows:
127+
128+
- **CountPlacement**: Roughly the amount of instances of this feature (in this case veins) per chunk
129+
- **BiomeFilter**: Allows us to control what biomes/dimensions it spawns (we'll do more with this later)
130+
- **InSquarePlacement**: Spreads the features more pseudo-randomly
131+
- **HeightRangePlacement**: Specifies the range of `y` coordinates where a feature can spawn; it supports three main types of distributions:
132+
1. **Uniform**:
133+
All `y` values within the range are equally likely to contain the feature. If you're unsure, just use this one.
134+
135+
2. **Trapezoid**:
136+
`y` values closer to the median `y` value have a higher probability of containing the feature.
137+
138+
3. **Biased-Bottom**:
139+
Uses a logarithmic scale where lower `y` values are more likely to get the feature. It receives a starting `y` coordinate, below which the feature never spawns. The second argument is the maximum height where the feature can spawn. The third argument defines a range in blocks over which the maximum probability is extended.
140+
141+
::: tip
142+
143+
Trees and other surface structures should include the modifier `PlacedFeatures.WORLD_SURFACE_WG_HEIGHTMAP` instead of `HeightRangePlacement`, to make sure the tree spawns on the surface.
144+
145+
:::
146+
147+
Now that we have the modifiers, we can register our placed feature:
148+
149+
@[code lang=java transcludeWith=:::datagen-world:register-placed-feature](@/reference/latest/src/main/java/com/example/docs/worldgen/ExampleModWorldPlacedFeatures.java)
150+
151+
## Biome Modifications {#biome-modifications}
152+
153+
Lastly, we need to add our placed feature to `BiomeModifications` during mod initialization. We can do this by adding the following to our mod initiializer:
154+
155+
@[code lang=java transcludeWith=:::datagen-world:biome-modifications](@/reference/latest/src/main/java/com/example/docs/ExampleMod.java)
156+
157+
::: tip
158+
159+
For trees, the second parameter should be set to `GenerationStep.Decoration.VEGETAL_DECORATION,`
160+
161+
:::
162+
163+
### Biome Specific Generation {#biome-specific-generation}
164+
165+
By changing the `BiomeSelectors` argument, we can have our feature spawn only in a specific type of biome:
166+
167+
@[code lang=java transcludeWith=:::datagen-world:selective-biome-modifications](@/reference/latest/src/main/java/com/example/docs/ExampleMod.java)
168+
169+
This would only spawn in biomes tagged with the `minecraft:is_forest` biome tag.
170+
171+
## Running Datagen {#running-datagen}
172+
173+
Now, when you run datagen, you should see a `.json` file under `src/main/generated/data/example-mod/worldgen/configured_feature` for each configured feature you added, and a file under `src/main/generated/data/example-mod/worldgen/placed_feature` for each placed feature as well!
174+
175+
::: details Generated File for the Configured Feature
176+
177+
@[code lang=json](@/reference/latest/src/main/generated/data/example-mod/worldgen/configured_feature/diamond_block_vein.json)
178+
179+
:::
180+
181+
::: details Generated File for the Placed Feature
182+
183+
@[code lang=json](@/reference/latest/src/main/generated/data/example-mod/worldgen/placed_feature/diamond_block_ore_placed.json)
184+
185+
:::
186+
187+
<!---->

reference/latest/src/client/java/com/example/docs/datagen/ExampleModDataGenerator.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
import com.example.docs.damage.ExampleModDamageTypes;
1313
import com.example.docs.datagen.internal.ExampleModInternalModelProvider;
1414
import com.example.docs.network.basic.ExampleModNetworkingBasicModelProvider;
15+
import com.example.docs.worldgen.ExampleModWorldConfiguredFeatures;
16+
import com.example.docs.worldgen.ExampleModWorldPlacedFeatures;
17+
import com.example.docs.worldgen.ExampleModWorldgenProvider;
1518

1619
// :::datagen-setup:generator
1720
public class ExampleModDataGenerator implements DataGeneratorEntrypoint {
@@ -61,6 +64,8 @@ public void onInitializeDataGenerator(FabricDataGenerator fabricDataGenerator) {
6164

6265
pack.addProvider(ExampleModAppearanceModelProvider::new);
6366

67+
pack.addProvider(ExampleModWorldgenProvider::new);
68+
6469
// :::datagen-setup:generator
6570
}
6671
// :::datagen-setup:generator
@@ -72,6 +77,12 @@ public void buildRegistry(RegistrySetBuilder registryBuilder) {
7277
registryBuilder.add(Registries.DAMAGE_TYPE, registerable -> {
7378
registerable.register(ExampleModDamageTypes.TATER_DAMAGE, TATER_DAMAGE_TYPE);
7479
});
80+
81+
// :::datagen-world:registries
82+
registryBuilder.add(Registries.CONFIGURED_FEATURE, ExampleModWorldConfiguredFeatures::configure);
83+
registryBuilder.add(Registries.PLACED_FEATURE, ExampleModWorldPlacedFeatures::configure);
84+
// :::datagen-world:registries
85+
7586
// :::datagen-enchantments:bootstrap
7687
registryBuilder.add(Registries.ENCHANTMENT, ExampleModEnchantmentGenerator::bootstrap);
7788
}

reference/latest/src/main/generated/data/example-mod/worldgen/configured_feature/diamond_block_vein.json

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

reference/latest/src/main/generated/data/example-mod/worldgen/configured_feature/diamond_tree.json

Lines changed: 44 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

reference/latest/src/main/generated/data/example-mod/worldgen/placed_feature/diamond_block_ore_placed.json

Lines changed: 28 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)