Documentation Steamworks
Les statistiques étape par étape

Introduction

Ce qui suit est un guide rapide, étape par étape, pour intégrer dans votre application des statistiques Steam très basiques en moins de 10 minutes et en moins de 10 lignes de code dans votre base de code. Le SDK Steamworks est livré avec une excellente application exemple, appelée Spacewar, qui démontre toute l'ampleur des fonctionnalités de Steam. Il est conseillé de commencer par là pour voir toutes les fonctionnalités de Steam en action. Ce didacticiel concentre les informations trouvées dans Spacewar et dans l'API des statistiques et des succès pour vous fournir seulement les informations nécessaires à la compréhension du fonctionnement de l'interface SteamUserStats. Notez qu'il y a beaucoup de chevauchements entre les statistiques et les succès. Ainsi, si vous intégrez les deux, sachez que beaucoup d'appels peuvent être regroupés.

Étape 1 : définir les statistiques de votre jeu

Les statistiques sont spécifiques à l'application et peuvent être configurées sur la page Configuration des succès de l'administration de l'application dans Steamworks. Ce qui suit correspond à la liste des statistiques disponibles dans l'application modèle Spacewar :
stats_spacewar.png

Étape 2 : travail d'encapsulation des statistiques

Le code qui suit est indépendant du jeu et peut être ajouté à votre jeu comme vous le souhaitez. La classe est entièrement fonctionnelle en l'état, mais peut être facilement étendue pour répondre à d'autres besoins. Tout ce code est tiré directement des fichiers exemples de Spacewar StatsAndAchievements.cpp/h.

Fichier d'entête

Nous définissons d'abord une structure qui contiendra nos données de statistiques reçues de Steam, puis nous définissons les types de statistiques dans une enum et fournissons ensuite une macro pour créer des objets statistiques. Ces données correspondent exactement à ce que l'on retrouve sur la page Configuration des statistiques.
#define _STAT_ID( id,type,name ) { id, type, name, 0, 0, 0, 0 } enum EStatTypes { STAT_INT = 0, STAT_FLOAT = 1, STAT_AVGRATE = 2, }; struct Stat_t { int m_ID; EStatTypes m_eStatType; const char *m_pchStatName; int m_iValue; float m_flValue; float m_flAvgNumerator; float m_flAvgDenominator; };

Ensuite, nous définissons une classe auxiliaire qui enveloppera tous les appels de l'API Steam Stats et créera tous les rappels Steam.
class CSteamStats { private: int64 m_iAppID; // AppID actuel Stat_t *m_pStats; // Données statistiques int m_iNumStats; // Nombre de statistiques bool m_bInitialized; // A-t-on appelé Request stats et reçu le rappel ? public: CSteamStats(Stat_t *Stats, int NumStats); ~CSteamStats(); bool RequestStats(); bool StoreStats(); STEAM_CALLBACK( CSteamStats, OnUserStatsReceived, UserStatsReceived_t, m_CallbackUserStatsReceived ); STEAM_CALLBACK( CSteamStats, OnUserStatsStored, UserStatsStored_t, m_CallbackUserStatsStored ); };

Fichier de code

Constructeur

Paramètres : le constructeur prend un pointeur sur un tableau de statistiques ainsi que la taille du tableau. Le formatage du tableau sera traité plus tard dans le code principal du jeu.
Éléments renvoyés : aucun.
Action : le constructeur initialise un certain nombre de membres tout en récupérant l'AppID que nous utilisons actuellement. De plus, il connecte les méthodes de rappel pour gérer les appels asynchrones effectués vers Steam. Enfin, il effectue un appel initial de RequestStats() pour obtenir les stats et les succès du compte actuel.
CSteamStats::CSteamStats(Stat_t *Stats, int NumStats) : m_iAppID( 0 ), m_bInitialized( false ), m_CallbackUserStatsReceived( this, &CSteamStats::OnUserStatsReceived ), m_CallbackUserStatsStored( this, &CSteamStats::OnUserStatsStored ) { m_iAppID = SteamUtils()->GetAppID(); m_pStats = Stats; m_iNumStats = NumStats; RequestStats(); }

RequestStats()

Paramètres : aucun.
Éléments renvoyés : un booléen qui indique si l'appel a réussi ou non. Si l'appel a échoué, alors il est très probable que Steam ne soit pas initialisé. Assurez-vous que vous avez un client Steam ouvert lorsque vous essayez d'effectuer cet appel et que SteamAPI_Init a bien été appelée avant.
Action : cette méthode enveloppe un appel à ISteamUserStats::RequestCurrentStats. Cet appel vers Steam est asynchrone et demande les statistiques du compte actuel. Cet appel doit être effectué avant que vous ne puissiez définir un succès ou des statistiques quels qu'ils soient. L'appel initial de cette méthode est effectué par le constructeur. Par la suite, vous pouvez l'appeler à tout moment si vous voulez vérifier les statistiques ou les succès mis à jour.
bool CSteamStats::RequestStats() { // Est-ce que Steam est lancé ? Si non, il est impossible d'obtenir des statistiques. if ( NULL == SteamUserStats() || NULL == SteamUser() ) { return false; } // Est-ce que la personne est connectée ? Si non, il est impossible d'obtenir des statistiques. if ( !SteamUser()->BLoggedOn() ) { return false; } // Demander les statistiques du compte. return SteamUserStats()->RequestCurrentStats(); }

StoreStats()

Paramètres : aucun.
Éléments renvoyés : un booléen qui indique si l'appel a réussi ou non. Si l'appel a échoué, alors il est très probable que Steam ne soit pas initialisé. Assurez-vous que vous avez un client Steam ouvert lorsque vous essayez d'effectuer cet appel et que SteamAPI_Init a bien été appelée avant.
Action : cette méthode enveloppe un appel à ISteamUserStats::StoreStats. Cet appel vers Steam est asynchrone et stocke les statistiques du compte actuel. Cet appel doit être effectué chaque fois que vous voulez mettre à jour les statistiques du compte.
bool CSteamStats::StoreStats() { if ( m_bInitialized ) { // charger les statistiques for ( int iStat = 0; iStat < m_NumStats; ++iStat ) { Stat_t &stat = m_pStats[iStat]; switch (stat.m_eStatType) { case STAT_INT: SteamUserStats()->SetStat( stat.m_pchStatName, stat.m_iValue ); break; case STAT_FLOAT: SteamUserStats()->SetStat( stat.m_pchStatName, stat.m_flValue ); break; case STAT_AVGRATE: SteamUserStats()->UpdateAvgRateStat(stat.m_pchStatName, stat.m_flAvgNumerator, stat.m_flAvgDenominator ); // La moyenne des résultats est calculée SteamUserStats()->GetStat(stat.m_pchStatName, &stat.m_flValue ); break; default: break; } } return SteamUserStats()->StoreStats(); } }

OnUserStatsReceived()

Paramètres : aucun.
Éléments renvoyés : aucun.
Action : cette méthode est un rappel qui est appelé chaque fois que vous essayez de demander des statistiques. Les statistiques sont demandées en utilisant : RequestStats(). La méthode met à jour la variable membre m_Stats pour refléter les dernières données de statistiques renvoyées depuis Steam.
void CSteamStats::OnUserStatsReceived( UserStatsReceived_t *pCallback ) { // Des rappels de statistiques provenant d'autres jeux peuvent arriver, ignorez-les if ( m_iAppID == pCallback->m_nGameID ) { if ( k_EResultOK == pCallback->m_eResult ) { OutputDebugString( "Stats et succès reçus de Steam\n" ); // charger les statistiques for ( int iStat = 0; iStat < m_iNumStats; ++iStat ) { Stat_t &stat = m_Stats[iStat]; switch (stat.m_eStatType) { case STAT_INT: SteamUserStats()->GetStat(stat.m_pchStatName, &stat.m_iValue); break; case STAT_FLOAT: case STAT_AVGRATE: SteamUserStats()->GetStat(stat.m_pchStatName, &stat.m_flValue); break; default: break; } } m_bInitialized = true; } else { char buffer[128]; _snprintf( buffer, 128, "Échec de RequestStats, %d\n", pCallback->m_eResult ); OutputDebugString( buffer ); } } }

OnUserStatsStored()

Paramètres : Sans objet.
Éléments renvoyés : aucun.
Action : cette méthode est un rappel qui est appelé chaque fois que vous essayez de stocker des statistiques sur Steam. Si l'une des statistiques que nous avons essayé de définir enfreint une contrainte, elle sera rétablie à son ancienne valeur pour que nous rechargions ses valeurs.
void CSteamStats::OnUserStatsStored( UserStatsStored_t *pCallback ) { // Des rappels de statistiques provenant d'autres jeux peuvent arriver, ignorez-les if ( m_iAppID == pCallback->m_nGameID ) { if ( k_EResultOK == pCallback->m_eResult ) { OutputDebugString( "StoreStats - success\n" ); } else if ( k_EResultInvalidParam == pCallback->m_eResult ) { // Une ou plusieurs statistiques que nous avons établies ont enfreint une contrainte. Elles ont été rétablies, // et leurs valeurs doivent être réitérées maintenant pour qu'elles restent synchronisées. OutputDebugString( "StoreStats - échec de validation de certaines stats\n" ); // Faites un faux rappel ici pour que les valeurs soient rechargées. UserStatsReceived_t callback; callback.m_eResult = k_EResultOK; callback.m_nGameID = m_iAppID; OnUserStatsReceived( &callback ); } else { char buffer[128]; _snprintf( buffer, 128, "Échec de StoreStats, %d\n", pCallback->m_eResult ); OutputDebugString( buffer ); } } }

Étape 3 : intégration dans votre jeu

Ce qui suit est une liste complète d'extraits de code que vous devez intégrer dans votre jeu aux emplacements appropriés.

Définitions et variables globales

Ce qui suit est la liste des fichiers entête qui sont nécessaires pour construire avec l'objet Stats, un tableau pour nos statistiques spécifiques au jeu et un pointeur global vers notre objet auxiliaire. Notez que les statistiques correspondent à celles de la page d'administration sur Steamworks.
... #include "steam_api.h" #include "isteamuserstats.h" #include "SteamStats.h" // Tableau de statistiques qui contiendra des données sur celles-ci et leur état Stat_t g_Stats[] = { _STAT_ID( 1, STAT_INT, "NumGames"), _STAT_ID( 2, STAT_INT, "NumWins"), _STAT_ID( 3, STAT_INT, "NumLosses"), _STAT_ID( 4, STAT_FLOAT, "FeetTraveled"), _STAT_ID( 5, STAT_AVGRATE, "AverageSpeed"), _STAT_ID( 7, STAT_FLOAT, "MaxFeetTraveled"), }; // Accès global aux objets Stats CSteamStats* g_SteamStats = NULL; ...

Initialisation

L'appel de SteamAPI_Init initialise tout Steam et doit être appelé avant toute autre chose. Si cet appel aboutit, l'objet auxiliaire est alors créé en passant le tableau des statistiques et la taille du tableau.
... // Initialiser Steam bool bRet = SteamAPI_Init(); // Créer l'objet « SteamStats » si Steam a été initialisé avec succès if (bRet) { g_SteamStats = new CSteamStats(g_Stats, 6); } ...

Traitement des rappels

Pour nous assurer que nous traitons tous les rappels Steam, nous devons régulièrement faire remonter les nouveaux messages. Pour cela, il suffit d'ajouter cet appel dans la boucle du jeu.
... SteamAPI_RunCallbacks();

Enregistrement des statistiques

Les statistiques sont stockées en appelant une seule fois StoreStats().
... if (g_SteamStats) g_SteamStats->StoreStats(); ...

Arrêter

L'appel de SteamAPI_Shutdown se trouve probablement déjà dans votre code. Elle arrête Steam et doit être appelée avant la fermeture de votre application. Enfin, l'objet auxiliaire créé précédemment est supprimé.
... // Arrêter Steam SteamAPI_Shutdown(); // Supprimer l'objet SteamStats if (g_SteamStats) delete g_SteamStats; ...

Étape 4 : test et dépannage

Cet échantillon de code fournit des informations de débogage à la console de débogage qui peuvent vous aider à comprendre quels appels réussissent ou échouent. Voici quelques messages d'échec typiques et leurs solutions :

L'application n'a pas réussi à démarrer, car steam_api.dll n'a pas été trouvé. Réinstaller l'application peut corriger ce problème.
Assurez-vous que steam_api.dll est dans le même répertoire que l'exécutable.

[S_API FAIL] SteamAPI_Init() a échoué : impossible de trouver une instance de Steam en cours d'exécution ou un fichier steamclient.dll local.
Vous n'avez probablement pas de client Steam en cours d'exécution. Lancez Steam et connectez-vous.

[S_API FAIL] SteamAPI_Init() a échoué : aucun AppID trouvé.
Il est très probable que vous n'ayez pas le fichier steam_appid.txt en place. Placez-le dans votre dossier source et assurez-vous qu'il contient votre numéro d'AppID.