Real badlands clay bands and a real biome temperature table

The bandlands rule cycled four terracotta colours off a per-column random draw.
Vanilla generates a 192-entry band table once per world, from a random source
named clay_bands, and reads it at the block's height shifted by the
clay_bands_offset noise. Brown, red and light grey terracotta were never placed
anywhere; the stripes were the wrong thickness and did not line up between
neighbouring columns. All seven colours now appear.

The temperature condition matched a hand-written list of eleven biome names.
Replacing it with the temperature field read out of the jar's 65 biome JSONs
fixes one of them: deep_frozen_ocean reads cold by name but its base
temperature is 0.5, so vanilla does not freeze it. taiga and the pine taigas
were the other way round -- excluded by name, and correctly so, but by
coincidence rather than by data.

Two parts of the vanilla calculation are left out and documented where they
belong: the height adjustment that cools peaks, and the "frozen" modifier that
warms scattered patches of frozen ocean. Both need PerlinSimplexNoise. Neither
is reachable from the overworld tree in a way that shows: the single condition
that consults temperature sits under a frozen_ocean biome check, below a water
check, and decides whether a hole in the ocean floor ices over. The snowy
mountain tops come from biome selection, not from here -- which is not what the
plan for this commit assumed.

The per-column *rand.Rand threaded through SurfaceContext goes away with the
old bandlands rule; nothing needs it now that vertical_gradient rolls
positionally.
This commit is contained in:
Master290 2026-07-27 02:31:10 +03:00
parent c19e5f0e4f
commit 3a255b52e1
8 changed files with 289 additions and 68 deletions

View file

@ -302,6 +302,48 @@ func main() {
fmt.Printf(" OK: %d of %d grass columns carry 2+ blocks of dirt\n", banded, allGrass)
}
// Badlands banding: the clay band table is 192 entries of seven terracotta
// colours. The stand-in it replaced cycled four, so brown, red and light
// grey never appeared anywhere in the world.
fmt.Println("\n=== Badlands clay bands (expect several terracotta colours down a column) ===")
terracottas := map[uint16]string{
12912: "terracotta", 11444: "white", 11445: "orange", 11448: "yellow",
11452: "light_gray", 11456: "brown", 11458: "red",
}
seenBands := map[uint16]int{}
badlandsCols := 0
for cx := int32(-300); cx < 300 && badlandsCols < 8; cx += 7 {
for cz := int32(-300); cz < 300 && badlandsCols < 8; cz += 7 {
name := world.BiomeNameAt(od, int(cx)*16+8, int(cz)*16+8)
if name != "minecraft:badlands" && name != "minecraft:eroded_badlands" && name != "minecraft:wooded_badlands" {
continue
}
ch := gen(cx, cz)
for lx := 0; lx < 16; lx += 4 {
for lz := 0; lz < 16; lz += 4 {
for wy := world.MinY + world.WorldHeight - 1; wy >= world.MinY; wy-- {
if _, isBand := terracottas[ch.GetBlock(lx, wy, lz)]; isBand {
seenBands[ch.GetBlock(lx, wy, lz)]++
}
}
}
}
badlandsCols++
}
}
if badlandsCols == 0 {
fmt.Println(" (no badlands in the scan area)")
} else {
for id, label := range terracottas {
fmt.Printf(" %-11s %d\n", label, seenBands[id])
}
if len(seenBands) < 6 {
fmt.Printf(" FAIL: only %d of 7 terracotta colours placed\n", len(seenBands))
} else {
fmt.Printf(" OK: %d of 7 terracotta colours across %d badlands chunks\n", len(seenBands), badlandsCols)
}
}
// 2) Cross-section at chunk (0,0): column x=8, over full Y, ASCII.
fmt.Println("\n=== Cross-section chunk(0,0) z=8, x=0..15 (side view, top 96 blocks near surface) ===")
c := gen(0, 0)