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
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
|
# VI. Поведение, управление, звук и сеть
Шестой том описывает подсистемы, которые превращают загруженный мир в
реагирующую игру: AI, Behavior, Wizard, Control, ввод, камеру, звук и сеть.
Эти области нельзя восстанавливать только по структуре файлов. Для них важны
порядок кадра, ownership объектов, timing событий и доказуемые границы между
решением, движением, presentation и транспортом.
Ключевой принцип: reader compatibility не равна gameplay compatibility.
Корректно разобранный ресурс ещё не доказывает, что runtime выбирает ту же
цель, строит тот же маршрут, применяет ту же collision correction, создаёт тот
же sound event или отправляет тот же network payload. Поэтому все утверждения
ниже разделяют подтверждённую структуру, восстановленный архитектурный
контракт и открытые участки, требующие динамической трассировки.
```text
AI / mission script
-> стратегическая цель, условия, команды миссии
Behavior
-> состояние объекта, target, global/local path
Wizard
-> локальная коррекция траектории
Control
-> physical step, collision proxy, итоговый transform
World3D
-> очередь событий, ownership, deferred deletion
Render / Sound / Net
-> представление, listener, mirrors и сообщения
```
Связанные главы: [мир и миссии](04-world.md), [геометрия и рендер](05-render.md)
и справочный [render frame](../reference/render-frame.md).
## AI, Behavior и Wizard
Iron3D разделяет стратегическое принятие решений, поведение конкретного объекта
и локальную коррекцию движения. Это разделение должно сохраниться в новой
реализации: стратегический AI не меняет transform напрямую, а collision manager
не выбирает игровую цель.
```text
ai.dll / SuperAI
-> цель клана, миссии и группы
Behavior.dll
-> состояние юнита, target, global path, local corridor
Wizard.dll
-> ближайшая допустимая траектория
Control.dll
-> физическое движение и столкновения
```
### Behavior
`CreateBehaviour` создаёт controller для отдельного игрового объекта.
`CreateDistributor` восстановлен по consumers как посредник распределения
команд или ресурсов; это высокоуверенный архитектурный вывод, а не доказанное
имя внутреннего класса. Behavior получает `IArealMap` через AI/клановый
контекст, ведёт radar/target state, строит global path, превращает его в local
corridor и передаёт движение Wizard.
Ошибочные состояния проверяются явно:
1. отсутствует system map;
2. отсутствует terrain interface;
3. active behavior не имеет `IArealMap`;
4. объект попал в non-reachable area;
5. объект пытается выйти из non-walkable area;
6. path generator вошёл в infinite cycle.
Эти случаи являются fatal или diagnostic conditions. Совместимая реализация не
должна тихо исправлять их teleport-ом, потому что такое исправление скрывает
ошибку areal graph, terrain query или state machine.
### Параметры Behavior.ini
Подтверждены настройки:
```text
PathFind_BuildingHitDist
PathFind_BuildingNearestDist
PathFind_NearBuildSpeedPercent
PathFind_CorridorRadius
PathFind_NearDoorCoeff
PathFind_fStepOffBuilding
PathFind_MaxAccel
PathFind_MaxRotation
PathFind_fStepDist
PathFind_MinPointInTrajectory
Network_ResourceTransferMaxDelay
```
Они задают геометрию corridor, дистанции реакции на здания, снижение скорости
возле препятствий, пределы ускорения и поворота, дискретизацию trajectory и
сетевой timeout передачи ресурсов. Значения читаются как runtime-конфигурация,
а не компилируются в код. Parser должен поддерживать комментарии `//`, пробелы
вокруг `=` и CRLF.
Файл также содержит logging/debug switches: `Behavior.log`, уровни ошибок,
show vectors и z-buffer debug. Эти переключатели полезны не только для
совместимости, но и как модель современных trace flags.
### Wizard
Wizard получает желаемое направление и corridor, анализирует ближайшие
ограничения и выдаёт скорректированную локальную траекторию. Behavior может
очищать её через `ClearWizardPath` при смене цели, повреждении global path или
переходе объекта в неактивное состояние.
Нужно различать четыре уровня движения:
- **global path** -- последовательность areals;
- **local path** -- точки или сегменты внутри corridor;
- **wizard path** -- краткосрочное движение с учётом ближайших препятствий;
- **physical step** -- фактически разрешённое Control перемещение.
Хранение всего маршрута одним массивом лишает систему возможности локально
обойти препятствие без полного повторного поиска. Граница Behavior/Wizard
существует именно для того, чтобы краткосрочная геометрическая коррекция не
ломала стратегический path state.
### SuperAI и миссионные сценарии
`CreateSuperAI` создаёт центральный controller клана; `GetSuperAI` возвращает
его. AI загружает файлы из `MISSIONS\SCRIPTS\`, проверяет версию и пишет ошибки
в `ai.log`. Несовпадение версии является отдельной ошибкой, а не неизвестной
командой.
Сценарный корпус содержит binary `.scr`, formula exports `.fml`, таблицу
переменных `varset.var` и `.trf`-данные. `.scr` хранит именованные секции и
события, например `Init`, `Mission`, `Problems0`, `Fort_Task_Complete` и
`Hero_Teleported`, вместе с числовыми ссылками на compiled instructions.
`.fml` является текстовым экспортом formula set. `varset.var` декларативно
описывает типы, defaults, ranges и строки через макросоподобные формы
`VAR(...)` и `STRING(...)`.
Безопасная runtime-модель:
```text
load script bundle
-> validate version and symbol tables
-> create global/formula variables
-> bind named events to instruction offsets
-> instantiate SuperAI per clan
-> dispatch MISSION_START and object events
-> update timers/conditions each simulation tick
-> enqueue game commands through World3D/Behavior
```
Сценарий не должен владеть игровым объектом напрямую. Он хранит logical/object
IDs и отправляет команды через игровые interfaces, чтобы удаление объекта или
сетевой mirror не оставили dangling pointer.
Полная grammar compiled instructions и точное значение всех opcodes остаются
открытым направлением. До появления decompiler-а `.scr` binary body сохраняется
lossless, а доказанные symbol/event tables документируются отдельно.
### TRF и preload-данные
TRF-файлы проходят структурный разбор. `auto.trf`, `data.trf` и tutorial
variants имеют сигнатуру [NRes](../reference/nres.md) и содержат большие
таблицы имён игровых прототипов: оружия, башен, сооружений и других объектов.
Также найдены preload-записи, ANI и SKE resources.
По содержимому, порядку загрузки и consumers TRF с высокой вероятностью
предоставляет AI/сценарному слою заранее подготовленную таблицу типов и
связанных данных. Framing и имена подтверждены corpus-ом, но полная семантика
каждой TRF-записи ещё не закрыта. Имена должны разрешаться через тот же
resource registry, что и миссионные объекты.
### Стабильность AI-слоя
`ai.dll`, `Behavior.dll` и `Wizard.dll` побайтно идентичны в Частях 1 и 2. Это
подтверждает, что разделение SuperAI -> Behavior -> Wizard и бинарная
реализация этих трёх уровней не менялись.
Сценарный корпус:
```text
Часть 1: 58 SCR, 58 FML, 29 TRF
Часть 2: 59 SCR, 59 FML, 44 TRF
```
Все TRF являются структурно валидными NRes. Неизменность DLL усиливает вывод о
стабильной VM, но не закрывает instruction grammar `.scr`: для неё нужен
dispatcher/jump-table decompiler. Дополнительные сценарные данные расширяют
differential corpus, но не заменяют анализ VM.
## Control, физика и коллизии
Control превращает желаемое движение в физически допустимое изменение
состояния. World3D владеет жизненным циклом объекта; Terrain предоставляет
поверхность и world queries; Behavior/Wizard задают намерение; Control создаёт
physical controller и collision representation.
Публичная поверхность:
```text
InitializeSettings
LoadControlSystem
LoadPhysicalModel
CreateCollManager
CreateCollObject
```
Модуль импортирует World3D queue/object functions, `Terrain::GetWorld`, часы,
тригонометрию и `g_FastProc`. Это подтверждает его положение между gameplay
object и геометрией мира.
### Control system и physical model
`LoadControlSystem` загружает настройки controller-а: ограничения скорости,
ускорения, поворота и режимы управления. `LoadPhysicalModel` загружает форму и
параметры, используемые для столкновений. Visible MSH не обязан совпадать с
collision representation: для физики часто нужна более простая и устойчивая
форма.
Практичная runtime-модель:
```c
struct PhysicalState {
Transform transform;
Vec3 linear_velocity;
Vec3 angular_velocity;
float requested_speed;
float requested_turn;
uint32_t flags;
};
struct CollisionProxy {
ObjectId owner;
ShapeSet shapes;
Bounds broad_phase_bounds;
uint32_t category_mask;
};
```
Названия полей здесь описывают контракт совместимой реализации, а не точный
layout исходного C++-объекта.
### Collision pipeline
Один расчётный шаг удобно разделить так:
1. controller получает желаемые `speed`/`turn` от Behavior или manual input;
2. вычисляет кандидатный transform на основе `dt`;
3. обновляет broad-phase bounds collision object;
4. collision manager находит потенциальные пары и terrain candidates;
5. narrow phase вычисляет контакт или допустимый остаток перемещения;
6. physical state корректируется;
7. World3D получает итоговый transform;
8. событие `GMSG_COLLISION_DETECTED` отправляется в согласованной фазе.
Позиция collision event после narrow phase является рекомендуемой фазой
реализации и согласуется с назначением сообщения, но точный call-site
относительно всех correction steps требует динамической трассировки Control.
Удаление объекта из обработчика остаётся отложенным по правилам World3D.
Collision manager не должен хранить прямую незащищённую ссылку на объект,
который уже pending-delete.
### CTLD и physical resources
Реестр прототипов ссылается на `*.ctl`, `*.cpt` и связанные control resources.
В Части 1 структурно проверен 531 CTLD payload без ошибок. Размеры и пять
внутренних счётчиков образуют множество вариантов: наиболее частый размер
392 байта с pattern `(0,0,0,1,0)`, но встречаются блоки от примерно 212 до
1868 байт и более сложные комбинации.
CTLD является составным count-driven форматом, а не фиксированной struct.
Parser должен:
- прочитать prefix и все счётчики с проверкой переполнения;
- вычислить границы секций по их counts;
- сохранять неизвестные records в typed raw containers;
- требовать точного завершения payload;
- не использовать размер одного популярного варианта как универсальный layout.
Полная предметная семантика всех секций ещё не доказана, но существующие файлы
можно безопасно читать, индексировать и сохранять.
### Terrain queries и movement handoff
Control получает world-interface Terrain и использует поверхность, faces и
ускорители для высоты, нормали и пересечений. Навигационный маршрут сообщает,
куда двигаться, но итоговый transform определяется по физической поверхности.
При переходе через склон controller должен согласовать горизонтальный шаг,
высоту и ориентацию с terrain normal.
Порядок операций должен быть детерминированным: пары collision objects
сортируются по стабильному ID, contacts обрабатываются в фиксированной
последовательности, а интеграция использует одну политику `dt` и округления.
Иначе одинаковая миссия постепенно расходится даже без сети.
### Различия Control в Части 2
`Control.dll` пересобрана при неизменных размере, imports и пяти именах/ordinals
exports; RVA всех пяти exports изменились. Форматы и cross-module boundary
сохранились, но точное physical/collision behavior нельзя считать побайтно тем
же.
CTLD-корпус расширен с 531 до 623 payload. Новых framing errors не найдено;
большинство общих CTLD изменено вместе с переработанными моделями. Это
подтверждает count-driven parser, но не закрывает предметную семантику shape
records и contact solver.
Differential test обеих частей должен воспроизводить движение без препятствий,
slope following, pair collision, timing collision event и удаление объекта в
callback. Сравниваются transforms и contact events по tick, а не только факт
успешной загрузки.
## Ввод, камера и управление
World3D нормализует клавиатуру, мышь и joystick в общие scan codes и manual
commands. Win32 message handler вызывает `UpdateManualEventsList`; перед
обработкой новой порции сообщений основной цикл вызывает
`ClearManualEventsList`. Снимок клавиатуры очищается отдельно через
`stdClearKeyboard`.
Публичная поверхность включает `WinMsg2ScanCode`, converters для
keyboard/mouse/joystick/predicate, `ScanCode2Str`, `ManualCommand2Str`,
`stdIsKeyPressed`, lock/unlock keyboard и чтение mouse shift. Это позволяет
хранить конфигурацию управления независимо от физического устройства.
### Event, state и axis
Ввод имеет минимум три семантики:
- **edge event** -- нажатие или отпускание в текущей порции сообщений;
- **held state** -- клавиша остаётся нажатой между кадрами;
- **analog value** -- смещение мыши или положение joystick axis.
Manual command дополняет источник коэффициентом, режимом wrap, dead
zone/threshold и временной характеристикой. Строки camera bindings показывают
команды `MCMD_STATE`, `MCMD_ANGLE_X`, `MCMD_ANGLE_Y`, режимы `MAN_WRAP` и
`MAN_NOTWRAP`, а также параметры ускорения в миллисекундах.
Simulation читает подготовленный input snapshot. Renderer не должен
самостоятельно опрашивать OS, иначе одно и то же нажатие будет зависеть от
частоты кадров.
### Joystick через DirectInput
`Joystick.dll` экспортирует:
```text
QueryJoy
CreateJoy
ReleaseJoy
SetJoyRange
PeekJoyMessage
GetJoyCaps
```
`QueryJoy` обнаруживает устройство, `CreateJoy` получает интерфейс DirectInput,
`SetJoyRange` нормализует оси в диапазон движка, `PeekJoyMessage` выдаёт
очередное унифицированное событие.
При потере устройства чтение может вернуть ошибку acquired state. Интерфейс
следует повторно получить, очистить устаревшее состояние и продолжить.
Hot-unplug не должен оставлять последнюю ось навсегда отклонённой.
`GetInstalledJoyNames` и `SetActiveJoy` в World3D связывают device list с
game-facing выбором.
### Два camera interface
World3D предоставляет `stdSetCurrentCamera`/`stdGetCurrentCamera`: это камера
как часть игрового состояния. Terrain имеет
`stdSetCurrentCamera2`/`stdGetCurrentCamera2`: concrete camera, которую world
renderer использует для matrices, viewport и visibility.
`LoadCamera` экспортирован обоими модулями. По call graph World3D-вариант
играет роль component bridge, а Terrain-вариант связан с concrete
camera/world implementation. Это архитектурный вывод: точные class names и
layout не восстановлены.
Минимальные данные камеры:
```text
world position and orientation
view matrix
projection parameters / field of view
near and far planes
viewport rectangle
camera mode and target object
manual angles/state
```
Такая граница позволяет game code работать с абстрактной камерой, не зная
внутреннего renderer representation.
### Camera commands и порядок кадра
Подтверждены команды `CMD_CAMERA_LEFT`, `CMD_CAMERA_RIGHT`, `CMD_CAMERA_UP`,
`CMD_CAMERA_DOWN`, `CMD_CAMERA_CENTER`, `CMD_CAMERA_INFRARED`, а также
spotlight и внешние/миссионные camera modes. Горизонтальный угол использует
wrap, вертикальный -- ограниченный диапазон. Center плавно возвращает обе оси к
заданному значению.
Порядок кадра:
1. собрать manual events;
2. обновить camera controller во время calculation;
3. вычислить итоговый transform и ограничения;
4. перед render установить current camera;
5. передать её Terrain и sound listener;
6. после кадра сохранить mode-specific state.
Camera smoothing должно использовать игровое время или специально
подтверждённые часы. Привязка к render delta делает управление разным при 30 и
144 FPS.
## Звуковая подсистема
Ngi32 создаёт низкоуровневый DirectSound backend. `services.dll` публикует
`ISoundServer`. Game, Terrain и FX работают уже через эти интерфейсы:
воспроизводят 2D/3D sources, меняют volume и связывают listener с camera.
Публичные функции Ngi32:
```text
niCreate3DSound
niGet3DSound
niGet3DSoundCaps
niMuteSound
```
Backend динамически вызывает `DirectSoundEnumerateA` и `DirectSoundCreate`;
параметр `DisableDSound` может полностью отключить этот путь.
### Устройство и capabilities
Конфигурация учитывает `3D Sound`, качество, reverse sound, частоту buffer,
режим постоянного воспроизведения и автоматический выбор лучшего устройства.
Эти значения преобразуются во внутренний capability/profile object до создания
sources.
Код содержит отдельный no-device state и строку `3D Sound was not initialized`.
Отсутствие 3D sound обрабатывается отдельно от ошибок simulation/resources.
Новый runtime не должен позволять отсутствию звука разрушать simulation и
обязан возвращать звуковым командам явный no-device result.
Общий sound object разделяется между подсистемами и использует счётчик
владельцев. Закрывать DirectSound следует после остановки всех sources и
atmosphere/FX managers.
### Sound resources и SWAV
Основная библиотека называется `sounds.lib`; `mission.cfg` также создаёт
именованные sound resources и variations. Legacy API `rsLoadWave` загружает
waveform из archive. Импорт `MSACM32` подтверждает путь преобразования сжатых
wave-данных в формат playback buffer.
Resource identity состоит из library и name. Один sound asset может иметь
несколько runtime sources с различными position, volume, pitch/flags и временем
запуска. Поэтому кэшировать следует decoded sample/buffer, а source object
создавать на событие.
FX opcode 2 хранит `archive[32] + name[32]` и обычно создаёт sound command.
Atmosphere использует отдельные loop/variation sources, например rain
background. Миссионный слой содержит voice events для завершения или провала
задания.
Проверенный SWAV-корпус:
```text
Часть 1: 399 — 306 MS ADPCM, 93 PCM
Часть 2: 540 — 446 MS ADPCM, 93 PCM, 1 empty entry
```
Все непустые записи имеют RIFF/WAVE framing и частоту 22 050 Hz. В Части 2
entry `ALIEN_ME.WAV` имеет размер 0. Это присутствующий archive key без
decodable waveform.
Sound loader должен различать:
- `entry_missing`;
- `entry_empty`;
- `wave_invalid`;
- `decoded_sample`.
Нулевой payload не передаётся RIFF parser-у и не должен приводить к чтению
header за границей.
### 3D listener и sources
Перед world traversal `stdRenderGame` обновляет listener из camera transform.
Listener содержит position, orientation и, при наличии, velocity. Source
содержит world position и параметры затухания. Spatialization выполняется
backend-ом либо совместимой программной моделью.
```text
camera transform
-> listener position/front/up
object or effect transform
-> source position
sample + source parameters
-> DirectSound 3D buffer
```
Прямо подтверждено обновление listener в начале `stdRenderGame`, до world
traversal. Sound events могут создаваться и в calculation/FX path, поэтому
нельзя утверждать, что listener предшествует созданию каждого source. Важно,
что spatial backend получает camera state текущего отображаемого кадра до
завершения его обработки. Перенос listener update после world render создаст
как минимум однокадровое рассогласование presentation.
### Громкость, mute и CD-аудио
`iron3d.dll` применяет отдельные настройки эффектов и CD sound. Параметр
`FORCE_CD_SOUND` меняет политику выбора музыкального источника. `niMuteSound`
должен временно остановить вывод без разрушения sample cache и logical playback
state.
В новой реализации полезно разделить buses: master, effects, ambient, voice и
music/CD. Это проектное решение совместимого backend-а, а не доказанный layout
оригинального mixer-а. Оно позволяет применять старые коэффициенты, не
переписывая individual source volume.
### Граница service layer
`Ngi32.dll` с DirectSound/backend code не изменилась между Частями 1 и 2, но
`services.dll` пересобрана и уменьшилась на 4 096 байт. Поэтому low-level
decoder/device path подтверждается одной машинной реализацией, а service
lifecycle, GUI/audio wiring и defaults требуют раздельной трассировки обеих
частей.
## Сетевая подсистема
Net инкапсулирует DirectPlay4A и lobby/service-provider API. World3D строит над
транспортом player identity, mirror objects и игровые сообщения. Эти уровни
следует разделять: DirectPlay отвечает за доставку bytes между players,
World3D -- за смысл сообщения и владение объектом.
Application GUID:
```text
{3C1D1F01-A870-11D1-8400-000021B14415}
```
Он передаётся network instance и service layer. Экземпляры с другим GUID не
принадлежат одному логическому приложению.
### Lifecycle соединения
Публичные функции Net покрывают полный цикл:
```text
CreateNetworkInstance
-> select/use service provider
-> setup connection
-> enumerate or create session
-> join/create session
-> create local player
-> send/receive messages and player data
-> destroy player
-> close session
-> close connection
```
Поддерживаются providers эпохи DirectPlay: TCP/IP, IPX и modem/lobby варианты,
если они установлены в системе. Функции явно проверяют, что DirectPlay enabled
до enumeration, session и player operations. Неверный порядок вызовов должен
возвращать понятную ошибку, а не разыменовывать пустой interface.
### Sessions, players и адреса
Net предоставляет enumeration service providers и sessions, выбор host/join,
player name/password/data, latency, максимальный размер сообщения, размер
очереди, server player info и provider address. Lobby launch обрабатывается
отдельной веткой.
Внутренняя модель должна хранить как минимум:
```c
struct NetPlayer {
TransportPlayerId transport_id;
uint16_t game_player_number;
string name;
RawBytes player_data;
bool is_local;
bool is_host;
};
```
Transport ID нельзя использовать как постоянный `ObjectId`. NetWatcher связывает
временный DirectPlay identifier с номером игрока и World3D entities.
### Игровые сообщения World3D
Подтверждённые имена message surface:
```text
GMSG_CREATE_REMOTE_PLAYER
GMSG_APPEND_RESOURCE
GMSG_CHANGE_OBJECT_OWNER
GMSG_SET_PLAYER_DATA
GMSG_MISSION_DATA_PATH
GMSG_TAKE_OBJECT
GMSG_TEXT_FOR_PLAYER
GMSG_SYNC_STATE
GMSG_CREATE_MIRROR
GMSG_PAUSE_REMOTE_PLAYER
GMSG_CONFIRM_PLAYER_DATA
GMSG_KILL_PLAYER
SYSMSG_SET_TIME
SYSMSG_SET_PLAYER_NUMBER
GMSG_END_MESSAGE_SEQ
GMSG_REMOVE_RESOURCE
```
`GMSG_COLLISION_DETECTED` относится к общей очереди, но не обязательно
передаётся по сети. Message ID, payload size и delivery policy должны быть
частью явной schema. Нельзя сериализовать C++ pointers или native padding.
### Mirror objects и ownership
Удалённо принадлежащий объект представлен local mirror instance. Он участвует в
рендере и spatial queries, но authority над его созданием, ключевыми properties
и удалением находится у owner player. Сообщение смены владельца обновляет эту
границу; оно не должно создавать второй объект с тем же ID.
Типовой путь:
```text
remote create message
-> validate player and ObjectId
-> resolve prototype/resources
-> CreateMirrorObject
-> apply initial state
-> AddMirrorObjectToGame
-> subsequent sync messages update mirror
```
При потере player NetWatcher инициирует предписанное удаление или transfer
ownership через World3D queue. Мгновенное освобождение во время receive callback
запрещено по тем же причинам, что и в calculation pass.
### Сжатие и wire compatibility
`netZipData` и `netUnZipData` образуют встроенный слой упаковки payload. Он
находится выше транспорта: переход с DirectPlay на UDP/ENet не отменяет
необходимость воспроизводить формат упакованного сообщения, если требуется
соединение с оригинальной игрой.
Полный wire schema, framing и алгоритм сжатия пока не доказаны packet
capture-ом. Поэтому нужны два режима:
- **native compatibility** -- отдельный adapter, реализуемый после трассировки
оригинальных packets;
- **modern multiplayer** -- новая versioned protocol schema, использующая ту же
game-message семантику, но не заявляющая совместимость с DirectPlay client.
Эти режимы нельзя незаметно смешивать. До доказательства native wire
compatibility современный transport должен быть versioned и отделён от слоя,
который претендует на совместимость с оригинальным клиентом.
### Стабильность сетевого слоя
`Net.dll` и `World3D.dll` побайтно идентичны в обеих частях. Application GUID,
DirectPlay wrapper, mirror-object API и World3D message surface относятся к
одной машинной реализации.
Это подтверждает отсутствие отдельной сетевой реализации для Части 2, но не
закрывает wire schema: без packet/send-receive capture по-прежнему неизвестны
точное framing, reliability flags, payload layouts и алгоритм `netZipData` для
native interoperability.
Для binary regression достаточно одного профиля неизменённых DLL, но message
captures должны включать контент обеих частей, потому что prototype/resource IDs
и mission data различаются.
## Контракты реализации
Совместимая реализация должна фиксировать не только результат, но и момент его
появления в кадре. Для Behavior, Control, input, sound и network особенно важны
tick boundaries: одна и та же команда, применённая на один tick раньше или
позже, меняет дальнейшую симуляцию.
### Trace-события
Минимальный trace для этого тома:
- input snapshot: edge events, held state, analog values;
- camera state: mode, target, angles, matrices, viewport;
- Behavior: target, areal, global path revision, local corridor;
- Wizard: requested vector, constraints, wizard path;
- Control: candidate transform, contacts, correction, final transform;
- World3D queue: message name, ObjectId, dispatch phase, deferred deletion;
- sound: sample key, source owner, position, event tick, listener state;
- network: player mapping, message ID, payload length, delivery policy.
Для рендера это связывается с [render frame](../reference/render-frame.md):
camera и listener должны попадать в trace до world traversal, иначе нельзя
отделить ошибку presentation от ошибки управления.
### Проверки Behavior и сценариев
- script version mismatch даёт отдельную ошибку;
- event table читается lossless;
- VM body сохраняется без потери неизвестных bytes;
- отсутствующий `IArealMap` не замалчивается;
- non-walkable/non-reachable states дают diagnostic condition;
- одинаковый input log воспроизводит одинаковый sequence Behavior commands;
- resource names из TRF разрешаются через общий registry.
### Проверки Control
- движение без препятствий;
- slope/terrain-following;
- симметричные pair-collision tests с переставленными IDs;
- contact event отправляется один раз в предписанной фазе;
- удаление объекта в collision callback безопасно;
- replay одинакового input log даёт одинаковые transforms;
- collision proxy перестраивается после смены component/model state.
### Проверки input и камеры
- edge event не повторяется как held state;
- mouse/joystick axis сбрасывается по правилам snapshot;
- hot-unplug joystick не оставляет старое отклонение;
- camera horizontal angle wraps, vertical angle clamps;
- center command использует подтверждённое время, а не render FPS;
- Terrain и sound получают одну и ту же camera frame.
### Проверки звука
- backend может отсутствовать без нарушения simulation;
- один decoded sample переиспользуется несколькими sources;
- `entry_missing`, `entry_empty` и `wave_invalid` различаются;
- listener совпадает с camera frame;
- loop source корректно переживает pause/resume;
- mute не сбрасывает position и time;
- missing sound resource содержит полную диагностическую цепочку;
- deterministic test сравнивает список sound events, а не waveform устройства.
### Проверки сети
- нельзя создавать queue с активной сетью и нулевым player ID;
- session/player operations до enable/setup возвращают ошибку;
- сообщения проверяют длину до чтения payload;
- sequence/end markers обрабатываются в стабильном порядке;
- duplicate create mirror не создаёт второй instance;
- ownership change атомарно обновляет routing;
- pause/time messages применяются в одной simulation boundary;
- resource transfer имеет timeout `Network_ResourceTransferMaxDelay`;
- disconnect не оставляет objects с несуществующим owner;
- replay записанного message log даёт одинаковое World3D state.
`resnet.log` и `NetWatch.log` следует поддерживать как отдельные каналы: первый
относится к transport/resource exchange, второй -- к связи players и game
objects.
## Границы знания
Подтверждены внешние interfaces, часть runtime order, значимые строки,
конфигурационные параметры, corpus-level counts и стабильность ряда DLL между
двумя частями. Открытыми остаются:
- instruction grammar `.scr` и semantics всех VM opcodes;
- точная семантика всех TRF-записей;
- полный layout CTLD shape records;
- contact solver и порядок всех correction steps;
- class layout камер, контроллеров, sound service и network watcher;
- DirectPlay wire framing, reliability flags и payload schema;
- алгоритм `netZipData`/`netUnZipData`;
- точные defaults service layer там, где DLL пересобраны.
Эти границы должны оставаться видимыми в документации и тестах. Если новая
реализация вводит удобный современный abstraction layer, он обязан быть
отделён от утверждений о native compatibility и покрыт отдельным trace.
|