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} }