feat(runtime): query and update loaded Control resources
Docs Deploy / Build and Deploy MkDocs (push) Successful in 1m17s

This commit is contained in:
Valentin Popov committed 2026-10-22 14:19:25 +04:00
1 parent 40e4392138
commit b9a4d1b478
4 files changed
+958 -25

No files matched your search

+20 -9
View File
@@ -282,15 +282,26 @@ Control различает добавление устройства и прим
подготовленного CTL должно оставаться явным unavailable result, а не
трактоваться как пустой список.
Глобальные Control selectors `1/2` и setter selector `1` по tag `19` описаны
там же только по статическому разбору `Control.dll`; их вызовы отдельно не
исполнялись. Проекция полного mission load недоступна для неполного списка
typed records, Control resource у non-geometric prototype и некоторых
неразрешённых EXTO node mappings; preview и объекты без Unit DAT root её не
строят. Её соответствие полной загрузке игры для всех типов компонентов и
factory paths ещё не установлено. Не восстановлен и жизненный цикл множителя
`+0x4c` после конструктора и переопределения; также неизвестно, когда эти
объекты создаются при отложенной загрузке.
Global Control getters `1/2` и setter `1` проверены в native x86 oracle для
искусственных factory/descriptor pairs `9`, `15` и `19`, а в Rust реализованы
для текущего descriptor tag `19` с factory tags `9`, `15`, `19` и `25`. Для tag
`25` общий getter slot `+0x10` подтверждён чтением vtable, но агрегатный вызов
этого класса native oracle не запускал. Rust API обращается к строкам проекции
конкретного живого `ObjectHandle`; это запрос к уже загруженной таблице, а не
исполнение Control или Behavior tick. Setter `17`, остальные factory tags и
внешние эффекты их методов не включены. Для tag `9` selector `0` использует
отдельный scale `+0x11c`; остальные поддержанные классы используют коэффициент
напрямую. Пустой набор и нулевой знаменатель остаются native no-result, а
неподдержанный factory tag и расчётный диапазон произведения/отношения за
нормальным диапазоном `f32` становятся явной ошибкой Rust.
Проекция полного mission load недоступна для неполного списка typed records,
Control resource у non-geometric prototype и некоторых неразрешённых EXTO node
mappings; preview и объекты без Unit DAT root её не строят. Её соответствие
полной загрузке игры для всех типов компонентов и factory paths ещё не
установлено. Setter `1` меняет multiplier `+0x4c` выбранных строк, но расписание
и lifetime этих объектов после конструктора и в отложенной загрузке остаются
непроверенными.
Для `Control.dll` (SHA-256
`bcb86318089028548a178b03a21accdce15df0cc85ddd91674cf3c2f55012c6e`) tag-26
+37 -8
View File
@@ -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