feat(runtime): project initial Behavior control groups
Docs Deploy / Build and Deploy MkDocs (push) Successful in 37s
Docs Deploy / Build and Deploy MkDocs (push) Successful in 37s
This commit is contained in:
4 files changed
+328
No files matched your search
@@ -262,6 +262,26 @@ Behavior (`Behavior.dll`, RVA `0x3600`) вызывает `World3D!stdGetGameMode
|
||||
с реальными интерфейсами ArealMap, нужными `FUN_10019e80`; полный Behavior tick
|
||||
flow и общий dispatcher событий также остаются открытыми.
|
||||
|
||||
`loaded_mission_behavior_control_groupings` публикует только начальную
|
||||
группировку подготовленной Control-таблицы. Ветка с меткой `2` исходного
|
||||
`Behavior.dll!FUN_1001be10` (RVA `0x1be10`) дополнительно вызывает
|
||||
`FUN_1001b4b0` и обращается к свойствам через QI `0x204`, включая запросы с
|
||||
номерами `0x700`, `6` и `0x400`. Результат `0x700` попадает в строку кандидата
|
||||
по смещению `+0x3c`, результат `6` — в `+0x40`, а `0x400` может обнулить второе
|
||||
поле. Их доменный смысл, множитель `0x700`, агрегаты Behavior QI `0x204` и
|
||||
прочие числовые поля кандидата не восстановлены. Rust не подставляет множитель
|
||||
`0x700`, нулевые агрегаты, выбранный индекс или эффект. Список для метки `30` не
|
||||
встречается в ресурсах AutoDemo и проверяется только на искусственном наборе.
|
||||
|
||||
Игнорируемая проверка AutoDemo сравнивает порядковые номера записей начальной
|
||||
группировки, отдельно выведенные по снимку текущих меток дескрипторов, с
|
||||
состоянием Rust после полной загрузки. Это подтверждает согласованность разбора
|
||||
подготовленной таблицы и правила группировки на этих ресурсах, но не является
|
||||
захватом состояния Behavior оригинала и не устанавливает, когда список
|
||||
прикрепляется или обновляется в живом объекте. Полный штатный путь загрузки и
|
||||
запуска, агрегаты Behavior QI `0x204`, обновление после изменений Control,
|
||||
`Handler(43)` и полный игровой цикл остаются отдельными границами.
|
||||
|
||||
Начальные свойства `CurrentOre`/`MaximumOre` восстановлены отдельно от
|
||||
регулярного обмена. В проверенных `Behavior.dll` (SHA-256
|
||||
`ddfbdbde07832358fe6e35e01c8dba9b58e7313789498b6049ed51d4ed9baf99`) RVA
|
||||
|
||||
@@ -763,6 +763,49 @@ tie-векторов подтверждает реакцию `FISTP`, но не
|
||||
одного numeric literal; остальные формы инструкции и содержимое `.scr`
|
||||
сохраняются reader-ом, но остаются вне этого исполнения.
|
||||
|
||||
### Начальная группировка подготовленных Control-дескрипторов
|
||||
|
||||
В проверенной GOG `Behavior.dll` (SHA-256
|
||||
`ddfbdbde07832358fe6e35e01c8dba9b58e7313789498b6049ed51d4ed9baf99`)
|
||||
`FUN_1001be10` (RVA `0x1be10`) получает список через QI с кодом `0x202` от
|
||||
`owner+0x5c`. Слоты `+0x50` и `+0x1c` этого интерфейса возвращают число строк и
|
||||
код-различитель для строки; цикл обрабатывает порядковые номера строк
|
||||
`0..count-1` по возрастанию. Метки `1`, `2` и `30` начинают группу, добавляют
|
||||
кандидата и добавляют отдельный элемент к последней группе соответственно.
|
||||
Запись с меткой `2` до первого заголовка попадает в отдельный вектор; метка `30`
|
||||
без группы игнорируется, как и все остальные метки.
|
||||
|
||||
Для источника списка проверена пара GOG DLL. В `Control.dll` SHA-256
|
||||
`bcb86318089028548a178b03a21accdce15df0cc85ddd91674cf3c2f55012c6e` запрос с
|
||||
кодом `0x202` отдаёт интерфейс `owner+8`; его методы-обёртки переходят к методам
|
||||
чтения канонического QI `0x204`, receiver которого равен `owner+0x0c`. Метод
|
||||
`Control.dll` RVA `0x8830` читает число из `[receiver+0x5b4]`, то есть
|
||||
`[owner+0x5c0]`; таблица указателей находится в `[receiver+0x5b0]`, то есть
|
||||
`[owner+0x5bc]`. Поле `[owner+0x5b4]` — отдельный указатель кэша, а не число
|
||||
строк. Метод чтения `Control.dll` RVA `0x2c390` выбирает указатель `table[index]`,
|
||||
разыменовывает указатель на дескриптор из записи `+0x48` и возвращает DWORD по
|
||||
адресу этого дескриптора. Загрузчик `FUN_10021d50` (RVA `0x21d50`) сохраняет там
|
||||
указатель текущего дескриптора, поэтому код-различитель — его текущая метка, а
|
||||
не неизменная метка фабрики.
|
||||
|
||||
В оригинальном Behavior внешняя строка имеет шаг `0x34`; её `+4` получает
|
||||
порядковый номер заголовка. Строка-кандидат имеет шаг `0x58`, а её `+8` хранит
|
||||
порядковый номер кандидата. Номера строк с меткой `30` добавляются в отдельный
|
||||
вектор последней внешней строки. Rust публикует только эти начальные номера:
|
||||
`MissionBehaviorControlGroup` и
|
||||
`MissionBehaviorControlGrouping` группируют строки из уже подготовленной
|
||||
Control-таблицы в её исходном порядке. `MissionBehaviorControlGroupingState`
|
||||
сохраняет `original_id`, `ObjectHandle` и либо результат, либо исходную причину
|
||||
недоступности Control-таблицы. Полная загрузка создаёт проекцию перед публикацией
|
||||
`LoadedMissionState`; предварительный просмотр возвращает пустой список. Проверки
|
||||
`behavior_control_grouping_uses_current_tags_and_table_ordinals` и игнорируемый
|
||||
`full_load_builds_initial_behavior_control_groupings_for_autodemo` покрывают
|
||||
искусственные граничные случаи и сохранённые номера строк AutoDemo соответственно.
|
||||
|
||||
Это начальное разложение подготовленного списка, а не реконструкция полной
|
||||
инициализации Behavior: отдельные свойства строки-кандидата, её числовые поля,
|
||||
эффекты и обновление списка после изменений Control здесь не моделируются.
|
||||
|
||||
### Изменение provider-состояния Control
|
||||
|
||||
Для `Control.dll` (SHA-256
|
||||
|
||||
@@ -260,6 +260,25 @@ Rust-тест повторно читает лицензированную ми
|
||||
TMA-записями и проверяет реальные `ObjectHandle`, но помечен `#[ignore]`, чтобы
|
||||
не требовать оригинальных ресурсов от остальных разработчиков.
|
||||
|
||||
После подготовки Control-таблицы можно разобрать и её начальную группировку для
|
||||
Behavior. Важны текущая метка записи и её порядковый номер в общей таблице:
|
||||
метка `1` начинает пустую группу, метка `2` становится кандидатом последней
|
||||
группы, а метка `30` записывает строку в отдельный список той же группы.
|
||||
Кандидат, встретившийся до первого заголовка, остаётся в списке без группы;
|
||||
ранняя метка `30` игнорируется. Например,
|
||||
для текущих меток `[2, 30, 1, 30, 2]` получаются незагруппированный кандидат
|
||||
`[0]` и группа с заголовком `2`, кандидатом `[4]` и строкой с меткой `30` под
|
||||
порядковым номером `[3]`. Все номера начинаются с нуля и отсчитываются по общей
|
||||
Control-таблице, а не по ключам устройств или записям CTLD.
|
||||
|
||||
Полная загрузка Rust сохраняет это начальное состояние рядом с подготовленными
|
||||
Control-таблицами по исходному TMA ID и `ObjectHandle`. Если таблица недоступна,
|
||||
проекция сохраняет причину ошибки; доступная пустая таблица означает пустую
|
||||
группировку. При предварительном просмотре список группировок не создаётся. Здесь
|
||||
разбирается только подготовленный порядок текущих Control-дескрипторов. Проекция
|
||||
не устанавливает, когда список присоединяется к живому Behavior, как он затем
|
||||
обновляется и как работает полный игровой цикл.
|
||||
|
||||
Список распределителя хранит не только участников, но и долю каждого. При
|
||||
добавлении двух объектов оба получают по половине общего веса. Если добавить
|
||||
третий, движок оставляет долю новой записи около одной трети, а оставшийся вес
|
||||
|
||||
Reference in new issue
Block a user