# 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.