test(runtime): verify native Control provider updates
Docs Deploy / Build and Deploy MkDocs (push) Successful in 33s
Docs Deploy / Build and Deploy MkDocs (push) Successful in 33s
This commit is contained in:
4 files changed
+312
-26
No files matched your search
@@ -326,20 +326,23 @@ sidecar недоступен, запрос `0xe00` сообщает это от
|
||||
Rust query обращается к загруженному объекту и поддерживает `0xe00` только для
|
||||
текущего descriptor tag `26` с factory tag `26`; другие активные typed tags и
|
||||
factory paths остаются явными границами. Этот запрос возвращает начальный
|
||||
снимок provider amount: Native `FUN_10010f30` (RVA `0x10f30`) изменяет и
|
||||
ограничивает количество, а связанные callbacks переносят его между строками;
|
||||
этот переход в Rust ещё не реализован.
|
||||
снимок provider amount; дальнейшее изменение строк в Rust не реализовано.
|
||||
Native oracle проверил изолированные пути распределения, обновления класса `4`
|
||||
и начальную ветвь таймера. Активную clock-ветвь не запускали; внешний источник
|
||||
времени и порядок вызовов остаются незакрытыми. Источник контактного коэффициента
|
||||
прослежен статически, но не исполнен; синтетические provider-строки не имеют
|
||||
родителей, а родительская логика и lifecycle истощения не проверены. Подробные
|
||||
векторы и статические границы приведены в
|
||||
[техническом подразделе о provider-состоянии Control](script-vm.md#изменение-provider-состояния-control).
|
||||
|
||||
Отдельный API `advance_loaded_mission_resources` принимает явное время очереди
|
||||
и обновляет представленные поля `CurrentOre`, строк распределителя и Control
|
||||
selector `1`. Его граница — статические снимки профиля и provider-значений:
|
||||
динамическое распространение Control amount, смена профилей, special
|
||||
object-state gate и жизненный цикл созданных/удалённых объектов здесь не
|
||||
моделируются. Если обязательный запрос позднего объекта не поддержан,
|
||||
транзакция возвращает ошибку и не применяет подготовленные изменения. API не
|
||||
подключён к игровому циклу; AutoDemo-тест подтверждает связь настоящих профилей
|
||||
с этим шагом, но не полный паритет миссии. Отдельный aggregate getter Behavior
|
||||
RVA `0xa490` в oracle не исполнен.
|
||||
selector `1`. API не подключён к игровому циклу и не обновляет Control amount,
|
||||
профили, special object-state gate или жизненный цикл объектов. Если обязательный
|
||||
запрос позднего объекта не поддержан, транзакция возвращает ошибку без применения
|
||||
подготовленных изменений. AutoDemo-тест подтверждает связь настоящих профилей с
|
||||
этим шагом, но не полный паритет миссии; отдельный aggregate getter Behavior RVA
|
||||
`0xa490` в oracle не исполнен.
|
||||
|
||||
Behavior selectors `0x1002` и `0x1005` используют значения выбранного
|
||||
профиля из `behpsp.res`, разобранного до создания нового мира. `0x1002` складывает
|
||||
|
||||
@@ -541,11 +541,14 @@ if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
||||
exit $LASTEXITCODE
|
||||
```
|
||||
|
||||
Native oracle Add, normalize и distributor tick компилируется и запускается
|
||||
так:
|
||||
Изолированный x86 oracle оригинальных Behavior, ArealMap и Control
|
||||
компилируется и запускается так:
|
||||
|
||||
```powershell
|
||||
$env:FPARKAN_ORIGINAL_BEHAVIOR_DLL = 'C:\GOG Games\Parkan - Iron Strategy\Behavior.dll'
|
||||
$env:FPARKAN_ORIGINAL_CONTROL_DLL = 'C:\GOG Games\Parkan - Iron Strategy\Control.dll'
|
||||
$env:FPARKAN_ORIGINAL_AREALMAP_DLL = 'C:\GOG Games\Parkan - Iron Strategy\ArealMap.dll'
|
||||
$env:FPARKAN_ORIGINAL_BEHAVIOR_PROFILE_RES = 'C:\GOG Games\Parkan - Iron Strategy\behpsp.res'
|
||||
New-Item -ItemType Directory -Force -Path target\behavior-distributor-native-oracle | Out-Null
|
||||
& "$env:WINDIR\Microsoft.NET\Framework\v4.0.30319\csc.exe" /nologo /platform:x86 /out:target\behavior-distributor-native-oracle\BehaviorDistributorTickOracle.exe crates\fparkan-runtime\tests\behavior_distributor_tick_native_oracle.cs
|
||||
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
||||
@@ -567,9 +570,15 @@ IAT-слоты `GetQueue` и `GetSystemArealMap`, а synthetic vtables зада
|
||||
Tick-векторы проверяют нулевой шаг, обе ветви селекторов скорости, пропуск
|
||||
состояния `0xfffe`, отсутствующий объект, повторное чтение `0x1002`, ограниченный
|
||||
запас руды, порог `0.01`, ветви дефицита/частичного/избыточного предложения и
|
||||
равенство спросу, разные веса и достаточную/недостаточную мощность. Это
|
||||
синтетические ArealMap объекты: oracle исполняет оригинальные scheduler и tick,
|
||||
но не сравнивает паритет Rust и не заменяет проверку полной миссии в игре.
|
||||
равенство спросу, разные веса и достаточную/недостаточную мощность. Тот же
|
||||
harness проверяет в оригинальном Control пропорциональное и последовательное
|
||||
распределение provider amount, коэффициент класса `4` с интервалом `2`, а также
|
||||
неактивную временную ветвь с входами `0.5`, `1` и `2`. Вызовы Control используют
|
||||
синтетические строки и хостовые callbacks; ArealMap тоже получает синтетические
|
||||
объекты. Harness сверяет SHA-256 всех трёх DLL; ArealMap загружается из
|
||||
изолированной временной рабочей папки, которую процесс затем удаляет. Эти тесты
|
||||
проверяют отдельные native-пути, но не полный Control update и не паритет Rust с
|
||||
игрой.
|
||||
|
||||
Caller oracle проверяет AutoDemo пару `(500.2857, 751.8217)`, четыре режима
|
||||
x87 на tie-векторах, границу `10000` и младший DWORD. AI oracle отдельно
|
||||
@@ -596,6 +605,45 @@ tie-векторов подтверждает реакцию `FISTP`, но не
|
||||
форме инструкции. Всё остальное содержимое `.scr` сохраняется reader-ом, но
|
||||
остаётся вне этого исполнения.
|
||||
|
||||
### Изменение provider-состояния Control
|
||||
|
||||
Для `Control.dll` (SHA-256
|
||||
`bcb86318089028548a178b03a21accdce15df0cc85ddd91674cf3c2f55012c6e`) native
|
||||
oracle вызывает оригинальные `FUN_10010ba0` (RVA `0x10ba0`), `FUN_10010f30`
|
||||
(RVA `0x10f30`) и selector-3 provider getter через vtable `0x3d254`, RVA
|
||||
`0xdc40`. Пропорциональный режим проверен на максимумах `[30, 60, 50]`, текущих
|
||||
значениях `[10, 20, 0]` и добавке `22`, результат `[14, 28, 10]`; отдельный
|
||||
вектор подтверждает последовательное заполнение вперёд и вычитание с конца.
|
||||
Проверены ограничение строк, снятие признака истощения при пополнении и порядок
|
||||
обратных вызовов. При x87 control word `0x007f` для `[2^24, 2]` с запросом `-1`
|
||||
получены значения `[16777214, 1.99999976]` и итог `16777216`: округление
|
||||
вычисленного изменения даёт `-2`. Oracle задаёт внешнюю публикацию результата
|
||||
обратным вызовом; provider строки не имеют родительских узлов и не проходят
|
||||
отдельный жизненный цикл истощения корневого объекта.
|
||||
|
||||
Для `FUN_10012a40` (RVA `0x12a40`) нативный вектор задаёт класс `4`, интервал
|
||||
`2`, коэффициент `+0x1a4` равный `1` и текущее значение `10.000001`; результат
|
||||
равен `8.000001`, вспомогательное поле — `-2`, нормализованное поле имеет биты
|
||||
`0x3da3d70c`. Происхождение коэффициента подтверждено только статическим
|
||||
трассированием: `FUN_1001a450` (RVA `0x1a450`) запрашивает интерфейс IID `0x0d`,
|
||||
вызывает его slot `+0x24`, читает DWORD по смещению `+0x0c` в полученной записи
|
||||
и сохраняет его в поле объекта `+0x1a4`. Поэтому нативный вектор проверяет
|
||||
арифметику `FUN_10012a40` с заданным коэффициентом, а не исполнение контактного
|
||||
пути или его игровой источник.
|
||||
|
||||
`FUN_1000bcf0` (RVA `0xbcf0`) получает абсолютное значение времени. Oracle
|
||||
исполняет только безопасную начальную ветвь при `+0xe0 = 0`: вход `0.5`
|
||||
обновляет `+0xe8`, а входы `1` и `2` синхронизируют `+0xe4`, `+0xec`, `+0xd8` и
|
||||
`+0xdc` без callbacks. Активную ветвь этот тест не запускал. Статический код
|
||||
показывает gate по `+0xe0`; при условии `randomized_deadline < +0xe4` или
|
||||
`+0xd4 != 0` вычисляет `dt = (+0xe4 - +0xec) * 0.001`. x87 выполняет `FSUB`,
|
||||
затем `FMUL` с binary32-константой `0.001` (`0x3a83126f`), после чего результат
|
||||
сохраняется в `f32`. Код вызывает `FUN_10012a40`, затем `FUN_1002d340` и
|
||||
присваивает `+0xec = +0xe4`. В соседней ветви update packet queue обрабатывается
|
||||
через `FUN_10012ce0`. Источник абсолютного времени извне и полный порядок
|
||||
вызовов в игре не установлены; эти связи остаются статическим выводом. Rust
|
||||
продолжает читать начальные provider snapshots и не моделирует эти изменения.
|
||||
|
||||
### Аргументы и обратный вызов Handler(30)
|
||||
|
||||
`resolve_handler30_with_values` сохраняет восстановленное ABI типов объявлений,
|
||||
|
||||
@@ -859,13 +859,26 @@ 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 или последующие изменения профиля.
|
||||
После загрузки количество в строках может меняться. Контроллер распределяет
|
||||
добавку либо пропорционально свободному месту, либо по очереди: при максимумах
|
||||
`[30, 60, 50]`, текущих значениях `[10, 20, 0]` и добавке `22` первый способ
|
||||
даёт `[14, 28, 10]`. При вычитании последовательный способ начинает с последней
|
||||
строки. Так одна таблица описывает и текущее значение, и то, как оно меняется.
|
||||
|
||||
Для точного повтора важен порядок округления. При исходных значениях `[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` и вернуться в него при
|
||||
|
||||
Reference in new issue
Block a user