Решили: высокоуровневый netcode из проекта удалён целиком. Работаем со Steam Networking Sockets
напрямую: SteamNetTransport реализует наш INetTransport на relay-сокете Facepunch, рукопожатие и
номера пиров переехали на наш уровень (CoopHandshake), сессия живёт на Steam-лобби. Из проекта
ушли NgoTransport, FacepunchTransportBootstrap, запаркованный SimSyncProbe, объект [Net] из
CoreScene и четыре пакета: netcode.gameobjects, multiplayer.tools, multiplayer.center,
multiplayer.playmode.
Сказано: «Ох, ты ведь обожаешь все уничтожать? хихи. Так вот… РЕЖЬ и давай самый чистый способ напрямую со Steam! хихи» (02.08.2026, сессия c3712a93). Ему же принадлежит рамка, из которой это следует: «Планирую только Steam».
Почему: HLAPI продаёт репликацию сетевых объектов, RPC и спавн. У нас нет ни одного сетевого объекта и не планируется — бой раздаётся лентой чанками, состояние забега идёт логом команд, присутствие своим пакетом. NGO выполнял ровно две работы: переносил байты и одобрял подключение, и обе мы уже продублировали (конверт с каналом, отпечаток контента). То есть платили версионной зависимостью за написанное.
Отдельно проверено, и это добило вопрос: готовый com.community.netcode.transport.facepunch из
Unity MCC объявляет зависимость netcode.gameobjects 1.0.0-pre.4 при нашей 2.11.2, репозиторий
community-ный без гарантий совместимости, а внутри тянет Facepunch 2.3.2 от 2020 года. Тянуть его
под нашу версию значило бы чинить чужой пакет ради того, что пишется своими тремя сотнями строк.
Что Steam даёт вместо этого: CreateRelaySocket у хоста и ConnectRelay(SteamId) у гостя идут
через Steam Datagram Relay — IP не раскрывается, NAT проходится, трафик едет по бэкбону Valve. Для
P2P это доступно любому партнёру бесплатно; договариваться с Valve нужно только про SDR для
выделенных серверов, которых у нас нет.
Грабли: я советовала оставить NGO «как отладочный путь» и была неправа — это была защита
написанного часом раньше, а не аргумент. Поймал Макс, процитировав мою же предыдущую формулировку.
Реального выигрыша не было: логику отлаживают LoopbackTransport и ChaosTransport (два узла в
одном процессе, потери по сиду), а единственное, чего они не дают, — настоящий сокет, и он теперь
ровно один, стимовский, и проверяется на двух машинах, потому что один Steam-клиент = один аккаунт.
Вторая: рукопожатие пришлось перенести на наш уровень до реза, а не после. Оно жило в
ConnectionApproval NGO, и вместе с пакетом ушла бы проверка версии и контента — а её отсутствие
всплывает не отказом, а сломанным показом боя у гостя.
Владелец правды: Net/Transport/SteamNetTransport.cs, Net/Session/CoopHandshake.cs,
Net/Session/CoopSession.cs, Net/Session/SteamLobbyService.cs. Границу стека держит тест
NoHighLevelNetcodeTests: код проекта, манифест пакетов и сцены не должны содержать чужого
сетевого стека — вернуть его можно было бы одним using в чужой правке.