Документація Steamworks
Крок за кроком: таблиці лідерів

Вступ

Нижче подається покроковий посібник з ітерації простих таблиць лідерів Steam до вашого застосунку, що займе менш як 10 хвилин. У розділі про SDK Steamworks подано чудовий приклад застосунку, що називається Spacewar. У ньому показано весь діапазон функцій Steam, тож рекомендуємо із ним ознайомитися. Тут інформація зі Spacewar і API таблиць лідерів у ISteamUserStats відфільтрована до необхідної для розуміння принципу роботи цих функцій.

Крок 1: визначення таблиць лідерів для вашої гри

Таблиці лідерів визначаються для конкретного застосунку й налаштовуються на сторінці конфігурації таблиць лідерів на партнерському сайті Steamworks.

Наступні поля потрібно заповнити для створення таблиці лідерів:
  • Назва. Виберіть таку назву, яка має сенс для внутрішньої розробки.
  • Назва в спільноті. Якщо таблиця лідерів показується в центрі спільноти, то вкажіть тут загальнодоступну назву. Якщо тут нічого не вказувати, то таблиця лідерів не показуватиметься.
  • Спосіб сортування. Вкажіть порядок сортування для таблиці лідерів. Для списків із місцем гравця використовуйте «за зростанням». Для списків із рахунком використовуйте «за спаданням».
  • Тип показу. Визначає тип даних, які показуються з таблицею лідерів. Варіанти: числа, секунди чи мілісекунди.
  • Запис даних. Якщо встановити «довірений запис», то клієнти не зможуть надсилати дані про очки в таблиці лідерів. Це можна буде зробити лише за допомогою веб-API SetLeaderboardScore. Стандартно: false.
  • Читання даних. Якщо встановити значення «друзі», то гра зможе читати дані таблиці лідерів лише для друзів користувача, але всі дані таблиці завжди можна буде прочитати за допомогою веб-API. Стандартно: false.

spacewar_leaderboards

Крок 2: інкапсуляція таблиці лідерів

Код нижче працює для всіх ігор і може бути доданий у будь-яку з них. Клас повністю функціональний, але його можна легко розширити, якщо потрібно. Увесь цей код взятий безпосередньо з файлу Leaderboards.cpp/h зі Spacewar.

Заголовний файл

Ми визначаємо допоміжний клас, який охопить усі виклики до API таблиць лідерів Steam, а також створення всіх обробників результату викликів Steam.
class CSteamLeaderboards { private: SteamLeaderboard_t m_CurrentLeaderboard; // дескриптор таблиці лідерів public: int m_nLeaderboardEntries; // скільки позицій? LeaderboardEntry_t m_leaderboardEntries[10]; // позиції CSteamLeaderboards(); ~CSteamLeaderboards(){}; void FindLeaderboard( const char *pchLeaderboardName ); bool UploadScore( int score ); bool DownloadScores(); void OnFindLeaderboard( LeaderboardFindResult_t *pResult, bool bIOFailure); CCallResult m_callResultFindLeaderboard; void OnUploadScore( LeaderboardScoreUploaded_t *pResult, bool bIOFailure); CCallResult m_callResultUploadScore; void OnDownloadScore( LeaderboardScoresDownloaded_t *pResult, bool bIOFailure); CCallResult m_callResultDownloadScore; };

Програмний код

Конструктор

Параметри — немає.
Повернені значення — немає даних.
Що робить — цей конструктор просто ініціалізує змінні члени.
CSteamLeaderboards::CSteamLeaderboards() : m_CurrentLeaderboard( NULL ), m_nLeaderboardEntries( 0 ) { }

FindLeaderboard()

Параметри — текстовий ідентифікатор таблиці лідерів, яку необхідно встановити (наприклад, «Пройдено метрів»).
Повернені значення — немає.
Що робить — метод є обгорткою для виклику ISteamUserStats::FindLeaderboard, що є асинхронним запитом дескриптора цієї таблиці лідерів. Цей виклик слід виконати перед отриманням чи встановленням позицій таблиці лідерів. Цей метод також установлює метод зворотного виклику для використання.
void CSteamLeaderboards::FindLeaderboard( const char *pchLeaderboardName ) { m_CurrentLeaderboard = NULL; SteamAPICall_t hSteamAPICall = SteamUserStats()->FindLeaderboard(pchLeaderboardName); m_callResultFindLeaderboard.Set(hSteamAPICall, this, &CSteamLeaderboards::OnFindLeaderboard); }

OnFindLeaderboard()

Параметри — немає даних.
Повернені значення — немає.
Що робить — цей метод є зворотним викликом, який викликається щоразу, коли ми пробуємо знайти таблицю лідерів у Steam. Якщо запитувана таблиця лідерів була знайдена, то встановлюємо дескриптор цієї таблиці як нашу поточну таблицю лідерів.
void CSteamLeaderboards::OnFindLeaderboard( LeaderboardFindResult_t *pCallback, bool bIOFailure ) { // перевіряємо, чи не було помилки під час виклику if ( !pCallback->m_bLeaderboardFound || bIOFailure ) { OutputDebugString( "Leaderboard could not be found\n" ); return; } m_CurrentLeaderboard = pCallback->m_hSteamLeaderboard; }

UploadScore()

Параметри — int32, що представляє значення для зберігання в поточній таблиці лідерів.
Повернені значення — false, якщо таблицю лідерів ще не обрано, інакше повертає true.
Що робить — метод є обгорткою для виклику ISteamUserStats::UploadLeaderboardScore, що є асинхронним викликом до Steam, який вивантажує рахунок поточного користувача до обраної поточної таблиці лідерів. Цей метод також установлює метод зворотного виклику для використання. Цей виклик слід робити після того, як ви обрали таблицю лідерів за допомогою FindLeaderboard().
bool CSteamLeaderboards::UploadScore( int score ) { if (!m_CurrentLeaderboard) return false; SteamAPICall_t hSteamAPICall = SteamUserStats()->UploadLeaderboardScore( m_CurrentLeaderboard, k_ELeaderboardUploadScoreMethodKeepBest, score, NULL, 0 ); m_callResultUploadScore.Set(hSteamAPICall, this, &CSteamLeaderboards::OnUploadScore); return true; }

OnUploadScore()

Параметри — немає даних.
Повернені значення — немає.
Що робить — цей метод є зворотним викликом, який викликається щоразу, коли ми пробуємо вивантажити рахунок до таблиці лідерів у Steam.
void CSteamLeaderboards::OnUploadScore(LeaderboardScoreUploaded_t *pCallback, bool bIOFailure) { if ( !pCallback->m_bSuccess || bIOFailure ) { OutputDebugString( "Score could not be uploaded to Steam\n" ); } }

DownloadScores()

Параметри — немає даних.
Повернені значення — false, якщо таблицю лідерів ще не обрано, інакше повертає true.
Що робить — метод є обгорткою для виклику ISteamUserStats::DownloadLeaderboardEntries, що є асинхронним викликом до Steam, який завантажує набір позицій з обраної поточної таблиці лідерів. У цьому випадку ми завантажуємо десять позицій: чотири перед поточним користувачем, позицію поточного користувача і п’ять місць після нього. Цей виклик можна змінити для отримання будь-якої кількості позицій із будь-якого місця таблиці лідерів. Цей метод також установлює метод зворотного виклику для використання. Цей виклик слід робити після того, як ви обрали таблицю лідерів за допомогою FindLeaderboard().
bool CSteamLeaderboards::DownloadScores() { if (!m_CurrentLeaderboard) return false; // завантажуємо дані таблиці лідерів навколо поточного користувача SteamAPICall_t hSteamAPICall = SteamUserStats()->DownloadLeaderboardEntries( m_CurrentLeaderboard, k_ELeaderboardDataRequestGlobalAroundUser, -4, 5); m_callResultDownloadScore.Set(hSteamAPICall, this, &CSteamLeaderboards::OnDownloadScore); return true; }

OnDownloadScore()

Параметри — немає даних.
Повернені значення — немає.
Що робить — цей метод є зворотним викликом, який викликається щоразу, коли ми пробуємо завантажити позиції з таблиці лідерів у Steam. Якщо дані успішно завантажено, тоді копіюємо їх до нашого масиву позицій. Кількість завантажених позицій зберігається в m_nLeaderboardEntries.
void CSteamLeaderboards::OnDownloadScore(LeaderboardScoresDownloaded_t *pCallback, bool bIOFailure) { if (!bIOFailure) { m_nLeaderboardEntries = min(pCallback->m_cEntryCount, 10); for (int index = 0; index < m_nLeaderboardEntries; index++) { SteamUserStats()->GetDownloadedLeaderboardEntry( pCallback->m_hSteamLeaderboardEntries,index,&m_leaderboardEntries[index],NULL,0); } } }

Крок 3: інтеграція у вашу гру

Далі подано повний перелік фрагментів коду, які потрібно інтегрувати у вашу гру у відповідних місцях.

Визначення й глобальні змінні

Нижче наведено перелік включень, які необхідні для об’єкта Leaderboards, і глобальний вказівник на допоміжний об’єкт.
... #include "steam_api.h" #include "SteamLeaderboards.h" // глобальний доступ до об’єкту таблиці лідерів CSteamLeaderboards* g_SteamLeaderboards = NULL; ...

Ініціалізація

Виклик SteamAPI_Init ініціалізує Steam і повинен бути виконаний у найпершу чергу. Якщо виклик успішний, то створюємо допоміжний об’єкт.
... // ініціалізуємо Steam bool bRet = SteamAPI_Init(); // створюємо об’єкт SteamLeaderboards, якщо Steam успішно ініціалізовано if (bRet) { g_SteamLeaderboards = new CSteamLeaderboards(); } ...

Обробка зворотних викликів

Для обробки всіх зворотних викликів Steam потрібно регулярно слухати нові повідомлення. Для цього в ігровий цикл додається такий виклик.
… SteamAPI_RunCallbacks(); …

Вимкнення

Виклик SteamAPI_Shutdown, котрий закриває Steam, імовірно, вже є у вашому коді. Його слід надіслати до того, як закриється застосунок. Наприкінці видаляється створений раніше допоміжний об’єкт.
... // вимикаємо Steam SteamAPI_Shutdown(); // видаляємо об’єкт SteamLeaderboards if (g_SteamLeaderboards) delete g_SteamLeaderboards; ...

Крок 4: тестування й вирішення проблем

Цей приклад коду виводить інформацію налагодження в консоль налагодження, котра потрібна для розуміння того, які виклики вдалися, а які — ні. Нижче наведено деякі типові сповіщення про помилки та способи виправлення:

This application has failed to start because steam_api.dll was not found. Re-installing the application may fix this problem. (Застосунок не запустився, оскільки файл steam_api.dll не знайдено. Повторна інсталяція застосунку може вирішити цю проблему).
Файл steam_api.dll має бути у тій самій директорії, що й виконуваний файл.

[S_API FAIL] SteamAPI_Init() failed; unable to locate a running instance of Steam, or a local steamclient.dll. (Виклик SteamAPI_Init() не вдався, не вдалося знайти запущений Steam або локальний файл steamclient.dll).
Найімовірніше, клієнт Steam не запущено. Запустіть Steam та увійдіть.

[S_API FAIL] SteamAPI_Init() failed; no appID found. (Виклик SteamAPI_Init() не вдався, не знайдено AppID).
Найімовірніше, файл steam_appid.txt відсутній у потрібній теці. Розташуйте його в потрібному місці й переконайтеся, що там є номер вашого AppID.