aboutsummaryrefslogtreecommitdiff
path: root/docs/appendices/knowledge-boundaries.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/appendices/knowledge-boundaries.md')
-rw-r--r--docs/appendices/knowledge-boundaries.md191
1 files changed, 144 insertions, 47 deletions
diff --git a/docs/appendices/knowledge-boundaries.md b/docs/appendices/knowledge-boundaries.md
index ab6c1f8..a60fa68 100644
--- a/docs/appendices/knowledge-boundaries.md
+++ b/docs/appendices/knowledge-boundaries.md
@@ -10,6 +10,11 @@ authoring API без динамического подтверждения.
Не доказаны символами точные имена renderer vtable slots, полный набор CShade
state transitions и окончательный порядок части transparent/FX/shadow subpasses.
+Дистанционная кривая тумана по квадратам границ подтверждена в живом CShade.
+Обычный GPU fog color из горизонта подтверждён исполнением; выбор проходов по
+native shade-state и их временные изменения цвета пока заменены общим туманом мира;
+это приближение считается как `render_coverage fog_pass_eligibility_approx`.
+
После ограничения цели рельефом интерактивная камера проверяет движение
против каждого отрисовываемого корневого строения класса `FORT` и его
отрисовываемых компонентов. Для этого пути используются текущая Node38-поза
@@ -45,33 +50,50 @@ 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 ещё не декодированы и считаются в `msh_type16_colors_unsupported`;
+в статических сценах 29 миссий GOG (1736 загрузок моделей) этот поток отсутствует.
+Его декодирование отложено до первого реального ненулевого счётчика.
+Внутренний ракурс «Конструктора» после
+настоящего входа игрока подтверждает исчезновение чёрной поверхности в проходе;
+наружные окна обеих миссий сверены на расстояниях около 60/85/110, а ближние
+окна — с внутренней стороны. Окно «Конструктора» на правом краю кадра при
+дистанции около 85 совпадает; внутренние дальние ракурсы и остальные случаи
+отсечения ещё не приняты. Общей готовности R2 эти пары не доказывают.
+
+Старые захваты без `geometry_projection` используют состояние камеры после
+обхода мира, которое может отсекать близкие поверхности. Это отмечается
+`captured_projection_unverified`; для приёмки таких поверхностей нужен новый захват.
+
+Захваты без `sky_uv_clock` не подтверждают начальное положение облаков,
+звёзд и фона. Replay использует elapsed clock приложения и считает
+это как `captured_sky_phase_unverified`; для приёмки неба нужен новый захват.
Закрывающий эксперимент: запустить оригинал в совместимой Windows/DirectX
среде, перехватить DirectDraw/Direct3D calls и surface flips, сохранить state
log на минимальных сценах с одним типом материала.
+Горизонтальные грани Land.msh с флагом `0x20000` используют исходную карту Du/Dv, окно shifted-камеры и квадратный размер текстуры, проверенные исполнением DLL. Диапазон глубины, небо/туман/FX основного вида и соответствие размеров при обрезанном capture остаются приближениями: `planar_reflection_render_context_approx`; неперспективная камера API использует обычное зеркало.
+Raw queue clock задаёт фазу волн отдельно от времени суток и sky elapsed; старые захваты без него считаются в `captured_water_phase_unverified`.
+Один target отражает ближайшую активную высоту воды; остальные высоты и неплоские грани считаются в `planar_reflection_other_planes_unsupported` и `planar_reflection_nonplanar_unsupported` и сохраняют обычный terrain shader.
+`terrain_face8_pipeline_unverified` теперь считает только исходные грани с `0x8` без `0x20000`; сама семантика оставшихся специальных проходов ещё не установлена.
+
## FXID field-level semantics
+Control Op1 пока использует цвет и радиус без случайных добавок команды;
+это явное приближение считается в `render_coverage control_op1_jitter_unsupported`.
+Масштаб радиуса длиной преобразованного направления и нижняя замена 0,01 восстановлены.
+
+Control Op2 воспроизводит modes 0/2; modes 1/3, body+76 и неподдержанные
+time modes/привязки считаются как `render_coverage control_op2_unsupported`.
+Управление фазой экземпляра командами Control остаётся до его подключения в runtime.
+При расширении выбранных начальных строк все пропущенные команды считаются
+в `control_fx_unsupported`, а time modes 4–17 — в `control_fx_requires_game_state`;
+причина и владелец выводятся в лог. Неразобранные FXID считаются отдельно в `control_fx_invalid_documents`.
+
Размеры команд, resource references, lifecycle, flags families и используемые
time modes известны. Не закрыто значение каждого поля body opcodes 1--10,
отсутствующий во всех проверенных каталогах opcode 6 и точные формулы редких
@@ -133,7 +155,7 @@ control word процесса.
Лицензированный AutoDemo по-прежнему загружается с raw TMA anchor-ами
`[(500.2857, 751.8217), (728.0, 449.0)]` и записями `[(500, 752, 0),
(728, 449, 1)]`. Rust теперь также читает optional `.fml` sibling для каждого
-script base и поддерживает numeric literal assignments в первом `Init`.
+script base и поддерживает узкий набор атомарных формул в первом `Init`.
Отсутствующий `.fml` не мешает пакету с одними `Handler(19)`; другие ошибки
чтения распространяются как VFS errors.
@@ -144,9 +166,11 @@ script base и поддерживает numeric literal assignments в первÐ
два доказанных действия: `Handler(19)` и formula assignment selector `-1` при
source `-1`, нулевой глубине условий и корректных индексах. У `Handler(19)`
control находится в `header_words[3]`, а `header_words[1]` — result-save
-reference; оба равны `0xffffffff` в поддержанной форме. У formula assignment
-`header_words[1]` — индекс целевой varset ячейки, `header_words[2]` — source,
-а индекс formula row занимает `header_words[6]`. Маппинг подтверждён
+reference; оба равны `0xffffffff` в поддержанной форме. В дисковом заголовке
+formula assignment `header_words[1]` — индекс целевой varset ячейки,
+`header_words[2]` — source, а индекс formula row занимает `header_words[6]`;
+индексы цели и формулы в native record находятся по смещениям `+0x08` и `+0x1c`
+соответственно. Маппинг подтверждён
`ai.dll!FUN_10011b20` (RVA `0x11b20`) и исполнителем `FUN_10012020` (RVA
`0x12020`), SHA-256 `c19cd6cd31cd2896f8c4ba0f0e700dd3408aec8182daaf4863d98a7d233a2abc`.
`Handler(19)` (`FUN_1000aa38`, RVA `0xaa38`) использует references `0..2`;
@@ -154,23 +178,58 @@ reference; оба равны `0xffffffff` в поддержанной форме
Formula table загружается из `<bundle-base>.fml`; native `FUN_100123b0`
(RVA `0x123b0`) проверяет ordinal, compiler `FUN_100152a0` (RVA `0x152a0`)
-строит numeric literal node, а evaluator `FUN_10015b30` (RVA `0x15b30`)
-возвращает его raw `f32`. Target type `3` сохраняет эти bits; type `5` проходит
-через `FUN_10012c00` (RVA `0x12c00`) и `__ftol` (RVA `0x1df70`) к raw DWORD
-с усечением к нулю. Изолированный x86 oracle на оригинальном `ai.dll` и
-настоящих ресурсах подтвердил таблицы `tut1_pl2`/`scr_pl_1`/`scream` с
+строит числовые, переменные и операторные узлы, а evaluator `FUN_10015b30`
+(RVA `0x15b30`) в проверенных путях `+` и `-` считывает значения переменных и
+сохраняет результаты как `f32` при x87 control word `0x007f`. В GOG-сборке
+`ai.dll` с SHA-256
+`c19cd6cd31cd2896f8c4ba0f0e700dd3408aec8182daaf4863d98a7d233a2abc` поиск
+переменной через varset vtable slot `+0x10` ведёт на RVA `0x16ad0`: сравнение
+байтов точное, регистр учитывается, при повторах берётся первое объявление.
+Getter `FUN_10013190` (RVA `0x13190`) читает type `3` как `f32`, type `5` как
+беззнаковый `DWORD` и возвращает число через x87. Затем evaluator сохраняет
+его как `f32` до операции. Оператор `+`
+считает right+left, `-` — left-right; результат также сохраняется как `f32`.
+Target type `3` сохраняет эти bits; type `5` проходит через `FUN_10012c00`
+(RVA `0x12c00`) и `__ftol` (RVA `0x1df70`) к raw DWORD с усечением к нулю.
+Изолированный x86 oracle на оригинальном `ai.dll` и настоящих ресурсах
+подтвердил таблицы `tut1_pl2`/`scr_pl_1`/`scream` с
26/5/149 строками и 15 присваиваний: кампанийные `df0..df3` и `Single.01`
`dT8/dT9` получают `0`; `scream` задаёт `fDifficulty = 0.8f` и остальные
проверенные DWORD `0, 0, 1, 10, 0, 100, 400, 2`.
-Граница Rust остаётся узкой: ссылка должна вести на один digit-starting numeric
-token и типизированную `float`/`DWORD` ячейку. Неизвестные expression nodes,
-переменные, unary operators, составные выражения и source-copy ветвь
-`source != 0xffffffff` остаются явными ошибками; native source-copy переносит
-всю varset record, не только числовое значение. В preview package сохраняется,
-но `Unsupported` не применяет частичные writes; полная загрузка отклоняет весь
-новый мир и сохраняет предыдущие world/RNG. Это политика Rust, не правило
-оригинального dispatcher-а.
+Граница Rust остаётся узкой: один числовой токен либо ASCII-имя переменной,
+или два таких атома с одним бинарным `+`/`-`. Имя проверяется раньше числового
+преобразования, сравнивается с учётом регистра и выбирает первое совпадение;
+публичный `FormulaTable::evaluate_numeric_literal` принимает только числовые
+литералы. Временная копия значений начинается со значений по умолчанию и
+обновляется после каждого успешного действия `Init`, поэтому следующая формула
+видит предыдущие записи. Нет
+поддержки неизвестных операторов, унарных форм, третьего атома, отсутствующих
+или не-ASCII имён и source-copy ветви `source != 0xffffffff`; native source-copy
+переносит всю запись varset. Preview сохраняет package, но не применяет частичные
+writes; полный load отклоняет новый мир и сохраняет прежние world/RNG. Это
+политика ограниченного Rust resolver-а, а не правило оригинального dispatcher-а.
+
+Ресурсные строки с переменными найдены в поздних событиях: `c1m3e.fml` row 19
+(`0.8 + fT`) вызывается из `Fort_Captured`, row 22
+(`dBuildingProtectHits - dT2`) — из `PBM_BUILDING_PROTECT_Start`, а `c1m4e.fml`
+row 0 (`fTemp + 0.00001`) — из `PBM_BUILDING_INF_CAPTURE_Start`. Декодирование
+этих `.scr` не показывает эти формулы в первом `Init`. Игнорируемая проверка
+читает настоящие `.fml` и `varset.var`, но вставляет строки в синтетический
+`Init`; она проверяет resolver, а не оригинальное исполнение. Одноразовый x86
+oracle на исходной GOG `ai.dll` с SHA-256
+`c19cd6cd31cd2896f8c4ba0f0e700dd3408aec8182daaf4863d98a7d233a2abc` проверил
+13 отдельных присваиваний: 9 контролируемых выражений и 4 вызова с настоящими
+строками `.fml` (`c1m3e` rows 19/22, `c1m4e` row 0 дважды подряд). В каждом векторе
+native harness записывал вычисленный `f32`, типизированное raw-слово и getter;
+scratch-проход через публичный Rust parser/resolver совпал со всеми 13
+векторами по `f32`-результату и raw-записи. Для native вызовов control word
+временно принудительно устанавливался в `0x007f`: 87 наблюдений сохранили
+`0x027f` на входе и после восстановления,
+а canary-проверки прошли. Менялись только varset-копии в памяти. Это
+подтверждает компиляцию формулы, локальное вычисление и typed writes для этих
+входов, но не запуск исходного поиска и обхода события `Init`, исполнение поздних
+событий или поведение живой миссии.
Лицензированный test загружает одну первую кампанийную миссию
`CAMPAIGN/CAMPAIGN.00/Mission.01/data.tma` после literal writes; это не проход
@@ -499,6 +558,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` в текущее и
@@ -741,16 +835,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` не имеет доказанных единиц