# Документация формата MSH Формат `.msh` используется игрой Parkan: Железная стратегия (1998) для хранения 3D-мешей. MSH файлы — это NRes архивы, содержащие несколько типизированных компонентов. ## Обзор Существует **два варианта** формата MSH: | Вариант | Применение | Ключевые компоненты | Хранение треугольников | |---------|------------|---------------------|------------------------| | **Модель** | Роботы, здания, объекты | 06, 0D, 07 | Индексированные треугольники | | **Ландшафт** | Террейн | 0B, 15 | Прямые треугольники | ### Автоопределение типа ``` Модель: Есть компонент 06 (индексы) И 0D (батчи) Ландшафт: Есть компонент 0B (материалы) И НЕТ компонента 06 ``` --- ## Сводка компонентов | Тип | Название | Размер элемента | Описание | |:---:|----------|:---------------:|----------| | 01 | Pieces | 38 (0x26) | Части меша / тайлы с LOD-ссылками | | 02 | Submeshes | 68 (0x44) | LOD части с баундинг-боксами | | 03 | Vertices | 12 (0x0C) | Позиции вершин (Vector3) | | 04 | неизвестно | 4 | (неизвестно) | | 05 | неизвестно | 4 | (неизвестно) | | 06 | Indices | 2 | Индексы вершин треугольников (только Модель) | | 07 | неизвестно | 16 | (только Модель) | | 08 | Animations | 4 | Кейфреймы анимации меша | | 0A | ExternalRefs | переменный | Внешние ссылки на меши (строки) | | 0B | неизвестно | 4 | неизвестно (только Ландшафт) | | 0D | неизвестно | 20 (0x14) | неизвестно (только Модель) | | 0E | неизвестно | 4 | неизвестно (только Ландшафт) | | 12 | MicrotextureMap | 4 | неизвестно | | 13 | ShortAnims | 2 | Короткие индексы анимаций | | 15 | неизвестно | 28 (0x1C) | неизвестно | --- ## Поток данных ### Модель (роботы, здания) ``` Компонент 01 (Pieces - части) │ └─► Lod[n] ──► Компонент 02 (индекс сабмеша) │ ├─► StartIndexIn07 ──► Компонент 07 (данные на треугольник) │ └─► StartOffsetIn0d:ByteLengthIn0D ──► Компонент 0D (батчи) │ ├─► IndexInto06:CountOf06 ──► Компонент 06 (индексы) │ │ │ └─► Компонент 03 (вершины) │ └─► IndexInto03 (базовое смещение вершины) ``` ### Ландшафт (террейн) ``` Компонент 01 (Тайлы, обычно 16×16 = 256) │ └─► Lod[n] ──► Компонент 02 (индекс сабмеша) │ └─► StartIndexIn07:CountIn07 ──► Компонент 15 (треугольники) │ └─► Vertex1/2/3Index ──► Компонент 03 (вершины) └─► StartIndexIn07:CountIn07 ──► Компонент 0B (материалы, параллельно 15) ``` **Важно:** В ландшафтных мешах поля `StartIndexIn07` и `CountIn07` в Компоненте 02 используются для индексации в Компонент 15 (треугольники), а не в Компонент 07. --- ## Структуры компонентов ### Компонент 01 - Pieces (0x26 = 38 байт) Определяет части меша (для моделей) или тайлы террейна (для ландшафтов). | Смещение | Размер | Тип | Поле | Описание | |:--------:|:------:|:---:|------|----------| | 0x00 | 1 | byte | Type1 | Флаги типа части | | 0x01 | 1 | byte | Type2 | Дополнительные флаги | | 0x02 | 2 | int16 | ParentIndex | Индекс родителя (-1 = корень) | | 0x04 | 2 | int16 | OffsetIntoFile13 | Смещение в короткие анимации | | 0x06 | 2 | int16 | IndexInFile08 | Индекс в анимации | | 0x08 | 30 | ushort[15] | Lod | Индексы сабмешей по LOD-уровням (0xFFFF = не используется) | **Ландшафт:** 256 тайлов в сетке 16×16. Каждый тайл имеет 2 LOD (индексы 0-255 и 256-511). --- ### Компонент 02 - Submeshes (Заголовок: 0x8C = 140 байт, Элемент: 0x44 = 68 байт) #### Заголовок (140 байт) | Смещение | Размер | Тип | Поле | Описание | |:--------:|:------:|:---:|------|----------| | 0x00 | 96 | Vector3[8] | BoundingBox | 8-точечный баундинг-бокс | | 0x60 | 12 | Vector3 | Center | Центральная точка | | 0x6C | 4 | float | CenterW | W-компонента | | 0x70 | 12 | Vector3 | Bottom | Нижняя точка | | 0x7C | 12 | Vector3 | Top | Верхняя точка | | 0x88 | 4 | float | XYRadius | Радиус в плоскости XY | #### Элемент (68 байт) | Смещение | Размер | Тип | Поле | Описание | |:--------:|:------:|:---:|------|----------| | 0x00 | 2 | ushort | StartIndexIn07 | **Модель:** Начальный индекс в Компоненте 07
**Ландшафт:** Начальный индекс треугольника в Компоненте 15 | | 0x02 | 2 | ushort | CountIn07 | **Модель:** Количество в Компоненте 07
**Ландшафт:** Количество треугольников | | 0x04 | 2 | ushort | StartOffsetIn0d | Начальное смещение в Компоненте 0D (только Модель) | | 0x06 | 2 | ushort | ByteLengthIn0D | Количество батчей в Компоненте 0D (только Модель) | | 0x08 | 12 | Vector3 | LocalMinimum | Минимум локального баундинг-бокса | | 0x14 | 12 | Vector3 | LocalMaximum | Максимум локального баундинг-бокса | | 0x20 | 12 | Vector3 | Center | Центр сабмеша | | 0x2C | 12 | Vector3 | Vector4 | Неизвестно | | 0x38 | 12 | Vector3 | Vector5 | Неизвестно | --- ### Компонент 03 - Vertices (0x0C = 12 байт) | Смещение | Размер | Тип | Поле | Описание | |:--------:|:------:|:---:|------|----------| | 0x00 | 4 | float | X | Координата X | | 0x04 | 4 | float | Y | Координата Y | | 0x08 | 4 | float | Z | Координата Z | --- ### Компонент 06 - Indices (2 байта) - Только Модель Массив `ushort` значений — индексы вершин треугольников. Используются группами по 3 для каждого треугольника. Ссылки через батчи Компонента 0D. --- ### Компонент 07 - Triangle Data (0x10 = 16 байт) - Только Модель Данные рендеринга на каждый треугольник. | Смещение | Размер | Тип | Поле | Описание | |:--------:|:------:|:---:|------|----------| | 0x00 | 2 | ushort | Flags | Флаги рендера | | 0x02 | 2 | ushort | Magic02 | Неизвестно | | 0x04 | 2 | ushort | Magic04 | Неизвестно | | 0x06 | 2 | ushort | Magic06 | Неизвестно | | 0x08 | 2 | int16 | OffsetX | Нормализованный X (÷32767 для -1..1) | | 0x0A | 2 | int16 | OffsetY | Нормализованный Y (÷32767 для -1..1) | | 0x0C | 2 | int16 | OffsetZ | Нормализованный Z (÷32767 для -1..1) | | 0x0E | 2 | ushort | Magic14 | Неизвестно | --- ### Компонент 0B - Material Data (4 байта) - Только Ландшафт Информация о материале/текстуре на каждый треугольник. Параллельный массив к Компоненту 15. | Смещение | Размер | Тип | Поле | Описание | |:--------:|:------:|:---:|------|----------| | 0x00 | 2 | ushort | HighWord | Индекс материала/текстуры | | 0x02 | 2 | ushort | LowWord | Индекс треугольника (последовательный) | --- ### Компонент 0D - Draw Batches (0x14 = 20 байт) - Только Модель Определяет батчи вызовов отрисовки. | Смещение | Размер | Тип | Поле | Описание | |:--------:|:------:|:---:|------|----------| | 0x00 | 2 | ushort | Flags | Флаги батча | | 0x02 | 2 | - | Padding | - | | 0x04 | 1 | byte | Magic04 | Неизвестно | | 0x05 | 1 | byte | Magic05 | Неизвестно | | 0x06 | 2 | ushort | Magic06 | Неизвестно | | 0x08 | 2 | ushort | CountOf06 | Количество индексов для отрисовки | | 0x0A | 4 | int32 | IndexInto06 | Начальный индекс в Компоненте 06 | | 0x0E | 2 | ushort | CountOf03 | Количество вершин | | 0x10 | 4 | int32 | IndexInto03 | Базовое смещение вершины в Компоненте 03 | --- ### Компонент 15 - Triangles (0x1C = 28 байт) Прямые определения треугольников. Используется и Моделью и Ландшафтом, но только Ландшафт использует их напрямую для рендеринга. | Смещение | Размер | Тип | Поле | Описание | |:--------:|:------:|:---:|------|----------| | 0x00 | 4 | uint32 | Flags | Флаги треугольника (0x20000 = коллизия) | | 0x04 | 4 | uint32 | MaterialData | Данные материала (см. ниже) | | 0x08 | 2 | ushort | Vertex1Index | Индекс первой вершины | | 0x0A | 2 | ushort | Vertex2Index | Индекс второй вершины | | 0x0C | 2 | ushort | Vertex3Index | Индекс третьей вершины | | 0x0E | 4 | uint32 | Magic0E | Неизвестно | | 0x12 | 4 | uint32 | Magic12 | Неизвестно | | 0x16 | 4 | uint32 | Magic16 | Неизвестно | | 0x1A | 2 | ushort | Magic1A | Неизвестно | #### MaterialData (0x04) - Структура материала ``` MaterialData = 0xFFFF_SSPP │ │└─ PP: Основной материал (byte 0) │ └─── SS: Вторичный материал для блендинга (byte 1) └────── Всегда 0xFFFF (байты 2-3) ``` | Значение SS | Описание | |:-----------:|----------| | 0xFF | Сплошной материал (без блендинга) | | 0x01-0xFE | Индекс вторичного материала для блендинга | Примеры: - `0xFFFFFF01` = Сплошной материал 1 - `0xFFFF0203` = Материал 3 с блендингом в материал 2 --- ### Компонент 0A - External References (переменный размер) Таблица строк для внешних ссылок на части меша. Формат: ``` [4 байта: длина] [байты строки] [null-терминатор] ...повтор... ``` Длина 0 означает пустую запись. Строки типа `"central"` имеют особое значение (flag |= 1). --- ## Пример: Ландшафт SC_1 ``` Land.msh (SC_1): ├── 01: 256 тайлов (сетка 16×16) ├── 02: 512 сабмешей (256 LOD0 + 256 LOD1) ├── 03: 10 530 вершин ├── 04: 10 530 данных на вершину ├── 05: 10 530 данных на вершину ├── 0B: 7 882 записи материалов ├── 0E: 10 530 данных на вершину ├── 12: 10 530 микротекстурный маппинг └── 15: 7 882 треугольника ├── LOD 0: 4 993 треугольника (тайлы 0-255 → сабмеши 0-255) └── LOD 1: 2 889 треугольников (тайлы 0-255 → сабмеши 256-511) ``` --- ## Использование ```csharp var converter = new MshConverter(); // Автоопределение типа и конвертация в OBJ converter.Convert("Land.msh", "terrain.obj", lodLevel: 0); converter.Convert("robot.msh", "robot.obj", lodLevel: 0); // Ручное определение типа var archive = NResParser.ReadFile("mesh.msh").Archive; var type = MshConverter.DetectMeshType(archive); // Возвращает: MshType.Model или MshType.Landscape ``` --- ## Формат WEA - Файлы материалов ландшафта Файлы `.wea` — текстовые файлы, определяющие таблицу материалов для ландшафта. ### Формат ``` {count} {index} {material_name} {index} {material_name} ... ``` ### Связь с Land.msh Каждая карта имеет два файла материалов: | Файл | Используется для | Треугольники в Comp15 | |------|------------------|----------------------| | `Land1.wea` | LOD0 (высокая детализация) | Первые N (сумма CountIn07 для LOD0) | | `Land2.wea` | LOD1 (низкая детализация) | Остальные | ### Пример (SC_1) **Land1.wea:** ``` 4 0 B_S0 1 L04 2 L02 3 L00 ``` **Land2.wea:** ``` 4 0 DEFAULT 1 L05 2 L03 3 L01 ``` ### Маппинг материалов Индекс материала в `Comp15.MaterialData & 0xFF` → строка в `.wea` файле. ``` Треугольник с MaterialData = 0xFFFF0102 └─ Основной материал = 02 → Land1.wea[2] = "L02" └─ Блендинг с материалом = 01 → Land1.wea[1] = "L04" ``` ### Типичные имена материалов | Префикс | Назначение | |---------|------------| | L00-L05 | Текстуры ландшафта (grass, dirt, etc.) | | B_S0 | Базовая текстура | | DEFAULT | Фолбэк для LOD1 | | WATER | Вода (поверхность) | | WATER_BOT | Вода (дно) | | WATER_M | Вода LOD1 | --- ## Источники - Реверс-инжиниринг `Terrain.dll` (класс CLandscape) - Декомпиляция Ghidra: `CLandscape::ctor` и `IMesh2_of_CLandscape::Render`