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