aboutsummaryrefslogtreecommitdiff
path: root/docs/appendices
diff options
context:
space:
mode:
Diffstat (limited to 'docs/appendices')
-rw-r--r--docs/appendices/knowledge-boundaries.md42
-rw-r--r--docs/appendices/script-vm.md65
2 files changed, 87 insertions, 20 deletions
diff --git a/docs/appendices/knowledge-boundaries.md b/docs/appendices/knowledge-boundaries.md
index e8bdb42..9869581 100644
--- a/docs/appendices/knowledge-boundaries.md
+++ b/docs/appendices/knowledge-boundaries.md
@@ -338,17 +338,37 @@ MSH-часть проверки подтверждает начальный сн
остаётся статическим выводом по RVA `AniMesh.dll+0xa460`, а последующие
изменения в полном Control/animation tick-е не проверялись.
-Для provider-строки Rust сохраняет исходные и текущие amount/type-1 поля
-отдельно, а `processed_amount_bits` соответствует native `+0x0c`. Инициализатор
-`Control.dll+0xf940` кладёт результат selector `3` в текущее и обработанное
-количество; при подтверждённых единичных множителях это raw `max_volume` NDP.
-Прямой API `apply_loaded_mission_control_node_delta` меняет amount, долю, флаг
-истощения, aggregate и dirty, применяя публикацию `0x200` к CPU-проекции
-соответствующего узла модели. Исходный `AniMesh.dll+0x5750` подтверждён в
-связке с `Control+0x10f30`: меняется только поле узла `+0x124`, а стадия и
-соседние узлы сохраняются. Эта проекция ещё не подключена к GPU/window path
-и сама delta-операция не выполняет пересчёт стадий, видимости, FX или время
-Control. Обработанное количество при ней остаётся прежним. Отдельный
+Для provider-строки Rust хранит amount `+0x08`, накопитель `+0x10`, обработанное
+количество `+0x0c`, долю `+0x14`, стадию `+0x18` и flags `+0x28` раздельно.
+Инициализатор `Control.dll+0xf940` кладёт результат selector `3` в текущее и
+обработанное количество; при подтверждённых единичных множителях это raw
+`max_volume` NDP. Таблица также хранит capacity aggregate `+0x58c`, текущий
+aggregate `+0x590`, dirty `+0x598` и начальный gate `+0x618`.
+
+Прямой API `apply_loaded_mission_control_node_delta` сохраняет native четвёртый
+аргумент `0`: меняет amount, долю, флаг истощения, aggregate и dirty, оставляя
+`+0x10` нетронутым. Публикация `0x200` отражается в CPU-проекции соответствующего
+узла модели по правилу исходного обработчика; стадия и соседние узлы не меняются.
+Обработанное количество при этой прямой операции остаётся прежним.
+API `distribute_loaded_mission_control_provider_amount` переносит
+`Control+0x10ba0`: proportional mode делит добавку по свободной ёмкости, а
+вычитание распределяет по текущим количествам; sequential заполняет строки
+вперёд, снимает с конца и использует исходный запрос даже если общая ёмкость
+округлилась вниз. Row updater вызывается с четвёртым аргументом `1`, поэтому
+`+0x10` получает фактическую разницу amount. После распределения обязателен
+`0x11130(root, true)`.
+
+Оба API работают только с CPU-проекцией и не подключены к GPU/window path или
+игровому Control clock. Gate `+0x618` изначально выключен; событие `7` задаёт его
+по правилу `gate = (arg == 2)` и вызывает `0x2dc20`, только если gate изменился.
+События Control в Rust пока не исполняются.
+Capacity aggregate выведен при подтверждённых единичных множителях Unit DAT;
+изменение масштабов `0x9ee0`/`0x9f90` не реализовано. Из-за округления `+0x590`
+может стать больше сохранённого `+0x58c`; распределение сохраняет этот signed
+capacity по native формуле, не вводя отдельного запрета. Если итоговый stage walk
+нуждается в неизвестном состоянии, depletion lifecycle, FX или host callback,
+распределение сообщает ошибку и не публикует ни одной частичной записи.
+Отдельный
`update_loaded_mission_control_node_stage` реализует наследование parent ratio
и stage, ceiling-арифметику, CPU visible stage и копию processed amount.
Отдельная `propagate_loaded_mission_control_node_stage` переносит `0x11130`:
diff --git a/docs/appendices/script-vm.md b/docs/appendices/script-vm.md
index 60d15e1..b658348 100644
--- a/docs/appendices/script-vm.md
+++ b/docs/appendices/script-vm.md
@@ -624,12 +624,25 @@ oracle вызывает оригинальные `FUN_10010ba0` (RVA `0x10ba0`),
`0xdc40`. Пропорциональный режим проверен на максимумах `[30, 60, 50]`, текущих
значениях `[10, 20, 0]` и добавке `22`, результат `[14, 28, 10]`; отдельный
вектор подтверждает последовательное заполнение вперёд и вычитание с конца.
-Проверены ограничение строк, снятие признака истощения при пополнении и порядок
-обратных вызовов. При x87 control word `0x007f` для `[2^24, 2]` с запросом `-1`
-получены значения `[16777214, 1.99999976]` и итог `16777216`: округление
-вычисленного изменения даёт `-2`. Oracle задаёт внешнюю публикацию результата
-обратным вызовом; provider строки не имеют родительских узлов и не проходят
-отдельный жизненный цикл истощения корневого объекта.
+Проверены ограничение строк, пропуск истощённых записей, их пополнение с флагом
+revive и порядок обратных вызовов. Все распределительные вызовы используют
+четвёртый аргумент `1` в `0x10f30`: фактическое изменение строки прибавляется к
+её полю `+0x10`. Для исходных значений `[2^24, 2]` и запроса `-1` получены
+`[16777214, 1.99999976]`, общий итог `16777216` и накопленные разницы
+`[-2, -2.3841858e-7]`. Проверка также подтверждает, что последовательный режим
+несёт исходный запрос между строками: сумма свободных мест `[16777216, 1]`
+округляется до `16777216`, однако запрос `33554432` заполняет обе строки.
+Oracle задаёт внешнюю публикацию результата обратным вызовом; provider-строки
+не имеют родительских узлов и не проходят отдельный жизненный цикл истощения
+корневого объекта.
+
+Агрегаты тоже округляются независимо. Начальная ёмкость `+0x58c = 33554436`
+для максимумов `[33554432, 3]` не меняется при обновлениях одной строки
+`-1, -1, -1, +3`, но текущий итог `+0x590` округляется до `33554440`.
+Следующая добавка `1` с revive использует signed capacity `-4`, выдаёт ratio `1`
+и сохраняет уже полные строки. Native oracle и Rust повторяют эту достижимую
+последовательность; отрицательный результат разности сам по себе не является
+ошибкой состояния.
Для `FUN_10012a40` (RVA `0x12a40`) нативный вектор задаёт класс `4`, интервал
`2`, коэффициент `+0x1a4` равный `1` и текущее значение `10.000001`; результат
@@ -654,14 +667,16 @@ oracle вызывает оригинальные `FUN_10010ba0` (RVA `0x10ba0`),
хосте класса `10`, как описано ниже. Источник входного времени и порядок его
доставки до обработчика установлены статически;
Rust ещё не вызывает этот бюджетный цикл; отдельно перенесён прямой путь
-изменения одной строки `0x10f30`, описанный ниже.
+изменения одной строки `0x10f30` и явный шаг распределения `0x10ba0`, описанные
+ниже. Ни один из них пока не подключён к игровому Control clock.
#### Прямое изменение одной строки в Rust
`apply_loaded_mission_control_node_delta(engine, handle, key, delta)` моделирует
`0x10f30` с нулевым четвёртым аргументом: накопление анимационного изменения
-`+0x10` и detached-ветвь сюда не входят. Максимум читается из исходной NDP
-строки при подтверждённых единичных множителях Unit DAT. Сначала складываются
+`+0x10` не выполняется, а текущее значение поля сохраняется; detached-ветвь
+объекта тоже не моделируется. Максимум читается из исходной NDP строки при
+подтверждённых единичных множителях Unit DAT. Сначала складываются
`f32` amount и delta, результат ограничивается `0..maximum`; при изменении
native `+0x590` получает `max(0, total + (new - old))`, `+0x14` — долю
`new / maximum`, а `+0x598` становится dirty. Флаг `+0x28 & 0x10` отмечает
@@ -711,6 +726,38 @@ Native oracle отдельно подтверждает сохранение `+0
native записывает биты `+0.0`, но сравнение количеств считает их равными:
доля, флаги, итог и callback остаются прежними. Этот случай сохранён и в Rust.
+#### Распределение provider-таблицы в Rust
+
+`distribute_loaded_mission_control_provider_amount` переносит общий шаг
+`Control.dll+0x10ba0`. Режим proportional распределяет добавку по свободной
+ёмкости, а снятие — по текущему количеству строк; sequential заполняет их с
+первой и снимает ресурс с последней. Для sequential native сохраняет исходную
+величину запроса, даже когда сумма свободных мест округляется вниз.
+`revive_exhausted` включает строки с флагом истощения `+0x28 & 0x10` при добавке.
+Rust хранит максимум общей таблицы `+0x58c` отдельно от текущей суммы `+0x590`;
+для загруженных Unit DAT эти значения рассчитаны при подтверждённых единичных
+масштабах. Их разность может стать отрицательной из-за независимого округления
+изменений текущего агрегата; распределитель сохраняет такой signed capacity по
+формуле оригинала. Обновления масштабов `0x9ee0` и `0x9f90` в Rust не реализованы.
+
+Native row updater вызывается здесь с четвёртым аргументом `1`, поэтому
+изменение `(new amount - old amount)` накапливается в provider `+0x10`.
+`apply_loaded_mission_control_node_delta` сохраняет прежний четвёртый аргумент
+`0` и оставляет этот накопитель нетронутым. После всех строк `0x10ba0`
+обязательно запускает `0x11130(root, update_effects=true)`. Rust переносит этот
+проход на копии таблицы: если ему нужны неизвестное состояние, depletion
+lifecycle, FX или host callback, весь шаг завершается ошибкой без частичных
+amount, accumulator, aggregate или stage изменений.
+
+Поле `+0x618` изначально выключено; обработчик события `7` задаёт gate по
+правилу `gate = (arg == 2)` и вызывает пересчёт `0x2dc20`, только если gate
+изменился. Проекция сохраняет начальное состояние и уважает установленную
+suspension-метку. События Control пока не исполняются,
+поэтому это API остаётся явным CPU-шагом и не подключено к игровому clock.
+Тесты Rust повторяют пропорциональный вектор, накопитель `+0x10`, округление
+`2^24`, sequential capacity boundary, достижимый negative capacity и откат при
+unsupported FX/lifecycle.
+
#### Бюджет и обновление устройства tag 15
Для той же сборки `Control.dll` oracle исполняет оригинальный диспетчер