Files
mc/server/world/generator/vanilla.go
T

114 lines
3.4 KiB
Go
Raw Normal View History

2026-07-11 00:33:35 +07:00
package generator
import (
"math"
"github.com/df-mc/dragonfly/server/block"
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
"github.com/df-mc/dragonfly/server/world/biome"
"github.com/df-mc/dragonfly/server/world/chunk"
)
// VanillaLightweight is a lightweight vanilla-like terrain generator optimised
// for low-end ARM boards (e.g. Armbian H680P). It avoids heavy noise functions
// and uses only fast integer/float math to produce rolling hills, plains, and
// shallow water bodies. Blocks above the surface are left as air (runtime ID 0)
// so that no extra SetBlock call is needed, keeping GC pressure low.
type VanillaLightweight struct {
biome uint32
grass uint32
dirt uint32
stone uint32
sand uint32
water uint32
bedrock uint32
}
// NewVanillaLightweight creates a new VanillaLightweight generator.
func NewVanillaLightweight(br world.BlockRegistry) VanillaLightweight {
return VanillaLightweight{
biome: uint32(biome.Plains{}.EncodeBiome()),
grass: br.BlockRuntimeID(block.Grass{}),
dirt: br.BlockRuntimeID(block.Dirt{}),
stone: br.BlockRuntimeID(block.Stone{}),
sand: br.BlockRuntimeID(block.Sand{}),
water: br.BlockRuntimeID(block.Water{Still: true, Depth: 8}),
bedrock: br.BlockRuntimeID(block.Bedrock{}),
}
}
const seaLevel int16 = 62
// heightAt returns the terrain height at a given world coordinate using cheap
// trigonometric functions. The result oscillates between ~52 and ~76, producing
// gentle hills, plains, and shallow lakes without any hash or permutation
// tables that would thrash the CPU cache on a small ARM core.
func heightAt(wx, wz float64) int16 {
h := 64.0 +
8.0*math.Sin(wx*0.0157)*math.Cos(wz*0.0157) +
4.0*math.Sin(wx*0.0341+wz*0.0271) +
2.0*math.Cos(wx*0.083)*math.Sin(wz*0.083)
return int16(h)
}
// GenerateChunk generates a single chunk.
func (v VanillaLightweight) GenerateChunk(pos world.ChunkPos, c *chunk.Chunk) {
min := int16(c.Range().Min())
cx, cz := int32(pos.X())<<4, int32(pos.Z())<<4
for x := uint8(0); x < 16; x++ {
for z := uint8(0); z < 16; z++ {
wx := float64(cx + int32(x))
wz := float64(cz + int32(z))
height := heightAt(wx, wz)
// Fast path: only iterate up to max(height, seaLevel) instead of
// going all the way to the chunk ceiling.
top := height
if seaLevel > top {
top = seaLevel
}
for y := min; y <= top; y++ {
c.SetBiome(x, y, z, v.biome)
switch {
case y == min:
c.SetBlock(x, y, z, 0, v.bedrock)
case y < height-3:
c.SetBlock(x, y, z, 0, v.stone)
case y < height:
c.SetBlock(x, y, z, 0, v.dirt)
case y == height:
if height < seaLevel-1 {
// Underwater floor → sand.
c.SetBlock(x, y, z, 0, v.sand)
} else {
c.SetBlock(x, y, z, 0, v.grass)
}
default:
// y > height && y <= seaLevel → water.
if y <= seaLevel {
c.SetBlock(x, y, z, 0, v.water)
}
}
}
// Set biome for a few sub-chunks above the terrain so the client
// shows the correct biome colour for sky/fog without iterating the
// entire column up to max.
for y := top + 1; y <= top+16 && y <= int16(c.Range().Max()); y++ {
c.SetBiome(x, y, z, v.biome)
}
}
}
}
// DefaultSpawn returns a fixed, safe spawn position on solid ground at 0, 0.
func (v VanillaLightweight) DefaultSpawn(dim world.Dimension) cube.Pos {
h := heightAt(0, 0)
return cube.Pos{0, int(h) + 1, 0}
}