Интеграция своей игры в Steam: работа с лобби в Steamworks.NET
Steam предоставляет инструменты для интеграции своих сервисов в игры с помощью Steamworks. Рассказываем о том, как создать игровое лобби и работать с ним.
10К открытий11К показов
Мало кто из геймеров не слышал про Steam. Первое появление площадки приходится аж на 2002 г. На ней крупные издатели могли безопасно распространять игры.
Спустя десяток лет появился Steam Greenlight, который дал возможность попасть на площадку не только крупным студиям, но и обычным инди-разработчикам. Пользователи сами выбирали, какие игры они хотят видеть на площадке. Но из-за появления массы второсортных игр такую систему пришлось закрыть. На место Greenlight пришел Direct. По словам разработчиков, такая система должна сделать процесс публикации упорядоченным, прозрачным и доступным для новых разработчиков со всего света.
За почти два десятилетия Steam перестал быть просто площадкой цифрового распространения. В нём появилась внутренняя экономика, достижения, коллекционные карточки, инвентарь. Всё это необходимо для повышения вовлечённости игрока. Естественно, нужно было дать возможность разработчикам как-то интегрировать эти составляющие Steam в свои игры. Для этого был создан Steamworks.
История Steam как многопользовательской платформы началась с CS 1.6. Мультиплеер всегда был одним из ключевых аспектов в процессе игры. Площадка даёт игрокам возможность связываться между собой по одноранговой сети (P2P), либо использовать выделенные игровые серверы. Для первого случая, естественно, необходим матчмейкинг — процесс объединения игроков в игровую сессию. Набор игроков происходит в лобби, где игроки могут обсудить различные игровые аспекты, выбрать персонажей и карту. Steamworks даёт исчерпывающее API для работы с матчмейкингом.
Примечание Оригинальный Steamworks работает на C++. В этой же статье будет идти речь о C# — Steamworks.NET. Это полноценная обёртка официального Steamworks. У Steam есть полная документация для матчмейкинга.
Установка (для Unity3D)
- Скачайте из репозитория Steamworks.NET актуальную версию SDK.
- Переместите всё содержимое в папку Assets.
- Запустите проект в Unity3D. После запуска в корне проекта создастся файл
steam_appid.txt
. В этом файле должен храниться ID вашего приложения в Steam. Если такового пока нет — можно использовать стандартный ID 480. Он принадлежит игре Spacewar. - Перезагрузите Unity3D, чтобы изменения файла вошли в силу.
- Обратите внимание на наличие файла
SteamManager.cs
. Он выполняет несколько крайне важных функций. Если файла нет, то его всегда можно найти в репозитории.
Введение
Ключевую роль в Steamworks играют Callback и CallResult. Обратные вызовы позволяют игре асинхронно работать со Steam.
Callback вызывается при каких-либо событиях в Steam. Это могут быть события получения сообщения в чате, изменение списка игроков лобби или даже открытие игрового оверлея. Рассмотрим следующий код, взятый с вики Steamworks.NET:
Вначале нужно создать экземпляр Callback. В данном случае это событие открытия/закрытия оверлея. Callback нужно инициализировать, привязав к нему функцию. Это стоит делать только убедившись, что Steam уже инициализирован: SteamManager.Initialized
. Для этого лучше всего подойдёт метод OnEnable()
, который вызывается сразу при старте игры.
Функции будет передана переменная, содержащая результат события. Для каждого типа обратного вызова свой тип переменной.
CallResult очень похож на Callback. Разница в том, что CallResult является результатом вызова определённого метода. Это может быть, к примеру, результат создания лобби или подключения к нему. Рассмотрим код с вики:
Как и в случае с Callback, тут сначала нужно создать экземпляр CallResult и инициализировать его. В методе Update()
идёт проверка на нажатие пробела. По нажатию будет отправлен запрос на получение количества игроков. Как и в прошлом случае, после получения ответа вызывается указанный метод, которому будет передан результат.
Обратите внимание, что при работе с CallResult в сигнатуре метода всегда будет bool bIOFailure
.
Для работы Callback и CallResult нужно циклически вызывать метод SteamAPI.RunCallbacks()
.
Примечание Вызов этого метода уже реализован в SteamManager.cs.
Подготовка
Для работы с матчмейкингом вам понадобятся некоторые структуры:
Каждое лобби имеет свои мета-данные: название карты или же режим игры. Нет каких-либо шаблонных данных — всё остаётся за разработчиком. Для работы с мета-данными понадобится структура LobbyMetaData
. Она представляет собой стандартную пару ключ-значение.
В лобби каждый игрок представляет из себя структуру LobbyMembers
, главным свойством которой является m_SteamID
— уникальный ID пользователя Steam.
Структура Lobby
описывает непосредственно лобби, а точнее — самые необходимые свойства, такие как:
- уникальный ID лобби;
- ID владельца лобби;
- список игроков в лобби;
- максимальное количество игроков в лобби;
- мета-данные лобби.
Также потребуются некоторые экземпляры Callbacks и CallResult, а именно:
И как полагается, стоит инициализировать все обратные вызовы и создать для них соответствующие методы:
Получение списка лобби
Чтобы получить список существующих лобби, используйте:
После получения ответа вызовется метод OnLobbyMatchList
. Методу передаётся только одно число — количество лобби. Его можно взять из переменной pCallback.m_nLobbiesMatching
.
Внимание Steamworks может вернуть в списке не более 50 лобби.
После получения списка лобби их неплохо было бы отобразить. Перебор списка лобби будет выглядеть так:
Вам нужно будет создать какой-нибудь метод отображения списка лобби (RenderLobby
), который будет принимать ID лобби:
Потом нужно дать возможность пользователю выбрать лобби, к которому он захочет подключиться, либо создать своё.
Фильтр списка лобби
Steamworks даёт возможность отфильтровать возвращаемый список по некоторым категориям.
Внимание Фильтр нужно устанавливать перед вызовом RequestLobbyList()
.
Вначале можно указать максимальное количество возвращаемых лобби. Чем меньше количество — тем быстрее обработается результат. Сделать это можно функцией SteamMatchmaking.AddRequestLobbyListResultCountFilter(max_count);
.
Дальше есть несколько типов фильтров (все они находятся в классе SteamMatchmaking
):
AddRequestLobbyListDistanceFilter
— задаёт расстояние, в пределах которого нужно искать лобби (исходя из IP пользователя). Принимает ELobbyDistanceFilter.AddRequestLobbyListFilterSlotsAvailable
— оставляет только те лобби, в которых доступно указанное количество свободных слотов.AddRequestLobbyListNearValueFilter
— сортирует лобби по степени удалённости значения от указанного. Таких фильтров можно указать несколько. Первый будет иметь больше всего влияния на сортировку, последний — меньше всего.AddRequestLobbyListNumericalFilter
— задаёт числовой тип сравнения.AddRequestLobbyListStringFilter
— задаёт строковый тип сравнения.
Три последних фильтра сравнивают/сортируют лобби по их мета-данным.
Например, после создания лобби вы выбираете какую-либо локацию. Название локации нужно будет сохранить в мета-данных лобби под ключом map_name
. Остальные пользователи смогут отфильтровать список лобби, в которых значение мета-данных map_name
будет тем, которые они выставят. Таким образом игрок сможет найти лобби с той локацией, которую он захочет.
Подключение к лобби
Чтобы присоединиться к существующему лобби:
После удачного подключения к лобби будет вызван метод OnLobbyEnter
. У всех же остальных участников лобби будет вызван метод OnLobbyChatUpdate
.
Создание своего лобби
Чтобы создать собственное лобби, используйте метод:
Метод CreateLobby
принимает два параметра. Первый — тип видимости лобби (по приглашению/для друзей/открытое); второй — максимальное количество игроков. В лобби может быть до 250 игроков, хотя на практике — от 2 до 5.
После удачного создания лобби будет вызван метод OnLobbyCreated
.
Пребывание в лобби
Скорей всего, в лобби вам нужно будет отображать список игроков и чат. Для этого потребуются некоторые методы. К примеру, чтобы получить Sprite
, содержащий аватар пользователя, используйте метод:
При этом разрешение аватара будет 128×128 пикселей.
Чтобы получить собственный Steam ID используйте SteamUser.GetSteamID()
. Для получения своего имени — SteamFriends.GetPersonaName()
. Если нужно получить имя другого пользователя — SteamFriends.GetFriendPersonaName(PlayerID)
.
Отправка сообщений в лобби
Steamworks даёт возможность обмена информацией в лобби. Это может быть уведомление о готовности какого-нибудь игрока, смена персонажа либо банальное получение сообщений в чате. В любом случае вам понадобится следующий метод:
Обратите внимание, что переменную current_lobby_id
вы должны обновлять самостоятельно при создании собственного лобби либо подключении к существующему.
После получения сообщения у всех пользователей (в том числе и у отправителя) вызовется метод OnLobbyChatMsg
.
Неплохим решением будет создание объекта данных, который будет иметь определённый тип (сообщение в чате, изменение готовности игрока и т. д.). Для отправки данных нужно будет его сериализовать в строку (например JSON) и отправить всем остальным через SendData
. При получении такого сообщения нужно будет десериализовать сообщение в объект, определить его тип и обработать. Тогда OnLobbyChatMsg
будет начинаться примерно так:
Изменение мета-данных лобби
Как говорилось ранее, мета-данные нужны для хранения какой-либо игровой информации о лобби: название карты, режим игры, минимальный уровень и т. д. Изменять мета-данные может только владелец лобби. Для быстрой проверки владения лобби можно использовать такой метод:
Для создания или изменения мета-данных используется этот метод:
Как понятно из кода, метод SetLobbyData
работает по стандартной схеме ключ-значение. Для всех остальных участников лобби есть отдельный аналогичный метод SetLobbyMemberData
.
Как только данные будут отосланы у всех клиентов вызовется метод OnLobbyDataUpdate
. Новые игроки, которые только вошли в лобби, будут получать сразу новые значения мета-данных.
Примечание. Перед отправкой данных происходит небольшая задержка. Несколько изменённых подряд мета-данных будут объединены и отправлены одним пакетом.
Чтобы удалить мета-данные, используйте:
10К открытий11К показов