Files
sindoring 5565858e35 Add quest authoring and scoped NPC questgiver migrations
Create and update quest drafts through shared Save, Undo, Export and Play workflows. Guard quest baselines and NPC references before generating content writes. Enable questgiver flags for an entire template or clone a simple template to isolate one selected spawn.

Validated on Windows x64: formatting, workspace Clippy, 53 passing tests, release build and UI capture. MariaDB temporary-table checks cover both scopes, drift rejection and idempotency; persistent table checksums remain unchanged. Manual in-game quest completion remains open.

Co-Authored-By: Codex <noreply@openai.com>
2026-11-04 21:22:56 +04:00

34 KiB
Raw Permalink Blame History

Состояние проекта и план

Документ для того, кто продолжает работу без владельца: человека или ИИ-агента. Сначала прочитай основные принципы: PRINCIPLES.md. Правила работы описаны в ../AGENTS.md. Состояние на 2026-11-04.

Что это

benilla-editor — редактор контента для сервера vMaNGOS (WoW 1.12.1, build 5875) на движке Benilla. Мир рисуется движком Benilla поверх установленного клиента WoW. Изменения сохраняются в файл проекта (JSON) и экспортируются как миграции world-базы vMaNGOS.

Конечная цель — полноценный редактор: NPC, квесты, предметы, маршруты, DBC, клиентские патчи, новые карты. R1 работает, игровая приёмка на WMO остаётся открытой; начат R2 — простые квесты.

Установка для контент-мейкеров

Старт без аргументов открывает выбор/создание проекта и настройки компьютера. Инструкция: install.md. JSON и миграции хранятся в отдельном репозитории контента; camp.json игнорируется только как локальный рабочий проект этого checkout. Профиль пользователя (editor-config) хранит подключение к БД, пути, Play и последние проекты в системных пользовательских каталогах; EDITOR_HOME позволяет выбрать отдельный профиль. .env импортируется явно, автоматическое чтение из исходников удалено. Play использует state/play профиля, выбранные Realm ID, путь ядра и порт мира. Скрипт scripts/package.ps1 создаёт Windows ZIP без проектов, настроек и ассетов. Benilla загружается Git-зависимостью по точному BENILLA_REV, без соседнего checkout; dev-поиск исходников отключён. Ревизия движка в этом шаге не менялась.

Проверено на Windows x64: cargo fmt, Clippy всех targets с -D warnings, 41 тест workspace (2 opt-in теста пропущены штатным запуском; проверка приоритета Realm ID отдельно прошла на временных таблицах локальной БД). Release ZIP распакован вне репозитория: старт с пустым профилем без WoW и открытие мира с локальными настройками прошли. Запуск из второй папки программы сохранил профиль побайтово; подтверждён кадром 1600×900. Скриншоты и логи — target/portable-*. macOS/Linux в этом шаге не собирались. Автообновление пока не реализовано.

Локальное окружение владельца (не требования к установке)

Что Где
Этот репозиторий C:\Users\sindo\benilla-editor
Benilla (движок, соседний checkout) C:\Users\sindo\benilla, закреплён коммит из BENILLA_REV (aa799a2c, origin/main нашего moonwell-client-core)
Ядро vMaNGOS (форк владельца) WSL /home/sindo/core, рабочая ветка development
Миграции контента в ядре /home/sindo/core/sql/content/migrations/, проекты: sql/content/projects/
Локальная БД vMaNGOS Docker vmangos-local-db-1, 127.0.0.1:13306, база mangos
Установка WoW (только чтение) C:\Program Files (x86)\World of Warcraft\Data
Локальные настройки пользовательский settings.json, путь показывает benilla-editor-cli config-path; .env — только для явного импорта

Ключи окружения / явного импорта .env:

  • WOW_DATA — папка установки.
  • EDITOR_WORLD_DB — mysql://vmangos:<пароль>@127.0.0.1:13306/mangos. Пароль лежит в /home/sindo/core/deploy/local/secrets/db_password.
  • EDITOR_EXPORT_DIR — путь UNC \\wsl.localhost\Ubuntu\home\sindo\core\sql\content\migrations.

Устройство кода

Крейт Что делает Bevy
editor-config Профиль пользователя, пути состояния/кэша, импорт .env, последние проекты. нет
editor-project Модель проекта: цель (версии Benilla и vMaNGOS), диапазон guid, спавны, baseline последнего экспорта, список экспортов с SHA-256. Сохранение побайтово стабильно. нет
editor-vmangos creature_migration: миграция в формате ядра. world_db: чтение базы (шаблоны, поиск, строки в диапазоне, audit). export: сверка с сервером и запись миграции, общая для CLI и окна. нет
editor-release Manifest релиза, схема 1 (см. release-manifest.md). нет
editor-cli benilla-editor-cli new / check / export / manifest-check. нет
editor-app Окно benilla-editor, модули ниже. да

Модули editor-app:

  • launcher.rs — выбор/создание проектов и локальные настройки без загруженного мира.
  • main.rs — запуск и профиль. Флаги: --settings, --import-env, --at x,y,z, --map, --entry, --display. Отсюда же диагностический режим EDITOR_SHOT.
  • camera.rs — свободная камера и луч курсора по поверхностям, на которых можно стоять.
  • preview.rs — модели существ. Обычные модели строятся с текстурами Monster1/2/3, гуманоиды — из модели расы, запечённой текстуры, волос, меха и геосетов. Каждый спавн стоит в анимации Stand на своём риге. Шлем, наплечники и оружие висят на якорях костей.
  • edit.rs — расстановка, выбор, перенос, поворот, высота, дубль, удаление, отмена и повтор, маркеры.
  • ui.rs — панели egui: каталог, инспектор, изменения, строка статуса. UiFocus не даёт миру перехватывать ввод над панелями.
  • server.rs — слой существующих спавнов сервера, только для чтения. Ячейки 128 ярдов в радиусе 320 ярдов от камеры читает отдельный поток со своим соединением, кадр его не ждёт.
  • play.rs, play_ui.rs — Play в отдельном окне клиента: выделенный локальный GM-аккаунт, точка старта проекта, проверка применённых миграций и необязательный скрипт подготовки. Настройка и ограничения: play.md.

Что сделано

R0 — технический прототип (закрыт, кроме проверки в игре)

  • Редактор использует только публичный API Benilla, форк патчить не пришлось. Сборка проверяет, что Git-зависимости движка в Cargo.toml совпадают с BENILLA_REV.
  • Координаты переводятся через benilla_assets::coords. Тест сверяет направление на сервере и в рендере.
  • Выбор поверхности проверен на земле и на полах WMO: 11 NPC в Штормграде, включая верхний этаж Башни магов. Отклонение 0–0,21 ярда ниже z сервера, луч остаётся на этаже NPC.
  • Миграции пишутся в формате ядра (sql/migrations/README) с id в таблице migrations, так что повторное применение ничего не делает. Таблицы world на MyISAM, отката нет, поэтому все проверки идут до первой записи:
    • новый guid должен быть свободен;
    • изменяемая или удаляемая строка должна совпадать с baseline по guid, entry и map;
    • на удаляемый спавн не должно быть ссылок в creature_addon, creature_movement, creature_linking, pool_creature, game_event_creature.
  • guid выдаются сверху вниз, от конца диапазона, и никогда не переиспользуются. Ядро даёт .npc add и временным существам номера выше MAX(creature.guid) (ObjectMgr::SetHighestGuids). После первого экспорта максимумом становится конец диапазона, и сервер выделяет номера выше него. Диапазон по умолчанию 9000000–9000999; на production его ещё нужно подтвердить.
  • Перед экспортом проект сверяется с сервером (world_db::audit). Конфликтом считаются:
    • чужая строка в диапазоне;
    • занятый guid, который проект добавляет;
    • отсутствие шаблона на patch_min спавна;
    • расхождение с последним экспортом, если все экспорты уже применены.
  • Сквозная проверка на локальном vMaNGOS прошла:
    • экспорт и применение;
    • повторное применение ничего не меняет;
    • изменение и удаление;
    • защита от занятого guid (ERROR 1644, база не тронута);
    • mangosd загружает спавны без ошибок.
  • Manifest релиза, схема 1: полный набор артефактов, потребители, неизменяемые ключи releases/<id>/ в S3, check_follows не пропустит потерю унаследованных DBC.
  • В ядре есть sql/content/, deploy/local/apply-content.sh, а init-db.sh применяет контент последним. Владелец закоммитил это в development (b32573186).

R1 — визуальная расстановка NPC (в работе)

  • Мир рендерится в отдельную текстуру размера свободной области между панелями, egui показывает её на полнооконной камере. Частичный Camera::viewport не используется: retained static-pass закреплённой Benilla его не применяет, поэтому при прежнем подходе статические объекты и земля расходились на экране. Размер текстуры учитывает DPI и окно; при изменении размера старая GPU-текстура освобождается. Пустая область отключает мир. Курсор переводится из окна в координаты текстуры; общий луч используется для NPC и Play. Проверено на Windows x64: fmt, Clippy, 45 тестов, release. Дефект воспроизведён в Northshire, исправление проверено на той же камере и при вращении; кадры и логи target/viewport-floating-*. Отчёт: target/viewport-target-report.md. Полная игровая приёмка NPC на WMO остаётся открытой.
  • Esc сбрасывает кисть каталога и выделение, включая выделение серверного NPC, даже при фокусе в строке поиска. Кнопка «Режим выбора (Esc)» отключает размещение, сохраняя открытый инспектор. Регрессионный тест ввода проверяет: два размещения → Esc → свободный щелчок без нового спавна → выбор первого NPC без изменения проекта.
  • Гуманоидные NPC показываются моделями: модель расы, запечённая текстура из BakedNpcTextures (она есть у всех 6984 гуманоидных display), волосы из CharSections, мех тауренов, геосеты прически и одежды. Проверено на людях, дворфе, ночных эльфах и тауренах.
  • Панели egui: каталог с поиском по базе, инспектор с отменой, список изменений с кнопками «Сохранить», «Проверить сервер», «Экспорт». Все подписи на русском.
  • CLI и окно экспортируют одним кодом (editor_vmangos::export).
  • Слой существующих спавнов сервера: модели с серо-синими кольцами. Под курсором строка статуса показывает, кто там стоит. Щелчок открывает спавн в инспекторе только для просмотра, поверх него ничего не ставится. Слой включается галочкой «спавны сервера». Учитываются спавны, которые сервер загружает на патче 10; диапазон guid проекта исключён. У аббатства Northshire прочитано 355 спавнов, прямой SQL по тем же ячейкам дал те же 355.
  • Если база недоступна, окно всё равно открывается, только без каталога и слоя. Слой переподключается, когда галочку включают снова.
  • NPC стоят в анимации Stand. Шлемы и наплечники на гуманоидах, оружие и щиты в руках: проверено на Магни (два молота), Болваре (меч и щит) и стражниках сервера.
  • 38 тестов и два opt-in теста БД: world_db::live_gear_and_box и play::live_security_matches_world_socket_realm_precedence. Windows: fmt, clippy с -D warnings, workspace tests и сборка окна проходят на закреплённом aa799a2c без BENILLA_PIN_ANY. Тест приоритетов прав отдельно прошёл на локальной БД, используя только временные таблицы соединения.
  • После обновления pin проверены WMO: Крепость Штормграда -8439.98,329.392,122.579 (пол 122.57927, отклонение +0.000267 ярда, 114 спавнов сервера) и Башня магов -9010.78,876.575,148.702 (пол 148.61842, отклонение -0.083572 ярда, 161 спавн). В обоих случаях все запрошенные ячейки прочитаны, ошибки слоя сервера отсутствуют, сохранён кадр. Отчёт и логи: target/pin-main-report.md, target/pin-main-*.log.

Play — проверка серверного контента

  • «Поставить точку Play» переводит следующий щелчок по поверхности в выбор места старта; направление берётся от камеры. Точка видна зелёным маркером, редактируется в настройках и сохраняется как необязательное поле play_start. Старые проекты читаются без изменения формата; точка не входит в SQL-diff.
  • Play сохраняет проект, проверяет локальный адрес, эффективный GM-уровень из account_access для локального RealmID 1 (его запись важнее общей -1), принадлежность персонажа и отсутствие активной сессии. Вторая сессия этого checkout блокируется файловой блокировкой ОС. Пароль передаётся только в окружении клиента.
  • Со скриптом подготовки изменения экспортируются общим кодом миграций. Стандартный scripts/prepare-play.ps1 применяет локальные миграции, перезапускает mangosd и ждёт порт мира. Без скрипта новые изменения или неприменённые экспорты блокируют Play.
  • Клиент запускается отдельным процессом; «Стоп» завершает только этот процесс. Настройки, аддон и логи изолированы в benilla-config/play/. Наследуемые инструменты WOW_* отключаются; игровой сеанс пользователя остаётся attended.
  • Аддон использует штатные API 1.12: один раз после входа нужного персонажа отправляет .gm off, затем .go xyzo с направлением и картой. В Lua-интерпретаторе Benilla проверены другой персонаж, повторное событие входа и отсутствие точки старта. Проверены блокировка сессии, передача учётных данных, совместимость старого проекта и отказ занятому аккаунту.
  • Для локального /home/sindo/core создан отдельный аккаунт EDITORPLAY (GM 3) и персонаж Playtester (человек-воин, уровень 1). Локальный .env заполнен, пароль в Git не входит. Клиент — существующий ../benilla/target/release/MoonWell.exe, подготовка — scripts/prepare-play.ps1. Права записаны в realmd.account_access, а не только в неиспользуемое серверной сессией поле account.gmlevel. Проверены SRP-вход, world handshake, перенос к сохранённой точке Play (ошибка 0 ярдов), получение живого волка guid 9000999 (entry 69, 55/55 здоровья) с сохранёнными координатами и направлением и чистый выход. Диагностика: target/play-wolf-live.log. Боевых действий проверка не выполняла.
  • Перезапуск мира сохраняет таймеры возрождения. Для guid 9000999 обнаружено сохранённое время возрождения; после его истечения подтверждён живой спавн. Выделение guid теперь хранит lowest_creature_guid и не возвращает удалённый guid после экспорта пустой baseline, чтобы новый NPC не наследовал состояние старого. Проверено после сохранения/загрузки.
  • Окно проверено диагностическим запуском без БД: панель Play, окно настроек и зелёный маркер точки старта. Снимок target/play-smoke.png, логи проверок target/play-*.log.

R2 — простые квесты (первый этап)

  • Окно «Квесты…»: новые черновики, тексты, уровни, патч, опыт и деньги; поиск NPC выдачи/сдачи по имени и выбор NPC в мире. Можно назначить квестодателем обычного NPC: режим «Все NPC этого типа» добавляет npc_flags | 2 во всех патчах, сохраняя остальные биты. Режим «Только выбранный NPC» создаёт полный шаблон с новым entry и меняет entry только выбранного спавна (в том числе существующего серверного guid), сохраняя исходных NPC. Это явно разрешённое владельцем исключение из общего режима просмотра серверных спавнов. До записи проверяются схема, хеши исходного шаблона, флаги, связи, свободный entry и guid. Копируются прежние связи с квестами; специальные роли/AI/ScriptName и другие опубликованные квесты проекта пока блокируют копирование, для них доступен общий режим. Связи ядра по-прежнему относятся к entry: повторное использование новой копии создаст ещё одного квестодателя. Диапазон новых entry задаёт владелец; опубликованные назначения нельзя удалить флажком или Undo. Диапазон и занятые номера сохраняются при Undo.
  • Квест-разговор (без целей убийства) и до 4 целей убийства, по 1–63 существа. Ограничение 63 — шесть бит счётчика журнала Vanilla (Player::SetQuestSlotCounter), а не ёмкость столбца SQL. Награда опытом задаёт базовый RewXP; ядро применяет свои уровневые коэффициенты.
  • Свой диапазон ID квестов задаётся в проекте один раз владельцем сервера. ID выдаются сверху вниз и не возвращаются после удаления черновика или Undo. Диапазон независим от creature guid.
  • Проект формата 2, чтение старого формата 1 сохранено. Проекты с квестами записываются как 2, чтобы старый редактор отказался их открывать и не потерял неизвестное содержимое при Save.
  • Общие Save/Undo/Redo, CLI Check, экспорт и подготовка Play учитывают квесты. Новые и изменённые квесты входят в ту же миграцию, что NPC; baseline обновляется после записи файла. Проверки занятости ID, точной строки предыдущего экспорта, связей, локализаций и NPC идут до записи migrations и контента. Неполные черновики сохраняются, но блокируют Check/Export/Play.
  • Первое ограничение R2: новые собственные квесты и их обновления. Удаляется только черновик до экспорта. Предметные цели/награды, цепочки, отдельные локализации, импорт чужих квестов и удаление опубликованного квеста ещё не реализованы. Русские тексты пока пишутся в базовые поля.
  • Windows x64: fmt, Clippy, тесты workspace, release; окно проверено кадром target/quest-ui.png. MariaDB: создание, повторное применение, обновление и обнуление цели, отказы при дрейфе и NPC без нужного флага прошли на временных таблицах. Семь постоянных таблиц сохранили контрольные суммы. Первый стенд ошибочно продолжил работу после сбоя CREATE TEMPORARY и создал тестовый квест 60009; его точные строки и два migration ID удалены, остатки проверены (все 0). Исправленный стенд использует явный DDL и прекращает работу при ошибке подготовки. Логи: target/quest-migration-smoke.log, target/quest-cleanup.log, target/quest-tests.log.
  • Оба режима квестодателя проверены на MariaDB во временных таблицах: общий режим сохраняет биты 8/128, добавляя 2; отдельный меняет только guid 79943, оставляя 79944 с entry 5403. Повторная миграция ничего не меняет, дрейф шаблона блокирует запись. Контрольные суммы девяти постоянных таблиц совпали. Лог: target/quest-giver-migration-smoke.log.
  • Прохождение квеста в клиенте через Play пока не проверено. Боевые квесты проверяет человек.

Что не проверено

  • Оставшаяся визуальная проверка R0. На земле перенос, координаты и направление спавна проверены по живому протоколу (см. Play выше). Для WMO поставить спавн, экспортировать, apply-content.sh, перезапустить mangosd, затем в клиенте .go xyz по строке из инспектора либо выбрать точку Play рядом со спавном и запустить клиент кнопкой Play. NPC должен стоять там же и смотреть туда же, что и стрелка. Benilla запрещает автоматические боевые прогоны (../benilla/docs/METHOD.md).
  • Действия мышью в окне: щелчки по панелям, перетаскивание в инспекторе и отмена одним шагом, кнопка «Экспорт». Код проверен снимками и тестами общих функций, но не руками.
  • Кадр из Крепости Штормграда (--at -8445,320,135) выглядит как вид изнутри стены. Похоже на положение камеры, а не на ошибку рендера, но это не разобрано.
  • В диагностических запусках на aa799a2c есть ошибки загрузки BLP волос дворфов (BLP mip level 9 out of bounds) и отсутствующего ресурса декора в Башне магов. Они не мешают проверенным лучам пола и загрузке моделей NPC, но полная корректность ресурсов этими проверками не подтверждена. Подробности в target/pin-main-report.md.

План

Порядок внутри R1, по приоритету:

  1. Слой существующих спавнов сервера — сделан (см. выше). Он только для чтения: правка чужих спавнов означает конфликты с upstream vMaNGOS и устаревший кеш WDB у клиентов, это отдельное решение владельца. Не проверено руками: наведение, щелчок и галочка.
  2. Шлем, наплечники, оружие на гуманоидах — сделано. Шлем (с суффиксом расы и пола) и наплечники берутся из ItemDisplayInfo по внешности display. Оружие и щит берутся из снаряжения entry (world_db::creature_gear: equipment_id → creature_equip_template → item_template): основная рука в правой, вторая в левой, щит на предплечье. Дальнобойное оружие не показывается.
  3. Поза — сделано. Каждый спавн получает свой риг по схеме анимированного доодада Benilla: RigPose, AnimationPlayer с Stand по кругу, слот RigSkin::allocate_bones, риг-меши из ModelForms::require_rigged. Предметы висят на якорях костей (RigPose::anchor_for) со смещением attachment. Если слотов нет, спавн остаётся в базовой позе: у рук тогда точки в начале координат, и оружие не показывается. В Торговом квартале Штормграда 299 спавнов, все в позе, переполнения палитры нет.
  4. Мелочи:
    • выбор модели из нескольких display_id1..4 шаблона — сделано: у кисти в каталоге и у спавна в инспекторе. Это только превью: сервер сам выбирает модель по вероятностям шаблона;
    • подтверждение перед экспортом — сделано (окно Dialog::Export);
    • предупреждение при закрытии окна с несохранёнными изменениями — сделано (WindowPlugin::close_when_requested выключен, ui::close_requested);
    • ужать картинку мира до свободной области между панелями — сделано в редакторе, без изменения Benilla; учтены DPI и выбор поверхности в viewport. Не проверено руками: щелчки по кнопкам диалогов и закрытие окна крестиком. Снимками проверено только, что окна диалогов рисуются.
  5. Критерий готовности R1: NPC расставлены в окне и видны моделями, экспортированы одной миграцией и в игре стоят там, где показывал редактор.

Следующие релизы, из исходного плана владельца:

Релиз Что
R2 Простые квесты: quest_template, связи с NPC (creature_questrelation и creature_involvedrelation), цели, награды, прохождение. Квест на убийство проверяет человек: автоматические бои запрещены.
R3 DBC: сборка, публикация в S3 по manifest, закрепление релиза, загрузка и проверка DBC перед компиляцией production-сервера. Без DBC сборка не продолжается. Схема manifest уже готова.
R4 Предметы, добыча, торговцы, диалоги, GameObject.
R5 Маршруты NPC (creature_movement), AI, события.
R6 Полётная сеть.
R7 Редактирование существующих карт (запись ADT, WMO, пересборка vmaps и mmaps).
R8 Новые карты, подземелья и рейды: простые части без механик боссов (см. PRINCIPLES.md). Как программировать механики боссов, владелец ещё не решил.
R9+ Заклинания, таланты, профессии, репутация, мировые события, транспорт, PvP.

Правила, которые действуют дальше:

  • Меняешь имя или текст существующего entry — клиенты со старым кешем WDB его не увидят. Нужен новый entry или clearClientCache в manifest.
  • Строки vMaNGOS привязаны к диапазонам патчей. Экспорт всегда выставляет patch_min и patch_max явно.
  • Код vMaNGOS под GPL. Редактор (MIT/Apache) читает схему и генерирует SQL, но код ядра не линкует.
  • DBC, MPQ и всё, что собрано из файлов установки, хранится только в S3 и никогда не попадает в Git.