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

@ -1,9 +1,6 @@
package worldgen
import (
"math/rand"
"testing"
)
import "testing"
// loadTestRules compiles the overworld surface rule set at a fixed seed.
func loadTestRules(t *testing.T) *SurfaceRuleSet {
@ -47,7 +44,6 @@ func TestSurfaceRuleNoPanic(t *testing.T) {
ctx.SeaLevel, ctx.MinY = 63, -64
ctx.MinSurfaceLevel, ctx.WaterHeight = 80, NoWaterAbove
ctx.SurfaceDepth = 3
ctx.Rng = rand.New(rand.NewSource(1))
for _, b := range biomes {
ctx.BiomeName = b
for y := 0; y < 100; y++ {
@ -70,7 +66,6 @@ func TestSurfaceBedrockFloor(t *testing.T) {
ctx.BiomeName = "minecraft:plains"
ctx.MinSurfaceLevel, ctx.WaterHeight = 62, NoWaterAbove
ctx.SurfaceDepth = 3
ctx.Rng = rand.New(rand.NewSource(1))
state, ok := rules.Apply(ctx)
if !ok {
t.Fatal("no rule matched at bedrock floor")
@ -116,21 +111,37 @@ func TestSurfaceBlockIDResolution(t *testing.T) {
}
}
// TestIsColdBiome confirms the snow-cover predicate recognises cold biomes so
// the temperature condition routes snowy biomes to snow.
func TestIsColdBiome(t *testing.T) {
cold := []string{"minecraft:snowy_plains", "minecraft:frozen_peaks", "minecraft:grove"}
// TestColdEnoughToSnow pins the temperature predicate against the biome table
// extracted from the jar. deep_frozen_ocean is the interesting case: the name
// reads cold but its base temperature is 0.5, so vanilla does not freeze it —
// the hand-written list this replaced got it wrong.
func TestColdEnoughToSnow(t *testing.T) {
cold := []string{
"minecraft:frozen_ocean", "minecraft:frozen_peaks", "minecraft:frozen_river",
"minecraft:grove", "minecraft:ice_spikes", "minecraft:jagged_peaks",
"minecraft:snowy_beach", "minecraft:snowy_plains", "minecraft:snowy_slopes",
"minecraft:snowy_taiga",
}
for _, b := range cold {
if !isColdBiome(b) {
t.Errorf("isColdBiome(%q) = false, want true", b)
if !coldEnoughToSnow(b) {
t.Errorf("coldEnoughToSnow(%q) = false, want true", b)
}
}
warm := []string{"minecraft:desert", "minecraft:plains", "minecraft:badlands"}
warm := []string{
"minecraft:desert", "minecraft:plains", "minecraft:badlands",
"minecraft:deep_frozen_ocean", "minecraft:taiga", "minecraft:windswept_hills",
}
for _, b := range warm {
if isColdBiome(b) {
t.Errorf("isColdBiome(%q) = true, want false", b)
if coldEnoughToSnow(b) {
t.Errorf("coldEnoughToSnow(%q) = true, want false", b)
}
}
if coldEnoughToSnow("minecraft:not_a_biome") {
t.Error("an unknown biome read as cold")
}
if len(biomeTemperature) != 65 {
t.Errorf("biome temperature table has %d entries, want 65", len(biomeTemperature))
}
}
// TestWaterCondition pins SurfaceRules.WaterConditionSource against the