1
mirror of https://github.com/sampletext32/ParkanPlayground.git synced 2025-12-11 04:51:21 +04:00
Files
parkan-playground/ParkanPlayground/MSH_FORMAT.md
bird_egop fcfb8d0e8a feat: Add landscape mesh support to MshConverter
- Auto-detect Model vs Landscape mesh types
- Model: uses indexed triangles (06, 0D, 07)
- Landscape: uses direct triangles (0B, 15)
- Add MSH_FORMAT.md documentation (Russian)
- Add Ghidra decompiled code for CLandscape
2025-12-05 18:04:50 +03:00

13 KiB
Raw Blame History

Документация формата 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) Сабмеши с баундинг-боксами
03 Vertices 12 (0x0C) Позиции вершин (Vector3)
04 VertexData1 4 Данные на вершину (неизвестно)
05 VertexData2 4 Данные на вершину (неизвестно)
06 Indices 2 Индексы вершин треугольников (только Модель)
07 TriangleData 16 Данные рендера на треугольник (только Модель)
08 Animations 4 Кейфреймы анимации меша
0A ExternalRefs переменный Внешние ссылки на меши (строки)
0B MaterialData 4 Материалы на треугольник (только Ландшафт)
0D DrawBatches 20 (0x14) Батчи отрисовки (только Модель)
0E VertexData3 4 Данные на вершину (только Ландшафт)
12 MicrotextureMap 4 Микротекстурный маппинг на вершину
13 ShortAnims 2 Короткие индексы анимаций
15 Triangles 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 Magic04 Неизвестно (часто 0xFFFFFF01)
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 Неизвестно

Компонент 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)

Использование

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

Источники

  • Реверс-инжиниринг Terrain.dll (класс CLandscape)
  • Декомпиляция Ghidra: CLandscape::ctor и IMesh2_of_CLandscape::Render