diff options
| author | Valentin Popov <valentin@popov.link> | 2026-10-31 06:47:32 +0300 |
|---|---|---|
| committer | Valentin Popov <valentin@popov.link> | 2026-10-31 06:47:32 +0300 |
| commit | 6412c12c09e9f9b9e1fa85eba0a2170afa86f405 (patch) | |
| tree | 7fef3a21c0c1442d521bf0d28a24023729c652ca /docs/appendices | |
| parent | 042be27c002900a15b04a58d07239fc189b5ea52 (diff) | |
| download | fparkan-6412c12c09e9f9b9e1fa85eba0a2170afa86f405.tar.xz fparkan-6412c12c09e9f9b9e1fa85eba0a2170afa86f405.zip | |
feat(runtime): restore Control selector 15
Diffstat (limited to 'docs/appendices')
| -rw-r--r-- | docs/appendices/script-vm.md | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/docs/appendices/script-vm.md b/docs/appendices/script-vm.md index be8c8b3..26ac234 100644 --- a/docs/appendices/script-vm.md +++ b/docs/appendices/script-vm.md @@ -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 |
