fix(runtime): follow linked nodes after building helper hits
Docs Deploy / Build and Deploy MkDocs (push) Successful in 1m16s
Docs Deploy / Build and Deploy MkDocs (push) Successful in 1m16s
This commit is contained in:
6 files changed
+693
-46
No files matched your search
@@ -16,15 +16,21 @@ state transitions и окончательный порядок части transp
|
||||
|
||||
Локальный MSH-запрос `query_slot_segment` сверён с оригиналом на фабричной
|
||||
стене и дверном проёме. Runtime-адаптер `query_building_segment_world` теперь
|
||||
переводит отрезок через переданные преобразования выбранных MSH-узлов, выбирает
|
||||
ближайшее мировое попадание и повторяет запрос для helper batch bit `0x0008`.
|
||||
Его синтетические тесты покрывают поворот, масштаб, отражение, helper-повтор и
|
||||
ограничение в 200 пересечений; они не доказывают паритет с полным мировым
|
||||
запросом оригинала.
|
||||
повторяет helper batch bit `0x0008` через связанный узел, указанный raw-словом
|
||||
`Batch20 +0x06`. При повторе он обходит Node38-поддерево: сначала допустимых
|
||||
потомков, затем сам узел. Флаги ветвления сверены с оригиналом. Синтетические
|
||||
тесты покрывают связи, отсутствие геометрии у промежуточного узла, маски,
|
||||
равные попадания и предел в 200 пересечений.
|
||||
|
||||
Открыты выбор нативной категории и состава узлов/слотов, получение актуальных
|
||||
поз и component bindings из runtime-объектов, подключение адаптера к свободной
|
||||
камере и сравнение мирового результата с оригиналом
|
||||
Игнорируемый тест на AutoDemo загружает настоящий объект PLANT 4 и подтверждает,
|
||||
что сегмент пересекает геометрию Node3 в исходной закрытой позе, но не
|
||||
пересекает её в открытой позе Node3 на frame `1`. В загруженных
|
||||
Control-привязках корня PLANT нет tag-21 записи для этого перехода. Тест задаёт
|
||||
frame `1` напрямую и не исполняет команду открытия из миссии.
|
||||
|
||||
Открыты выбор первого корня и состава узлов/слотов нативного мирового запроса,
|
||||
полный обход текущих runtime-поз и component bindings, подключение адаптера к
|
||||
свободной камере и сравнение итогового результата мирового запроса с оригиналом
|
||||
([MSH](../reference/msh.md)).
|
||||
|
||||
Для MSH без потока цветов type 16 подтверждён только один постоянный alpha
|
||||
|
||||
+37
-19
@@ -153,7 +153,10 @@ struct Batch20 {
|
||||
```
|
||||
|
||||
Byte `material_index` выбирает строку WEAR; high word at `+0x02` сохраняется
|
||||
отдельно для native overrides. Loader проверяет, что
|
||||
отдельно для native overrides. Слово `local_batch_index` остаётся raw-полем
|
||||
`+0x06`: в пути CBuilding helper retry оно вместе с базой модели задаёт
|
||||
связанный корень Node38, а у отдельной `ModelAsset` база равна нулю. Вне этого
|
||||
пути слово сохраняется без вывода о его значении. Loader проверяет, что
|
||||
`index_start + index_count` остаётся внутри type 6, а каждый использованный
|
||||
индекс через `base_vertex` попадает в position stream. `vertex_count` и
|
||||
`local_batch_index` доступны renderer для исходного draw contract.
|
||||
@@ -200,11 +203,10 @@ Rust использует обычное деление `f32`, поэтому п
|
||||
### Мировой отрезок по выбранным узлам
|
||||
|
||||
Локальный запрос выше проверяет один узел и slot модели. Runtime-функция
|
||||
`query_building_segment_world` принимает мировой отрезок и список выбранных
|
||||
узлов со slot-ами и их преобразованиями `world_from_node`. Для каждого узла она
|
||||
переводит оба конца отрезка обратной матрицей, вызывает `query_slot_segment`, а
|
||||
найденную точку переносит назад в мир. Затем она выбирает ближайшее попадание
|
||||
среди переданных узлов.
|
||||
`query_building_segment_world` принимает мировой отрезок и исходный список
|
||||
выбранных узлов со slot-ами и их преобразованиями `world_from_node`. Первый
|
||||
проход сохраняет порядок этого списка, переводит концы отрезка обратной
|
||||
матрицей и выбирает ближайшее попадание в мире.
|
||||
|
||||
```text
|
||||
segment_node = inverse(world_from_node) * segment_world
|
||||
@@ -213,20 +215,36 @@ distance² = dot(hit_world - original_start, hit_world - original_start)
|
||||
```
|
||||
|
||||
`original_start` остаётся началом первоначального мирового отрезка, даже когда
|
||||
запрос перезапускается. Нативный CBuilding query сохраняет raw
|
||||
`Batch20.batch_flags & 0x0008`: если ближайшее попадание помечено этим bit,
|
||||
следующий проход начинается в его мировой точке и идёт к исходному концу.
|
||||
Первичный запрос исключает из batch только `0x0200`, а тип-7 треугольники —
|
||||
`0x0024`. Счётчик ограничивает число всех пересечений: при посещении 200
|
||||
запрос завершается ошибкой до проверки bit `0x0008`.
|
||||
запрос перезапускается. Если ближайший batch имеет bit `0x0008`, его ключ
|
||||
`local_batch_index` выбирает новый корень Node38, а отрезок начинается в
|
||||
мировой точке helper-попадания и идёт к исходному концу. Runtime обходит
|
||||
метаданные этого поддерева даже у узлов без переданной геометрии; сами slot-
|
||||
запросы выполняются только для узлов, присутствующих во входном списке. Обход
|
||||
проверяет сначала допустимых потомков, затем сам узел. Header bit `0x0010`
|
||||
прекращает обход его потомков; bit `0x0004` у дочернего узла исключает всю эту ветвь, но bit
|
||||
`0x0004` у текущего корня не мешает запросу его собственной геометрии. Слово
|
||||
родителя `0xFFFF` не связывает узел с дочерним корнем, а helper-ключ `0xFFFF`
|
||||
считается ошибкой данных.
|
||||
|
||||
Эта схема восстановлена по GOG `Terrain.dll` SHA-256
|
||||
`af87d1b2e728a0be73c52be3b44cc196ab46da7799f25a15d40f8c9b0b425ead`:
|
||||
мировой обход проходит через `FUN_10016a20` (RVA `0x16A20`), CBuilding выполняет
|
||||
запрос и helper-перезапуски в `FUN_10035430` (RVA `0x35430`), а guard находится
|
||||
в участке `0x358FC..0x35926`. Runtime-модуль проверен на синтетических
|
||||
переносах, поворотах, масштабах и отражениях; подключение к текущим позам
|
||||
объектов и камере приложения пока не выполнено.
|
||||
В каждом проходе batch `0x0200` и type-7 triangle flags `0x0024` исключаются.
|
||||
Ближайшее попадание и разрешение равных расстояний сохраняют правила локального
|
||||
запроса; расстояние измеряется от первоначального начала. Счётчик ограничивает
|
||||
все пересечения: при посещении 200 запрос завершается ошибкой до проверки bit
|
||||
`0x0008`.
|
||||
|
||||
Эта схема сверена с GOG `Terrain.dll` SHA-256
|
||||
`af87d1b2e728a0be73c52be3b44cc196ab46da7799f25a15d40f8c9b0b425ead` (RVA
|
||||
`0x35430`, `0x35961`) и `AniMesh.dll` SHA-256
|
||||
`65659bf67f20e5be77d67a5b2f59968f61b94293143807fa59ca451c560c4f7e` (RVA
|
||||
`0x134D0`, `0x10A50`). Игнорируемый тест загружает настоящий объект PLANT 4
|
||||
миссии AutoDemo и проверяет, что сегмент пересекает геометрию Node3 в исходной
|
||||
закрытой позе, но проходит без попадания при явно заданной открытой позе frame
|
||||
`1`. Это проверка запроса для двух поз, а не открытие двери игровой командой.
|
||||
В загруженных Control-привязках корня PLANT нет tag-21 записи для перехода
|
||||
Node3; тест задаёт frame `1` напрямую и не исполняет команду открытия из
|
||||
миссии.
|
||||
Нативный выбор первого корня и полный мировой обход ещё не сопоставлены с Rust;
|
||||
app пока не передаёт этой функции живые runtime-позы и bindings.
|
||||
|
||||
## Сторона грани в цветовом проходе
|
||||
|
||||
|
||||
Reference in new issue
Block a user