Files
fparkan/docs/tomes/06-behavior.md
T

770 lines
41 KiB
Markdown
Raw Normal View History

2026-06-22 01:58:51 +04:00
# 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.