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

Засев видов

Сервер сам разрешает сражения. Он применяет формулу урона, бросает случайный разброс урона, решает критические удары и определяет IV, характер, пол и шайни каждого пойманного монстра. Чтобы делать всё это, ему нужны базовые характеристики, типы, коэффициент поимки и соотношение полов каждого вашего вида.

Он не получает их от клиента. Клиент, который мог бы присылать собственные характеристики видов, мог бы прислать что угодно, поэтому сервер отказывается читать их из полезной нагрузки сражения. Он читает их из собственного хранилища, которое изначально пусто.

Что будет, если пропустить это​

Ничего заметного. И в этом проблема, которую стоит понять прежде всего.

Незасеянный сервер не выдаёт ошибку, не предупреждает и не отказывается начать сражение. Он идёт по цепочке запасных вариантов:

  1. Хранилище species_data — засеянные значения, ваши реальные данные.
  2. SPECIES_FALLBACK_TABLE — шесть встроенных видов, жёстко заданных в модуле сервера для его собственных тестов.
  3. DEFAULT_SPECIES — одна типовая строка характеристик, применяемая ко всем остальным.

Так что незасеянный сервер преспокойно проводит сражения, в которых у каждого вашего существа одинаковые подставные характеристики. Пол при поимке определяется ровно 50/50 независимо от вида. Эффективность типов разрешается относительно NORMAL. Никто не получает сообщения об ошибке, потому что с точки зрения сервера ничего не пошло не так: он спросил хранилище, в хранилище ничего не было, он использовал значение по умолчанию.

Засев — это то, что делает авторитетный сервер авторитетным над вашей игрой, а не над заглушкой.

Две половины и почему они разделены​

Засев намеренно разделён на шаг экспорта внутри Unity и шаг засева вне его.

RPC засева (mce_species_seed) — только от сервера к серверу: она отклоняет любой вызов с пользовательской сессией и требует HTTP-ключ рантайма Nakama. Этот ключ — учётные данные администратора: тот, у кого он есть, может писать в хранилище любого игрока. Его нельзя коммитить, нельзя встраивать в сборку и нельзя вводить в ScriptableObject.

Поэтому Unity, который не может безопасно хранить этот ключ, лишь записывает файл. Скрипт, запущенный из вашего терминала и читающий ключ из окружения, отправляет его.

Вкладка Seeding в OpenMon Hub

Вкладка Seeding в Hub — это путь для покупателя для всего ниже: она экспортирует файлы и сообщает, что в данный момент хранит сервер.

Шаг 1 — Экспорт из Unity​

Hub: вкладка Online → Species Data → Export Species Seed JSON (или Export seed files на вкладке Seeding, запускающая все экспортёры, включая виды).

Это читает активную базу данных монстров и записывает два файла в SeedData/ в корне вашего проекта — намеренно вне Assets/, чтобы Unity никогда не импортировал их и они были покрыты .gitignore:

ФайлСодержимое
species-seed.jsonПолезная нагрузка для отправки
species-seed.report.txtКаждая пропущенная запись и каждое значение, которое сервер заменит

Читайте отчёт. Сервер ограничивает каждую характеристику диапазоном 1–255 и подставляет собственное значение по умолчанию для всего, что выходит за этот диапазон, молча. Если у одного из ваших видов базовая характеристика равна 0, это значение будет заменено на сервере, и отчёт — единственное место во всём конвейере, где вы вообще увидите об этом упоминание.

Записи пропускаются, а не экспортируются, если у них нет номера декса, номер декса совпадает с другой записью, нет форм или нет первого типа. Каждый из таких случаев указан в отчёте по имени.

Экспортируется только базовая форма каждого вида. Сервер хранит данные вида только по номеру декса, поэтому вторая строка для альтернативной формы перезаписала бы первую.

Шаг 2 — Засев сервера​

Из Assets/OpenMon/Online/Server~/nakama/:

# bash
export NAKAMA_HTTP_KEY=your-runtime-http-key
npm run seed:species
# PowerShell
$env:NAKAMA_HTTP_KEY="your-runtime-http-key"
npm run seed:species

Скрипт проверяет файл перед отправкой чего-либо и отказывается засевать, если находит значение, которое сервер молча заменил бы. Затем он отправляет виды частями, потому что RPC превращает каждый запрос в одну запись в хранилище, а целый декс в одной записи — это то, на чём Nakama начинает отказывать.

ПеременнаяПо умолчаниюЗначение
NAKAMA_HTTP_KEY—Обязательна. Рантайм-http_key сервера.
NAKAMA_URLhttp://127.0.0.1:7360Базовый URL сервера.
SEED_FILESeedData/species-seed.jsonАльтернативный путь ввода.
SEED_CHUNK_SIZE100Видов на запрос.

Чтобы проверить экспорт, ничего не отправляя:

npm run seed:species:check

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

Шаг 3 — Проверка​

Откройте OpenMon Hub. Вкладка контента сообщает о двух вещах, и они отвечают на разные вопросы.

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

Вторая — кнопка Verify server, и только она обращается к сети. Она различает три исхода, и это различие важно:

РезультатЗначение
SeededВ коллекции есть строки видов, и сообщается сколько.
EmptyСервер ответил. Его коллекция пуста.
Could not askНет сети, неверный хост, неверный ключ сервера. Это ничего не говорит о данных.

«Не засеян» и «нет ответа» — разные факты. Индикатор состояния, который их сливает, хуже, чем его отсутствие, потому что он сообщает о проблеме данных, когда настоящая проблема сетевая.

Можно также проверить прямо по базе данных:

select count(*) from storage where collection = 'species_data';

Засеянные строки записываются под системным пользователем Nakama с публичным чтением и записью только сервером, поэтому клиенты могут читать данные видов, но ни один клиент не может их когда-либо записать.

Когда засевать заново​

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