aboutsummaryrefslogtreecommitdiff
path: root/docs/appendices
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2026-10-20 08:06:17 +0300
committerValentin Popov <valentin@popov.link>2026-10-20 08:06:17 +0300
commit374db10daf5db88a52596edebc6cf5f2d560065f (patch)
treeb77e7bc5a09e4a4496c1ad555336cdac5079f9aa /docs/appendices
parentcaef8f8e6c0ae81b46fcab39cd4f2b74e1b29235 (diff)
downloadfparkan-trunk.tar.xz
fparkan-trunk.zip
fix(runtime): model distributor share normalizationtrunk
Diffstat (limited to 'docs/appendices')
-rw-r--r--docs/appendices/knowledge-boundaries.md18
-rw-r--r--docs/appendices/script-vm.md50
2 files changed, 49 insertions, 19 deletions
diff --git a/docs/appendices/knowledge-boundaries.md b/docs/appendices/knowledge-boundaries.md
index b10a002..873497c 100644
--- a/docs/appendices/knowledge-boundaries.md
+++ b/docs/appendices/knowledge-boundaries.md
@@ -157,13 +157,17 @@ Behavior (`Behavior.dll`, RVA `0x3600`) вызывает `World3D!stdGetGameMode
подтверждает только состав списков, не точную эквивалентность всей загрузки или
регулярного шага Behavior.
-Нативный `Behavior.dll!Add` (RVA `0x1aac0`) создаёт для каждого участника запись
-размером `0x1c` с начальной долей `1 / count`, а `normalize` (RVA `0x1ac90`)
-перенормирует прежние доли после добавления. Rust пока хранит только членство:
-поля записи, доли и их изменение ещё не исполняются. Не восстановлено и
-соединение с реальными интерфейсами ArealMap, необходимыми для регулярного
-вызова `FUN_10019e80`; остальной Behavior tick flow и общий dispatcher событий
-также остаются открытыми.
+Нативный `Behavior.dll!Add` (RVA `0x1aac0`) и `normalize` (RVA `0x1ac90`)
+проверены прямыми x86-вызовами на синтетических записях при x87 control word
+`0x007f`, измеренном также у игры на входах обоих методов. Rust повторяет
+начальные доли и нормализацию отдельными операциями `f32`, а повторную запись
+сопоставляет по `ObjectHandle`, меняя только долю существующего участника.
+Пять DWORD после доли хранятся сырыми; ненулевое первое слово закрепляет вес,
+смысл четырёх следующих не установлен. Лицензированный AutoDemo-тест проверяет
+список TMA-объектов и получившиеся начальные доли по кланам, но это не сравнение
+живых весов миссии с полями исходных runtime-записей. Не восстановлено соединение
+с реальными интерфейсами ArealMap, нужными `FUN_10019e80`; полный Behavior tick
+flow и общий dispatcher событий также остаются открытыми.
Для `Handler(30)` отдельно подтверждены обратный вызов `iron3d.dll` RVA
`0x611d0` (SHA-256 `d1dc4ea8535e2069b0a05c9e8be2724dd438ba44cca7a83007d8b2e50f9e35fa`),
diff --git a/docs/appendices/script-vm.md b/docs/appendices/script-vm.md
index 4020ebb..c15b208 100644
--- a/docs/appendices/script-vm.md
+++ b/docs/appendices/script-vm.md
@@ -441,15 +441,36 @@ selector `1` на интерфейсе получателя становится
`0x3f2aaaab`). Эти векторы проверяют арифметику исходной функции, но не
распределение реальной карты.
-Текущие типы Rust не дают честно наполнить этот список: мир хранит
-идентификаторы и преобразования объектов, но не нужные tick ресурсные поля;
-`MissionObjectDraft.properties` сохраняет сырые слова без связи с QI
-`0x16`/`0x204` или свойством `0x02000100`. Методы добавления и перенастройки
-строк `FUN_1001a9a0` и `FUN_1001aac0` доступны через entries vtable
-`0x10059794` по смещениям `+0x0c` и `+0x10`; кто именно вызывает эти методы и
-какие значения передаёт, пока не установлено. TMA-anchors и сырые preview
-drafts не используются вместо неизвестной регистрации. `step_headless` по-прежнему
-шагает только `World`.
+Полная загрузка Rust теперь собирает этот список из runtime `ObjectHandle` и
+сохраняет веса вместе с пятью исходными DWORD хвоста каждой записи. Членство
+строится только для полного режима; preview остаётся статическим. Это пока не
+даёт ресурсных полей и интерфейсов ArealMap для `FUN_10019e80`, а
+`step_headless` по-прежнему шагает только `World`.
+
+### Добавление и нормализация долей
+
+В этой же GOG `Behavior.dll` (SHA-256
+`ddfbdbde07832358fe6e35e01c8dba9b58e7313789498b6049ed51d4ed9baf99`)
+`FUN_1001aac0` (RVA `0x1aac0`) добавляет запись размером `0x1c`. Её слово по
+`+0x04` — доля `f32`, а слова `+0x08..+0x18` копируются как сырой хвост.
+Новая запись начинается с доли `1 / count` и нулевого хвоста. При повторном
+ключе запись не вставляется снова: меняется только её доля, остальные пять
+DWORD сохраняются. После каждого вызова выполняется `FUN_1001ac90` (RVA
+`0x1ac90`). Она считает долю целевого ключа и записей с ненулевым первым словом
+хвоста фиксированной. Если сумма остальных долей положительна, остаток от
+единицы распределяется пропорционально; при нулевой или отрицательной сумме он
+делится поровну между изменяемыми записями. Проверенный ветвящийся путь также
+направляет unordered-сумму в пропорциональную ветвь, но стандартный набор этих
+тестов содержит конечные значения.
+
+Инструкции Add и normalize выполнялись при x87 control word `0x007f`, то есть
+с 24-битной точностью мантиссы; такой же CW измерен у оригинальной игры на
+входах обоих методов. Поэтому Rust повторяет их в порядке списка отдельными
+операциями `f32`, без раннего перехода в `f64`. Native x86 oracle проверяет
+три последовательных Add, повторный ключ с sentinel-хвостом, фиксированную
+запись, нулевую сумму и пограничный вектор округления. В последнем доли имеют
+биты `[0x3f000000, 0x3f000000, 0x33000000]`. Эти сценарии сверяют локальную
+арифметику на стандартных конечных данных, а не весь игровый запуск.
Для проверки использованы три x86 helper-а на синтетической памяти. Caller
oracle вызывает оригинальные `iron3d.dll` entry points и проверяет преобразование
@@ -485,7 +506,8 @@ if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
exit $LASTEXITCODE
```
-Отдельный oracle distributor tick компилируется и запускается так:
+Native oracle Add, normalize и distributor tick компилируется и запускается
+так:
```powershell
$env:FPARKAN_ORIGINAL_BEHAVIOR_DLL = 'C:\GOG Games\Parkan - Iron Strategy\Behavior.dll'
@@ -498,8 +520,12 @@ exit $LASTEXITCODE
Oracle проверяет SHA-256 оригинального `Behavior.dll`:
`ddfbdbde07832358fe6e35e01c8dba9b58e7313789498b6049ed51d4ed9baf99`. Harness
-вызывает функцию по RVA `0x19e80` при единственной подмене импортного
-слота `GetSystemArealMap`; машинный код tick не патчится. Проверяются нулевой
+явно устанавливает x87 CW `0x007f` для вызовов Add (`0x1aac0`) и normalize
+(`0x1ac90`), проверяет CW до и после каждого вызова и восстанавливает прежнее
+значение перед tick suite. Для этих двух методов подменяется только bounded
+вставка синтетического vector; их машинный код не патчится. Для tick helper
+подменяет только IAT-слот `GetSystemArealMap` и вызывает RVA `0x19e80`.
+Проверяются нулевой
шаг, обе ветви селекторов скорости, пропуск состояния `0xfffe`, missing lookup,
динамическое повторное чтение `0x1002`, ограниченный запас руды, разные веса,
достаточное и недостаточное значение мощности. Это синтетические ArealMap