Features
Features are everything the game scatters over the terrain during the features step: trees, ores, flowers, geodes, springs. They are declared in two files:
- A configured feature says what to place - the tree species, the ore type, the block - with all its parameters.
- A placed feature wraps a configured feature and says where and how often - count per chunk, height range, rarity, filters.
The split is what lets one tree configuration be placed densely in a forest and sparsely in plains. A biome only ever references placed features, listed per decoration step.
References: Configured feature, Placed feature, misode's feature and placed feature generators
Configured Features
Each feature type is a function on configuredFeaturesBuilder, taking the file name first: one call produces one file and returns its FeatureArgument, so a configured feature always holds exactly one feature type. Declare several at once inside a configuredFeatures { } block, or call configuredFeaturesBuilder directly to capture the argument:
Each file lands in data/<namespace>/worldgen/feature/<name>.json, its fields next to type:
Tree
Trees combine a trunk placer, a foliage placer and block state providers for the blocks themselves. belowTrunkProvider takes a ruleBasedStateProvider and defaults to an empty one, which places nothing under the trunk.
Foliage placers take their radius and offset as int providers or plain Ints: blobFoliagePlacer(radius = 2, height = 3) writes constants, and blobFoliagePlacer(height = 3) { radius(uniform(2, 3)) } sets a provider in the block. A placer left to its block, like the poplar one below, uses the same setters: radius(6) and height(uniform(5, 6)).
Every vanilla trunk placer, foliage placer and decorator has its builder, like the poplar ones: a straight trunk branching where the rhombus-shaped foliage starts, with shelf mushrooms on the logs.
The other decorators are alterGround, attachedToLeaves, attachedToLogs, beehive, cocoa, creakingHeart, leaveVine, paleMoss, placeOnGround and trunkVine.
A fallenTree takes the same decorators twice: stumpDecorators for the stump, logDecorators for the log lying next to it, whose length is logLength. attachedToLogs always takes at least one direction, given as its arguments.
rootPlacer adds roots under the trunk and raises the trunk above them. Only the mangrove one exists, mangroveRootPlacer, with the vanilla mangrove values below: the roots grow up to 8 blocks wide and 15 long, skew off their course 20% of the time, turn muddy over mud, and get a moss carpet on top half of the time.
Ore
Ore features replace existing terrain blocks. size is the maximum vein size, higher means bigger veins. discardChanceOnAirExposure skips blocks exposed to air (0.0 for full veins, 1.0 to never show an ore in a cave wall). Vanilla values:
| Vanilla feature | size |
discardChanceOnAirExposure |
|---|---|---|
ore_iron |
9 |
0.0 |
ore_iron_small |
4 |
0.0 |
ore_gold |
9 |
0.0 |
ore_gold_buried |
9 |
0.5 |
ore_diamond_small |
4 |
0.5 |
ore_diamond_medium |
8 |
0.5 |
ore_diamond_large |
12 |
0.7 |
ore_diamond_buried |
8 |
1.0 |
targets { } is shared by ore, scatteredOre and replaceSingleBlock, the three features replacing terrain blocks; the first target matching a block wins. The rule test builders (blockMatch, tagMatch, randomBlockMatch, ...) are scoped to target { } and are the same ones the structure processors use. Vanilla bounds each ore target in height by combining them:
Reference: Ore feature
Block Column
blockColumn stacks layers along a direction, each declared inside layers { } with its height and its provider.
Columns, Pillars And Spreads
Three features build the basalt deltas and the glowstone of the Nether. Their predicate properties (canReplace, continueThrough) take the block predicate builders.
steppedColumnCluster grows a cluster of columns up from the ground, each one stepping down towards its edges.
| Property | Range | Tuning |
|---|---|---|
columnCount |
1..150 | How many columns the cluster has, more columns make a denser, wider cluster. |
clusterReach |
0..13 | How far from the placement position columns can start, capped by height. |
columnReach |
0..3 | How wide each column is, 0 gives one-block-wide spikes. |
height |
1..10 | How tall the columns are. |
canReplace |
- | The blocks a column can grow into. |
continueThrough |
- | The blocks a growing column goes through instead of stopping, such as its own block. |
cannotPlaceOn |
- | A block, a block tag or a list of blocks a column cannot start from. |
singleBlockPillar stacks one block after the other, up or down from the placement position.
| Property | Default | Tuning |
|---|---|---|
direction |
UP |
VerticalDirection.UP grows towards the sky, DOWN hangs from a ceiling. |
chanceToContinue |
1 |
Chance (0 to 1) to place one more block, lower values give shorter pillars. |
canReplace |
any | The blocks the pillar can grow into. |
capFeature |
none | A placed feature run at the end of the pillar. |
randomNeighborSpread sets block on the placement position, then tries random positions around it and places block on each one that passes canReplace and has exactly one of its 6 face neighbors in acceptedNeighbors, so a blob grows outwards from the blocks it is attached to.
| Property | Range | Tuning |
|---|---|---|
attempts |
1..3000 | How many positions are tried, more attempts give a bigger blob. |
xzOffset |
-16..16 | Horizontal spread of the attempts, a trapezoid keeps most near the center. |
yOffset |
-16..16 | Vertical spread of the attempts, uniform(-11, 0) only grows downwards. |
acceptedNeighbors |
- | A block, a block tag or a list of blocks, exactly one face neighbor has to be one. |
canReplace |
- | The blocks that can be replaced. |
Overlay And Patchy Squares
overlay places every placed feature of its list, whether or not the others were placed, where sequence stops at the first one that isn't. A single feature or tag is written as a bare string.
overlay, sequence and simpleRandomSelector also take a block where feature(...) adds a placed feature by ID and placed(...) { } adds a placed feature written inline, with its placement modifiers declared in the block, using the same builders as placedFeature { }. A tag isn't possible in the block because the game only reads a tag as the whole field, never as an entry of a list. An inline placed feature references its configured feature by ID: Kore can't write the configured feature inline yet, because the configured feature builders always register a file. A single entry is written bare, as a string or as an object.
projectedRandomPatchySquare covers a square of side 2 * size + 1 centered on the placement position, keeping each column with a probability that falls off towards the corners (the center cross is always kept). Each kept column is projected downward through the blocks matching projectThrough, for at most maxProjectionHeight steps, and block is placed where it stops. Vanilla caps its basalt pillars with it.
| Property | Range | Tuning |
|---|---|---|
size |
1..16 | Half the side of the square, sampled once per placement. |
maxProjectionHeight |
0.. | The most steps down a column is projected, 0 behaving like 1. |
projectThrough |
- | The blocks a projection passes through while moving down, usually air. |
Templates And Processors
template places one of its weighted structure templates, picked by weight, and runs the optional processors list on it. processors takes a processor list by ID with processorListOrInline(ProcessorLists.X), or written inline with processorListOrInline { }, whose block holds the same processor builders as processorList { }.
An ID is written as a bare string ("processors": "minecraft:empty"). fossil takes both forms for fossilProcessors and overlayProcessors, and so do the single and legacySingle template pool elements.
All Feature Types
Kore covers every vanilla configured feature type.
| Builder | Places | Vanilla use |
|---|---|---|
bamboo(probability) |
Bamboo stalks | Jungle bamboo |
blockBlob(...) |
Small block blob on a surface | Mossy cobblestone in forests |
blockColumn(...) |
Vertical stack of blocks with layers | Custom pillars |
blockPile(...) |
Piles of blocks | Pumpkin/melon patches |
coralClaw(feature) |
A claw-shaped coral | Warm ocean vegetation |
coralTree(feature) |
A branching coral tree | Warm ocean vegetation |
deltaFeature(...) |
Basalt delta with contents and rim | Nether basalt deltas |
disk(...) |
Circular disk of blocks | Clay, sand, gravel patches |
endGateway(...) |
End gateway portal | End outer islands |
endPodium(active) |
End exit portal podium | Dragon fight portal |
endSpike(...) |
End obsidian pillar with crystal | The End respawn pillars |
fallenTree(...) |
A tree trunk lying on the ground | Fallen oak, birch, spruce logs |
fillLayer(...) |
A full layer of blocks | Custom dimension layers |
fossil(...) |
Structure-based fossil | Underground fossils |
geode(...) |
Hollow structure with layered shells | Amethyst geodes |
hugeBrownMushroom(...) |
Large brown mushroom | Swamp/mushroom island fungi |
hugeFungus(...) |
Huge nether fungus | Crimson/warped forests |
hugeRedMushroom(...) |
Large red mushroom | Swamp/mushroom island fungi |
iceberg(...) |
Iceberg | Frozen ocean icebergs |
lake(...) |
Liquid pool | Underground lava lakes |
largeDripstone(...) |
Tall stalactite or stalagmite | Cave ceilings/floors |
multifaceGrowth(block, ...) |
Multi-face block spread | Glow lichen, sculk vein |
netherrackReplaceBlobs(...) |
Blobs replacing netherrack | Nether gravel/blackstone blobs |
ore(...) |
Ore vein replacing terrain | Every overworld ore |
overlay(...) |
Several features, all of them placed | Basalt delta pillars |
projectedRandomPatchySquare(...) |
Patchy square projected on a surface | Basalt pillar caps |
randomBooleanSelector(...) |
One of two features, at random | Symmetric ore variants |
randomNeighborSpread(...) |
Blocks spreading from neighbors | Nether glowstone blobs |
randomSelector(...) |
Weighted random feature picker | Mixed ore deposits |
replaceSingleBlock(...) |
Blocks replaced by rule targets | Custom block swaps |
rootSystem(...) |
Roots under a tree | Mangrove roots |
scatteredOre(...) |
Scattered ore deposits | Nether gold ore blobs |
sculkPatch(...) |
Sculk spread from charges | Deep dark sculk patches |
sequence(...) |
Several features, in order | Multi-step feature chains |
simpleBlock(...) |
A single block state | Flowers, mushrooms |
simpleRandomSelector(...) |
Uniform random feature picker | Coral type variety |
singleBlockPillar(...) |
One-block-wide pillar, up or down | Basalt delta pillars |
speleothem(...) |
Single pointed speleothem | Cave stalactites/stalagmites |
speleothemCluster(...) |
Dense speleothem growth | Cave speleothem rooms |
spike(...) |
Tall spiky columns | Ice spikes in frozen biomes |
springFeature(...) |
Fluid source block | Water/lava springs |
steppedColumnCluster(...) |
Cluster of stepped columns | Basalt delta columns |
template(...) |
A weighted structure template | Desert wells, sulfur springs |
tree(...) |
A tree, trunk and foliage | Every vanilla tree |
underwaterMagma(...) |
Underwater magma blocks | Ocean floors |
vegetationPatch(...) |
Vegetation on surfaces | Cave moss patches |
waterloggedVegetationPatch(...) |
Waterlogged vegetation patches | Underwater cave plants |
weightedRandomSelector(...) |
Weighted random feature picker | Mixed ore/vegetation deposits |
Features Without Configuration
Ten feature types have no fields at all. Their builders take only a file name and nothing else:
blueIce, bonusChest, chorusPlant, endIsland, endPlatform, freezeTopLayer, monsterRoom, noOp, vines, voidStartPlatform.
Reference: Feature types
Block State Providers
A block state provider decides which block state is placed at a position. It fills every field typed BlockStateProvider: toPlace on simpleBlock, stateProvider on disk, trunkProvider and foliageProvider on tree, and so on.
Every builder extends BlockStateProviderScope, so they resolve inside the configuration block of a feature actually taking a provider, and nowhere else. Providers nest freely: any of them can be the source of a randomizedIntStateProvider, the data of a weighted entry or the then of a rule.
| Builder | Written type | Picks the state from |
|---|---|---|
copyPropertiesProvider(source) |
copy_properties |
A source provider, with the existing block's properties copied |
dualNoiseProvider { } |
dual_noise |
Two Perlin noises, one selecting the variety, one picking a state |
noiseProvider { } |
noise |
A single Perlin noise mapped onto a list of states |
noiseThresholdProvider { } |
noise_threshold |
A Perlin noise compared against a threshold |
randomBlockProvider(blocks) |
random_block |
The default state of a random block or block tag |
randomizedIntStateProvider(property) { } |
randomized_int |
Another provider, with one integer property randomized |
rotatedBlockProvider(state, direction) |
rotated |
A block or provider, rotated on its axis or facing |
ruleBasedStateProvider { } |
rule_based |
Ordered block predicate rules, with an optional fallback |
simpleStateProvider(block) |
simple |
A fixed block |
weightedStateProvider { } |
weighted |
A weighted random pick across several providers |
The Kotlin classes carry the full name (SimpleBlockStateProvider, RuleBasedBlockStateProvider, and so on).
Reference: Block state provider
Simple And Rotated
Both take a block, a block plus a property map, or a block plus a block state builder. rotatedBlockProvider also takes another provider, and rotates the axis of a log or the facing of a dispenser towards direction, or towards a random one at every position when direction is omitted.
Random Block
randomBlockProvider places the default state of a random block among the blocks or block tags it is given.
Weighted
Entries are declared inside the provider block, each drawn proportionally to its weight, which defaults to 1. An entry takes a block, a block state, another provider, or a receiver block setting data itself.
Noise-Based
The three noise-based providers share seed, scale and a noise { } block. noise(baseOctave, vararg amplitudeModifiers) is the short form, and noise(baseOctave) { } the receiver form over NoiseParameters (amplitudeModifiers(...), baseAmplitude, normalize, octaveCount); dualNoiseProvider gets the same pair as slowNoise. states(...) takes either blocks or block states.
Randomized Int State
Takes the state given by source and overrides one integer block state property with a sampled value. The block placed by source has to declare that property.
Rule Based
Rules are evaluated top-to-bottom and the first rule that yields a result wins, falling back to fallback when none does. When no rule nor the fallback yields one, the provider yields none.
Both predicate blocks run on a block predicate scope: a single predicate is used as-is, several are wrapped in an all_of. See Block Predicates for the full list.
Block State Provider Files
blockStateProvider writes a provider to data/<namespace>/worldgen/block_state_provider/<name>.json and returns its BlockStateProviderArgument. reference(id) then puts that ID wherever a provider is expected, written as the bare ID. A file holds an inline provider, never a reference.
The game ships eight providers under the BlockStateProviders enum, such as BlockStateProviders.SOIL_BENEATH_TREE for the below_trunk_provider of a tree: CAVE_VINES_BODY, CAVE_VINES_HEAD, FLOWER_FLOWER_FOREST, FLOWER_MEADOW, FLOWER_PLAIN, MANGROVE_PROPAGULE, PODZOL_BENEATH_TREE and SOIL_BENEATH_TREE.
Kore writes every provider as a typed object. When reading a pack, a bare ID is a reference and an object with an id and no type, a full block state like { "id": "minecraft:frosted_ice", "properties": { "age": "0" } }, is a simple provider.
Placed Features
A placed feature wraps a configured feature with placement modifiers, applied in order. Each modifier filters or transforms the stream of candidate positions, so the order matters: count() multiplies positions, heightRange() moves them vertically, biome() drops the ones that ended up outside the biome.
The usual shape is: pick a frequency, spread horizontally, position vertically, then filter. biome() belongs last, since it has to see the final position.
| Modifier | Effect | Vanilla example (placed_feature/) |
|---|---|---|
biome() |
Drops positions outside a biome listing the feature | ore_diamond, last of its modifiers |
blockPredicateFilter { } |
Drops positions failing a block predicate | acacia, a would_survive check on the sapling |
carvingMask(step) |
Keeps only blocks carved by air or liquid |
- |
count(n) |
Repeats the position n times per chunk |
ore_diamond, 7 |
countOnEveryLayer(n) |
Repeats n times on every solid layer |
delta, 40 |
cuboid(xzSize, ySize) |
Spreads the position over a cuboid around it | - |
environmentScan(...) |
Scans up or down for a valid position | cave_vines, scans up for at most 12 steps |
fixedPlacement(...) |
Replaces positions with absolute coordinates | end_platform, [100, 49, 0] |
heightMap(type) |
Moves the position onto a heightmap | bamboo_light, MOTION_BLOCKING |
heightRange(provider) |
Moves the position to a sampled Y level | ore_diamond, trapezoid from aboveBottom(-80) to aboveBottom(80) |
inSquare() |
Randomizes X and Z inside the chunk | ore_diamond |
noiseBasedCount(...) |
Count driven by the noise value at the position | kelp_cold, noiseToCountRatio = 120, noiseFactor = 80.0 |
noiseThresholdCount(...) |
One of two counts, chosen by a noise threshold | flower_plains, noiseLevel = -0.8, belowNoise = 15, aboveNoise = 4 |
offset(x, y, z) |
Shifts the position, each axis -16..16 |
cave_vines, y = -1 |
randomChance(chance) |
Keeps the position with a 0..1 probability |
- |
randomlySelected { } |
Sends each position through one random modifier | feature/desert_well, suspicious sand at one of five offsets |
rarityFilter(chance) |
Keeps the position with a 1/chance probability |
lake_lava_surface, 200 |
surfaceRelativeThresholdFilter(...) |
Filters on the distance to the surface | glow_lichen, OCEAN_FLOOR_WG with maxInclusive = -13 |
surfaceWaterDepthFilter(maxDepth) |
Drops positions under deeper water than maxDepth |
dark_forest_vegetation, 0 |
count, countOnEveryLayer, cuboid, heightRange, randomChance and rarityFilter have no default, the value is required. count, countOnEveryLayer and cuboid take int providers or plain Ints (count(10) is count(constant(10))), heightRange takes a height provider or a bare vertical anchor (heightRange(absolute(32))), randomChance a Float from 0 to 1 and rarityFilter a positive Int; cuboid also takes optional includeEdges and includeInterior booleans, both true in the game when left out; see Providers for the distributions available. offset takes either plain Ints for its axes or int providers for them, 0 when left out, and a mix of both wraps the plain ones in constant(...): offset(x = 1) moves every position the same way, offset(y = uniform(-2, 2)) scatters it, offset(x = constant(1), y = uniform(-2, 2)) does both. randomlySelected { } takes a block of at least one modifier, built with the same builders as the placed feature itself, and picks one of them at random for each position:
Vanilla uses it in the desert_well configured feature, where the suspicious sand of the well is placed at one of five offsets under it. An empty block isn't possible because the game requires at least one modifier, so randomlySelected {} throws.
Reference: Placement modifier
Complete Example
An ore and a tree, from configured feature to biome.
See Also
- Biomes - listing placed features per decoration step
- Block Predicates - the tests used by placement filters and providers
- Providers - height, int and float providers
- World Generation - overview of the worldgen system
