⏳ 時空連續體:作物離線持久化生長模擬引擎
時空連續體(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 注入參考.
