diff --git a/.env.example b/.env.example index 96f07f9..a045bcc 100644 --- a/.env.example +++ b/.env.example @@ -5,4 +5,8 @@ AWS_SECRET_ACCESS_KEY= AWS_DEFAULT_REGION= AWS_BUCKET= AWS_ENDPOINT= -AWS_USE_PATH_STYLE_ENDPOINT= \ No newline at end of file +AWS_USE_PATH_STYLE_ENDPOINT= + +PRODUCTION_REALMLIST= +PTR_REALMLIST= +LOCAL_REALMLIST= diff --git a/.gitignore b/.gitignore index f914e60..ed2187a 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,8 @@ __pycache__/ manifest.json .claude .vscode -dist \ No newline at end of file +dist +build/ +Wow*.exe +*.backup.exe +Logs/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..461366c --- /dev/null +++ b/.gitmodules @@ -0,0 +1,20 @@ +[submodule "vendor/warcraftxl"] + path = vendor/warcraftxl + url = https://github.com/WarcraftXL/wxl-core.git + branch = main +[submodule "vendor/modules/wxl-modern-assets"] + path = vendor/modules/wxl-modern-assets + url = https://github.com/WarcraftXL/wxl-modern-assets.git + branch = main +[submodule "vendor/modules/wxl-modern-render"] + path = vendor/modules/wxl-modern-render + url = https://github.com/WarcraftXL/wxl-modern-render.git + branch = main +[submodule "vendor/modules/wxl-unit-outline"] + path = vendor/modules/wxl-unit-outline + url = https://github.com/WarcraftXL/wxl-unit-outline.git + branch = main +[submodule "vendor/modules/wxl-modern-adt"] + path = vendor/modules/wxl-modern-adt + url = https://github.com/WarcraftXL/wxl-modern-adt.git + branch = main diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..b3da6b1 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,46 @@ +# MoonWell Client Sources — Agent Guide + +## Проект + +WoW-клиент на базе патча **3.3.5a (build 12340, WotLK)**. Репозиторий содержит UI-аддоны и +кастомные интерфейсы для приватного сервера MoonWell. + +Стек: Lua 5.1, FrameXML (XML + Lua), WoW Addon API 3.3.5. + +--- + +## Навыки (Skills) + +Перед тем как работать с UI — **прочитай соответствующий файл из `ai-skills/`**. + +| Задача | Файл | +|--------|------| +| Верстка фреймов, XML, Lua CreateFrame, pixel-perfect из Figma, текстуры, шрифты, якоря | [`ai-skills/ui/SKILL.md`](ai-skills/ui/SKILL.md) | +| Виджеты, типы фреймов, Button/EditBox/ScrollFrame, события, SavedVariables, Blizzard API | [`ai-skills/ui/widgets-and-api.md`](ai-skills/ui/widgets-and-api.md) | + +Читай **весь файл** скилла, а не отдельные секции — там есть ограничения API, типичные ошибки +и готовые шаблоны. + +--- + +## Ключевые ограничения (всегда держи в голове) + +- `## Interface: 30300` — никаких retail-API +- Нет `SetSize()` → только `SetWidth()` / `SetHeight()` +- Нет `C_Timer`, `CreateFramePool`, `PixelUtil` +- Текстуры: только степени двойки, максимум 512×512 px, формат `.tga` / `.blp` +- XML-атрибуты: `relativeTo` (не `relativeKey`), `$parentX` (не `$parent.X`) +- Кнопки и ScrollFrame в XML должны иметь `name` + +--- + +## Структура аддона + +``` +AddonName/ +├── AddonName.toc ← обязательно, имя файла = имя папки +├── AddonName.xml ← верстка (загружается первой) +└── AddonName.lua ← логика +``` + +Порядок файлов в TOC важен: XML раньше Lua. diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..66927ee --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,74 @@ +cmake_minimum_required(VERSION 3.20) +project(MoonWellWarcraftXL LANGUAGES CXX) + +# WarcraftXL remains an upstream submodule. MoonWell modules are attached to +# its aggregate DLL target here, so updating the framework does not mix our +# client-specific offsets and policy into the upstream checkout. +add_subdirectory(vendor/warcraftxl) + +set(WXL_EXTERNAL_MODULES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/vendor/modules") + +function(wxl_collect_sources output) + file(GLOB_RECURSE collected CONFIGURE_DEPENDS ${ARGN}) + set(${output} "${collected}" PARENT_SCOPE) +endfunction() + +if(TARGET WarcraftXL) + wxl_collect_sources(WXL_MODERN_ASSETS_RUNTIME + "${WXL_EXTERNAL_MODULES_DIR}/wxl-modern-assets/src/*.cpp" + "${WXL_EXTERNAL_MODULES_DIR}/wxl-modern-assets/shared/*.cpp") + if(WXL_MODERN_ASSETS_EXCLUDE_REGEX) + list(FILTER WXL_MODERN_ASSETS_RUNTIME EXCLUDE REGEX + "${WXL_MODERN_ASSETS_EXCLUDE_REGEX}") + endif() + wxl_collect_sources(WXL_MODERN_RENDER_RUNTIME + "${WXL_EXTERNAL_MODULES_DIR}/wxl-modern-render/src/*.cpp") + wxl_collect_sources(WXL_UNIT_OUTLINE_RUNTIME + "${WXL_EXTERNAL_MODULES_DIR}/wxl-unit-outline/src/*.cpp") + wxl_collect_sources(WXL_MODERN_ADT_RUNTIME + "${WXL_EXTERNAL_MODULES_DIR}/wxl-modern-adt/src/*.cpp" + "${WXL_EXTERNAL_MODULES_DIR}/wxl-modern-adt/shared/*.cpp") + + target_sources(WarcraftXL PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/modules/moonwell/src/MoonWell.cpp" + ${WXL_MODERN_ASSETS_RUNTIME} + ${WXL_MODERN_RENDER_RUNTIME} + ${WXL_UNIT_OUTLINE_RUNTIME} + ${WXL_MODERN_ADT_RUNTIME}) + + # wxl-modern-render needs its module-root includes and D3D12 import library. + include("${WXL_EXTERNAL_MODULES_DIR}/wxl-modern-render/module.cmake") +endif() + +if(TARGET WarcraftXLHost) + wxl_collect_sources(WXL_MOONWELL_HOST + "${CMAKE_CURRENT_SOURCE_DIR}/modules/moonwell/host/*.cpp") + wxl_collect_sources(WXL_MODERN_ASSETS_HOST + "${WXL_EXTERNAL_MODULES_DIR}/wxl-modern-assets/host/*.cpp" + "${WXL_EXTERNAL_MODULES_DIR}/wxl-modern-assets/shared/*.cpp") + if(WXL_MODERN_ASSETS_EXCLUDE_REGEX) + list(FILTER WXL_MODERN_ASSETS_HOST EXCLUDE REGEX + "${WXL_MODERN_ASSETS_EXCLUDE_REGEX}") + endif() + wxl_collect_sources(WXL_MODERN_ADT_HOST + "${WXL_EXTERNAL_MODULES_DIR}/wxl-modern-adt/host/*.cpp" + "${WXL_EXTERNAL_MODULES_DIR}/wxl-modern-adt/shared/*.cpp") + + target_sources(WarcraftXLHost PRIVATE + ${WXL_MOONWELL_HOST} + ${WXL_MODERN_ASSETS_HOST} + ${WXL_MODERN_ADT_HOST}) +endif() + +# Minimal native-D3D9 proxy retained as a recovery renderer. The regular +# package uses WarcraftXL's D3D9On12 proxy required by wxl-modern-render. +if(CMAKE_SIZEOF_VOID_P EQUAL 4) + add_library(MoonWellLoader SHARED + "${CMAKE_CURRENT_SOURCE_DIR}/loader/d3d9.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/loader/d3d9.def") + set_target_properties(MoonWellLoader PROPERTIES + OUTPUT_NAME "d3d9-native" + PREFIX "" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/artifacts") + target_compile_definitions(MoonWellLoader PRIVATE WIN32_LEAN_AND_MEAN NOMINMAX) +endif() diff --git a/CUSTOMIZATION_PLAN.md b/CUSTOMIZATION_PLAN.md new file mode 100644 index 0000000..3b6b9b0 --- /dev/null +++ b/CUSTOMIZATION_PLAN.md @@ -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 | 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. diff --git a/CUSTOM_CREATURES.md b/CUSTOM_CREATURES.md new file mode 100644 index 0000000..3b030c1 --- /dev/null +++ b/CUSTOM_CREATURES.md @@ -0,0 +1,83 @@ +# Автоматический импорт mount и pet + +Список современных моделей находится в `custom-creatures.json`. В нём есть две независимые +секции: + +```json +{ + "mounts": [ + "assets/creatures/my_mount" + ], + "pets": [ + "assets/creatures/my_pet" + ] +} +``` + +Папка должна быть результатом **Raw M2 export** из wow.export и содержать: + +- один основной `.m2`; +- `*.manifest.json`; +- все упомянутые в manifest текстуры, skin, skeleton, bone и animation-файлы. + +Разрешены абсолютные пути, например `C:/Users/sindo/wow.export/creature/catslime`, но для +воспроизводимой сборки папку лучше скопировать внутрь репозитория и указать относительный путь. + +## Что делает сборщик + +При обычном запуске `tool.exe`, `run.ps1` или `deploy.ps1` сборщик: + +1. читает manifest каждой модели и размещает retail M2 со всеми зависимостями в loose-каталоге + `Data/Patch-WXL.MPQ`, создавая рядом `.mdx`-алиас для загрузчика WoW 3.3.5, чтобы WarcraftXL всегда + преобразовывал MD21 до загрузки клиентом; +2. генерирует `WXLFileData.csv` для WarcraftXL; +3. дописывает модели в `CreatureModelData.dbc` и `CreatureDisplayInfo.dbc`; +4. сохраняет стабильные ID в `custom-creatures.lock.json`; +5. для `pets` создаёт companion summon spell и строку skill line `778`; +6. кладёт серверные DBC, SQL и таблицу ID в `build/server-dbc`. + +Полный `Spell.dbc` в патч не копируется. WarcraftXL читает компактный +`WXLSpellOverrides.tsv` и при открытии DBC добавляет новые spell-записи к штатному файлу клиента. + +Перестановка моделей в списке не меняет уже выданные ID. Lock-файл необходимо хранить в Git. + +## Дополнительные параметры + +Если значений по умолчанию недостаточно, вместо строки используется объект: + +```json +{ + "folder": "assets/creatures/my_mount", + "key": "my_mount", + "name": "My Mount", + "name_ru": "Мой транспорт", + "archive": "Creature/MyMount", + "model_file": "my_mount.m2", + "template_display_id": 2404, + "display_scale": 1.0, + "model_scale": 1.0, + "collision_width": 0.6111, + "collision_height": 2.031, + "mount_height": 1.8657, + "flags": 0 +} +``` + +Для `mounts` по умолчанию клонируется верховая лошадь с display ID `2404`, для `pets` — +компаньон-кот с display ID `5448`. Шаблон задаёт физические размеры, звук и прочие поля DBC; +параметры объекта позволяют их переопределить. + +## Установка на сервер + +Для каждого элемента `pets` сборщик автоматически выдаёт `creatureEntry`, `summonSpellID` и +`skillLineAbilityID`. Значения находятся в `build/server-dbc/custom-creatures.csv`. + +1. Скопировать `CreatureModelData.dbc` и `CreatureDisplayInfo.dbc` из `build/server-dbc` в + серверный каталог `data/dbc`. +2. Применить `build/server-dbc/custom-creatures.sql` к `acore_world`. +3. Перезапустить worldserver: DBC и таблицы `spell_dbc` загружаются только при старте. +4. Для проверки изучить выданный spell командой `.learn `. + +SQL создаёт `creature_template`, `creature_model_info`, `creature_template_model`, companion spell и строку skill line. +Генерация полноценного mount spell для секции `mounts` остаётся отдельным этапом: mount требует +другой spell-шаблон с аурами скорости и `SPELL_AURA_MOUNTED`. diff --git a/README.md b/README.md index 7748f09..3055a40 100644 --- a/README.md +++ b/README.md @@ -1,90 +1,143 @@ # MoonWell Client Sources -Репозиторий с ресурсами и исполняемым файлом модифицированного клиента World of Warcraft 3.3.5a. +Исходники клиентских изменений MoonWell для World of Warcraft 3.3.5a (build 12340). -Основная цель проекта: хранить и сопровождать клиентские изменения поверх стандартных MPQ-пакетов WoW, включая интерфейс, графику, звук и дополнительные данные для кастомных систем сервера. +Клиент переведён на [WarcraftXL](https://github.com/WarcraftXL): `Wow.exe` больше не содержит +MoonWell-патчей. Неподписанный оригинальный executable загружается как обычно, локальный +`d3d9.dll` proxy подхватывает `WarcraftXL.dll`, а модуль MoonWell применяет проверенные изменения +только к памяти запущенного процесса. -## Что находится в репозитории +## Что перенесено из модифицированного Wow.exe -- `Wow.exe` - модифицированный клиентский исполняемый файл. - - Поддерживает использование до 4 ГБ ОЗУ. - - Игнорирует блокирование изменений в исходниках `GlueXML`, что позволяет вносить свои изменения в интерфейс и модели. -- `patch-4/` - наши изменения поверх стандартного `patch-4.MPQ`. - - Содержит графические элементы внутриигрового магазина. - - Основная зона изменений: `Interface/Store_UI`. -- `patch-ruRU-4/` - наши изменения поверх стандартных `patch-ruRU-1.MPQ`, `patch-ruRU-2.MPQ` и `patch-ruRU-3.MPQ`. - - Содержит ресурсы локали `ruRU`, связанные с экраном входа, `GlueXML`, заставками и звуком. - - Внутри есть `Interface/GlueXML`, `Interface/Glues`, `Interface/LoginScreen`, `Sound/Ambience`, `Sound/Music`. -- `patch-ruRU-5/` - пакет русской локализации и дополнительных интерфейсных ресурсов. - - Содержит перевод на русский язык для glue-интерфейса и связанных экранов клиента. - - Внутри есть `Interface/GlueXML`, `Interface/Glues`, `Interface/GluesVideo`, `Interface/Loginscreen`, `Interface/tooltips`, `Interface/cinematics`. -- `patch-Z/` - кастомный пакет для модуля Mythic+. - - Содержит графические ресурсы Mythic+. - - Также включает связанные клиентские данные в `DBFielsClient/` и иконки в `Interface/Icons/`. +- разблокировка пользовательского `GlueXML`; +- `CreateCharacter(name, modeId)` и поле режима в `CMSG_CHAR_CREATE`; +- одиннадцатое значение `GetCharacterInfo` — `charFlags`, включая флаг предателя `0x40000000`; +- загрузка WarcraftXL без import-table patch и без отдельного injector. -## Структура по назначению +Large Address Aware намеренно не включён: Windows читает этот PE-флаг до загрузки DLL, поэтому +сохранить его и одновременно оставить файл байт-в-байт оригинальным невозможно. Это означает +стандартный 2-ГБ лимит адресного пространства для 32-битного клиента. -### Внутриигровой магазин +## Структура -Файлы магазина находятся в [`patch-4/Interface/Store_UI`](./patch-4/Interface/Store_UI). +```text +modules/moonwell/ MoonWell runtime-модуль WarcraftXL +vendor/warcraftxl/ закреплённый upstream git submodule +vendor/modules/ закреплённые модули WarcraftXL +src/Data/ исходники MPQ-патчей +tool/ сборщик MPQ +build-warcraftxl.ps1 сборка Win32 runtime/proxy и x64 asset host +run.ps1 полная сборка, установка и запуск клиента +Wow_Original.exe локальный оригинал build 12340 (не хранится в Git) +``` -Примеры ресурсов: +Подключены модули `wxl-modern-assets`, `wxl-modern-render`, `wxl-unit-outline` и +`wxl-modern-adt`. Их точные ревизии вместе с ревизией ядра закреплены git submodule. +Для обновления всех зависимостей WarcraftXL: -- `Currencies/Gold.blp` -- `Currencies/Token.blp` -- `Frames/StoreFrame_Main.blp` +```powershell +git submodule update --remote vendor/warcraftxl vendor/modules/* +``` -### Экран входа и локализованные ресурсы +После обновления обязательно пересоберите и проверьте вход/создание персонажа: API WarcraftXL +пока развивается. -Файлы экрана входа и связанные ресурсы находятся в [`patch-ruRU-4`](./patch-ruRU-4). +## Требования -Основные каталоги: +- Visual Studio 2022 с C++ toolchain для Win32 и x64; +- CMake 3.20+; +- Rust/Cargo для существующего MPQ-сборщика; +- локальный оригинальный `Wow_Original.exe` с SHA-256 + `AA63A5750D60EF16746C686B3D5E26876D98953EAB08B1C026CD0FAF78E88CB8`. -- `Interface/GlueXML` - Lua/XML-исходники интерфейса загрузки и логина -- `Interface/Glues` - графика и модели для glue-экрана -- `Interface/LoginScreen` - фон и связанные изображения -- `Sound/Ambience/GlueScreen` - фоновые звуки -- `Sound/Music/GlueScreenMusic` - музыка экрана входа +После клонирования инициализируйте submodule: -### Русский перевод для `patch-ruRU-5` +```powershell +git submodule update --init --recursive +``` -Файлы русской локализации и расширенного glue-интерфейса находятся в [`patch-ruRU-5`](./patch-ruRU-5). +## Сборка WarcraftXL -Основные каталоги: +Быстрое полное развёртывание клиента одной командой: -- `Interface/GlueXML` - Lua/XML-исходники экранов логина, выбора реалма, выбора и создания персонажа -- `Interface/Glues` - текстуры, кнопки, логотипы и элементы интерфейса для `CharacterCreate` и `CharacterSelect` -- `Interface/GluesVideo` - видеоресурсы и ассеты glue-экранов -- `Interface/Loginscreen` - фон и изображения экрана входа -- `Interface/tooltips` - локализованные рамки и оформление тултипов -- `Interface/cinematics` - элементы интерфейса для роликов и заставок +```powershell +.\deploy.ps1 +``` -Этот пакет используется как слой русификации для дополнительных экранов клиента и их визуальных элементов. +Скрипт инициализирует зависимости, собирает MPQ-патчи, Win32 runtime, D3D9 proxy и x64 Host, +обновляет `dist`, устанавливает комплект в клиент и формирует `manifest.json`. Путь берётся из +`WOW_HOME`/`.env`, а при их отсутствии используется `C:\Program Files (x86)\World of Warcraft`. -### Mythic+ +Полезные варианты: -Файлы Mythic+ находятся в [`patch-Z`](./patch-Z). +```powershell +# Явный путь и запуск клиента после установки +.\deploy.ps1 -ClientPath 'D:\Games\World of Warcraft' -StopClient -Launch -Основные каталоги: +# Быстро обновить только WarcraftXL без пересборки MPQ +.\deploy.ps1 -SkipDataBuild -- `Interface/MythicPlus/textures` - текстуры интерфейса Mythic+ -- `Interface/MythicPlus/sounds` - звуки таймеров и событий -- `Interface/Icons` - дополнительные иконки -- `DBFielsClient` - клиентские DBC-данные, связанные с отображением предметов и интерфейсом +# Аварийный native D3D9 вместо D3D9On12 +.\deploy.ps1 -NativeRenderer +``` -## Как воспринимать содержимое репозитория +Без установки в клиент: -- Каталоги `patch-*` представляют содержимое соответствующих MPQ-патчей в распакованном виде. -- Названия каталогов соответствуют именам клиентских патч-пакетов, поверх которых вносятся наши изменения. -- Репозиторий не является полной копией клиента WoW, а только набором модифицированных клиентских ресурсов и исполняемого файла. +```powershell +.\build-warcraftxl.ps1 -Configuration Release +``` -## Для чего используется +С установкой: -Проект нужен для сопровождения клиентской части MoonWell: +```powershell +.\build-warcraftxl.ps1 -Configuration Release ` + -ClientPath 'C:\Program Files (x86)\World of Warcraft' -Deploy +``` -- кастомизации GlueXML; -- поддержки русского перевода для `patch-ruRU-5`; -- поддержки внутриигрового магазина; -- добавления графики и данных для Mythic+; -- хранения пакетов графических улучшений; -- работы с модифицированным `Wow.exe` для WoW 3.3.5a. +При `-Deploy` скрипт: + +1. проверяет хеш `Wow_Original.exe`; +2. сохраняет прежний модифицированный клиент как `Wow.moonwell-patched.backup.exe`; +3. восстанавливает оригинальный `Wow.exe`; +4. устанавливает `WarcraftXL.dll`, D3D9On12 proxy и `Utils\WarcraftXLHost.exe`; +5. монтирует шейдеры modern ADT как loose patch `Data\Patch-WXL.MPQ`; +6. при `-PackagePath` кладёт полный runtime-комплект в `dist` для launcher/S3. + +Основной proxy использует D3D9On12, необходимый `wxl-modern-render`. Эффекты постобработки в самом +модуле по умолчанию выключены. Для диагностики или несовместимой видеосистемы можно собрать и +установить native-переходник без modern-render: + +```powershell +.\build-warcraftxl.ps1 -Configuration Release -NativeRenderer ` + -ClientPath 'C:\Program Files (x86)\World of Warcraft' -Deploy +``` + +Резервная DLL всегда также сохраняется как `Utils\d3d9-native.dll`. + +Полная сборка MPQ, установка WarcraftXL и запуск: + +```powershell +$env:WOW_HOME = 'C:\Program Files (x86)\World of Warcraft' +.\run.ps1 +``` + +Диагностика запуска находится в `Logs\wxl-core.log`, `Logs\d3d9proxy.log` и +`Utils\WarcraftXLHost.log` внутри клиента. + +## MPQ-пакеты + +Распакованные изменяемые слои уже находятся в `src/Data/`; полный набор базовых MPQ для сборки +WarcraftXL не требуется и в объектное хранилище не загружается. + +Основные пакеты: + +- `patch-4` — ресурсы внутриигрового магазина; +- `patch-ruRU-4` — экран входа и GlueXML; +- `patch-ruRU-5` — русская локализация и интерфейс; +- `patch-Z` — Mythic+ ресурсы и клиентские данные. + +## Лицензирование + +WarcraftXL распространяется по GPL-3.0 и подключён как отдельный upstream submodule. MoonWell-модуль, +скомпонованный в `WarcraftXL.dll`, должен распространяться с соблюдением GPL-3.0 и доступным +соответствующим исходным кодом. Репозиторий не должен публиковать Blizzard assets или `Wow.exe`. diff --git a/Wow.exe b/Wow.exe deleted file mode 100644 index fb862d7..0000000 Binary files a/Wow.exe and /dev/null differ diff --git a/ai-skills/ui/SKILL.md b/ai-skills/ui/SKILL.md new file mode 100644 index 0000000..af0c6d3 --- /dev/null +++ b/ai-skills/ui/SKILL.md @@ -0,0 +1,535 @@ +--- +name: wow-335a-ui +description: > + Верстка и разработка UI-аддонов для World of Warcraft 3.3.5a (WotLK, build 12340). + Используй этот скилл при любой работе с интерфейсом WoW 3.3.5: создание фреймов + через XML или Lua CreateFrame(), позиционирование через SetPoint/якоря, слои + (BACKGROUND/ARTWORK/OVERLAY/HIGHLIGHT), страты (frameStrata), текстуры, шрифты, + кнопки, ScrollFrame, скрипты-события, структура аддона (TOC + XML + Lua), + SavedVariables, работа с Blizzard API патча 3.3.5. Также применяй когда речь идёт + об AzerothCore, кастомных интерфейсах для WoW-прайват серверов 3.3.5a, Eluna + или модификации FrameXML. ОБЯЗАТЕЛЬНО применяй при задачах pixel-perfect переноса + дизайна (Figma/PSD/скриншот) в WoW UI: пересчёт координат с учётом UIParent scale, + конвертация цветов HEX→RGBA, подбор шрифтов, подготовка текстур (степени двойки, + TexCoord-кроп), устранение расхождений между макетом и игровым интерфейсом. +--- + +# WoW 3.3.5a — Верстка UI (FrameXML / AddOn Development) + +## Ключевые ограничения патча 3.3.5a + +- **API версии**: `## Interface: 30300` (build 12340) +- **Lua версия**: Lua 5.1 +- **Текстуры**: только степени двойки по ширине/высоте (8, 16, 32, 64, 128, 256, 512 px); максимум 512×512 +- **Нет** `:SetSize()` — только `:SetWidth()` / `:SetHeight()` (или через XML ``) +- **Нет** `hooksecurefunc` для защищённых фреймов без taint +- Отсутствуют многие retail-API: нет `C_Timer`, нет `CreateFramePool`, нет `PixelUtil` +- Таймеры — через `OnUpdate` с накоплением `elapsed` + +--- + +## Pixel-Perfect: перенос дизайна из Figma/PSD в WoW UI + +### Главная проблема: система координат WoW ≠ пиксели экрана + +WoW рисует UI в **виртуальных единицах**, а не в экранных пикселях. Размер виртуального экрана зафиксирован движком на **768 единиц по высоте**, ширина зависит от соотношения сторон: + +| Разрешение | Виртуальная ширина | Виртуальная высота | +|-----------|-------------------|-------------------| +| 1024×768 | 1024 | 768 | +| 1280×960 | 1024 | 768 | +| 1920×1080 | 1365 | 768 | +| 2560×1440 | 1365 | 768 | + +> **Вывод**: высота UIParent всегда = 768. Всё, что сделано в Figma на 768px по высоте, переносится 1:1 без пересчёта. При другой высоте холста в Figma — нужен коэффициент. + +### Пересчёт координат из Figma в WoW + +```lua +-- Формула: wow_value = figma_value * (768 / figma_canvas_height) +-- Если макет сделан на 1080px: +local SCALE = 768 / 1080 -- ≈ 0.711 + +local function px(figma_px) + return math.floor(figma_px * SCALE + 0.5) -- округление к ближайшему +end + +-- Использование: +frame:SetWidth(px(400)) -- figma: 400px → wow: 284 +frame:SetHeight(px(200)) -- figma: 200px → wow: 142 +frame:SetPoint("TOPLEFT", UIParent, "TOPLEFT", px(50), -px(30)) +``` + +> Если макет 768px в высоту — `SCALE = 1.0`, пересчёт не нужен. + +### UIParent scale и как он ломает пиксели + +Игрок может изменить масштаб UI в настройках. Это сдвигает все координаты. + +```lua +-- Получить текущий масштаб UIParent +local uiScale = UIParent:GetScale() -- обычно 0.64–1.0 + +-- Перевести экранные пиксели в виртуальные единицы WoW +local function screenPxToWow(px) + local screenH = select(2, GetPhysicalScreenSize()) -- реальный размер экрана + return px * (768 / screenH) / uiScale +end + +-- Принудительно зафиксировать scale (использовать с умом!) +-- UIParent:SetScale(1.0) -- сломает все стандартные фреймы +``` + +**Рекомендация**: не трогай `UIParent:SetScale()`. Вместо этого рисуй в виртуальных единицах и принимай, что у разных игроков масштаб разный. Для абсолютного pixel-perfect на конкретном разрешении — дай опцию ручного масштабирования фрейма в настройках. + +```lua +-- Масштабируй только свой фрейм +frame:SetScale(0.85) +-- Тогда все дочерние элементы тоже масштабируются +``` + +--- + +### Цвета: Figma HEX/RGBA → WoW RGBA + +WoW принимает цвета в диапазоне **0.0–1.0** (не 0–255). + +```lua +-- Конвертер HEX → WoW RGBA +local function hex(str, a) + str = str:gsub("#", "") + local r = tonumber(str:sub(1,2), 16) / 255 + local g = tonumber(str:sub(3,4), 16) / 255 + local b = tonumber(str:sub(5,6), 16) / 255 + return r, g, b, a or 1.0 +end + +-- Использование: +tex:SetVertexColor(hex("#FF6A00")) -- непрозрачный +tex:SetVertexColor(hex("#FF6A00", 0.8)) -- 80% непрозрачность +fs:SetTextColor(hex("#FFD100")) +frame:SetBackdropColor(hex("#1A1A2E", 0.95)) +frame:SetBackdropBorderColor(hex("#4A90D9")) +``` + +**Figma opacity → WoW alpha**: значение из Figma (например, 75%) делится на 100 → `0.75`. + +```lua +-- Figma: opacity 60% +frame:SetAlpha(0.60) +tex:SetAlpha(0.60) +``` + +--- + +### Шрифты: как приблизить к дизайну + +WoW 3.3.5a поддерживает только `.ttf` шрифты, помещённые в папку аддона. + +```lua +-- Кастомный шрифт из аддона +fs:SetFont("Interface\\AddOns\\MyAddon\\fonts\\MyFont.ttf", 14, "OUTLINE") +-- Флаги: "", "OUTLINE", "THICKOUTLINE", "MONOCHROME", "OUTLINE,MONOCHROME" +``` + +**Соответствие Figma → WoW размер шрифта**: + +| Figma (макет 1080px) | WoW pt (при SCALE=0.711) | +|---------------------|--------------------------| +| 12 px | 9 | +| 14 px | 10 | +| 16 px | 11 | +| 18 px | 13 | +| 24 px | 17 | +| 32 px | 23 | + +```lua +-- Автоматический пересчёт размера шрифта +local function fontSize(figma_pt) + return math.max(8, math.floor(figma_pt * SCALE + 0.5)) +end +fs:SetFont("Fonts\\FRIZQT__.TTF", fontSize(18), "OUTLINE") +``` + +> **Минимальный читаемый размер в WoW**: 8 pt. Ниже — нечитаемо. + +**Встроенные шрифты WoW 3.3.5a**: +``` +Fonts\FRIZQT__.TTF — основной интерфейсный (без кириллицы!) +Fonts\MORPHEUS.ttf — декоративный (заголовки) +Fonts\ARIALN.TTF — Arial Narrow +Fonts\skurri.ttf — шрифт повреждений +``` + +> **Кириллица**: встроенные шрифты WoW не поддерживают кириллицу. Положи в аддон `.ttf` с кириллицей (например, PT Sans, Roboto) и подключи явно. + +--- + +### Текстуры: подготовка под ограничения движка + +#### Требования к текстурам WoW 3.3.5a +- Ширина и высота — **степени двойки**: 2, 4, 8, 16, 32, 64, 128, 256, 512 +- Максимум: **512×512 px** +- Формат: `.tga` (RGBA, 32-bit) или `.blp` +- Текстура не обязана быть квадратной: 512×64 — ок, 256×128 — ок + +#### Как уместить большой элемент дизайна + +Если элемент из Figma больше 512px — разрезай на части: + +``` +[512×256] [512×256] ← верхняя половина (левая + правая) +[512×256] [512×256] ← нижняя половина +``` + +```lua +-- Сборка из 4 текстур +local tl = frame:CreateTexture(nil, "BACKGROUND") +tl:SetTexture("Interface\\AddOns\\MyAddon\\bg_tl") +tl:SetPoint("TOPLEFT", frame, "TOPLEFT") +tl:SetWidth(256); tl:SetHeight(128) + +local tr = frame:CreateTexture(nil, "BACKGROUND") +tr:SetTexture("Interface\\AddOns\\MyAddon\\bg_tr") +tr:SetPoint("TOPRIGHT", frame, "TOPRIGHT") +tr:SetWidth(256); tr:SetHeight(128) +-- ... и так далее +``` + +#### TexCoord — показать только часть текстуры + +Если в одном файле несколько элементов (спрайт-лист), используй `SetTexCoord`: + +```lua +-- SetTexCoord(left, right, top, bottom) — от 0.0 до 1.0 +-- Пример: иконка занимает правый нижний квадрант 256×256 атласа +tex:SetTexCoord(0.5, 1.0, 0.5, 1.0) + +-- Формула для ячейки в сетке (col/row с нуля): +local cols, rows = 4, 4 +local col, row = 2, 1 -- третья колонка, вторая строка +tex:SetTexCoord( + col/cols, -- left + (col+1)/cols, -- right + row/rows, -- top + (row+1)/rows -- bottom +) +``` + +> **Важно**: при SetTexCoord текстура тайлится внутри заданного Size фрейма. SetAllPoints растягивает — SetWidth/SetHeight + SetPoint = точный размер. + +--- + +### Позиционирование: от Figma к SetPoint + +В Figma позиция элемента — это X,Y от левого верхнего угла холста (или родителя). В WoW — якорная система. + +**Алгоритм переноса**: + +1. Определи ближайший угол/сторону в Figma (от чего считать) +2. Вычисли отступ от этой стороны +3. Пересчитай через `px()` + +```lua +-- Figma (холст 1365×768): +-- Элемент: X=50, Y=30, W=200, H=100 +-- → привязка от TOPLEFT UIParent + +frame:SetWidth(px(200)) +frame:SetHeight(px(100)) +frame:SetPoint("TOPLEFT", UIParent, "TOPLEFT", px(50), -px(30)) +-- ^^^ ^^^ +-- X offset Y offset (отрицательный! вниз) +``` + +> **Знаки осей WoW**: X растёт вправо (+), Y растёт вверх (+). Отступ вниз от TOPLEFT — **отрицательный**. + +| Figma anchor | WoW SetPoint | +|-------------|-------------| +| Top-Left | `"TOPLEFT", UIParent, "TOPLEFT", x, -y` | +| Top-Right | `"TOPRIGHT", UIParent, "TOPRIGHT", -x, -y` | +| Bottom-Left | `"BOTTOMLEFT", UIParent, "BOTTOMLEFT", x, y` | +| Bottom-Right | `"BOTTOMRIGHT", UIParent, "BOTTOMRIGHT", -x, y` | +| Center | `"CENTER", UIParent, "CENTER", x - W/2_canvas, y` | + +--- + +### Вспомогательный модуль: px-утилиты (вставь в начало Lua) + +```lua +-- PixelHelper — pixel-perfect вёрстка из Figma +local PH = {} + +PH.CANVAS_HEIGHT = 768 -- высота холста в Figma (измени если другая!) + +function PH.scale() + return 768 / PH.CANVAS_HEIGHT +end + +-- Пересчёт px из Figma → WoW единицы +function PH.px(v) + return math.floor(v * PH.scale() + 0.5) +end + +-- Цвет из HEX (#RRGGBB или #RRGGBBAA) +function PH.color(hex, alpha) + hex = hex:gsub("#","") + local r = tonumber(hex:sub(1,2),16)/255 + local g = tonumber(hex:sub(3,4),16)/255 + local b = tonumber(hex:sub(5,6),16)/255 + local a = alpha or (hex:len() == 8 and tonumber(hex:sub(7,8),16)/255) or 1 + return r, g, b, a +end + +-- Размер шрифта из Figma → WoW +function PH.font(pt) + return math.max(8, math.floor(pt * PH.scale() + 0.5)) +end + +-- Установка якоря с автопересчётом +function PH.point(frame, point, relativeTo, relPoint, x, y) + frame:SetPoint(point, relativeTo, relPoint, PH.px(x or 0), PH.px(y or 0)) +end + +-- Размер фрейма из Figma +function PH.size(frame, w, h) + frame:SetWidth(PH.px(w)) + frame:SetHeight(PH.px(h)) +end + +-- Экспорт глобально (или оставь локальным) +MyAddon_PH = PH +``` + +**Использование**: +```lua +local px = MyAddon_PH.px +local color = MyAddon_PH.color +local pxfont = MyAddon_PH.font + +MyAddon_PH.size(frame, 400, 250) +MyAddon_PH.point(frame, "TOPLEFT", UIParent, "TOPLEFT", 50, -30) +frame:SetBackdropColor(color("#1A1A2E", 0.95)) +fs:SetTextColor(color("#FFD100")) +fs:SetFont("Interface\\AddOns\\MyAddon\\fonts\\MyFont.ttf", pxfont(16), "OUTLINE") +``` + +--- + +### Чеклист pixel-perfect переноса + +- [ ] Холст Figma = 768px в высоту (или задан `PH.CANVAS_HEIGHT`) +- [ ] Все размеры и отступы пересчитаны через `px()` +- [ ] Цвета конвертированы через `color()` +- [ ] Текстуры нарезаны до 512×512, размеры кратны степени двойки +- [ ] Шрифты `.ttf` подключены из папки аддона (если кириллица или кастомный шрифт) +- [ ] Размеры шрифтов пересчитаны через `font()` +- [ ] Y-отступы от верхних якорей — **отрицательные** +- [ ] Проверено на scale UIParent ≠ 1.0 (изменить в настройках игры для теста) +- [ ] Текстуры без SetAllPoints — точный SetWidth/SetHeight + SetPoint + +--- + +``` +MyAddon/ +├── MyAddon.toc ← обязателен, имя файла = имя папки +├── MyAddon.xml ← верстка фреймов (опционально) +└── MyAddon.lua ← логика +``` + +### TOC-файл (3.3.5a) + +```toc +## Interface: 30300 +## Title: My Addon +## Notes: Описание аддона +## Author: Ilyas +## Version: 1.0 +## SavedVariables: MyAddonDB + +MyAddon.xml +MyAddon.lua +``` + +> Файлы загружаются **в порядке перечисления**. XML раньше Lua — фреймы существуют к моменту выполнения скриптов. + +--- + +## XML-верстка + +### Минимальный шаблон XML-файла + +```xml + + +