2026-02-10 01:58:16 +04:00
|
|
|
|
# Инструменты в каталоге `tools`
|
|
|
|
|
|
|
|
|
|
|
|
## `archive_roundtrip_validator.py`
|
|
|
|
|
|
|
|
|
|
|
|
Скрипт предназначен для **валидации документации по форматам NRes и RsLi на реальных данных игры**.
|
|
|
|
|
|
|
|
|
|
|
|
Что делает утилита:
|
|
|
|
|
|
|
|
|
|
|
|
- находит архивы по сигнатуре заголовка (а не по расширению файла);
|
|
|
|
|
|
- распаковывает архивы в структуру `manifest.json + entries/*`;
|
|
|
|
|
|
- собирает архивы обратно из `manifest.json`;
|
|
|
|
|
|
- выполняет проверку `unpack -> repack -> byte-compare`;
|
|
|
|
|
|
- формирует отчёт о расхождениях со спецификацией.
|
|
|
|
|
|
|
|
|
|
|
|
Скрипт не изменяет оригинальные файлы игры. Рабочие файлы создаются только в указанном `--workdir` (или во временной папке).
|
|
|
|
|
|
|
|
|
|
|
|
## Поддерживаемые сигнатуры
|
|
|
|
|
|
|
|
|
|
|
|
- `NRes` (`4E 52 65 73`)
|
|
|
|
|
|
- `RsLi` в файловом формате библиотеки: `NL 00 01`
|
|
|
|
|
|
|
|
|
|
|
|
## Основные команды
|
|
|
|
|
|
|
|
|
|
|
|
Сканирование архива по сигнатурам:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
python3 tools/archive_roundtrip_validator.py scan --input tmp/gamedata
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Распаковка/упаковка одного NRes:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
python3 tools/archive_roundtrip_validator.py nres-unpack \
|
|
|
|
|
|
--archive tmp/gamedata/sounds.lib \
|
|
|
|
|
|
--output tmp/work/nres_sounds
|
|
|
|
|
|
|
|
|
|
|
|
python3 tools/archive_roundtrip_validator.py nres-pack \
|
|
|
|
|
|
--manifest tmp/work/nres_sounds/manifest.json \
|
|
|
|
|
|
--output tmp/work/sounds.repacked.lib
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Распаковка/упаковка одного RsLi:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
python3 tools/archive_roundtrip_validator.py rsli-unpack \
|
|
|
|
|
|
--archive tmp/gamedata/sprites.lib \
|
|
|
|
|
|
--output tmp/work/rsli_sprites
|
|
|
|
|
|
|
|
|
|
|
|
python3 tools/archive_roundtrip_validator.py rsli-pack \
|
|
|
|
|
|
--manifest tmp/work/rsli_sprites/manifest.json \
|
|
|
|
|
|
--output tmp/work/sprites.repacked.lib
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Полная валидация документации на всём наборе данных:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
python3 tools/archive_roundtrip_validator.py validate \
|
|
|
|
|
|
--input tmp/gamedata \
|
|
|
|
|
|
--workdir tmp/validation_work \
|
|
|
|
|
|
--report tmp/validation_report.json \
|
|
|
|
|
|
--fail-on-diff
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Формат распаковки
|
|
|
|
|
|
|
|
|
|
|
|
Для каждого архива создаются:
|
|
|
|
|
|
|
|
|
|
|
|
- `manifest.json` — все поля заголовка, записи, индексы, смещения, контрольные суммы;
|
|
|
|
|
|
- `entries/*.bin` — payload-файлы.
|
|
|
|
|
|
|
|
|
|
|
|
Имена файлов в `entries` включают индекс записи, поэтому коллизии одинаковых имён внутри архива обрабатываются корректно.
|
2026-02-09 22:39:12 +00:00
|
|
|
|
|
|
|
|
|
|
## `init_testdata.py`
|
|
|
|
|
|
|
|
|
|
|
|
Скрипт инициализирует тестовые данные по сигнатурам архивов из спецификации:
|
|
|
|
|
|
|
|
|
|
|
|
- `NRes` (`4E 52 65 73`);
|
|
|
|
|
|
- `RsLi` (`NL 00 01`).
|
|
|
|
|
|
|
|
|
|
|
|
Что делает утилита:
|
|
|
|
|
|
|
|
|
|
|
|
- рекурсивно сканирует все файлы в `--input`;
|
|
|
|
|
|
- копирует найденные `NRes` в `--output/nres/`;
|
|
|
|
|
|
- копирует найденные `RsLi` в `--output/rsli/`;
|
|
|
|
|
|
- сохраняет относительный путь исходного файла внутри целевого каталога;
|
|
|
|
|
|
- создаёт целевые каталоги автоматически, если их нет.
|
|
|
|
|
|
|
|
|
|
|
|
Базовый запуск:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
python3 tools/init_testdata.py --input tmp/gamedata --output testdata
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Если целевой файл уже существует, скрипт спрашивает подтверждение перезаписи (`yes/no/all/quit`).
|
|
|
|
|
|
|
|
|
|
|
|
Для перезаписи без вопросов используйте `--force`:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
python3 tools/init_testdata.py --input tmp/gamedata --output testdata --force
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Проверки надёжности:
|
|
|
|
|
|
|
|
|
|
|
|
- `--input` должен существовать и быть каталогом;
|
|
|
|
|
|
- если `--output` указывает на существующий файл, скрипт завершится с ошибкой;
|
|
|
|
|
|
- если `--output` расположен внутри `--input`, каталог вывода исключается из сканирования;
|
|
|
|
|
|
- если `stdin` неинтерактивный и требуется перезапись, нужно явно указать `--force`.
|
2026-02-10 23:27:43 +00:00
|
|
|
|
|
|
|
|
|
|
## `msh_doc_validator.py`
|
|
|
|
|
|
|
|
|
|
|
|
Скрипт валидирует ключевые инварианты из документации `/Users/valentineus/Developer/personal/fparkan/docs/specs/msh.md` на реальных данных.
|
|
|
|
|
|
|
|
|
|
|
|
Проверяемые группы:
|
|
|
|
|
|
|
|
|
|
|
|
- модели `*.msh` (вложенные `NRes` в архивах `NRes`);
|
|
|
|
|
|
- текстуры `Texm` (`type_id = 0x6D786554`);
|
|
|
|
|
|
- эффекты `FXID` (`type_id = 0x44495846`).
|
|
|
|
|
|
|
|
|
|
|
|
Что проверяет для моделей:
|
|
|
|
|
|
|
|
|
|
|
|
- обязательные ресурсы (`Res1/2/3/6/13`) и известные опциональные (`Res4/5/7/8/10/15/16/18/19`);
|
|
|
|
|
|
- `size/attr1/attr3` и шаги структур по таблицам;
|
|
|
|
|
|
- диапазоны индексов, батчей и ссылок между таблицами;
|
|
|
|
|
|
- разбор `Res10` как `len + bytes + NUL` для каждого узла;
|
|
|
|
|
|
- матрицу слотов в `Res1` (LOD/group) и границы по `Res2/Res7/Res13/Res19`.
|
|
|
|
|
|
|
|
|
|
|
|
Быстрый запуск:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
python3 tools/msh_doc_validator.py scan --input testdata/nres
|
|
|
|
|
|
python3 tools/msh_doc_validator.py validate --input testdata/nres --print-limit 20
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
С отчётом в JSON:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
python3 tools/msh_doc_validator.py validate \
|
|
|
|
|
|
--input testdata/nres \
|
|
|
|
|
|
--report tmp/msh_validation_report.json \
|
|
|
|
|
|
--fail-on-warnings
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## `msh_preview_renderer.py`
|
|
|
|
|
|
|
|
|
|
|
|
Примитивный программный рендерер моделей `*.msh` без внешних зависимостей.
|
|
|
|
|
|
|
|
|
|
|
|
- вход: архив `NRes` (например `animals.rlb`) или прямой payload модели;
|
|
|
|
|
|
- выход: изображение `PPM` (`P6`);
|
|
|
|
|
|
- использует `Res3` (позиции), `Res6` (индексы), `Res13` (батчи), `Res1/Res2` (выбор слотов по `lod/group`).
|
|
|
|
|
|
|
|
|
|
|
|
Показать доступные модели в архиве:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
python3 tools/msh_preview_renderer.py list-models --archive testdata/nres/animals.rlb
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Сгенерировать тестовый рендер:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
python3 tools/msh_preview_renderer.py render \
|
|
|
|
|
|
--archive testdata/nres/animals.rlb \
|
|
|
|
|
|
--model A_L_01.msh \
|
|
|
|
|
|
--output tmp/renders/A_L_01.ppm \
|
|
|
|
|
|
--width 800 \
|
|
|
|
|
|
--height 600 \
|
|
|
|
|
|
--lod 0 \
|
|
|
|
|
|
--group 0 \
|
|
|
|
|
|
--wireframe
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Ограничения:
|
|
|
|
|
|
|
|
|
|
|
|
- инструмент предназначен для smoke-теста геометрии, а не для пиксельно-точного рендера движка;
|
|
|
|
|
|
- текстуры/материалы/эффектные проходы не эмулируются.
|
|
|
|
|
|
|
|
|
|
|
|
## `msh_export_obj.py`
|
|
|
|
|
|
|
|
|
|
|
|
Экспортирует геометрию `*.msh` в `Wavefront OBJ`, чтобы открыть модель в Blender/MeshLab.
|
|
|
|
|
|
|
|
|
|
|
|
- вход: `NRes` архив (например `animals.rlb`) или прямой payload модели;
|
|
|
|
|
|
- выбор геометрии: через `Res1` slot matrix (`lod/group`) как в рендерере;
|
|
|
|
|
|
- опция `--all-batches` экспортирует все батчи, игнорируя slot matrix.
|
|
|
|
|
|
|
|
|
|
|
|
Показать модели в архиве:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
python3 tools/msh_export_obj.py list-models --archive testdata/nres/animals.rlb
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Экспорт в OBJ:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
python3 tools/msh_export_obj.py export \
|
|
|
|
|
|
--archive testdata/nres/animals.rlb \
|
|
|
|
|
|
--model A_L_01.msh \
|
|
|
|
|
|
--output tmp/renders/A_L_01.obj \
|
|
|
|
|
|
--lod 0 \
|
|
|
|
|
|
--group 0
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Файл `OBJ` можно открыть напрямую в Blender (`File -> Import -> Wavefront (.obj)`).
|