1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
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. Что должна сделать реализация, если правило нарушено?
Если на один из вопросов нет ответа, утверждение остаётся согласованным выводом
или открытым вопросом, а не закрытым контрактом.
|