From caef8f8e6c0ae81b46fcab39cd4f2b74e1b29235 Mon Sep 17 00:00:00 2001 From: Valentin Popov Date: Tue, 20 Oct 2026 08:44:10 +0400 Subject: feat(runtime): register mission objects with clan distributors --- docs/tomes/04-world.md | 20 ++++++++++++++++ docs/tomes/06-behavior.md | 58 +++++++++++++++++++++++++++++++++++++---------- 2 files changed, 66 insertions(+), 12 deletions(-) (limited to 'docs/tomes') diff --git a/docs/tomes/04-world.md b/docs/tomes/04-world.md index dcd53b2..1123bc7 100644 --- a/docs/tomes/04-world.md +++ b/docs/tomes/04-world.md @@ -215,6 +215,26 @@ MissionObjectDraft { `fparkan-world` не подтверждено. Смещения, условия версий и контрольные суммы исследованных сборок приведены в [справочнике TMA](../reference/tma.md). +Это слово влияет не только на сценарий. Успешно загруженный пакет клана +публикует его `SuperAI` в таблице `GetSuperAI`; World3D передаёт первый DWORD +дескриптора создания через Behavior, где он выбирает тот же номер таблицы. +Поэтому при создании полного мира можно отнести объект к конкретному клановому +диспетчеру, если его номер лежит в диапазоне `0..63` и сценарий этого клана +загружен. Rust хранит такую связь отдельно от владельца объекта: + +```text +TMA raw_after_resource = 1 + -> GetSuperAI[1] доступен после загрузки script bundle клана 1 + -> запись объекта относится к distributor клана 1 +``` + +Для объектов с Unit DAT используется старший бит DWORD по смещению `+4` от +начала DAT как общий признак, по которому оригинальный World3D создаёт +registration key для Behavior. Это второе 32-битное слово заголовка. Из него +нельзя вывести сторону или тип владельца. В AutoDemo это связывает поля TMA, +class word из Unit DAT и выбранный клановый AI, не меняя `OwnerId` и хеш +игрового состояния. + Свойства хранятся как ordered property bag: ```text diff --git a/docs/tomes/06-behavior.md b/docs/tomes/06-behavior.md index cd08969..b30bc7d 100644 --- a/docs/tomes/06-behavior.md +++ b/docs/tomes/06-behavior.md @@ -204,11 +204,47 @@ SuperAI для записей кланов, затем обновляет Behavi не воспроизводит аргумент обратного вызова в `AI+0x3fc`, защиту от повторного входа `AI+0x78`, одноразовую метку `AI+0x8a8` или обновления Behavior на игровых тиках. При этом один конкретный шаг Behavior — распределение ресурсов — уже -исполнен на исходной DLL с искусственными объектами; FParkan пока не вызывает -его, потому что игровой мир Rust ещё не предоставляет нужные ресурсные -интерфейсы. Runtime также не подменяет очередь оригинала: вызывающая сторона -сама передаёт время, а локальный генератор Rust пока учитывает только случайные -числа восстановленного стартового шага. +исполнен на исходной DLL с искусственными объектами. Rust пока не вызывает +регулярный шаг: игровой мир ещё не предоставляет нужные ресурсные интерфейсы. +При полной загрузке Rust уже восстанавливает членство объектов в клановых +списках Behavior, но сами записи распределителя и их доли пока не моделирует. +Runtime также не подменяет очередь оригинала: вызывающая сторона сама передаёт +время, а локальный генератор Rust пока учитывает только случайные числа +восстановленного стартового шага. + +### Откуда берутся объекты распределителя + +Для каждого клана Iron3D создаёт AI независимо от того, найден ли его `.scr`. +Таблица `GetSuperAI` получает указатель только для клана, чей пакет сценария +успешно загружен. У размещённого объекта первое DWORD после имени ресурса +выбирает индекс этой таблицы; второй соседний DWORD для этой цели не используется. +World3D получает индекс через дескриптор создания объекта и передаёт его в +Behavior. Отдельно DWORD по смещению `+4` от начала Unit DAT задаёт class word +объекта. Это второе 32-битное слово файла; его старший бит приводит к созданию +registration key, который проходит защиту Behavior вместе с проверками AI и +distributor. + +Для обычной полной загрузки Rust сохраняет по одной записи состояния на клан. +Каждый размещённый объект с известным Unit DAT и установленным старшим битом +получает существующий `ObjectHandle` и попадает в список только при точном +совпадении индекса `raw_after_resource` с доступной записью `GetSuperAI`. Индекс +не перенумеровывается: например, пакет клана 1 остаётся слотом 1 даже если +пакет клана 0 отсутствует. Preview сохраняет свои статические данные, но не +создаёт эти связи. + +В лицензированной AutoDemo это даёт четыре членства: TMA объекты 4 и 6 идут +в слот 0, а объекты 5 и 7 — в слот 1. У парных записей первого клана raw +селектор равен 0, у второго — 1; классы из Unit DAT равны `0x80000010` для +`wor_l_n1.dat` и `0x80000002` для `gener01.dat`. Тот же обычный путь в исходном +Behavior добавил четыре ключа `0x80000003..0x80000006` в два distributor-а. +Rust-тест повторно читает лицензированную миссию, связывает результаты с её +TMA-записями и проверяет реальные `ObjectHandle`, но помечен `#[ignore]`, чтобы +не требовать оригинальных ресурсов от остальных разработчиков. + +Это пока только перечень участников. Оригинальный `Behavior.dll!Add` создаёт для +каждого участника запись размером `0x1c` с долей `1 / count`, после чего +нормирует прежние доли. Rust ещё не хранит эти поля и не исполняет их регулярный +обмен ресурсами. Поля не выводятся из TMA-соседнего слова или `OwnerId`. ### Регулярная передача ресурсов @@ -227,13 +263,11 @@ Resource Distributor работает со списком зарегистрир исходной `Behavior.dll`, но объекты и ответы интерфейсов заданы тестом; это ещё не воспроизведение реальной миссии. -Пока мы знаем точные границы интерфейсных запросов и некоторые ветви классов -объектов, но не все доменные значения полей записи и не происхождение реальных -строк списка. Загрузчик FParkan не должен создавать такие строки из похожих -полей миссии: сначала нужно доказать путь регистрации и связать его с типами -ресурсных объектов. Технические идентификаторы и численные векторы приведены -в [приложении о сценарной машине](../appendices/script-vm.md), а оставшиеся -вопросы перечислены в [границах знания](../appendices/knowledge-boundaries.md). +Членство списка связано с реальным путём регистрации, но выполнение этой +миссии не сравнивалось с тем, как исходная DLL заполняет поля записи `0x1c` и +нормирует доли. Rust пока не хранит эти поля, а игровому миру ещё не хватает +ресурсных интерфейсов ArealMap для регулярного шага. Открытые вопросы и границы +проверки приведены в [границах знания](../appendices/knowledge-boundaries.md). Первый часто встречающийся table entry с side effect — `Handler(2)` (176 records в corpus). Он берёт active instruction, разрешает семь slots через -- cgit v1.2.3