feat(runtime): initialize per-clan AI record slots
Docs Deploy / Build and Deploy MkDocs (push) Successful in 1m17s
Docs Deploy / Build and Deploy MkDocs (push) Successful in 1m17s
This commit is contained in:
3 files changed
+489
-1
No files matched your search
@@ -184,6 +184,34 @@ core и `ResearchCandidateSet::refresh_selection`: последний получ
|
||||
создаёт владельца живого контекста, не передаёт реальные AI candidates и не
|
||||
выбирает результат Handler(43). Это не общий dispatcher и не загрузка игры.
|
||||
|
||||
Начальный массив слота AI `+0x38` теперь восстановлен отдельно от этого
|
||||
исследовательского пути. В `iron3d.dll` SHA-256
|
||||
`d1dc4ea8535e2069b0a05c9e8be2724dd438ba44cca7a83007d8b2e50f9e35fa`
|
||||
`FUN_100392e0` (RVA `0x392e0`) вызывает слот для каждого значения счётчика
|
||||
`second_resource.tag`. В `ai.dll` SHA-256
|
||||
`c19cd6cd31cd2896f8c4ba0f0e700dd3408aec8182daaf4863d98a7d233a2abc` метод
|
||||
RVA `0x2010` передаёт `AI+0x83c` в `FUN_10002980` (RVA `0x2980`), где
|
||||
`FUN_100048f0` (RVA `0x48f0`) добавляет переданный DWORD. Вызывающая сторона
|
||||
повторно передаёт `0xffffffff`; эта функция не записывает значение обратно.
|
||||
Поэтому подтверждён только начальный массив sentinel-слов. Неизвестно, какие
|
||||
поздние обработчики читают эти ячейки и заменяет ли кто-либо их ID. В начальном
|
||||
массиве нет назначенных ID объектов; дальнейший смысл этих слов пока не
|
||||
установлен. Сам массив не является списком
|
||||
`BehaviorDistributorState.registered_objects` и не определяет владельца
|
||||
контекста исследований.
|
||||
|
||||
Rust хранит этот снимок как `MissionAiStartupState` в состоянии загруженной
|
||||
миссии. Полная загрузка проходит по всем TMA-кланам, включая кланы без пакета
|
||||
сценария и без пути таблицы исследований; при предпросмотре список состояний AI
|
||||
остаётся пустым. Знаковое поле `second_resource.tag` читается по сырым битам как
|
||||
`u32`. Бюджет в 1 000 000 DWORD на миссию и выделение памяти с обработкой ошибки
|
||||
защищают только память Rust; это ограничение не приписывается оригинальному
|
||||
движку. Искусственные Rust-тесты проверяют обе формы TMA-клана, индекс клана,
|
||||
независимые массивы, пустой путь сценария, предпросмотр, чтение тега как
|
||||
беззнакового числа, лимит и откат при ошибке. Проверка на оригинальных ресурсах
|
||||
для `Single.01` подтверждает состояния обоих кланов (`9/9`) до выполнения
|
||||
`Init`; это не полный запуск миссии и не исполнение исходных DLL.
|
||||
|
||||
Для GOG-сборки также найден статический host call path в `Init`. В
|
||||
`iron3d.dll!FUN_1005ff40` (RVA `0x5ff40`) одна ветвь сначала проходит записи
|
||||
кланов и вызывает для них `FUN_100392e0`, затем вызывает `FUN_10039440` (RVA
|
||||
|
||||
@@ -195,6 +195,39 @@ Rust исполняет подтверждённый поднабор перво
|
||||
|
||||
### Первый запуск сценария
|
||||
|
||||
Перед настройкой первого шага каждый AI получает начальный массив DWORD. В
|
||||
`iron3d.dll` SHA-256
|
||||
`d1dc4ea8535e2069b0a05c9e8be2724dd438ba44cca7a83007d8b2e50f9e35fa`
|
||||
`FUN_100392e0` (RVA `0x392e0`) повторяет вызов слота AI `+0x38` столько раз,
|
||||
сколько задаёт `second_resource.tag` этой строки TMA. Этот слот ведёт в
|
||||
`ai.dll` SHA-256
|
||||
`c19cd6cd31cd2896f8c4ba0f0e700dd3408aec8182daaf4863d98a7d233a2abc`:
|
||||
метод RVA `0x2010` передаёт коллекцию при `AI+0x83c` в `FUN_10002980`
|
||||
(RVA `0x2980`), а она добавляет один DWORD через `FUN_100048f0` (RVA
|
||||
`0x48f0`). Каждый вызов копирует `0xffffffff`; входное слово не меняется.
|
||||
Поэтому тег `3` даёт `[0xffffffff, 0xffffffff, 0xffffffff]`. Это число
|
||||
начальных ячеек, а не назначение трёх ID.
|
||||
|
||||
Изолированная x86-проверка вызовом оригинальной `ai.dll` подтвердила пары
|
||||
«число слотов/ёмкость» `0/0`, `1/17`, `17/17` и `18/34`. Все добавленные слова
|
||||
равны `0xffffffff`, а входное значение, контрольные поля, память вне заголовка
|
||||
массива и указатель стека сохраняются. Это подтверждает добавление начального
|
||||
слова, но не работу последующих обработчиков.
|
||||
|
||||
Rust хранит такой снимок в отдельном `MissionAiStartupState` для каждого TMA-клана,
|
||||
а не в пакете сценария. При полной загрузке (`Full`) создаётся запись для каждого
|
||||
клана, в том числе если у него нет пути сценария или пути таблицы исследований. Счётчик
|
||||
берётся из сырых битов `second_resource.tag` как `u32` у обеих форм записи —
|
||||
`Standard` и `Spatial`; нулевой счётчик даёт существующее состояние с пустым
|
||||
списком. Статический режим предпросмотра не создаёт состояний AI.
|
||||
|
||||
Загрузка отклоняет суммарный объём свыше 1 000 000 DWORD и резервирует память
|
||||
проверяемой операцией; это защита Rust от чрезмерного выделения памяти, а не
|
||||
ограничение оригинальной игры. Rust сохраняет начальные слова, но не
|
||||
восстанавливает работу последующих обработчиков и не назначает этим словам ID
|
||||
объектов. Этот массив также не является списком
|
||||
`BehaviorDistributorState.registered_objects`.
|
||||
|
||||
До регулярной работы Behavior настраивает расписание своего первого шага. Он
|
||||
берёт текущее 32-битное время игровой очереди и назначает проверку через три
|
||||
интервала по 64 мс, добавляя небольшую случайную задержку от 0 до 63 мс. Эта
|
||||
|
||||
Reference in new issue
Block a user