# План расширенной кастомизации персонажей 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 | 4–7 дней | | Независимые косметические каналы | 4–7 дней | | Asset pipeline | 3–5 дней | | Серверное хранение и протокол | 4–7 дней | | Текстурные слои и geoset | 5–10 дней | | Новый UI создания/изменения | 5–8 дней | | Полный вертикальный срез одной расы | 5–10 дней | | Каждая следующая раса | 2–5 дней | | Стабилизация и regression | 7–12 дней | Ориентиры: - технический прототип одной расы: 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.