Не партнёр

Главная Документация и помощь
Документация Steamworks
Статистика и достижения

Введение

Статистики и достижения Steam представляют собой удобный инструмент для их отслеживания у пользователей. Данные пользователей привязаны к их аккаунтам Steam, что позволяет форматировать и отображать статистику и достижения в их профилях сообщества.

Назначение

В дополнение к наградам для игроков, достижения используются для поощрения командной игры и взаимодействия между игроками, а также добавляют дополнительное измерение к целям игры, вознаграждая игроков за пребывание в игре в течение долгого времени.

Статистика отслеживает точно определённые фрагменты информации, такие как игровое время, число потраченных бонусов и т. д. Их можно использовать и просто для отслеживания внутриигровых данных. К примеру, пользователю можно выдать достижение на основании статистики, собранной во время игры в течение нескольких сессий на разных компьютерах.

Обзор реализации

Определение статистики и достижений

Достижения определяются для конкретного приложения и устанавливаются на странице управления приложением на партнёрском сайте Steamworks.

Есть три типа статистики, которые может хранить игра:
  • INT - 32-битное целое число со знаком (к примеру, число сыгранных игр)
  • FLOAT - 32-битное число с плавающей точкой (к примеру, число пройденных автомобилем миль)
  • AVGRATE - скользящее среднее. См. AVGRATE-статистика

На сайте Steamworks доступен интерфейс для определения и обновления статистик и достижений, с помощью которого выполняются следующие действия:
  • Определение начальных статистик и достижений
  • Добавление статистик и достижений
  • Обновление названий, описаний и иконок достижений
  • Обновление параметров статистик и их ограничений (максимальное и минимальное значения, размер окна для скользящего среднего и т. д.)
Статистики обладают следующими свойствами:
  • ID — автоматически генерируемый номер для каждого достижения.
  • Type — INT, FLOAT или AVGRATE.
  • Название для API — строка, используемая API при доступе к этой статистике.
  • Установлено — показывает, кто может задавать статистику. По умолчанию — клиент. Больше информации здесь.
  • Только приращение — если установлено, этой статистике позволено только увеличиваться с течением времени.
  • Максимальное изменение — если установлено, накладывает ограничение на изменение значения в результате одного вызова SetStat.
  • Минимальное значение — если установлено, определяет минимум для значения статистики. По умолчанию равно минимуму для соответствующего типа числа (INT_MIN или -FLT_MAX).
  • Максимальное значение — если установлено, определяет максимум для значения статистики. По умолчанию равно максимуму для соответствующего типа числа (INT_MAX или FLT_MAX).
  • Стандартное значение — если установлено, новый пользователь получит это значение по умолчанию для данной статистики. Если не установлено, равно нулю.
  • Суммарное — если установлено, Steam будет хранить общее суммарное значение для этой статистики. См. ниже раздел «Общие статистики».
  • Название для отображения — это название показывается в сообществе Steam. Может быть локализовано.
Статистики AVGRATE могут обладать дополнительными свойствами:
  • Окно - размер скользящего окна, используемого для усреднения.
Статистика типа AVGRATE автоматически усредняется. См. раздел AVGRATE ниже.

Достижения обладают следующими свойствами:
  • ID — автоматически генерируемый номер для каждого достижения.
  • Название для API — строка, используемая API при доступе к этому достижению.
  • Прогресс статистики — отсылает к статистике, используемой в сообществе как индикатор прогресса для этого достижения. Достижение автоматически разблокируется, если статистика достигает значения разблокировки.
  • Название для отображения — это название показывается в уведомлениях клиента и в сообществе. Может быть локализовано.
  • Описание — описание достижения, которое показывается в сообществе. Может быть локализовано.
  • Установлено — показывает, кто может разблокировать достижение. По умолчанию — клиент. Больше информации здесь.
  • Скрытое — если установлено, «скрытое» достижение (совсем) не показывается на странице пользователя в сообществе, пока он не разблокирует его.
  • Иконка полученного — показывается, когда достижение получено.
  • Иконка неполученного — показывается до тех пор, пока достижение не получено.

Далее показаны достижения из Spacewar (образец приложения)::
achievements_spacewar.png

Использование статистик и достижений

Получение статистик и достижений в игре:

  • После инициализации Справочник по API Steamworks можно начать использовать функции, которые находятся в ISteamUserStats.
  • В начале игровой сессии для получения данных пользователя с сервера Steam вызывается ISteamUserStats::RequestCurrentStats. Когда данные будут готовы, будет получен обратный вызов ISteamUserStats::UserStatsReceived_t.
  • Для обработки данных и создания состояния игры используются итераторы ISteamUserStats::GetStat и ISteamUserStats::GetAchievement.
  • При желании можно отображать достижения в игре. Для извлечения человекочитаемых свойств достижений, включая название ("name") и описание ("desc"), используется ISteamUserStats::GetAchievementDisplayAttribute. Эти свойства можно локализовать на партнёрском сайте Steamworks, и тогда возвращаемые данные будут зависеть от языка, на котором запущена игра. Также возможно получить иконку достижения (ISteamUserStats::GetAchievementIcon) или время, в которое было разблокировано то или иное достижение (ISteamUserStats::GetAchievementAndUnlockTime).
  • Когда та или иная статистика изменяется, еще до того как показать изменения пользователю, вызывается ISteamUserStats::SetStat или ISteamUserStats::UpdateAvgRateStat. Этот вызов изменяет только состояние в памяти Steam и требует мало ресурсов. Это позволяет Steam сохранять изменения между сессиями даже в случае сбоя игры.
  • В соответствующих точках в игре (чекпоинты, переходы между уровнями) вызывается ISteamUserStats::StoreStats для передачи изменений на сервер. После выполнения будет получен обратный вызов ISteamUserStats::UserStatsStored_t.
  • Для достижений, у которых есть индикатор прогресса, для отображения всплывающего уведомления в тех точках, где нужно показать продвижение игрока, используется ISteamUserStats::IndicateAchievementProgress. К примеру, если пользователю для достижения нужно 20 побед, можно вызвать IndicateAchievementProgress после 10 побед, чтобы показать ему, что он на полпути.
  • Когда одно или несколько достижений разблокированы, вызывается ISteamUserStats::SetAchievement для каждого из них, а потом сразу ISteamUserStats::StoreStats для передачи на сервер. Игра получит обратный вызов ISteamUserStats::UserAchievementStored_t для каждого полученного достижения. В оверлее пользователю будет показано соответствующее уведомление.

AVGRATE-статистика

Статистика этого типа предоставляет доступ к уникальным и полезным возможностям, которые объясняются здесь чуть подробнее.

Предположим, нужно отслеживать среднюю статистику, такую как «Число очков в час». Можно подойти к этому так: хранить две статистики, INT ВсегоОчков и FLOAT ВсегоЧасовИгровогоВремени, и затем поделить очки на время.

Недостаток данного подхода заключается в том, что как только игрок наиграл значительное количество времени, изменения среднего значения будут меняться чрезвычайно медленно. Чем больше играет пользователь, тем меньше меняется среднее. Если он наиграл 100 часов, исчисляемое среднее будет «отставать» на 50 часов. При этом если навыки игрока улучшились, он не увидит ожидаемый прирост показателя «Число очков в час».

AVGRATE позволяет задать «скользящее окно» для среднего. К примеру, для расчетов можно брать только несколько последних часов игры, так что статистика будет должным образом отражать текущий уровень навыка игрока.

Для того, чтобы задать AVGRATE-статистику «Число очков в час», где будут учитываться только 20 последних часов игры, потребуется следующее:
  • Обратите внимание на то, что поскольку среднее будет принимать значение «в час», единицей времени всех переменных, связанных с этой статистикой, должны быть «часы». Это применимо как к свойству «Окно» статистики, так и к параметру dSessionLength, передаваемому в UpdateAvgRateStat ниже.
  • Создается AVGRATE-статистика под названием AvgPointsPerHour, свойству «Окно» установливается значение 20 (в часах).
  • В подходящие моменты игры вызывается ISteamUserStats::UpdateAvgRateStat со следующими параметрами:
    • pchName — AvgPointsPerHour
    • flCountThisSession — число очков, заработанных игроком с последнего вызова UpdateAvgRateStat.
    • dSessionLength — игровое время, прошедшее с последнего вызова UpdateAvgRateStat. Единица измерения та же, что и «Окно», т. е. часы.
  • К примеру, если игрок заработал 77 очков в последнем раунде, который продлился 0,225 часов (13,5 минут), это будет SteamUserStats()->UpdateAvgRateStat( "AvgPointsPerHour", 77, 0.225 )
В этом примере Steam возьмет среднее текущего раунда (342,2 очка в час = 77 / 0,225) и перемешает с предыдущим значением. Результат будет отображать среднее за последние 20 часов игры. Если статистика является новой для данного игрока, текущее значение составит 342,2.

В данном примере за единицу времени принимаются часы, но можно использовать и любые другие. Помните, что эта единица должна использоваться для всех вычислений: как для dSessionLength, так и для «Окна».

Получение статистик других игроков

Для запроса статистик других игроков используется ISteamUserStats::RequestUserStats. Затем для получения данных используются ISteamUserStats::GetUserStat, ISteamUserStats::GetUserAchievement и ISteamUserStats::GetUserAchievementAndUnlockTime. При отправке другим игроком на сервер автоматически эти данные не обновляются, так что для обновления данных потребуется снова вызвать ISteamUserStats::RequestUserStats.

Чтобы избежать перегрузки памяти используется алгоритм вытеснения давно неиспользуемого, так что статистики других игроков будут периодически выгружаться. При этом будет автоматически отправлен обратный вызов ISteamUserStats::UserStatsUnloaded_t. Статистики указанного игрока будут недоступны, пока ISteamUserStats::RequestUserStats не будет вызван заново.

Оффлайн-режим

Steam хранит локальный кэш статистик и достижений, чтобы данные могли использоваться даже в офлайн-режиме. Не отправленные на сервер статистики сохраняются до тех пор, пока пользователь не зайдет в сеть. Если изменения произошли на нескольких компьютерах, Steam автоматически объединит достижения и выберет тот набор статистик, в котором произошло наибольшее продвижение. Поскольку Steam хранит локальный кэш статистик, игре создавать аналогичный кэш необязательно. Подобное дублирование может привести к конфликту, и если это произойдет, пользователь сочтет, что он отброшен назад, и разозлится.

Статистики игровых серверов

Бок о бок с ISteamUserStats существует ISteamGameServerStats для игровых серверов. Функции здесь могут устанавливать статистики и давать пользователям достижения, но только если для параметра «установлено» выбраны значения «официальные игровые серверы» (Official GS) или «игровые серверы» (GS). Разница между ними в том, что официальные игровые серверы — это те, которые принадлежат вам и контролируются вами. Использование официальных игровых серверов позволяет увеличить уровень защиты против читеров, так как пользователи могут изменять собственные серверы или сфабриковать данные на них. Чтобы указать, какие серверы являются официальными, их IP-адреса вводятся здесь.

Статистики и достижения, устанавливаемые на игровых серверах, не могут быть установлены клиентами. Игровые серверы могут устанавливать статистики и достижения только для пользователей, играющих на сервере. Если пользователь покидает сервер, есть небольшой период, в течение которого можно установить новые статистики, но после этого новые загрузки данных на сервер будут запрещены. Это обеспечивает непротиворечивость и помогает избежать ситуаций, когда неисправный сервер может установить статистику для кого угодно в любое время. Учитывая это ограничение, важно не дожидаться окончания раунда для обновления статистик, а устанавливать их последовательно, чтобы они сохранялись после выхода пользователей из игры.

Клиенты получат автоматические обновления, когда сервер меняет их статистики. Однако как и при установке статистик клиентом, установленная одному пользователю статистика не обновляется автоматически у других пользователей и со временем может устареть.

Сброс статистик

Во время разработки может потребоваться полностью сбросить статистики и достижения на одном или всех аккаунтах. Для сброса статистики на одном аккаунте вызывается ISteamUserStats::ResetAllStats. Чтобы удалить и достижения, для bAchievementsToo устанавливается значение true. После вызова нужно пройти по всем достижениям и статистикам, чтобы сбросить их состояние в памяти игры. Для всех пользователей удалить статистики и достижения нельзя. Одна из причин, почему это нельзя сделать, заключается в том, что даже если бы подобный общий сброс и состоялся, продолжающиеся игры могли бы этого не заметить и записать имеющиеся у них значения заново. Однако есть простой способ встроить систему общего сброса в игру. Для этого потребуется следующее.
  • При определении статистики в её название добавляется «версия номер такая-то» ("Version")
  • Этот жестко закодированный номер используется в игре
  • Как только у игрока появляются изменения в статистике, его версия сравнивается с версией статистики в игре
  • Если они не совпадают, вызывается ISteamUserStats::ResetAllStats и для игрока устанавливается «версия статистики с нужным номером».
Таким образом, для общего сброса требуется просто поменять жестко закодированный номер версии. Когда пользователи получат новую сборку, произойдет общий сброс.

Непротиворечивость статистик

Рекомендуется принимать во внимание тот факт, что связанные статистики могут начать противоречить друг другу. К примеру, в игре могут быть три статистики: «Число выигранных игр», «Число проигранных игр», «Число сыгранных игр». Несмотря на лучшие побуждения статистики могут рассинхронизироваться друг с другом, и это действительно происходит постоянно. В данном примере это может привести к ситуации, когда сумма выигранных и проигранных игр не будет равна числу сыгранных игр. Если устранить эту проблему, удалив «Число проигранных игр» и заменив этот показатель разницей между числом сыгранных и выигранных игр, может возникнуть ситуация, когда число проигранных игр будет отрицательным. Поэтому лучше отбросить «Число сыгранных игр» и вычислять его как сумму выигранных и проигранных игр.

Общие статистики

Статистику можно пометить как «Суммарное [значение]», чтобы указать Steam на необходимость хранения общего суммарного значения для всех пользователей. Оно может использоваться для получения данных о количестве денег в экономике, числе убийств, предпочитаемом оружии, любимых локациях, а также о том, какие команды лучше играют. С другой стороны, этот параметр нельзя использовать для таких статистик как «Больше всего убийств», поскольку его суммирование для множества игроков не имеет смысла. Поскольку статистики находятся в руках пользователей, этими данными часто манипулируют. Как следствие, крайне важно при использовании суммарных значений установить рамки для минимального и максимального значений, максимального изменения, а также, если применимо, установить параметр «только приращение». Максимальное изменение для суммарных статистик имеет специальное значение. Когда на сервер отправляется новое значение, общее значение изменится не больше, чем значение максимального изменения. Это ограничивает скорость, с которой читер может повлиять на общие статистики.

Для доступа к суммарным значениям вызывается ISteamUserStats::RequestGlobalStats и затем ISteamUserStats::GetGlobalStat для каждой общей статистики. При вызове ISteamUserStats::RequestGlobalStats также можно запросить данные за определенное число дней. Исторические данные показывают значение изменения данной статистики на тот или иной день. Их можно получить, вызвав ISteamUserStats::GetGlobalStatHistory.

Запрос на получение процентов выполнения можно отправить и из клиента. Для этого сначала вызывается ISteamUserStats::RequestGlobalAchievementPercentages. Затем при вызове ISteamUserStats::GetMostAchievedAchievementInfo и ISteamUserStats::GetNextMostAchievedAchievementInfo выполняется итерация по порядку от наиболее выполненных к наименее выполненным. Также можно получить процент выполнения того или иного достижения, вызвав ISteamUserStats::GetAchievementAchievedPercent.

Достижения в сообществе Steam

После выхода игры информация об индивидуальном и общем продвижении и достижениях будет показываться на страницах в сообществе. В профиле каждого игрока будет ссылка на страницу, при переходе на которую будет виден список выполненных и невыполненных достижений.
Обратите внимание: достижения для игры не будут показаны до тех пор, пока приложение не станет так или иначе видимым в сообществе.

Каждое достижение выводится с соответствующей иконкой, названием и описанием, указанном в Steamworks. Если название и описание были локализованы для языка, который выбран пользователем, они показываются на этом языке.

С этой страницы, а также со страницы игры в магазине, также будут ссылки на страницу общей статистики игры. На ней показывается, какой процент игроков Steam получил то или иное достижение, при этом достижения будут отсортированы от самого часто выполняемого к самому редко выполняемому. Это интересно игрокам, а также отличный ресурс для разработчика: действительно ли специальные задачи, которые поставлены перед игроками, так трудны? Или, может быть, они чересчур тяжелы? Статистика достижений также доступна на сайте с отчётами о продажах и активациях.

Остались вопросы?

Задавайте их в соответствующем разделе обсуждений группы разработчиков