aboutsummaryrefslogtreecommitdiff
path: root/docs/tomes
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2026-10-22 13:19:25 +0300
committerValentin Popov <valentin@popov.link>2026-10-22 13:19:25 +0300
commitb9a4d1b478d9ff6dff457617f7296c54db70532e (patch)
treee839d5892f2bf09092cd09a79ab47582719c3517 /docs/tomes
parent40e43921385740b6e2cb502f1cb5e3d8347dc2d7 (diff)
downloadfparkan-b9a4d1b478d9ff6dff457617f7296c54db70532e.tar.xz
fparkan-b9a4d1b478d9ff6dff457617f7296c54db70532e.zip
feat(runtime): query and update loaded Control resources
Diffstat (limited to 'docs/tomes')
-rw-r--r--docs/tomes/06-behavior.md45
1 files changed, 37 insertions, 8 deletions
diff --git a/docs/tomes/06-behavior.md b/docs/tomes/06-behavior.md
index 0bd00df..2b26f62 100644
--- a/docs/tomes/06-behavior.md
+++ b/docs/tomes/06-behavior.md
@@ -668,14 +668,43 @@ Native x86 oracle для тех же GOG DLL выполняет конструк
Статический разбор глобального Control interface показывает aggregate getters
`1/2` (`FUN_1002b410`, RVA `0x2b410`) и setter `1` (`FUN_1002ba30`, RVA
-`0x2ba30`) для устройств tag `19`. Для конечных значений getter `1` вычисляет
-`sum(base * multiplier) / sum(base)`, а getter `2` — `sum(base)`. При встрече
-отрицательного base selector `1` сразу возвращает `1.0`, а selector
-`2` — этот base. Если подходящих записей нет или сумма base неположительна,
-getter возвращает неуспех без записи результата. Setter пишет multiplier `+0x4c`
-только устройствам tag `19` с положительным selector-0 значением; пустой набор
-возвращает успех. Это вывод статического анализа для конечных входных значений,
-без отдельного native execution oracle для глобальных selectors.
+`0x2ba30`) для текущего descriptor tag `19`. Getter `1` складывает ответы
+виртуального selector `0x200` в числитель и selector `0` в знаменатель; getter
+`2` возвращает сумму selector `0`. Для обычного factory tag `19` эти ответы
+равны `coefficient * multiplier` и `coefficient`, то есть отношение сводится к
+`sum(coefficient * multiplier) / sum(coefficient)`. У factory tag `9` selector
+`0` умножает коэффициент на отдельное поле `+0x11c`, тогда как selector `0x200`
+использует коэффициент и multiplier; эта особая база меняет знаменатель.
+Обработчик factory tag `9` расположен в Control RVA `0x255c0`, а его конструктор
+RVA `0x25460` задаёт `+0x11c = 1.0`. При встрече отрицательного ответа selector
+`0` getter `1` сразу возвращает `1.0`, а getter `2` — этот ответ. Если подходящих
+записей нет или сумма базы неположительна, getter возвращает неуспех без записи
+результата. Setter пишет multiplier `+0x4c` только устройствам с текущим
+descriptor tag `19` и положительным selector-0 ответом; пустой набор возвращает
+успех. Фильтр использует **текущий descriptor tag**, который может измениться
+при `INTO`, а виртуальный вызов остаётся методом исходного factory-класса.
+
+Этот путь проверяется native x86 oracle на оригинальной `Control.dll` указанной
+выше: искусственные factory/descriptor пары `9`, `15` и `19` покрывают setter,
+отрицательные ответы, округление и тег `9` с scale `0.5`. Для factory tag `25`
+его vtable slot `+0x10` статически указывает на общий getter RVA `0x21d00`, но
+отдельный aggregate oracle этот класс не запускал. Rust хранит начальный scale
+factory `9` и предоставляет `query_loaded_mission_control_resource` для selector
+`1`/`2` и `set_loaded_mission_control_multiplier` для setter-а `1`. Вызовы
+сначала проверяют живой `ObjectHandle`, затем обращаются к таблице этого объекта
+из полной загрузки миссии. Синтетические тесты проверяют границы пустой таблицы,
+нулевого знаменателя, неподдержанных factory tags и чисел за диапазоном
+нормального `f32`; лицензированный тест сверяет реальные descriptor tags и
+получает для `min_l_n1.dat` сумму `16` и отношение `1` до setter-а.
+
+В этом API пока реализованы только getter selectors `1`/`2` и setter `1`.
+Отдельный native setter selector `17`, tag-specific методы прочих factory tags,
+их внешние эффекты и вызов из регулярного шага Behavior здесь не моделируются.
+Числа должны оставаться конечными и нормальными либо точным нулём; произведения
+и отношения за поддерживаемым диапазоном `f32` возвращают явную ошибку, а не
+подменяются нулём или `None`. При проверке диапазона Rust оценивает операцию в
+`f64`, затем выполняет её в `f32`; это ограниченная проверка диапазона, а не
+эмуляция полного x87 accumulator-а.
Отдельная ветка того же GOG `AniMesh.dll` показывает, когда создаётся Behavior
для host object. В `FUN_10002ff0` (RVA `0x2ff0`, SHA-256