// Package chunk 区块数据结构:一维数组 + 每区块独立锁(场景/区块管理.md §2)。 // // 布局:16×16×256 一维 []block.State(索引 (y*16+z)*16+x), // 天空光/方块光各 4-bit 打包存储(每字节 2 个方块)。 package chunk import ( "sync" "sync/atomic" "mc/internal/block" ) // 区块尺寸常量(设计.md §4.1)。 const ( SizeX = 16 // 水平 X 大小 SizeZ = 16 // 水平 Z 大小 Height = 256 // 垂直高度 SectionY = Height / 16 // section 数量(16×16×16) ) // Chunk 一个区块。锁粒度:每 Chunk 一个 RWMutex(禁止全局锁,性能与内存.md §3)。 type Chunk struct { CX, CZ int32 mu sync.RWMutex blocks []block.State // 方块状态(一维数组,cache 友好) sky []uint8 // 天空光 4-bit 打包 blockLt []uint8 // 方块光 4-bit 打包 Dirty atomic.Bool // mesh 需重建(渲染.md §3.3) LightDirty atomic.Bool // 光照需重算(光照.md) SaveDirty atomic.Bool // 需写盘(存档与持久化.md §2) } // New 创建全空气区块。 func New(cx, cz int32) *Chunk { return &Chunk{ CX: cx, CZ: cz, blocks: make([]block.State, SizeX*SizeZ*Height), sky: make([]uint8, SizeX*SizeZ*Height/2), blockLt: make([]uint8, SizeX*SizeZ*Height/2), } } // Index 计算方块数组索引:(y*16+z)*16+x。 func Index(x, y, z int) int { return (y*SizeZ+z)*SizeX + x } // Block 读取方块(读锁)。 func (c *Chunk) Block(x, y, z int) block.State { c.mu.RLock() defer c.mu.RUnlock() return c.blocks[Index(x, y, z)] } // SetBlock 写入方块并标脏(mesh + 光照 + 存档)。 func (c *Chunk) SetBlock(x, y, z int, s block.State) { c.mu.Lock() c.blocks[Index(x, y, z)] = s c.mu.Unlock() c.Dirty.Store(true) c.LightDirty.Store(true) c.SaveDirty.Store(true) } // Fill 初始化填充(生成器专用,不标存档脏:生成结果属纯函数可重算)。 func (c *Chunk) Fill(x, y, z int, s block.State) { c.blocks[Index(x, y, z)] = s } // FillAll 整块填充(生成器初始化)。 func (c *Chunk) FillAll(s block.State) { for i := range c.blocks { c.blocks[i] = s } } // SkyLight 读取天空光(4-bit,0–15)。 func (c *Chunk) SkyLight(x, y, z int) uint8 { return nibble(c.sky, Index(x, y, z)) } // SetSkyLight 写入天空光。 func (c *Chunk) SetSkyLight(x, y, z int, v uint8) { setNibble(c.sky, Index(x, y, z), v) } // BlockLight 读取方块光(4-bit,0–15)。 func (c *Chunk) BlockLight(x, y, z int) uint8 { return nibble(c.blockLt, Index(x, y, z)) } // SetBlockLight 写入方块光。 func (c *Chunk) SetBlockLight(x, y, z int, v uint8) { setNibble(c.blockLt, Index(x, y, z), v) } // nibble 读取半字节(偶数索引 → 低 4 位,奇数索引 → 高 4 位)。 func nibble(arr []uint8, idx int) uint8 { if idx&1 == 0 { return arr[idx/2] & 0xF } return arr[idx/2] >> 4 } // setNibble 写入半字节。 func setNibble(arr []uint8, idx int, v uint8) { v &= 0xF if idx&1 == 0 { arr[idx/2] = (arr[idx/2] & 0xF0) | v } else { arr[idx/2] = (arr[idx/2] & 0x0F) | (v << 4) } } // Snapshot 无锁快照(mesh 构建 goroutine 读取用;调用方需保证期间无写入)。 func (c *Chunk) Snapshot() []block.State { c.mu.RLock() defer c.mu.RUnlock() out := make([]block.State, len(c.blocks)) copy(out, c.blocks) return out }