feat(runtime): restore Control selector 15
Docs Deploy / Build and Deploy MkDocs (push) Successful in 36s
Docs Deploy / Build and Deploy MkDocs (push) Successful in 36s
This commit is contained in:
3 files changed
+415
-14
No files matched your search
@@ -1060,6 +1060,71 @@ factory-класса. В Rust неизвестный текущий тег за
|
||||
CPU-вызов, ни локальные векторы не означают включения бюджетного шага в Control
|
||||
clock.
|
||||
|
||||
#### Глобальный Control getter: сырой селектор `0x0f`
|
||||
|
||||
В `Control.dll` SHA-256
|
||||
`bcb86318089028548a178b03a21accdce15df0cc85ddd91674cf3c2f55012c6e`
|
||||
`FUN_1002b410` (RVA `0x2b410`) принимает сырой селектор в `EDX` и указатель
|
||||
результата из `[ESP+4]`; общий выход использует `RET 4`. Сырой селектор `0x0f`
|
||||
попадает в case RVA `0x2b8f5`. Владелец хранит ссылки на объекты, добавленные
|
||||
фабриками `9` (`owner+0x5cc`) и `21` (`owner+0x5d0`).
|
||||
|
||||
Фабрика `21` вызывает общий getter `FUN_10021d00` (RVA `0x21d00`): selectors
|
||||
`0..5` читают шесть текущих `coefficient_bits` по `this+0x54`. Общий загрузчик
|
||||
RVA `0x21d50` первоначально копирует descriptor words `[11..16]` в это поле. Фабрика `9`
|
||||
использует getter `FUN_100255c0` (RVA `0x255c0`), который для selector `0`
|
||||
умножает коэффициент `[this+0x54]` на множитель `[this+0x11c]`. Поэтому Rust
|
||||
выбирает последнюю строку каждого `factory_tag` `9` и `21` в исходном порядке
|
||||
таблицы; текущий `descriptor.tag` не меняет выбранную фабрику. Если любой строки нет,
|
||||
результат отсутствует до проверки полей другой строки.
|
||||
|
||||
Арифметика case `0x0f` сохраняет порядок и отдельное округление каждого шага:
|
||||
|
||||
```text
|
||||
sum = f32(D5)
|
||||
for k = 4, 3, 2, 1, 0:
|
||||
sum = f32(sum + Dk)
|
||||
out = f32(C0 * sum)
|
||||
```
|
||||
|
||||
`Dk` — текущий коэффициент `k` из `coefficient_bits` фабрики `21`; `C0` —
|
||||
selector `0` фабрики `9`, то есть
|
||||
`coefficient_bits[0] * class9_selector0_scale_bits`. Общие `multiplier_bits`, `node_provider_status` и
|
||||
`native_word_50_bits` в этом обратном вызове не читаются. Rust проверяет, что
|
||||
входы и промежуточные результаты конечны и являются обычными числами либо
|
||||
точным нулём; переполнение, денормализованные числа и отсутствующие поля
|
||||
остаются типизированными ошибками. Диапазон
|
||||
проверяется через `f64`, а затем операция выполняется в `f32` с округлением
|
||||
после каждого сложения. Это воспроизводит описанные записи `f32`, но не
|
||||
моделирует полное управляющее состояние x87. Этот getter не реализует весь Control
|
||||
metadata `0x36`, Handler `43` или каталог свойств.
|
||||
|
||||
Лицензионный acceptance-test загружает `MISSIONS/Autodemo.00/data.tma` с явным
|
||||
`MissionStartupInput { queue_time_ms: 100_000, research_creation_gate: false }`
|
||||
и вызывает публичный `query_loaded_mission_control_resource(..., 15)`. Native
|
||||
вызов исходного `Control.dll` того же SHA выполнен с `executionCW=0x007f` и
|
||||
получил следующие биты на Rust-подготовленном снимке входных полей:
|
||||
|
||||
| `original_id` | Результат selector `0x0f` |
|
||||
| --- | --- |
|
||||
| `0` | `0x46572800` |
|
||||
| `1` | `0x4636d000` |
|
||||
| `2` | `0x467b4001` |
|
||||
| `3` | `0x468ca000` |
|
||||
| `4` | `0x46ec4001` |
|
||||
| `5` | `0x46ec4001` |
|
||||
|
||||
Для `original_id` `6` и `7` таблица Rust не содержит обоих требуемых объектов
|
||||
фабрик (`factory_tag` `9` и `21`), поэтому публичный запрос возвращает `None`.
|
||||
Исходный обратный вызов для этих двух объектов отдельно не запускался; ветвь
|
||||
неуспеха native getter-а проверена на отдельном векторе с отсутствующим указателем.
|
||||
|
||||
Сравнение шести значений проверяет формулу getter-а на исходных игровых ресурсах
|
||||
и снимке входных полей, подготовленном Rust. Оно не снимает состояние фабрик,
|
||||
созданных оригиналом. Время и флаг `queue_time_ms` и
|
||||
`research_creation_gate` задаёт тест, поэтому эти значения не подтверждают
|
||||
начальное состояние запуска AutoDemo в оригинале.
|
||||
|
||||
#### Фабричный tag 26: изменяемая добавка
|
||||
|
||||
В этой сборке `Control.dll` SHA-256
|
||||
|
||||
+31
-11
@@ -992,21 +992,41 @@ descriptor tag `19` и положительным selector-0 ответом; п
|
||||
его 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-а.
|
||||
`1`, `2` и `15`, а также `set_loaded_mission_control_multiplier` для setter-а
|
||||
`1`. Вызовы сначала проверяют живой `ObjectHandle`, затем обращаются к таблице
|
||||
этого объекта из полной загрузки миссии. Синтетические тесты проверяют границы
|
||||
пустой таблицы, нулевого знаменателя, отсутствующих объектов фабрик и чисел за
|
||||
диапазоном нормального `f32`; лицензированный тест сверяет реальные descriptor
|
||||
tags и получает для `min_l_n1.dat` сумму `16` и отношение `1` до setter-а.
|
||||
|
||||
Сырой селектор `0x0f` соединяет два ранее созданных объекта владельца: у строки
|
||||
с `factory_tag = 9` берётся коэффициент и его текущий множитель, а у строки с
|
||||
`factory_tag = 21` — шесть текущих `coefficient_bits`. `INTO` может поменять
|
||||
`descriptor.tag`, не заменяя объект фабрики, поэтому query выбирает последние
|
||||
строки по `factory_tag`, а не по текущему tag. Если любой объект фабрики
|
||||
отсутствует, ответ — `None`. Иначе шесть коэффициентов складываются с индекса `5`
|
||||
к `0` с округлением до `f32` после каждого сложения; результат умножается на
|
||||
selector `0` фабрики `9` (`coefficient_bits[0] * class9_selector0_scale_bits`).
|
||||
Общие `multiplier_bits`, `node_provider_status` и `native_word_50_bits` в этой
|
||||
формуле не участвуют.
|
||||
|
||||
Лицензионная проверка загружает AutoDemo с явно переданными
|
||||
`MissionStartupInput { queue_time_ms: 100_000, research_creation_gate: false }`
|
||||
и вызывает `query_loaded_mission_control_resource(..., 15)` для исходных
|
||||
объектов `0..5`; для `6` и `7` Rust возвращает `None`, потому что не хватает как
|
||||
минимум одного объекта фабрики. Native-биты для `0..5` приведены в технической
|
||||
главе. Проверка сверяет результат исходного геттера на снимке входных полей,
|
||||
подготовленном Rust. Время и флаг заданы самим тестом; они не доказывают
|
||||
начальный режим запуска AutoDemo в оригинале и не являются захватом его фабрик
|
||||
или состояния объекта Control.
|
||||
|
||||
В этом API пока реализованы только getter selectors `1`/`2` и setter `1`.
|
||||
Отдельный native setter selector `17`, tag-specific методы прочих factory tags,
|
||||
их внешние эффекты и вызов из регулярного шага Behavior здесь не моделируются.
|
||||
Числа должны оставаться конечными и нормальными либо точным нулём; произведения
|
||||
и отношения за поддерживаемым диапазоном `f32` возвращают явную ошибку, а не
|
||||
подменяются нулём или `None`. При проверке диапазона Rust оценивает операцию в
|
||||
`f64`, затем выполняет её в `f32`; это ограниченная проверка диапазона, а не
|
||||
эмуляция полного x87 accumulator-а.
|
||||
и суммы за поддерживаемым диапазоном `f32` возвращают явную ошибку, а не
|
||||
подменяются нулём или `None`. При проверке диапазона Rust сначала оценивает
|
||||
границы в `f64`, затем выполняет каждую операцию в `f32`; это сохраняет
|
||||
пошаговое округление этого getter-а, но не эмулирует весь x87 execution state.
|
||||
|
||||
Отдельная ветка того же GOG `AniMesh.dll` показывает, когда создаётся Behavior
|
||||
для host object. В `FUN_10002ff0` (RVA `0x2ff0`, SHA-256
|
||||
|
||||
Reference in new issue
Block a user