MAATRIX GAMES / Блог / Работа с сейв-файлами игрового сервера

Работа с сейв-файлами игрового сервера

MAATRIX GAMES

Рано или поздно каждый, кто держит игровой сервер, лезет руками в папку с сохранением — либо чтобы сделать копию перед рискованным апдейтом, либо потому что после бага мир не открывается и нужно что-то там подправить. Проблема в том, что сейв-файл — это не текстовый документ, который можно смело открыть в блокноте и поправить циферку: у большинства игр это бинарный формат со своей внутренней структурой, и одно неаккуратное действие — скопировать файл, пока сервер в него пишет, или отредактировать не тем инструментом — превращает рабочий мир в кучу байт, которую движок отказывается читать. Разберём, где обычно лежат сейвы, в каком они виде, как их копировать без риска и когда вообще имеет смысл лезть внутрь руками.

Где обычно лежат сейв-файлы

Общий паттерн почти во всех играх с выделенным сервером — отдельная папка saves/, world/ или подобная рядом с исполняемым файлом сервера, а не где-то в системных директориях. Конкретика отличается от игры к игре:

  • Minecraft — папка мира прямо в корне сервера: world/, world_nether/, world_the_end/ (имя берётся из level-name в server.properties). Внутри — level.dat (метаданные мира), region/ с файлами чанков r.X.Z.mca, playerdata/ с данными игроков по UUID.
  • Rust — всё лежит в server/<identity>/, где <identity> — значение из параметра запуска -identity. Карта — <level>.map, сохранение — <level>.sav и рядом .sav.N (предыдущие версии автосейва), плюс SQLite-базы плагинов Oxide/uMod, если они установлены.
  • ARK: SurvivalShooterGame/Saved/SavedArks/, файлы <MapName>.ark и профили игроков/племён *.arkprofile, *.arktribe.
  • Valheim.fwl (world file, метаданные и сид) и .db (собственно данные мира) в worlds_local/ или в профиле пользователя, если сервер запущен без явного пути.
  • 7 Days to Die — сохранение в Saves/<WorldName>/<GameName>/, там же файл региона region/ и player.ttp/.map с прогрессом игроков.
  • Project ZomboidZomboid/Saves/Multiplayer/<servername>/, база данных в формате SQLite (map_*.db).

Если сомневаетесь, где именно лежит сейв конкретной игры — проще всего посмотреть на файлы, которые меняют дату модификации во время игры (ls -lt в директории сервера сразу после активной сессии покажет, что реально пишется), либо свериться с официальной документацией движка/игры — она обычно указывает точный путь.

Форматы: бинарь, база данных, изредка текст

У абсолютного большинства игр сейв — бинарный формат, специфичный для движка: сериализованные структуры данных игры, часто со сжатием (Minecraft-регионы используют zlib/gzip-компрессию каждого чанка внутри .mca-файла). Открыть такой файл в текстовом редакторе бессмысленно — вы увидите нечитаемый набор символов, и там же легко случайно испортить кодировку, если редактор попробует пересохранить файл со своими переносами строк.

Некоторые игры используют под капотом обычные форматы баз данных — это удобнее для анализа и иногда для точечного вмешательства:

  • SQLite (Project Zomboid, часть плагинов Rust/Minecraft для экономики и статистики) — можно открыть штатной утилитой sqlite3 или GUI-инструментом вроде DB Browser for SQLite, посмотреть таблицы, выполнить SELECT, при необходимости — аккуратный UPDATE одной строки.
sqlite3 map_p0_0.db
sqlite> .tables
sqlite> SELECT * FROM world WHERE key='timestamp';

Для полностью бинарных форматов (Minecraft NBT, сейвы ARK, Rust) выручают специализированные инструменты экспорта в читаемый вид — например, для Minecraft это NBT-редакторы (NBTExplorer и подобные), которые парсят .dat/.mca в понятное дерево тегов и позволяют посмотреть или изменить конкретное значение, не трогая остальную структуру файла вручную. Экспорт в JSON/YAML для анализа — это шаг, который стоит делать через такой специализированный инструмент, а не пытаться разобрать бинарь самостоятельно.

Единственное действительно текстовое, что часто путают с «сейвом» — это конфиги (server.properties, .yml, .json настройки модов). Это не игровой прогресс, а параметры сервера — их редактировать текстовым редактором безопасно, и это отдельная тема, которую мы разбирали в статье про работу с конфигурационными файлами.

Нужен игровой сервер?

MAATRIX GAMES — 45+ игр, деплой за минуты, DDoS-защита, автобэкапы. Тарифы от 399 ₽/мес.

Создать сервер

Безопасное копирование работающего сейва

Главная ловушка при копировании сейва «на живую» — сервер продолжает писать в файл в момент, пока вы его копируете, и на выходе получается снапшот, где часть данных из «до», часть из «после», а иногда файл просто повреждён на структурном уровне (например, недописанный регион чанка). Симптом — сервер после рестарта на этой копии либо не запускается, либо запускается с явно битым куском мира.

Правила безопасного копирования, от простого к надёжному:

  1. По возможности копируйте в момент, когда сервер не пишет активно — например, сразу после автосейва и до того, как накопится новая порция изменений. Для многих игр окно между записями достаточно широкое, чтобы cp/tar за пару секунд успел скопировать консистентный снапшот.
  2. Приостановите запись на сервере перед копированием, если такая команда есть. В Minecraft это save-off (отключает автосейв) → save-all flush (форсирует финальную запись на диск) → копирование → save-on (включает обратно):
save-off
save-all flush
# теперь можно безопасно копировать world/
save-on
  1. Остановите сервер на момент копирования, если пауза недопустима или команды приостановки нет — самый надёжный, но не всегда приемлемый вариант из-за простоя для игроков. Для небольшого приватного сервера пара минут даунтайма обычно не проблема, для активного публичного — уже ощутимо.
  2. Снапшот файловой системы (LVM/ZFS/Btrfs snapshot), если хостинг это поддерживает — снимает вопрос консистентности полностью, потому что снапшот атомарен, а сервер продолжает работать без паузы. Такой подход детальнее разбирали в статье про автобэкапы по расписанию.
# копирование после flush, с проверкой что архив не пустой и не битый
tar -czf world_$(date +%Y%m%d_%H%M).tar.gz world/
tar -tzf world_$(date +%Y%m%d_%H%M).tar.gz > /dev/null && echo "архив читается корректно"

Последняя строка — не лишняя предосторожность: tar -tzf проверяет, что архив разворачивается без ошибок, прежде чем вы понадеетесь на эту копию как на рабочую.

Перенос сейва между серверами

Копирование сейва на другую машину — типичная задача при миграции к другому хостеру или при разворачивании тестового окружения с копией прода. Здесь к правилам безопасного копирования добавляется ещё пара нюансов:

  • Версия игры/сервера должна совпадать или быть новее, никогда не старее. Загрузка мира новой версией движка в старую — обычно нормально (движок сам мигрирует формат), а вот открыть сейв от новой версии на старом сервере зачастую невозможно или ведёт к повреждению данных.
  • Переносите весь набор файлов, а не только «главный» сейв — отдельно лежащие профили игроков, базы плагинов, файлы конфигурации whitelist/banlist. Забытый playerdata/ в Minecraft означает, что все игроки на новом сервере окажутся с прогрессом по умолчанию, будто зашли впервые.
  • Проверяйте права доступа и владельца файлов после переноса на linux-хостинг — если архив распаковывался из-под другого пользователя, сервис может не иметь прав на запись в свои же файлы сохранения.

Подробный разбор всего процесса переезда — в статье про миграцию сервера к другому хостеру без потери мира.

Ручное редактирование сейва: когда это оправдано

Лезть в сейв руками — крайняя мера, а не рутинная практика. Типичные ситуации, когда без этого не обойтись:

  • Восстановление после бага движка или мода, когда конкретный объект/чанк/сущность вызывает краш при загрузке, а откат к предыдущему бэкапу неприемлем (потеряется слишком много прогресса). Решение — найти и точечно удалить или обнулить проблемную сущность через NBT-редактор (для Minecraft) или редактор соответствующего формата, не трогая остальной мир.
  • Возврат утерянного прогресса игроку после доказанного бага (не потому что «попросил в дискорде») — например, вернуть инвентарь после краша, который стёр предметы.
  • Снятие бана/восстановление доступа, когда штатная команда недоступна, а правка идёт напрямую в файл банлиста или в базу плагина permissions.

Обязательные правила при ручной правке:

  1. Сначала полная резервная копия оригинала, до любых изменений, отдельно от рабочих бэкапов по расписанию — если что-то пойдёт не так, откатываетесь на неё, а не на вчерашний автобэкап с чужими потерями.
  2. Сервер должен быть остановлен на время правки — редактирование файла, в который параллельно пишет запущенный сервер, почти гарантированно приводит к повреждению при следующей записи.
  3. Меняйте минимально необходимое — конкретное поле конкретной сущности через специализированный редактор, а не «на глаз» в бинарном hex-редакторе, если для формата есть штатный/специализированный инструмент.
  4. Проверяйте результат на копии, а не на проде — распакуйте отредактированный файл на тестовый инстанс сервера, убедитесь, что мир загружается без ошибок в логе, и только потом выкатывайте на боевой.

Если после правки сервер не стартует — первым делом смотрите лог запуска: сообщение об ошибке парсинга конкретного файла обычно прямо указывает, что именно не так со структурой.

Инструменты для просмотра и правки

Для NBT-формата Minecraft (level.dat, файлы игроков) — специализированные NBT-редакторы с деревом тегов и GUI, которые парсят бинарную структуру в понятный вид и не дают случайно сломать формат при сохранении. Для SQLite-баз — sqlite3 в консоли или DB Browser for SQLite с графическим интерфейсом для просмотра таблиц и точечных UPDATE. Для полностью проприетарных бинарных форматов без открытого редактора (некоторые файлы ARK, Rust) — единственный безопасный путь обычно не прямое редактирование, а использование внутриигровых или консольных команд сервера через RCON, которые сами корректно меняют состояние сейва.

Общее правило при выборе инструмента: если для формата существует специализированный редактор, поддерживаемый сообществом игры — используйте его, а не универсальный hex-editor. Специализированный инструмент знает структуру формата и не даст сохранить файл в невалидном состоянии; hex-редактор такой защиты не даёт вообще.

Сжатие старых сейвов и экономия места

Старые бэкапы сейвов — особенно ежедневные копии за несколько месяцев — быстро съедают место на диске, если их не архивировать плотнее. Свежие копии (последние несколько дней) стоит держать как есть, для быстрого разворачивания без лишнего шага, а более старые — пережать плотнее или перенести на холодное хранилище.

# пережать архивы старше 14 дней максимальным уровнем компрессии gzip
find /home/gameserver/backups -name "*.tar.gz" -mtime +14 -exec gzip -d {} \; \
  -exec gzip -9 {} \;

Для больших миров (модовый Minecraft, Rust с большой картой) разница между стандартным gzip -6 и -9 бывает заметной по размеру, но за счёт заметно большего времени сжатия — имеет смысл только для архивов, которые вы уже не разворачиваете быстро, а держите «на всякий случай». Ещё один вариант — zstd с высоким уровнем компрессии, который на больших файлах часто даёт лучшее соотношение скорость/размер, чем gzip, если утилита доступна на хостинге.

Не забывайте, что сжатие снижает нагрузку на диск, но не заменяет ротацию — политику хранения (сколько версий и как долго) стоит держать отдельно от вопроса сжатия.

Нужен игровой сервер?

MAATRIX GAMES — 45+ игр, деплой за минуты, DDoS-защита, автобэкапы. Тарифы от 399 ₽/мес.

Создать сервер

Частые вопросы

Можно ли просто скопировать папку world без остановки сервера?

Технически да, риск получить битую копию невелик, если копирование быстрое (секунды), но лучше сначала форсировать сохранение командой сервера (save-all flush в Minecraft) или остановить сервис — особенно для больших миров, где копирование занимает не секунды, а десятки секунд и больше.

Почему сервер не запускается после моей правки NBT/сейва?

Чаще всего — формат файла нарушен: не тот тип тега, битая контрольная сумма региона, или редактор пересохранил файл в неподдерживаемой кодировке/сжатии. Восстановите резервную копию, сделанную перед правкой, и повторите изменение через специализированный редактор, а не вручную в hex-режиме.

Как понять, что сейв повреждён, ещё до попытки загрузки?

Проверяйте архив на целостность командой распаковки в /dev/null (tar -tzf для tar.gz) сразу после создания бэкапа — не ждите, пока понадобится реальное восстановление, чтобы обнаружить проблему.

Нужно ли бэкапить сейв отдельно от общего бэкапа сервера?

Не обязательно отдельно, но перед любой ручной правкой сейва делайте именно точечную копию непосредственно этого файла — так проще откатить конкретное изменение, не разворачивая весь сервер из общего архива.

Стоит ли хранить сейвы в git для истории изменений?

Для бинарных форматов git малополезен — diff между версиями нечитаем, а репозиторий быстро раздувается. Для истории версий лучше подходит обычная ротация именованных архивов с датой в имени, а git оставить для конфигов и скриптов, которые действительно текстовые.