aboutsummaryrefslogtreecommitdiff
path: root/docs/appendices
diff options
context:
space:
mode:
Diffstat (limited to 'docs/appendices')
-rw-r--r--docs/appendices/knowledge-boundaries.md93
-rw-r--r--docs/appendices/script-vm.md103
2 files changed, 159 insertions, 37 deletions
diff --git a/docs/appendices/knowledge-boundaries.md b/docs/appendices/knowledge-boundaries.md
index 7fb6798..7f049fc 100644
--- a/docs/appendices/knowledge-boundaries.md
+++ b/docs/appendices/knowledge-boundaries.md
@@ -10,6 +10,10 @@ authoring API без динамического подтверждения.
Не доказаны символами точные имена renderer vtable slots, полный набор CShade
state transitions и окончательный порядок части transparent/FX/shadow subpasses.
+Дистанционная кривая тумана по квадратам границ подтверждена в живом CShade.
+Выбор проходов по native shade-state и GPU fog color пока заменён общим туманом мира с цветом горизонта;
+это приближение считается как `render_coverage fog_pass_eligibility_approx`.
+
После ограничения цели рельефом интерактивная камера проверяет движение
против каждого отрисовываемого корневого строения класса `FORT` и его
отрисовываемых компонентов. Для этого пути используются текущая Node38-поза
@@ -45,26 +49,13 @@ MSH-запрос со свободной preview-камерой; это не пÐ
стратегической и следящей камерами не подтверждено
([MSH](../reference/msh.md)).
-Для MSH без потока цветов type 16 подтверждён только один постоянный alpha
-override для диапазонов с CPU-цветом и raw-флагом `Batch20` `0x0008`: GOG
-`Terrain.dll`, SHA-256
-`af87d1b2e728a0be73c52be3b44cc196ab46da7799f25a15d40f8c9b0b425ead`, RVA
-`0x1B0F0`, задаёт alpha `0`, если установлен bit `0x0040` и сброшен `0x0010`.
-Это покрывает `0x0148`; `0x0108`, `0x0118` и `0x0058` сохраняют alpha MAT0,
-причём в `0x0058` bit `0x0010` имеет приоритет. Поток type 16 или отсутствие
-`0x0008` исключают override. Проверка заводской сцены с фиксированной нативной
-камерой подтвердила на одном кадре входа восстановление X-образного рисунка
-двери, который виден и в оригинале; прежний Vulkan-readback показывал на этом
-месте сплошной чёрный прямоугольник. Сравнение выполнено при времени сцены
-2000 мс и трёх кадрах, запуск с Vulkan validation завершился без предупреждений
-и ошибок. Это подтверждает только структуру проёма в этой сцене: правильность
-освещения и полный попиксельный паритет не установлены.
-
-Общее fade-поведение по расстоянию в preview не реализовано. Открыты точная
-метрика расстояния, выбор первого CPU-принятого треугольника диапазона и
-эквивалентность frustum/culling-отбора оригинала; эти вопросы нельзя вывести из
-захвата заводской двери. Данные потока type 16 ещё не декодированы, поэтому
-правило выше относится только к MSH-диапазонам без этого потока цветов.
+Кривые alpha и метрика расстояния порталов реализованы для MSH без type 16
+([описание кадра](../reference/render-frame.md#прозрачность-порталов-msh)). Native CPU clipping может выбрать другую первую вершину;
+это приближение явно считается как `portal_fade_packet_selection_approx`.
+
+Данные type 16 ещё не декодированы. Внутренний ракурс «Конструктора» после
+настоящего входа игрока подтверждает исчезновение чёрной поверхности в проходе;
+для всей приёмки R2 ещё нужны пары обеих миссий на трёх дистанциях.
Закрывающий эксперимент: запустить оригинал в совместимой Windows/DirectX
среде, перехватить DirectDraw/Direct3D calls и surface flips, сохранить state
@@ -72,6 +63,10 @@ log на минимальных сценах с одним типом матер
## FXID field-level semantics
+Control Op1 пока использует цвет и радиус без случайных добавок команды;
+это явное приближение считается в `render_coverage control_op1_jitter_unsupported`.
+Масштаб радиуса длиной преобразованного направления и нижняя замена 0,01 восстановлены.
+
Размеры команд, resource references, lifecycle, flags families и используемые
time modes известны. Не закрыто значение каждого поля body opcodes 1--10,
отсутствующий во всех проверенных каталогах opcode 6 и точные формулы редких
@@ -536,6 +531,41 @@ MSH-часть проверки подтверждает начальный сн
остаётся статическим выводом по RVA `AniMesh.dll+0xa460`, а последующие
изменения в полном Control/animation tick-е не проверялись.
+Устройство фабрики `2` через selector `6` читает `+0x174` только при текущем descriptor tag `2`,
+затем проверяет, что устройство создано фабрикой `2` и поле доступно. Значение
+должно быть конечным нормальным числом или нулём любого знака. Строки в
+`[27..35)` и `[35..43)` читаются до первого NUL: хвост игнорируется,
+ASCII-регистр не важен. После изменения пустая строка оставляет старые биты;
+пустая пара конструктора уже совпадает и не вызывает пересчёт. Проверка не
+использует список имён: нужен один корневой mesh `BULL` из `ObjectsRegistry`,
+без дочерних компонентов и записей timeline; все типизированные записи должны
+иметь tag `17`, а эффекты и таблица NDP — разбираться полностью. Число строк
+NDP произвольно, включая пустую таблицу.
+
+Сканер возвращает коды выбранной начальной группы в исходном порядке. Допустимы
+`1/4/12`. `Some([])` означает, что по полному разбору данных команд нет: группа
+отсутствует, пуста или сырое беззнаковое значение индекса не меньше числа
+групп. `None` означает неподдержанный либо неполный разбор; повреждённые данные
+дают ошибку. Для выбранного opcode `4` нужны FXID-типы `2/3/4/5/7/8/9` и
+допустимые CPT-смещения внутри компонента; типы `1/6/10` остаются недоступными.
+Непредставленный ключ или число не превращаются в ноль. Если распознанный
+ресурс повреждён, новая миссия завершается ошибкой до публикации, сохраняя
+прежние мир и RNG.
+
+Загрузка лицензированной AutoDemo и Rust-запрос selector `6` охватили 12
+устройств и семь пар с битовыми значениями:
+`bb_m_01=43f98000`, `bm_m_01=44228000`, `bl_l_01=436a0000`,
+`br_b_01=44c80000`, `bf_b_01=443b8000`, `bl_m_01=443b4000`,
+`bm_l_01=43340000`. Все семь значений совпали с замороженными арифметическими
+векторами. Пятнадцать изолированных вызовов selector `35` оригинальной DLL
+(включая семь однострочных BULL-таблиц) проверили арифметику при x87 control
+word `0x007f`, но не создавали полный native World. Таблица Control-устройств
+Rust по-прежнему строится при полной загрузке
+Unit DAT. CPU-проекция не воспроизводит временное создание объектов оригинала и
+его побочные эффекты FX, звука и RNG, размещение в World или следующий Control
+tick. Полное размещение объектов, игровой tick, Handler 43 и другие
+неподдержанные форматы остаются открытыми.
+
Для provider-строки Rust хранит amount `+0x08`, накопитель `+0x10`, обработанное
количество `+0x0c`, долю `+0x14`, стадию `+0x18` и flags `+0x28` раздельно.
Инициализатор `Control.dll+0xf940` кладёт результат selector `3` в текущее и
@@ -778,16 +808,19 @@ resource-device значения во время игры.
`0x5780/0x57c0` участвуют в векторе; Rust воспроизводит его raw output bits и
отдельные cache, order, clamp и signed-zero случаи.
-Для обычной начальной загрузки scale-input тоже закрыт. AniMesh constructor
-оставляет `+0x158/+0x15c/+0x160` равными `1.0`; перед Control event `4` World3D
-проходит Agent event `0`, AniMesh RVA `0x1a80` вызывает базовый return `0x17df0`
-и передаёт event `4/null` модели, FX, CollManager и CollObject. Их проверенные
-ветви `0x75b0/0x6fc0`, Effect RVA `0x3d30`, Control RVA `0x1ce00` и `0x1fe00`
-не вызывают AniMesh setter `0x14770` и не меняют outer scale. Поэтому FAC0 в
-стандартном `LoadAgent` получает `[1, 1, 1]`. Другой маршрут
-`AddNewObjectToGame`/mirror к setter и последующие placement/tick остаются
-отдельными границами. В synthetic x86-векторе по-прежнему явно заданы `[2,3,5]`;
-он не является источником scale для полного load.
+Для обычной начальной загрузки входной масштаб единичный. Конструктор модели
+AniMesh RVA `0x68a0` задаёт `Model+0x158/+0x15c/+0x160 = 1.0`;
+`Agent+0x158` хранит указатель на отдельный Control. Перед Control event `4`
+World3D проходит Agent event `0`: AniMesh RVA `0x1a80` вызывает базовый return
+`0x17df0` и передаёт event `4/null` модели, FX, CollManager и CollObject.
+Проверенные ветви модели `0x75b0/0x6fc0`, Effect `0x3d30` и CollManager
+`0x1ce00` не меняют масштаб. CollObject получает событие через основной
+интерфейс `0x3c2fc`, slot `+0x08 -> 0x1f530`: он кэширует host-интерфейсы,
+а необязательный вызов CollManager `0x1c330` сохраняет только указатель
+`CollObject+0x20` в `CollManager+0x3c`. Поэтому FAC0 получает `[1, 1, 1]`.
+Отдельные пути `AddNewObjectToGame`/mirror и последующие placement/tick остаются
+за этой границей. В synthetic x86-векторе scales `[2,3,5]` заданы отдельно.
+Подробная привязка интерфейсов приведена в [разборе Script VM](script-vm.md).
Смысл `Slot68 +0x30/+0x34`, tag-27 cache DWORD, owner accumulators `+0x530`,
`+0x534`, `+0x538` и результата mutable word `26` не имеет доказанных единиц
diff --git a/docs/appendices/script-vm.md b/docs/appendices/script-vm.md
index 51dd429..f7f8b97 100644
--- a/docs/appendices/script-vm.md
+++ b/docs/appendices/script-vm.md
@@ -1410,18 +1410,36 @@ payload. Позже та же функция `World3D+0x7cb0` повторяет
времени из `DATWorld+0x32a38` (`0x7e6e`); `World3D+0x7ea0` передаёт туда же
время в `0x80a9`. Setter `World3D+0x5140` записывает входной DWORD в эту ячейку.
Нулевой вызов связывает интерфейсы, а ненулевой `NumericTime` запускает отдельную
-ветвь активации. Конструктор AniMesh задаёт `+0x158/+0x15c/+0x160` равными `1.0`.
-Обработчик модели `0x75b0/0x6fc0` привязывает интерфейсы и матрицу, Effect RVA
-`0x3d30` и Control RVA `0x1ce00` сохраняют host/service указатели, а Control
-`0x1fe00` меняет только локальный collision-флаг. Эти ветви не вызывают AniMesh
-scale setter `0x14770` и не пишут поля масштаба. При загрузке AniMesh получает
-Control secondary owner с QI selector `0xa` и сохраняет возвращённый base owner
+ветвь активации. Модель занимает отдельный объект в памяти: её конструктор
+AniMesh RVA `0x68a0` задаёт `Model+0x158/+0x15c/+0x160 = 1.0`.
+Поле `Agent+0x158` хранит указатель на Control. Проверенные ветви модели
+`0x75b0/0x6fc0`, Effect RVA `0x3d30` и CollManager RVA `0x1ce00` сохраняют
+матрицу и служебные указатели, оставляя масштаб модели неизменным.
+
+Фабрика CollObject возвращает вторичный интерфейс `object+4`. QI `0x28`
+вычитает `4` и сохраняет в `Agent+0x170` основной объект с vtable `0x3c2fc`.
+Его event slot `+0x08` ведёт в Control RVA `0x1f530`. При event `4/null`
+обработчик кэширует семь host-интерфейсов; при наличии QI `0x203` вызывает
+CollManager slot `+0x10` таблицы `0x3c178`. Этот метод, RVA `0x1c330`,
+сохраняет только указатель `CollObject+0x20` в `CollManager+0x3c`.
+Для свежего BULL Agent без внешнего host QI `6` при привязке даёт основной Agent
+с vtable `0x201d4`. Ненулевой event `4` вызывает его slot `+0x24`, AniMesh
+RVA `0x17d60`, который читает `[Agent+0x120]`; вызывающий код сохраняет
+результат в `CollObject+0x24`.
+Затем CollObject slot `+0x0c`, Control RVA `0x1fe00`, сбрасывает бит `0`
+поля `CollObject+0x30`. Event `0x15` с первым DWORD payload `9` завершается
+без вызовов и записей. Поле Control `owner+0x34` хранит указатель на CollObject;
+его slot `+0x14`, RVA `0x1f670`, меняет флаги `CollObject+0x30`.
+Перечисленные ветви не вызывают AniMesh setter `0x14770`.
+
+При загрузке AniMesh получает Control secondary owner с QI selector `0xa`
+и сохраняет возвращённый base owner
в `Agent+0x158`: `AniMesh.dll+0x2ff0` делает этот вызов в RVA `0x32ee..0x3300`,
а `Control.dll+0x76f0` для selector `0xa` вычитает `0x14` из `ECX` и возвращает
указатель. Диспетчер AniMesh RVA `0x1afb..0x1b0d` посылает через `Agent+0x158`
событие `4` в slot `+0x08`. Его base-owner vtable — Control RVA `0x3d298`, и
slot ведёт прямо в `0x314f0`; при нулевом payload исходный обработчик проходит
-`0x7830 -> 0xf940`, поэтому FAC0 входит с constructor scales `[1, 1, 1]`.
+`0x7830 -> 0xf940`, поэтому FAC0 получает Model scale `[1, 1, 1]`.
Встречающиеся рядом переходники относятся к другим интерфейсам: Control owner
`+4` с таблицей `0x3d254` проходит через `0x31ae0` (adjust `-4`), а owner `+8`
с таблицей `0x3d1fc` — через `0x31b00` (adjust `-8`). Последний путь не является
@@ -1477,6 +1495,77 @@ descriptor word `8`. Текущий tag `26` тем же общим reader-ом
умножает на `M`. Это правило не меняет отдельные callbacks бюджета или запись
factory-26 selector `0x500`.
+Сырой selector `6` в `FUN_1002bb40` выбирает устройство по ordinal через
+интерфейс `owner+0x0c`: таблица `this+0x5b0` соответствует `owner+0x5bc`.
+RVA `0x2bb91` проверяет тег текущего descriptor на равенство `2`. При совпадении
+RVA `0x2bb9a` загружает `device+0x174` как `f32`, сохраняет значение в выходной
+буфер и возвращает `AL=1`/`RET 8`; другие текущие теги возвращают false.
+Наличие поля `+0x174` подтверждено для экземпляра фабрики `2`. INTO сохраняет
+исходный тип экземпляра, поэтому проверка тега descriptor отдельно не доказывает
+наличие этого поля у другой фабрики. Rust selector `6` сначала проверяет
+текущий descriptor tag: тег не `2` даёт `Ok(None)`; затем требуется известная
+фабрика `2` и конечное нормальное число либо ноль любого знака в `+0x174`. В
+`Control.dll` (SHA-256
+`bcb86318089028548a178b03a21accdce15df0cc85ddd91674cf3c2f55012c6e`) поле
+получает ноль в конструкторе по RVA `0x294c0`; чтение, сравнение пары строк и
+пересчёт находятся по RVA `0x2bb40`, `0x29940` и `0x296f0`.
+
+Typed record хранит две ASCII C-строки в words `[27..35)` и `[35..43)`. Строка
+заканчивается на первом NUL: байты за ним игнорируются, а регистр при сравнении
+не учитывается. Если новая, изменённая пара содержит пустую строку, native
+recalc завершается до `CreateObject` и selector `35`, поэтому сохраняются
+прежние биты. Пустая пара конструктора уже совпадает с текущей и вообще не
+запускает recalc. Иначе append и первая активная запись `INTO` применяют
+результат в исходном порядке. Для нераспознанной формы поле остаётся
+недоступным; ошибка разбора распознанного, но повреждённого ресурса прерывает
+новую загрузку до публикации.
+
+В общем случае native selector 35 не равен сумме сырых Max:
+`Control.dll` getter `0x0dc40` (selector 3) читает Max по `descriptor+4`, где
+указатель descriptor лежит в начале runtime provider row, затем умножает его
+на масштабы владельца `+0x660` и `+0x548`. Функция `0x13620` складывает выходы
+в порядке строк с округлением `f32`; при `row+0x24 != 0xffffffff` добавляется
+индексированный вклад. Конструктор `0xb240` задаёт runtime `row+0x24`
+служебное значение `0xffffffff`. Только в свежей форме поддержанного BULL оба
+масштаба равны `1`, а все `row+0x24` равны
+`0xffffffff`, поэтому формула сводится к NDP Max сумме.
+
+Пересчёт создаёт временный объект запросом `9` через `World3D.dll+0x7cb0`.
+Загрузчик `Control.dll+0x32280` формирует для его корня входной контекст с
+полем `+0xc8 = 0xffffffff`. Для разрешённых opcode `1` и `12`, а
+также `4` только после FXID/CPT-проверки, подтверждённые callbacks сохраняют
+входы суммы: `Control.dll` RVA `0x43d0` меняет только локальные слова; в
+`AniMesh.dll` (`65659bf67f20e5be77d67a5b2f59968f61b94293143807fa59ca451c560c4f7e`)
+RVA `0x5500/0x93c0` меняют узлы и список модели, а `0x5320` не пишет её
+масштабы. Это статическая граница свежего пути, не снимок живого native World
+после всех creation callbacks.
+
+Проверка opcode `4` читает только выбранные строки и принимает FXID-типы
+`2/3/4/5/7/8/9` с распознанными ASCII-ссылками и CPT offsets внутри компонента;
+типы `1/6/10`, отсутствующие ресурсы и непроверенные offsets оставляют поле
+недоступным. В `Effect.dll` (SHA-256
+`386a3e8db1ce23f61957825d633c7dae1ed40c25cab0cf10a534385fd7cee789`) проверены
+инициализаторы типов `2/3/4/5/7/8/9` по RVA `0x12d10/0x103b0/0x108c0/0x28a0/
+0x1720/0x11230`; тип `9` разделяет путь типа `3`.
+
+`AssetManager::initial_control_effect_opcodes` собирает исходный порядок кодов
+выбранной начальной группы до фильтра opcode `4`. `Some([])` означает, что
+по структуре данных команд нет: группа отсутствует, пуста или её беззнаковый
+индекс не меньше числа групп. Условия отдельных строк этот читатель не
+вычисляет. `None` означает неподдержанный либо
+неполный формат, а повреждённая структура возвращает ошибку. Такая разница не
+позволяет принять неизвестный разбор за пустую сумму.
+
+Ресурсные callbacks в этой цепочке привязаны также к следующим образам.
+Записи палитры и звуковые либо графические буферы имеют отдельное хранение;
+проверенные начальные вызовы не меняют входы суммы NDP.
+
+| Модуль | SHA-256 | Существенные RVA |
+|---|---|---|
+| `World3D.dll` | `17e4a3089b2583a8cf2356c9db0390b1aba138356a09130d79b4e7e4791da61e` | `0x7cb0` — создание; `0x4b10/0x4cb0` — текстуры и lightmap |
+| `Ngi32.dll` | `bab9840d94f4e4e74ffc26677724fa896cf4823845504d09a9e025f80016edf5` | `0x11f80` — чтение ресурса; `0x11410` — счётчик палитры; `0xd620/0xe900` — звуковые буферы |
+| `Terrain.dll` | `af87d1b2e728a0be73c52be3b44cc196ab46da7799f25a15d40f8c9b0b425ead` | `0x166a0/0x17ac0` — получение указателя на числовое поле World |
+
FCA0 передаёт в owner query порядковый номер `i`; query `0x2bb40` находит
устройство `i` и вызывает его reader. Уже reader `FUN_10021d00` получает provider
key из поля устройства `+0x04`. Provider getter `FUN_1000dc40` (RVA `0x0dc40`)