vernadsky
Физическая география планеты: рельеф, вода, климат, биомы, стабильные идентификаторы. Не знает об игре.
Зачем это нужно
Планету для игры проще сгенерировать, чем нарисовать: карта нужна на тысячу провинций, и она должна быть правдоподобной. Рельеф, реки, климат и биомы связаны между собой, поэтому генерируются стадиями, каждая следующая опирается на предыдущие.
Генератор намеренно нейтрален: он описывает физическую географию и ничего не знает о фракциях, экономике, игровых провинциях и правилах симуляции. Базовая единица деления карты называется территория — географическая единица без игровой семантики. Провинция, государство или морская зона — то, что читатель данных собирает из территорий и клеток уже на своей стороне.
Предыдущая попытка, mapgen, была единым крейтом под конкретную игру.
vernadsky — то, во что она выросла: алгоритмы (рельеф, биомы, климат,
разбиение на территории) перенесены, а границы проведены заново.
Как устроено
Репозиторий — это Cargo workspace из восьми крейтов. Стадии идут в фиксированном порядке, и каждая работает с тем, что оставила предыдущая:
core → terrain → climate → biome → hydrology → territory →
export → tools
Вход всего конвейера — зерно и параметры; skeleton_world(width, height, seed)
в vernadsky-core создаёт пустую сетку нужного размера, которую дальше
заполняют стадии. Результат — одно значение GeographicWorld, которое можно
сразу записать в файл экспорта.
Стадии
- core (
vernadsky-core) — контракт данных: схемаGeographicWorld, целочисленные решётки физических величин, пространства идентификаторов, канонический бинарный экспорт. Единственное место, где числа с плавающей точкой превращаются в экспортируемые значения. - terrain — рельеф: fBm-шум OpenSimplex2 на цилиндре (карта бесшовна по x,
полюса зажимаются), эффект острова, сглаживание, степенная коррекция и
нормировка min/max с целевой долей суши. На выходе — метры: уровень моря
0.5соответствует0 м, шкала до ±6000 м. Эрозия подключается профилем (температурное выветривание и гидравлические капли из потокаterrain.erosion). - climate — среднегодовая температура, относительная влажность и осадки
по клеткам, пересчитанные в физические единицы (°C, %, мм/год); шум
температуры берётся из потока
climate.temperature. - biome — таблица из шестнадцати биомов как упорядоченные наборы правил
(вода → горы → климат), все пороги лежат на решётках, граница между биомами
дизерится по клеткам. Реестр
biomes-v1владеет соответствием идентификатор ↔ имя ↔ категория ↔ канонический цвет. - hydrology — водоёмы и речная сеть. Водоёмы классифицируются заливкой от
полюса: океан, а замкнутые компоненты делятся на моря и озёра по площади.
Реки строятся по накоплению стока — маршрутизация по убыванию высоты с
каноническими разрешениями ничьих; лёд блокирует сток, пустыни испаряют
половину. Порог дренажа задаётся долей от клеток суши (
0.12 %), поэтому сеть остаётся тонкой и ветвящейся на любой сетке. - territory — разбиение карты на территории: кандидаты на суше взвешиваются по климату и высоте, зёрна берутся равномерно по спектру весов, рост идёт многоисточниковым BFS с заполнением по ближайшему центроиду. Вода делится по связным компонентам, так что море никогда не остаётся одним неделимым пространством. Здесь же — регионы: континенты и морские бассейны как компоненты связности графа соседства территорий.
- export — производные признаки: стартовый природный потенциал каждой территории суши (комфорт по температуре × влажность × равнинность, в промилле 0…1000) и нейтральные географические факты — близость к морю, устья рек, горный рельеф — как детерминированные запросы, которые потребитель трактует как порты, эстуарии и перевалы.
- tools — отладочная утилита: рендерит слои мира и пишет экспорт.
Две стадии — territory и hydrology — не потребляют случайность вообще:
их результат полностью определяется предыдущими стадиями.
Контракт
Данные, которые отдаёт генератор:
- Схема
GeographicWorldверсии 1. Идентификаторы клеток, территорий, регионов, водоёмов, рек и биомов — часть публичного контракта: по ним потребители связывают данные между экспортами, поэтому смена способа вывода идентификаторов — ломающее изменение. - Решётки. Все физические величины пересекают границу стадии и попадают в экспорт только как целые значения решёток. Это снимает вопрос платформенной арифметики: сравнивать и хешировать приходится целые.
- Экспорт. Канонический бинарный формат: magic
VGW\0, целые фиксированной ширины little-endian, у каждой переменной секции счётчикu32. В конце —content_hash(FNV-1a 64 по всем предыдущим байтам): это проверка целостности и воспроизводимости. - Версии. Файл несёт версию схемы, стратегию идентификаторов, версию
реестра решёток и версию реестра биомов (
biomes-v1) — файл самодостаточен для интерпретации.
Детерминизм и управляемый дрейф
Генерация — чистая функция от зерна и параметров: одни и те же входы дают байт в байт одинаковый результат на каждом запуске и каждой поддерживаемой платформе.
Случайность берётся из именованных потоков (rng-streams-v1): поток ChaCha8
выводится из зерна мира и имени, закреплённого за стадией. Потоки независимы и
перезапускаемы, поэтому добавление новой механики не сдвигает поведение уже
существующих.
Чтобы это не разъехалось молча, в репозитории лежат золотые манифесты: набор семян (включая граничные значения) с закреплёнными хешами полных экспортов и канарейка чувствительности хеша. Случайная недетерминированность или дрейф схемы валят тесты.
Дрейф контента при этом бывает осознанным. Таких правок три, и каждая оформлена явно — с повышением версии параметров и перегенерацией золотых манифестов:
- Порог дренажа рек стал независим от разрешения сетки (параметры v3).
- Шум рельефа нормируется в пространстве карты: число базовых объектов —
доля окружности карты (
features_across, по умолчанию1.5), а не частота на клетку, плюс нижний предел детализации (min_feature_cells, по умолчанию8) против прибрежного «шума». Теперь любое разрешение рисует одну и ту же планету, а не рассыпается в архипелаг при росте сетки. - Сглаживание рельефа стало бесшовным по x (пока в невыпущенном разделе): раньше горизонтальное окно блюра зажималось на краях карты, и рельеф ломался на шве, хотя шум, подъём острова и эрозия уже замыкались по цилиндру.
Как получить такую карту
Сам генератор — библиотека; посмотреть на результат удобнее отладочной утилитой
vernadsky-tools. Это инструмент диагностики, не часть контракта генератора:
тяжёлые зависимости вроде image живут только в его крейте. Из входов нужен
только seed — остальное имеет значения по умолчанию.
cargo run -p vernadsky-tools -- render --seed 42 --grid-height 512 --width 512 --out map
Утилита собирает мир из семени через весь конвейер и растеризует каждый слой в
свой PNG: имя файла — <out>.<слой>.png, слой рисуется отдельной картой.
map.height.png— высота;map.water.png— вода;map.rivers.png— реки;map.temperature.png,map.humidity.png,map.precipitation.png— климат;map.biome.png— биомы;map.territory.png,map.regions.png— территории и регионы;map.potential.png— природный потенциал.
По умолчанию сетка 48×32, разбиение — 12 территорий суши и 8 водных. Ключи
--width и --grid-height задают разрешение, --land-count и --water-count —
разбиение, --zoom увеличивает картинку целым множителем (до 16×), если клеток
мало и результат нужно рассмотреть.
Тот же мир сохраняется как канонический экспорт и читается обратно:
cargo run -p vernadsky-tools -- dump --seed 42 --width 512 --grid-height 512 --out world.gwb
cargo run -p vernadsky-tools -- validate --input world.gwbworld written to world.gwb (262144 cells, 20 territories, pipeline 1.60s)
valid export world.gwb: 512×512 cells, 20 territories, 7 regions, 4 water bodies, 293 rivers; seed 0x000000000000002a, params version 4
Время конвейера зависит от машины; остальное — из самого файла. Мир можно читать
и из экспорта, а не только из семени: render --input world.gwb рисует те же слои
по уже собранному файлу.
Что получилось
Одна команда выше, семя 42, сетка 512×512: 262 144 клетки, 20 территорий, 7 регионов, 4 водоёма и 293 реки. Климатические слои рисуются на фиксированных физических шкалах — поэтому картинки разных семян сравнимы между собой. В категориальных слоях правила тоже фиксированы: биомы берут канонические цвета реестра, территории и регионы — детерминированную палитру.

Высота. Слой нормируется по самому миру, а не по общей шкале: тёмное — ниже, светлое — выше. Уровень моря — 0 м, полная шкала высот — ±6000 м.

Вода. Светлое — суша, голубым — вода; оттенок различает океан, море и озеро. В этом мире четыре водоёма.

Реки. 293 реки: подсвечены клетки русел — и на суше, и в воде.

Температура. Фиксированная шкала −90…+60 °C (палитра RdBu): тёплый пояс у экватора, холодные полюса.

Влажность. Фиксированная шкала 0…100 % (BrBG).

Осадки. Фиксированная шкала 0…3000 мм/год (YlGnBu).

Биомы. Шестнадцать биомов, цвета берутся из реестра biomes-v1 — одного на
все слои и экспорты.

Территории. 20 территорий — 12 на суше и 8 на воде, каждая своим цветом. Заполнение идёт по ближайшему центроиду, поэтому края зон многоугольные, со ступеньками по сетке клеток.

Регионы. Те же территории, сгруппированные в континенты и морские бассейны: семь регионов вместо двадцати цветов.

Природный потенциал. По территориям суши, шкала 0…1000 ‰: от бурого к зелёному. Вода и клетки вне территорий остаются фоном.
Карты воспроизводимы: тот же запуск даёт те же файлы, и это свойство под проверкой, а не пожелание — за случайное расхождение отвечают золотые манифесты из раздела выше.
- ЛицензияMIT / Apache-2.0
- Версия0.1.0
- ИзданиеRust 2024
- MSRV1.92.0
- Частиcore, terrain, climate, biome, hydrology, territory, export, tools