Уже больше года я занимаюсь активным администрированием нашего сервера Minecraft. За это время вышло шесть обновлений, которые дополняют игровой процесс. Первые обновления прошли без серьезных вызовов, но версии 26.2 и 26.3 внесли изменения в генератор мира.
Из-за особенностей игры новые локации могут быть появиться только там, где до обновления еще не ступала нога игрока. Это подтолкнуло меня провести небольшой аудит нашего игрового мира и подготовить его к обновлению — сбросить области, в которых игроки были только «проездом». Отсутствие вайпов (периодического полного сброса игрового процесса) на сервере и относительно большой игровой мир сделали эту задачу особенно интересной.
В этой статье вас ждет обзор утилит для управления мирами, скриншоты нашей карты и описания некоторых внутриигровых механик.
Обновления Minecraft
На старте сервера актуальной версией игры была 1.21.5. Затем в течение года выходили небольшие обновления:
- 1.21.6 «В погоне за небесами» — новое транспортное существо «счастливый гаст», рецепт седла и улучшения в работе поводка.
- 1.21.9 «Медный век» — снаряжение из меди, копье и новые декоративные блоки.
- 1.21.11 «Скакуны Хаоса» — наутилус (морское транспортное существо), а также враждебные мобы на лошадях и с копьями.
- 26.1 «Крошечный захват» — обновленные модели всех детенышей существ, рецепт бирки и золотой одуванчик.
Эти обновления легко вписывались в существующий мир:
- медь уже существовала в версии 1.21.5, обновление лишь дало ей новые варианты применения;
- «счастливый гаст» добывается в битве с обычным гастом, который существует в игре с 2010 года;
- враждебные и дружелюбные монстры появляются в мире исходя из общего количества активных сущностей на сервере и присутствия игрока рядом.
В версиях 26.2 «Хаос в Кубе» и 26.3 «Зов дикой природы» появились новые биомы, — серные пещеры и пестрый лес, а также новая структура — заброшенный лагерь. Уже сгенерированные участки мира после обновления сервера остаются нетронутыми, а новые биомы и структуры могут появиться только при посещении новых территорий.

Более чем за год работы сервера почти три тысячи игроков могли сгенерировать мир на десятки тысяч блоков от спавна, что усложнило бы поиски новых биомов. Поэтому первым шагом стал аудит мира. Насколько мир исследован, в каких направлениях, и как можно оценить «заселенность» той или иной территории.
Строение игрового мира
Прежде чем приступить к использованию инструментов, необходимо освежить (или выучить) базовые знания об устройстве игрового мира.
Легко заметить, что трехмерный мир Minecraft разбит на блоки, каждый из которых занимает ровно один куб размером 1х1х1. Ось Y направлена вверх. Каждый блок имеет свои координаты, при этом значения координат всегда целочисленные.
По вертикали блоки можно ставить на отрезке [-64; 319] (до обновления 1.18 — [0; 255]), по горизонтали в любом направлении, граница по умолчанию — 59 999 968 блоков.

Для оптимизации блоки объединяются в чанки — области 16×16 по горизонтали на всю высоту мира. То есть один чанк содержит 16x16x384 = 98304 блоков. Игра оперирует чанками: если в поле зрения игрока попадает хотя бы один блок, то сервер загружает весь чанк.
Чанки, в свою очередь, объединяются в регион, включающий область размером 32×32 чанка, или 512×512 блоков. Регионы используются для сохранения данных мира на диск. У блоков, чанков и регионов собственная система координат, но об этом мы поговорим позднее.
Теперь перейдем к более игровым деталям.
Верхний мир, нижний мир и Край
В Minecraft по умолчанию три «измерения», между которыми можно путешествовать через порталы.
- Верхний мир (Overworld) — «обычный» мир, с которого начинается игра.
- Нижний мир (Nether) — «ад», более опасный лавово-огненный мир.
- Край (The End) — мистический мир с драконом в космосе.
Верхний и Нижний миры связаны: игрок может самостоятельно построить рамку портала и перейти из одного мира в другой. Здесь стоит отметить важную игровую механику: расстояния в Нижнем мире соотносятся как 1:8 с Верхним миром. Таким образом, если зайти в Нижний мир, преодолеть 1 000 блоков по прямой и вернуться в Верхний мир, то между порталом входа и порталом выхода будет 8 000 блоков. Эта игровая механика позволяет быстро, но рискованно преодолевать большие расстояния в Верхнем мире.
К сожалению, игра не позволяет корректно оценивать игровой мир с точки зрения администрирования. Во-первых, сервер никогда не держит в памяти весь мир, а только загружает чанки вокруг игроков. Во-вторых, сервер никак не выделяет несгенерированные области мира, а молча создает их при необходимости.
Перечисленные далее инструменты требуют прямого доступа к файлам игрового мира. Крайне не рекомендуется использовать эти инструменты на работающем сервере, так как это может привести к повреждению мира.
Делайте резервные копии.
Верхний мир нашего сервера ограничен 100 000 блоков в каждую сторону. По примерным расчетам, полная генерация в среднем будет занимать 400 ГБ без учета пользовательских построек. На текущий момент мир «весит» 190 ГБ.
Откроем же его.
uNmINed

Для чтения мира вне игры потребуется uNmINeD — утилита для просмотра миров Minecraft (как Java Edition, так и Bedrock Edition) и Hytale. Для эффективной работы этой утилиты потребуется твердотельный накопитель, иначе процесс затянется.
Утилита генерирует полноценный предпросмотр «вид сверху» до масштаба 1:32, и позволяет видеть контуры до 1:4096. Это позволяет оценить маршруты путешествий игроков.

Общая карта мира показывает, что вся работа начата не зря: центр мира сгенерирован в среднем в радиусе 7 000 блоков от спавна, а игроки отдают предпочтение левой половине мира.
Об этой утилите я уже рассказывал в своем Telegram‑канале. Подписывайтесь, там делюсь заметками к статьям, над которыми работаю, публикую небольшие познавательные посты, а по пятницам традиционно выкладываю мемы.
Также видно, что в мире очень много несвязанных маленьких областей. Часть из них выглядят искусственно: один полностью сгенерированный чанк в центре «черновой» области 5×5 чанков.

Когда игрок выходит из Нижнего мира, сервер генерирует чанки вокруг точки выхода в области 16х16. После выхода игрок обычно совершает небольшой обзор, что дополнительно генерирует область произвольной формы.
Хотя утилита uNmINed показывает именно визуализацию на большей части окна, в интерфейсе также есть панели, отображающие «сырую» информацию о каждом чанке. Среди многообразия информации я хочу акцентировать внимание на параметре InhabitedTime.
Когда чанк загружен, он считает время своего существования: каждый игровой такт значение InhabitedTime увеличивается на количество игроков, из-за которых чанк загружен. Этот параметр используется сервером для вычисления локальной сложности: вокруг базы игрока со временем будут появляться более сильные враждебные монстры. Если базу создают несколько игроков, то сложность будет расти быстрее.
Для администратора этот параметр важен именно возможностью оценить «заселенность» чанка. Если у чанка InhabitedTime равен нулю, то есть несколько вариантов, почему так произошло.
Среди параметров у чанков также есть атрибут Status, который показывает текущее состояние чанка в контексте генерации. Для некоторых этапов генерации чанку нужны все восемь «соседей». Так что некоторые чанки использовались исключительно для помощи генерации и на самом деле никогда не посещались игроком.
Кроме того, некоторые плагины могут запрашивать состояние чанков по любым координатам и, сами того не ведая, генерировать их. Похоже, именно это является причиной появления «правильных» чанков 5х5.

Сперва я выбрал чанк с точкой появления в мире (спавном), и там InhabitedTime равен 69 687 111 тактам. 20 тактов равны одной секунде реального времени, поэтому чанк спавна пробыл загруженным почти 81 человеко-день.
Затем я выбрал чанк одной из линий, которые очевидно были созданы полетом. Параметр InhabitedTime имеет значение 25 тактов, то есть всего 1.25 секунды реального времени. Более того, параметр LastUpdate показывает время последнего обновления чанка: здесь оно произошло на 181 023 855-м такте от создания мира.
Текущее внутриигровое время мира — 726 463 872 тактов. Если учесть, что игровые сутки длятся 24 000 тактов (20 минут реального времени), то с момента изменения прошло 22 726 внутриигровых дней. 62 внутриигровых года!
Определенно, в таком чанке никто не строил баз и не хранил ресурсы, так что его можно без опасений сбросить. Остается лишь небольшое опасение: как сброшенные чанки «впишутся» в существующий мир?
Персистентная генерация
В основе любого мира Minecraft лежит сид (зерно генерации). Определяет он буквально все: ландшафт, биомы, структуры. Если сгенерировать два разных мира с одним сидом, то эти миры будут похожи. И это правило сохраняется между версиями.
В Minecraft используется многоступенчатая генерация мира. Если упрощать, то сперва генерируется ландшафт, потом карта температур и карта влажности, и в зависимости от этих параметров определяется биом. В каждом биоме генерируются свои структуры.
Обновления 26.2 и 26.3 всего лишь расширили список возможных биомов и структур, при этом никак не повлияв на общую логику генерации мира. По-настоящему крупные изменения на этом уровне происходили в версиях 1.7.2 (2013) и 1.18 (2021). В первой появилась температурная карта, а во второй — увеличение высоты мира.

На изображении выше представлен скалистый холм, соседствующий с вишневой рощей и ледяными пиками. Часть с обрывом имеет биом «Равнины».

При генерации мира с тем же сидом в новейшей версии холм сохраняет свой ландшафт, но равнины около обрыва превращаются в пестрый лес. При наложении двух изображений друг на друга видно, что мелкие детали вроде травы, выпавшего снега и структуры ледяных пиков отличаются, но едва ли это будет заметно в игре без прямого сравнения со старой версией.
Это значит, что удаление «бесхозных» чанков не навредит миру. Но с помощью чего выполнить такую задачу?
MCASelector

Утилита uNmINed подходит в основном для быстрого и удобного просмотра, а вот MCASelector — уже для активных действий. У утилиты есть графический интерфейс и возможность работы в командной строке.
MCASelector позволяет выполнять массовые операции над чанками мира, в том числе выделять их по заданному условию и удалять. Наиболее логичной и безопасной операцией мне показалось выделение чанков с InhabitedTime = 0. Это удалит все «хвосты», которые использовались для генерации, и случайные запросы по всей карте. Выполняем:
# Сохраняем выделение в selection.csv
java -jar mcaselector-2.9.jar --mode select --world survival-2025\dimensions\minecraft\overworld --query "InhabitedTime = 0" --output selection.csv
# Удаляем чанки и регионы, описанные в selection.csv
java -jar mcaselector-2.9.jar --mode delete --world survival-2025\dimensions\minecraft\overworld --selection selection.csv
Таких чанков оказалось ОЧЕНЬ много. На домашнем компьютере с SSD процесс выделения занял почти час, а затем еще полчаса ушло на удаление после чего объем Верхнего мира сократился с 190 ГБ до 74 ГБ. Следующий этап — поиск минимального времени, которое позволит убрать «тропинки» от полетов и пешеходного путешествий, но не сотрет базы игроков.

Я начал с 5 минут и постепенно сокращал время. На изображении пример, в котором выбираются чанки со временем жизни менее 15 секунд — при таком значении путь удаляется только частично. Это была пешеходная тропа, и игрок преодолевал перепады высот. Опытным путем было получено значение 60 секунд (1200 тактов), которое стирает большинство путей полностью.
План надежный, но тревожность не отпускала. С одной стороны, минута на чанк — это очень короткий срок: едва ли игрок за такой промежуток времени мог сделать что-то большее, чем дом 2х2 из грязи. С другой стороны, игрок мог планировать свое будущее: отметить понравившуюся территорию, чтобы вернуться туда позже. Будет неловко, если она внезапно сменит биом.
Мне показалось логичным проверить не только время InhabitedTime, но и наличие деятельности игроков в этих чанках.
У нас, кстати, еще много материалов про Minecraft и другие игры
Дополнительная валидация
На сервере есть набор классических плагинов, свойственных «мирным» серверам, среди которых Essentials и WorldGuard. Первый добавляет, расширяет и улучшает стандартные серверные команды, а второй позволяет создавать «регионы-приваты» чтобы защитить территорию от игроков с недобрыми намерениями.
Таким образом, если игрок нашел для себя интересное место, то он либо «заприватит» его, либо отметит его как еще один дом командой /sethome, чтобы иметь возможность телепортироваться туда позже.
Все регионы WorldGuard хранятся в файле regions.yml в виде двух точек — диагональных вершин прямоугольного параллелепипеда. Каждый «дом» Essentials описывается одной точкой в мире и также хранится в yaml-файле. Остается только сопоставить точки с выделением, сделанным в MCASelector.
CSV-файл, сгенерированный MCASelector, состоит из четырех столбцов:
region_x;region_z;chunk_x;chunk_z
Первый и второй столбец определяют глобальные координаты региона, третий и четвертый — глобальные координаты чанка. Например, если строка содержит координаты 190;70;6080;2240, то это значит, что в регионе 190;70 (файл r.190.70.mca) нужно найти чанк с абсолютными координатами 6080;2240. Если координат чанка не указано, например 190;70, то это значит, что операция производится над всеми чанками региона.
Проблема в том, что MCASelector оперирует регионами и чанками, а плагины сервера — блоками. К счастью, по координатам блока можно вычислить координаты чанка и региона, а по координатам чанка — регион. Используем деление с округлением вниз.
chunk_x = floor(block_x / 16)
region_x = floor(block_x / 512)
region_x = floor(chunk_x / 32)
# Координата Z вычисляется аналогично
Дальше — простая математика. Точку «дома» игрока превращаем в координаты чанка. Две точки «привата» превращаем в список чанков, на которых он размещается. Дополнительно вычисляем небольшую буферную зону в 10-15 чанков вокруг каждой точки и каждого «привата».
Затем для каждой строки CSV-файла проверяем, нет ли этого чанка среди тех, которые были вычислены на предыдущем шаге. Если нет, то строку переписываем в результирующий файл.
Остается последний раз отсмотреть, какие чанки отмечены на удаление и отправить на очистку второй раз.
Полный скрипт доступен на GitHub Gist.
Результаты

Запуск непосредственно на сервере с NVMe прошел быстрее. Выделение чанков с InhabitedTime = 0 заняло всего 13 минут. На удаление ушло 4 минуты. Второй этап — очистка чанков со временем жизни меньше 60 секунд — занял шесть минут. Из них пять было затрачено на создание выделения, меньше минуты на валидацию и 5 секунд на удаление. После всех очистительных процедур мир сократился с 192 ГБ до 13 ГБ.
Очистка «меньше минуты времени существования чанка», конечно, пощадила некоторые тропы, где игроки пережидали ночь, добывали ресурсы или боролись с ландшафтом.
Получилось взаимовыгодно: локации, существенно измененные игроками, остаются таковыми, игроки проще получают доступ к контенту новых обновлений, а у администратора меньший расход дискового пространства на поддержание сервера и резервных копий.
Возможно, стоило изучить эту технику раньше.
