⏳ コンティニュアム: オフライン作物成長持続エンジン
**時空連続体(The Continuum)**は本作の看板シミュレーションエンジンです。バニラではチャンクアンロード時に作物の成長が停止しますが、The Continuumはアンロード時刻を記憶し、再読込時に実時間に応じた成長をスムーズに再現します。
📊 技術仕様インフォボックス
| 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{ ticks}$)以上経過した記録は保存時に自動削除 |
| 対応植物 | 一般作物、サトウキビ、サボテン、ネザーウォート、カカオ、ツタ、苗木、スイートベリー |
⚙️ コンティニュアムの動作原理
┌─────────────────────────────────────────────────────────────┐
│ 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およびMOD作物)
$$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 ticks (~11.37分) | 確率10% | 段階3 |
| カカオ豆 | 6,825 ticks (~5.68分) | 確率20% | 段階2 |
| スイートベリー | 6,825 ticks (~5.68分) | 確率20% | 段階3 |
| ツタ | 13,650 ticks (~11.37分) | 確率10% | 下方向への伝播 |
| 苗木 | 95,550 ticks (~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}$$ 定期自動保存時(BEFORE_SAVE)、30日以上経過した記録はメモリとディスクから自動的に削除されます。
💾 チャンク永続化とディスク書き込みゼロ保証
- 疎結合タイムスタンプ保存:
ContinuumDataに保存されるため、チャンク自体のunsavedフラグはfalseを維持します。 - 純粋読み取りスキャン:パレットチェックのみを行い、チャンクを変更済みにしません。
- 条件付きブロック書き込み:実際に成長が進んだ場合($\Delta \text{age} > 0$)のみ
setBlock()を呼び出し、不要なディスク書き込みを防ぎます($0\text{ ディスクI/O}$)。
See also: パフォーマンスとキュー調整, 作物レジストリと汎用作物, and アーキテクチャと Mixin ターゲット.
