This commit is contained in:
2026-07-18 17:05:18 +04:00
parent 9fdb7ed718
commit 85f80445d1
+788
View File
@@ -0,0 +1,788 @@
# План расширенной кастомизации персонажей MoonWell
## 1. Цель
Создать для клиента WoW 3.3.5a (build 12340) расширенную систему внешности, визуально и по удобству близкую к retail, сохранив оригинальный `Wow.exe` и используя WarcraftXL для всех клиентских расширений.
Система должна:
- поддерживать стандартные параметры 3.3.5a и дополнительные параметры MoonWell;
- показывать одинаковую внешность при создании, выборе персонажа, входе в мир и другим игрокам;
- хранить дополнительные параметры на сервере и считать сервер источником истины;
- поддерживать текстурные слои, geoset базовой модели и отдельные прикрепляемые M2-модели;
- работать без Eluna/AIO в качестве постоянного транспорта состояния;
- позволять добавлять новые варианты преимущественно данными и ассетами;
- иметь версионирование формата и безопасный откат.
## 2. Не входит в первую версию
- полное копирование внутренних `ChrCustomization*` DB2 и протокола актуального retail-клиента;
- поддержка всех retail-рас, которых нет в MoonWell;
- динамическое изменение скелета или пропорций тела;
- автоматический импорт всех retail-ассетов без ручной проверки;
- публикация полного дампа современных файлов Blizzard;
- изменение бинарника `Wow.exe` на диске.
## 3. Базовые ограничения
### Клиент
- WoW 3.3.5a, build 12340, Lua 5.1, `## Interface: 30300`.
- `Wow.exe` должен оставаться оригинальным с контролируемым SHA-256.
- Новое нативное поведение реализуется модулем MoonWell внутри WarcraftXL.
- GlueXML и FrameXML не используют retail API (`C_Timer`, `CreateFramePool`, `PixelUtil` и т. п.).
- Для анимаций интерфейса используется `OnUpdate`.
- UI-текстуры: `.blp`/`.tga`, размеры по степеням двойки, не более 512×512 на отдельный UI-тайл.
- В Lua/XML использовать `SetWidth`/`SetHeight`, а не `SetSize`.
### Ассеты и рендер
- Исходные современные M2/MD21 обрабатываются `wxl-modern-assets`.
- Каждая модель проверяется на поддерживаемую версию формата, лимит костей, материалы, анимации и attachment points.
- Не использовать OBJ/FBX/glTF как вход для игрового клиента: нужны исходные `.m2`, `.skin`, `.skel`, `.anim` и `.blp`.
- UI-превью и модель в мире должны использовать один каталог вариантов и одинаковые идентификаторы.
### Сервер
- Сервер валидирует расу, пол, доступность и совместимость каждого выбора.
- Клиент не может назначить себе недоступный вариант внешности.
- Дополнительные параметры хранятся отдельно от стандартных байтов внешности 3.3.5a.
- Изменения схемы БД поставляются миграциями и имеют обратимый путь.
## 4. Целевая архитектура
```text
Retail CDN (выбранные FileDataID)
Asset manifest + downloader + validation
Patch*.MPQ / loose Patch-WXL assets
├── wxl-modern-assets
├── адаптированный wxl-equip-extension
└── MoonWell customization runtime
Lua API / GlueXML UI
MoonWell customization protocol
AzerothCore storage + validation + broadcast
```
### Компоненты
1. **Asset pipeline** — получает только перечисленные зависимости по `FileDataID`, сохраняет манифест и проверяет комплектность.
2. **`wxl-modern-assets`** — загружает и приводит современные M2/MD21 и текстуры к контракту клиента 3.3.5a.
3. **Адаптированный `wxl-equip-extension`** — прикрепляет M2, поддерживает collection M2, два модельных канала, attachment points и фильтрацию geoset.
4. **MoonWell customization runtime** — управляет независимыми косметическими каналами, текстурными слоями, geoset базовой модели и Lua API.
5. **GlueXML UI** — категории, список вариантов, камера, случайный выбор, сброс и предварительный просмотр.
6. **Серверный модуль** — хранение, валидация, загрузка, изменение и распространение внешности.
## 5. Типы параметров внешности
### Стандартные параметры 3.3.5a
- пол;
- цвет кожи;
- лицо;
- причёска;
- цвет волос;
- стандартная особенность лица/борода.
Они продолжают использовать штатные поля персонажа и стандартный пакет создания.
### Дополнительные текстурные параметры
- шрамы;
- татуировки тела;
- татуировки лица;
- макияж;
- рисунок/отметины;
- дополнительные оттенки кожи;
- дополнительные слои лица.
Реализация: расширение `CharSections`, каталог слоёв и модификация/перехват клиентского композитора текстуры персонажа.
### Geoset базовой модели
- дополнительные причёски;
- части бороды и усов;
- форма ушей/бровей;
- варианты клыков;
- встроенные рога;
- скрытие частей базовой модели.
Реализация: таблица выбора geoset по расе, полу, категории и варианту.
### Прикрепляемые M2-элементы
- серьги и пирсинг;
- украшения для волос;
- объёмные бороды;
- рога и дополнительные клыки;
- протезы;
- венцы, диадемы и прочие аксессуары;
- независимые объёмные элементы тела.
Реализация: косметические каналы поверх механизма `wxl-equip-extension`.
## 6. Косметические каналы
Кастомизация не должна занимать реальные слоты экипировки. Нужен отдельный реестр каналов:
```text
hair_extra
beard_extra
horns
ears
tusks
piercing_1
piercing_2
accessory_head
accessory_face
accessory_body_1
accessory_body_2
```
Для каждого канала задаются:
- стабильный числовой `option_id`;
- допустимые расы и пол;
- `display_id` или прямое описание M2;
- Model1/Model2;
- Texture1/Texture2;
- attachment point для каждого модельного канала;
- список разрешённых geoset collection M2;
- флаги суффиксов расы/пола и структуры каталогов;
- правила конфликта со шлемом и настоящей экипировкой;
- приоритет и взаимоисключающие каналы;
- значение сброса (`choice_id = 0`).
## 7. Адаптация `wxl-equip-extension`
### Обязательные работы
- закрепить точную ревизию репозитория как submodule;
- адаптировать сборочную структуру к текущему WarcraftXL MoonWell;
- проверить пересечение хуков с `wxl-modern-assets` и существующими `OnItemSlotChange`, `OnItemSlotClear`, `OnM2PerFrameUpdate`;
- вынести разбор Model1/Model2, `Icon2`, attachment points и collection geoset в переиспользуемый слой;
- добавить API независимых косметических каналов, не привязанных к надетому предмету;
- устранить утечку/остаток collection M2 после снятия или смены варианта;
- обеспечить корректное уничтожение дочерних моделей при смене персонажа, карты, формы и пола;
- исключить двойное прикрепление модели при повторной синхронизации;
- очистить мусорные Model1/Model2 в старых строках `ItemDisplayInfo.dbc`;
- добавить диагностический лог разрешения пути, модели, текстуры, attachment point и geoset;
- реализовать безопасный fallback при отсутствии ассета.
### Проверки совместимости
- персонаж игрока;
- другие игроки;
- NPC с тем же `display_id`;
- экран создания;
- экран выбора;
- парикмахерская;
- смена экипировки;
- превращения и shapeshift;
- транспорт;
- телепорт и смена карты;
- повторный вход и `/reload`.
## 8. Каталог данных кастомизации
Нужен единый, версионируемый источник данных, из которого генерируются клиентское и серверное представления.
Предлагаемая запись:
```text
option_id
choice_id
race_mask
gender_mask
category
label_key
render_type
char_section_id
geoset_ids
model_1
model_2
texture_1
texture_2
attachment_1
attachment_2
flags
conflict_group
unlock_condition
asset_manifest_id
enabled
```
Требования:
- `(option_id, choice_id)` никогда не переиспользуется с другим смыслом;
- удалённый вариант остаётся распознаваемым для миграции старых персонажей;
- порядок отображения UI хранится отдельно от стабильного идентификатора;
- клиент и сервер собираются из одной версии каталога;
- версия каталога входит в сетевое рукопожатие.
## 9. Серверное хранение
### Предлагаемая таблица
```sql
character_customization (
guid INT UNSIGNED NOT NULL,
option_id SMALLINT UNSIGNED NOT NULL,
choice_id INT UNSIGNED NOT NULL,
updated_at TIMESTAMP NOT NULL,
PRIMARY KEY (guid, option_id)
)
```
Дополнительно:
- индекс по `guid`;
- внешний ключ или очистка записей при удалении персонажа;
- миграция с начальными значениями для существующих персонажей;
- сервис сброса неизвестных/отключённых вариантов;
- аудит изменения внешности при необходимости.
### Серверная логика
- загрузить набор при `Character::LoadFromDB` или эквивалентном этапе;
- валидировать выбор по расе, полу, режиму игры и доступности;
- сохранять транзакционно;
- включать состояние в данные экрана выбора персонажа;
- отправлять полный snapshot при входе в мир;
- отправлять delta при изменении;
- рассылать актуальное состояние игрокам в зоне видимости;
- отправлять snapshot при появлении объекта в зоне видимости нового клиента;
- ограничить частоту изменений;
- запретить недоступные комбинации независимо от клиентского UI.
## 10. Сетевой протокол MoonWell
### Общие требования
- собственный namespace/opcode или надёжный WarcraftXL transport;
- версия протокола и версия каталога;
- явная длина сообщения и лимит числа записей;
- little-endian поля с фиксированной шириной;
- сервер является источником истины;
- неизвестные поля пропускаются или отклоняются согласно версии;
- отсутствие расширения не ломает стандартный вход в игру.
### Сообщения
```text
CMSG_MOONWELL_CUSTOMIZATION_CREATE
protocol_version
catalog_version
option_count
repeated(option_id, choice_id)
SMSG_MOONWELL_CUSTOMIZATION_RESULT
result_code
normalized choices
SMSG_MOONWELL_CUSTOMIZATION_SNAPSHOT
player_guid
catalog_version
option_count
repeated(option_id, choice_id)
CMSG_MOONWELL_CUSTOMIZATION_UPDATE
option_count
repeated(option_id, choice_id)
SMSG_MOONWELL_CUSTOMIZATION_DELTA
player_guid
option_count
repeated(option_id, choice_id)
```
### Экран выбора персонажа
Предпочтительный вариант — отдельный snapshot после получения списка персонажей. Не расширять штатный пакет без строгой проверки длины и совместимости.
Клиент должен:
- сопоставить snapshot с GUID персонажа;
- применить его к модели выбранного персонажа;
- хранить данные только до обновления от сервера;
- показывать стандартную внешность, если snapshot отсутствует или версия несовместима.
## 11. Клиентский runtime API
Планируемый API WarcraftXL:
```text
MoonWellCustomizationGetCatalogVersion()
MoonWellCustomizationGetOptions(race, gender)
MoonWellCustomizationGetChoices(optionId)
MoonWellCustomizationGetCurrent(optionId)
MoonWellCustomizationPreview(optionId, choiceId)
MoonWellCustomizationResetPreview()
MoonWellCustomizationCommitPreview()
MoonWellCustomizationRandomize()
MoonWellCustomizationApplySnapshot(guid, data)
MoonWellCustomizationClear(guid)
```
Требования:
- Lua получает только безопасные операции высокого уровня;
- нативный слой владеет указателями моделей и их жизненным циклом;
- повторное применение snapshot идемпотентно;
- preview не меняет серверное состояние;
- при ошибке модель возвращается к последнему подтверждённому snapshot;
- смена расы или пола пересчитывает допустимость всех параметров;
- отсутствие M2/текстуры отключает только конкретный вариант, а не весь экран.
## 12. Применение внешности
Порядок применения должен быть фиксированным:
1. базовая раса и пол;
2. стандартные параметры 3.3.5a;
3. `CharSections` и текстурные слои;
4. geoset базовой модели;
5. скрытие/конфликты с экипировкой;
6. независимые косметические M2-каналы;
7. обновление материалов и композитной текстуры;
8. окончательное обновление позы и камеры превью.
При смене одного параметра обновляется только затронутый слой, если это безопасно. Полная пересборка модели используется как fallback.
## 13. Интерфейс создания персонажа
### Структура
- категории слева или справа от модели;
- прокручиваемая сетка вариантов;
- текстовое название активной категории;
- состояние выбранного варианта;
- кнопки случайного выбора и сброса;
- возврат к выбору расы/класса без потери валидных параметров;
- подтверждение создания только после серверной валидации;
- плавное приближение камеры к зоне редактирования.
### Категории первой версии
- кожа;
- лицо;
- причёска;
- цвет волос;
- борода/особенность лица;
- шрамы;
- татуировки;
- серьги/пирсинг;
- расовый аксессуар.
Категории скрываются, если для текущей расы/пола нет вариантов.
### Камера
- профиль камеры задаётся по расе, полу и категории;
- отдельно настраиваются distance, вертикальная цель, горизонтальный сдвиг и FOV;
- переход использует easing через `OnUpdate`;
- короткие и средние расы имеют отдельные профили;
- при выходе из кастомизации камера плавно возвращается к полному росту;
- вращение персонажа доступно во всех режимах;
- UI не перекрывает лицо и активный аксессуар на 4:3, 16:9 и 16:10.
### Ограничения UI 3.3.5a
- XML загружается раньше Lua;
- именованные Button и ScrollFrame;
- `relativeTo`, а не `relativeKey`;
- `$parentX`, а не `$parent.X`;
- `SetWidth`/`SetHeight` вместо `SetSize`;
- таймеры и анимации через `OnUpdate`;
- UI-атласы режутся на тайлы не более 512×512.
## 14. Парикмахерская и изменение существующего персонажа
- использовать тот же каталог и preview API;
- получать текущий серверный snapshot при открытии;
- считать стоимость на сервере;
- подтверждать изменение одним атомарным запросом;
- откатывать preview при закрытии или отказе сервера;
- блокировать недоступные варианты;
- поддерживать бесплатные/платные категории отдельными правилами;
- обновлять внешность окружающим только после подтверждения.
## 15. Получение retail-ассетов без установки клиента
### Инструменты
- `wow.export` в online-режиме — поиск и предварительный просмотр;
- Wago Tools/wow-listfile — поиск пути и `FileDataID`;
- TACTSharp/TACTTool — точечная загрузка исходных файлов с CDN Blizzard.
### Манифест ассета
```text
asset_id
source_product
source_build
file_data_id
original_path
target_path
sha256
kind
parent_asset_id
license_note
```
### Пайплайн
1. Выбрать модель и исходный retail build.
2. Зафиксировать корневой `FileDataID`.
3. Выгрузить M2 и определить зависимости.
4. Загрузить `.skin`, `.skel`, `.anim` и текстуры.
5. Проверить хэши и комплектность.
6. Проверить модель в изолированном preview.
7. Проверить downport через `wxl-modern-assets`.
8. Добавить запись в каталог кастомизации.
9. Упаковать только выбранные файлы.
10. Не помещать массовый дамп retail-клиента в Git.
### Автоматические проверки ассета
- поддерживаемая версия M2/MD21;
- наличие всех skin-профилей;
- разрешимые FileDataID и пути текстур;
- наличие внешнего скелета/анимаций;
- attachment points для целевой расы;
- лимит костей на draw после разбиения;
- валидные материалы и blend modes;
- отсутствие коллизий целевых путей;
- размер итогового MPQ и память после загрузки;
- корректное освобождение ресурсов.
## 16. Этапы реализации
### Этап 0. Исследование и фиксация контрактов
- [ ] Зафиксировать ревизии WarcraftXL и всех модулей.
- [ ] Зафиксировать исходный retail build для ассетов.
- [ ] Составить карту существующих хуков персонажа и DBC.
- [ ] Проверить структуру штатных пакетов создания/выбора персонажа.
- [ ] Зафиксировать каталог option/choice ID.
- [ ] Утвердить правила доступности и монетизации.
- [ ] Выбрать первую расу для вертикального среза: человек.
**Результат:** техническая спецификация без конфликтующих точек расширения.
### Этап 1. Интеграция equip-extension
- [ ] Добавить репозиторий как закреплённый submodule.
- [ ] Адаптировать CMake/module layout.
- [ ] Собрать Win32 runtime и x64 host.
- [ ] Устранить конфликт хуков с текущим WarcraftXL.
- [ ] Исправить снятие collection M2.
- [ ] Очистить мусорные поля `ItemDisplayInfo.dbc`.
- [ ] Добавить smoke-тест Model1/Model2 на каждом поддержанном слоте.
- [ ] Добавить диагностическое логирование.
**Результат:** современная объёмная экипировка работает и корректно снимается.
### Этап 2. Независимые косметические каналы
- [ ] Отделить attachment runtime от реальных слотов экипировки.
- [ ] Реализовать реестр косметических каналов.
- [ ] Реализовать add/replace/remove/clear.
- [ ] Реализовать conflict groups и приоритеты.
- [ ] Реализовать скрытие под шлемом.
- [ ] Добавить API preview.
- [ ] Проверить смену карты, формы и пола.
**Результат:** аксессуар можно показать без создания фиктивного предмета.
### Этап 3. Asset pipeline
- [ ] Добавить входной manifest с FileDataID.
- [ ] Реализовать пакетную загрузку через CDN.
- [ ] Добавить локальный кэш по хэшу.
- [ ] Автоматически проверять зависимости.
- [ ] Формировать отчёт о пропущенных файлах.
- [ ] Интегрировать выбранные ассеты в MPQ build.
- [ ] Добавить контроль размера и дубликатов.
**Результат:** воспроизводимая сборка выбранных retail-ассетов без полного клиента.
### Этап 4. Серверное хранение и протокол
- [ ] Добавить миграцию `character_customization`.
- [ ] Реализовать серверный каталог допустимых вариантов.
- [ ] Реализовать create/update validation.
- [ ] Реализовать snapshot и delta.
- [ ] Подключить данные к character enum/select flow.
- [ ] Рассылать состояние в visibility range.
- [ ] Добавить rate limit и журнал ошибок.
- [ ] Добавить fallback для клиента без совместимой версии.
**Результат:** параметры сохраняются и одинаково видны всем клиентам.
### Этап 5. Текстурные слои и geoset
- [ ] Расширить/переопределить `CharSections` данными MoonWell.
- [ ] Реализовать слои шрамов, татуировок и макияжа.
- [ ] Реализовать таблицу geoset базовой модели.
- [ ] Синхронизировать цветовые зависимости.
- [ ] Обеспечить совместимость с надетой бронёй.
- [ ] Добавить полную пересборку как fallback.
**Результат:** работают не только прикрепляемые M2, но и полноценные параметры тела/лица.
### Этап 6. Новый UI создания персонажа
- [ ] Создать адаптивную панель категорий.
- [ ] Создать прокручиваемую сетку choices.
- [ ] Подключить preview API.
- [ ] Добавить race/gender/category camera profiles.
- [ ] Добавить randomize и reset.
- [ ] Добавить обработку недоступного ассета.
- [ ] Добавить серверное подтверждение создания.
- [ ] Проверить 4:3, 16:9, 16:10 и UI scale.
**Результат:** законченный retail-подобный пользовательский сценарий.
### Этап 7. Вертикальный срез — человек
- [ ] Мужская и женская модели.
- [ ] Стандартные категории.
- [ ] Минимум одна новая текстурная категория.
- [ ] Минимум два M2-косметических канала.
- [ ] Сохранение, выбор персонажа и отображение в мире.
- [ ] Видимость другим игрокам.
- [ ] Парикмахерская/изменение существующего персонажа.
- [ ] Полный regression-тест экипировки.
**Результат:** одна раса полностью проходит production-сценарий.
### Этап 8. Масштабирование на все расы WotLK
- [ ] Дворфы.
- [ ] Ночные эльфы.
- [ ] Гномы.
- [ ] Дренеи.
- [ ] Орки.
- [ ] Нежить.
- [ ] Таурены.
- [ ] Тролли.
- [ ] Эльфы крови.
- [ ] Отдельная настройка камер для каждого пола.
- [ ] Матрица конфликтов расовых элементов с экипировкой.
**Результат:** единый уровень качества для всех доступных рас.
### Этап 9. Стабилизация и выпуск
- [ ] Нагрузочный тест большого скопления игроков.
- [ ] Проверка утечек модели/текстур при многократной смене вариантов.
- [ ] Проверка холодного кэша WarcraftXLHost.
- [ ] Проверка отсутствующих/повреждённых ассетов.
- [ ] Версионирование manifest, каталога и протокола.
- [ ] Миграция существующих персонажей.
- [ ] Rollback-пакет.
- [ ] Документация для добавления новой категории/расы.
- [ ] Обновление deploy-скрипта и launcher manifest.
**Результат:** воспроизводимый production-релиз.
## 17. Матрица тестирования
### Персонажи
- каждая раса × каждый пол;
- стандартный режим × предатель;
- новый персонаж × существующий персонаж;
- минимальное × максимальное число выбранных параметров;
- случайная комбинация × преднамеренно конфликтная комбинация.
### Состояния клиента
- создание;
- выбор;
- загрузочный экран;
- вход в мир;
- появление другого игрока;
- телепорт;
- смерть/дух;
- транспорт;
- shapeshift/превращение;
- парикмахерская;
- смена экипировки;
- скрытие шлема/плаща;
- `/reload`;
- переподключение;
- выход и повторный вход.
### Графика
- native renderer и основной D3D9On12 путь;
- разные уровни component texture quality;
- включённые/выключенные SSAA, SSAO и AA;
- дальние LOD;
- тени;
- прозрачные и emissive материалы;
- несколько одинаковых моделей одновременно;
- 4:3, 16:9, 16:10 и разные UI scale.
### Сеть и сервер
- потеря/повтор snapshot;
- snapshot до появления модели и после неё;
- неизвестная версия каталога;
- неизвестный option/choice;
- запрещённый выбор;
- слишком большое сообщение;
- быстрое повторное изменение;
- одновременное изменение и телепорт;
- сохранение при logout/crash;
- удаление и восстановление персонажа.
## 18. Производительность
Целевые ограничения:
- не выполнять разбор каталога каждый кадр;
- не пересобирать всю модель при изменении независимого аксессуара;
- кэшировать разрешённые пути и обработанные modern assets;
- не создавать дубликаты одной и той же дочерней M2-модели;
- освобождать attachment при удалении/скрытии объекта;
- ограничить число одновременных косметических M2 на персонажа;
- иметь настройку отключения дальних косметических attachment;
- измерять время первой загрузки, потребление RAM/VRAM и frame time;
- логирование hot path отключено в release-сборке.
Предварительный бюджет первой версии:
- до 6 независимых M2-каналов на персонажа;
- не более двух моделей на канал;
- отсутствие постоянной работы Lua `OnUpdate`, кроме активной UI-анимации;
- пересборка полной внешности только при snapshot, смене расы/пола или восстановлении после ошибки.
## 19. Безопасность и целостность
- сервер проверяет все ID и комбинации;
- клиент не передаёт пути файлов серверу;
- протокол содержит только числовые option/choice ID;
- сообщения имеют максимальный размер и максимальное число записей;
- сервер нормализует дубликаты option ID;
- неизвестные значения не записываются в БД;
- стоимость изменения рассчитывается сервером;
- unlock condition проверяется сервером;
- клиентский каталог не считается доказательством доступности;
- журналировать несовпадение версии и попытки недопустимых изменений.
## 20. Сборка, доставка и откат
### Сборка
- закреплённые submodule revisions;
- asset manifest с SHA-256;
- генерация клиентского и серверного каталога из одного источника;
- сборка WarcraftXL Win32 и Host x64;
- сборка MPQ;
- автоматическая проверка оригинального `Wow.exe`;
- формирование launcher manifest.
### Версионирование
- `customization_protocol_version`;
- `customization_catalog_version`;
- `customization_asset_version`;
- совместимая версия WarcraftXL runtime.
### Откат
- сервер умеет не отправлять расширенные сообщения;
- клиент при отсутствии данных показывает стандартную внешность;
- отключение модуля не блокирует вход персонажа;
- миграция БД не удаляет стандартные параметры;
- предыдущие MPQ/runtime хранятся как отдельный release artifact;
- неизвестные сохранённые choices не удаляются автоматически без миграции.
## 21. Оценка трудоёмкости
Для одного разработчика при наличии подготовленных ассетов:
| Работа | Оценка |
|---|---:|
| Адаптация и исправление equip-extension | 47 дней |
| Независимые косметические каналы | 4–7 дней |
| Asset pipeline | 35 дней |
| Серверное хранение и протокол | 4–7 дней |
| Текстурные слои и geoset | 5–10 дней |
| Новый UI создания/изменения | 5–8 дней |
| Полный вертикальный срез одной расы | 5–10 дней |
| Каждая следующая раса | 2–5 дней |
| Стабилизация и regression | 712 дней |
Ориентиры:
- технический прототип одной расы: 1–2 недели;
- production-вертикаль людей: 3–5 недель;
- все десять рас WotLK: 2–3 месяца;
- насыщенность категориями, близкая к retail: 3–6 месяцев.
Главный переменный фактор — подготовка и проверка ассетов, а не серверная схема.
## 22. Рекомендуемый первый milestone
Вертикальный срез для людей обоих полов:
- штатные пять категорий;
- одна текстурная категория: шрамы;
- два независимых M2-канала: серьги и аксессуар для волос;
- серверное сохранение;
- snapshot на экране выбора;
- видимость другим игрокам;
- изменение через парикмахерскую;
- камера по категориям;
- корректная работа со шлемом;
- один полный набор automated/manual acceptance checks.
Этот milestone должен подтвердить всю архитектуру до масштабирования на остальные расы.
## 23. Критерии готовности production-версии
- [ ] `Wow.exe` идентичен оригиналу по SHA-256.
- [ ] Все расширения поставляются через WarcraftXL и MPQ.
- [ ] Клиент и сервер используют одинаковую версию каталога.
- [ ] Внешность сохраняется после выхода и перезапуска клиента.
- [ ] Экран создания, экран выбора и модель в мире совпадают.
- [ ] Другие игроки видят подтверждённую сервером внешность.
- [ ] Недоступные варианты невозможно применить изменённым клиентом.
- [ ] Смена/снятие варианта не оставляет collection M2.
- [ ] Нет placeholder-моделей из мусорных строк `ItemDisplayInfo.dbc`.
- [ ] Нет заметных утечек памяти при многократном preview.
- [ ] Отсутствующий ассет не приводит к падению клиента.
- [ ] Все расы и оба пола проходят тестовую матрицу.
- [ ] Камера корректно кадрирует низких, средних и высоких персонажей.
- [ ] UI работает на 4:3, 16:9, 16:10 и разных UI scale.
- [ ] Реализован и проверен rollback.
- [ ] Описан процесс добавления новой категории, choice и ассета.
## 24. Открытые решения перед началом реализации
- точная ревизия `wxl-equip-extension` для закрепления;
- список категорий первого релиза;
- исходный retail build для моделей;
- набор моделей для вертикального среза людей;
- формат единого каталога: JSON, CSV или генератор из SQL/YAML;
- транспорт custom packets между WarcraftXL и AzerothCore;
- способ передачи snapshots на экране выбора;
- политика скрытия аксессуаров под шлемом;
- правила доступности и разблокировки вариантов;
- использование парикмахерской или отдельного UI изменения внешности;
- лимит косметических M2 на одного персонажа;
- политика хранения выбранных Blizzard-ассетов и доступа к ним;
- минимальная поддерживаемая версия launcher/runtime.