diff options
| author | Valentin Popov <valentin@popov.link> | 2026-06-22 00:58:51 +0300 |
|---|---|---|
| committer | Valentin Popov <valentin@popov.link> | 2026-06-22 00:58:51 +0300 |
| commit | 78fc5f1debf1395d5df0bab7cc0dde54351205cb (patch) | |
| tree | ef8f7c72a183723fcbea0b2d1fefd7c28ca7bc18 /docs/specs/terrain-map-loading.md | |
| parent | 50c2cf4686b53ebd2b76318223096660e92305a4 (diff) | |
| download | fparkan-78fc5f1debf1395d5df0bab7cc0dde54351205cb.tar.xz fparkan-78fc5f1debf1395d5df0bab7cc0dde54351205cb.zip | |
docs: rewrite MkDocs documentation
Diffstat (limited to 'docs/specs/terrain-map-loading.md')
| -rw-r--r-- | docs/specs/terrain-map-loading.md | 291 |
1 files changed, 0 insertions, 291 deletions
diff --git a/docs/specs/terrain-map-loading.md b/docs/specs/terrain-map-loading.md deleted file mode 100644 index a511799..0000000 --- a/docs/specs/terrain-map-loading.md +++ /dev/null @@ -1,291 +0,0 @@ -# Terrain + ArealMap - -Документ описывает подсистему ландшафта и ареалов мира в движке Parkan: Iron Strategy: - -- `Land.msh` (terrain-геометрия и вспомогательные таблицы); -- `Land.map` (ареалы и навигационные связи); -- `BuildDat.lst` (категории объектных зон). - -Описание дано в высокоуровневом переносимом виде, без ссылок на внутренние адреса и имена из дизассемблера. - -Связанные страницы: - -- [NRes](nres.md) -- [RsLi](rsli.md) -- [MSH core](msh-core.md) -- [Render pipeline](render.md) - -## 1. End-to-End загрузка уровня - -Для каждой карты движок загружает пару файлов: - -- `.../Land.msh` -- `.../Land.map` - -Высокоуровневый порядок: - -1. Открыть `Land.msh` как `NRes`. -2. Прочитать обязательные terrain-chunk'и. -3. Построить runtime-структуры terrain (slots, faces, spatial grid). -4. Открыть `Land.map` как `NRes`. -5. Найти единственный chunk `type=12`. -6. Прочитать ареалы, их связи и cell-grid. -7. Применить инициализацию объектных категорий из `BuildDat.lst`. - -## 2. Формат `Land.msh` - -`Land.msh` — обычный `NRes` архив с фиксированным набором terrain-ресурсов. - -## 2.1. Состав chunk'ов - -Обязательные типы: - -- `1`, `2`, `3`, `4`, `5`, `11`, `18`, `21` - -Опциональные типы: - -- `14` - -Наблюдаемый retail-порядок chunk'ов: - -```text -[1, 2, 3, 4, 5, 18, 14, 11, 21] -``` - -## 2.2. Stride и атрибуты - -| Type | Назначение | Stride | -|---:|---|---:| -| 1 | node/slot матрица | 38 | -| 3 | позиции вершин | 12 | -| 4 | нормали (packed) | 4 | -| 5 | UV (packed) | 4 | -| 11 | cell-ускоритель | 4 | -| 14 | доп. поток | 4 | -| 18 | доп. поток | 4 | -| 21 | terrain face | 28 | - -Общее правило для этих chunk'ов: - -- `attr1 == size / stride` -- `attr3 == stride` - -## 2.3. Type `2`: slot table - -`type=2` содержит: - -- заголовок `0x8C` байт; -- затем таблицу slots по `68` байт. - -Инварианты: - -- `size >= 0x8C` -- `(size - 0x8C) % 68 == 0` -- `attr1 == (size - 0x8C) / 68` -- `attr3 == 68` - -## 2.4. Type `21`: terrain face (28 байт) - -Высокоуровневая структура face: - -- флаги face; -- индексы треугольника (`i0, i1, i2`); -- индексы соседей (`n0, n1, n2`, значение `0xFFFF` = нет соседа); -- служебные поля (материал/класс/edge-поля и др.). - -Критичные проверки: - -- `i0/i1/i2 < vertex_count` (`type=3`); -- `nX == 0xFFFF` или `nX < face_count`. - -## 2.5. Маски face и compact-представления - -В рантайме используются: - -- полная 32-битная маска (`full`); -- компактные представления (`compactMain16`, `compactMaterial6`). - -Подтвержденный remap `full -> compactMain16`: - -| Full bit | Compact bit | -|---:|---:| -| `0x00000001` | `0x0001` | -| `0x00000008` | `0x0002` | -| `0x00000010` | `0x0004` | -| `0x00000020` | `0x0008` | -| `0x00001000` | `0x0010` | -| `0x00004000` | `0x0020` | -| `0x00000002` | `0x0040` | -| `0x00000400` | `0x0080` | -| `0x00000800` | `0x0100` | -| `0x00020000` | `0x0200` | -| `0x00002000` | `0x0400` | -| `0x00000200` | `0x0800` | -| `0x00000004` | `0x1000` | -| `0x00000040` | `0x2000` | -| `0x00200000` | `0x8000` | - -Подтвержденный remap `full -> compactMaterial6`: - -| Full bit | Compact bit | -|---:|---:| -| `0x00000100` | `0x01` | -| `0x00008000` | `0x02` | -| `0x00010000` | `0x04` | -| `0x00040000` | `0x08` | -| `0x00080000` | `0x10` | -| `0x00000080` | `0x20` | - -Для 1:1 реализации нужно поддерживать оба представления и обратное восстановление `compact -> full`. - -## 2.6. Type `11` и cell-ускоритель terrain - -`type=11` служит источником cell-ускорителя для terrain-запросов. - -Практические требования для editor/toolchain: - -- не переупорядочивать содержимое без полного пересчета зависимых таблиц; -- сохранять служебные/неизвестные поля побайтно; -- выполнять валидацию диапазонов face/slot после любых правок. - -## 3. Формат `Land.map` (chunk `type=12`) - -`Land.map` — `NRes`, содержащий ровно один ресурс `type=12`. - -Контракт верхнего уровня: - -- `entry.attr1` = `areal_count`; -- payload включает: - - `areal_count` переменных записей ареалов; - - затем grid-секцию cell-попаданий. - -## 3.1. Запись ареала - -Старт записи: - -```c -float anchor_x; // +0 -float anchor_y; // +4 -float anchor_z; // +8 -float reserved_12; // +12 -float area_metric; // +16 -float normal_x; // +20 -float normal_y; // +24 -float normal_z; // +28 -uint32_t logic_flag; // +32 -uint32_t reserved_36; // +36 -uint32_t class_id; // +40 -uint32_t reserved_44; // +44 -uint32_t vertex_count; // +48 -uint32_t poly_count; // +52 -``` - -Далее: - -1. `float3 vertices[vertex_count]` -2. `EdgeLink8 links[vertex_count + 3 * poly_count]`, где - `EdgeLink8 = { int32 area_ref; int32 edge_ref; }` -3. для каждого полигона block: - - `uint32 n` - - `4 * (3*n + 1)` байт данных полигона - -## 3.2. Семантика edge-link - -Для `links[0 .. vertex_count-1]`: - -- `(-1, -1)` означает «соседа нет»; -- иначе `area_ref` указывает на индекс соседнего ареала, `edge_ref` — на ребро в соседнем ареале. - -## 3.3. Grid-секция после ареалов - -Формат: - -```c -uint32 cellsX; -uint32 cellsY; -for (x=0; x<cellsX; x++) { - for (y=0; y<cellsY; y++) { - uint16 hitCount; - uint16 areaIds[hitCount]; - } -} -``` - -В runtime существует упакованное cell-meta представление: - -- high 10 бит: `hitCount`; -- low 22 бита: `startIndex` (в общем `areaIds` пуле). - -## 3.4. Валидация целостности chunk 12 - -Обязательные проверки: - -- `areal_count > 0`; -- `cellsX > 0 && cellsY > 0`; -- каждый `area_id` из cell-списков `< areal_count`; -- все `area_ref/edge_ref` валидны относительно целевых ареалов; -- полный объем прочитанных байт должен точно совпасть с размером payload. - -## 4. `BuildDat.lst` - -Используются 12 объектных категорий ареалов: - -| Имя | Маска | -|---|---:| -| `Bunker_Small` | `0x80010000` | -| `Bunker_Medium` | `0x80020000` | -| `Bunker_Large` | `0x80040000` | -| `Generator` | `0x80000002` | -| `Mine` | `0x80000004` | -| `Storage` | `0x80000008` | -| `Plant` | `0x80000010` | -| `Hangar` | `0x80000040` | -| `MainTeleport` | `0x80000200` | -| `Institute` | `0x80000400` | -| `Tower_Medium` | `0x80100000` | -| `Tower_Large` | `0x80200000` | - -Файл должен парситься строго секционно; поврежденный формат считается ошибкой. - -## 5. Требования к reader/writer/editor - -1. Сохранять порядок и бинарную форму chunk'ов, если не выполняется осознанная нормализация. -2. Все неизвестные поля хранить и писать побайтно (`preserve-as-is`). -3. После правок пересчитывать только вычислимые поля, не «чистить» opaque-данные. -4. Проверять диапазоны индексов между связанными таблицами (`nodes/slots/faces/vertices/areas/cells`). -5. Для неизмененных ресурсов обеспечивать byte-identical roundtrip. - -## 6. Эмпирическая верификация (retail) - -Валидация на `testdata/Parkan - Iron Strategy`: - -- карт: `33` -- `Land.msh`: `33/33` валидны -- `Land.map`: `33/33` валидны -- `issues_total = 0`, `errors_total = 0`, `warnings_total = 0` - -Подтвержденные наблюдения: - -- `Land.msh` порядок chunk'ов стабилен: `[1,2,3,4,5,18,14,11,21]`; -- `Land.map` всегда содержит один chunk `type=12`; -- `cellsX == cellsY == 128` во всех retail-картах; -- `poly_count == 0` во всем проверенном retail-корпусе; -- `normal` имеет длину ~1.0; -- `reserved_12`, `reserved_36`, `reserved_44` в retail наблюдаются как `0`. - -Проверено legacy-валидатором terrain/map форматов. - -## 7. Статус покрытия и что осталось до 100% - -Закрыто: - -- бинарный контракт `Land.msh` и `Land.map`; -- диапазонные и структурные инварианты; -- remap масок `full/compact`; -- валидация на полном retail-корпусе карт. - -Осталось до полного 100% архитектурного покрытия движка: - -1. Полная доменная семантика `class_id` и `logic_flag` (игровые значения/поведенческие правила). -2. Полная спецификация ветки `poly_count > 0` на живых данных (в retail не встречена). -3. Полная field-level семантика части битов `TerrainFace28.flags` (бинарный контракт и remap закрыты, но не все биты имеют документированные геймплейные имена). |
