aboutsummaryrefslogtreecommitdiff
path: root/docs/specs/nres.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/specs/nres.md')
-rw-r--r--docs/specs/nres.md200
1 files changed, 0 insertions, 200 deletions
diff --git a/docs/specs/nres.md b/docs/specs/nres.md
deleted file mode 100644
index 150b38b..0000000
--- a/docs/specs/nres.md
+++ /dev/null
@@ -1,200 +0,0 @@
-# NRes
-
-`NRes` — базовый контейнер ресурсов движка Parkan: Iron Strategy.
-Страница фиксирует формат на диске и runtime-контракт чтения/поиска/сохранения в высокоуровневом виде, без привязки к внутренним адресам и именам из дизассемблера.
-
-Связанная страница:
-
-- [RsLi](rsli.md)
-
-## 1. Назначение
-
-`NRes` используется как универсальный архив:
-
-- 3D-модели (`*.msh`, `*.rlb`);
-- текстуры (`Texm`);
-- материалы (`MAT0`);
-- эффекты (`FXID`);
-- миссионные и служебные ресурсы.
-
-Формат поддерживает:
-
-- чтение;
-- поиск по имени;
-- редактирование (add/replace/remove);
-- полную пересборку архива.
-
-## 2. Общий layout файла
-
-```text
-[Header: 16]
-[Data region: variable, 8-byte aligned chunks]
-[Directory: entry_count * 64, всегда в конце файла]
-```
-
-Критично: каталог всегда расположен в конце файла.
-
-## 3. Заголовок (16 байт)
-
-Все значения little-endian.
-
-| Offset | Size | Type | Значение |
-|---:|---:|---|---|
-| 0 | 4 | char[4] | `NRes` |
-| 4 | 4 | u32 | `0x00000100` (версия 1.0) |
-| 8 | 4 | i32 | `entry_count` (должен быть `>= 0`) |
-| 12 | 4 | u32 | `total_size` (должен быть равен фактическому размеру файла) |
-
-Производные значения:
-
-- `directory_size = entry_count * 64`;
-- `directory_offset = total_size - directory_size`.
-
-Ограничения:
-
-- `directory_offset >= 16`;
-- `directory_offset + directory_size == total_size`.
-
-## 4. Запись каталога (64 байта)
-
-| Offset | Size | Type | Поле |
-|---:|---:|---|---|
-| 0 | 4 | u32 | `type_id` |
-| 4 | 4 | u32 | `attr1` |
-| 8 | 4 | u32 | `attr2` |
-| 12 | 4 | u32 | `size` (размер payload) |
-| 16 | 4 | u32 | `attr3` |
-| 20 | 36 | char[36] | `name_raw` (C-строка) |
-| 56 | 4 | u32 | `data_offset` |
-| 60 | 4 | u32 | `sort_index` |
-
-### 4.1. Имя ресурса (`name_raw`)
-
-Контракт:
-
-- максимум 35 полезных байт + NUL;
-- допускается ровно один терминатор внутри 36-байтового поля;
-- имя сравнивается регистронезависимо по ASCII-правилу (`A..Z` -> `a..z`).
-
-Для writer/editor:
-
-- запрещено писать NUL внутри полезной части имени;
-- запрещены имена длиной > 35 байт.
-
-### 4.2. Диапазон данных (`data_offset`, `size`)
-
-Для каждой записи:
-
-- `data_offset >= 16`;
-- `data_offset + size <= directory_offset`.
-
-Практически (канонический writer): каждый payload начинается с 8-байтного выравнивания.
-
-## 5. Таблица сортировки (`sort_index`)
-
-`sort_index` задает перестановку «отсортированный список -> исходный индекс записи».
-
-Пусть:
-
-- `entries[i]` — i-я запись каталога в исходном порядке;
-- `P` — массив индексов `0..entry_count-1`, отсортированный по `entries[idx].name` (ASCII case-insensitive).
-
-Тогда в канонической записи:
-
-- `entries[i].sort_index = P[i]`.
-
-Это именно таблица для бинарного поиска по имени, а не «ранг текущей записи».
-
-## 6. Поиск по имени
-
-Алгоритм поиска:
-
-1. Выполнить бинарный поиск по диапазону `i in [0, entry_count)`.
-2. На шаге `i` взять `target = entries[i].sort_index`.
-3. Сравнить искомое имя с `entries[target].name` (ASCII case-insensitive).
-4. При совпадении вернуть `target`.
-
-Fail-safe поведение:
-
-- если `sort_index` некорректен (выход за диапазон), реализация должна перейти на линейный fallback по всем записям;
-- fallback использует то же ASCII case-insensitive сравнение.
-
-## 7. Каноническая пересборка архива
-
-Канонический writer выполняет:
-
-1. Пишет заглушку заголовка (16 байт).
-2. Пишет payload всех записей в текущем порядке.
-3. После каждого payload добавляет 0-padding до кратности 8.
-4. Пересчитывает `sort_index` через сортировку имен.
-5. Дописывает каталог (`entry_count * 64`).
-6. Пересчитывает и записывает `total_size`.
-
-Итоговый файл должен удовлетворять всем ограничениям из разделов 3–5.
-
-## 8. Режим `raw` (совместимость инструментов)
-
-Для служебных инструментов допускается `raw_mode`:
-
-- любой бинарный файл трактуется как один «сырой» ресурс;
-- возвращается одна запись (`name = RAW`, `data_offset = 0`, `size = len(file)`).
-
-Этот режим не является форматом `NRes` на диске, это только режим открытия.
-
-## 9. Контрольные инварианты
-
-Минимальный набор проверок при чтении:
-
-1. `magic == "NRes"`.
-2. `version == 0x100`.
-3. `entry_count >= 0`.
-4. `header.total_size == file_size`.
-5. Каталог находится в конце файла.
-6. Для каждой записи диапазон данных не пересекает каталог.
-7. Имя корректно C-терминировано и не длиннее 35 байт.
-
-Минимальный набор проверок при записи:
-
-1. Все имена <= 35 байт и без внутренних NUL.
-2. `sort_index` формирует валидную перестановку `0..N-1`.
-3. Все паддинги между payload состоят из нулевых байт.
-4. `total_size` равен фактической длине выходного файла.
-
-## 10. Эмпирическая проверка на retail-корпусе
-
-Валидация на полном наборе `testdata/Parkan - Iron Strategy`:
-
-- найдено `120` архивов `NRes`;
-- roundtrip `unpack -> repack -> byte-compare`: `120/120` совпали побайтно;
-- критических расхождений формата не обнаружено.
-
-Проверено legacy-валидатором архивов.
-
-## 11. Статус покрытия и что осталось до 100%
-
-Закрыто:
-
-- формат заголовка/каталога;
-- правила поиска;
-- каноническая пересборка;
-- строгие инварианты валидатора;
-- побайтовый roundtrip на retail-корпусе.
-
-Осталось до полного 100% архитектурного покрытия движка:
-
-1. Формальная семантика `attr1/attr2/attr3` для всех типов ресурсов (частично вынесена в профильные страницы `msh`, `material`, `texture`, `fxid`, `terrain`).
-2. Полная спецификация поведения при не-ASCII именах (в реальных игровых архивах используется ASCII-практика; для Unicode-коллации движок не документирован).
-3. Полная спецификация платформенных гарантий атомарной записи (формат данных закрыт, но OS-уровневые гарантии замены файла зависят от платформы и файловой системы).
-## 12. Специализация `objects.rlb`
-
-Хотя `objects.rlb` формально является обычным `NRes`, его payload имеет отдельный семантический контракт:
-
-- запись каталога соответствует одному объектному прототипу;
-- payload записи - массив фиксированных ссылок `ObjectRef64` (`archive_name[32] + resource_name[32]`);
-- runtime-резолв меша выполняется через эти ссылки, а не через имя entry `*.msh` внутри `objects.rlb`.
-
-Это означает, что `objects.rlb` должен рассматриваться не как архив мешей, а как реестр привязок между mission/unit-ключами и фактическими ресурсами.
-
-См. детальную страницу:
-
-- [Object registry (`objects.rlb`)](object-registry.md)