Skip to content

⏳ 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

ComponentSpecification
Engine Classnet.instantgratification.agrarianreform.continuum.ContinuumManager
Data Handlernet.instantgratification.agrarianreform.continuum.ContinuumData
Scanner Helpernet.instantgratification.agrarianreform.continuum.CropScanner
Saved Data IDagrarian_reform_continuum (Dimension-scoped SavedDataType)
Limite de AtualizaçõesCROPS_PER_TICK = 5 (Fila global suave)
Palette Pre-Filtersection.hasOnlyAir() & section.maybeHas(AgrarianCropRules::isCropBlock)
Limite de AntiguidadeEntradas com mais de 30 dias reais ($51,840,000\text{ ticks}$) são limpas ao salvar
Plantas SuportadasTodas 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 PlantaTicks por EstágioProbabilidade por TickEstágio Máx / Limite
Fungo do Nether13,650 ticks (~11.37 min)10% por tick aleatórioEstágio 3
Cacau6,825 ticks (~5.68 min)20% por tick aleatórioEstágio 2
Bagas Doces6,825 ticks (~5.68 min)20% por tick aleatórioEstágio 3
Vinhas13,650 ticks (~11.37 min)10% por tick aleatórioPropagação para baixo
Mudas de Árvore95,550 ticks (~79.6 min)1.4% por tick aleatórioEstá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:

  1. section.hasOnlyAir(): Pula sub-chunks vazios em $0.0001\mu\text{s}$.
  2. 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

  1. Horários desacoplados: Ficam guardados em ContinuumData, deixando LevelChunk.unsaved em false.
  2. Verificação só leitura: Examina paletas sem marcar o chunk como alterado.
  3. 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.

Official documentation & web portal for Dasik Igaijinn mods.