- Обновлены спецификации `runtime-pipeline`, `sound`, `terrain-map-loading`, `texture`, `ui` и `wear`. - Добавлены разделы о статусе покрытия и оставшихся задачах для достижения 100% завершенности. - Внесены уточнения по архитектурным ролям, минимальным контрактам и требованиям к toolchain для каждой подсистемы. - Уточнены форматы данных и правила взаимодействия между компонентами системы.
10 KiB
Terrain + ArealMap
Документ описывает подсистему ландшафта и ареалов мира в движке Parkan: Iron Strategy:
Land.msh(terrain-геометрия и вспомогательные таблицы);Land.map(ареалы и навигационные связи);BuildDat.lst(категории объектных зон).
Описание дано в высокоуровневом переносимом виде, без ссылок на внутренние адреса и имена из дизассемблера.
Связанные страницы:
1. End-to-End загрузка уровня
Для каждой карты движок загружает пару файлов:
.../Land.msh.../Land.map
Высокоуровневый порядок:
- Открыть
Land.mshкакNRes. - Прочитать обязательные terrain-chunk'и.
- Построить runtime-структуры terrain (slots, faces, spatial grid).
- Открыть
Land.mapкакNRes. - Найти единственный chunk
type=12. - Прочитать ареалы, их связи и cell-grid.
- Применить инициализацию объектных категорий из
BuildDat.lst.
2. Формат Land.msh
Land.msh — обычный NRes архив с фиксированным набором terrain-ресурсов.
2.1. Состав chunk'ов
Обязательные типы:
1,2,3,4,5,11,18,21
Опциональные типы:
14
Наблюдаемый retail-порядок chunk'ов:
[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 / strideattr3 == stride
2.3. Type 2: slot table
type=2 содержит:
- заголовок
0x8Cбайт; - затем таблицу slots по
68байт.
Инварианты:
size >= 0x8C(size - 0x8C) % 68 == 0attr1 == (size - 0x8C) / 68attr3 == 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. Запись ареала
Старт записи:
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
Далее:
float3 vertices[vertex_count]EdgeLink8 links[vertex_count + 3 * poly_count], гдеEdgeLink8 = { int32 area_ref; int32 edge_ref; }- для каждого полигона block:
uint32 n4 * (3*n + 1)байт данных полигона
3.2. Семантика edge-link
Для links[0 .. vertex_count-1]:
(-1, -1)означает «соседа нет»;- иначе
area_refуказывает на индекс соседнего ареала,edge_ref— на ребро в соседнем ареале.
3.3. Grid-секция после ареалов
Формат:
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
- Сохранять порядок и бинарную форму chunk'ов, если не выполняется осознанная нормализация.
- Все неизвестные поля хранить и писать побайтно (
preserve-as-is). - После правок пересчитывать только вычислимые поля, не «чистить» opaque-данные.
- Проверять диапазоны индексов между связанными таблицами (
nodes/slots/faces/vertices/areas/cells). - Для неизмененных ресурсов обеспечивать 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всегда содержит один chunktype=12;cellsX == cellsY == 128во всех retail-картах;poly_count == 0во всем проверенном retail-корпусе;normalимеет длину ~1.0;reserved_12,reserved_36,reserved_44в retail наблюдаются как0.
Инструмент:
tools/terrain_map_doc_validator.py
7. Статус покрытия и что осталось до 100%
Закрыто:
- бинарный контракт
Land.mshиLand.map; - диапазонные и структурные инварианты;
- remap масок
full/compact; - валидация на полном retail-корпусе карт.
Осталось до полного 100% архитектурного покрытия движка:
- Полная доменная семантика
class_idиlogic_flag(игровые значения/поведенческие правила). - Полная спецификация ветки
poly_count > 0на живых данных (в retail не встречена). - Полная field-level семантика части битов
TerrainFace28.flags(бинарный контракт и remap закрыты, но не все биты имеют документированные геймплейные имена).