// Package redstone 方块更新队列与红石信号传播(场景/红石与方块更新.md §2–§3)。 // // 设计要点: // - 延迟更新队列(0/1/2/4 tick)+ 每 tick 迭代上限(防无限递归); // - 红石信号 0–15,仅沿线缆传播(每格衰减 1),与方块光完全分离。 package redstone import ( "sync" ) // 更新类型(红石与方块更新.md §2)。 const ( KindNeighbor = 0 // 邻居变化 KindScheduled = 1 // 定时刻(延迟更新) KindBlockEntity = 2 // 方块实体 tick ) // 迭代上限(红石与方块更新.md §2:每 tick 20000,防级联风暴)。 const DefaultIterLimit = 20000 // Update 一个方块更新事件。 type Update struct { X, Y, Z int32 Kind uint8 Delay int // 剩余延迟 tick } // Queue 延迟更新队列(有序消费)。 type Queue struct { mu sync.Mutex events []Update iterCap int dropped int // 超限丢弃计数(告警用) } // NewQueue 创建队列。 func NewQueue() *Queue { return &Queue{iterCap: DefaultIterLimit} } // Push 入队。 func (q *Queue) Push(u Update) { q.mu.Lock() q.events = append(q.events, u) q.mu.Unlock() } // Pending 待处理事件数。 func (q *Queue) Pending() int { q.mu.Lock() defer q.mu.Unlock() return len(q.events) } // Dropped 返回被丢弃的事件数(迭代上限触发次数)。 func (q *Queue) Dropped() int { q.mu.Lock() defer q.mu.Unlock() return q.dropped } // Tick 每 tick 消费队列:延迟递减,到期的事件交给 handle 处理。 // 处理数量受 iterCap 限制;超限事件丢弃并计数(红石与方块更新.md §6 踩坑)。 func (q *Queue) Tick(handle func(u Update)) { q.mu.Lock() kept := q.events[:0] var due []Update for _, u := range q.events { if u.Delay > 0 { u.Delay-- kept = append(kept, u) continue } due = append(due, u) } q.events = kept q.mu.Unlock() processed := 0 for _, u := range due { if processed >= q.iterCap { q.mu.Lock() q.dropped++ q.mu.Unlock() continue } handle(u) processed++ } } // 红石信号(红石与方块更新.md §3:0–15,与方块光分离)。 // Src 信号源。 type Src struct { X, Y, Z int32 Level uint8 // 0–15 } // SpreadWire 红石信号沿线缆传播:每格衰减 1,仅经过 isWire 判定的线缆格。 // set 写信号值;返回值无(传播结果由调用方通过 set 收集)。 // 与光照 Propagate 的关键区别:红石只走线缆、不穿过所有方块(红石与方块更新.md §6 踩坑)。 func SpreadWire(sources []Src, isWire func(x, y, z int32) bool, set func(x, y, z int32, v uint8)) { type pos struct{ x, y, z int32 } q := make([]pos, 0, 64) power := make(map[pos]uint8, 64) for _, s := range sources { p := pos{s.X, s.Y, s.Z} power[p] = s.Level set(p.x, p.y, p.z, s.Level) q = append(q, p) } dirs := [6][3]int32{{1, 0, 0}, {-1, 0, 0}, {0, 1, 0}, {0, -1, 0}, {0, 0, 1}, {0, 0, -1}} for len(q) > 0 { p := q[0] q = q[1:] lv := power[p] if lv <= 1 { continue } for _, d := range dirs { n := pos{p.x + d[0], p.y + d[1], p.z + d[2]} if !isWire(n.x, n.y, n.z) { continue } if old, ok := power[n]; !ok || old < lv-1 { power[n] = lv - 1 set(n.x, n.y, n.z, lv-1) q = append(q, n) } } } }