aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/appendices/knowledge-boundaries.md45
-rw-r--r--docs/appendices/script-vm.md70
-rw-r--r--docs/tomes/06-behavior.md57
3 files changed, 147 insertions, 25 deletions
diff --git a/docs/appendices/knowledge-boundaries.md b/docs/appendices/knowledge-boundaries.md
index a64b68e..bbf0e4b 100644
--- a/docs/appendices/knowledge-boundaries.md
+++ b/docs/appendices/knowledge-boundaries.md
@@ -177,7 +177,11 @@ token и типизированную `float`/`DWORD` ячейку. Неизве
всей цепочки кампании. Обычная `Single.01` доходит до следующего blocker-а:
`Handler(43)` в clan 1, `Init` instruction 10. Rust не перескакивает его;
preview оставляет varset этого клана на defaults, а полный load завершает ошибкой
-с rollback. Это ещё не загрузка/запуск игры и не общий dispatcher.
+с rollback. Для самого расчёта уже есть отдельный bounded reader research-таблицы
+и pure ore/power core в `fparkan-assets`. Они принимают один Unit DAT и не
+исполняют script instruction: runtime по-прежнему не создаёт владельца живого
+контекста, не перечисляет AI candidates и не выбирает результат Handler(43).
+Это ещё не загрузка/запуск игры и не общий dispatcher.
Для GOG-сборки также найден статический host call path в `Init`. В
`iron3d.dll!FUN_1005ff40` (RVA `0x5ff40`) одна ветвь сначала проходит записи
@@ -752,15 +756,36 @@ command/event captures для меню, HUD, briefing и диалогов.
## Research, economy and properties
-Экспорты `LoadResearch`, `CalcFullResearchCost`, TRF/preload resources и TMA
-properties доказывают отдельный слой исследований, стоимости, добычи и
-производственных параметров. Формулы стоимости, dependency graph технологий,
-inventory/economy transitions и точная типизация всех 16-byte property values
-не закрыты.
-
-Закрывающий эксперимент: сопоставить research functions с ресурсами и UI,
-снять изменения state на контролируемых покупках/исследованиях и построить
-typed schema свойств по consumers, а не по одному имени.
+Для GOG `ArealMap.dll` SHA-256
+`a25f9254ebb339d70e2e07c8121950191e9584ca0858d8e9c2e2b6c671edf6ea`
+`CalcFullResearchCost` по RVA `0x16280` имеет подтверждённый ABI
+stdcall `[context, candidate, out1, out2]`, `RET 0x10`, и восстановленный
+алгоритм для одного candidate tree: zero-kind subtree pruning, direct preorder,
+общая дедупликация, ordered DFS по `TRF2`/`TRF3`, raw gates из `TRF1` и
+последовательное `f32` сложение. Принятый набор из 23 synthetic native cases
+включал Calc и два AI predicate; для контролируемых сравнений x87 word был
+установлен в `0x007f`. У набора synthetic context, поэтому он не измеряет
+реальную миссионную стоимость.
+
+`fparkan-assets` декодирует используемые NRes chunks, сохраняя сырые TRF0 words
+и непрозрачные данные. Native cost outputs сопоставлены только с двумя raw
+words: out1 складывает TRF0 word 1 и подписан как ore, out2 складывает word 0
+и подписан как power. Смыслы остальных полей полного 32-byte callback record
+не установлены. Non-ASCII case folding research keys также остаётся открытым;
+Rust явно возвращает unsupported для таких сравнений.
+
+Открыты host binding полного Handler(43), factory/ownership/lifetime реального
+исследовательского context при запуске миссии, AI candidate enumeration и tie
+selection, live x87 policy, inventory/economy transitions и точная типизация
+всех 16-byte TMA property values. Контролируемый тест с настоящими
+`scream.trf` и `12hel1.dat` проверяет разбор и API одного candidate, но не
+сравнивает результат с native вызовом реального миссионного context.
+
+Закрывающий эксперимент для оставшихся границ: связать startup owner, research
+context и AI candidate selection в реальном `Init`; затем сравнить контекст,
+порядок кандидатов и cost outputs оригинала с Rust на одной миссии. Покупки,
+inventory transitions и typed property schema требуют отдельных контролируемых
+исследований.
## Rare branches
diff --git a/docs/appendices/script-vm.md b/docs/appendices/script-vm.md
index 49af347..be8c8b3 100644
--- a/docs/appendices/script-vm.md
+++ b/docs/appendices/script-vm.md
@@ -34,6 +34,60 @@ VM state;
`.trf` — NRes tables, чей framing подтверждён, а field semantics местами лишь
consumer-inferred.
+### Исследовательский профиль TRF и стоимость кандидата
+
+Для одной ветви `Handler(43)` уже восстановлен путь вычисления стоимости.
+Результат привязан к GOG `ArealMap.dll`, SHA-256
+`a25f9254ebb339d70e2e07c8121950191e9584ca0858d8e9c2e2b6c671edf6ea`,
+`CalcFullResearchCost` по RVA `0x16280`. Реальный ABI — четыре аргумента
+stdcall на стеке: `[context, candidate, out1, out2]`; функция снимает с него
+`0x10` байт и не принимает `candidate` через `ECX`.
+
+Источник этих таблиц привязан к GOG `MisLoad.dll`, SHA-256
+`c607762bb67db14ca530927c8e1347339b62b0a163ac90c708ee83142292e2bf`.
+`FUN_10002fe0` (RVA `0x2fe0`) загружает required TRF chunks. Внутренний
+research context разрешает ключ через `FUN_10002a40` (RVA `0x2a40`), выдаёт
+32-byte row record через `FUN_10002aa0` (RVA `0x2aa0`) и возвращает ordered
+dependency array через `FUN_10002cf0` (RVA `0x2cf0`). Эти методы соответствуют
+виртуальным слотам context `+0x08`, `+0x0c` и `+0x24`; native Calc получает их
+через таблицу вызовов, а не напрямую из файлов.
+
+`ResearchTrfDocument` в `fparkan-assets` повторно использует NRes reader и
+сохраняет исходный архив. `TRF0.attr1` задаёт число строк по 40 байт; native
+загрузчик требует `TRF0.attr2 == 3`. `TRF1` задаёт один флаговый byte на строку:
+Rust воспроизводит native zero-fill при коротком payload и отклоняет более
+длинный. `TRFB.attr1` задаёт пары little-endian `(u16 name_offset, u16 row)`;
+имя берётся из NUL-terminated pool `TRF6`. Поиск идёт по исходному порядку и
+берёт первую ASCII-case-insensitive пару. Связь строки с парой использует
+только младшие 16 бит сырого слова `TRF0` по смещению `+0x20`.
+
+Две таблицы зависимостей имеют собственные размеры: `TRF2` считает группы,
+`TRF3` содержит их плоский упорядоченный поток индексов; `TRF4`/`TRF5` образуют
+отдельную пару. Только `TRF2`/`TRF3` участвуют в `CalcFullResearchCost`.
+Отсутствующий `TRF3` или `TRF5` означает пустой поток лишь при нулевой сумме
+счётчиков соответствующей таблицы. Required `TRF7`–`TRFA` остаются
+непрозрачными. Reader проверяет фактически читаемые срезы, строки, ссылки и
+размеры выделений для памяти Rust; это дополнительная безопасность, а не
+утверждение, что native loader отвергает те же плохие файлы.
+
+Из флагового byte `TRF1` native provider строит слова record `+0`, `+4` и `+8`
+из битов `(1, 0, 2)`. `CalcFullResearchCost` использует первые два как raw gate,
+не присваивая им общего игрового имени: `+0` определяет, добавлять ли строку,
+`+4` — раскрывать ли её зависимости. Нулевой `kind` компонента Unit DAT
+отсекает весь узел с потомками. Иначе дерево сканируется в preorder; найденные
+строки добавляются один раз, затем для каждой прямой строки выполняется
+упорядоченный DFS по `TRF2`/`TRF3`. Общая таблица посещений завершает циклы и
+удаляет повторы.
+
+По debug-строкам `out1` — ore и суммирует `TRF0` word 1, а `out2` — power и
+суммирует word 0. Native код хранит каждый шаг суммы как `f32`; один cost-вектор
+`1, 2^24, -2^24` даёт первый результат `0`, а в другом порядке
+`2^24, -2^24, 1` даёт `1`. Rust core сохраняет тот же порядок накопления. В
+принятом наборе из 23 синтетических вызовов оригинальных DLL были случаи
+`CalcFullResearchCost` и два AI-предиката; x87 control word был установлен в
+`0x007f` для контролируемых сравнений. Набор проверяет выбранные ветви на
+синтетическом контексте, но не использует реальный контекст миссии.
+
## Безопасная модель исполнения
Целевая VM должна разделять immutable package (bytecode, symbols, events,
@@ -285,9 +339,12 @@ TMA properties остаются four raw `u32` words плюс имя, пока c
сохраняются `NOT USED`; corpus подтверждает `Invulnerability`, life state,
`ClanID`, ore, speed и free-time properties.
-Research/economy работают в simulation: `LoadResearch` и
-`CalcFullResearchCost` доказывают данные и вычислимую стоимость, но не полный
-layout prerequisites/modifiers/unlocks. General formula evaluator требует
+Для одного кандидата и одной research-таблицы порядок prerequisite-closure,
+дедупликация и две выходные стоимости `CalcFullResearchCost` восстановлены и
+проверены отдельно, как описано в
+[исследовательском профиле TRF](#исследовательский-профиль-trf-и-стоимость-кандидата).
+Это не закрывает production-modifier/unlock data, экономические переходы или
+полное исполнение Handler(43). Общий evaluator формул всё ещё требует
versioned grammar, typed operands, deterministic numeric policy, bounded stack
и явных errors; x87-compatible rounding нужен там, где оно выбирает ветку.
Описанный ниже literal-путь первого `Init` не закрывает общий evaluator.
@@ -448,8 +505,11 @@ Rust сохраняет всю таблицу строк, но вычисляеÑ
полную загрузку кампании Mission.01 после этих присваиваний; у обычной
`Single.01` clan 1 после формул остаётся `Handler(43)` в instruction 10, который
не поддержан и не обходится. Preview оставляет значения этого клана без
-частичных записей, а полный load возвращает ошибку транзакционно. Это не
-подтверждение запуска самой игры или полной VM.
+частичных записей, а полный load возвращает ошибку транзакционно. В
+`fparkan-assets` теперь отдельно доступны bounded TRF reader и pure cost core
+для одного Unit DAT, но script/runtime пока не создают нужный research context,
+не перечисляют AI candidates и не выполняют этот handler. Это не подтверждение
+запуска самой игры или полной VM.
### Первый вызов Behavior и сценарного `Init`
diff --git a/docs/tomes/06-behavior.md b/docs/tomes/06-behavior.md
index 9350d94..b4bddb7 100644
--- a/docs/tomes/06-behavior.md
+++ b/docs/tomes/06-behavior.md
@@ -485,16 +485,53 @@ Tag выбирает конкретное правило. Для tag 1 запиÑ
### TRF и preload-данные
-TRF-файлы проходят структурный разбор. `auto.trf`, `data.trf` и tutorial
-variants имеют сигнатуру [NRes](../reference/nres.md) и содержат большие
-таблицы имён игровых прототипов: оружия, башен, сооружений и других объектов.
-Также найдены preload-записи, ANI и SKE resources.
-
-По содержимому, порядку загрузки и consumers TRF с высокой вероятностью
-предоставляет AI/сценарному слою заранее подготовленную таблицу типов и
-связанных данных. Framing и имена подтверждены corpus-ом, но полная семантика
-каждой TRF-записи ещё не закрыта. Имена должны разрешаться через тот же
-resource registry, что и миссионные объекты.
+TRF-архивы используют несколько потребителей; один подтверждённый путь ведёт
+из `Handler(43)` к вычислению стоимости исследования. В проверенной сборке GOG
+`CalcFullResearchCost` из `ArealMap.dll` получает таблицу, загруженную через
+`MisLoad.dll`. Для этого пути `TRF0` содержит строки по десять сырых `u32`,
+`TRF1` — байты флагов, `TRFB` — пары «смещение имени и номер строки», а
+`TRF6` — пул строк с нулевыми окончаниями. Слово 8 строки связывает её с
+`TRFB` через младшие 16 бит; старшая половина сохраняется как неизвестное
+значение. `TRF2` и `TRF3` образуют упорядоченные списки предварительных
+исследований, которые читает этот путь стоимости. `TRF4`/`TRF5` образуют
+отдельную пару таблиц, но `CalcFullResearchCost` её не использует. Непрозрачные
+`TRF7`–`TRFA` остаются в архиве и требуются загрузчику.
+
+Модуль `fparkan-assets` разбирает этот профиль в `ResearchTrfDocument` и
+вычисляет пару результатов для одного Unit DAT:
+
+```rust
+let table = ResearchTrfDocument::decode(archive_bytes)?;
+let cost = calc_full_research_cost(&candidate, &table)?;
+```
+
+Расчёт проходит компоненты Unit DAT в порядке дерева. Компонент с нулевым
+`kind` завершает весь свой участок вместе с потомками. Для остальных ключ
+ресурса ищется среди имён `TRFB`; повтор строки добавляется лишь один раз.
+После прямых компонентов алгоритм обходит список `TRF2`/`TRF3` в его исходном
+порядке, углубляясь сразу в найденные предварительные исследования. Общая
+таблица посещений не даёт повторно добавлять узел и завершает циклы. Два бита
+флагов `TRF1` управляют включением строки и обходом её зависимостей; остальные
+сырые биты и слова не получают игровых имён без отдельного доказательства.
+
+Результат первого native-выхода подписан в отладочной строке как ore и
+суммирует слово 1 `TRF0`, второй подписан как power и суммирует слово 0. Каждое
+сложение сохраняется как `f32` в порядке найденной последовательности. В
+принятом наборе из 23 синтетических тестов оригинальных DLL проверялись
+`CalcFullResearchCost` и два AI-предиката; именно вызовы `CalcFullResearchCost`
+подтвердили порядок обхода, дедупликацию, циклы, флаги и отсечение дерева.
+Две проверки суммы показали чувствительность округления: одна и та же сумма
+`1, 2^24, -2^24` даёт `0`, а в другом порядке `2^24, -2^24, 1` даёт `1`.
+
+Эта проверка использовала синтетический исследовательский контекст и заданное
+для опыта x87-слово управления `0x007f`; она не запускала штатный `Handler(43)`.
+Локальный Rust-core принимает таблицу и одного Unit DAT, но пока не выбирает
+кандидата в AI-каталоге и не связывает таблицу с владельцем полного старта
+миссии. Поэтому `Single.01` всё ещё останавливается на неподдержанном
+`Handler(43)`. Разбор с настоящими `scream.trf` и `12hel1.dat` проверяет
+совместимость ресурса с API, но сам по себе не сравнивает стоимость с
+оригинальным живым контекстом. Проверки границ байтов защищают Rust от плохих
+входных данных и не приписываются нативному загрузчику.
### Стабильность AI-слоя