aboutsummaryrefslogtreecommitdiff
path: root/docs/appendices/script-vm.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/appendices/script-vm.md')
-rw-r--r--docs/appendices/script-vm.md49
1 files changed, 45 insertions, 4 deletions
diff --git a/docs/appendices/script-vm.md b/docs/appendices/script-vm.md
index 6f52556..bd363e5 100644
--- a/docs/appendices/script-vm.md
+++ b/docs/appendices/script-vm.md
@@ -692,9 +692,11 @@ provider остаётся с заданным тестом значением `0
стадийное наследование доли родителя тоже не переписывает `+0x124` модели.
Поэтому Rust хранит `mesh_state.type1_value_bits` отдельно от
`current_type1_value_bits` provider, а `mesh_state.visible_stage` — отдельно от
-будущего Control stage/sentinel. Неизвестный узел даёт ошибку без частичной
+текущего Control stage/sentinel. Неизвестный узел даёт ошибку без частичной
записи; callback отражён в CPU-проекции, но GPU/window path ещё не подключён.
-Полный пересчёт стадии `0x11130`/`0x11220`, видимости и FX также не вызывается.
+Delta API не вызывает стадийный проход. Отдельный single-node API для
+`0x11220` описан в разделе о стадиях; обход `0x11130`, видимость и FX остаются
+вне этого исполнения.
Истощение корня или критического узла возвращает `UnsupportedNodeLifecycle`
до записи: состояние владельца `+0x550`, отложенная гибель и сопутствующие
callbacks ещё не реализованы. Отсутствие MSH flags, provider aggregate,
@@ -928,6 +930,42 @@ provider-состояния в реальной миссии. Ограничен
`AniMesh.dll!FUN_10005810` передаётся только видимое значение
`min(stage, count - 1)`.
+Rust API `update_loaded_mission_control_node_stage(engine, handle, key,
+update_effects)` переносит отдельный вызов `0x11220` в пределах подтверждённой
+арифметики и CPU-модели. Он читает текущие flags, count и parent, копирует долю
+родителя по `4` и его Control stage по `8`, записывает изменённую видимую стадию
+по правилу исходного `AniMesh+0x5810`, ставит flag `0x200` при переходе и
+сохраняет текущее количество в `processed_amount_bits`. Начальные снимки не
+меняются. Возвращаемый bool означает только смену Control stage: при неизменной
+стадии обработанное количество всё равно обновляется. Модельный `+0x124` при
+наследовании доли не переписывается.
+
+Flags `0x1c0` вместе с `0x10` и `0xc0` дают нативный ранний выход до чтения
+mesh metadata и обновления `+0x0c`. Когда эти же flags требуют lifecycle
+callback, API возвращает `UnsupportedNodeLifecycle`. Переход при
+`update_effects = true` требует не только создания FX, но и host notifications
+через `0x11af0`; пока он возвращает `UnsupportedNodeEffects`. Если стадия не
+меняется, нативный код пропускает эту ветвь и такой вызов поддержан.
+Переход через sentinel при снятом flag `2` требует `0x11920` и возвращает
+`UnsupportedNodeVisibility`. Неверные parent/count, неизвестное состояние
+модели и неподдержанные доли также отклоняются. Все эти ошибки сохраняют
+прежнее состояние, включая ещё не скопированную долю родителя.
+
+Здесь поддержаны конечные нормальные доли `0..1` и ноль. У инструкции `FILD`
+целый count остаётся точным до `FMUL`; предварительный cast count в `f32`
+может изменить ответ. Native вектор `count = 16777217`, `ratio = 0.75` получает
+Control/visible stage `4194304`; ранний cast давал бы `4194305`. Rust умножает
+целый count на 24-битную мантиссу доли в `u64`, округляет произведение один раз
+и точно масштабирует его степенью двойки. Это проверка арифметики с
+искусственным большим count, а не число стадий в игровых ресурсах.
+
+Native oracle и Rust-тест также проверяют двухстадийный случай `ratio = 0.5`
+со стадией `1`, обновление только обработанного количества при неизменной
+стадии и отсутствие такого обновления при защищённом раннем выходе. Licensed
+тест повторяет отдельный переход `0 → 1` на двухстадийном узле настоящего
+`min_l_n1.dat`, с `update_effects = false`. Полный игровой вызов не подменяется
+этим режимом: FX, lifecycle, видимость и обход потомков ещё требуют реализации.
+
После перехода родительского ряда `FUN_10011130` находит более поздние строки
с его индексом в поле parent. Обход идёт в глубину: сначала ребёнок и всё его
поддерево, затем следующий ребёнок. Рост стадии или истощение родителя снимает
@@ -1061,7 +1099,8 @@ SHA-256 `65659bf67f20e5be77d67a5b2f59968f61b94293143807fa59ca451c560c4f7e`,
RVA `0x68a0`) читает три DLL scale globals, которые после LoadLibrary в oracle
равны `1.0`. В Rust `initial_amount_bits` сохраняет это общее начальное
количество отдельно от текущего и последнего обработанного. Прямой delta API
-меняет только текущее количество; стадийный update пока не перенесён.
+меняет только текущее количество; отдельный стадийный API обновляет
+обработанное и текущую стадию в подтверждённой области.
Licensed full-load regression `full_load_builds_effective_control_device_table_for_mine_unit_dat`
проверяет значения настоящего `min_l_n1.dat`: корневой provider row `0` даёт
@@ -1070,7 +1109,9 @@ Licensed full-load regression `full_load_builds_effective_control_device_table_f
строки tag-26 устройства вдвое. Rust `0xe00` и `0x1002` дают `0.5`, и обычный
шаг runtime сохраняет эту долю. Это вызов прямого API, а не полный живой
Control tick. Проекция поля модели `+0x124` также получает `0.5`, а её видимая
-стадия остаётся `0`; GPU/window path этим тестом не исполняется.
+стадия этого ресурсного узла остаётся `0`. Затем другой, двухстадийный узел
+получает долю `0.5` и отдельный stage API переводит его из `0` в `1`.
+GPU/window path этим тестом не исполняется.
Native-часть этих ABI проверок воспроизводит
`behavior_distributor_tick_native_oracle.cs` на синтетически выделенной памяти