# OpenWC Портирование клиента **World of Warcraft 3.3.5a (12340)** на **Godot 4.6**. Текущий фокус проекта: загрузка данных из клиента, разбор форматов WoW и отображение мира в Godot так, чтобы его можно было смотреть и дальше редактировать уже средствами движка. Сейчас проект уже умеет: - открывать MPQ-архивы клиента через editor plugin; - извлекать файлы из MPQ в `res://data/extracted`; - читать `BLP2` текстуры; - читать `ADT`-тайлы terrain; - рендерить terrain из `ADT` с текстурными слоями `MCLY/MCAL`; - учитывать `holes` в `MCNK`; - читать и рендерить воду из `MH2O`; - стримить мир чанками с LOD в runtime; - стримить мир в **editor preview** по мере движения камеры в 3D viewport; - читать `WDT` и собирать состав мира по данным карты, а не по сканированию папки; - читать `WMO` и автоматически расставлять его в мире через world-level registry с дедупом по `unique_id` (WMO на границе тайлов не дублируется); - подхватывать глобальный WMO из `WDT.MWMO/MODF` для WMO-only карт (инстансы); - читать `M2` (MD20 + SKIN00) и ставить его через `MultiMesh` из ADT doodad placements. Что пока не доведено до полноценного world renderer: - вода без простого базового материала: нет нормального water shader, depth fade, shoreline blending, анимации; - M2 renderer статический: material flags (cull/unshaded), blend modes 2+, billboards для листвы и UV-transform'ы не применяются; анимация/скиннинг не парсятся; - импорт обратно в форматы WoW; - полноценные инструменты редактирования мира в editor. ## Текущее состояние ### Реализовано - `MPQManager` - открытие клиентских архивов; - список архивов по приоритету; - listing/extract по фильтру. - `BLPLoader` - чтение `BLP2` из файла или из байтов; - поддержка основных сжатых форматов, достаточная для terrain textures. - `ADTLoader` - `MTEX`, `MMDX/MMID`, `MWMO/MWID`; - `MDDF`, `MODF` (с `unique_id`, `flags`, `doodad_set`, `name_set`); - `MCVT`, `MCNR`, `MCLY`, `MCAL`; - `holes`; - `MH2O`. - `WDTLoader` - `MVER`, `MPHD` (flags карты: global_wmo / big_alpha / sort_by_size_class); - `MAIN` — таблица присутствия 64×64 ADT-тайлов; - `MWMO` + `MODF` — глобальный WMO для инстансных/WMO-only карт. - `ADTBuilder` - сборка terrain в `Node3D`; - terrain material с 4 слоями; - legacy/big/compressed alpha; - chunk-level LOD; - первый проход рендера воды. - `StreamingWorld` - runtime streaming тайлов и чанков; - editor streaming вокруг камеры viewport; - состав мира берётся из `WDT` (fallback на папочный скан, если `.wdt` отсутствует); - отдельные `ADT`-узлы под `Terrain` в дереве сцены; - world-level WMO registry с refcount-дедупом по `unique_id`: WMO живёт пока на него ссылается хотя бы один загруженный тайл. - `WMOLoader` / `WMOBuilder` - root/group parsing; - `WMOBuilder` собирает mesh по группам; - интегрирован в `StreamingWorld` через world-level registry; - глобальный WMO из `WDT` ставится один раз при загрузке карты. - `M2Loader` / `M2Builder` - парсинг `MD20` + `SKIN00`: vertices/normals/UVs, materials (flags + blend_mode), texture combos, batches; - `M2Builder` собирает `ArrayMesh` + `StandardMaterial3D`; - в `StreamingWorld` расставляется через `MultiMesh` из `ADT.MDDF`. ### Частично реализовано - `M2` renderer - статическая геометрия рендерится корректно; - material flags пока не применяются (cull_mode, unshaded, depth_write); - blend modes 2+ (additive / modulate) схлопнуты в обычный alpha; - билборды (leaf bones) не распознаются — листва деревьев плоская; - UV-трансформы (waterfalls, флаги, порталы) не применяются. ### Не реализовано - скиннинг и анимации `M2` (bones, key frames); - particles / ribbons; - сохранение terrain/liquid/object placement обратно в WoW-форматы; - редакторские инструменты изменения ADT/WMO данных. ## Структура проекта - `sources/` - исходный клиент WoW 3.3.5a, без модификаций. - `data/extracted/` - извлечённые из MPQ файлы, с которыми работает Godot. - `data/cache/` - generated/offline cache: baked terrain, M2 GLB cache, WMO scene cache. Эти файлы не являются исходниками проекта и игнорируются git. - `addons/mpq_extractor/` - editor plugin и GDScript-сборщики сцен. - `src/native/` - C++ GDExtension: MPQ, BLP, ADT, WMO. - `src/scenes/` - готовые сцены для просмотра мира. - `src/tools/` - bake/conversion scripts. - `src/resources/` - Godot resources, generated GLB assets and runtime resource scripts. - `reference/` - external reference sources/tools: Blender WoW Studio, wow.export and Noggit RED. Runtime-project must not depend on this directory. - `reference/noggit-red/` - Noggit RED source reference for WoW 3.3.5 map editing, ADT/WMO/M2 placement behavior and UID workflows. - внешние reference sources и tools для сверки форматов. Runtime-проект не должен зависеть от этой директории. - `third_party/` - `godot-cpp`, `StormLib` и другие зависимости. ## Требования - Windows - Godot `4.6` - Visual Studio 2022 с C++ workload - CMake - клиент **WoW 3.3.5a (12340)** ## Сборка Собрать GDExtension: ```bat cd src\native build.bat Release ``` После успешной сборки DLL появится в: ```text addons/mpq_extractor/bin/ ``` VS Code/CMake использует `src/native` как `cmake.sourceDirectory`. ## Подготовка данных По умолчанию plugin смотрит на клиент в: ```text res://sources ``` И извлекает файлы в: ```text res://data/extracted ``` ### Через editor plugin 1. Открой проект в Godot. 2. Убедись, что plugin `MPQ Extractor` включён. 3. Внизу editor открой панель `MPQ Extractor`. 4. Укажи путь к клиенту WoW 3.3.5a. 5. Выбери locale. 6. Нажми `Open Client Archives`. 7. Для полной распаковки используй фильтр `*` и `Extract`. Для terrain/world обычно нужны как минимум: - `World/Maps/...` - `Textures/...` - `World/wmo/...` - `DBFilesClient/...` если позже понадобится работа с DBC ## Основные классы GDExtension ### `MPQManager` Доступен из GDScript. Основные методы: - `open_client(base_path, locale)` - `list_files(filter="*")` - `extract_files(filter, output_dir)` - `read_file(internal_path)` ### `BLPLoader` Читает WoW `BLP2` и возвращает `Image`. Основные методы: - `load_image(path)` - `load_image_from_bytes(bytes)` ### `ADTLoader` Читает `ADT` и возвращает `Dictionary` с terrain, texture layers, placements и liquid. Основные поля результата: - `textures` - `m2_names` - `wmo_names` - `m2_placements` - `wmo_placements` - `chunks` Каждый chunk содержит: - `index_x`, `index_y` - `origin` - `heights` - `normals` - `holes` - `layers` - `alpha_maps` - `liquids` ### `WMOLoader` Читает root/group файлы `WMO` и возвращает `Dictionary` с `materials` и `groups`. Подключён в `StreamingWorld` через world-level registry. Дедуп по `unique_id` из `ADT.MODF`, refcount по тайлам. ### `WDTLoader` Читает `WDT` карты и возвращает `Dictionary`: - `version` — `MVER` (ожидается 18); - `flags`, `has_global_wmo`, `big_alpha`, `sort_by_size_class` — из `MPHD`; - `tiles: Array[Dictionary]` — присутствующие тайлы `{x, y, flags}` из `MAIN`; - `global_wmo_name: String` + `global_wmo_placement: Dictionary` — если карта WMO-only. `StreamingWorld` по умолчанию строит мир из этого списка. Папочный скан остаётся fallback'ом. ### `M2Loader` Читает `.m2` (`MD20`) + `00.skin` и возвращает `Dictionary` с геометрией: - `textures`, `materials` (`flags`, `blend_mode`), `texture_combos`; - `vertices`, `normals`, `uvs`, `indices`; - `batches: Array[Dictionary]` — `{index_start, index_count, material_id, texture_combo_index}`. Кости, анимации и частицы пока не читаются. ## Export/bake scripts Все проектные скрипты экспорта и запекания лежат в `src/tools/`. Скрипты с расширением `.gd` запускаются через Godot headless и требуют собранный GDExtension, потому что используют `ADTLoader`, `M2Loader` и `WMOLoader`. Перед запуском данные клиента должны быть извлечены в `res://data/extracted`. Если `godot` не добавлен в `PATH`, используй путь из `.vscode/settings.json`, например: ```powershell & 'c:\Godot 4.6\Godot_v4.6.1-stable_win64.exe' --headless --path . --script res://src/tools/bake_all.gd -- --map Azeroth --force ``` ### `src/tools/bake_all.gd` Запекает terrain, M2 doodads и WMO objects за один проход. ```powershell godot --headless --path . --script res://src/tools/bake_all.gd -- --map Azeroth --force ``` Основные аргументы: - `--map Azeroth` - `--extracted res://data/extracted` - `--terrain-output res://data/cache/baked_terrain_v2` - `--m2-output res://data/cache/m2_glb` - `--wmo-output res://data/cache/wmo_tscn` - `--full-texture-size 2048` - `--coarse-texture-size 512` - `--skip-terrain`, `--skip-m2`, `--skip-wmo` - `--force` ### `src/tools/bake_adt_terrain_cache.gd` Запекает terrain tiles в `.res` ресурсы `BakedADTTile`. Runtime streaming читает их из `baked_tile_cache_dir`. ```powershell godot --headless --path . --script res://src/tools/bake_adt_terrain_cache.gd -- --map Azeroth --output res://data/cache/baked_terrain_v2 --force ``` Основные аргументы: - `--map Azeroth` - `--extracted res://data/extracted` - `--output res://data/cache/baked_terrain_v2` - `--tile-x 32`, `--tile-y 48` для одного тайла - `--full-texture-size 2048` - `--coarse-texture-size 512` - `--texture-size N` legacy alias для обоих размеров - `--force` ### `src/tools/bake_m2_cache.gd` Сканирует ADT tiles, собирает уникальные M2 paths и запекает M2 doodads в `PackedScene` `.tscn`. ```powershell godot --headless --path . --script res://src/tools/bake_m2_cache.gd -- --map Azeroth --output res://data/cache/m2_glb --force ``` Основные аргументы: - `--map Azeroth` - `--extracted res://data/extracted` - `--output res://data/cache/m2_glb` - `--force` ### `src/tools/bake_wmo_cache.gd` Сканирует ADT tiles, собирает уникальные WMO paths и запекает WMO world objects в `PackedScene` `.tscn`. ```powershell godot --headless --path . --script res://src/tools/bake_wmo_cache.gd -- --map Azeroth --output res://data/cache/wmo_tscn --force ``` Основные аргументы: - `--map Azeroth` - `--extracted res://data/extracted` - `--output res://data/cache/wmo_tscn` - `--force` ### `src/tools/collect_world_m2_list.gd` Сканирует ADT tiles и сохраняет список уникальных M2 paths. Полезно перед массовой конвертацией или для оценки объема M2 cache. ```powershell godot --headless --path . --script res://src/tools/collect_world_m2_list.gd -- --map Azeroth --output res://data/cache/m2_glb/Azeroth_m2_list.txt ``` Основные аргументы: - `--map Azeroth` - `--extracted res://data/extracted` - `--output res://data/cache/m2_glb/Azeroth_m2_list.txt` ### `src/tools/m2_to_gltf.py` Python converter для WoW 3.3.5 M2 v264 в GLTF 2.0 `.glb`. Также экспортирует texture layers рядом с GLB. Для DXT BLP decoding нужен `Pillow`. Один M2: ```powershell python src/tools/m2_to_gltf.py data/extracted/Character/BloodElf/Female/BloodElfFemale.M2 src/resources/characters/BloodElf/Female ``` Рекурсивная конвертация: ```powershell python src/tools/m2_to_gltf.py --all data/extracted/Character --out src/resources/characters ``` Аргументы: - `input` путь к одному `.M2` - `output_dir` директория вывода для одного `.M2` - `--all SEARCH_DIR` рекурсивно конвертирует все `.M2` под директорией - `--out OUT_ROOT` root вывода для `--all`; по умолчанию `src/resources` ### Reference-only export scripts В `reference/` лежат внешние скрипты и исходники для сверки форматов, включая Blender/WoW export tools из `reference/` и `reference/wow.export/`. Они не являются частью project pipeline, не вызываются runtime-кодом и не должны использоваться как источник project cache без явного переноса в `src/tools/`. Найденные reference scripts, связанные с export/conversion: - `reference/blender-wow-studio-3.4-1.1.0_Experimental/io_scene_wmo/m2/export_m2.py` - `reference/blender-wow-studio-3.4-1.1.0_Experimental/io_scene_wmo/m2/operations/convert_m2_bones.py` - `reference/blender-wow-studio-3.4-1.1.0_Experimental/io_scene_wmo/m2/operations/m2_export_validation.py` - `reference/blender-wow-studio-3.4-1.1.0_Experimental/io_scene_wmo/wmo/export_wmo.py` - `reference/wow.export/addons/blender/io_scene_wowobj/animation_processor.py` - `reference/wow.export/addons/blender/io_scene_wowobj/import_wowobj.py` - `reference/wow.export/addons/blender/io_scene_wowobj/__init__.py` `toolbar.py` files в reference UI directories относятся к Blender UI этих внешних tools и не являются самостоятельными export/bake entrypoints. `reference/noggit-red/` is not an export script collection. It is a source reference for WoW 3.3.5 map editing behavior: ADT/WMO/M2 placement, UID handling, map editing workflows and related editor code. ## GDScript-сборщики ### `ADTBuilder` Файл: `addons/mpq_extractor/loaders/adt_builder.gd` Умеет: - собрать весь `ADT` в `Node3D`; - собрать отдельный chunk с нужным LOD; - собрать water root для тайла; - создать layered terrain material; - загрузить BLP-текстуры через `BLPLoader`. ### `WMOBuilder` Файл: `addons/mpq_extractor/loaders/wmo_builder.gd` Умеет: - собрать `Node3D` из данных `WMOLoader`; - создать по одному `MeshInstance3D` на группу; - назначить базовые материалы. ## Сцены просмотра ### `src/scenes/streaming/test.tscn` Файл: `src/scenes/streaming/test.tscn` Тестовая сцена, которая грузит квадрат тайлов вокруг центра карты. Скрипт: `src/scenes/streaming/test_world_loader.gd` Подходит для: - быстрой проверки terrain; - отладки парсинга `ADT`; - проверки AABB и координат. ### `src/scenes/preview/adt_tile_preview.tscn` Файл: `src/scenes/preview/adt_tile_preview.tscn` Preview одного `ADT` прямо в editor. Скрипт: `src/scenes/preview/adt_tile_preview.gd` Полезно для: - проверки одного конкретного тайла; - отладки terrain layers; - проверки воды и дыр по отдельному `ADT`. Основные export-поля: - `map_name` - `tile_x` - `tile_y` - `reload_now` ### `src/scenes/streaming/eastern_kingdoms_streaming.tscn` Файл: `src/scenes/streaming/eastern_kingdoms_streaming.tscn` Главная сцена для стриминга мира. Скрипт: `src/scenes/streaming/streaming_world_loader.gd` Умеет: - находить все доступные `ADT` тайлы в `World/Maps/Azeroth`; - загружать/выгружать тайлы по мере перемещения; - строить chunk mesh по LOD; - отдельно добавлять воду на тайл; - работать и в runtime, и в editor. ## Editor streaming `StreamingWorld` теперь умеет подгружать мир прямо в editor по мере движения камеры viewport. Ключевые export-поля: - `editor_preview_enabled` - `editor_follow_view_camera` - `editor_preview_center_x` - `editor_preview_center_y` - `editor_preview_tile_radius` - `editor_reload_now` Логика такая: - `editor_preview_center_x/y` задают anchor, который сдвигается к `origin`, чтобы мир было удобно смотреть в Godot; - при `editor_follow_view_camera = true` стриминг идёт вокруг положения editor camera в 3D viewport; - тайлы и их children появляются под `Terrain` в Scene Tree. Это нужно, чтобы визуально проверить, что мир действительно собирается по мере перемещения по карте, а не только как статичный превью-блок. ## Runtime streaming и LOD В runtime `StreamingWorld`: - подгружает `ADT` тайлы по расстоянию; - для terrain использует chunk-level LOD; - хранит дальний мир на грубом chunk LOD; - отдельно создаёт воду на тайл. Основные параметры: - `tiles_per_tick` - `chunk_ops_per_tick` - `lod0_radius_chunks` - `lod1_radius_chunks` - `lod2_radius_chunks` - `lod2_tile_radius` ## Управление камерой Файл: `src/scenes/camera/fly_camera.gd` Управление: - `RMB` удерживать для обзора; - `WASD` движение; - `Q/E` вниз/вверх; - `Shift` ускорение. ## Что именно уже исправлено в terrain pipeline По сравнению с самым ранним состоянием проекта уже поправлены: - layout `MCNKHeader`; - offsets внутри `MCNK`; - чтение `MCVT`; - чтение `MCNR`; - legacy `MCAL`; - big alpha / compressed alpha; - корректные local coordinates внутри `ADT`-узла; - holes; - chunk winding/culling; - editor preview одного тайла; - streaming всего `Azeroth`; - первый проход `MH2O`. ## Ограничения текущей версии - terrain текстурирование уже рабочее, но ещё не 1:1 как в клиенте/Noggit во всех edge cases; - water renderer сейчас базовый, без настоящих WoW water materials; - `M2` рендерится статикой без билбордов, UV-анимаций и скелетной анимации; - старые `baked_terrain_v2` tile-кэши (до добавления `unique_id` в `MODF`) не дедупят WMO на границах тайлов до перезапечки через `bake_all.gd`; - проект сейчас ориентирован на просмотр и исследование данных, а не на полный round-trip import/export. ## Ближайшие логичные шаги 1. Довести M2 renderer: - **A.** Применять material flags: корректный `cull_mode`, `unshaded`, `depth_write`; blend modes 2+ (`additive`, `modulate`) вместо плоского alpha. - **B.** Билборды: парсить bones из `M2`, помечать billboard-флаги, для батчей ссылающихся на billboard-bone выдавать отдельные ноды с `BillboardMode = BILLBOARD_ENABLED`. Листва деревьев перестанет быть плоской. - **C.** UV-трансформы и vertex colors — custom shader, per-instance UV offset в `MultiMesh`. Waterfalls, порталы, флаги. 2. Скелетная анимация и скиннинг `M2` (bones, key frames, attachments) — отдельный крупный кусок. 3. Довести water shader (depth fade, shoreline blending, анимация). 4. Editor-side инструменты редактирования terrain/liquid/object placement. 5. Подготовить формат сохранения обратно в WoW-совместимые структуры. ## Быстрый старт 1. Положить клиент WoW 3.3.5a в `sources/` или указать путь через plugin. 2. Собрать расширение: ```bat cd src\native build.bat Release ``` 3. Извлечь данные в `res://data/extracted` через `MPQ Extractor`. 4. Открыть одну из сцен: - `src/scenes/preview/adt_tile_preview.tscn` - `src/scenes/streaming/test.tscn` - `src/scenes/streaming/eastern_kingdoms_streaming.tscn` Если нужен именно просмотр мира в editor по движению камеры, используй: - `src/scenes/streaming/eastern_kingdoms_streaming.tscn` - `editor_preview_enabled = true` - `editor_follow_view_camera = true`