feat(fx): track phase and restart per effect instance
Docs Deploy / Build and Deploy MkDocs (push) Successful in 38s
Docs Deploy / Build and Deploy MkDocs (push) Successful in 38s
This commit is contained in:
7 files changed
+379
-152
No files matched your search
@@ -91,6 +91,9 @@ Control Op1 пока использует цвет и радиус без слу
|
||||
Control Op2 воспроизводит modes 0/2; modes 1/3, body+76 и неподдержанные
|
||||
time modes/привязки считаются как `render_coverage control_op2_unsupported`.
|
||||
Управление фазой экземпляра командами Control остаётся до его подключения в runtime.
|
||||
Часы экземпляра поддерживают modes 0–3, смену режима и отложенный перезапуск;
|
||||
preview создаёт их в момент ноль. Динамический manager A8 заменён нулём
|
||||
(`control_fx_manager_flag_stub`); очередь update с шагом 50 ms ещё не подключена.
|
||||
При расширении выбранных начальных строк все пропущенные команды считаются
|
||||
в `control_fx_unsupported`, а time modes 4–17 — в `control_fx_requires_game_state`;
|
||||
причина и владелец выводятся в лог. Неразобранные FXID считаются отдельно в `control_fx_invalid_documents`.
|
||||
|
||||
@@ -416,10 +416,23 @@ RVA `0x93D0`, ветка mode 1 с `0x9739`, сборка столбцов `0x97
|
||||
XY, ненулевой выбирает статические quad/cap координаты. Op4 вычисляет локальное
|
||||
расстояние камеры тем же component-wise projection, что использует native path.
|
||||
|
||||
FX-команды используют общий preview clock и ограниченный набор time modes:
|
||||
mode 0 оставляет фазу равной нулю, mode 1 вычисляет `elapsed / duration` без
|
||||
зажатия, mode 2 повторяет цикл. Header flags `0x200` и `0x20` преобразуют эту
|
||||
фазу; command path `0x8120` зажимает результат только после преобразований.
|
||||
FX-команды одной Control-строки используют общие часы экземпляра
|
||||
`fparkan_fx::clock::FxInstanceClock`. Время хранится в миллисекундах `f32`,
|
||||
отдельно от длительности документа: mode 0 возвращает постоянную фазу
|
||||
(при создании ноль), mode 1 — `(now − origin) / duration`, mode 2 повторяет
|
||||
цикл, mode 3 возвращает `1 − (now − origin) / duration`.
|
||||
Header flags `0x200` и `0x20` преобразуют незажатую фазу; command path
|
||||
`0x8120` зажимает результат только после преобразований.
|
||||
Вызов `set_time` меняет начало отсчёта и режим экземпляра, сохраняя режим
|
||||
документа. Запрос перезапуска (`Effect.dll` RVA `0x7B40`, instance bit `0x20`)
|
||||
срабатывает после конца текущего времени жизни: следующий update начинает
|
||||
новый цикл в своём времени и возвращает режим документа. Это отдельный флаг,
|
||||
не header `0x20`, складывающий фазу треугольником. Правила режимов, gates
|
||||
`0x80/0x100` и установления времени сверены вызовом эталонной DLL с x87 CW
|
||||
`0x007F`; отложенный переход закреплён Rust-тестом по ветви update `0x8120`.
|
||||
Все экземпляры статического preview пока создаются в момент ноль; геометрия,
|
||||
свет и звук получают одну фазу на обновление сцены. Команды Control ещё не
|
||||
меняют эти часы, а нативная очередь обновления с шагом 50 ms не моделируется.
|
||||
В [эталонной Effect.dll](original-binaries.md) RVA `0x5C60` режимы 4–17
|
||||
читают состояние владельца или провайдера; режим 14 тоже входит в эту группу.
|
||||
Пропуски при расширении выбранных начальных Control-строк учитываются по
|
||||
@@ -433,8 +446,8 @@ Effect renderer проверяет header bit `0x800` только при
|
||||
render selector 0; native AniMesh component path был захвачен с selector 1,
|
||||
поэтому preview использует selector 1 и не подавляет такие visual commands.
|
||||
Этот capture также показал `0xD00` FX entries в 53-entry manager. Динамическое
|
||||
состояние manager `A8`, связанное с header gate и фактической FX phase, пока не
|
||||
моделируется. Header bit `0x10` относится к activation lifecycle и сам по себе
|
||||
состояние manager `A8` пока заменено нулём; экземпляры с gates `0x80/0x100`
|
||||
считаются в `control_fx_manager_flag_stub`. Header bit `0x10` относится к activation lifecycle и сам по себе
|
||||
не отключает draw.
|
||||
Header jitter и random shift хранятся один раз на Control row и совместно
|
||||
применяются к его sibling-командам; отдельный детерминированный поток каждой
|
||||
|
||||
+15
-1
@@ -740,6 +740,19 @@ struct FxHeader60 {
|
||||
локальную точку опоры, scale -- базовый масштаб экземпляра. Unknown flags и
|
||||
settings ID сохраняются.
|
||||
|
||||
У каждого экземпляра эффекта есть своё начало отсчёта. Например, эффект
|
||||
длительностью четыре секунды, созданный на 135-й секунде, на 137-й находится
|
||||
в середине цикла: `(137 − 135) / 4 = 0,5`. Режим может идти вперёд,
|
||||
повторяться, идти назад или сохранять постоянную фазу. Вызывающий код может
|
||||
сменить режим экземпляра, не меняя документ. Запрос перезапуска ждёт конца
|
||||
текущего цикла и начинает новый при следующем обновлении.
|
||||
|
||||
Эти правила реализованы в `fparkan-fx::clock`. Приложение передаёт одну фазу
|
||||
геометрии, свету и звуку одной Control-строки; повторная отправка кадра не
|
||||
пересчитывает её и не расходует случайные числа повторно. В статической сцене
|
||||
все экземпляры пока рождаются в момент ноль. Управляющие команды Control и
|
||||
очередь обновления с шагом 50 миллисекунд остаются задачами игрового цикла.
|
||||
|
||||
Каждая команда начинается с `uint32_t command_word`:
|
||||
|
||||
```text
|
||||
@@ -867,7 +880,8 @@ Effect renderer подавляет header bit `0x800` только при
|
||||
render selector 0. Native AniMesh component path захвачен с selector 1, а в
|
||||
его 53-entry manager присутствуют FX entries с header `0xD00`; preview
|
||||
использует selector 1 и пропускает такие visual commands. Изменения manager
|
||||
`A8`, которые задают runtime phase/header gate, пока не моделируются. Header
|
||||
`A8`, которые задают runtime phase/header gate, пока заменены нулём с явным
|
||||
счётчиком `control_fx_manager_flag_stub`. Header
|
||||
bit `0x10` относится к activation lifecycle и не выключает draw.
|
||||
|
||||
Для visual effect renderer использует MAT0, указанный самой командой. Его
|
||||
|
||||
Reference in new issue
Block a user