Skip to content

⏳ Le Continuum : Moteur de persistance et croissance hors-ligne

Le Continuum (The Continuum) est le moteur de simulation phare. En vanilla, la pousse cesse au déchargement d'un chunk. The Continuum comble ce manque en conservant l'horodatage et en simulant la pousse hors-ligne sans à-coups.


📊 Infobox des spécifications techniques

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)
Cadence de mise à jourCROPS_PER_TICK = 5 (File d'attente globale régulée)
Palette Pre-Filtersection.hasOnlyAir() & section.maybeHas(AgrarianCropRules::isCropBlock)
Plafond d'obsolescenceEntrées de plus de 30 jours réels ($51,840,000\text{ ticks}$) purgées à la sauvegarde
Plantes prises en chargeToutes cultures, canne à sucre, cactus, verrues du Nether, cacao, lianes, pousses, baies

⚙️ Fonctionnement du Continuum

┌─────────────────────────────────────────────────────────────┐
│                     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 │
└─────────────────────────────────────────────────────────────┘

📐 Formules mathématiques de rattrapage

$$\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. Cultures courantes (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. Hauteur de la canne à sucre et des cactus

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

3. Intervalles de stades d'autres plantes

Type de planteTicks par stadeProbabilité par tickStade max / Limite
Verrue du Nether13,650 ticks (~11.37 min)10% par tick aléatoireStade 3
Gousses de cacao6,825 ticks (~5.68 min)20% par tick aléatoireStade 2
Baies sucrées6,825 ticks (~5.68 min)20% par tick aléatoireStade 3
Lianes13,650 ticks (~11.37 min)10% par tick aléatoirePropagation vers le bas
Pousses d'arbres95,550 ticks (~79.6 min)1.4% par tick aléatoireStade 2 (Arbre formé)

⚡ Optimisations de performances

1. Sub-Chunk Palette-Level Pre-Filtering

Au lieu de scanner $98,304$ blocs, CropScanner interroge la palette de chaque section $16 \times 16 \times 16$ LevelChunkSection :

  1. section.hasOnlyAir() : Ignore les sous-chunks vides en $0.0001\mu\text{s}$.
  2. section.maybeHas(AgrarianCropRules::isCropBlock) : Vérifie la palette. Sans cultures, les 4 096 blocs sont directement passés. Cela élimine 85% à 95% des sections non agricoles sans charge de calcul.

2. Purge des horodatages obsolètes après 30 jours

$$\text{Max Timestamp Age} = 30\text{ days} \times 86,400\text{ s/day} \times 20\text{ ticks/s} = 51,840,000\text{ ticks}$$ Lors des sauvegardes automatiques (BEFORE_SAVE), les données vieilles de plus de 30 jours sont supprimées.


💾 Persistance des chunks et 0 écriture sur disque

  1. Horodatage découplé : Enregistré dans ContinuumData, laissant LevelChunk.unsaved à false.
  2. Scan en lecture seule : Analyse les blocs sans marquer le chunk comme modifié.
  3. Écriture sélective : level.setBlock() n'est appelé que si la plante a réellement évolué ($\Delta \text{age} > 0$), évitant des écritures disque ($0\text{ I/O disque}$).

See also: Performances et régulation de file d'attente, Registre des plantes et cultures universelles, and Architecture et cibles Mixin.

Official documentation & web portal for Dasik Igaijinn mods.