Vanilla-faithful overworld generator (final_density + multi-noise biomes), full connection lifecycle (status/login/configuration/play), chunk streaming, creative block editing, and the protocol/nbt/registry infrastructure.
88 lines
2.2 KiB
Go
88 lines
2.2 KiB
Go
package world
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"regionio/internal/worldgen"
|
|
)
|
|
|
|
// SeaLevel is the water surface height for generated terrain.
|
|
const SeaLevel = 63
|
|
|
|
// NewTerrainGenerator returns a chunk generator backed by a density function.
|
|
// The density tree is built once (shared, read-only noise state) and sampled
|
|
// per block.
|
|
func NewTerrainGenerator(seed int64) Generator {
|
|
density := worldgen.SimpleTerrain(seed)
|
|
return func(cx, cz int32) *Chunk {
|
|
return generateFromDensity(density, cx, cz)
|
|
}
|
|
}
|
|
|
|
// generateFromDensity fills a chunk by sampling the density function (>0 is
|
|
// solid). The per-column sampling is the expensive part and is run in parallel
|
|
// across the 16 x-rows; chunk assembly is sequential to avoid racing on lazy
|
|
// section allocation. Sampling the density only reads shared noise state, so it
|
|
// is safe to run concurrently.
|
|
func generateFromDensity(d worldgen.DensityFunction, cx, cz int32) *Chunk {
|
|
c := NewChunk(cx, cz, BiomePlains)
|
|
|
|
var columns [16][16][WorldHeight]uint16
|
|
var wg sync.WaitGroup
|
|
for lx := 0; lx < 16; lx++ {
|
|
wg.Add(1)
|
|
go func(lx int) {
|
|
defer wg.Done()
|
|
for lz := 0; lz < 16; lz++ {
|
|
wx := float64(int(cx)*16 + lx)
|
|
wz := float64(int(cz)*16 + lz)
|
|
computeColumn(d, wx, wz, &columns[lx][lz])
|
|
}
|
|
}(lx)
|
|
}
|
|
wg.Wait()
|
|
|
|
for lx := 0; lx < 16; lx++ {
|
|
for lz := 0; lz < 16; lz++ {
|
|
col := &columns[lx][lz]
|
|
for i := 0; i < WorldHeight; i++ {
|
|
if s := col[i]; s != StateAir {
|
|
c.SetBlock(lx, MinY+i, lz, s)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return c
|
|
}
|
|
|
|
// computeColumn fills out with the block state for each Y in one column.
|
|
func computeColumn(d worldgen.DensityFunction, wx, wz float64, out *[WorldHeight]uint16) {
|
|
var solid [WorldHeight]bool
|
|
top := -1
|
|
for i := 0; i < WorldHeight; i++ {
|
|
y := MinY + i
|
|
if d.Compute(worldgen.FunctionContext{X: wx, Y: float64(y), Z: wz}) > 0 {
|
|
solid[i] = true
|
|
top = i
|
|
}
|
|
}
|
|
|
|
for i := 0; i < WorldHeight; i++ {
|
|
y := MinY + i
|
|
switch {
|
|
case y == MinY:
|
|
out[i] = StateBedrock
|
|
case solid[i]:
|
|
switch {
|
|
case i == top && y >= SeaLevel:
|
|
out[i] = StateGrass
|
|
case i > top-4:
|
|
out[i] = StateDirt
|
|
default:
|
|
out[i] = StateStone
|
|
}
|
|
case y < SeaLevel:
|
|
out[i] = StateWater
|
|
}
|
|
}
|
|
}
|