131 lines
4.2 KiB
Go
131 lines
4.2 KiB
Go
// 村庄生成:结构 pass(村民系统.md §2、世界生态.md §3)。
|
||
//
|
||
// 规则:村庄按 384 格网格撒点(噪声抖动选位,仅平原/森林群系),
|
||
// 每个村庄水井 + 3 间房屋;建筑按绝对坐标定义,跨区块落位(世界生成.md §4)。
|
||
package worldgen
|
||
|
||
import (
|
||
"mc/internal/block"
|
||
"mc/internal/chunk"
|
||
)
|
||
|
||
// 村庄参数(村民系统.md §2)。
|
||
const (
|
||
villageSpacing = 384 // 村庄网格间距(格)
|
||
villageJitter = 96 // 中心抖动半径
|
||
villageRadius = 32 // 村庄建筑最大半径(区块跨越判定)
|
||
)
|
||
|
||
// villageCenter 返回网格点 (gx, gz) 派生出的村庄中心绝对坐标。
|
||
func (g *Generator) villageCenter(gx, gz int32) (int32, int32) {
|
||
jx := int32(g.ore.Eval2(float64(gx)*7.7+91, float64(gz)*3.1+17) * villageJitter)
|
||
jz := int32(g.ore.Eval2(float64(gx)*5.3+57, float64(gz)*8.9+29) * villageJitter)
|
||
return gx*villageSpacing + villageSpacing/2 + jx, gz*villageSpacing + villageSpacing/2 + jz
|
||
}
|
||
|
||
// placeVillage 生成跨越本区块的村庄建筑(世界生成.md §4 跨区块安全)。
|
||
func (g *Generator) placeVillage(c *chunk.Chunk, cx, cz int32) {
|
||
minX, maxX := cx*16, cx*16+15
|
||
minZ, maxZ := cz*16, cz*16+15
|
||
// 附近的网格点(±1 个网格内即可覆盖)
|
||
for dgx := int32(-1); dgx <= 1; dgx++ {
|
||
for dgz := int32(-1); dgz <= 1; dgz++ {
|
||
gx := floorDiv32(cx*16, villageSpacing) + dgx
|
||
gz := floorDiv32(cz*16, villageSpacing) + dgz
|
||
vx, vz := g.villageCenter(gx, gz)
|
||
// 村庄建筑范围与本区块相交?
|
||
if vx < minX-villageRadius || vx > maxX+villageRadius || vz < minZ-villageRadius || vz > maxZ+villageRadius {
|
||
continue
|
||
}
|
||
// 群系白名单(沙漠/雪原不建村)
|
||
b := g.biomeAt(vx, vz)
|
||
if b != biomePlains && b != biomeForest {
|
||
continue
|
||
}
|
||
// 水井 + 房屋(绝对坐标,逐块过滤到当前区块)
|
||
h := int32(g.heightAt(vx, vz))
|
||
g.placeWellAbs(c, cx, cz, vx, h, vz)
|
||
offsets := [][2]int32{{-12, -8}, {8, -10}, {-4, 12}}
|
||
for i, o := range offsets {
|
||
hx, hz := vx+o[0], vz+o[1]
|
||
hh := int32(g.heightAt(hx, hz))
|
||
g.placeHouseAbs(c, cx, cz, hx, hh, hz, uint64(gx)*73856093^uint64(gz)*19349663^uint64(i))
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// inChunk 判定绝对坐标是否属于区块 (cx, cz)。
|
||
func inChunk(x, z, cx, cz int32) bool {
|
||
return floorDiv32(x, 16) == cx && floorDiv32(z, 16) == cz
|
||
}
|
||
|
||
// setAbs 绝对坐标写入(跨区块过滤,世界生成.md §4)。
|
||
func (g *Generator) setAbs(c *chunk.Chunk, cx, cz, x, y, z int32, s block.State) {
|
||
if y < 0 || y >= chunk.Height {
|
||
return
|
||
}
|
||
if !inChunk(x, z, cx, cz) {
|
||
return
|
||
}
|
||
c.Fill(int(x-cx*16), int(y), int(z-cz*16), s)
|
||
}
|
||
|
||
// placeWellAbs 水井:圆石环 + 中心水(3×3,村民系统.md §2 布局)。
|
||
func (g *Generator) placeWellAbs(c *chunk.Chunk, cx, cz, wx, h, wz int32) {
|
||
for dx := int32(-1); dx <= 1; dx++ {
|
||
for dz := int32(-1); dz <= 1; dz++ {
|
||
if dx == 0 && dz == 0 {
|
||
g.setAbs(c, cx, cz, wx+dx, h+1, wz+dz, g.water) // 井水
|
||
} else {
|
||
g.setAbs(c, cx, cz, wx+dx, h+1, wz+dz, g.cobble) // 井沿
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// placeHouseAbs 村民房屋:木板地基 + 墙高 3(门洞)+ 平顶外沿 + 四角火把。
|
||
// 布局与 entity.Blueprint 一致(村民系统.md §6.2)。
|
||
func (g *Generator) placeHouseAbs(c *chunk.Chunk, cx, cz, hx, h, hz int32, seed uint64) {
|
||
w, d := int32(5+seed%2), int32(5) // 5–6 × 5
|
||
for x := int32(0); x < w; x++ {
|
||
for z := int32(0); z < d; z++ {
|
||
g.setAbs(c, cx, cz, hx+x, h+1, hz+z, g.planks)
|
||
}
|
||
}
|
||
// 墙(2 层,南侧门洞)
|
||
for y := int32(2); y <= 3; y++ {
|
||
for x := int32(0); x < w; x++ {
|
||
for z := int32(0); z < d; z++ {
|
||
edge := x == 0 || x == w-1 || z == 0 || z == d-1
|
||
if !edge {
|
||
continue
|
||
}
|
||
if y == 2 && z == d-1 && x == w/2 {
|
||
continue // 门洞
|
||
}
|
||
g.setAbs(c, cx, cz, hx+x, h+y, hz+z, g.planks)
|
||
}
|
||
}
|
||
}
|
||
// 屋顶外沿
|
||
for x := int32(-1); x <= w; x++ {
|
||
for z := int32(-1); z <= d; z++ {
|
||
g.setAbs(c, cx, cz, hx+x, h+4, hz+z, g.planks)
|
||
}
|
||
}
|
||
// 四角火把
|
||
for _, cc := range [4][2]int32{{0, 0}, {w - 1, 0}, {0, d - 1}, {w - 1, d - 1}} {
|
||
g.setAbs(c, cx, cz, hx+cc[0], h+3, hz+cc[1], g.torch)
|
||
}
|
||
}
|
||
|
||
// floorDiv32 负安全除法(villageCenter 网格定位)。
|
||
func floorDiv32(a, b int32) int32 {
|
||
q := a / b
|
||
if a%b < 0 {
|
||
q--
|
||
}
|
||
return q
|
||
}
|