Решили: инициализация Steam и прокачка его колбэков живут в своём классе — SteamBootstrap
(IStartable + ITickable в корне), AppId там же константой.
Почему это запись, а не тихая правка: класс появился не из потребности, а из ДЫРЫ. SteamClient.Init
и RunCallbacks жили в FacepunchTransportBootstrap, который удалили 02.08 вместе с высокоуровневым
netcode. Файл делал две работы, а удалялся за одну — и с тех пор Steam в проекте не поднимался
вообще: ни Init, ни RunCallbacks, ни AppId нигде.
Чем это опасно именно здесь. Симптом неотличим от штатного внешнего отказа: SteamClient.IsValid
возвращает false, лобби «просто не создаётся», кнопка приглашения гаснет — ровно так игра ведёт
себя, когда Steam не запущен. То есть весь кооп-код читался бы как «написан и не работает по внешней
причине», а искать это пришлось бы на живом тесте вдвоём, где стоимость минуты самая высокая.
Нашлось за минуту грепом по SteamClient.Init — но только потому, что вопрос «а всё ли готово к
тесту» был задан ДО теста.
Колбэки качаем сами (asyncCallbacks: false): фоновый поток Facepunch отдавал бы события лобби и
приглашений вне главного потока Unity, а трогают они UI и сеанс. Цена — один вызов в кадр.
steam_appid.txt в корне репозитория — иначе из редактора Steam не понимает, под каким
приложением мы ходим. Число публичное (оно на странице магазина), секрета в файле нет.
Урок общий, не про Steam: удаляя файл, чьё имя называет ОДНУ работу, проверь, не делает ли он вторую. Здесь имя говорило про транспорт, а половина содержимого была про жизненный цикл платформы.
Владелец правды: Net/Session/SteamBootstrap.cs, steam_appid.txt, строка про Steam в CLAUDE.md.