From 315afff2202f3d7cfd7299a29c0ca67a757b9e2e Mon Sep 17 00:00:00 2001 From: Valentin Popov Date: Sun, 1 Nov 2026 13:13:53 +0400 Subject: feat(fx): track phase and restart per effect instance --- docs/appendices/knowledge-boundaries.md | 3 +++ docs/reference/environment-effects.md | 25 +++++++++++++++++++------ docs/tomes/05-render.md | 16 +++++++++++++++- 3 files changed, 37 insertions(+), 7 deletions(-) (limited to 'docs') diff --git a/docs/appendices/knowledge-boundaries.md b/docs/appendices/knowledge-boundaries.md index 04dc822..baf5ed5 100644 --- a/docs/appendices/knowledge-boundaries.md +++ b/docs/appendices/knowledge-boundaries.md @@ -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`. diff --git a/docs/reference/environment-effects.md b/docs/reference/environment-effects.md index 677c159..0e709d9 100644 --- a/docs/reference/environment-effects.md +++ b/docs/reference/environment-effects.md @@ -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-командам; отдельный детерминированный поток каждой diff --git a/docs/tomes/05-render.md b/docs/tomes/05-render.md index 266cb47..7cbe7d7 100644 --- a/docs/tomes/05-render.md +++ b/docs/tomes/05-render.md @@ -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, указанный самой командой. Его -- cgit v1.2.3