chore: simplify project to engine docs and tests

Remove planning and acceptance scaffolding while retaining the native Vulkan mission preview, format readers, runtime algorithms, and ordinary Rust tests. Keep the book aligned with the runnable project and validate checked-in shaders without generated tool metadata.
This commit is contained in:
2026-09-06 05:22:12 +04:00
parent da03e77f53
commit aa51f3574d
167 changed files with 667 additions and 23705 deletions
-39
View File
@@ -98,42 +98,3 @@ typed schema свойств по consumers, а не по одному имени
Такие ветки реализуются по бинарному коду и synthetic tests, а статус
corpus-verified получают только после реального файла или runtime trace.
## Dynamic-stage requirements
Оставшиеся вопросы нельзя закрыть только статическими архивами. Нужна
изолированная 32-bit Windows-среда, неизменённые игровые каталоги, manifest
SHA-256, debugger, API/vtable hooks, controlled clocks/input и автоматический
launcher, который восстанавливает snapshot, запускает один test case, собирает
логи и завершает процесс без ручного вмешательства.
Для каждого capture сохраняются build profile, module hashes, mission/resource
key, configuration, device profile, initial state, input/time script и версии
инструментов.
## Local evidence requests
Поддерживаемая desktop-платформа — только Windows/Vulkan. Локальный smoke
`fparkan-vulkan-smoke` уже подтверждает настоящий Win32 surface/swapchain,
300 кадров, controlled resize и отсутствие validation warnings/errors.
Это закрывает фундамент Stage 0, но не доказывает визуальный паритет игры.
Следующие доказательства всё ещё нужны именно для Iron3D-compatible рендера:
- capability-gated capture из оригинального GOG процесса с camera/matrix,
draw/state и frame-boundary provenance;
- фиксированные Windows Vulkan captures статической модели, lightmapped модели
и terrain после совпадения backend-neutral command capture;
- затем controlled captures анимации, FX, прозрачности, теней и атмосферы.
Linux/macOS, GLES2, RG40XX и удалённые portability runners не являются
acceptance-гейтами этого проекта. Они не должны появляться в списке блокеров
или подменять Windows evidence.
## Closure criteria
Вопрос считается закрытым только при наличии build fingerprint, raw trace,
parser trace-а, минимального воспроизводимого input/resource/save/message,
формального контракта или явно ограниченной гипотезы, differential test для
изменённых DLL, обновления тематической главы и regression case, запускаемого
без ручного анализа.
+6 -14
View File
@@ -52,18 +52,11 @@ number, size, operands, control flow, effects, errors и минимальный
GOG `ai.dll` доказывает этот framing двумя consumer-ами: loader по
`0x10001000` открывает `<bundle>.scr`, `varset.var`, `<bundle>.fml`, затем
собирает ровно 73 pointers handlers; `0x10011b20` читает описанную count-driven
структуру. Команда
структуру. В GOG `c1m2p.scr` reader находит 73 handler slots,
9 events, 17 nested records и 20 references, заканчивая на EOF.
Это подтверждает разбор пакета, но не смысл всех opcodes.
```powershell
cargo run -p fparkan-cli -- script inspect `
'C:\GOG Games\Parkan - Iron Strategy\MISSIONS\SCRIPTS\c1m2p.scr' --format json
```
на исходном пакете возвращает `opcode_handler_count=73`, 9 events, 17 nested
records, 20 references и 0 trailing bytes. Это corpus evidence для reader-а,
но не разрешение на исполнение неизвестных 73 opcodes.
Теперь установлен selector: loader `0x10001000` создаёт 73 pointers в
Selector устроен следующим образом: loader `0x10001000` создаёт 73 pointers в
фиксированном порядке, а `0x10011e70` копирует их без перестановки в runtime
array. Во всех 58 GOG `.scr` первый header word каждого nested record равен
`0..72` либо `0xffff_ffff`: соответственно 2095 handler selectors и 3992
@@ -157,9 +150,8 @@ slot2 одновременно в `+0x24/+0x28`, slot3 в `+0x2c` и slot6 в `+
На границе mission runtime выбранный TMA clan `first_resource` теперь
материализуется как отдельный `MissionScriptBundle`: loader нормализует
`<base>.scr`, декодирует его тем же bounded reader-ом и публикует immutable
package вместе с clan provenance. Headless report выводит число таких packages
и их named events. Это именно wiring входных данных, не VM execution: Init и
остальные events пока не dispatch-ятся, а ошибка чтения сохраняет
package вместе с clan provenance. Это именно wiring входных данных, не VM
execution: Init и остальные events пока не dispatch-ятся, а ошибка чтения сохраняет
transactional rollback mission loader-а.
TMA properties остаются four raw `u32` words плюс имя, пока consumer/schema не
-83
View File
@@ -1,83 +0,0 @@
# Current Project Audit
Baseline command:
```text
cargo xtask ci
```
Result on 2026-07-18:
- canonical pipeline passes locally with Rust 1.97.1: formatting, policy,
shader provenance, workspace tests, `clippy`, docs and `cargo deny` are
executed through `cargo xtask ci`;
- `rust-toolchain.toml` pins Rust 1.97.1 and installs only the
`x86_64-pc-windows-msvc` target; Linux and macOS target installation is not
part of the default developer setup;
- internal path dependencies are version-pinned and the Windows-only winit
graph enables only `rwh_06`, excluding Unix window-system dependencies;
- `cargo deny` runs without advisory exceptions in the supported Windows graph.
Native Vulkan evidence:
- Windows x86_64 local smoke passed again on 2026-07-18 with Rust 1.97.1, the
system Vulkan loader 1.4.350, and an AMD Radeon Pro WX 3200 Series;
- the smoke created a Win32 surface and swapchain, presented 300 frames,
exercised a controlled resize (three observed resize events and two
swapchain recreations), and shut down with zero validation warnings and
errors;
- Windows is the sole supported runtime target for this project; Linux and
macOS smoke gates are explicitly out of scope.
Scope labels:
- Stage 0 codebase gates: locally evidenced.
- Stage 0 Windows native runtime: locally evidenced.
- Linux/macOS runtime and cross-platform hosted CI: out of scope.
## Current architecture contract
The standalone engine keeps binary formats, the resource graph, simulation,
animation math and backend-neutral render commands independent from the GPU
adapter. Windows presentation uses `winit`, `raw-window-handle`, `ash-window`
and `ash`; only the Vulkan/FFI adapters may contain narrowly documented
`unsafe` code. Raw Vulkan handles do not cross that boundary.
The baseline is Vulkan 1.1 with surface, Win32-surface and swapchain support,
binary semaphores/fences and a classic render-pass path. Device capability is
queried at runtime; dynamic rendering, descriptor indexing, synchronization2,
timeline semaphores and extended dynamic state are optional capability-gated
enhancements, not requirements. The canonical initial texture upload is RGBA8
UNORM. Headless builds remain independent of `winit`, Vulkan and a window
system.
## Current stage model
The canonical Vulkan-revision plan has six dependency-ordered stages numbered
0--5. Keeping its original numbering matters: Stage 4 is an evidence-gated
animation/FX runtime, while Stage 5 is the mission/world vertical slice that
depends on it. They must not be reported as one completed stage.
0. reproducible Windows/Vulkan foundation;
1. paths, VFS and lossless archives;
2. prototype graph and prepared CPU assets;
3. static Vulkan model/terrain viewer;
4. animation and FX runtime, with reference-only semantics until runtime
captures close the x87 and effect-lifecycle evidence gaps;
5. transactional map, mission and world vertical slice, rendered from the
same immutable snapshot through Vulkan.
This is a local, Windows-only adoption of the Notion page "План реализации
stage 0--5: Vulkan revision" (reviewed on 2026-07-18). Its former
Linux/macOS portability and hosted-CI goals are intentionally not imported:
they conflict with the current supported-platform boundary above. The
portable architectural rules that do apply -- backend-neutral commands,
runtime capability queries, narrow Vulkan/FFI `unsafe`, offline shader
validation, and command capture before pixel comparison -- are retained in
this audit and the rendering tome.
Contract tests and failure tests precede implementation. Synthetic checks never
read licensed roots; licensed corpus checks use absolute paths from the local
manifest. Backend-neutral command capture precedes pixel comparison, and GPU
addresses, allocator addresses and driver timing are excluded from deterministic
state hashes.
-88
View File
@@ -1,88 +0,0 @@
# Сверка локальной книги с FParkan в Notion
Проверка выполнена 18 июля 2026 года по странице `FParkan`, её восьми томам,
плану Vulkan revision и приложениям A--D. Цель — не копировать структуру
Notion, а убедиться, что каждый доказательный контракт доступен в `docs/` и
остается применимым к Windows/Vulkan scope.
| Notion | Локальное место |
| --- | --- |
| Статьи 1--3 | `tomes/01-guide.md` |
| Статьи 4--8 | `tomes/02-architecture.md` |
| Статьи 9--13 | `tomes/03-resources.md` и `reference/` |
| Статьи 14--18 | `tomes/04-world.md` и `reference/tma.md` |
| Статьи 19--27 | `tomes/05-render.md`, `reference/` и `rendering/` |
| Статьи 28--32 | `tomes/06-behavior.md` |
| Статьи 33--37 | `tomes/07-implementation.md` и `baseline/vulkan-revision-plan.md` |
| Статьи 38--42 | `tomes/08-evidence.md`, `appendices/glossary.md`, `evidence/` |
| Приложение A | этот audit, `baseline/current-project-audit.md` и тематические тома |
| Приложение B | `appendices/ui-shell.md` |
| Приложение C | `appendices/saves-campaign.md` |
| Приложение D | `appendices/script-vm.md` |
В ходе сверки добавлены отсутствовавшие локальные контракты UI/Shell,
сохранений/campaign и Script VM. Повторы не переносились: форматы, ABI и
corpus statistics уже находятся рядом с соответствующими readers/consumers.
Не перенесены только противоречащие утвержденному scope цели: Linux, macOS,
MoltenVK, GLES/RG40XX и hosted CI. Они не считаются пробелами. Текущие
доказательства Windows/Vulkan и все последующие уточнения ведутся только в
локальных файлах.
## Повторная содержательная сверка (18 июля 2026)
Повторная сверка проверяет не количество дочерних страниц в Notion, а
утверждения, которые они добавляют к реализации. Источником были корневая
страница `FParkan`, восемь оглавлений с 42 статьями, а также две специальные
страницы: `План реализации stage 0–5: Vulkan revision` (редакция 18 июля) и
`Ревью перехода на Vulkan: решение, доказательства и ограничения`.
| Контракт из Notion | Локальное подтверждение | Результат |
| --- | --- | --- |
| Статьи 1–3: терминология, уровень доказательств, методика | `tomes/01-guide.md` | Полностью покрыто. |
| Статьи 4–8: bootstrap, DLL, frame loop, World3D | `tomes/02-architecture.md` | Полностью покрыто. |
| Статьи 9–13: VFS, NRes, RsLi, registry, unit и auxiliary formats | `tomes/03-resources.md` и `reference/` | Полностью покрыто. |
| Статьи 14–18: TMA, mission loader, Land, ArealMap и world construction | `tomes/04-world.md`, `reference/tma.md`, `reference/msh.md` | Полностью покрыто. |
| Статьи 19–27: Ngi32, MSH, animation, MAT0/WEAR/Texm, terrain и кадр | `tomes/05-render.md`, `reference/`, `rendering/` | Покрыто; локально дополнено более свежими evidence по D3D7 camera, Node38 и Terrain/GetShade. |
| Статьи 28–32: AI, control, camera, audio, network | `tomes/06-behavior.md`, `appendices/script-vm.md` | Полностью покрыто. |
| Статьи 33–37 и Vulkan revision: ports, stages, deterministic gates, Vulkan profile | `tomes/07-implementation.md`, `baseline/vulkan-revision-plan.md` | Полностью покрыто в Windows-only редакции. |
| Статьи 38–42 и приложения A–D: ABI, corpus, knowledge boundaries, glossary, shell, saves, VM | `tomes/08-evidence.md`, `appendices/`, `evidence/`, этот audit | Полностью покрыто. |
Пропущенных применимых технических контрактов в этом срезе не найдено. В
частности, локальный Vulkan plan уже содержит независимость решений Vulkan и
`winit`, Vulkan 1.1 baseline, `ash`-изоляцию, SPIR-V manifest/hash, capability
gates, canonical RGBA8 upload и первичность backend-neutral command capture.
Не переносились только исторические cross-platform acceptance требования из
Notion: они прямо отменены текущим Windows-only scope, а не потеряны при
синхронизации.
Следовательно, новые факты следует добавлять непосредственно в тематический
локальный документ; повторный перенос дерева или дублирование страниц Notion
не требуется.
## Проверяемые источники и правило разрешения расхождений
Содержательная сверка опирается не только на оглавления. Были прочитаны
корневая страница `FParkan`, оглавления томов I--VIII и актуальные специальные
страницы [Vulkan revision](https://app.notion.com/p/387e79f2db3981778f94cdf34db5f93f),
[Vulkan review](https://app.notion.com/p/388e79f2db39810eb649edbe90bca529),
а также исторические статьи 33--34. Это позволяет отличить контракт от
исторического статуса работы.
- В локальной книге сохранены применимые контракты Vulkan revision: Windows
как единственная acceptance-платформа, Vulkan 1.1 baseline, изоляция
`ash`/raw handles в adapter-е, capability gates, offline SPIR-V и первичность
backend-neutral command capture.
- Не переносится прежний статус-аудит Notion (например, утверждения о
synthetic-only renderer или незакрытом Windows smoke): он описывал состояние
до последующих локальных captures и потому не является спецификацией.
- Не переносятся Linux, macOS/MoltenVK и portability-enumeration требования.
Это сознательно исключённая область, а не пробел документации.
- Если страница Notion и свежий локальный evidence расходятся, локальный
evidence с командой воспроизведения, артефактом и датой имеет приоритет;
спорный факт отмечается как граница знания, пока не будет перепроверен.
Таким образом, на момент сверки не обнаружено пропущенных применимых
технических контрактов: содержательные добавления из Notion уже разнесены по
тематическим локальным документам, а новые результаты разработки должны
добавляться только локально.
-158
View File
@@ -1,158 +0,0 @@
# План реализации: Vulkan revision (Windows)
Это локальная, действующая редакция плана `stage 0--5`. Она была получена
вдумчивой сверкой с одноимённой страницей книги FParkan в Notion 18 июля
2026 года. В Notion оставлены исторические формулировки и кроссплатформенные
цели; этот документ сохраняет все применимые технические требования и
приводит их к текущему контракту: самостоятельный движок для Windows,
оригинальные файлы игры и Vulkan.
## Неизменяемые решения
- Vulkan — единственный GPU API. Он заменяет прежнюю DirectDraw/Direct3D
реализацию на уровне наблюдаемой семантики кадра, а не через эмуляцию COM
объектов или буквальный перевод старых вызовов.
- `winit` — отдельный adapter окна, ввода и event loop. Vulkan не является
заменой SDL2: это независимые слои. В текущем проекте SDL2 не используется.
- `ash`, `ash-window` и `raw-window-handle` остаются внутри Windows
platform/Vulkan adapters. Backend-neutral crates не экспортируют raw Vulkan
handles и сохраняют `#![forbid(unsafe_code)]`; каждый `unsafe` в adapter-е
имеет локальный safety contract, правило владения и regression test.
- Baseline: Vulkan 1.1, surface + Win32 surface + swapchain, classic render
pass, binary semaphores и fences. Format/queue/present/image-count/sampler
capabilities запрашиваются у конкретного устройства. Dynamic rendering,
descriptor indexing, synchronization2, timeline semaphores и extended
dynamic state допускаются только через capability gate.
- Исходные MSH, WEAR, MAT0 и Texm остаются CPU-форматами. Стартовый upload
путь — канонический RGBA8 UNORM; packed/native GPU formats допустимы только
после доказательства эквивалентности. Shader variants собираются offline в
SPIR-V и проверяются validator-ом, manifest-ом и hash.
- Первичный эталон — backend-neutral command capture. Сравнение пикселей
начинается лишь после совпадения draw order, pipeline key, resource IDs,
descriptor bindings, ranges и transforms. GPU handles, allocator addresses
и driver timing не входят в deterministic state hash.
Windows — единственная runtime-платформа acceptance. Требования Notion к
Linux, macOS/MoltenVK, portability enumeration и hosted CI намеренно не
переносятся: они противоречат утверждённой области проекта, а не являются
пропуском документации. Headless сборка по-прежнему не зависит от окна,
Vulkan loader или `winit`.
## Stage 0 — воспроизводимая Windows/Vulkan основа
**Цель:** минимальный реальный Vulkan vertical slice без игровых assets и
локальные повторяемые gates.
- Зафиксировать stable Rust/MSRV, `Cargo.lock` и `--locked`; расширять
`cargo xtask ci` форматированием, tests, clippy, документацией, policy для
licenses/advisories/sources и проверкой разрешённого `unsafe` allowlist.
- Synthetic gate не читает лицензированные каталоги и не может молча пропускать
тест. Licensed corpus запускается отдельно по абсолютным путям local
manifest. Hosted CI/CD в этот scope не входит.
- Поддерживать typed parsing конфигурации xtask и `cargo_metadata`, а не
ручную интерпретацию TOML; исключать устаревшие adapter names и Python
runtime components из policy.
- Поддерживать `fparkan-platform-winit` (lifecycle, resize/DPI, input,
suspend/resume, raw handles) и `fparkan-render-vulkan` (instance,
validation, device scoring, queues, swapchain, resize/out-of-date/suboptimal
handling, deterministic capability report).
- Acceptance: Windows smoke создаёт настоящее окно/swapchain, показывает не
менее 300 кадров с resize и завершается без validation errors; negative
cases проверяют loader/device/present-queue/surface-format failures.
## Stage 1 — пути, VFS и архивы
**Цель:** безопасный lossless resource substrate без GPU coupling.
- Для каждого пути различать raw legacy bytes, normalized path, ASCII lookup
key и host path; strict и compatible policy не смешивать.
- Применить symlink-safe traversal и casefold-collision policy ко всем VFS.
- В каждый parser/decompressor внедрить общие `DecodeLimits` и
`AllocationBudget`; malformed offsets, counts и decompression bombs должны
завершаться bounded errors.
- Довести NRes и RsLi до lossless reader/editor/writer: сохранять unknown и
non-zero regions, stable directory order, все наблюдённые decode methods,
explicit compatibility profile и output limits.
- Resource repository обязан иметь generation handles, decoded-byte budget,
deterministic eviction, lock-free decompression section и структурированные
ошибки с archive/entry/path/offset/phase/cause chain.
- Acceptance: synthetic no-edit и edit roundtrip, stale handles, traversal,
symlink/casefold и byte-identical corpus reports; Part 1/Part 2 не дают
необъяснённых parser failures.
## Stage 2 — prototype graph и CPU assets
**Цель:** полный mission-reachable graph и typed prepared assets до GPU.
- Разрешить `objects.rlb`, unit DAT, inheritance, BASE/resource variants и
все компоненты unit, сохраняя hierarchy, provenance и multi-component
composition.
- Каждый edge хранит typed provenance: mission object, component, prototype,
model, wear, material, texture, lightmap или effect. Циклы, depth limit,
optional fallback и corrupt reachable dependency имеют разные outcomes.
- `fparkan-assets` — единственный слой CPU preparation; apps и runtime не
парсят assets ad hoc. Assets immutable, имеют stable IDs, а graph failures
содержат полную parent chain.
- Acceptance: graph order/IDs стабильны; все mission-reachable requests
обеих частей завершаются с failures 0 и передают runtime только prepared
assets.
## Stage 3 — статический Vulkan viewer
**Цель:** доказуемый статический MSH/terrain render из оригинальных assets.
- Закрыть validation streams/slots/batches/indices, Texm decode/mips/palettes/
Page rectangles и WEAR/MAT0 fallback с раздельными texture/lightmap identity.
- Backend-neutral `LegacyPipelineState` и canonical `PipelineKey` выбираются
до GPU. Vulkan adapter владеет staging/device buffers, image transitions,
samplers/descriptors, pipeline cache, depth, diffuse/lightmap bindings,
alpha/depth/cull/blend mapping и lifecycle per-frame resources.
- Viewer/debug modes включают model, texture, material, wireframe, normals,
bounds, LOD/group и terrain; upload cache ограничен GPU budget.
- Acceptance: CPU golden vectors, descriptor/pipeline-key/row-stride tests,
command captures до GPU и fixed-camera captures модели, lightmapped модели
и terrain; Windows validation smoke остаётся clean.
## Stage 4 — animation и FX runtime
**Цель:** заменить reference stubs доказанным deterministic runtime.
- Реализовать type 8/type 19 node sampling, fallback keys, hierarchy и
material timeline по подтверждённым modes/masks. Portable math не выдают за
x87-compatible: второй путь появляется только после captured vectors.
- FXID отделяет lifecycle/time/RNG gates от backend: неподтверждённые fields
сохраняются raw и не исполняются как догадки; emit формирует
backend-neutral primitive/audio commands.
- Pose/effect snapshots immutable per frame; Part 1/Part 2 profiles различают
только там, где это подтверждено differential captures.
- Acceptance: frame-by-frame poses имеют approved references, FXID corpus не
имеет parser errors, один seed даёт одинаковые commands. До этого semantic
статус строго `reference-only`, а не `runtime-compatible`.
## Stage 5 — карта, миссия и мир
**Цель:** транзакционно загрузить миссию, выполнить headless steps и показать
тот же immutable world snapshot через Vulkan.
- Закрыть Land.msh/TerrainFace28, Land.map, grid/graph validation и runtime
spatial acceleration для surface/raycast/visibility queries.
- Loader выполняет `Context -> Map -> TMA -> Graph -> Assets -> Construct ->
Register`, откатывая любую ошибку. Он сохраняет raw transforms, properties,
original IDs и provenance всех mission components.
- World queue, generation handles, deferred deletion, deterministic clock и
snapshot contract проверяются replay/hash tests; terrain/navigation и render
читают один опубликованный snapshot, не mutable world.
- Acceptance: headless mission replay стабилен, transaction rollback не
оставляет частичного мира, а Windows Vulkan frame использует ту же snapshot
и имеет связанный command/pixel artifact.
## Сверка с Notion
Восемь томов локальной книги покрывают 42 основные статьи Notion по тем же
разделам I--VIII; приложения сведены в `appendices/` и том VIII. Специальное
Vulkan-ревью дополнительно внесло в локальные материалы следующие точные
факты: исходный Ngi32 dynamically resolves DirectDraw/Direct3D, современная
граница замены находится выше Vulkan, а совпадающий SHA-256 Ngi32 в Частях 1 и
2 позволяет использовать один backend contract. Детали доказательства и
текущие native captures находятся в `tomes/05-render.md`,
`evidence/original_engine_hashes.md` и `rendering/renderer_truth_table.md`.
-65
View File
@@ -1,65 +0,0 @@
# Original Engine Hashes
Страница фиксирует минимальный статический baseline, на который должны
ссылаться capture fixtures и Stage 4 evidence.
## Scope
- Источник: локальная статическая сверка Part 1 (`IS`) и Part 2 (`IS2`).
- Метод: SHA-256, export/import tables, `objdump -p`, `strings`.
- Эта страница не заменяет динамические traces: она задаёт only-if-match
binary baseline для дальнейших runtime captures.
## Stable binaries across Part 1 / Part 2
| Binary | SHA-256 | Size | Notes |
| --- | --- | ---: | --- |
| `Ngi32.dll` | `bab9840d94f4e4e74ffc26677724fa896cf4823845504d09a9e025f80016edf5` | 253952 | Shared low-level render/resource/audio boundary |
| `World3D.dll` | `17e4a3089b2583a8cf2356c9db0390b1aba138356a09130d79b4e7e4791da61e` | 208896 | Shared gameplay/world/render lifecycle baseline |
| `Terrain.dll` | `6d3e68f0e15b297f6c184af3113baf1f31e19c3326c18f0150dec659242ed667` | 708608 | Shared terrain/shade/world baseline |
| `iron_3d.exe` / `iron_3d_p2.exe` | `f476af85c034a4b4f34f49d0806e4dff397b5da0ee26d382a7674231144979f7` | 36864 | Shared launcher binary |
## GOG research baseline
The canonical disassembly source is the windowed GOG installation, not the
Part 1/Part 2 test installations. Its `Terrain.dll` is a distinct revision:
| Binary | SHA-256 | Size | Notes |
| --- | --- | ---: | --- |
| `Terrain.dll` | `af87d1b2e728a0be73c52be3b44cc196ab46da7799f25a15d40f8c9b0b425ead` | 499712 | GOG camera receiver evidence; do not reuse Part 1/2 RVAs without a matching hash |
## Divergent binaries across Part 1 / Part 2
Эти модули нельзя автоматически считать behavior-compatible между частями:
- `AniMesh.dll`
- `Effect.dll`
- `iron3d.dll`
- `services.dll`
- `Control.dll`
- `ArealMap.dll`
## Practical use
1. Frame-order traces для `World3D.dll`, `Terrain.dll` и `Ngi32.dll` можно
привязывать к shared profile, пока hash совпадает.
2. Animation and FX captures обязаны храниться раздельно для Part 1 и Part 2,
потому что `AniMesh.dll` и `Effect.dll` отличаются.
3. Любой runtime fixture должен записывать минимум:
- `game_part`
- `module_name`
- `module_sha256`
- `mission`
- `frame_or_tick`
- `schema_version`
## Export / import focus for Stage 4
- `World3D.dll`: `stdCalculateGame`, `stdRenderGame`, `sendEndOfRender`
- `Terrain.dll`: `GetShade`, `GetWorld`, `stdSetCurrentCamera2`
- `AniMesh.dll`: `LoadAgent`, `LoadAniMesh`
- `Effect.dll`: `CreateFxManager`, `InitializeSettings`
- `Ngi32.dll`: `niGet3DRender`, `n3dPrimitive`, `n3dEndScene`, `rsLoadTexture`, `rsLoadMultiTexture`
Если будущий capture fixture не указывает, к какому hash он относится, такой
fixture нельзя считать acceptance evidence.
-107
View File
@@ -1,107 +0,0 @@
# Stage 4 Capture Schema
Stage 4 нельзя закрывать набором ad-hoc логов. Нужна схема, по которой
animation, FX и rendered frame captures сравниваются между Part 1, Part 2 и
современной реализацией.
## Goals
- сделать captures пригодными для автоматического diff;
- не хранить host-specific пути, временные каталоги и нестабильные handles;
- связывать frame traces, command captures и pixel artifacts общим identity.
## Common envelope
```json
{
"schema_version": "fparkan-stage4-capture-v1",
"capture_kind": "frame-trace | animation-pose | fx-lifecycle | render-frame",
"game_part": "part1 | part2",
"mission": "MISSIONS/.../data.tma",
"frame_id": 123,
"tick": 123,
"module_hashes": {
"World3D.dll": "sha256...",
"Terrain.dll": "sha256...",
"AniMesh.dll": "sha256...",
"Effect.dll": "sha256..."
},
"tool_version": "codex/manual/fixture version",
"notes": []
}
```
## Capture kinds
### `frame-trace`
Используется для порядка фаз и внешних вызовов.
Required fields:
- `events`: ordered list of `{ phase, symbol, sequence, object_id?, fx_id?, camera_id? }`
- `queue_counters`: deferred operations, visible objects, emitted FX, UI callbacks
- `rng_state`: optional, if recoverable
### `animation-pose`
Используется для x87 / portable sampler parity.
Required fields:
- `clip_id`
- `node_index`
- `sample_time`
- `numeric_profile`
- `translation`
- `rotation_quat`
- `scale`
- `matrix_hash`
### `fx-lifecycle`
Используется для create/update/emit/stop parity.
Required fields:
- `fx_id`
- `instance_id`
- `time`
- `opcode_events`
- `rng_calls`
- `resource_refs`
- `emissions`
### `render-frame`
Связывает backend-neutral snapshot с live Vulkan output.
Required fields:
- `camera`
- `visible_object_ids`
- `draws`
- `pipeline_keys`
- `resource_ids`
- `validation`
- `pixel_artifact`
## Stability rules
1. Не записывать абсолютные host paths.
2. Не записывать raw pointer addresses как identity fields.
3. `frame_id` должен совпадать между trace, command capture и pixel artifact.
4. GPU-specific transient handles допустимы только внутри diagnostics fields и
не участвуют в canonical equality.
5. Любой capture without `module_hashes` считается informational, а не
acceptance-grade.
## Acceptance mapping
- `S4-TRACE-*` rows читают `frame-trace`
- `S4-ANIM-*` rows читают `animation-pose`
- `S4-FX-*` rows читают `fx-lifecycle`
- `S4-VK-*` и `S4-PIXEL-*` rows читают `render-frame`
Эта схема intentionally минимальна. Новые поля можно добавлять, но нельзя
ломать перечисленные identity and parity anchors без смены `schema_version`.
+21 -66
View File
@@ -1,72 +1,27 @@
# FParkan
FParkan -- самостоятельная техническая книга о восстановлении игрового движка
Iron3D из *Parkan: Iron Strategy*. Она ведёт от запуска оригинальной программы
и карты DLL к форматам ресурсов, загрузке миссии, геометрии, материалам,
рендеру, поведению, звуку, сети и плану чистой совместимой реализации.
Эта книга рассказывает, как устроен движок *Паркан: Железная стратегия* и как
FParkan воспроизводит его работу на Rust и Vulkan. Начнём с простого вопроса:
что должно произойти между выбором миссии и появлением первого кадра?
Ответ связывает архивы, модели, поверхность карты, камеру, свет и поведение
объектов в одну программу.
Сайт оформлен как онлайн-книга: тома читаются последовательно, а справочник
используется как быстрый доступ к форматам, проверочным правилам и границам
доказанного знания.
Главы читаются последовательно. Для знакомства с игровой разработкой
подойдут первые две; подробные структуры файлов можно искать в справочнике.
## Источник истины и синхронизация
1. [Путеводитель](tomes/01-guide.md): основные понятия и чтение бинарных структур.
2. [Архитектура и игровой цикл](tomes/02-architecture.md): запуск, мир и кадр.
3. [Ресурсы](tomes/03-resources.md): архивы, имена и связи файлов.
4. [Миссии и ландшафт](tomes/04-world.md): размещение объектов и поверхность.
5. [Геометрия и рендер](tomes/05-render.md): путь от вершины до пикселя.
6. [Поведение, управление и звук](tomes/06-behavior.md): интерактивный мир.
7. [Работа над движком](tomes/07-implementation.md): код, тесты и проверка результата.
8. [Устройство оригинальной программы](tomes/08-evidence.md): DLL, адреса и конфигурация.
Каталог `docs/` — единственный рабочий источник истины для FParkan. 18 июля
2026 года его содержательно сопоставили с книгой FParkan в Notion; результат,
маршрутизация статей и сознательно исключённые цели зафиксированы в
[сверке](baseline/notion-reconciliation.md). Актуальные локальные материалы
содержат и последующие результаты разработки. Notion больше не
является местом внесения изменений: новые факты, исправления и решения
фиксируются только здесь, в томе, справочнике или evidence-документе, которому
они принадлежат.
В [глоссарии](appendices/glossary.md) собраны термины, а в
[открытых вопросах](appendices/knowledge-boundaries.md) — ещё не восстановленное
поведение. Описание алгоритма оригинала и возможности текущего приложения
различаются явно. Предположение остаётся предположением, пока его не
подтверждают игровые файлы или код оригинала.
При расхождении приоритет имеют более новое локальное доказательство и текущий
scope проекта: самостоятельный runtime ориентирован исключительно на Windows и
Vulkan. Исторические упоминания других ОС в старых внешних заметках не
расширяют поддерживаемую платформу.
Действующий dependency-ordered план `stage 0--5` находится в
[Vulkan revision для Windows](baseline/vulkan-revision-plan.md). Это
редакторская локальная версия: она включает недостающие контрактные требования
из Notion, но не переносит снятые с проекта Linux/macOS и hosted-CI цели.
## Как читать
Если вы впервые разбираете игровой движок, начните с тома I и II. Там вводится
лексика, доказательная политика, модульная архитектура и жизненный цикл кадра.
Если нужна реализация совместимого движка, читайте тома III--VII линейно:
ресурсы, миссии, мир, рендер, интерактивные подсистемы и порядок работ.
Если вы проверяете выводы, переходите к тому VIII и приложениям. Там собраны
уровни уверенности, corpus gates, открытые вопросы и критерии закрытия.
## Восемь томов
1. **Путеводитель и методика** -- назначение книги, маршруты чтения, язык
предметной области и правила проверки.
2. **Запуск, архитектура и игровой цикл** -- `iron_3d.exe`, пятнадцать DLL,
сервисы, World3D, очередь объектов и границы кадра.
3. **Ресурсная система и форматы** -- NRes, RsLi, кэши, имена, `objects.rlb`,
unit DAT и сквозное разрешение ресурсов.
4. **Мир, миссии и runtime** -- TMA, ландшафт, ареалы, маршруты, создание мира
и свойства размещённых объектов.
5. **Геометрия, материалы и рендер** -- MSH, анимация, WEAR, MAT0, Texm, FXID,
свет, атмосфера и полный render frame.
6. **Поведение, управление, звук и сеть** -- AI, Behavior, Wizard, Control,
ввод, камера, звук и DirectPlay-слой.
7. **Руководство по полной реализации** -- целевая архитектура, этапы работ,
тестовый контур, точность, скорость и критерий совместимости.
8. **Справочник и доказательная база** -- ABI, конфигурация, статистика
корпусов, границы знания и глоссарий.
## Политика доказательств
Специфические утверждения об Iron3D принимаются только после локальной проверки
на исполняемых файлах, DLL, демоверсии, полных каталогах Частей 1 и 2 или на
взаимных инвариантах реальных ресурсов. Внешние описания и текущий код FParkan
могут подсказывать вопросы, но не заменяют проверку.
Неизвестные поля не получают правдоподобных имён. Пока смысл не закрыт,
документация фиксирует raw layout, границы, безопасное чтение и lossless
сохранение.
Команды запуска и проверки приведены в [README](../README.md).
+1 -5
View File
@@ -47,7 +47,7 @@ Validated `ModelAsset` также сохраняет decoded type 8 keys и type
`ModelAnimation`. `node38_fallback_pose` возвращает pose по `fallback_key`,
то есть доказанный static input. `parent_or_link == 0xFFFF` означает root;
иначе это parent index, обязательно меньший индекса child. Этот контракт
подтверждён на licensed animation gates обеих частей и защищён fallback-ом:
подтверждён на тестах анимации с оригинальными ресурсами обеих частей и защищён fallback-ом:
модель с нарушенным порядком не получает придуманную hierarchy.
В legacy-camera static preview стандартный узел уже получает свой fallback pose
@@ -58,10 +58,6 @@ pose применяется `Rz * Ry * Rx`, scale и mission translation. Гео
быть нарисован разными node poses. Это static fallback hierarchy, а не полная
animation parity: dynamic type-19 frame-map sampling остаётся отдельной задачей.
Для воспроизводимого исследования `fparkan-cli model inspect --root <game>
--archive <archive> --resource <model.msh>` выводит Node38 metadata, включая
parent index, fallback key и наличие LOD0/group0 geometry.
## Slot and batch
Type 2 содержит header `0x8C`, затем `Slot68`:
+33
View File
@@ -0,0 +1,33 @@
# Оригинальные модули
RVA в книге относится к определённой сборке DLL. SHA-256 позволяет
проверить, что сравнивается тот же код.
## Совпадающие модули частей 1 и 2
| Binary | SHA-256 | Size | Notes |
| --- | --- | ---: | --- |
| `Ngi32.dll` | `bab9840d94f4e4e74ffc26677724fa896cf4823845504d09a9e025f80016edf5` | 253952 | Shared low-level render/resource/audio boundary |
| `World3D.dll` | `17e4a3089b2583a8cf2356c9db0390b1aba138356a09130d79b4e7e4791da61e` | 208896 | Shared gameplay/world/render lifecycle baseline |
| `Terrain.dll` | `6d3e68f0e15b297f6c184af3113baf1f31e19c3326c18f0150dec659242ed667` | 708608 | Shared terrain/shade/world baseline |
| `iron_3d.exe` / `iron_3d_p2.exe` | `f476af85c034a4b4f34f49d0806e4dff397b5da0ee26d382a7674231144979f7` | 36864 | Shared launcher binary |
## Сборка GOG
The canonical disassembly source is the windowed GOG installation, not the
Part 1/Part 2 test installations. Its `Terrain.dll` is a distinct revision:
| Binary | SHA-256 | Size | Notes |
| --- | --- | ---: | --- |
| `Terrain.dll` | `af87d1b2e728a0be73c52be3b44cc196ab46da7799f25a15d40f8c9b0b425ead` | 499712 | GOG camera receiver evidence; do not reuse Part 1/2 RVAs without a matching hash |
## Различающиеся модули
Эти модули нельзя автоматически считать behavior-compatible между частями:
- `AniMesh.dll`
- `Effect.dll`
- `iron3d.dll`
- `services.dll`
- `Control.dll`
- `ArealMap.dll`
-51
View File
@@ -1,51 +0,0 @@
# Renderer Truth Table
Эта страница нужна для одной вещи: не позволять путям smoke, planning и capture
выглядеть как «почти готовый renderer». Каждый путь доказывает разный класс
свойств, и acceptance не должен смешивать их.
## Краткая матрица
| Path | Native window / swapchain | Draws pixels | Uses original assets | Acceptance class | Что доказывает | Чего не доказывает |
| --- | --- | --- | --- | --- | --- | --- |
| `fparkan-vulkan-smoke` / `VulkanSmokeRenderer` | Yes | Yes | Static MSH plus sampled TEXM | `covered-gpu` for Stage 0 smoke and explicit MSH/TEXM/descriptor bridge IDs | Loader, instance, surface, swapchain, submit/present, validation-clean triangle path; original MSH indexed draw; TEXM RGBA8 staging upload; per-batch WEAR/MAT0 diffuse descriptors and fragment sampling | MAT0 phase animation, lightmaps, legacy blend/depth/cull states, terrain, camera/node transforms, gameplay rendering |
| `VulkanPlanningBackend` | No | No | Optional CPU-side IDs only | `covered-planning` | Deterministic command validation, canonical capture, frame submission planning | Любой live GPU draw, pixel parity, validation-clean asset frame |
| `RecordingBackend` | No | No | Optional CPU-side IDs only | `covered-planning` | Stable command capture for backend-neutral tests | Native window, Vulkan, GPU resource lifetime, pixels |
| `NullBackend` | No | No | Optional CPU-side IDs only | Usually `covered` for validation-only rows | Command stream framing and bounds validation | Capture stability, GPU execution, pixels |
| `VulkanAssetRenderer` | Yes | Yes | Yes | `covered-gpu` | Static original asset rendering: MSH/Texm/WEAR/MAT0/terrain through Vulkan | Animation/FX parity unless explicitly wired |
| `fparkan-game --backend static-vulkan` | Yes, GOG `Autodemo.00` | Yes, full static AutoDemo preview | Eight mission objects, 66 MSH components, original diffuse TEXM and Land2 terrain base layer | `covered-gpu` for the bounded static-scene bridge | Diagnostic XY framing with recovered translation/scale/Z Euler placement, fallback node hierarchy, optional captured legacy camera, 32-bit GPU indices, diffuse descriptors, terrain base draws and synchronized teardown telemetry | Material phases, Land1 blend/microtexture/lightmaps, animated keys, FX, camera control and gameplay parity |
| Future rendered `fparkan-game` mode | Yes | Yes | Yes | `covered-gpu` plus original-evidence IDs | Mission-driven render snapshot execution and pixel capture | Original-runtime parity for animation/FX/x87 without dedicated captures |
## Rules
1. IDs со смыслом `VK`, `GPU`, `DRAW`, `PIXEL`, `VALIDATION` или `RENDERED`
на Stage 3+ не могут закрываться через `NullBackend`, `RecordingBackend`
или `VulkanPlanningBackend`.
2. `covered-planning` означает command planning/capture evidence. Этот статус
никогда не считается доказательством draw пикселей.
3. `covered-stub` зарезервирован для явно помеченных `STUB` acceptance rows и
не считается compatibility closure для FX lifecycle.
4. `covered-gpu` требует live native handles, реальный draw path и связанный
renderer artifact: report, capture или approved pixel.
## Current repository status
- Реальный Vulkan в репозитории имеет smoke triangle path и узкий static asset bridge. `VulkanStaticDrawRange` сохраняет исходный `Batch20.material_index`; когда smoke запускается с `--wear-root`, `--wear-archive`, `--wear-name` без override, он дедуплицирует selectors, проходит каждый через `WEAR → MAT0 → Textures.lib`, создаёт по одному image/descriptor set и бинит set непосредственно перед соответствующим indexed draw. Direct TEXM и `--material-index` — намеренно однотекстурные compatibility modes. Fresh GOG `fortif.rlb::FR_L_MTP.msh` подтверждает 237 batch draws, но его selectors все `0`, поэтому live report содержит один binding `MTP_01.0`; unit contract подтверждает точное сопоставление двух разных selectors с разными descriptor sets. Это не доказывает material phase animation, lightmaps, alpha/depth/cull state, terrain, camera/node transforms или pixel approval.
- Lightmap остаётся отдельным, не реализованным contract: оригинальный `World3D.dll` экспортирует самостоятельный `SetLightMapLib` наряду с `SetTexturesLib` и `SetMaterialLib`; WEAR содержит независимый блок `LIGHTMAPS`. Текущая документация не подтверждает связь этих slots с `Batch20.material_index` или их UV/channel semantics, поэтому viewer не подменяет lightmap diffuse texture и не добавляет недоказанное binding.
- `apps/fparkan-game` по умолчанию выдаёт `render-planning` JSON report поверх
synthetic window descriptor и `VulkanPlanningBackend`. Opt-in `--backend static-vulkan`
создаёт native `winit` window. Для GOG `MISSIONS/Autodemo.00/data.tma` он уже
рендерит весь статический набор из восьми mission objects и 66 MSH components с
diagnostic XY camera (or an optional captured legacy camera), доказанным `Rz * Ry * Rx` placement transform,
fallback node hierarchy и Land2 base terrain. Последний validation-clean
текущий трёхкадровый запуск после применения placement transform в XY path
имел 71 material descriptor, `clip_visible_vertices=75543` и readback hash
`5444013368935681345`. Это `covered-gpu` для ограниченного
static-scene bridge, но не pixel parity и не доказательство material phase,
Land1 blend, microtexture, lightmap, dynamic animation, FX, live camera
selection или gameplay rendering.
- `apps/fparkan-viewer` сейчас inspection-only CLI и не открывает live Vulkan
asset viewer.
- Следующий реальный milestone для rendered acceptance: `VulkanAssetRenderer`
с upload/draw/capture path для хотя бы одной оригинальной модели и одного
terrain slice.
+22 -225
View File
@@ -1,115 +1,19 @@
# I. Путеводитель и методика
# I. Путеводитель
Первый том задаёт язык и правила всей документации. Он объясняет, как читать
технические главы, какие термины используются для игрового runtime, как
разделяются уровни уверенности и какие требования предъявляются к реализации,
которая должна работать с оригинальными данными без потери информации.
Игра выглядит как непрерывное движение, но компьютер строит её из отдельных
шагов. Он читает ввод, обновляет мир, вычисляет положение моделей и рисует
очередной кадр. Чтобы воспроизвести старую игру, нужно понять как её файлы,
так и правила этих шагов.
Документация рассчитана на разработчика, который уже умеет читать C/C++,
байтовые форматы, PE-модули и графические pipeline, но не обязательно знаком с
Iron3D. Поэтому этот том не описывает один конкретный crate, package или
физическое деление будущего кода. Он фиксирует контракты: что должно быть
прочитано, сохранено, рассчитано и показано.
Книга не требует опыта игровой разработки. Ниже объясняются основные понятия,
а последующие главы показывают их на конкретных данных «Паркана».
Подробные таблицы адресов и байтов полезны при реализации; при первом чтении
их можно пропустить.
## Назначение книги
Книга ведёт от общей архитектуры Iron3D к точным форматам данных и алгоритмам
исполнения. Практическая цель -- реализация, способная открыть оригинальный
каталог *Parkan: Iron Strategy*, загрузить миссию, создать мир, провести
игровой шаг и сформировать кадр.
Форматы в главах описываются как байтовые контракты. Если указано поле
`+0x10`, это означает расположение в потоке или структуре данных, а не
разрешение читать файл прямым `reinterpret_cast`. Для постоянных layouts
используются offsets, проверки размеров, bounded cursor и явное сохранение
неизвестных байтов. Для versioned и variable-length записей приоритет имеет
последовательный parser с контролем границ.
Игровое поведение описывается не только размером структур. Совместимая
реализация должна учитывать порядок событий, время, fallback-правила,
идентификаторы объектов, численные ограничения, состояние материалов,
границы кадра и правила завершения операций.
## Маршруты чтения
**Читатель, новый для игровой разработки**, начинает с базовых понятий этого
тома, затем переходит к архитектуре, игровому циклу и вводу в рендер. После
этого имеет смысл читать главы о миссиях, мире и ресурсных форматах.
**Разработчик совместимого движка** читает тома II-VII линейно. Технические
главы имеют одинаковую логику: назначение подсистемы, данные на диске,
представление в памяти, алгоритм работы, проверки и требования к новой
реализации.
**Аналитик оригинальной программы** использует этот том вместе с разделами о
доказательной базе, ABI, результатах корпусных проверок и границах знания.
Факты, согласованные выводы и открытые вопросы должны оставаться разделёнными:
это позволяет расширять реализацию без подмены проверенных контрактов
удобными догадками.
## Состав документации
1. **Путеводитель и методика** -- язык предметной области, правила чтения и
процедура проверки.
2. [**Запуск, архитектура и игровой цикл**](02-architecture.md) -- от
`iron_3d.exe` до расчёта и вывода кадра.
3. [**Ресурсная система и форматы**](03-resources.md) -- архивы, кэши, реестры
и служебные данные.
4. [**Мир, миссии и игровой runtime**](04-world.md) -- TMA, ландшафт, ареалы и
создание объектов.
5. [**Геометрия, материалы и рендер**](05-render.md) -- от вершины модели до
изображения на экране.
6. [**Поведение, управление, звук и сеть**](06-behavior.md) -- интерактивные
подсистемы.
7. [**Руководство по полной реализации**](07-implementation.md) -- предлагаемая
архитектура и порядок работ.
8. [**Справочник и доказательная база**](08-evidence.md) -- ABI,
конфигурация, статистика и открытые вопросы.
Дополнительные краткие определения собраны в
[глоссарии](../appendices/glossary.md). Технические области, где контракт ещё
не закрыт полностью, перечислены в
[границах знания](../appendices/knowledge-boundaries.md).
## Условные обозначения
`+0x10` означает смещение поля относительно начала структуры или записи.
`RVA 0x13B60` -- адрес относительно базы PE-модуля. `u16`, `u32`, `i16` и
`float32` обозначают типы фиксированной ширины. `LE` означает little-endian.
`payload` -- полезные данные записи после метаданных контейнера. `EOF` -- точное
завершение файла или ограниченного блока.
Если в тексте указан hash, RVA или ordinal, значение относится к явно
обозначенному binary profile. Адреса разных сборок не объединяются по имени
функции. При публикации функции нужны минимум модуль, SHA-256 сборки и RVA.
Размеры структур выражаются в байтах. Счётчики и offsets считаются частью
формата, даже когда их можно восстановить из длины файла. Padding, reserved
поля, неизвестные хвосты и gaps не нормализуются без доказанного правила.
## Совместимость
Слово "совместимость" в этой книге имеет несколько уровней.
**Reader** умеет открыть файл, проверить границы, извлечь известные поля и
сохранить неизвестные bytes так, чтобы данные можно было записать обратно.
**Viewer** умеет показать ресурс: модель, texture, material, эффект или карту.
Viewer может быть полезен для анализа, но он не доказывает поведение runtime.
**Runtime** умеет создать мир, зарегистрировать объекты, исполнять события,
обновлять время, применять контроллеры, выбирать видимое состояние и передавать
его рендеру.
**Полноценный движок** дополнительно воспроизводит порядок операций, численные
правила, fallback-поведение, resource lifetime, reference ownership, pause,
manual input, сетевые идентификаторы, boundaries кадра и состояние
интерактивных подсистем.
Поэтому файл может быть "прочитан правильно", но всё ещё не быть реализованным
на уровне движка. Например, reader MSH может восстановить вершины и индексы,
viewer может нарисовать mesh, а runtime обязан ещё сохранить material slots,
animation state, bounds, LOD, visibility, collision и связи с объектом мира.
`+0x10` означает смещение в байтах от начала записи. `RVA` — адрес относительно
начала загруженной DLL. `u16`, `u32`, `i16`, `float32` — числа фиксированного
размера. `LE` означает little-endian: младший байт числа записан первым.
`EOF` — конец файла. Неизвестные поля сохраняются без изменений.
## Движок как программа длительного действия
@@ -250,122 +154,15 @@ Writer пересчитывает только производные значе
записей, сортировочные таблицы и padding, если правило доказано. Unknown fields
и reserved ranges сохраняются побайтно.
## Иерархия доказательств
Документация использует четыре уровня уверенности.
## Проверка предположений
**Прямое наблюдение** -- поле, значение или последовательность видны в
инструкции программы, таблице PE, экспорте, строке, обработчике файла или в
самом ресурсе. Это самый сильный уровень.
Формат подтверждается тем, как оригинальная программа читает запись, и тем,
какие значения встречаются в игровых ресурсах. Изображение из стороннего
просмотрщика помогает заметить ошибку, но само по себе не доказывает формулу.
Для восстановленного поведения оставляем небольшой тест с конкретным входом
и ожидаемым результатом. Для неопределённого поля прямо пишем, что его смысл
неизвестен.
**Корпусное подтверждение** -- правило проверено на всех подходящих файлах
одного или нескольких явно названных наборов: демоверсии, Части 1 и Части 2.
Например, базовый корпус содержит 435 моделей MSH, 518 textures Texm и 923
эффекта FXID, прошедших структурные проверки без ошибок; полные части расширяют
эту матрицу вариантов.
**Согласованный вывод** -- назначение восстановлено по нескольким независимым
признакам: вызывающим функциям, vtable slots, строкам ошибок, диапазонам
значений и связям между форматами. Такой вывод пригоден для реализации, но его
численные детали следует проверять тестами.
**Открытый вопрос** -- данные можно читать и сохранять, однако предметный смысл
поля или редкой ветки не доказан. Такие bytes нельзя обнулять,
переупорядочивать или превращать в authoring API.
Уровень уверенности должен быть виден из формулировки. "Поле равно" означает
проверенный layout или значение. "Вероятно отвечает за" означает согласованный
вывод. "Неизвестно" означает сохранять без изменения и не строить вокруг этого
публичный контракт.
## Проверенные материалы
Локальный набор проверки включает демоверсию, полные каталоги Частей 1 и 2,
исполняемые файлы, 15 DLL каждой сборки и игровые ресурсы. DLL из
первоначального архива и DLL демоверсии совпали по SHA-256: `15/15`, поэтому
выводы по этому коду и demo-ресурсам образуют один доказательный профиль.
Исполняемый файл демоверсии `iron_3d.exe` имеет размер 36 864 байта, PE32/x86,
entry RVA `0x141E`, image base `0x400000` и SHA-256
`b0a8b0db1c3a8698c4d4604d89c655496bd91ac1f8859a455e8a45838aebfbd6`.
Исполняемые файлы Частей 1 и 2 также имеют размер 36 864 байта и побайтно
совпадают между собой, но относятся к другому binary profile: entry RVA
`0x147E`, SHA-256
`f476af85c034a4b4f34f49d0806e4dff397b5da0ee26d382a7674231144979f7`.
Полные каталоги Частей 1 и 2 суммарно включают 60 TMA, 1 101 unit DAT, 254
NRes-файла и 14 975 NRes entries. Все контейнеры и TMA прошли bounded parser до
точного EOF; полный достижимый граф обеих частей разрешился без ошибок.
## Процедура проверки
Проверка строится как воспроизводимая цепочка:
1. Снять PE-метаданные, хэши, импорты, экспорты, ordinals, RTTI и строки.
2. Построить граф вызовов между модулями и отметить фабрики подсистем.
3. Разобрать функции запуска, загрузчики файлов, главный цикл и критические
vtable-вызовы.
4. Проверить форматы независимыми reader-скриптами с контролем границ и точного
завершения файла.
5. Построить цепочку миссия -> объект -> прототип -> модель -> материал ->
texture.
6. Сравнить счётчики, диапазоны, ссылки и размеры на всём доступном корпусе.
Ключевой результат сквозной проверки демо-миссий: все 201 объектов шести
миссий разрешились в 501 запрос прототипов, затем в 501 модель, 501 таблицу
WEAR, 3 879 слотов материалов и 5 085 ссылок на textures или lightmaps. Ошибок
в фактически исполняемом пути нет.
## Что не считается доказательством
Удобное имя поля не доказывает его назначение. Совпадение layout с текущей
реализацией не доказывает поведение оригинального runtime. Успешный viewer не
доказывает writer. Успешный reader одного файла не доказывает формат всего
корпуса. Совпадение ABI не доказывает побайтную идентичность всех сборок.
Если локальные данные и предположение расходятся, приоритет имеют исполняемый
код, реальные ресурсы и взаимные invariants между форматами. Неизвестное поле
лучше оставить без имени, чем дать ему ложное предметное значение.
## Требования к воспроизводимости
Каждая новая реализация должна иметь strict parser mode, lossless roundtrip
mode и набор corpus tests. Неизвестные поля сохраняются побайтно. Любое
присвоенное полю имя должно сопровождаться наблюдаемым поведением или тестом.
Численные правила -- округление, порядок умножения, RNG и время -- считаются
частью формата исполнения, даже если файл читается правильно.
Минимальный отчёт проверки должен фиксировать:
1. build profile и hashes модулей;
2. путь или ключ ресурса;
3. размер входного файла и hash входных bytes;
4. версию parser-а или commit реализации;
5. список включённых quirks;
6. число прочитанных записей и точку EOF;
7. ошибки, предупреждения и unknown ranges;
8. результат roundtrip, если writer участвует в проверке.
Для runtime-проверок дополнительно нужны mission key, configuration, device
profile, начальное состояние, input/time script и trace значимых callbacks.
## Разделение профилей
Binary profile описывает исполняемый код: PE-метаданные, exports/imports,
ordinals, hashes, RVA и layout функций. Corpus profile описывает набор файлов:
каталог, миссии, ресурсы, размеры, counts, variants и статистику parser-а.
Эти профили нельзя смешивать без явной пометки. Один и тот же формат может
иметь общий смысл в разных сборках, но отличаться редкими ветками, адресами
функций или набором встреченных вариантов. Один и тот же address может иметь
смысл только внутри конкретного module hash.
При расширении документации новое утверждение должно отвечать на три вопроса:
1. Где это видно напрямую?
2. На каком корпусе это проверено?
3. Что должна сделать реализация, если правило нарушено?
Если на один из вопросов нет ответа, утверждение остаётся согласованным выводом
или открытым вопросом, а не закрытым контрактом.
RVA зависит от сборки DLL. Сравнивая инструкции, сначала сверяют соответствующий
файл с [таблицей оригинальных модулей](../reference/original-binaries.md).
-15
View File
@@ -484,21 +484,6 @@ Visual dependency expansion наследует этот индекс на edges
diffuse texture и lightmap. Поэтому ошибка или asset в любой из этих фаз
сохраняет путь до конкретной записи unit DAT, а не только до миссионного object.
Для воспроизводимой проверки используется `fparkan-cli prototype inspect`.
Схема JSON `fparkan-prototype-inspect-v2` содержит lossless hex каждого
32-byte поля unit record и materialized graph edges с `unit_component_index`.
Например, для GOG AutoDemo:
```powershell
cargo run -p fparkan-cli -- prototype inspect `
--root 'C:\GOG Games\Parkan - Iron Strategy' `
--key 'UNITS\UNITS\AutoDEMO\w_m_wlk2.dat' --format json
```
Вывод фиксирует 18 component records, их MSH/WEAR/MAT0/Texm dependencies и
точные parent edges. JSON предназначен для анализа и regression evidence, а
не для интерпретации `kind`, links или opaque tails как готовой game logic.
## Вспомогательные форматы
MSH, материал и текстура отвечают за видимую форму. Полноценный прототип
+62 -1091
View File
File diff suppressed because it is too large Load Diff
-18
View File
@@ -447,24 +447,6 @@ Licensed test на GOG `Autodemo.00` запускает этот путь для
доказывает связывание current runtime data, но не доказывает семантику
оригинального движения.
Путь доступен и через самостоятельный composition root:
```powershell
fparkan-headless --root "C:\GOG Games\Parkan - Iron Strategy" `
--mission MISSIONS/Autodemo.00/data.tma `
--move-object 0 419.10318 717.433 0.25 --ticks 1
```
`--move-object` принимает original object ID, target X/Y и maximum step;
требует `--root` и `--mission`, допускается один раз за запуск и отвергает
non-finite/неположительный шаг ещё при разборе аргументов. Приложение печатает
`reached`, затем normal headless tick/hash. Проверка на GOG 18 июля 2026 года
загрузила 8 objects, 343 areals и 3 174 terrain surfaces без graph failures;
команда для объекта `0` вернула `reached=false`, что подтверждает именно
ограниченный шаг, а не телепортацию к цели.
### Различия Control в Части 2
`Control.dll` пересобрана при неизменных размере, imports и пяти именах/ordinals
exports; RVA всех пяти exports изменились. Форматы и cross-module boundary
сохранились, но точное physical/collision behavior нельзя считать побайтно тем
+67 -711
View File
@@ -1,711 +1,67 @@
# VII. Руководство по полной реализации
Этот том описывает инженерный путь к совместимому движку FParkan. Он опирается
на доказанные форматы и runtime-контракты, но не требует повторять физическое
деление оригинала на пятнадцать DLL. Повторить нужно наблюдаемое поведение:
форматы, имена, fallback, object IDs, порядок событий, численную политику,
границы кадра, сохранения и воспроизводимость прохождения.
Предложенные ниже modules, handles, snapshots, queues и scheduler phases являются
целевой архитектурой новой реализации, а не восстановленным внутренним layout
оригинального Iron3D. Главная практическая цель: запускаться из неизменённого
оригинального каталога игры, проходить corpus gates для демоверсии, Части 1 и
Части 2, а затем измеримо двигаться от archive compatibility к полной игровой
совместимости.
## Целевая архитектура
Практичная форма новой реализации -- модульный монолит с узкими интерфейсами и
отдельными platform adapters. Внутренние границы должны соответствовать ролям
Iron3D, а не обязательно его DLL. Это упрощает перенос на современные платформы
и оставляет возможность поддерживать разные compatibility profiles для разных
сборок данных.
```text
application запуск, окно, конфигурация, shutdown
platform filesystem, clocks, input, threads, dynamic libraries
resources NRes, RsLi, paths, archives, cache and diagnostics
assets MSH, WEAR, MAT0, Texm, FXID and auxiliary formats
mission TMA, unit DAT, prototype graph, scenario data
world ObjectId, queue, lifecycle, time, messages, mirrors
terrain Land.msh, Land.map, surface and spatial queries
navigation areals, graph search, corridors
behavior unit state machines, target and path requests
physics control systems, collision proxies and contacts
animation pose sampling, hierarchy and blending
audio sample cache, sources, listener and buses
render immutable frame contracts and modern backend
network game message schema plus transport adapters
tools validators, extractors, viewers, captures and editors
```
Каждый модуль зависит от нижележащих интерфейсов, а не от concrete managers.
Behavior видит `INavigation` и `IPhysicsCommandSink`, но не включает headers
renderer-а. Render получает immutable snapshot, а не mutable world. Network
receive не меняет мир напрямую: validated messages попадают в очередь следующей
calculation boundary.
### Центральные идентичности
Resource identity хранит и исходное написание, и нормализованный ASCII-key для
поиска:
```c
struct ResourceKey {
NormalizedRelativePath archive;
FixedAsciiName name;
uint32_t type_id;
};
```
Normalization сохраняет исходную строку для diagnostics и roundtrip, а отдельный
ASCII-casefold key используется только для lookup. Эта граница важна для
архивов [NRes](../reference/nres.md), таблиц [RsLi](../reference/rsli.md),
prototype references и fallback-путей материалов.
Object identity разделяет внутреннюю защиту от dangling references и исходную
сетевую/script-семантику:
```c
struct ObjectHandle { uint32_t generation; uint32_t slot; };
struct OriginalObjectId { uint32_t raw; };
```
`ObjectHandle` нужен для безопасного внутреннего владения, deferred deletion и
weak references. `OriginalObjectId` сохраняет наблюдаемую семантику исходной
игры: scripts, mirrors, network messages и savegame references должны видеть
логический ID, а не адрес объекта или номер slot в новом allocator-е.
Frame snapshot отделяет simulation от render. Simulation пишет mutable state;
renderer читает опубликованное состояние или строго ограниченную фазу
`in_render`. Deferred deletion применяется между фазами, а не во время traversal.
Командный контур renderer-а должен сверяться с [описанием кадра](../reference/render-frame.md)
до pixel comparison.
### Владение ресурсами
Ресурс проходит несколько уровней:
```text
ArchiveHandle -> EntryView -> DecodedBlob -> ParsedAsset -> RuntimeResource
```
`EntryView` ссылается на metadata архива, `DecodedBlob` владеет подготовленными
bytes, `ParsedAsset` является CPU-представлением, `RuntimeResource` может
дополнительно владеть GPU/audio objects. Eviction верхнего уровня не закрывает
архив, если он ещё нужен другому entry. Ссылки идут вниз только через явные
handles.
Для shared objects допустимы reference counting или generation handles.
Intrusive refcount нужен только в ABI-shim; внутренний современный код
предпочтительно держит понятное владение и weak handles. Архивы, decoded blobs,
CPU assets и GPU resources имеют отдельные бюджеты и отдельные diagnostics.
### Backend adapters
Render, audio, input и network получают отдельные adapters. Compatibility state
живёт вне Vulkan, D3D11 или Metal backend; DirectPlay compatibility живёт
отдельно от modern transport. Так можно заменить платформу, не меняя форматы,
игровую семантику и regression corpus.
Backend adapter не должен быть местом, где исправляются данные. Если
[MSH](../reference/msh.md), [MAT0](../reference/materials.md) или
[Texm](../reference/texm.md) требуют fallback, это фиксируется в asset/runtime
слое и попадает в trace. Backend получает уже выбранные resources, states и
draw items.
### Scheduler phases
```text
collect_platform_events
build_input_snapshot
advance_game_clock
calculate_world_queue
apply_deferred_operations
update_navigation_physics_animation_fx
publish_render_snapshot
render_world
render_ui
end_frame_callbacks
maintenance_and_eviction
```
Фазы имеют стабильный порядок и запрещённые операции. Registry mutation
запрещена во время world traversal, GPU upload не изменяет simulation state, а
maintenance не влияет на gameplay. Script timers, material animation и FX
lifetime относятся к game time, если обратное не доказано.
Сначала реализуется однопоточный эталон. Параллелизм добавляется только внутри
фаз с детерминированным merge: decoding независимых assets, culling chunks или
подготовка immutable draw items. Это снижает риск скрытых race conditions и
расхождений replay.
### Структурированные ошибки
Каждая ошибка должна содержать фазу, путь, archive entry, object/prototype key,
offset и цепочку причины.
```text
MissionLoadError
mission: Campaign.00/Mission.02
object: 17
resource_name: UNITS/.../unit.dat
component: e_tur_...
prototype: objects.rlb::e_tur_...
cause: model archive missing
```
Логическое отсутствие необязательного lightmap, отсутствующий entry в архиве,
неизвестное opaque поле, выход ссылки за диапазон и повреждённый offset имеют
разный severity и разные способы исправления. Ошибка данных должна быть
actionable chain, а не строка вида `failed to load resource`.
## Порядок работ
Движок строится от данных к поведению и от детерминированных CPU-компонентов к
аппаратным. Каждый этап заканчивается исполняемым инструментом и тестовым
критерием. Нельзя начинать полноценный gameplay, пока ресурсный граф и
model/material path не дают воспроизводимый результат.
### Этап 0. Corpus harness
- индексировать оригинальный каталог и вычислить hashes;
- реализовать bounded binary cursor и structured diagnostics;
- создать CLI для массового запуска parser-ов;
- сохранять JSON-отчёт с counts, variants, warnings и failures;
- зафиксировать демоверсию, Часть 1 и Часть 2 как независимые baselines.
Готовность: повторный запуск на каждом неизменённом каталоге даёт идентичный
отчёт. Любой parser умеет завершиться контролируемой ошибкой с offset и
контекстом, а не crash или allocation по непроверенному count.
### Этап 1. Архивы и пути
- реализовать strict/lossless [NRes](../reference/nres.md) reader/writer;
- реализовать [RsLi](../reference/rsli.md) mapping, table transform, lookup,
LZSS и Deflate;
- добавить адаптивный decoder для методов `0x080` и `0x0A0`;
- воспроизвести overlay и известные compatibility quirks;
- реализовать archive-handle cache и ASCII name policy.
Готовность: неизменённые архивы проходят byte-identical roundtrip; поиск всех
имён совпадает с каталогом; malformed corpus отклоняется без выхода за память.
NRes с ненулевым unindexed region обязательно остаётся regression case.
### Этап 2. Граф ресурсов
- разобрать `objects.rlb` и unit DAT;
- построить resolver прямой MSH, рекурсивного parent prototype через
`objects.rlb` и отдельного BASE payload;
- реализовать dependency graph с reachability от миссии;
- добавить parsers CTPT, NDPR и остальных служебных форматов в lossless-режиме;
- создать инспектор прототипа, показывающий все связанные ресурсы.
Готовность: 201 demo-объект раскрывается в 501 прототип. Затем все миссии
Частей 1 и 2 дают 4 701 и 5 845 prototype requests без failures. Недостижимые
отсутствующие ресурсы отмечаются отдельно от критических ошибок в reachable
graph.
### Этап 3. Статический asset viewer
- реализовать [MSH](../reference/msh.md) core streams, slots и batches;
- декодировать Texm во все подтверждённые pixel formats;
- разобрать WEAR и [MAT0](../reference/materials.md) с точными fallback;
- построить современный renderer compatibility layer;
- добавить wireframe, normals, bounds, LOD/group и material debug views.
Готовность: открываются 435/511 моделей, 518/631 textures и 905/1 127 materials
Частей 1/2; batch/index bounds не нарушаются; viewer показывает корректно
текстурированную статическую модель из исходного архива. Красивый viewer всё ещё
означает только asset compatibility, а не готовую игру.
Текущее состояние репозитория нужно формулировать строже. `apps/fparkan-viewer`
сейчас является inspection CLI и synthetic command producer, а не live Vulkan
asset viewer. Реальный Vulkan в репозитории сегодня доказан только через
Stage 0 smoke triangle path; Stage 3 GPU vertical slice для оригинального
`MSH` + `Texm` + `WEAR/MAT0` + terrain остаётся блокером. Для различения
smoke, planning и live GPU путей используйте [таблицу правды renderer paths](../rendering/renderer_truth_table.md).
### Этап 4. Анимация и эффекты
- реализовать MSH type 8/type 19 sampling и hierarchy;
- добавить x87-compatible reference path для чувствительных формул;
- реализовать material phase animation;
- разобрать FXID header/commands и runtime instances;
- сначала поддержать все opcodes, встречающиеся в корпусе, сохраняя raw body;
- добавить deterministic RNG stream и effect capture.
Готовность: frame-by-frame poses совпадают с golden reference своей части; все
923/1 065 FXID создаются без parser errors; перезапуск одинакового effect seed
даёт идентичный список emitted primitives.
Текущее состояние репозитория опять же уже, чем целевой этап. В коде есть
portable reference sampler и детерминированный FX reference stub, но нет
runtime-captured parity для lifecycle/opcode semantics и нет Stage 4 rendered
acceptance поверх live Vulkan asset renderer. Поэтому rendered Stage 4 следует
считать заблокированным входным gate Stage 3, а parallel Stage 4 work вести
через captures, schemas и backend-neutral snapshots.
### Этап 5. Карта и мир
- реализовать `Land.msh` и corrected `TerrainFace28` layout;
- построить terrain rendering и CPU surface queries;
- реализовать `Land.map`, cell grid и graph links;
- визуализировать areals и найденные маршруты;
- разобрать [TMA](../reference/tma.md) и выполнять staged mission loading;
- создать World3D queue, ObjectId и deferred deletion.
Готовность: 65 карт и 60 TMA Частей 1 и 2 загружаются до EOF; все areal links
валидны; objects появляются в правильных transforms; мир выдерживает расчётные
шаги без рендера.
### Этап 6. Gameplay controllers
- подключить input snapshot и camera controller;
- реализовать navigation corridor, Behavior state machine и Wizard boundary;
- создать physical controller и collision manager;
- загрузить control resources в lossless typed model;
- внедрить game time, pause, event queue и end-of-frame callbacks;
- подключить AI layer и symbol/event layer сценариев.
Готовность: юнит получает цель, строит маршрут, движется по terrain, реагирует
на collision и исполняет базовые миссионные события в детерминированном replay.
На этом этапе вводится differential branch для изменённых `AniMesh`, `Control` и
`Effect`; неизменённые DLL используют общий reference path.
### Этап 7. Полный кадр, звук и UI
- реализовать render phases, sorting, lighting, shadows и atmosphere;
- подключить 3D listener, sample cache, FX sounds и mission audio;
- воспроизвести shell/UI loading и post-world pass;
- добавить frame capture до UI и после UI;
- зафиксировать capability fallback profiles.
Готовность: миссия визуально и звуково проходима; каждый draw и sound event
имеет trace; одинаковый replay создаёт одинаковые command lists. На этом этапе
вводится differential branch для `iron3d` и `services`.
### Этап 8. Сеть, сохранения и динамическая совместимость
- реализовать modern transport над versioned game-message schema;
- отдельно исследовать DirectPlay wire и `netZipData` для native compatibility;
- добавить mirrors, ownership transfer и disconnect cleanup;
- восстановить save/campaign state и dispatcher;
- выполнить динамические captures оригинала для render states, script VM и
physics edge cases.
Готовность: одиночная кампания запускается из оригинального каталога,
сохраняется и продолжается; multiplayer replay согласован между peers; full
corpus не создаёт новых parser variants без явной регистрации.
## Тестовый контур
Совместимость нельзя подтвердить одним screenshot. Нужны тесты на уровне bytes,
структур, ссылок, simulation state, команд renderer-а и конечного изображения.
Каждый слой локализует свой класс ошибки.
```text
unit tests
-> parser/property tests
-> corpus validation
-> cross-resource integration
-> deterministic simulation replay
-> render/audio command captures
-> pixel and gameplay parity
```
Failure верхнего уровня всегда должен позволять спуститься к меньшему тесту и
понять причину.
### Unit, property и fuzz tests
Для каждого binary primitive проверяются little-endian чтение, bounded strings,
checked arithmetic и cursor boundaries. Для структур -- минимальный размер,
максимальные counts, пустые arrays, нулевые варианты и редкие branches.
Property tests генерируют случайные корректные NRes/RsLi/WEAR records,
выполняют encode -> decode и сравнивают семантику. Fuzz tests изменяют длины,
offsets, counts и termination bytes и требуют контролируемой ошибки без crash и
чрезмерного выделения памяти.
Критические алгоритмы имеют отдельные vectors: ASCII casefold, NRes permutation
search, RsLi byte transform, LZSS backreferences, quaternion shortest path,
matrix composition и terrain mask remap.
### Corpus validation
Каждый файл оригинального каталога проходит parser своего семейства. Отчёт
содержит hash, variant, counts, warnings, errors и точный offset сбоя. Baseline
демоверсии:
```text
MSH 435
MAT0 905
Texm 518
FXID 923
WEAR 457
Land.msh 6
Land.map 6
TMA 6
unit DAT 425
errors 0
```
Изменение parser-а принимается только если baseline остаётся стабильной либо
новый variant зарегистрирован с образцом и объяснением. Warnings должны быть
именованными: «неизвестное opaque поле» не равно «выход ссылки за диапазон».
### Cross-resource integration
Интеграционный тест начинается с миссии и проходит весь dependency graph:
object -> prototype -> MSH -> WEAR -> MAT0 -> Texm/lightmap/FXID. Он не
ограничивается тем, что файлы существуют: material slot должен указывать на
допустимый MAT0, phase -- на допустимую texture, model batch -- на существующий
WEAR index.
Demo mission total: 201 objects -> 501 prototypes -> 501 object MSH/WEAR.
Чистый object graph даёт 3 873 material slots и 5 049 texture requests; после
включения environment WEAR итог равен 3 879 material slots, 5 067 textures и
18 lightmaps, failures 0. Такой тест ловит ошибки casefold, suffix, fallback и
путей, которые отдельный parser не замечает.
Для каждого отсутствующего узла отчёт хранит полный parent chain, чтобы
различать broken global archive и реально достижимый mission failure.
### Deterministic simulation replay
#### Mission transform state in the world contract
`fparkan-world` now carries a `TransformState` for every live object: the
three TMA position words, three orientation words and three scale words are
preserved as exact IEEE-754 bit patterns. This stores source identity before a
movement or physics controller interprets axes, units or Euler order.
`WorldSnapshot` publishes transforms in stable object-handle order and the
canonical SHA-256 state hash includes every transform word.
Mission loading assigns this state after construction and before registration.
A headless licensed GOG AutoDemo run on 2026-07-18 loaded eight objects, 343
areals and 3,174 terrain surfaces with zero graph failures, then completed two
deterministic ticks. This is the state foundation for a future route/movement
controller; it does not claim recovered velocity, collision or original
behavior-controller semantics.
The ordinary planning renderer now consumes this snapshot state before falling
back to a mission draft. Its current transform bridge applies the preserved
position and non-uniform scale only; raw orientation remains uninterpreted in
this backend-neutral path. A GOG AutoDemo planning run on 2026-07-18 completed
two ticks with eight objects, 66 draws and state hash
`a54855a4f47ffa380911228f295dd49a9a7b88d6ff271a23db48ba318b1fbbb4`.
Записывается начальная миссия, seed, input events, network messages и значения
внешних часов. На контрольных ticks сохраняется canonical state hash:
```text
sorted ObjectId list
transforms and velocities
critical properties and owners
AI/behavior state IDs
active effect state
game clock and RNG states
```
Pointer addresses, allocator order и GPU handles в hash не входят. Два запуска с
одинаковым log должны давать одинаковый state hash на каждом checkpoint. Первое
расхождение гораздо информативнее финального разного результата миссии.
### Render command parity
До pixel comparison сравнивается command list:
```text
camera matrices and viewport
visible ObjectIds
render phase and stable order
model/node/slot/batch IDs
material phase and texture handles
legacy pipeline states
index ranges and transforms
```
Если command lists совпадают, но pixels различаются, проблема находится в
shader/backend, sampling или численной точности. Если command lists уже
различаются, pixel diff лишь скрывает более раннюю ошибку.
Golden captures следует хранить отдельно для статической модели, анимации,
terrain, transparent FX, shadows, lightmap и atmosphere.
### Pixel, audio и network tests
Pixel tests используют фиксированное разрешение, camera, device profile, seed и
timeline. Сравниваются exact pixels для CPU/reference path и tolerance metrics
для GPU path, но tolerance не должна скрывать переставленные прозрачные
primitives.
Audio tests сравнивают список sound events, sample IDs, positions, loop flags и
gains; waveform зависит от mixer/device и является вторичным уровнем. Network
tests воспроизводят captured message sequences, проверяют mirrors, ownership и
disconnect. Для native DirectPlay compatibility дополнительно нужен packet-level
corpus.
## Regression baselines
Corpus validation формирует три независимых отчёта: демоверсия, Часть 1 и
Часть 2. Каждый сохраняет manifest файлов, hashes executable/DLL, variants,
warnings, global archive health и mission reachability.
Ключевые corpus gates:
```text
NRes: 120 файлов / 6 804 entries и 134 / 8 171 для Частей 1/2
TMA: 29 миссий / 864 objects / 28 extras и 31 / 885 / 41
MSH: 435 и 511 моделей
MAT0: 905 и 1 127 материалов
Texm: 518 и 631 текстура
FXID: 923 и 1 065 эффектов
full reachability: 4 701 и 5 845 prototype requests, failures 0
```
Расширенные mission-reachability totals:
```text
Часть 1: 29 TMA, 864 objects, 4 701 prototypes,
36 954 materials, 48 806 textures, 139 lightmaps, failures 0
Часть 2: 31 TMA, 885 objects, 5 845 prototypes,
50 888 materials, 68 603 textures, 214 lightmaps, failures 0
```
Обязательные regression cases:
- NRes с ненулевым unindexed region;
- prototype inheritance через `objects.rlb`;
- unit DAT `description[32]` без NUL;
- TMA epilogue и `extra_count` 0--4;
- empty SWAV entry;
- stale save-slot metadata без payload;
- build-scoped RVA lookup.
Byte-identical asset comparison выполняется только внутри одного корпуса. Между
Частями 1 и 2 сравниваются semantic invariants и decoded representation,
поскольку многие assets пересобраны.
## Точность, скорость и повторяемость
Совместимый движок должен быть корректным, повторяемым и достаточно быстрым.
Эти свойства нельзя получать одним и тем же приёмом. Сначала создаётся простой
эталонный путь, затем он измеряется и оптимизируется без изменения результата.
Главные источники расхождений: x87 extended precision, преобразование float в
integer, порядок операций, старые SIMD implementations, нестабильная сортировка,
RNG и использование разных часов.
### x87 и округление
Оригинальный x86-код мог хранить промежуточные значения в 80-битных регистрах
x87, а в память записывать 32-битный float. Современный compiler чаще использует
SSE с округлением после каждой операции. Различие заметно на границах animation
frame, culling plane и collision threshold.
Для критических формул нужен reference mode:
- фиксированный порядок операций без reassociation;
- запрещённый fast-math;
- явные преобразования и проверенный режим округления;
- тесты возле half-integer и epsilon boundaries;
- при необходимости extended intermediate через `long double` на проверенной
платформе.
Не требуется эмулировать x87 во всём движке. Нужно локализовать функции, где
малое отличие меняет дискретное решение, и держать для них scalar reference path.
### RNG как часть состояния
FX, atmosphere и, вероятно, AI используют случайные значения. Один глобальный
RNG легко расходится, если новая реализация запрашивает дополнительное число для
визуальной оптимизации. Для трассировки полезны именованные streams:
```text
world/gameplay RNG
AI/script RNG
FX instance RNG
atmosphere RNG
non-deterministic cosmetic RNG
```
Для native parity может потребоваться один общий алгоритм и точная sequence. До
подтверждения capture каждый stream хранит seed и счётчик вызовов в trace.
Cosmetic stream не входит в simulation hash.
### Стабильный порядок
Коллекции не должны зависеть от адресов, unordered containers или порядка
завершения worker threads. Для объектов, collision pairs, opaque/transparent
draws и network messages задаются явные stable keys:
- objects -- queue insertion sequence или OriginalObjectId;
- collision pairs -- упорядоченная пара IDs;
- opaque draws -- phase, pipeline key, material, stable insertion ID;
- transparent draws -- layer, quantized distance, stable insertion ID;
- network messages -- sequence и sender.
Даже когда математический результат коммутативен, side effects, cache accesses и
RNG делают порядок наблюдаемым.
### Часы и fixed-step
Monotonic platform clock хранится отдельно от game clock. Pause и time scaling
применяются к game clock. Simulation работает с фиксированным или точно
воспроизводимым шагом, а render может интерполировать presentation state, не
изменяя authoritative world.
Maintenance timers кэшей используют реальные часы или отдельную подтверждённую
шкалу; их срабатывание не должно менять gameplay. При перегрузке лучше выполнить
ограниченное число simulation steps и явно зафиксировать dropped presentation
frames, чем передать огромный `dt` в AI/physics.
### Оптимизация без потери эталона
1. Сохранить scalar reference implementation.
2. Добавить profiler counters на decoding, culling, sorting, animation, upload
и draw.
3. Оптимизировать только измеренный bottleneck.
4. Сравнить SIMD/parallel результат с reference на полном corpus.
5. Оставить runtime switch для отключения оптимизации при диагностике.
`g_FastProc` удобно моделировать как таблицу function objects: все slots сначала
указывают на scalar path, затем безопасные slots заменяются SIMD-вариантами
после self-test на старте.
### Кэш и память
Архивы, decoded blobs, CPU assets и GPU resources имеют отдельные budgets.
Eviction разрешена только для объектов с нулевым external refcount и после
безопасной frame fence. Original delayed cleanup порядка десятков секунд можно
воспроизвести policy-параметрами, не сканируя все entries каждый кадр.
Основные показатели: число открытых архивов, decoded bytes, resident
textures/lightmaps, models, active FX, draw items и deferred-delete size. Любой
неограниченно растущий счётчик является regression. Производительность считается
достаточной только после корректности: стабильные 60 FPS с неверным LOD или
пропущенными эффектами не являются успехом.
## Release gates
Версия не выпускается, если:
- появился новый corpus error;
- изменился byte roundtrip неизменённых ресурсов;
- dependency graph получил failure в достижимом пути;
- deterministic replay расходится;
- command capture изменился без ожидаемого changelog;
- parser допускает allocation по непроверенному count;
- новая оптимизация не имеет scalar reference comparison.
Каждое исправление регистрирует минимальный regression asset или synthetic
vector. Если новый behavior намеренно отличается от предыдущего, изменение
должно иметь compatibility profile, corpus sample и объяснение, почему старый
baseline был неполным или неверным.
## Уровни совместимости
Слово «совместимый» используется только с уровнем:
1. **Archive-compatible** -- открывает и сохраняет контейнеры.
2. **Asset-compatible** -- декодирует модели, материалы, текстуры и эффекты.
3. **Mission-compatible** -- загружает карту и создаёт все объекты.
4. **Runtime-compatible** -- исполняет время, события, поведение и физику.
5. **Presentation-compatible** -- воспроизводит рендер и звук.
6. **Game-compatible** -- позволяет пройти миссии, сохраняться и продолжать.
7. **Native-interoperable** -- взаимодействует с оригинальной сетью и внешним
ABI.
Viewer с красивой моделью находится только на втором уровне.
### Обязательные критерии запуска и данных
- приложение запускается из неизменённого оригинального каталога;
- относительные пути, регистр и legacy encodings разрешаются по исходным
правилам;
- все требуемые NRes/RsLi открываются без предварительной конвертации;
- parsers проверяют границы и не используют неопределённые bytes как указатели;
- неизвестные поля сохраняются lossless;
- все mission-reachable prototype, model, material, texture, lightmap и effect
references разрешаются;
- отсутствие необязательного ресурса следует документированному fallback, а не
случайному default.
### Обязательные критерии мира
- TMA разбирается до точного EOF;
- `Land.msh` и `Land.map` создают корректную поверхность и areal graph;
- ObjectId, owner и mirror semantics устойчивы;
- queue traversal и deferred deletion безопасны;
- pause, game time и simulation steps повторяемы;
- AI/Behavior/Wizard/Control взаимодействуют через заданные границы;
- collision и navigation не подменяют друг друга;
- script events используют logical IDs и переживают удаление объектов;
- deterministic replay совпадает на контрольных ticks.
### Обязательные критерии presentation
- static и animated MSH используют правильные slots, batches и transforms;
- WEAR/MAT0/Texm fallback и phase timing совпадают;
- mip-skip, palettes, Page atlases и lightmaps работают;
- render phases, depth/cull/blend state и transparent order подтверждены
captures;
- FXID commands и RNG дают устойчивый результат;
- camera и 3D sound listener синхронизированы;
- atmosphere, тени, солнце и flares не являются декоративными заглушками;
- UI и world rendering имеют правильную границу;
- golden command captures стабильны, pixel parity измеряется на фиксированных
сценах.
### Обязательные критерии полной игры
- все доступные миссии стартуют, завершаются и корректно сообщают
success/failure;
- campaign dispatcher сохраняет прогресс;
- savegame восстанавливает world, script, AI, RNG и clocks, а не только
placement;
- input remapping, pause, camera modes, sound и настройки работают из UI;
- длительный прогон не накапливает objects, resources или audio sources;
- ошибки данных показывают actionable chain;
- производительность приемлема без отключения подсистем;
- демоверсия, Часть 1 и Часть 2 проходят один и тот же тестовый контур с
раздельными manifests и эталонами.
### Native interoperability
Самый строгий уровень дополнительно требует совпадения x86 ABI экспортов, vtable
slots и calling conventions для подключаемых оригинальных модулей, а также
DirectPlay wire/framing и compression. Этот уровень независим от возможности
играть в новом standalone runtime.
Проект может честно заявлять game compatibility без native DLL/network
interoperability, но это должно быть явно указано. Аналогично pixel-perfect режим
может быть отдельным compatibility profile поверх функционально корректного
renderer-а.
### Совместимость нескольких наборов данных
Критерий полной совместимости применяется отдельно к демоверсии, Части 1 и
Части 2. Прохождение одного набора не позволяет заявлять поддержку остальных.
Обязательное различие:
- **format compatibility** -- один parser принимает все три набора;
- **content compatibility** -- конкретная миссия разрешает весь reachable graph;
- **behavior compatibility** -- runtime совпадает с соответствующей сборкой
изменённых DLL;
- **cross-version support** -- один новый движок выбирает корректные данные и
defaults по fingerprint установки.
Content fingerprint включает hashes executable/DLL и manifest ключевых архивов.
Он не используется для запрета модификаций, но выбирает compatibility profile и
делает отклонение диагностируемым.
## Definition of done
Полное документирование и реализация считаются завершёнными только когда каждый
критерий связан с главой спецификации, executable test и хотя бы одним
corpus/golden case. Утверждение без проверяемого критерия остаётся
исследовательской заметкой, а не контрактом.
# VII. Работа над движком
FParkan развивается небольшими законченными изменениями. Для нового поведения
сначала нужен пример из оригинала и Rust-тест, затем реализация и объяснение
в соответствующей главе. Если меняется видимый результат, проверка заканчивается
запуском приложения на настоящих игровых ресурсах.
## Где находится код
Библиотеки в `crates/` читают архивы и форматы, связывают ресурсы миссии,
вычисляют геометрию и хранят мир. Они не создают окно и не обращаются к GPU.
Окно находится в адаптере winit, графические ресурсы — в адаптере Vulkan.
`fparkan-game` связывает их в приложение.
У файла на диске и объекта в игре разные сроки жизни. Одна модель может быть
прочитана однажды и использоваться многими объектами, у каждого из которых
свои положение и время анимации. Материалы и текстуры тоже разделяются между
экземплярами. Владение этими данными видно из Rust-структур; отдельный сервис
или интерфейс добавляется, когда появляется реальная потребность.
## Один тест на правило
Для бинарного формата полезен короткий массив байтов: тест проверяет значения
полей и отказ при обрыве записи или неправильной ссылке. Для преобразования
координат удобны точки и повороты, результат которых легко посчитать вручную.
Тесты находятся рядом с соответствующим алгоритмом и запускаются через
`cargo test --workspace`.
Оригинальные ресурсы остаются в установленной игре. Локальные тесты с ними
помечены `#[ignore]`, чтобы обычная проверка работала без коммерческих файлов.
Сообщение об ошибке должно назвать ресурс и причину: например, какой материал
сослался на отсутствующую текстуру. Отдельный отчёт для каждого запуска не нужен.
## Числа и порядок вычислений
Порядок умножения матриц имеет значение: поворот объекта вокруг своей оси и
поворот его положения вокруг начала мира дают разные результаты. Единицы высоты
ландшафта могут отличаться от единиц размещённых объектов. Эти преобразования
выполняются в одном месте и проверяются конкретными точками.
Оригинальный x86-код использует x87. Промежуточное значение может иметь большую
точность, чем сохранённый `float32`. Особенно внимательно проверяются переходы
между кадрами анимации, округление и границы треугольников. Эмулировать x87 во
всём движке не требуется: существенные расхождения разбираются в конкретной
формуле.
Случайные числа и порядок обхода тоже влияют на поведение. Перестановка вызовов
генератора меняет время молнии или траекторию частицы даже при прежнем seed.
Для повторяемой проверки сохраняют начальное состояние и одинаковую
последовательность шагов. Дополнительные потоки и альтернативные алгоритмы
имеют смысл после измерения узкого места.
## Проверка изображения
Успешное создание Vulkan pipeline доказывает только корректность обращения
к API. Положение моделей, масштаб карты, текстуры, прозрачность и свет
проверяются в самом окне. Validation layer помогает находить ошибки владения
GPU-ресурсами, синхронизации и пересоздания swapchain.
Кадр для сравнения читается после завершения работы GPU. При изменении размера
окна старые framebuffer и изображения освобождаются лишь после окончания их
использования. При сворачивании окно может иметь нулевой размер; тогда новые
кадры не отправляются. Обычное закрытие завершает программу успешно.
Оптимизация начинается с измерения: время загрузки, число повторных декодирований,
объём текстур и время кадра. Повторное использование уже загруженного ресурса
обычно полезнее дополнительного слоя управления кэшем.
+19 -663
View File
@@ -1,33 +1,9 @@
# VIII. Справочник и доказательная база
# VIII. Устройство оригинальной программы
Восьмой том фиксирует, на чём держится книга: ABI, exports/imports, файловая
поверхность, статистика корпусов, открытые вопросы, критерии доказанности и
словарь терминов. Это самостоятельная справочная глава: она не заменяет
профильные статьи о форматах, но задаёт общий контракт, по которому проверяются
реализация, parser-ы, compatibility layer и будущие динамические эксперименты.
## Как читать доказательства
Доказательством считается наблюдение, которое можно повторить на конкретном
файле, сборке или трассе. Вывод может объединять несколько наблюдений, но он
должен сохранять происхождение данных: демоверсия, полная Часть 1 и полная
Часть 2 не смешиваются в один безымянный corpus.
Для каждого утверждения полезно различать четыре уровня:
- `layout-confirmed`: известны offset, size, count, bounds и правила безопасного
чтения;
- `corpus-verified`: branch или вариант реально встречается в доступных игровых
данных;
- `code-confirmed`: branch виден в бинарном коде, но отсутствует в доступном
corpus;
- `behavior-confirmed`: поведение подтверждено исполнением оригинальной
программы, трассой API/vtable или controlled differential test.
Если поле не имеет доказанного предметного смысла, документация хранит его как
opaque field. Это не мешает lossless read/write, но запрещает строить writer,
который очищает, переименовывает или пересчитывает такое поле на основании
правдоподобной догадки.
Здесь собраны детали, полезные при чтении оригинальных DLL: экспортируемые
функции, соглашения вызова, адреса и конфигурационные файлы. Адрес относится
к конкретной сборке; сравнить её можно по
[хэшам модулей](../reference/original-binaries.md).
## ABI и границы модулей
@@ -215,12 +191,10 @@ RVA используются только для сопоставления и
implementation не должна встраивать их как постоянные игровые идентификаторы.
Таблица внутренних RVA хранится по SHA-256 конкретного модуля.
Операционные evidence-артефакты, которые должны оставаться синхронизированными
с кодом и acceptance, вынесены в отдельные страницы:
- [Hashes и import/export summary оригинального движка](../evidence/original_engine_hashes.md)
- [Stage 4 capture schema](../evidence/stage4_capture_schema.md)
- [Renderer truth table](../rendering/renderer_truth_table.md)
Сводка hashes и import/export оригинального движка вынесена в отдельную
[страницу](../reference/original-binaries.md). Текущее состояние
реализации и границы live Vulkan path описаны в [справочнике render frame](../reference/render-frame.md)
и в исходном коде адаптера.
Подтверждённые hashes неизменённых DLL:
@@ -229,11 +203,10 @@ World3D.dll 17e4a3089b2583a8cf2356c9db0390b1aba138356a09130d79b4e7e4791da61e
Ngi32.dll bab9840d94f4e4e74ffc26677724fa896cf4823845504d09a9e025f80016edf5
```
Повторный headless IDA/Hex-Rays review GOG `World3D.dll` с этим hash уточнил
RVA export-ов: `stdCalculateGame=0x139A0`, `stdRenderGame=0x13BD0`,
Для GOG `World3D.dll` с этим hash RVA export-ов такие: `stdCalculateGame=0x139A0`,
`stdRenderGame=0x13BD0`,
`sendEndOfRender=0x13D90`, `stdSetCurrentCamera=0x13E60` и
`stdGetCurrentCamera=0x13E80`. Предыдущая таблица была сдвинута и не должна
использоваться для hooks или differential capture.
`stdGetCurrentCamera=0x13E80`.
`stdRenderGame(camera)` сначала вызывает экспорт Terrain
`stdSetCurrentCamera2(camera)`, затем сохраняет текущий camera pointer в
@@ -254,7 +227,7 @@ Terrain object. Следовательно, selector `18`, slot `+12` и global
должны оставаться именованными evidence boundary до dynamic capture; считать
`stdGetCurrentCamera2` getter-ом переданной camera было бы ошибкой.
Повторный headless-IDA review той же GOG базы уточняет рабочий static contract
Статический анализ той же GOG базы уточняет рабочий контракт
`CBufferingCamera`. Метод Terrain RVA `0x4D740` копирует ровно 64 байта
(16 dword) в component offset `+0x10`. Frame-preparation метод RVA `0x4D9C0`
получает viewport rectangle через virtual slot `+0x3C`, выводит width, height,
@@ -546,628 +519,11 @@ provenance: parser хранит не только effective value, но и пр
identifier и path normalization должны оставаться разными слоями: локализация
текста не меняет ASCII-casefold policy имён entries.
## Результаты проверки корпусов
### Demo baseline
## Дальнейшее чтение
Демоверсия содержит `iron_3d.exe`, те же 15 DLL и сокращённый набор
миссий/ресурсов. Все 15 DLL совпали с первоначально исследованными файлами по
SHA-256. Поэтому executable, бинарный код DLL и demo-assets относятся к одной
совместимой технологической сборке.
```text
modules: 16, из них DLL: 15
DLL exports: 313
DLL imports: 1126
DLL identity: 15/15
```
`iron_3d.exe`: 36 864 байта, PE32/x86, image base `0x400000`, entry RVA
`0x141E`, timestamp 28 июня 2001 года, SHA-256
`b0a8b0db1c3a8698c4d4604d89c655496bd91ac1f8859a455e8a45838aebfbd6`.
### Миссии и сквозные ссылки
Шесть TMA разобраны до точного EOF: суммарно 20 paths, 15 clans, 201 placed
objects и 1 extra record. 48 объектов ссылаются на unit DAT, 153 -- на прямые
prototype keys. Unit-файлы раскрыли 348 компонентов.
Сквозной результат:
```text
501 prototype requests 501 resolved
501 MSH requests 501 resolved
501 WEAR requests 501 resolved
3879 material slots 3879 resolved
5067 texture requests 5067 resolved
18 lightmap requests 18 resolved
failures 0
```
Это самое сильное интеграционное подтверждение текущего корпуса: имена,
архивы, ASCII casefold и fallback согласуются между реальными форматами.
### Реестр и unit DAT
`objects.rlb` содержит 590 prototype entries:
```text
554 имеют прямую MSH-ссылку
549 прямых MSH разрешаются в demo-каталоге
34 раскрываются через родительский prototype и локальный BASE
7 не дают доступной геометрии
41 ссылка общего реестра указывает на отсутствующий demo-content
```
Негеометрические или неразрешённые глобальные entries:
```text
sun_01
sun_02
ws_al_01
ws_al_02
ws_fl_01
ws_hm_01
ws_hm_02
```
Они не входят в фактически требуемую цепочку проверенных миссий.
Проверено 425 unit DAT, 5 219 records, errors 0. Все records имеют kind 1 и
archive `objects.rlb`; в 5 205 name fields есть ненулевые хвостовые байты после
string terminator. Такой tail является данными, а не мусором, если цель --
lossless roundtrip.
### Модели
Проверено 435 MSH без errors/warnings; 157 анимированных. Диапазоны: 1-38
nodes, 1-112 slots, 12-9 686 vertices, 1-439 batches.
```text
414 моделей: types [1,2,3,4,5,15,13,6,7,8,19,9,10,17]
21 модель: [1,2,3,4,5,18,15,13,6,7,8,19,9,10,17,20]
```
Type 17 непуст у 29 моделей; type 20 встречается у 21. Редкий variant type 1
найден в `system.rlb::MTCHECK.MSH`.
Повторная проверка terrain исправила layout face: vertex indices находятся с
`+0x08`, neighbor indices с `+0x0E`. Эта локальная проверка имеет приоритет над
ранними черновыми описаниями.
### Материалы и текстуры
Проверено 457 WEAR, 905 MAT0 и 518 Texm без ошибок. У всех MAT0 `attr2 = 6`.
531 материал содержит одну phase; максимальное число phases -- 29. У 860
материалов один animation block, у 43 -- два, у 2 -- восемь.
Распределение Texm по форматам:
```text
indexed 15
565 155
4444 59
888 52
8888 237
```
Форматы 556 и 88 присутствуют в loader-е, но не встречаются в demo-assets.
65 текстур содержат `Page`; размеры лежат от `8x8` до `256x256`. Все 385
уникальных texture references из MAT0 разрешаются.
### Эффекты
Проверено 923 FXID без ошибок. Наиболее часты команды 3, 7, 1 и 2. Команда 6 в
данных демоверсии не встречается. Наблюдаются режимы времени 0, 1, 2, 4, 5,
14, 15, 16 и 17.
### Карты
Шесть `Land.msh` и шесть `Land.map` проходят проверку без ошибок. Всего 3 811
ареалов; grid всегда `128x128`, максимальное число candidates в ячейке -- 10,
`poly_count` во всех записях равен нулю.
```text
AutoMAP 3051 vertices, 3174 faces, 343 areas
PROL 11125 vertices, 9234 faces, 731 area
Tut_1 8827 vertices, 8290 faces, 378 areas
Tut_2 9456 vertices, 8996 faces, 900 areas
Tut_3 9833 vertices, 8560 faces, 722 areas
Tut_4 9022 vertices, 8612 faces, 737 areas
```
Максимальное отклонение длины areal normal от единицы около `1.05e-7`.
### Вспомогательные форматы
```text
CTPT 284 resources, 3599 points, errors 0
NDPR 494 resources, 1915 records, errors 0
BASE 30 resources, errors 0
EXPL 144 resources, versions 1/2/3, errors 0
reference arrays 585 resources, 2956 records, errors 0
SUND 2 resources, 12 keys, errors 0
CTLD 531 payloads, errors 0
TRF 5 files, errors 0
preload 38 entries
ANI 8 resources
SKE 6 resources
```
CTPT names подтверждают attachment semantics: `TurretCenter`, `TurretDirect`,
`CameraCenter`, `TargetDirect`, `Root`, `Sfx`, `Width`, `Height`, `Dir` и
другие.
### Как читать статистику
Нулевое число parser errors подтверждает layout и диапазонные инварианты на
имеющихся variants, но не автоматически раскрывает предметный смысл каждого
opaque field. Отсутствие opcode или poly branch в corpus означает, что эту
ветку нельзя считать corpus-verified.
Особенно важно различать весь архив и достижимый runtime path. В `objects.rlb`
есть ссылки на вырезанный demo-content, однако шесть миссий не требуют их.
Поэтому quality gate имеет два отчёта: global archive health и mission
reachability.
### Полные каталоги Частей 1 и 2
Статистика демоверсии остаётся неизменной. Полные Части 1 и 2 образуют два
самостоятельных профиля с отдельными manifests, hashes и golden data.
Часть 1:
```text
files 1 017, bytes 197 056 957
NRes 120 / 6 804 entries
TMA 29 / 864 objects / 28 extras
unit DAT 425 / 5 219 records
objects.rlb 590 prototypes
MSH 435, MAT0 905, Texm 518, FXID 923
Land maps 33 / 34 662 areals
reachable prototypes 4 701
materials 36 954, textures 48 806, lightmaps 139
reachability failures 0
```
Часть 2:
```text
files 1 302, bytes 358 004 931
NRes 134 / 8 171 entries
TMA 31 / 885 objects / 41 extras
unit DAT 676 / 8 145 records
objects.rlb 683 prototypes
MSH 511, MAT0 1 127, Texm 631, FXID 1 065
Land maps 32 / 18 984 areals
reachable prototypes 5 845
materials 50 888, textures 68 603, lightmaps 214
reachability failures 0
```
Bootstrap Частей 1 и 2 идентичен. Девять DLL идентичны, шесть пересобраны при
сохранённом ABI. Активные NRes entries сравниваются так: 3 733 идентичны, 2 503
имеют изменённый payload, 1 934 добавлены в Части 2, 567 удалены. Это
показывает стабильность форматов при существенной переработке content,
особенно MSH, CTLD и FXID.
## Границы знания
### Закрытые или практически закрытые области
- Startup bootstrap и восемь exports `iron3d.dll`.
- Карта 15 DLL, exports/imports и основные interface boundaries.
- NRes layout, поиск и writer rules.
- RsLi header, table transform, lookup, mapping и используемые decode paths.
- TMA всех 60 проверенных миссий, unit DAT и `objects.rlb` resolution.
- MSH core/animation range contracts.
- WEAR, MAT0, Texm и FXID framing.
- `Land.msh`/`Land.map` и areal grid.
- World3D calculation/render order и deferred deletion.
- Сквозная mission-to-texture цепочка.
Полная проверка доступных каталогов усилила NRes active ranges, recursive
prototype inheritance через `objects.rlb`, bounded non-NUL unit descriptions,
полный TMA epilogue, extra records и Clan mode 0, MSH/MAT0/Texm/FXID variant
matrix Частей 1 и 2, 65 `Land.msh`/`Land.map`, полный reachable graph 60
миссий, stability matrix пятнадцати DLL, empty SWAV и stale save-slot metadata.
### Render-state и pixel parity
Доказан порядок frame boundaries, world traversal, material resolve и крупных
проходов. Не доказаны символами точные названия renderer vtable slots
`+0x28/+0x30/+0x34`, полный набор state transitions CShade и окончательный
взаимный порядок некоторых transparent/FX/shadow subpasses.
Pixel parity требует эталонных кадров оригинала с фиксированными camera,
timing, seed, разрешением и capability profile. Вместе с изображением
необходимо сохранять command/state trace; иначе pixel difference не позволяет
отличить ошибку формата от ошибки backend-а.
Минимальный capture должен фиксировать resolution, bit depth, selected driver,
device capabilities, camera matrices, mission, game time, seed, input log,
scene boundaries, transforms, render states, texture-stage states, texture
binds, viewport, clear, draw calls и `Blt/Flip`. Сначала сравниваются command
lists; pixel diff имеет смысл только после совпадения geometry/state sequence.
### FXID field-level semantics
Размеры команд, resource references, lifecycle, flags families и используемые
time modes известны. Не закрыто значение каждого поля body opcodes 1-10,
отсутствующий во всех проверенных каталогах opcode 6 и точные формулы редких
time modes.
Закрывающий эксперимент: создать инструмент, который изменяет по одному полю
копии эффекта, воспроизводить его в контролируемой сцене и логировать runtime
command object, emitted primitives и sound events. Одновременно reads в
`Effect.dll` сопоставляются с offsets body.
### Script VM
Сценарные packages, symbol names, event sections, variable declarations и
version check доступны. Полная instruction grammar `.scr`, semantics всех
opcodes и serialization состояния VM ещё не восстановлены.
План реконструкции:
1. Найти loader `.scr`, version check, границы bytecode, таблицы
strings/symbols/events.
2. Найти dispatcher loop по повторяющемуся чтению opcode и indirect branch или
jump table.
3. Для каждого handler определить instruction size, operands, чтения/записи VM
state, stack effect, branch target и world side effects.
4. Hook-нуть dispatcher и писать запись `package,event,ip,opcode,raw
operands,state before,state after,next ip`.
5. Построить disassembler и CFG; branch target обязан попадать на
подтверждённую границу инструкции.
6. Закрывать opcode после статического handler contract, одного динамического
trace и одного regression script.
После opcode table отдельно восстанавливаются serialization IP, call/event
frames, variables, timers и RNG.
### Physical/control formats
CTLD и связанные resources структурно читаются, count patterns и variants
известны. Не названы все секции, shape types, coefficients и точный contact
solver. То же относится к редким MSH types 17/20 и части CTPT/NDPR flags.
Закрывающий эксперимент: трассировать `LoadControlSystem`,
`LoadPhysicalModel` и создание collision objects на нескольких прототипах;
записать offsets, созданные shape instances и реакции на контролируемое
движение. Изменение одного resource field должно связываться с одним
наблюдаемым параметром.
### Сеть
DirectPlay lifecycle и имена игровых сообщений известны. Точные framing,
payload schema, reliability flags и алгоритм `netZipData` пока не подтверждены
записью сетевого обмена. Поэтому совместимость с оригинальным сетевым клиентом
ещё не доказана.
Для закрытия нужны два оригинальных клиента в изолированной среде и логирование
`netZipData`, `netUnZipData`, DirectPlay Send/Receive и World3D message
enqueue/dequeue. Native interoperability подтверждается только успешным
обменом original client <-> compatibility implementation в обе стороны.
### Редкие или отсутствующие corpus-ветки
- `Land.map poly_count > 0`: layout читается из loader-а, но ни одна из 65
проверенных карт не содержит живой записи.
- RsLi adaptive methods `0x080`/`0x0A0`: decoder path известен, однако
демоверсия и обе полные части их не используют.
- Texm formats 556 и 88: loader поддерживает их, но ни один проверенный Texm не
использует эти значения.
- FX opcode 6: размер известен, однако живой command отсутствует во всём
доступном corpus.
- Некоторые material flags и MSH auxiliary streams встречаются слишком редко
для полного authoring contract.
Такие ветки реализуются строго по бинарному коду и synthetic tests, а статус
corpus-verified получают только после появления реального файла.
### Сохранения и campaign state
`saveslots.cfg` и `missions/dispatcher.ini` найдены, но полный бинарный
savegame payload, serialization World3D/AI/script/RNG и правила миграции версии
не восстановлены. Без этого нельзя честно заявлять полную campaign
compatibility.
Минимальный набор сохранений для каждой части:
```text
S0 сразу после старта миссии
S1 тот же state без simulation step
S2 изменена только позиция одного объекта
S3 изменено только здоровье/свойство
S4 активен один Behavior order/path
S5 активен один FX и timer
S6 изменена одна script variable
S7 изменён research/economy state
S8 перед/после mission completion
S9 pause и non-default game time
```
Без самих binary save payload возможно описать обязательный state и найти код
сериализации, но невозможно доказать disk layout и roundtrip.
### Shell, HUD, шрифты и локализация
Граница shell подтверждена экспортами `createShell`/`getIShell`, `IGUIServer`,
верхнеуровневым UI-pass и файлами `ui/*.cfg`, `DATA/TextRes.cfg`,
`gamefont.rlb` и `sprites.lib`. RsLi framing двух библиотек закрыт, но widget
tree, layout rules, font glyph metrics, sprite command semantics,
focus/navigation и полный HUD state machine пока не восстановлены до
field-level спецификации.
До закрытия новая реализация может построить функционально эквивалентный UI
поверх известных ресурсов, но не заявлять native layout/behavior parity.
### Исследования, экономика и игровые свойства
Экспорты `LoadResearch`, `CalcFullResearchCost`, TRF/preload resources и TMA
properties доказывают отдельный слой исследований, стоимости, добычи и
производственных параметров. Сквозные имена (`MaximumOre`, `CurrentOre`,
`FreeResearchTime`, `FreeConstructionTime` и другие) доступны, однако формулы
стоимости, dependency graph технологий, inventory/economy transitions и точная
типизация всех 16-byte property values не закрыты.
Закрывающий эксперимент: сопоставить `LoadResearch`/`CalcFullResearchCost` с
ресурсами и UI, снять изменения state на контролируемых покупках/исследованиях
и построить typed schema свойств по consumers, не по одному имени.
### Условия динамического этапа
Полное закрытие оставшихся вопросов технически возможно, но не только по
статическим архивам. Нужна среда, способная запускать оригинальный 32-битный
код, и набор эталонных наблюдений:
1. Изолированная 32-битная Windows VM или отдельная машина с исходными
DirectDraw/Direct3D/DirectSound/DirectPlay interfaces.
2. Два неизменённых игровых каталога и manifest SHA-256 для executable, DLL,
конфигураций и ключевых архивов.
3. Отладчик с hardware/software breakpoints, просмотром x87/SSE state и
сохранением memory dumps.
4. API/vtable hooking для Win32 file I/O, DirectDraw/Direct3D, DirectSound и
DirectPlay; hooks должны писать binary trace, не изменяя порядок вызовов.
5. Управляемые clocks, input log и RNG seed либо trace всех вызовов источника
случайности.
6. Автоматический launcher, который восстанавливает snapshot VM, запускает один
test case, собирает логи и завершает процесс без ручного вмешательства.
Для каждого capture сохраняются profile сборки, hash модулей,
mission/resource key, конфигурация, device profile, начальное состояние,
input/time script и версии инструментов.
### Критерий закрытия открытого вопроса
Для каждого открытого вопроса должны существовать:
- build fingerprint и адреса наблюдаемых функций;
- raw trace и автоматический parser trace-а;
- минимальный воспроизводимый input/resource/save/message;
- формальный контракт или явно ограниченная гипотеза;
- differential test для Частей 1 и 2, если модуль изменён;
- обновление тематической статьи;
- regression case, запускаемый без ручного анализа.
До выполнения этих условий статический контракт пригоден для реализации, но
утверждение о полном поведенческом или native-паритете не публикуется.
## Глоссарий
### Бинарные файлы и reverse engineering
**PE (Portable Executable)** -- формат исполняемых файлов Windows: EXE и DLL.
Он содержит заголовки, секции, таблицы импортов и экспортов, relocations и
адрес точки входа.
**Image base** -- предпочтительный адрес начала загруженного PE-образа.
**VA** -- виртуальный адрес в процессе. **RVA** -- адрес относительно image
base. Адрес функции в памяти обычно равен `image_base + RVA`.
**Import** -- внешняя функция или переменная, которую модуль получает из другой
DLL. **Export** -- символ, предоставляемый другим модулям. Имя, ordinal и
calling convention вместе образуют часть бинарного контракта.
**ABI** -- соглашение о двоичном взаимодействии: размещение аргументов, возврат
значений, очистка stack, layout структур, порядок virtual methods и правила
владения.
**Calling convention** -- часть ABI, определяющая передачу аргументов и очистку
stack. Для исследованного 32-битного кода важны `__cdecl`, `__stdcall` и
`__thiscall`.
**Vtable** -- массив указателей на virtual methods C++-объекта. Запись
`vtable +0x34` означает вызов указателя по байтовому смещению `0x34` от начала
таблицы.
**Static analysis** исследует файл без его исполнения: disassembly, strings,
imports, call graph и data flow. **Dynamic analysis** наблюдает работающую
программу: breakpoints, traces, API hooks, memory state и packet/frame captures.
**Evidence** -- наблюдение, которое можно повторить. **Inference** -- вывод,
объединяющий несколько наблюдений. **Hypothesis** -- рабочее предположение, ещё
не подтверждённое достаточным экспериментом.
### Форматы данных и ресурсы
**Archive** -- контейнер, объединяющий множество ресурсов. **Entry** -- запись
его каталога. **Payload** -- полезные bytes конкретной записи.
**Magic** -- короткая сигнатура формата, например `NRes` или `Texm`.
**Version** -- номер варианта layout. Проверка одной magic без проверки version
и размеров недостаточна.
**Offset** -- положение данных относительно начала файла или структуры.
**Size** -- число занимаемых bytes. **Stride** -- размер одного элемента
массива. **Alignment** -- требование начинать данные на address или offset,
кратном заданному числу.
**Little-endian** -- порядок, в котором младший byte многобайтного числа
расположен первым. Все основные числовые поля исследованных форматов Iron3D
используют этот порядок.
**Fixed-size string** -- поле заранее известной длины. Полезная строка
заканчивается первым NUL, но оставшиеся bytes поля могут содержать служебный
хвост и должны сохраняться.
**Opaque field** -- поле с доказанными offset и размером, но не установленным
предметным смыслом. Его безопасно читать и копировать, но нельзя очищать или
переосмысливать без эксперимента.
**Invariant** -- условие, которое обязано выполняться: диапазон находится
внутри payload, индекс указывает на существующий элемент, число записей
соответствует размеру секции.
**Strict reader** отклоняет любое нарушение контракта. **Compatibility reader**
дополнительно воспроизводит только известные особенности оригинала, например
именованный fallback. Compatibility mode не означает игнорирование произвольной
порчи.
**Roundtrip** -- последовательность decode -> encode. **Byte-identical
roundtrip** создаёт файл, полностью совпадающий с исходным. **Lossless editor**
может изменить известное поле, сохранив все остальные bytes и порядок записей.
**Fallback** -- явно предписанный запасной путь, например материал `DEFAULT`,
затем entry 0. **Heuristic** -- догадка по похожим данным; она не должна
незаметно заменять доказанный fallback.
### Игровой runtime
**Engine** -- программная среда, которая загружает данные, ведёт время,
исполняет мир и формирует изображение/звук. **Game** -- конкретные правила,
миссии и содержимое, работающие поверх engine services.
**World** -- долгоживущее состояние миссии: objects, terrain, время, кланы и
managers. **Scene** -- представление части мира для конкретной обработки, чаще
всего текущей камеры.
**Game object** -- сущность с идентичностью, transform, properties и lifecycle.
**Component/controller** -- специализированная часть поведения: animation,
physics, AI или rendering representation.
**Simulation** отвечает за изменение мира. **Tick** -- один расчётный шаг
simulation. **Frame** -- одно подготовленное изображение. Число ticks и frames
за единицу времени не обязано совпадать.
**Game loop** -- повторяющийся порядок ввода, расчёта, рендера и обслуживания.
**Scheduler phase** -- явно ограниченный участок loop, где разрешены
определённые операции.
**Event/message** -- типизированное сообщение между objects или subsystems.
**Queue traversal** -- стабильный обход зарегистрированных объектов.
**Deferred deletion** -- перенос фактического удаления до безопасной границы
после traversal.
**Determinism** -- одинаковый результат при одинаковом initial state, input,
времени и порядке событий. **Replay** -- повторное исполнение записанной
последовательности входов/сообщений для проверки determinism.
**Authority** -- subsystem или network peer, которому разрешено окончательно
менять состояние объекта. **Mirror object** -- локальное представление объекта,
authority которого находится у другого player.
### Геометрия, анимация и рендеринг
**Mesh** -- набор vertex/index streams и draw-групп, описывающий форму.
**Node** -- элемент hierarchy модели со своим local transform. **Slot** в MSH
-- выбранная геометрическая группа для комбинации node, LOD и group; он также
хранит bounds и диапазоны batches.
**Batch** -- непрерывный индексный диапазон с одним material slot и общим
render state. **Transform** переводит данные между local, world, view и clip
spaces. Порядок умножения matrices является частью контракта.
**Quaternion** -- четырёхкомпонентное представление вращения. **Keyframe** --
pose в определённое время. **Sampling** выбирает pose для времени, а
**blending** смешивает animation states.
**Bounds** -- упрощённый объём для быстрых тестов. **AABB** -- пара
minimum/maximum по осям. **Bounding sphere** -- center и radius.
**Renderer** -- subsystem, преобразующая подготовленную сцену в изображение.
**Backend** -- реализация renderer поверх конкретного API или устройства.
**Draw call** -- команда нарисовать диапазон primitives с текущими resources и
states. **Material** -- правила отображения поверхности: texture, коэффициенты,
прозрачность и режимы pipeline. **Material phase** -- одно временное состояние
анимированного материала.
**Texture** -- двумерный массив texels. **UV coordinates** -- координаты
выборки. **Mip chain** -- последовательность уменьшенных уровней texture.
**Lightmap** -- texture с заранее рассчитанным вкладом освещения.
**Fixed-function pipeline** -- старый графический pipeline, где приложение
выбирает predefined transform, lighting, texture-stage и blend states вместо
пользовательских shaders.
**Depth buffer** хранит глубину уже принятой поверхности. **Alpha test**
полностью принимает или отвергает fragment. **Blending** смешивает новый цвет с
framebuffer.
**Back buffer** -- скрытый framebuffer. **Present/flip** делает завершённый
кадр видимым. **Pixel parity** -- совпадение конечного изображения при
фиксированных условиях.
### Навигация, физика, звук и сеть
**Areal** -- логическая область карты с границей, class/flags и связями с
соседями. **Areal graph** -- граф, вершинами которого служат области, а рёбрами
-- допустимые переходы. **Cell grid** -- пространственный индекс для candidate
areas или objects.
**Pathfinding** -- поиск маршрута по графу. **A\*** использует стоимость уже
пройденного пути и оценку расстояния до цели. Навигационная проходимость,
отсутствие collision и видимость -- разные свойства.
**Collision proxy** -- упрощённое представление объекта для столкновений.
**Broad phase** быстро находит потенциальные пары; **narrow phase** выполняет
точную проверку и вычисляет contact.
**Sample** -- декодированные звуковые данные. **Source** -- экземпляр
воспроизведения с position, gain, loop state и временем. **Listener** -- позиция
и ориентация слушателя для 3D spatialization.
**Transport** -- механизм доставки bytes между peers. **Protocol** -- framing,
message types, порядок и правила подтверждения. **Serialization** --
преобразование typed state в byte sequence.
**Reliable delivery** гарантирует доставку/порядок в пределах выбранной модели;
**unreliable delivery** допускает потери ради задержки. **Wire compatibility**
-- способность обмениваться данными с оригинальным клиентом, а не только
воспроизводить ту же игровую семантику в новом протоколе.
## Связанные локальные справки
- [NRes](../reference/nres.md)
- [RsLi](../reference/rsli.md)
- [TMA](../reference/tma.md)
- [MSH](../reference/msh.md)
- [Texm](../reference/texm.md)
- [Materials](../reference/materials.md)
- [Render frame](../reference/render-frame.md)
- [Границы знания](../appendices/knowledge-boundaries.md)
- [Глоссарий](../appendices/glossary.md)
## Дополнительное чтение
Эти материалы помогают понять PE, ABI, сжатие, graphics pipeline, game loop и
навигацию. Они не являются доказательством поведения Iron3D: детали движка
принимаются только после проверки его бинарного кода и игровых ресурсов.
- [Microsoft PE/COFF specification](https://learn.microsoft.com/en-us/windows/win32/debug/pe-format)
- [Microsoft x86 calling conventions](https://learn.microsoft.com/en-us/cpp/build/x86-calling-conventions)
- [Intel Software Developer Manuals](https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html)
- [Ghidra documentation](https://ghidra-sre.org/)
- [RFC 1951: DEFLATE](https://www.rfc-editor.org/rfc/rfc1951)
- [zlib manual](https://zlib.net/manual.html)
- [Kaitai Struct user guide](https://doc.kaitai.io/user_guide.html)
- [Microsoft Direct3D documentation](https://learn.microsoft.com/en-us/windows/win32/direct3d)
- [Vulkan specification](https://registry.khronos.org/vulkan/specs/1.4-extensions/html/vkspec.html)
- [Real-Time Rendering resources](https://www.realtimerendering.com/)
- [LearnOpenGL](https://learnopengl.com/)
- [Scratchapixel](https://www.scratchapixel.com/)
- [Game Programming Patterns](https://gameprogrammingpatterns.com/)
- [Fix Your Timestep](https://gafferongames.com/post/fix_your_timestep/)
- [Red Blob Games: A*](https://www.redblobgames.com/pathfinding/a-star/introduction.html)
[Глоссарий](../appendices/glossary.md),
[открытые вопросы](../appendices/knowledge-boundaries.md),
[сценарная VM](../appendices/script-vm.md),
[сохранения и кампания](../appendices/saves-campaign.md),
[интерфейс игры](../appendices/ui-shell.md).