- Updated MSH documentation to reflect changes in material, wear, and texture specifications. - Introduced new `render.md` file detailing the render pipeline process. - Removed outdated sections from `runtime-pipeline.md` and redirected to `render.md`. - Added detailed specifications for `Texm` texture format and `WEAR` wear table. - Updated navigation in `mkdocs.yml` to align with new documentation structure.
7.3 KiB
7.3 KiB
FXID
FXID — бинарный формат эффекта в движке Parkan: Iron Strategy.
Эта страница задаёт контракт формата и исполнения на уровне, достаточном для 1:1 порта рендера/симуляции эффектов и для lossless-инструментов.
Связанный контейнер: NRes / RsLi.
1. Контейнер
- Тип ресурса в
NRes:0x44495846(FXID). - Значения
attr1/attr2/attr3в типовых игровых данных стабильны, но при редактуре их нужно сохранять как есть.
2. Бинарный формат
Все значения little-endian.
2.1. Заголовок (60 байт)
struct FxHeader60 {
uint32_t cmd_count; // 0x00
uint32_t time_mode; // 0x04
float duration_sec; // 0x08
float phase_jitter; // 0x0C
uint32_t flags; // 0x10
uint32_t settings_id; // 0x14
float rand_shift_x; // 0x18
float rand_shift_y; // 0x1C
float rand_shift_z; // 0x20
float pivot_x; // 0x24
float pivot_y; // 0x28
float pivot_z; // 0x2C
float scale_x; // 0x30
float scale_y; // 0x34
float scale_z; // 0x38
};
Поток команд начинается строго с offset = 0x3C.
2.2. Команда
Каждая команда:
uint32 cmd_word- body фиксированного размера, зависящего от
opcode
Поля cmd_word:
opcode = cmd_word & 0xFFenabled = (cmd_word >> 8) & 1bits 9..31нужно сохранять 1:1
Выравнивания между командами нет.
2.3. Размеры команд
| Opcode | Размер |
|---|---|
| 1 | 224 |
| 2 | 148 |
| 3 | 200 |
| 4 | 204 |
| 5 | 112 |
| 6 | 4 |
| 7 | 208 |
| 8 | 248 |
| 9 | 208 |
| 10 | 208 |
3. Смысл заголовка
cmd_count: число команд в потоке.time_mode: способ вычисления текущего коэффициента эффекта.duration_sec: длительность (в рантайме переводится в миллисекунды).phase_jitter: амплитуда случайного фазового сдвига.flags: флаги поведения (видимость, альфа-модификаторы, режимы гейтинга).settings_id: индекс профиля/настроек эффекта.rand_shift_*: случайный пространственный сдвиг.pivot_*: локальная опора.scale_*: базовый масштаб инстанса эффекта.
4. Флаги заголовка
Практически важные биты:
0x0001: случайный сдвиг фазы0x0008: случайный пространственный сдвиг (rand_shift_*)0x0010: ветки видимости/окклюзии0x0020: треугольный ремап альфы0x0040: инверсия исходного active-state0x0080,0x0100: фильтрация по времени суток0x0200: умножение альфы на нормализованное время жизни0x0400,0x1000: дополнительные биты состояния менеджера эффекта0x0800: дополнительный гейтинг
Неизвестные биты должны сохраняться без изменений.
5. time_mode (0..17)
База:
tn = (now - start) / (end - start)prev = предыдущая вычисленная альфа
Поддерживаемые семейства режимов:
- константный режим;
- линейный (
tn), обратный (1-tn), циклический (fract(tn)); - режимы от внешних параметров мира/очереди;
- режимы на основе норм векторов состояния;
- режимы с ограничением вниз/вверх относительно
prev.
После вычисления:
- при
flags & 0x0200применяетсяalpha *= tn; - при
flags & 0x0020применяется triangular remap.
6. Resource-ссылки внутри команд
Для opcode 2/3/4/5/7/8/9/10 используется ссылка:
struct ResourceRef64 {
char archive[32];
char name[32];
};
Контракт:
- строки ASCII, нуль-терминированные;
- сравнение имён регистронезависимое;
- обычно:
opcode 2:sounds.lib+*.wav- остальные:
material.lib+ имя материала/эффекта.
7. Runtime-контракт исполнения
На создании инстанса:
- Заголовок копируется в runtime-состояние.
- Вычисляется
end_time. - Для каждой команды создаётся runtime-объект по
opcode. - В объект копируется
enabled. - Объект инициализируется контекстом эффекта.
На каждом кадре:
- Вычисляется текущий коэффициент/альфа по
time_modeиflags. - Выполняется update каждой команды.
- Выполняется emit/render часть активных команд.
- Применяются события Start/Stop/Restart.
8. Строгий парсер (рекомендуемый)
- Проверить
len(payload) >= 60. - Прочитать
cmd_count. - Идти от
ptr = 0x3C. - Для каждой команды:
- проверить
ptr + 4 <= len; - прочитать
opcode; - проверить, что
opcodeподдержан; - проверить
ptr + size(opcode) <= len; - сдвинуть
ptr += size(opcode).
- проверить
- Проверить
ptr == len(payload).
9. Writer и редактор
Для lossless-совместимости:
- сохранять все неизвестные поля/биты;
- не менять фиксированные размеры команд;
- не добавлять padding;
- пересчитывать только
cmd_countи размеры контейнера; - сохранять порядок команд.
10. Что требуется для 1:1 переноса
- Полная поддержка opcode
1..10. - Точный контракт вычисления
time_modeиflags. - Точное поведение
ResourceRef64. - Повторяемый RNG и одинаковая политика плавающей точки.
11. Статус валидации
- Формальные инварианты FXID зафиксированы в
tools/msh_doc_validator.pyиtools/fxid_abs100_audit.py. - В текущем рабочем окружении нет полного набора игровых архивов (
testdataбез payload), поэтому массовая повторная проверка корпуса здесь не выполнялась.