- Обновлены спецификации `runtime-pipeline`, `sound`, `terrain-map-loading`, `texture`, `ui` и `wear`. - Добавлены разделы о статусе покрытия и оставшихся задачах для достижения 100% завершенности. - Внесены уточнения по архитектурным ролям, минимальным контрактам и требованиям к toolchain для каждой подсистемы. - Уточнены форматы данных и правила взаимодействия между компонентами системы.
8.0 KiB
8.0 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. - На полном retail-корпусе
testdata/Parkan - Iron Strategyпроверено923/923FXID payload без ошибок.
12. Статус покрытия и что осталось до 100%
Закрыто:
- Контейнер FXID, fixed-size командный поток, opcode-покрытие
1..10. - Базовый runtime-контур исполнения эффекта.
- Корпусная валидация формата на retail-данных.
Осталось:
- Полная field-level семантика payload каждого opcode для авторинга новых эффектов «с нуля».
- Формальная спецификация всех
time_modeветок на уровне точных числовых формул и edge-case поведения. - Полный набор пиксельных parity-тестов FX (оригинал vs новый рендер) на фиксированных сценах.