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:
parent
c19e5f0e4f
commit
3a255b52e1
8 changed files with 289 additions and 68 deletions
87
internal/worldgen/bandlands.go
Normal file
87
internal/worldgen/bandlands.go
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
package worldgen
|
||||
|
||||
import "math"
|
||||
|
||||
// bandlands.go ports SurfaceSystem's badlands clay banding: a 192-entry table
|
||||
// of terracotta colours generated once per world, indexed by height plus a
|
||||
// noise offset. It is what gives badlands their horizontal stripes.
|
||||
//
|
||||
// The previous stand-in cycled four colours off a per-column random draw, which
|
||||
// produced stripes of the wrong thickness in the wrong places and never used
|
||||
// brown, red or light grey at all.
|
||||
|
||||
const clayBandCount = 192
|
||||
|
||||
// clayBands is the generated band table plus the noise that shifts it
|
||||
// horizontally.
|
||||
type clayBands struct {
|
||||
bands [clayBandCount]uint16
|
||||
offset *NormalNoise
|
||||
}
|
||||
|
||||
// bandAt is SurfaceSystem.getBand.
|
||||
func (c *clayBands) bandAt(x, y, z int) uint16 {
|
||||
// Math.round, which is floor(v+0.5) — not Go's round-half-away-from-zero.
|
||||
shift := int(math.Floor(c.offset.GetValue(float64(x), 0, float64(z))*4.0 + 0.5))
|
||||
return c.bands[((y+shift)%clayBandCount+clayBandCount)%clayBandCount]
|
||||
}
|
||||
|
||||
// newClayBands is SurfaceSystem.generateBands: terracotta everywhere, then
|
||||
// orange stripes at random intervals, then runs of yellow, brown and red, then
|
||||
// white bands flanked by light grey.
|
||||
func newClayBands(random RandomSource, offset *NormalNoise) *clayBands {
|
||||
c := &clayBands{offset: offset}
|
||||
terracotta, _ := surfaceBlockID("minecraft:terracotta", nil)
|
||||
orange, _ := surfaceBlockID("minecraft:orange_terracotta", nil)
|
||||
yellow, _ := surfaceBlockID("minecraft:yellow_terracotta", nil)
|
||||
brown, _ := surfaceBlockID("minecraft:brown_terracotta", nil)
|
||||
red, _ := surfaceBlockID("minecraft:red_terracotta", nil)
|
||||
white, _ := surfaceBlockID("minecraft:white_terracotta", nil)
|
||||
lightGray, _ := surfaceBlockID("minecraft:light_gray_terracotta", nil)
|
||||
|
||||
for i := range c.bands {
|
||||
c.bands[i] = terracotta
|
||||
}
|
||||
// The stride is added to the loop variable, so the ++ at the end of each
|
||||
// iteration is part of the spacing — as it is in vanilla.
|
||||
for i := 0; i < clayBandCount; i++ {
|
||||
if i += int(random.NextIntN(5)) + 1; i >= clayBandCount {
|
||||
continue
|
||||
}
|
||||
c.bands[i] = orange
|
||||
}
|
||||
c.makeBands(random, 1, yellow)
|
||||
c.makeBands(random, 2, brown)
|
||||
c.makeBands(random, 1, red)
|
||||
|
||||
whiteBandCount := nextIntBetweenInclusive(random, 9, 15)
|
||||
for i, start := 0, 0; i < whiteBandCount && start < clayBandCount; i, start = i+1, start+int(random.NextIntN(16))+4 {
|
||||
c.bands[start] = white
|
||||
if start-1 > 0 && random.NextBoolean() {
|
||||
c.bands[start-1] = lightGray
|
||||
}
|
||||
if start+1 >= clayBandCount || !random.NextBoolean() {
|
||||
continue
|
||||
}
|
||||
c.bands[start+1] = lightGray
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// makeBands is SurfaceSystem.makeBands: six to fifteen runs of one colour, each
|
||||
// a few bands wide, dropped at random offsets.
|
||||
func (c *clayBands) makeBands(random RandomSource, baseWidth int, state uint16) {
|
||||
bandCount := nextIntBetweenInclusive(random, 6, 15)
|
||||
for i := 0; i < bandCount; i++ {
|
||||
width := baseWidth + int(random.NextIntN(3))
|
||||
start := int(random.NextIntN(clayBandCount))
|
||||
for p := 0; start+p < clayBandCount && p < width; p++ {
|
||||
c.bands[start+p] = state
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// nextIntBetweenInclusive is RandomSource.nextIntBetweenInclusive.
|
||||
func nextIntBetweenInclusive(random RandomSource, lo, hi int) int {
|
||||
return lo + int(random.NextIntN(int32(hi-lo+1)))
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue