Files
fparkan/docs/specs/object-registry.md
Valentin Popov 4ef08d0bf6 feat: add terrain-core, tma, and unitdat crates with parsing functionality
- Introduced `terrain-core` crate for loading and processing terrain mesh data.
- Added `tma` crate for parsing mission files, including footer and object records.
- Created `unitdat` crate for reading unit data files with validation of structure.
- Implemented error handling and tests for all new crates.
- Documented object registry format and rendering pipeline in specifications.
2026-02-19 16:07:01 +04:00

146 lines
6.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Object Registry (`objects.rlb`)
`objects.rlb` - это не архив с готовыми мешами.
Это реестр игровых прототипов, который связывает логический идентификатор объекта (`r_h_01`, `s_tree_04`, `fr_m_brige`, ...) с набором реальных ресурсов в других архивах.
Документ описывает формат и runtime-контракт на высоком уровне, без привязки к внутренним именам/адресам из дизассемблера.
Связанные страницы:
- [Missions](missions.md)
- [NRes](nres.md)
- [MSH core](msh-core.md)
- [Wear (`WEAR`)](wear.md)
- [Material (`MAT0`)](material.md)
- [Render pipeline](render.md)
## 1. Роль в пайплайне
При загрузке миссии движок работает так:
1. Из `data.tma` получает `resource_name` объекта:
- либо прямой ключ (`s_tree_04`);
- либо путь к `*.dat` (например `UNITS\\UNITS\\HERO\\tut1_p.dat`).
2. Для `*.dat` читает заголовок и получает:
- `archive_name` (в retail-корпусе всегда `objects.rlb`);
- `model_key` (например `R_H_02`).
3. В `objects.rlb` по ключу (`model_key`/`resource_name`) ищет запись прототипа.
4. Из записи прототипа резолвит фактический `*.msh` и архив, где лежит геометрия.
5. Дальше запускается стандартная цепочка:
`MSH -> WEAR -> MAT0 -> Texm`.
## 2. Контейнер
`objects.rlb` сам является обычным `NRes`-архивом.
Практические наблюдения на retail-корпусе:
- формат заголовка/каталога полностью совпадает с `NRes`;
- payload каждой записи прототипа кратен `64` байтам;
- имя entry в каталоге - это логический ключ объекта (например `r_h_01`, `s_tree_04`).
## 3. Формат payload записи прототипа
Payload состоит из массива фиксированных записей:
```c
struct ObjectRef64 {
char archive_name[32]; // C-строка (CP1251/ASCII)
char resource_name[32]; // C-строка (CP1251/ASCII)
}
```
Интерпретация:
- `archive_name`: архив-источник (`bases.rlb`, `static.rlb`, `fortif.rlb`, `effects.rlb`, ...).
- `resource_name`: имя ресурса в этом архиве (`*.msh`, `*.wea`, `*.cpt`, `*.ctl`, `*.bas`, ...).
Важно:
- после первого `NUL` в 32-байтовом поле могут встречаться служебные байты; для runtime-резолва используется только C-строка до первого `NUL`;
- неизвестные хвостовые байты должны сохраняться 1:1 при writer/roundtrip-редактировании.
## 4. Runtime-резолв геометрии
Канонический порядок выбора меша:
1. Найти запись прототипа по ключу в `objects.rlb`.
2. Прочитать список `ObjectRef64`.
3. Если есть ссылка на `*.msh`:
- взять первую валидную ссылку;
- открыть указанный архив;
- загрузить этот `*.msh`.
4. Если `*.msh` нет, но есть `*.bas`:
- взять stem от `*.bas` (`fr_m_brige.bas` -> `fr_m_brige`);
- искать `<stem>.msh` в том же архиве (`fortif.rlb`).
5. Если нет ни `*.msh`, ни `*.bas`, объект трактуется как не-геометрический (пример: солнечный/системный объект) и в 3D-проход не попадает.
## 5. Типовые примеры
`r_h_01`:
- `bases.rlb :: r_h_01.msh`
- `bases.rlb :: r_h_01.wea`
- `bases.rlb :: r_h_01.cpt`
- ...
`s_tree_04`:
- `static.rlb :: s_tree_0_04.msh`
- `static.rlb :: s_tree_0_04.wea`
- ...
`fr_m_brige`:
- прямого `*.msh` в записи нет;
- есть `fortif.rlb :: fr_m_brige.bas`;
- меш резолвится как `fortif.rlb :: fr_m_brige.msh`.
`sun_01`:
- ссылки на `*.sun`/effect-ресурсы;
- 3D-меш отсутствует.
## 6. Инварианты для reader/writer
Reader:
- payload записи прототипа должен быть кратен `64`;
- каждая запись читается как две независимые C-строки фиксированной длины;
- поиск в архивах должен быть case-insensitive по ASCII.
Writer/editor:
- сохранять порядок `ObjectRef64` без перестановок;
- сохранять неизвестные служебные байты полей 1:1;
- не нормализовать имена, если это не требуется задачей.
## 7. Валидация
Проверено на retail-корпусе `testdata/Parkan - Iron Strategy`:
- все `590` записей `objects.rlb` имеют payload, кратный `64`;
- `554` записей имеют прямую ссылку на `*.msh`;
- `34` записи используют ветку через `*.bas`;
- `2` записи не содержат геометрии (системные/sun).
Интеграционные тесты в Rust подтверждают резолв:
- `r_h_01 -> bases.rlb :: r_h_01.msh`
- `s_tree_04 -> static.rlb :: s_tree_0_04.msh`
- `fr_m_brige -> fortif.rlb :: fr_m_brige.msh`
## 8. Статус покрытия и что осталось до 100%
Закрыто:
1. Формат payload записи прототипа (`ObjectRef64`) и правила чтения.
2. Runtime-алгоритм выбора меша (`*.msh` напрямую и fallback через `*.bas`).
3. Корпусная проверка структуры и интеграционные тесты резолва.
Осталось:
1. Полная field-level семантика служебных байтов после `NUL` в `resource_name[32]`.
2. Формальная семантика всех категорий ссылок (`*.ctl`, `*.cpt`, `*.ndp`, `*.sun`) в терминах систем движка (не только render-пути).
3. Writer-спецификация уровня "authoring new prototype from scratch" с гарантией runtime-паритета.