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 :
É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.