diff options
Diffstat (limited to 'docs/tomes/06-behavior.md')
| -rw-r--r-- | docs/tomes/06-behavior.md | 76 |
1 files changed, 69 insertions, 7 deletions
diff --git a/docs/tomes/06-behavior.md b/docs/tomes/06-behavior.md index b3dd8d0..0ebbbf7 100644 --- a/docs/tomes/06-behavior.md +++ b/docs/tomes/06-behavior.md @@ -859,13 +859,75 @@ tag-26 ряда получается `1.0` provider × `1.0` coefficient × `1.0 `1.0`. Эти запросы используют начальные provider-значения после конструкторов, а не результаты живого игрового тика. -Поведение provider-строк меняется и после загрузки: например, -`Control.dll!FUN_10010f30` (RVA `0x10f30`) обновляет и ограничивает текущее -значение, а соседние процедуры распространяют его между связанными строками. -Эти изменения пока не отражены в Rust-снимке. Поэтому запрос Control `0xe00` и -Behavior selector `0x1002`, который его суммирует, используют исходное состояние -полной загрузки. Selector `0x1005` прямо возвращает загруженную ставку профиля. -Ни один из них пока не исполняет Control tick или последующие изменения профиля. +У Control есть и начальные сведения о модели узла, но их таблица не совпадает +с NDP. Sidecar задаёт состав и порядок provider-строк, а поле type-1 `+0x14` +получает начальное значение `1.0` от нативного конструктора. AniMesh отдельно +собирает глобальный список MSH-узлов. При создании строки Control берёт +mesh-состояние по её порядковому номеру в общей таблице provider, а не пытается +угадать пару по локальному номеру строки sidecar-а. Например, после 22 +корневых строк номер 22 указывает на первый глобальный узел присоединённой +`EXTO`-модели, который +происходит из её локального узла `1`. + +В снимке это необязательное поле: `None` означает, что для данного номера не +удалось получить MSH-узел; исходные запросы к NDP от этого не исчезают. Поэтому +начальное значение и поза модели остаются отдельными частями состояния: + +```rust +initial_mesh_state: Option<MissionControlNodeInitialMeshState> +``` + +Внутри снимка хранятся родительский индекс, переведённые флаги Control и число +начальных стадий. Узлы корневой модели добавляются все, а присоединённая `EXTO` +начинает с локального узла `1`. Это описывает исходную настройку: код пока не +переключает стадии в ходе игры и не исполняет полный Control tick. + +На той же начальной стадии Control вычисляет количество строки по NDP +`max_volume`. Для загрузки Unit DAT проверенные множители равны `1.0`, поэтому +количество совпадает с исходным значением NDP. Оригинал начинает с одинакового +текущего и последнего обработанного количества; Rust сохраняет его один раз как +`initial_amount_bits`. Это исходный снимок, а не неизменяемая вместимость: +позднее Control меняет оба количества. В лицензированном `min_l_n1.dat` +проверены, например, root row `0` со значением `1.0` и строка `EXTO` с local +row `1` в общей позиции `22` со значением `6000.0`. + +После загрузки количество в строках может меняться. Контроллер распределяет +добавку либо пропорционально свободному месту, либо по очереди: при максимумах +`[30, 60, 50]`, текущих значениях `[10, 20, 0]` и добавке `22` первый способ +даёт `[14, 28, 10]`. При вычитании последовательный способ начинает с последней +строки. Так одна таблица описывает и текущее значение, и то, как оно меняется. + +У строк есть и связи с родительскими узлами. Когда стадия родителя меняется, +Control пересчитывает дочерние строки в глубину: ребёнка вместе со всем его +поддеревом, затем следующего ребёнка. Для числа вариантов `count` внутренняя +стадия вычисляется как `count - ceil(f32(count * ratio))`, а видимое значение +ограничивается диапазоном модели. Например, при трёх стадиях доли +`[0.1, 0.4, 0.5, 1, 0]` дали `[2, 1, 1, 0, 3]`; последнее значение — sentinel +истощения, а в модель передаётся индекс не выше `count - 1`. Нативные проверки +подтвердили порядок обхода и передачу состояния в AniMesh. + +Выбранная стадия также задаёт, какие данные MSH попадают в пересчёт видимости. +У одного синтетического узла первый слот давал `[42, 330]`, а слот другой стадии — +`[102, 570]`. В проверенных векторах одинаковые данные при скрытии и повторном +включении восстановили суммы; переходы с разными слотами — нет. Эти проверки +исполняют исходные DLL на тестовых строках, но не являются запуском Control на +полной миссии; Rust пока сохраняет только начальное состояние provider-строк. +Подробные границы приведены в [техническом приложении](../appendices/script-vm.md#родители-стадии-и-видимость-provider-узлов). + +Для точного повтора важен порядок округления. При исходных значениях `[2^24, 2]` +и запросе `-1` оригинал сначала складывает общий итог с изменением, затем +вычитает прежний итог. Из-за округления фактическое изменение получается `-2`. +Нативная проверка подтвердила это поведение; Rust пока использует начальный +снимок provider-строк и не исполняет их дальнейшее распределение. + +Отдельный путь объекта класса `4` умножает интервал на контактный коэффициент и +передаёт изменение строке. В проверенном примере коэффициент `1`, интервал `2`, +и значение строки уменьшается на `2`; этот коэффициент не является ставкой +производства из профиля. Проверка времени охватывает только начальную ветвь: +активную ветвь не запускали, а источник времени и полный порядок вызовов в игре +пока не установлены. Поэтому запросы Rust `0xe00` и `0x1002` используют +начальные снимки provider-строк, а `0x1005` — загруженную ставку профиля. +Точные нативные векторы и открытые границы описаны в [приложении](../appendices/script-vm.md#изменение-provider-состояния-control). На x87 control word `0x007f` каждое умножение округляет мантиссу до 24 бит, но промежуточная степень может выйти за диапазон `f32` и вернуться в него при |
