Skip to content

⏳ Континуум: Движок офлайн-роста растений

Континуум (The Continuum) — ведущий движок симуляции. В ванильном Minecraft рост останавливается при выгрузке чанка. The Continuum сохраняет временные метки выгрузки и плавно симулирует прошедшее время без лагов.


📊 Инфоблок технических характеристик

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)
Бюджет очередиCROPS_PER_TICK = 5 (Глобальная очередь без блокировок)
Palette Pre-Filtersection.hasOnlyAir() & section.maybeHas(AgrarianCropRules::isCropBlock)
Предел устареванияЗаписи старше 30 реальных дней ($51,840,000\text{ тактов}$) удаляются
Поддерживаемые культурыВсе культуры, тростник, кактус, адский нарост, какао, лианы, саженцы, ягоды

⚙️ Как работает Континуум

┌─────────────────────────────────────────────────────────────┐
│                     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 и моды)

$$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 тактов (~11.37 мин)10% за случайный тактСтадия 3
Какао-бобы6,825 тактов (~5.68 мин)20% за случайный тактСтадия 2
Сладкие ягоды6,825 тактов (~5.68 мин)20% за случайный тактСтадия 3
Лианы13,650 тактов (~11.37 мин)10% за случайный тактРост вниз
Саженцы95,550 тактов (~79.6 мин)1.4% за случайный тактСтадия 2 (Рост дерева)

⚡ Оптимизация производительности

1. Sub-Chunk Palette-Level Pre-Filtering

Вместо перебора всех $98,304$ блоков CropScanner использует фильтрацию палитры для каждой секции $16 \times 16 \times 16$ LevelChunkSection:

  1. section.hasOnlyAir(): Пропускает пустые подчанки за $0.0001\mu\text{s}$.
  2. 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 реальных дней удаляются из памяти и диска.


💾 Сохранение чанков и нулевая запись на диск

  1. Независимое сохранение времени: Временные метки хранятся в ContinuumData, сохраняя флаг LevelChunk.unsaved в false.
  2. Чтение без изменения чанков: Проверка палитр не помечает чанки измененными.
  3. Запись только при росте: Вызов level.setBlock() происходит только при реальном приросте ($\Delta \text{age} > 0$), защищая диск от лишней записи ($0\text{ Disk I/O}$).

See also: Производительность и ограничение очереди, Реестр растений и универсальные культуры, and Архитектура и миксины.

Official documentation & web portal for Dasik Igaijinn mods.