The positioning of each placement is determined by its placement rules.
#### Types of placement rules
##### game_start
This rule is currently exclusively used to establish a “center” placement that subsequent placements may place relative to. It automatically assigns the placement with this rule to the (0, 0) position (the center of the world grid). If this rule is assigned to a placement, it is a good idea to ensure it is placed first (via world_definition.js, which is outside the scope of this document). It is also not able to be combined with any other placement rules (since it automatically determines the placement position).
{
// [placement details here]
"placement_rules": [
{
"game_start": {}
}
]
},
##### distance
This rule does most of the heavy lifting. Most placements employ one or more distance rules. An example from the campaign “extreme_hills_1” biome placement is shown below.
"placement_rules": [
{
"distance": {
"chunk_distance_from_parent": [
64,
96
],
"distance_to_zero_score": 20,
"tag_parent": "center",
"weight": 3
}
},
{
"distance": {
"chunk_distance_from_parent": [
40,
105
],
"distance_to_zero_score": 10,
"tag_parent": "wellOfFate",
"weight": 1
}
},
{
"distance": {
"chunk_distance_from_parent": 40,
"distance_to_zero_score": 20,
"tag_parent": "village",
"weight": 1,
"mandatory_threshold": 0.5
}
}, // etc.
]
Each rule has a weight, a tag_parent, and a chunk_distance_from_parent. Essentially, “I want to be [chunk_distance_from_parent] chunks from [tag_parent] placement (or placement type), and this desire is [weight] important”.
Each individual distance rule is scored for each available placement candidate, and then the candidate receives a total score based on the individual scores’ weighted average. The position with the highest overall score wins. In the event that multiple position options share the same high score, one is chosen at random. See Scoring distance rules for more details, as well as a detailed explanation of mandatory_threshold and distance_to_zero_score.
Within the winning grid position, the precise placement location is offset by a random amount, controlled by a placement’s optional jitter parameter.
###### chunk_distance_from_parent
This is how far we want our placement to place away from the parent placement or placement category, in chunks (16-block units). We can either provide two integers, interpreted as a minimum and maximum; or one integer, interpreted as a minimum with ∞ as the maximum. Note that providing two identical integers will cause the range to be interpreted as the latter case, with ∞ max distance – the exception to this rule is [0, 0].
###### one_of
Distance scores can also nest recursively into themselves using the one_of[] attribute. one_of rules are scored by assessing all the constituent rules and yielding the maximum among them. They are particularly useful in scenarios where you want something to place near one of several specific placements, and it doesn’t matter which one. In the following example, a placement has two distance rules, the second of which is itself made up of two more distance rules. The placement will attempt to place within 24 chunks of either brokenlands_1 or brokenlands_2.
"placement_rules": [
{
"distance": {
"chunk_distance_from_parent": 25,
"distance_to_zero_score": 10,
"tag_parent": "village",
"weight": 3
}
},
{
"distance": {
"one_of": [
{
"chunk_distance_from_parent": [
0,
24
],
"distance_to_zero_score": 30,
"tag_parent": "brokenlands_1"
},
{
"chunk_distance_from_parent": [
0,
24
],
"distance_to_zero_score": 30,
"tag_parent": "brokenlands_2"
} // etc.
]
}
}
]
##### precise_distance
Sometimes, we need something to reliably place relative to another placement with a higher level of precision than what is possible with the normal distance rule (8✕8 chunks). In this case, we can use a precise distance rule. A placement may only have one precise distance rule, and precise distance rules cannot be used in conjunction with any other types of placement rules. **Note that biome pixels cannot be placed with <code>precise_distance</code> rules.</strong>
"placement_rules": [
{
"precise_distance": {
"chunk_distance_from_parent": [
8,
9
],
"tag_parent": "wetlands_1_village",
"jitter_angle": 1,
"do_not_scale_distance": true
}
}
]
Each rule has a tag_parent, a chunk_distance_from_parent, and may optionally have a jitter_angle attribute. The placement will place exactly within the range of chunk_distance_from_parent distance away from the placement specified by tag_parent. **Note that unlike in the regular distance rule, the <code>tag_parent</code> in the <code>precise_distance</code> rule <em>must</em> be a specific placement, not a <code>placement_type</code>. </strong>
If the placement specifies multiple initial_villages, they will all be spread around the parent placement, with random radii (as above, within the range given by chunk_distance_from_parent) and perfectly even angular spacing from one another (fig. 2). If the precise distance rule specifies a jitter_angle, the angular spacing of each placement is randomized within +/- jitter_angle radians (fig. 3).
<table>
<tr>
<td><img src="images/world_placement/drawing01.png">
</td>
<td><img src="images/world_placement/drawing02.png">
</td>
</tr>
<tr>
<td><b>Figure 2:</b> A precise distance placement with three <code>initial_villages</code> and <code>jitter_angle == 0</code>. Each placement (<strong>C</strong>) has equal angular spacing (120<strong>°</strong>, in this case) and respects the desired distance to their parent (<strong>P</strong>).
</td>
<td><b>Figure 3:</b> A precise distance placement with three <code>initial_villages</code> and <code>jitter_angle != 0</code>. The placements (<strong>C</strong>) still respect the distance to their parent (<strong>P</strong>), but the angles are somewhat randomized (exaggerated slightly for effect).
</td>
</tr>
</table>
##### saturate
The saturate rule is used to place many copies of a placement all over the world. This rule has just one optional parameter: density_per_8x8_chunk_pixel. This many copies of the placement in question are placed within each non-ocean pixel in the biome grid (with jitter, again, subject to the placement’s optional jitter parameter). Currently, the saturate rule is used to place slot_invasion throughout the world, which can be used to dynamically place piglin bases during gameplay via the invasion system.
The saturate placement rule is intended to be used with a particular slot-type placement. Only one placement may use the saturate rule. (If multiple placements use the saturate rule, only the one parsed last will actually be placed.) The saturate rule also may not be used in conjunction with any other placement rules.
##### explicit
The explicit rule is used to place a particular placement at an exact position in the world (block_x, block_z). It is not currently used by any campaign placement, but it may be useful for debugging purposes. The explicit rule may not be combined with any other rules.
#### Scoring distance rules
When we are placing something that uses distance rules, we test every possible location (that is, each available pixel in the biome grid) and pick the one that nets us the best weighted score.
##### Single rules
We will illustrate the following example:
"distance": {
"chunk_distance_from_parent": [
80,
120
],
"distance_to_zero_score": [
10,
20
],
"tag_parent": "center"
}
Here, we are asking to place something between 80 and 120 chunks from the center placement (which is located in the center of the biome grid). See fig. 4.
!
Figure 4: Visualizing the aforementioned placement rule, with a range of [80, 120] to the center placement (<strong>C</strong>). Any pixels in the green section are awarded a score of 1.0, and pixels outside of this section receive a score of 0.0.##### distance_to_zero_score
The above example employs the optional distance_to_zero_score parameter. This allows us to award non-zero scores to placements that are outside of the chunk_distance_from_parent range by up to distance_to_zero_score chunks. There is a linear falloff behavior where pixels closer to the chunk_distance_from_parent range receive scores closer to 1.0, and the scores approach 0.0 as the distance from the core range approaches distance_to_zero_range (fig. 5).
If distance_to_zero_score is provided as an array of two integers, the first is interpreted as the “inner” distance value and the second is the “outer” – this is helpful for situations where we can be more lenient in either the “too close” or the “too far” direction. Conversely, if only one integer is provided, it is interpreted as both the inner and outer distance.
!
Figure 5: Visualizing the aforementioned placement rule but with the addition of a <code>distance_to_zero_range</code> of 20. Any pixels in the green section are awarded a score of 1.0, pixels in the yellow section receive a score between 0.0 and 1.0 (closer to green means higher score), and pixels in white sections receive a score of 0.0.##### mandatory_threshold
If a placement rule scores below its given mandatory threshold for a given candidate location, the total weighted score will be zero for that candidate location. Thus, manditory_threshold is useful for situations where you want to ensure one or more particular rules are respected. A low threshold (e.g. 0.1) means we have more leniency in the distance_to_zero_score sense, while a high threshold (e.g. 1.0) means we have no leniency.
Be cautious when assigning manditory_threshold to multiple distance rules on one placement, because that may significantly decrease the probability of finding a successful candidate location.
##### Rule weights
Each distance rule has a weight attribute indicating its relative importance. That is, if a particular distance rule is very important compared to another one, it is a good idea to assign a large weight to the more important one and a small weight to the less important one.
We calculate a total weight w<sub>t</sub> by summing the individual weights w<sub>i</sub>:
!
The final score s<sub>f</sub> for a potential placement location is given by the sum of each individual score s<sub>i</sub> multiplied by its weight w<sub>i</sub>, all divided by the total weight w<sub>t</sub>:
!
For example, if for a given potential placement location:
- rule 1 receives a score of 0.9 and has a weight of 2
- rule 2 receives a score of 0.4 and has a weight of 5
Its final score will be:
!