Решили: транспорт живёт за INetTransport, и за ним сразу два тела — LoopbackNetwork (несколько
пиров в одном процессе, без NGO и сцен) и ChaosTransport (порча канала по сиду). Отпечаток
совместимости — ContentFingerprint (хеш отсортированного набора id + версия сборки + версия схемы).
Пакет com.unity.multiplayer.tools 2.2.9 добавлен.
Почему свой chaos, а не Network Simulator от Unity: тот работает только с UTP, а релизный транспорт у нас Facepunch/Steam — но главное не это. Симулятор не даёт воспроизводимости: падение ловится ожиданием, пока сеть поведёт себя так же. Из сида история канала повторяется вызовом теста. Приём называется Deterministic Simulation Testing, и половина метода у нас уже стояла — детерминированное боевое ядро.
Почему MaxReliableMessageBytes торчит в интерфейсе: ниже нашего кода предел не проверяет никто
(FacepunchTransport отдаёт данные прямо в Connection.SendMessage, Steam режет на 512 КБ и возвращает
InvalidParam, который транспорт не читает). Loopback сознательно врёт тем же числом: шов, где в
тестах проходит то, что в игре уезжает в тишину, хуже отсутствующего.
Почему FNV-1a, а не string.GetHashCode: последний рандомизирован между запусками процесса, и
отпечаток на нём не совпал бы даже у одной сборки с самой собой. Набор id сортируется нами, хотя база и
обещает порядок: отпечаток обязан зависеть от НАБОРА контента, иначе пересборка базы у одного из игроков
разводила бы сессию на ровном месте. Разделитель между id обязателен — без него «a»+«bc» совпало бы с
«ab»+«c».
Грабли:
- Правка
.asmdefне виднаcompile-check.ps1до рефреша. Скрипт собирает по готовым командам редактора изLibrary/Bee/artifacts/*.rsp, а новую ссылку сборки генерирует Unity. Симптом — «CS0234: пространство имён не существует» при верном asmdef на диске. Лечится однимrefresh_unity, но помнить надо: asmdef — ассет, и правило «ассеты через редактор» на него распространяется. add_packageупал первым вызовом наEPERM: renameвнутриLibrary/PackageCache(файл держал другой процесс), манифест при этом остался чистым — половинчатого состояния не возникло. Вторая попытка прошла. Плюс сам ответ MCP пришёл таймаутом, потому что Unity в этот момент импортировал пакет: проверять результат надо по манифесту на диске, а не по ответу инструмента.
Не сделано и знаем об этом: UTP-профиль как третья реализация INetTransport поверх NGO. Он
требует NetworkManager в сцене, то есть работы через редактор, и приезжает вместе с сессией.
Loopback и chaos закрывают всё, что можно закрыть без сцены.
Владелец правды: Net/Transport/ целиком, Data/ContentFingerprint.cs; инварианты — тесты
TransportSeamTests (доставка только в Poll, копия payload, громкий отказ сверх предела, один сид →
одна история, надёжное не теряется) и ContentFingerprintTests (независимость от порядка,
чувствительность к набору, границы id, отдельная проверка версий).