feat(runtime): support class-9 and default Control budgets
Docs Deploy / Build and Deploy MkDocs (push) Successful in 35s
Docs Deploy / Build and Deploy MkDocs (push) Successful in 35s
This commit is contained in:
5 files changed
+986
-67
No files matched your search
@@ -360,13 +360,16 @@ API `distribute_loaded_mission_control_provider_amount` переносит
|
||||
|
||||
Три API работают только с CPU-проекцией и не подключены к GPU/window path или
|
||||
игровому Control clock. Отдельный
|
||||
`advance_loaded_mission_control_budget` переносит `0x2d340` для factory
|
||||
callbacks `15/19` и current descriptor tags `15/19` (категории `0/1`); ставки сохраняются
|
||||
в текущих полях `+0x5dc/+0x5e0`. Он выполняется транзакционно, а неизвестный
|
||||
callback, provider или диапазон числа возвращает ошибку без частичного
|
||||
`advance_loaded_mission_control_budget` переносит `0x2d340` для фабричных
|
||||
callbacks `9`, `15`, `19` и общей default-пары; category lookup использует
|
||||
текущий descriptor tag из подтверждённого префикса `0..=34`. Ставки сохраняются
|
||||
в `+0x5dc/+0x5e0`. Шаг выполняется транзакционно, а неподдержанный
|
||||
специализированный callback, provider или диапазон числа возвращает ошибку без частичного
|
||||
изменения. Тест с нулевым знаменателем генератора подтверждает откат после уже
|
||||
выполненного изменения потребителем. Пустая таблица всё равно записывает в оба поля отрицательный ноль;
|
||||
неактивный callback не требует provider lookup. Gate `+0x618` изначально
|
||||
неактивный callback не требует provider lookup. Class-9 constructor начинает
|
||||
шесть значений `+0x98..+0xac` с `1.0` и шесть дельт `+0xb0..+0xc4` с нуля;
|
||||
`INTO` сохраняет эти runtime-массивы. Gate `+0x618` изначально
|
||||
выключен; событие `7` задаёт его по правилу `gate = (arg == 2)` и вызывает
|
||||
`0x2dc20`, только если gate изменился. События Control в Rust пока не
|
||||
исполняются, поэтому ресурсный шаг вызывается явно и не подключён к часам.
|
||||
@@ -418,13 +421,16 @@ rate, изменение provider и собственного множителя
|
||||
подтверждают текущие ставки `+0x5dc/+0x5e0`, включая значения `0.2`/`0.4` у
|
||||
потребителя tag 15, пустой результат `-0.0` и невырожденную пару исходных
|
||||
устройств tag 19/tag 15 при `dt = 0.375`; Rust-тест повторяет поля этой пары
|
||||
на синтетической таблице. Реализация принимает только описанные factory и
|
||||
category tags; остальные callbacks и состояния остаются явными ошибками.
|
||||
на синтетической таблице. Rust переносит class-9 rate/update и шестизначную
|
||||
adjustment `0x25a90`, общую default callback-пару `0x21860/0x21890`, а также
|
||||
category map только для current descriptor tags `0..=34`. Специализированные
|
||||
factory callbacks вне этого набора остаются явными ошибками.
|
||||
Лицензированный `min_l_n1.dat` содержит исходные factory/current tags
|
||||
`[19, 19, 9, 15, 12, 12, 13, 13, 26, 25, 21]`. Публичный API оставляет всю
|
||||
таблицу без изменений при не конечном интервале и при первом неподдержанном
|
||||
current tag `9`; полный бюджетный проход для этой реальной таблицы поэтому не
|
||||
проверен. Успешные бюджетные native-векторы используют синтетические
|
||||
таблицу без изменений при не конечном интервале. Для конечного интервала
|
||||
предварительная проверка распознаёт категории, но находит неподдержанный
|
||||
factory tag `26` и отклоняет вызов до вычисления ставок и обновлений; полный
|
||||
бюджетный проход для этой реальной таблицы поэтому не проверен. Успешные бюджетные native-векторы используют синтетические
|
||||
NDP/Node38-строки и подтверждают локальные переходы и порядок вызовов, а не
|
||||
полный Control tick на миссии. Прямые oracle-вызовы `0x11220` для одиночной
|
||||
строки используют `updateEffects = false`, что исключает ветвь Control FX и
|
||||
|
||||
@@ -792,21 +792,23 @@ provider getter и изменение количества не подменен
|
||||
|
||||
Rust предоставляет явный CPU-вызов
|
||||
`advance_loaded_mission_control_budget(engine, handle, dt)`. Он переносит
|
||||
диспетчер и callbacks исходных factory tags `15` и `19`, если текущий
|
||||
descriptor tag равен `15` или `19` (native categories `0` или `1`). Rates `+0x5dc/+0x5e0`
|
||||
сохраняются отдельно. Вызов работает на копии полного состояния: неизвестный
|
||||
descriptor, factory callback, provider или численный диапазон возвращает
|
||||
ошибку без публикации частичных изменений. Вызов ещё не включён в Control clock;
|
||||
нативный oracle также проверяет пустую таблицу с отрицательным нулём в обеих
|
||||
выходных ставках и невырожденную пару исходных устройств tag 19/tag 15 при
|
||||
`dt = 0.375`. Этот парный вектор проверяет изменения amount, processed amount,
|
||||
накопителя, доли, обоих множителей и ставок `+0x5dc/+0x5e0` по битам. Rust-тест
|
||||
повторяет его на синтетической provider-таблице. Для лицензированного
|
||||
`min_l_n1.dat` отдельный тест подтверждает состав factory/current tags и то, что
|
||||
первый неподдержанный current tag `9` отклоняет весь шаг без изменений; полного
|
||||
успешного бюджетного прохода для реальной миссионной таблицы пока нет.
|
||||
Rust также отклоняет нулевой знаменатель обновления tag 19; тест вызывает эту
|
||||
ошибку после изменения provider потребителем и подтверждает откат всей таблицы.
|
||||
исходные callbacks factory tags `9`, `15`, `19` и общий default callback, а
|
||||
категории выбирает по текущему descriptor tag. Native map подтверждён только
|
||||
для префикса тегов `0..=34`; неизвестная категория, специализированный
|
||||
callback, provider или численный диапазон возвращает ошибку без публикации
|
||||
частичных изменений. Ставки `+0x5dc/+0x5e0` сохраняются отдельно, а сам вызов
|
||||
ещё не включён в Control clock.
|
||||
|
||||
Нативный oracle проверяет пустую таблицу с отрицательным нулём в обеих выходных
|
||||
ставках, невырожденную пару исходных устройств tag 19/tag 15 при `dt = 0.375`
|
||||
и tag 9 с шестью значениями и шестью накопителями изменений. Rust-тесты
|
||||
повторяют их по битам, включая положительное и отрицательное обновления tag 9.
|
||||
В лицензированном `min_l_n1.dat` предварительная проверка распознаёт категории,
|
||||
но находит неподдержанный factory tag `26` и отклоняет бюджет до расчёта ставок
|
||||
или вызова устройств; транзакционный тест подтверждает, что исходная таблица
|
||||
не меняется. Полный бюджетный проход на реальной миссии пока не выполнен. Rust также отклоняет нулевой знаменатель
|
||||
обновления tag 19; тест вызывает эту ошибку после изменения provider
|
||||
потребителем и подтверждает откат всей таблицы.
|
||||
|
||||
#### Генератор tag 19 в том же бюджетном проходе
|
||||
|
||||
@@ -846,6 +848,74 @@ tag `15`: смысл изменения этого поля зависит от
|
||||
Поддержанные Rust-векторы не означают, что любой Control descriptor или
|
||||
полный миссионный цикл уже работает.
|
||||
|
||||
#### Класс 9: ставка и шесть изменяемых значений
|
||||
|
||||
У `Control.dll` SHA-256
|
||||
`bcb86318089028548a178b03a21accdce15df0cc85ddd91674cf3c2f55012c6e`
|
||||
класс `9` использует constructor RVA `0x25460`, vtable `0x3c938`, rate
|
||||
`0x25700`, update `0x257b0` и adjustment `0x25a90`. Constructor начинает шесть
|
||||
значений в `+0x98..+0xac` с `1.0`, а шесть накопителей в `+0xb0..+0xc4` — с
|
||||
нуля. Текущий `INTO` заменяет descriptor и общие коэффициенты, сохраняя эти
|
||||
runtime-массивы.
|
||||
|
||||
Для rate `q` — текущее значение provider, `B` — descriptor `+0x20`, `C0..C2` —
|
||||
коэффициенты, а `scale` — class-9 поле `+0x11c`. Сначала отдельно округляются
|
||||
`G0 = C0 * scale`, сумма шести значений, и свободная величина `6 - sum`; затем
|
||||
вычисляются доступная часть `(6 - sum) * G0` и запрос `(C1 * q) * dt`. Rate
|
||||
равна `-(dt * B) - C2 * min(доступная часть, запрос)`. В update множитель
|
||||
`+0x4c` сначала получает allocation, затем вычисляется
|
||||
`S = -(rate(dt) * allocation) - (dt * B)`. При `C2 > 0` изменение равно
|
||||
`S / C2`; иначе его знак выбирает `±((C1 * q) * dt)`. Если `+0x618` не
|
||||
приостанавливает обновление, а `G0 > 0`, изменение делится на `G0 * 6` и
|
||||
передаётся `0x25a90`.
|
||||
|
||||
Adjustment умножает упорядоченную сумму шести значений на единственную
|
||||
binary32-константу `0x3e2aaaab` — приблизительное `1/6`. Дополнительного деления
|
||||
на шесть нет. При положительном изменении native ограничивает фактор сверху
|
||||
единицей и приближает каждое значение к `1`; при отрицательном — уменьшает
|
||||
каждое пропорционально ему. Каждый фактический шаг также прибавляется к своему
|
||||
накопителю. Oracle запускает исходные entry points на оригинальном Control.dll
|
||||
при x87 control word `0x007f`:
|
||||
|
||||
| Вектор | Вход | Rate / multiplier | Шесть выходных значений | Шесть выходных дельт |
|
||||
|---|---|---|---|---|
|
||||
| Уменьшение | `q=.4, dt=.5, B=.2, C0=10, scale=1, C1=.6, C2=2`, allocation `.5`; все значения `1`, дельты `0` | `0xbdcccccd`, `0x3f000000` | `0x3f7fe4b1` во всех строках | `0xb9da740e` во всех строках |
|
||||
| Смешанный набор | `q=.4, dt=.5, B=.2, C0=.75, scale=1.25, C1=.6, C2=2`, allocation `1`; значения `[0,.25,.5,.75,1,.9]`, дельты `[.1,-.2,0,.3,-.4,.5]` | `0xbeae147b`, `0x3f800000` | `[3d49a637,3e92e795,3f064d32,3f432699,3f800000,3f67a90a]` | `[3e18cff4,be26fda3,3cc9a637,3e9fe6cc,becccccd,3f0142a4]` |
|
||||
|
||||
Отдельный прямой вызов `0x25a90` для значения `[0,1,1,1,1,1]`, нулевых
|
||||
накопителей и добавки `.1` записывает `0x3f19999c` в первую пару value/delta;
|
||||
остальные пять строк остаются неизменными. Этот vector фиксирует умножение на
|
||||
сохранённую константу, а не вычисление `sum / 6`. Rust хранит оба массива
|
||||
отдельно и сохраняет их при descriptor override; ошибки численного диапазона
|
||||
не публикуют частичный результат.
|
||||
|
||||
#### Общие default budget callbacks и категории
|
||||
|
||||
Ветка фабрики Control RVA `0x2d4b0` направляет обычные классы в constructor
|
||||
`0x20800`; он устанавливает vtable `0x3c448` и word `+0x50 = 5`. Rate и update
|
||||
этого семейства — исходные `0x21860` и `0x21890`: первая возвращает
|
||||
`-(dt * descriptor[+0x20])`, второй записывает allocation в `+0x4c` после
|
||||
общей проверки активности provider. Фабричные теги `12`, `13` и `25` идут по
|
||||
ветке default; tag `21` явно выбирает ту же пару. У tags `4`, `8` и `27` свои
|
||||
vtable/constructor, но их rate/update entries указывают на ту же пару. Native
|
||||
oracle проверяет factory routing тегов `12/13`, vtable pointers и прямой
|
||||
вызов rate/update общей пары. Rust повторяет формулу и сохраняет исходные
|
||||
word-50 defaults, в частности `0x200` у тега `4` и ноль у тега `27`.
|
||||
|
||||
Descriptor category lookup `0x2c3a0` возвращает следующие значения для
|
||||
проверенного префикса `0..=34`:
|
||||
|
||||
```text
|
||||
[0,4,4,0,2,3,0,0,2,5,5,0,0,0,1,0,3,2,0,1,3,5,4,0,4,0,3,5,0,0,4,0,1,2,4]
|
||||
```
|
||||
|
||||
Именно текущий descriptor выбирает категорию; callback остаётся у исходного
|
||||
factory-класса. В Rust неизвестный текущий тег за концом префикса и
|
||||
специализированный factory callback не подменяются общей формулой. На
|
||||
лицензированном Unit DAT полный проход доходит до factory `26` и возвращает
|
||||
ошибку без частичного изменения таблицы. Ни этот CPU-вызов, ни локальные
|
||||
векторы не означают включения бюджетного шага в Control clock.
|
||||
|
||||
#### Активация и начальные часы
|
||||
|
||||
Для Control класса `4` oracle вызывает исходный конструктор RVA `0x31490`
|
||||
|
||||
@@ -725,6 +725,14 @@ component ID и multiplier `2.5` при копировании новых коэ
|
||||
и дополнительная строка `fx` возвращают cursor `record + 0xbf`.
|
||||
Слово CTLD `+0x18 == -1` сохраняет фабричное `+0x50` и при INTO-замене.
|
||||
|
||||
Ветвь фабрики `0x2d4b0` направляет factory tags без отдельного случая в
|
||||
конструктор `0x20800`; его vtable использует общий reader `0x21d50` в slot
|
||||
`+0x1c`. Поэтому common-field override применяется и к этой default-семье,
|
||||
включая tag `6`; Rust-тест проверяет его вместе с тегами `12` и `13`. Tags
|
||||
`1`, `17`, `26` и `30` остаются явными границами: фабрика выбирает для них
|
||||
отдельные классы, а проверки текущей реализации ещё не покрывают их полное
|
||||
setter-поведение.
|
||||
|
||||
У tag `2` slot `+0x1c` указывает на обёртку `0x29650`. Она вызывает тот же
|
||||
reader, затем сохраняет selector `1` в `+0x120`, округляет selector `0` через
|
||||
x87 `FISTP` в `+0x124` и заново обнуляет массив `+0x12c` по накопленному числу
|
||||
@@ -1061,15 +1069,25 @@ Rust переносит этот порядок, сохраняет native на
|
||||
в массиве, его обновление перечитывает уже изменённую долю после обслуживания
|
||||
категории tag 15. Этот явный вызов хранит также две выходные ставки `+0x5dc` и
|
||||
`+0x5e0`, но сам по себе ещё не запускается игровыми часами.
|
||||
Поддержаны factory callbacks `15/19` и текущие descriptor tags `15/19`
|
||||
(категории `0/1`); неизвестное устройство,
|
||||
недоступные данные provider или нулевой знаменатель останавливают весь шаг без
|
||||
частичных изменений.
|
||||
Другие категории и полный миссионный цикл пока не подтверждены. В лицензированном
|
||||
`min_l_n1.dat` рядом с тегами `19` и `15` есть также factory tags `9`, `12`,
|
||||
`13`, `21`, `25` и `26`; поэтому его полный проход пока явно отклоняется на
|
||||
первой неподдержанной категории `9`. Проверка сохраняет всю таблицу без
|
||||
изменений и не доказывает успешный бюджетный шаг на реальной миссии.
|
||||
Помимо класса `15` и генератора `19` поддержан класс `9`: он считает ставку
|
||||
через шесть собственных значений и при распределении обновляет их вместе с
|
||||
накопленными изменениями. Например, для доли provider `0.4`, интервала `0.5`,
|
||||
`B = 0.2`, коэффициентов `C0 = 0.75`, `C1 = 0.6`, `C2 = 2` и масштаба
|
||||
`1.25` исходная ставка имеет биты `0xbeae147b`; после полного выделения
|
||||
обновлённые шесть значений совпадают с native побитно.
|
||||
|
||||
Несколько фабричных классов используют общий callback: ставка равна
|
||||
`-(dt * B)`, а обновление записывает долю выделения в множитель. К этому
|
||||
семейству относятся фабричные теги `12`, `13`, `25` и `21`, а также другие
|
||||
классы, которые исходный диспетчер направляет в фабрику по умолчанию. Текущая
|
||||
категория читается из descriptor: её native map подтверждён только для тегов
|
||||
`0..=34`. Неподдержанный специализированный callback, недоступный provider или
|
||||
неподдержанное число останавливают шаг без частичных изменений. В
|
||||
лицензированном `min_l_n1.dat` предварительная проверка распознаёт текущие
|
||||
категории и выявляет неподдержанный factory tag `26`; она отклоняет бюджетный
|
||||
вызов до расчёта ставок и обновлений, сохраняя таблицу целиком. Полный
|
||||
бюджетный проход на реальной миссии и подключение к игровым часам пока не
|
||||
подтверждены.
|
||||
|
||||
Отдельный путь объекта класса `4` умножает интервал на контактный коэффициент и
|
||||
передаёт изменение строке. В проверенном примере коэффициент `1`, интервал `2`,
|
||||
|
||||
Reference in new issue
Block a user