⏳ O Continuum: Motor de crescimento e persistência offline
O Contínuo (The Continuum) é o mecanismo de simulação principal. No vanilla, o crescimento cessa ao descarregar chunks. The Continuum soluciona isso salvando horários e simulando crescimento offline suavemente ao carregar.
📊 Infobox de especificações técnicas
| 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) |
| Limite de Atualizações | CROPS_PER_TICK = 5 (Fila global suave) |
| Palette Pre-Filter | section.hasOnlyAir() & section.maybeHas(AgrarianCropRules::isCropBlock) |
| Limite de Antiguidade | Entradas com mais de 30 dias reais ($51,840,000\text{ ticks}$) são limpas ao salvar |
| Plantas Suportadas | Todas as plantações, cana, cacto, fungo do Nether, cacau, vinhas, mudas, bagas |
⚙️ Como o Continuum funciona
┌─────────────────────────────────────────────────────────────┐
│ 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 │
└─────────────────────────────────────────────────────────────┘📐 Fórmulas matemáticas de compensação
$$\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. Plantações padrão (CropBlock & mods)
$$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. Altura de cana e cactos
$$\Delta \text{age} = \left\lfloor \frac{\Delta t_{\text{effective}}}{1365} \right\rfloor$$
3. Intervalos de outros vegetais
| Tipo de Planta | Ticks por Estágio | Probabilidade por Tick | Estágio Máx / Limite |
|---|---|---|---|
| Fungo do Nether | 13,650 ticks (~11.37 min) | 10% por tick aleatório | Estágio 3 |
| Cacau | 6,825 ticks (~5.68 min) | 20% por tick aleatório | Estágio 2 |
| Bagas Doces | 6,825 ticks (~5.68 min) | 20% por tick aleatório | Estágio 3 |
| Vinhas | 13,650 ticks (~11.37 min) | 10% por tick aleatório | Propagação para baixo |
| Mudas de Árvore | 95,550 ticks (~79.6 min) | 1.4% por tick aleatório | Estágio 2 (Vira árvore) |
⚡ Otimizações de desempenho
1. Sub-Chunk Palette-Level Pre-Filtering
Em vez de percorrer $98.304$ blocos, o CropScanner lê as paletas das seções $16 \times 16 \times 16$ LevelChunkSection:
section.hasOnlyAir(): Pula sub-chunks vazios em $0.0001\mu\text{s}$.section.maybeHas(AgrarianCropRules::isCropBlock): Consulta a paleta. Sem plantações, todos os 4.096 blocos são ignorados na hora. Isso descarta entre 85% e 95% das seções sem nenhum impacto de desempenho.
2. Limpeza de registros com mais de 30 dias
$$\text{Max Timestamp Age} = 30\text{ days} \times 86,400\text{ s/day} \times 20\text{ ticks/s} = 51,840,000\text{ ticks}$$ Durante autosaves (BEFORE_SAVE), dados mais antigos que 30 dias reais são apagados do arquivo e da memória.
💾 Persistência de chunks e zero escrituras em disco
- Horários desacoplados: Ficam guardados em
ContinuumData, deixandoLevelChunk.unsavedemfalse. - Verificação só leitura: Examina paletas sem marcar o chunk como alterado.
- Escrita condicional: O
level.setBlock()só é chamado se houver crescimento real ($\Delta \text{age} > 0$), economizando gravações em disco ($0\text{ I/O de disco}$).
See also: Desempenho e controle de filas, Registro de plantas e culturas universais, and Arquitetura e mixins.
