Creating a Feature from Scratch

This guide will outline the process of creating a new feature from the beginning.

If you haven’t already, please read the Config Development Introduction & Creating A Pack From Scratch for more information before continuing.

For a more detailed and in-depth guide about creating a new feature from scratch, please read this unofficial development guide, Feature Config.

Setting up a New Feature

PROCEDURE

1. Add feature stage(s)

Feature generation is divided up into generation stages. Your pack will need to define at least one generation stage in order to generate any features.

Open your pack manifest in your editor of choice.

Add the generation-stage-feature addon as a dependency, using versions 1.+.

This addon will allow us to create new generation stages for features within the pack manifest.

pack.yml
1id: YOUR_PACK_ID
2
3version: 0.1.0
4
5addons:
6  language-yaml: "1.+"
7  chunk-generator-noise-3d: "1.+"
8  ...
9  generation-stage-feature: "1.+"

Add the highlighted lines below to your pack manifest to create these generation stages.

pack.yml
 1id: YOUR_PACK_ID
 2
 3...
 4
 5stages:
 6  - id: trees
 7    type: FEATURE
 8
 9  - id: landforms
10    type: FEATURE

We’ll only be using the trees stage for this guide.

Tip

The generation stage ids can be named to your liking and generation stages will generate in order from top to bottom.

2. Create your structure file

Structure files can either be dynamic TerraScript .tesf or static schematic .schem files.

TerraScript files are written in the TerraScript Language. TerraScript allows for procedurally generated structures and unique complex structure layouts.

  1. Add the structure-terrascript-loader addon to the pack manifest, using versions 1.+

  2. Create a blank .tesf file.

  3. Add TerraScript within the .tesf file to generate the structure.

oak_tree.tesf will be the example file name used for this guide.

A sample oak_tree.tesf file has been provided below if you need it.

oak_tree.tesf
 1num height = 5+randomInt(3);
 2
 3num randPrecision = 100;
 4num radius = 2.5+randomInt(randPrecision)/randPrecision*2;
 5num warp = 1;
 6num warpFreq = 1;
 7num squish = 1.5+randomInt(randPrecision)/randPrecision;
 8num radiusSquared = pow(radius,2);
 9
10for (num h = 0; h < height; h = h + 1) block(0,h,0,"minecraft:oak_log");
11
12for (num x = -radius-warp; x < radius+warp; x = x + 1) {
13    for (num y = (-radius-warp)/squish; y < (radius+warp)/squish; y = y + 1) {
14        for (num z = -radius-warp; z < radius+warp; z = z + 1) {
15            num warpX = warp * sampler("simplex3",
16                                warpFreq*(x+originX()),
17                                warpFreq*(y+originY()+1000),
18                                warpFreq*(z+originZ()));
19            num warpY = warp * sampler("simplex3",
20                                warpFreq*(x+originX()),
21                                warpFreq*(y+originY()+2000),
22                                warpFreq*(z+originZ()));
23            num warpZ = warp * sampler("simplex3",
24                                warpFreq*(x+originX()),
25                                warpFreq*(y+originY()+3000),
26                                warpFreq*(z+originZ()));
27            if (pow(x+warpX,2)+pow((y+warpY)*squish,2)+pow(z+warpZ,2) < radiusSquared) {
28                block(x, y+height, z,"minecraft:oak_leaves", false);
29            }
30        }
31    }
32}

Schematic files consist of an arrangement of blocks that make up a structure that can be saved through WorldEdit.

  1. Add the structure-sponge-loader addon to the pack manifest, using versions 1.+

  2. Source a .schem file, these can be created using WorldEdit if you wish to create your own.

  3. Add the .schem file to your pack.

oak_tree.schem will be the example file name used for this guide.

3. Create your feature config

Add the config-feature addon to the pack manifest, using versions 1.+.

This addon will allow us to create feature config files.

pack.yml
1id: YOUR_PACK_ID
2
3version: 0.1.0
4
5addons:
6  ...
7  config-feature: "1.+"

Create a blank config file and open it your editor.

Set the config type via the type parameter, and config id as shown below.

oak_trees.yml will be example file name used for the feature config in this guide.

oak_trees.yml
1id: OAK_TREES
2type: FEATURE

4. Add the feature distributor

Distributors determine the x-axis and z-axis placement of a feature in the world.

Add the config-distributors addon to the pack manifest, using versions 1.+.

This addon provides a set of distributors to use within feature config files.

pack.yml
1id: YOUR_PACK_ID
2
3version: 0.1.0
4
5addons:
6  ...
7  config-distributors: "1.+"

Configure the oak_trees.yml config to utilize the PADDED_GRID distributor type as shown below.

oak_trees.yml
1id: OAK_TREES
2type: FEATURE
3
4distributor:
5  type: PADDED_GRID
6  width: 12
7  padding: 4
8  salt: 5864

The PADDED_GRID distributor type utilizes cells in a grid with the feature placed within each cell with padding between each cell to ensure that features don’t generate too close to one another.

PADDED_GRID utilizes the nested parameters width, padding, and salt.

  • Width - Determines the size of each cell that will contain your feature

  • Padding - Determines the gap between each cell

  • Salt - Typically a random number that offsets the distributor results to prevent feature placement overlap with the same distributor type. Salt function covered in detail here.

../../../_images/paddedgrid.png

Note

Documentation of PADDED_GRID and other distributor types can be found here.

5. Add the feature locator

Locators determine the y-axis placement of a feature in the world.

Add the config-locators addon to the pack manifest, using versions 1.+.

This addon provides a set of locators to use within feature config files.

pack.yml
1id: YOUR_PACK_ID
2
3version: 0.1.0
4
5addons:
6  ...
7  config-locators: "1.+"

Configure the oak_trees.yml config to utilize the TOP locator type as shown below.

oak_trees.yml
 1id: OAK_TREES
 2type: FEATURE
 3
 4distributor:
 5  ...
 6
 7locator:
 8  type: TOP
 9  range:
10    min: 0
11    max: 319

The TOP locator type will place the feature on the block located at the highest y-level.

Note

Documentation of the various locator types available can be found here.

Tip

You can utilize multiple locators for stricter criteria as shown below with the AND locator.

feature.yml
 1locator:
 2  type: AND
 3  locators:
 4    - type: TOP
 5      range: &range  #range values anchored for other locators to use
 6        min: 0
 7        max: 319
 8    - type: PATTERN
 9      range: *range  #references previously anchored range values
10      pattern:
11        type: MATCH_SET
12        blocks:
13          - minecraft:grass_block
14          - minecraft:dirt
15        offset: -1

6. Add the structure

You can now add your structure to the oak_trees.yml config with the highlighted lines below.

oak_trees.yml
 1id: OAK_TREES
 2type: FEATURE
 3
 4distributor:
 5  ...
 6
 7locator:
 8  ...
 9
10structures:
11  distribution:
12    type: CONSTANT
13  structures: oak_tree

The structures parent key consists of the nested parameters structures.structures and structures.distribution.

structures.structures determines the structure or weighted list of structures to select from upon feature generation in the world.

structures.distribution determines the noise sampler that influences the structure selection results.

Tip

Features can select from a weighted list of structures with a noise sampler to guide the structure selection as shown below.

feature.yml
1structures:
2  distribution:
3    type: WHITE_NOISE
4    salt: 4357
5  structures:
6    - oak_tree_1: 1
7    - oak_tree_2: 1
8    - oak_tree_3: 1

Weighted lists covered in detail here.

7. Apply features to biomes

Open a biome file with your editor.

We’ll use FIRST_BIOME from Creating A Pack From Scratch for this guide

Add the highlighted lines below to the FIRST_BIOME config.

first_biome.yml
 1id: FIRST_BIOME
 2
 3type: BIOME
 4
 5vanilla: minecraft:plains
 6
 7terrain:
 8  sampler:
 9    type: LINEAR_HEIGHTMAP
10    base: 64
11
12palette:
13  - BLOCK:minecraft:stone: 319
14
15features:
16  trees:
17    - OAK_TREES

The OAK_TREES feature should now generate your oak tree structures in FIRST_BIOME.

Tip

Multiple generation stages in biome configs will be done as shown below:

first_biome.yml
 1id: FIRST_BIOME
 2
 3type: BIOME
 4
 5...
 6
 7features:
 8  trees:
 9    - OAK_TREES
10  landforms:
11    - ROCKS

8. Load your pack

At this stage, your pack should now be capable of generating oak trees! You can load up your pack by starting your development client / server which contains the pack you have just defined. You can confirm that your pack has loaded if the pack id (as specified in the pack manifest) appears when using the /packs command, or in your console when starting the server / client up.

If for whatever reason your pack does not load, an error message will show up in console explaining why the pack has failed to load, please read through any of these errors and try to interpret what you may have done wrong, and follow through the previous steps again carefully.

If you still are unable to load the pack, feel free to contact us with any relevant errors.

Conclusion

Once you have verified your pack has loaded correctly, you can now generate a world with your new oak trees!