docs: rewrite MkDocs documentation
This commit is contained in:
@@ -0,0 +1,371 @@
|
||||
# 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 и связи с объектом мира.
|
||||
|
||||
## Движок как программа длительного действия
|
||||
|
||||
Обычная прикладная программа получает запрос, вычисляет результат и заканчивает
|
||||
работу. Игра живёт в цикле: прочитать ввод, обновить состояние мира,
|
||||
сформировать звук и изображение, показать кадр и повторить. Движок -- набор
|
||||
подсистем и соглашений, которые делают этот цикл устойчивым.
|
||||
|
||||
**Simulation** отвечает на вопрос "что произошло в мире": куда переместился
|
||||
объект, кого он видит, сколько у него здоровья, сработал ли эффект, изменился
|
||||
ли маршрут или приказ. **Rendering** отвечает на другой вопрос: "как текущее
|
||||
состояние показать". В корректной архитектуре рендер не решает игровые правила,
|
||||
а читает подготовленное состояние.
|
||||
|
||||
**Tick** -- один шаг расчёта. **Frame** -- одно изображение. Они могут
|
||||
выполняться с разной частотой: игра способна рассчитать несколько шагов между
|
||||
двумя показами или временно не рисовать, не останавливая логику. Поэтому время,
|
||||
накопление input, порядок callbacks и момент удаления объектов считаются частью
|
||||
контракта.
|
||||
|
||||
## Мир, сцена и объект
|
||||
|
||||
**Мир** -- долгоживущее состояние миссии: ландшафт, объекты, время, погода,
|
||||
принадлежность к кланам и глобальные сервисы. **Сцена** -- представление той
|
||||
части мира, которую можно обработать для текущей камеры. **Игровой объект** --
|
||||
сущность с идентификатором, положением, набором свойств и поведением.
|
||||
|
||||
В Iron3D объектами управляет World3D. Объекты регистрируются в общей очереди,
|
||||
получают события, участвуют в расчёте и могут быть удалены отложенно, чтобы не
|
||||
разрушить обход коллекции посреди шага. Это важнее, чем конкретный контейнер в
|
||||
новой реализации: совместимость определяется моментом наблюдаемого добавления,
|
||||
обновления и удаления.
|
||||
|
||||
Мир не равен renderer scene graph. Один объект может иметь runtime state,
|
||||
controller, сетевой mirror, визуальную модель, collision bounds и script state.
|
||||
Часть этих данных нужна для gameplay, часть -- для вывода, часть -- для
|
||||
сохранения и воспроизведения.
|
||||
|
||||
## Ресурс, модель и материал
|
||||
|
||||
**Ресурс** -- именованный блок данных, который можно найти и загрузить. Архивы
|
||||
`NRes` и `RsLi` содержат таблицы таких блоков. Имя, индекс, размер, offset,
|
||||
compression method и fallback-правило являются частью контракта загрузки.
|
||||
|
||||
**Модель** описывает форму объекта. Она состоит из вершин, индексов, узлов,
|
||||
групп треугольников, слотов материалов и auxiliary streams. **Vertex** хранит
|
||||
положение и обычно дополнительные атрибуты: нормаль для освещения и
|
||||
UV-координату для выборки texture. **Triangle** -- три вершины, образующие
|
||||
примитив. **Index buffer** хранит номера вершин и позволяет переиспользовать их
|
||||
между треугольниками. **Batch** -- непрерывный диапазон индексов, который
|
||||
рисуется одним материалом и одним набором состояний.
|
||||
|
||||
**Материал** описывает способ отображения поверхности: texture references,
|
||||
цвет, прозрачность, режимы смешивания и анимацию параметров. **Texture** --
|
||||
изображение в памяти графической системы. **Mip-уровни** -- уменьшенные копии
|
||||
изображения для дальних объектов. **Lightmap** -- дополнительная texture с
|
||||
заранее рассчитанным освещением.
|
||||
|
||||
Runtime должен связывать эти уровни по цепочке: миссия выбирает объект, объект
|
||||
ссылается на prototype, prototype приводит к модели, модель -- к WEAR,
|
||||
материалам, textures и lightmaps. Ошибка на любом участке этой цепочки может
|
||||
не проявиться в parser-е, но проявится в игровом кадре.
|
||||
|
||||
## Пространственные понятия
|
||||
|
||||
**Transform** переводит точку из локальных координат модели в координаты мира,
|
||||
камеры и экрана. **Иерархия узлов** позволяет одному элементу наследовать
|
||||
движение другого. **LOD** выбирает менее подробную геометрию вдали. **Culling**
|
||||
отбрасывает то, что не видно. **Bounds** -- упрощённая оболочка объекта,
|
||||
обычно сфера или AABB, используемая для быстрых тестов.
|
||||
|
||||
**Collision** отвечает на геометрические пересечения. **Navigation** ищет
|
||||
допустимый маршрут. В Iron3D эти задачи разделены: Control обслуживает
|
||||
физическую модель и столкновения, а ArealMap хранит пространственные области и
|
||||
связи между ними.
|
||||
|
||||
Важно не смешивать визуальные и игровые упрощения. Render bounds могут быть
|
||||
достаточны для отсечения, но не обязаны совпадать с collision shape. Навигация
|
||||
может использовать areal graph, который не является ни mesh-ем модели, ни
|
||||
геометрией ландшафта в renderer-е.
|
||||
|
||||
## Графический конвейер
|
||||
|
||||
Процессор выбирает видимые объекты, готовит матрицы, материалы и списки
|
||||
примитивов. Графический backend передаёт вершины, индексы, textures и state
|
||||
драйверу. Видеокарта преобразует вершины в координаты экрана, разбивает
|
||||
треугольники на фрагменты, проверяет глубину, смешивает цвет и записывает
|
||||
результат в буфер кадра. После завершения буфер становится видимым
|
||||
пользователю.
|
||||
|
||||
Для совместимости важны не только данные draw call. Контракт включает frame
|
||||
boundaries, viewport, camera state, порядок world traversal, material resolve,
|
||||
shadow/transparent/FX subpasses, завершение renderer-а, восстановление state и
|
||||
callbacks после рендера. Если часть имён vtable slots ещё не доказана, новая
|
||||
реализация должна фиксировать крупный порядок операций и оставлять
|
||||
детализацию проверяемой.
|
||||
|
||||
## Практический словарь реализации
|
||||
|
||||
**Handle** -- компактная ссылка на управляемый объект. **Cache** -- сохранённый
|
||||
результат загрузки или декодирования. **Reference count** -- число владельцев
|
||||
ресурса. **Fallback** -- предписанный запасной вариант при отсутствии данных.
|
||||
**Invariant** -- условие, которое всегда должно быть истинным для корректного
|
||||
файла или runtime-состояния. **Determinism** -- повторяемость результата при
|
||||
одинаковых входных данных и порядке событий.
|
||||
|
||||
**Strict mode** -- режим parser-а, который принимает только корректный файл:
|
||||
верные magic, версии, размеры, ranges, индексы и точный EOF. **Lossless mode**
|
||||
-- режим чтения/записи, который сохраняет неизвестные поля, padding, gaps и raw
|
||||
payload без нормализации. **Quirk** -- именованное отклонение, разрешённое
|
||||
только после проверки на реальных данных или исполняемом коде.
|
||||
|
||||
Эти слова используются как технические термины. Если глава называет значение
|
||||
fallback-ом, invariant-ом или quirk-ом, это должно иметь проверяемое
|
||||
последствие в reader-е, writer-е или runtime.
|
||||
|
||||
## Как читать C/C++-схемы структур
|
||||
|
||||
Структуры в главах описывают байтовый layout, а не переносимый C++ object
|
||||
model. Если поля на диске идут без padding, reader должен читать их по offsets
|
||||
либо использовать явно проверенный packed layout. Прямое отображение native
|
||||
struct допустимо только при доказанном размере, выравнивании и endian-правиле.
|
||||
|
||||
`sizeof` обязательно проверяется `static_assert` или эквивалентным compile-time
|
||||
test. Это особенно важно для records, где 32-битное поле начинается после
|
||||
нечётного числа 16-битных или 8-битных полей: стандартное выравнивание
|
||||
современного compiler-а может вставить скрытые bytes и изменить offsets.
|
||||
|
||||
Для variable-length форматов предпочтителен bounded cursor:
|
||||
|
||||
1. Прочитать header и проверить минимальный размер.
|
||||
2. Проверить, что offsets и sizes лежат внутри текущего блока.
|
||||
3. Прочитать таблицы до объявленного count, не до "пока получается".
|
||||
4. Проверить ссылки между таблицами.
|
||||
5. Дойти до точного EOF или сохранить явно разрешённый trailing payload.
|
||||
|
||||
Writer пересчитывает только производные значения: размеры, offsets, число
|
||||
записей, сортировочные таблицы и 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. Что должна сделать реализация, если правило нарушено?
|
||||
|
||||
Если на один из вопросов нет ответа, утверждение остаётся согласованным выводом
|
||||
или открытым вопросом, а не закрытым контрактом.
|
||||
Reference in New Issue
Block a user