⏳ 时空连续体:作物离线持久化生长模拟引擎
时空连续体(The Continuum) 是 Agrarian Reform 的核心仿真引擎。在原版 Minecraft 中,区块卸载或服务器关闭的瞬间作物生长便完全停滞。时空连续体 通过持久化区块卸载时间戳并在重新加载时平滑追赶真实流逝时间,完美弥补了这一断层,且绝不引发瞬间卡顿。
📊 核心技术特性信息框
| Component | Specification |
|---|---|
| Engine Class | net.instantgratification.agrarianreform.continuum.ContinuumManager |
| Data Handler | net.instantgratification.agrarianreform.continuum.ContinuumData |
| Scanner Helper | net.instantgratification.agrarianreform.continuum.CropScanner |
| Saved Data ID | agrarian_reform_continuum (Dimension-scoped SavedDataType) |
| 更新限流额度 | CROPS_PER_TICK = 5(全局无锁队列平滑节流) |
| Palette Pre-Filter | section.hasOnlyAir() & section.maybeHas(AgrarianCropRules::isCropBlock) |
| 陈旧记录上限 | 超过 30 个真实日($51,840,000\text{ 刻}$)在存档时自动清理 |
| 支持植物类型 | 全能通用作物、甘蔗、仙人掌、下界疣、可可豆、藤蔓、树苗、甜浆果 |
⚙️ 时空连续体运行机制
┌─────────────────────────────────────────────────────────────┐
│ CHUNK UNLOAD EVENT │
│ ServerChunkEvents.CHUNK_UNLOAD records server game time pos │
│ Saved to world storage via ContinuumData (SavedDataType) │
└──────────────────────────────┬──────────────────────────────┘
│
▼ (Offline / World Unloaded Time Delta)
┌──────────────────────────────┴──────────────────────────────┐
│ CHUNK LOAD EVENT │
│ ServerChunkEvents.CHUNK_LOAD retrieves unload timestamp │
│ Calculates timeDelta = currentTick - unloadTick │
└──────────────────────────────┬──────────────────────────────┘
│
▼
┌──────────────────────────────┴──────────────────────────────┐
│ SUB-CHUNK PALETTE-GATED SCANNER │
│ CropScanner skips empty air & non-crop sections (O(1)) │
│ Queues matching plants into ConcurrentLinkedQueue │
└──────────────────────────────┬──────────────────────────────┘
│
▼
┌──────────────────────────────┴──────────────────────────────┐
│ THROTTLED PER-CROP TICK PROCESSOR │
│ ServerTickEvents.END_SERVER_TICK processes 5 crops/tick │
│ Scales delta per-crop via AgrarianCropRules & updates state │
└─────────────────────────────────────────────────────────────┘📐 数学补算模型与公式
$$\Delta t_{\text{effective}} = \begin{cases} 0 & \text{if } M_{\text{crop}} \le 0 \ \left\lfloor \frac{\Delta t \cdot M_{\text{crop}}}{100} \right\rfloor & \text{if } M_{\text{crop}} > 0 \end{cases}$$
1. 标准作物 (CropBlock 与模组作物)
$$S = \text{CropScanner.getSpeed}(\text{crop}, \text{level}, \text{pos})$$ $$T_{\text{stage}} = \left( \frac{25.0}{S} + 1.0 \right) \cdot \frac{4096.0}{3.0}$$ $$\Delta \text{age} = \left\lfloor \frac{\Delta t_{\text{effective}}}{T_{\text{stage}}} \right\rfloor$$
2. 甘蔗与仙人掌柱状高度
$$\Delta \text{age} = \left\lfloor \frac{\Delta t_{\text{effective}}}{1365} \right\rfloor$$
3. 其他植物阶段时间间隔
| 植物类型 | 单阶段刻数 | 随机刻基础概率 | 最大阶段 / 限制 |
|---|---|---|---|
| 下界疣 | 13,650 刻 (~11.37 分钟) | 每随机刻 10% | 阶段 3 |
| 可可豆 | 6,825 刻 (~5.68 分钟) | 每随机刻 20% | 阶段 2 |
| 甜浆果丛 | 6,825 刻 (~5.68 分钟) | 每随机刻 20% | 阶段 3 |
| 藤蔓 | 13,650 刻 (~11.37 分钟) | 每随机刻 10% | 向下蔓延生长 |
| 树苗 | 95,550 刻 (~79.6 分钟) | 每随机刻 1.4% | 阶段 2 (触发长成大树) |
⚡ 极限性能优化策略
1. Sub-Chunk Palette-Level Pre-Filtering
与遍历已加载区块内全部 $98,304$ 个三维坐标不同,CropScanner 对每个 $16 \times 16 \times 16$ 的 LevelChunkSection 实施子区块调色板过滤:
section.hasOnlyAir():在 $0.0001\mu\text{s}$ 内瞬间跳过全空子区块。section.maybeHas(AgrarianCropRules::isCropBlock):直接检索调色板数组。若不含农作物方块,4,096 格的大区域即刻跳过。 这一优化在零体素遍历开销下直接排除了 85% 至 95% 的非农业子区块。
2. 30 天过期时间戳自动清理
$$\text{Max Timestamp Age} = 30\text{ days} \times 86,400\text{ s/day} \times 20\text{ ticks/s} = 51,840,000\text{ ticks}$$ 在周期性自动保存时(ServerLifecycleEvents.BEFORE_SAVE),超过 30 天真实时间的记录将自动从内存和文件中清除。
💾 区块持久化与零磁盘写入保证
- 世界级解耦时间戳:区块卸载时间戳保存在独立的
ContinuumData中,使区块本身的LevelChunk.unsaved依然保持false。 - 100% 只读区块加载检测:基于调色板预过滤检查方块,绝不污染区块脏状态。
- 条件式方块状态写入:仅当作物产生实际成长($\Delta \text{age} > 0$)时才调用
level.setBlock(),避免多余的磁盘 I/O($0\text{ 磁盘写入}$)。
See also: 性能优化与队列节流, 作物注册表与通用作物, and 架构设计与 Mixin 注入参考.
