diff options
| author | Valentin Popov <valentin@popov.link> | 2026-10-23 11:02:27 +0300 |
|---|---|---|
| committer | Valentin Popov <valentin@popov.link> | 2026-10-23 11:02:27 +0300 |
| commit | 7c909ea67ba7f27e11d5b33b8df9f6569da7eb7b (patch) | |
| tree | 344ca595b3fcd34eb20671b65ad86146813d7873 /docs | |
| parent | 83db371742ad3865bf4dc534ae38429c07a936d3 (diff) | |
| download | fparkan-7c909ea67ba7f27e11d5b33b8df9f6569da7eb7b.tar.xz fparkan-7c909ea67ba7f27e11d5b33b8df9f6569da7eb7b.zip | |
feat(runtime): advance loaded mission resources
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/appendices/knowledge-boundaries.md | 25 | ||||
| -rw-r--r-- | docs/appendices/script-vm.md | 91 | ||||
| -rw-r--r-- | docs/tomes/06-behavior.md | 44 |
3 files changed, 125 insertions, 35 deletions
diff --git a/docs/appendices/knowledge-boundaries.md b/docs/appendices/knowledge-boundaries.md index 3744d84..b9bbf27 100644 --- a/docs/appendices/knowledge-boundaries.md +++ b/docs/appendices/knowledge-boundaries.md @@ -325,17 +325,28 @@ sidecar недоступен, запрос `0xe00` сообщает это отÐ Rust query обращается к загруженному объекту и поддерживает `0xe00` только для текущего descriptor tag `26` с factory tag `26`; другие активные typed tags и -factory paths остаются явными границами. Snapshot показывает состояние сразу -после native-конструкторов, но он не обновляется при Control tick-е. Native -`FUN_10010f30` (RVA `0x10f30`) изменяет и ограничивает provider amount, а -связанные callbacks переносят его между строками; их общий переход в Rust ещё -не реализован. Поэтому вызов нельзя считать живым ресурсным симулятором. +factory paths остаются явными границами. Этот запрос возвращает начальный +снимок provider amount: Native `FUN_10010f30` (RVA `0x10f30`) изменяет и +ограничивает количество, а связанные callbacks переносят его между строками; +этот переход в Rust ещё не реализован. + +Отдельный API `advance_loaded_mission_resources` принимает явное время очереди +и обновляет представленные поля `CurrentOre`, строк распределителя и Control +selector `1`. Его граница — статические снимки профиля и provider-значений: +динамическое распространение Control amount, смена профилей, special +object-state gate и жизненный цикл созданных/удалённых объектов здесь не +моделируются. Если обязательный запрос позднего объекта не поддержан, +транзакция возвращает ошибку и не применяет подготовленные изменения. API не +подключён к игровому циклу; AutoDemo-тест подтверждает связь настоящих профилей +с этим шагом, но не полный паритет миссии. Отдельный aggregate getter Behavior +RVA `0xa490` в oracle не исполнен. + Behavior selectors `0x1002` и `0x1005` используют значения выбранного профиля из `behpsp.res`, разобранного до создания нового мира. `0x1002` складывает только текущие descriptor tag `26` запросы `0xe00`, затем применяет `Transfer_Ore_OffBoard`; `0x1005` возвращает `Transfer_Power_Out`. Это начальный -снимок: он не отражает последующие изменения provider-строк, Control tick-а или -профиля. Полная загрузка сохраняет результат у `ObjectHandle` и возвращает +снимок профиля и provider-строк. Полная загрузка сохраняет результат у +`ObjectHandle` и возвращает ошибку, если известный код класса не имеет корректной записи; класс, отсутствующий в таблице выбора, сохраняет начальные значения конструктора. Preview и объекты без полного Unit DAT не получают профильное состояние. diff --git a/docs/appendices/script-vm.md b/docs/appendices/script-vm.md index c15b208..99c448f 100644 --- a/docs/appendices/script-vm.md +++ b/docs/appendices/script-vm.md @@ -373,10 +373,17 @@ nearest-even `FISTP qword`, младший DWORD, преобразование D deadline `+0x14` по формуле `время + 3*64 + jitter`, где `jitter` лежит в `0..63` и получен одним шагом глобального MSVCRT LCG. В этой ветви она также обнуляет пять слов `+0x30..+0x40`. При повторном вызове до deadline ненулевой -`+0x10` оставляет deadline прежним, не расходует новое случайное число и не -очищает эти слова. Поведение после истечения deadline этим опытом не проверено. -Если само время очереди равно нулю, `+0x10` остаётся нулевым, и повторный вызов -снова проходит ветвь начальной подготовки. +`+0x10` оставляет срок прежним, не расходует новое случайное число и не +очищает эти слова. Если само время очереди равно нулю, `+0x10` остаётся +нулевым, и повторный вызов снова проходит ветвь начальной подготовки. После +срока scheduler продолжает при нулевом deadline или при беззнаковом +`now > deadline`; равенство ненулевому deadline ещё ждёт. Он считает +`u32(now - first_time)` с переполнением по модулю `2^32`, переводит миллисекунды в секунды через x87 +`FILD`/`FMUL`/`FSTP` и планирует следующий срок от текущего времени. Шаг +интервала равен `3 * 64 + jitter`: один шаг LCG `state = state * 214013 + +2531011` выдаёт значение `random = (state >> 16) & 0x7fff`, а +`jitter = ((random & 0xff) * 64) >> 8`. Native oracle проверяет +равенство и проход срока, обёртку и большие интервалы с округлением времени. Путь host callback в проверенной паре DLL теперь статически известен. В `iron3d.dll` функция `FUN_1005ff40` (RVA `0x5ff40`) сначала вызывает @@ -400,9 +407,11 @@ callback-точку входа и порядок внутри неё, но не bundle, но остальные потребители исходного глобального RNG не моделируются. В Rust также нет значения аргумента в `AI+0x3fc`, recursion guard `AI+0x78` или одноразового latch `AI+0x8a8`. Поэтому это связанный начальный поднабор, а -не полная активация SuperAI. Восстановленный ниже distributor tick проверен на -исходной DLL, но пока не подключён к Rust игровому циклу: у runtime нет -ArealMap-объектов и интерфейсов, которые нужны этому вызову. При +не полная активация SuperAI. После полной загрузки узкая Rust-реализация +вызывается явно через `advance_loaded_mission_resources(engine, queue_time_ms)`; +runtime не читает системную очередь, а приложение пока не вызывает API из +игрового цикла. Шаг использует разрешённые handles и представленные snapshots +профилей и Control, поэтому не воспроизводит отсутствующие в них callbacks. При ошибке ограниченного `Init` Rust отклоняет полную загрузку и сохраняет прежний мир и состояние генератора; такая политика отката принадлежит Rust loader-у. @@ -428,9 +437,33 @@ DWORD по смещению `+0x14` как `f32`; если выходной ук пока не получило доменного имени. Идентификаторы и границы вызовов не задают полную семантику свойств. -Изолированный x86 oracle вызывает исходный tick с подменой только IAT-слота -`GetSystemArealMap`; синтетические vtables записывают последовательность -вызовов и ответы. Для смешанного примера два прохода нашли объекты в порядке +Раздача считает доступный за этот шаг объём `A`, полный спрос `D` и взвешенный +спрос `W = Σ(demand × share)`. Из них выводятся коэффициенты приоритетной доли +`P`, остатка `R` и расхода `C`. В таблице ниже показан исходный порядок +проверок: он важен, когда нестандартные доли дают `W > D`. + +| Первое совпавшее условие (при `A > 0`, `D > 0`) | `P` | `R` | `C` | +| --- | ---: | ---: | ---: | +| `A ≤ W` | `A / W` | `0` | `1` | +| `W < A < D` | `1` | `(A − W) / (D − W)` | `1` | +| `A ≥ D` | `1` | `1` | `D / A` | + +При нулевом доступном количестве или спросе native path не выделяет +положительное значение. Строка с долей `share` получает коэффициент +`(1 − share) × R + share × P`, который сочетается с её спросом или доступной +вместимостью. `C` задаёт долю отбора руды у источников; для источников энергии +этот коэффициент вычисляется, но native-код не применяет его к производству. +У объектов в ветви приёма руды (не источников руды) native-код ограничивает `CurrentOre`: +если `MaximumOre − CurrentOre < 0.01`, значение становится `MaximumOre`. +Сравнение строгое: при разнице ровно `0.01` значение не меняется. +В x86-коде это константа `0x3c23d70a`; сравнение и округление проверены при +игровом x87 control word `0x007f`. + +Изолированный x86 oracle вызывает исходный scheduler RVA `0x1adb0`, который +сам вызывает исходный tick RVA `0x19e80`. Для синтетического времени он +подменяет IAT-слот `GetQueue`; tick подменяет `GetSystemArealMap`, а синтетические +vtables записывают последовательность вызовов и ответы. Для смешанного примера +два прохода нашли объекты в порядке `41,42,41,42`. Производитель руды с начальным значением `1` и скоростью `4` вернул при следующем чтении скорость `1`; получатель с начальным значением `6` получил `7`, а агрегаты distributor равны `[0,1,1,0.375,6]`. При запасе @@ -441,11 +474,13 @@ selector `1` на интерфейсе получателя становится `0x3f2aaaab`). Эти векторы проверяют арифметику исходной функции, но не распределение реальной карты. -Полная загрузка Rust теперь собирает этот список из runtime `ObjectHandle` и -сохраняет веса вместе с пятью исходными DWORD хвоста каждой записи. Членство -строится только для полного режима; preview остаётся статическим. Это пока не -даёт ресурсных полей и интерфейсов ArealMap для `FUN_10019e80`, а -`step_headless` по-прежнему шагает только `World`. +Полная загрузка Rust собирает этот список из runtime `ObjectHandle` и сохраняет +веса и поля строк, а также начальные ore-свойства объектов. Членство строится +только для полного режима; preview остаётся статическим. Явный API +`advance_loaded_mission_resources` использует очередь времени, расписание, +профили и представленные Control-таблицы, чтобы исполнить этот ограниченный +шаг над загруженным состоянием. `step_headless` по-прежнему шагает только +`World`. ### Добавление и нормализация долей @@ -520,17 +555,21 @@ exit $LASTEXITCODE Oracle проверяет SHA-256 оригинального `Behavior.dll`: `ddfbdbde07832358fe6e35e01c8dba9b58e7313789498b6049ed51d4ed9baf99`. Harness -явно устанавливает x87 CW `0x007f` для вызовов Add (`0x1aac0`) и normalize -(`0x1ac90`), проверяет CW до и после каждого вызова и восстанавливает прежнее -значение перед tick suite. Для этих двух методов подменяется только bounded -вставка синтетического vector; их машинный код не патчится. Для tick helper -подменяет только IAT-слот `GetSystemArealMap` и вызывает RVA `0x19e80`. -Проверяются нулевой -шаг, обе ветви селекторов скорости, пропуск состояния `0xfffe`, missing lookup, -динамическое повторное чтение `0x1002`, ограниченный запас руды, разные веса, -достаточное и недостаточное значение мощности. Это синтетические ArealMap -объекты; исполнение оригинальной функции проверяет векторы oracle, но не -подменяет сравнение Rust и интеграционную проверку миссии в игре. +явно устанавливает x87 CW `0x007f` для Add (`0x1aac0`), normalize (`0x1ac90`) +и scheduler/tick (`0x1adb0`/`0x19e80`), проверяя слово перед набором вызовов +и восстанавливая прежнее значение после каждого набора. Для Add и normalize +подменяется только bounded вставка синтетического vector; их машинный код не +патчится. Scheduler и tick тоже исполняются оригинальными: подменяются лишь +IAT-слоты `GetQueue` и `GetSystemArealMap`, а synthetic vtables задают часы и +ответы объектов. Проверяются равенство и проход срока, переполнение времени +и точные `f32`-биты elapsed seconds (`1 → 0x3a83126f`, `1001 → 0x3f8020c5`, +`16777217 → 0x46831270`, `16777219 → 0x46831271`, `u32::MAX → 0x4a83126f`). +Tick-векторы проверяют нулевой шаг, обе ветви селекторов скорости, пропуск +состояния `0xfffe`, отсутствующий объект, повторное чтение `0x1002`, ограниченный +запас руды, порог `0.01`, ветви дефицита/частичного/избыточного предложения и +равенство спросу, разные веса и достаточную/недостаточную мощность. Это +синтетические ArealMap объекты: oracle исполняет оригинальные scheduler и tick, +но не сравнивает паритет Rust и не заменяет проверку полной миссии в игре. Caller oracle проверяет AutoDemo пару `(500.2857, 751.8217)`, четыре режима x87 на tie-векторах, границу `10000` и младший DWORD. AI oracle отдельно diff --git a/docs/tomes/06-behavior.md b/docs/tomes/06-behavior.md index bcb7320..b3dd8d0 100644 --- a/docs/tomes/06-behavior.md +++ b/docs/tomes/06-behavior.md @@ -326,8 +326,48 @@ Resource Distributor работает со списком зарегистрир записях при игровом x87 control word `0x007f`: проверены добавление, повторный ключ, закреплённая запись, нулевая сумма и округление. Это позволяет Rust сохранять начальный список, но пока не подтверждает веса реальных объектов в -живой миссии. Для регулярного шага по-прежнему не хватает интерфейсов ArealMap. -Остальные ограничения собраны в [границах знания](../appendices/knowledge-boundaries.md). +живой миссии. + +Узкая часть регулярного шага уже связана с загруженным состоянием движка. +`advance_loaded_mission_resources(engine, queue_time_ms)` принимает явную +метку времени общей 32-битной очереди. Для каждого видимого Behavior clan он +проверяет срок запуска, выполняет два прохода по списку и сохраняет пять +итогов: доступную энергию и руду, буфер руды, потребление энергии и потребление +руды. В обоих проходах объекты разрешаются заново по исходному TMA ID. Первый +проход измеряет поставки и потребность, второй повторно читает представленные +профильные и Control-значения перед применением выделения. Нативный код также +запрашивает интерфейсы во втором проходе, но динамические getter-callbacks в +этом снимке Rust не воспроизводятся. + +Планировщик использует беззнаковое сравнение времени: равенство ненулевому +сроку ещё не запускает шаг, а нулевой срок не задерживает его. Переполнение +вычитания даёт 32-битную длительность. Затем +длительность переводится в секунды с округлением, подтверждённым x87-путём +оригинальной DLL. Нативный oracle проверяет его на длинных интервалах, включая +значения около границы точного целого `f32`, а также на равенстве и строгом +проходе срока. Формула запуска, native vectors и команда воспроизведения +описаны в технической главе [script VM](../appendices/script-vm.md). + +Шаг работает только с уже созданными полными объектами миссии и снимками тех +профилей и Control-таблиц, чьи запросы и setters представлены в runtime. Он +обновляет загруженные `CurrentOre`, поля строк распределителя и поддержанный +Control selector `1`; неподдержанное свойство, запрос Control или невозможное +арифметическое значение возвращает ошибку. Обновления нескольких кланов, их +расписания и RNG фиксируются одной транзакцией: если обязательный запрос +позднего клана не разрешён, ранее подготовленные изменения остаются +неприменёнными. Приложение пока не вызывает +этот API из игрового цикла, а динамические callbacks, которые переносят +количество между Control provider-строками, ещё не моделируются. Поэтому это +исполняемый загруженный resource step, а не полный симулятор миссии. + +Для настоящих ресурсов AutoDemo тест проходит несколько временных точек: +генераторы `ObjectId 6` и `ObjectId 7` читают `Transfer_Power_Out = 10` из +`prof_generator.var`; после шага в 500 мс каждый сообщает 5 единиц доступной +энергии. Это подтверждает связь загруженного профиля с runtime-расчётом, но не +сравнение полной миссии с оригинальной игрой. Native oracle сверяет исходные +планировщик и распределитель GOG `Behavior.dll`; техническая процедура и +проверяемые векторы описаны в [script VM](../appendices/script-vm.md). Остальные ограничения собраны в +[границах знания](../appendices/knowledge-boundaries.md). Первый часто встречающийся table entry с side effect — `Handler(2)` (176 records в corpus). Он берёт active instruction, разрешает семь slots через |
