Files
parkan-playground/MshLib/docs/MSH_FORMAT.md
T
2026-05-17 15:40:16 +03:00

16 KiB
Raw Blame History

Документация формата MSH

Формат .msh используется игрой Parkan: Железная стратегия (1998) для хранения 3D-мешей. MSH файлы — это NRes архивы, содержащие несколько типизированных компонентов.

Обзор

Существует два варианта формата MSH:

Вариант Применение Ключевые компоненты Хранение треугольников
Модель Роботы, здания, объекты 06, 0D, 07 Индексированные треугольники
Ландшафт Террейн 0B, 15 Прямые треугольники

Автоопределение типа

Модель:    Есть компонент 06 (индексы) И 0D (батчи)
Ландшафт:  Есть компонент 0B (материалы) И НЕТ компонента 06

Сводка компонентов

Тип Название Размер элемента Описание
01 Node table 38 (0x26), редко 24 Узлы модели / тайлы; старое имя: Pieces
02 Header + slots 0x8C + n*68 Общий заголовок и slot records; старое имя: Submeshes
03 Positions 12 (0x0C) Позиции вершин (Vector3); старое имя: Vertices
04 PackedNormals 4 int8[4], normal = clamp(component / 127.0, -1..1)
05 PackedUV0 4 int16[2], uv = component / 1024.0
06 Index buffer 2 Индексы вершин треугольников
07 Tri descriptors 16 Описатели треугольников для коллизии/пикинга
08 AnimKeyPool 24 Кейфреймы анимации меша
0A Node strings переменный Строки узлов; старое имя: ExternalRefs
0B неизвестно 4 неизвестно (только Ландшафт)
0D Batch table 20 (0x14) Батчи рендера; FParkan Res13 decimal
0E неизвестно 4 неизвестно (только Ландшафт)
12 MicrotextureMap 4 неизвестно
13 AnimMap 2 Карта кадров анимации, на нее указывает AnimMapStart из 0x01
15 TerrainTriangle table 28 (0x1C) Terrain-гипотеза

Поток данных

Модель (роботы, здания)

Компонент 01 (Pieces - части)
    │
    └─► Lod[n] ──► Компонент 02 (индекс сабмеша)
                        │
                        ├─► TriStart:TriCount ──► Компонент 07 (данные на треугольник)
                        │
                        └─► BatchStart:BatchCount ──► Компонент 0D (батчи)
                                                                    │
                                                                    ├─► IndexStart:IndexCount ──► Компонент 06 (индексы)
                                                                    │                                   │
                                                                    │                                   └─► Компонент 03 (вершины)
                                                                    │
                                                                    └─► BaseVertex (базовое смещение вершины)

Ландшафт (террейн)

Компонент 01 (Тайлы, обычно 16×16 = 256)
    │
    └─► Lod[n] ──► Компонент 02 (индекс сабмеша)
                        │
                        └─► TriStart:TriCount ──► Компонент 15 (треугольники)
                                                              │
                                                              └─► Vertex1/2/3Index ──► Компонент 03 (вершины)
                                                         
                        └─► TriStart:TriCount ──► Компонент 0B (материалы, параллельно 15)

Важно: В ландшафтных мешах поля TriStart и TriCount в Компоненте 02 используются для индексации в Компонент 15 (треугольники), а не в Компонент 07.


Структуры компонентов

Компонент 0x01 - Node table (0x26 = 38 байт)

Определяет узлы модели или тайлы terrain. Старое локальное имя: Pieces / SubMesh.

Смещение Размер Тип Поле Описание
0x00 2 uint16 Header0 Заголовочное слово узла; старые имена: Type1 + Type2
0x02 2 uint16 ParentOrLink Индекс родителя/ссылка; старый локальный тип int16 показывал 0xFFFF как -1
0x04 2 uint16 AnimMapStart Начало блока в 0x13 или 0xFFFF; старое имя: OffsetIntoFile13
0x06 2 uint16 FallbackKey Индекс fallback-ключа в 0x08; старое имя: IndexInFile08
0x08 30 ushort[15] SlotIndex Индексы slot в 0x02 по формуле lod * 5 + group; старое имя: Lod

Ландшафт: 256 тайлов в сетке 16×16. Каждый тайл имеет 2 LOD (индексы 0-255 и 256-511).


Компонент 0x02 - Header + slots (Заголовок: 0x8C = 140 байт, slot: 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 TriStart Начальный индекс в Компоненте 07; в landscape-tooling может указывать в 15
0x02 2 ushort TriCount Количество записей в Компоненте 07; в landscape-tooling может быть count для 15
0x04 2 ushort BatchStart Начальное смещение в Компоненте 0D (только Модель)
0x06 2 ushort BatchCount Количество батчей в Компоненте 0D (только Модель)
0x08 12 Vector3 LocalMinimum Минимум локального баундинг-бокса
0x14 12 Vector3 LocalMaximum Максимум локального баундинг-бокса
0x20 12 Vector3 Center Центр сабмеша
0x2C 4 float SphereRadius Радиус bounding sphere; старый Vector4 был overlay-гипотезой
0x30 20 uint32[5] Opaque Непонятый tail, сохранять 1:1; старый Vector5 был overlay-гипотезой

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


Компонент 0x07 - Tri descriptors (0x10 = 16 байт)

Описатели треугольников для коллизии/пикинга.

Смещение Размер Тип Поле Описание
0x00 2 ushort TriFlags Флаги треугольника; старое имя: Flags
0x02 2 ushort Link0 Связь/opaque поле 0; старое имя: Magic02
0x04 2 ushort Link1 Связь/opaque поле 1; старое имя: Magic04
0x06 2 ushort Link2 Связь/opaque поле 2; старое имя: Magic06
0x08 2 int16 NormalX Упакованная X-компонента нормали; старое имя: OffsetX
0x0A 2 int16 NormalY Упакованная Y-компонента нормали; старое имя: OffsetY
0x0C 2 int16 NormalZ Упакованная Z-компонента нормали; старое имя: OffsetZ
0x0E 2 ushort SelectorPacked Три 2-битных селектора; 3 трактуется как 0xFFFF; старое имя: Magic14

Компонент 0B - Material Data (4 байта) - Только Ландшафт

Информация о материале/текстуре на каждый треугольник. Параллельный массив к Компоненту 15.

Смещение Размер Тип Поле Описание
0x00 2 ushort HighWord Индекс материала/текстуры
0x02 2 ushort LowWord Индекс треугольника (последовательный)

Компонент 0x0D - Batch table (0x14 = 20 байт)

Определяет батчи вызовов отрисовки. В терминах FParkan это Res13 decimal.

Смещение Размер Тип Поле Описание
0x00 2 ushort BatchFlags / Flags.low Флаги батча
0x02 2 ushort MaterialIndex / Flags.high Индекс material slot
0x04 2 ushort Opaque4 Opaque, старое имя TriangleCount не подтверждено
0x06 2 ushort Opaque6 Opaque
0x08 2 ushort IndexCount Количество индексов для отрисовки в 0x06
0x0A 4 uint32 IndexStart Начальный индекс в Компоненте 06
0x0E 2 ushort Opaque14 Opaque, старое имя CountOf03 не подтверждено
0x10 4 uint32 BaseVertex Базовое смещение вершины в Компоненте 03

Компонент 0x15 - TerrainTriangle table (0x1C = 28 байт)

Прямые определения terrain-треугольников. Это hex-компонент 0x15 проекта, не FParkan Res15 decimal.

Смещение Размер Тип Поле Описание
0x00 4 uint32 Flags Флаги треугольника (0x20000 = коллизия)
0x04 4 uint32 MaterialData Данные материала; старое имя: Magic04
0x08 2 ushort Vertex1Index Индекс первой вершины
0x0A 2 ushort Vertex2Index Индекс второй вершины
0x0C 2 ushort Vertex3Index Индекс третьей вершины
0x0E 4 uint32 Opaque0E Opaque; старое имя: Magic0E
0x12 4 uint32 Opaque12 Opaque; старое имя: Magic12
0x16 4 uint32 Opaque16 Opaque; старое имя: Magic16
0x1A 2 ushort Opaque1A Opaque; старое имя: 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)

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

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 (сумма TriCount для 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