Skip to content

⏳ El Continuo: Motor de persistencia y crecimiento offline

El Continuo (The Continuum) es el motor de simulación insignia. En vanilla, el crecimiento se detiene al descargar el chunk. The Continuum guarda marcas temporales y simula el crecimiento offline en tiempo real sin congelar el servidor.


📊 Infobox de especificaciones 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)
Límite de actualizaciónCROPS_PER_TICK = 5 (Cola global regulada sin bloqueos)
Palette Pre-Filtersection.hasOnlyAir() & section.maybeHas(AgrarianCropRules::isCropBlock)
Caducidad de marcasEntradas de más de 30 días reales ($51,840,000\text{ ticks}$) se eliminan al guardar
Plantas compatiblesCultivos universales, caña de azúcar, cactus, verruga del Nether, cacao, lianas, brotes, bayas

⚙️ Cómo funciona El Continuo

┌─────────────────────────────────────────────────────────────┐
│                     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 compensación

$$\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. Cultivos estándar (CropBlock y 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 caña de azúcar y cactus

$$\Delta \text{age} = \left\lfloor \frac{\Delta t_{\text{effective}}}{1365} \right\rfloor$$

3. Intervalos de fases de otras plantas

Tipo de plantaTicks por faseProbabilidad por tickFase máx / Límite
Verruga del Nether13,650 ticks (~11.37 min)10% por tick aleatorioFase 3
Vainas de cacao6,825 ticks (~5.68 min)20% por tick aleatorioFase 2
Arbusto de bayas6,825 ticks (~5.68 min)20% por tick aleatorioFase 3
Lianas13,650 ticks (~11.37 min)10% por tick aleatorioPropagación hacia abajo
Brotes de árbol95,550 ticks (~79.6 min)1.4% por tick aleatorioFase 2 (Crecimiento de árbol)

⚡ Optimizaciones de rendimiento

1. Sub-Chunk Palette-Level Pre-Filtering

En lugar de examinar $98,304$ coordenadas, CropScanner consulta la paleta de cada LevelChunkSection de $16 \times 16 \times 16$:

  1. section.hasOnlyAir(): Descarta sub-chunks vacíos en $0.0001\mu\text{s}$.
  2. section.maybeHas(AgrarianCropRules::isCropBlock): Consulta la paleta. Si no hay cultivos, se descartan los 4,096 bloques. Esto rechaza entre un 85% y un 95% de sub-chunks sin plantas agrícolas sin coste de iteración.

2. Purga de marcas temporales de más de 30 días

$$\text{Max Timestamp Age} = 30\text{ days} \times 86,400\text{ s/day} \times 20\text{ ticks/s} = 51,840,000\text{ ticks}$$ Durante los guardados automáticos (BEFORE_SAVE), las entradas con más de 30 días reales se eliminan de memoria y disco.


💾 Persistencia de chunks y cero escrituras en disco

  1. Marcas desacopladas: Se almacenan en ContinuumData, manteniendo el flag LevelChunk.unsaved en false.
  2. Escaneo de lectura pura: Inspecciona estados de bloques sin ensuciar el chunk.
  3. Modificación condicional: Solo se llama a level.setBlock() si hay crecimiento real ($\Delta \text{age} > 0$), ahorrando escrituras en disco ($0\text{ I/O de disco}$).

See also: Rendimiento y control de colas, Registro de cultivos y soporte universal, and Arquitectura y mixins.

Official documentation & web portal for Dasik Igaijinn mods.