⚡ 性能优化与队列节流引擎
Agrarian Reform 专为高负载服务器精心设计,即便承载万人级农业巨型农场也不会引起瞬间卡顿、看门狗超时或 TPS 下降。
📊 性能技术指标信息框
| Property | Value |
|---|---|
| Global Throttling Budget | CROPS_PER_TICK = 5 |
| Queue Implementation | java.util.concurrent.ConcurrentLinkedQueue |
| Sub-Chunk Palette Filter | hasOnlyAir() & maybeHas(AgrarianCropRules::isCropBlock) |
| 水分检索机制 | 切比雪夫同心环方块扫描 ($r=1 \to \text{maxRange}$,临近水源极速跳出) |
| 靴子优化防抖 | 赤足极速快速判断 ($0.0001\mu\text{s}$,跳过开销巨大的附魔查询) |
| 运行诊断日志 | 静态 SLF4J 记录器,受瞬态游戏规则 agrarian_reform:debug_mode 管控 |
🧠 架构设计与快速跳过流水线
┌─────────────────────────────────────────────────────────────┐
│ CHUNK LOAD SCAN EVENT │
│ Palette Pre-Filter: section.hasOnlyAir() & maybeHas() │
│ Rejects 85%+ empty non-crop sub-chunks in O(1) time │
└──────────────────────────────┬──────────────────────────────┘
│
▼
┌──────────────────────────────┴──────────────────────────────┐
│ ConcurrentLinkedQueue<CropUpdateTask> │
│ Lock-free thread-safe task buffer │
└──────────────────────────────┬──────────────────────────────┘
│
▼
┌──────────────────────────────┴──────────────────────────────┐
│ ServerTickEvents.END_SERVER_TICK │
│ Polls at most 5 tasks per tick │
│ Updates block states smoothly across consecutive game ticks │
└─────────────────────────────────────────────────────────────┘为什么每刻处理 5 处作物?
当玩家在卸载包含 10,000 处作物的农场 24 小时后重新加载时,若在一刻内同时触发 10,000 次方块状态更新,会导致服务器产生超过 1000ms 的严重卡死。
通过无锁并发地以每刻 5 处作物的速率分摊更新:
- 区块加载期间服务器 TPS 依然牢牢稳固在 20 TPS。
- 10,000 处作物在后台平滑过渡 2,000 刻(约 100 秒)即可全部追赶完毕,丝毫不影响正常游玩与网络延迟。
🏎️ 核心快速跳过与算法优化
- 子区块调色板快速排查:取代逐一扫描区块内 $98,304$ 个方块坐标的方式,
CropScanner直接检索子区块调色板。若一个 $16 \times 16 \times 16$ 的子区块不含农业方块,整段区域将在 $0.0001\mu\text{s}$ 内瞬间跳过。 - 切比雪夫同心环由内向外扫描:耕地水分计算由最近的方形环($r = 1 \to \text{maxRange}$)逐步外扩。由于多数耕地紧邻水源($r=1$),在第一环命中后即刻判定完成,无需遍历全部 $17 \times 17$ 位置。
- 赤足踩踏防抖:实体接触耕地时,
GrowthHelper.hasSoftStep()首先检查脚部装备槽是否为空。若为空,则彻底跳过复杂的 NBT 附魔遍历。 - 最大成熟期立即跳出:在高倍率生长循环中,一旦作物达到最大成熟度,循环即刻终止,避免无效的方块状态写入。
💾 零磁盘写入保障与脏状态维护
- 只读区块表面快速扫描:初始加载扫描 100% 只读,绝不调用
LevelChunk.setBlockState(),保持区块内部unsaved标识为false。 - 精细化方块状态写入:在
ContinuumManager.processCropUpdate中,仅当阶段增量 $\Delta \text{age} > 0$ 时才调用level.setBlock()。 - 原生零磁盘 I/O 保护:未改动区块保持
unsaved == false,Minecraft 原生ChunkMap.save()会直接跳过 NBT 序列化与.mca写入($0\text{ 磁盘写入开销}$)。
See also: 时空连续体 (离线生长模拟), 水动力学与灌溉系统, and 架构设计与 Mixin 注入参考.
