Documentation Steamworks
Les succès étape par étape

Introduction

Ce qui suit est un guide rapide, étape par étape, pour intégrer dans votre application des succès 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 pour comprendre le 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 succès de votre jeu

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

Étape 2 : travail d'encapsulation des succès

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'en-tête

Nous commençons par définir une structure qui contiendra nos données de succès reçues depuis Steam et une macro qui crée des objets de ce type. Ces données correspondent exactement à ce que l'on retrouve sur la page Configuration des succès.
#define _ACH_ID( id, name ) { id, #id, name, "", 0, 0 } struct Achievement_t { int m_eAchievementID; const char *m_pchAchievementID; char m_rgchName[128]; char m_rgchDescription[256]; bool m_bAchieved; int m_iIconImage; };

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 CSteamAchievements { private: int64 m_iAppID; // AppID actuel Achievement_t *m_pAchievements; // Données des succès int m_iNumAchievements; // Nombre de succès bool m_bInitialized; // A-t-on appelé RequestStats et reçu le rappel ? public: CSteamAchievements(Achievement_t *Achievements, int NumAchievements); ~CSteamAchievements(); bool RequestStats(); bool SetAchievement(const char* ID); STEAM_CALLBACK( CSteamAchievements, OnUserStatsReceived, UserStatsReceived_t, m_CallbackUserStatsReceived ); STEAM_CALLBACK( CSteamAchievements, OnUserStatsStored, UserStatsStored_t, m_CallbackUserStatsStored ); STEAM_CALLBACK( CSteamAchievements, OnAchievementStored, UserAchievementStored_t, m_CallbackAchievementStored ); };

Fichier de code

Constructeur

Paramètres : le constructeur prend un pointeur sur un tableau de succès ainsi que la taille du tableau. Le formatage du tableau sera traité plus tard dans le code principal du jeu.
Renvoie : S. O.
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 de l'utilisateur actuel.
CSteamAchievements::CSteamAchievements(Achievement_t *Achievements, int NumAchievements): m_iAppID( 0 ), m_bInitialized( false ), m_CallbackUserStatsReceived( this, &CSteamAchievements::OnUserStatsReceived ), m_CallbackUserStatsStored( this, &CSteamAchievements::OnUserStatsStored ), m_CallbackAchievementStored( this, &CSteamAchievements::OnAchievementStored ) { m_iAppID = SteamUtils()->GetAppID(); m_pAchievements = Achievements; m_iNumAchievements = NumAchievements; RequestStats(); }

RequestStats()

Paramètres : aucun
Renvoie : 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 et les succès de l'utilisateur 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 CSteamAchievements::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 l'utilisateur est connecté ? Si non, il est impossible d'obtenir des statistiques. if ( !SteamUser()->BLoggedOn() ) { return false; } // Demander les statistiques de l'utilisateur. return SteamUserStats()->RequestCurrentStats(); }

SetAchievement()

Paramètres : identifiant de chaîne du succès que vous voulez définir (par exemple : « ACH_WIN_ONE_GAME »).
Renvoie : un booléen qui indique si l'appel a réussi ou non. Si l'appel a échoué, soit Steam n'est pas initialisé, soit vous n'avez toujours pas traité le rappel depuis l'appel initial de RequestStats. Vous ne pouvez pas définir de succès tant que le rappel n'a pas été reçu.
Action : cette méthode définit un succès comme « réussi » et envoie le résultat à Steam. Vous pouvez définir un succès plusieurs fois. Ainsi, vous n'avez pas besoin de définir uniquement les succès qui n'ont pas déjà été définis. Il s'agit d'un appel asynchrone qui déclenche deux rappels : OnUserStatsStored() et OnAchievementStored().
bool CSteamAchievements::SetAchievement(const char* ID) { // Un appel de Steam a-t-il été reçu ? if (m_bInitialized) { SteamUserStats()->SetAchievement(ID); return SteamUserStats()->StoreStats(); } // Si non, les succès ne peuvent pas être définis return false;

OnUserStatsReceived()

Paramètres : S. O.
Renvoie : rien
Action : cette méthode est un rappel qui est appelé chaque fois que vous essayez de demander des statistiques. Les statistiques et les succès sont demandés en utilisant : RequestStats(). La méthode met à jour la variable membre m_pAchievements pour refléter les dernières données de statistiques et de succès renvoyées depuis Steam.
void CSteamAchievements::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"); m_bInitialized = true; // chargez les succès for ( int iAch = 0; iAch < m_iNumAchievements; ++iAch ) { Achievement_t &ach = m_pAchievements[iAch]; SteamUserStats()->GetAchievement(ach.m_pchAchievementID, &ach.m_bAchieved); _snprintf( ach.m_rgchName, sizeof(ach.m_rgchName), "%s", SteamUserStats()->GetAchievementDisplayAttribute(ach.m_pchAchievementID, "nom")); _snprintf( ach.m_rgchDescription, sizeof(ach.m_rgchDescription), "%s", SteamUserStats()->GetAchievementDisplayAttribute(ach.m_pchAchievementID, "desc")); } } else { char buffer[128]; _snprintf( buffer, 128, "Échec de RequestStats, %d\n", pCallback->m_eResult ); OutputDebugString( buffer ); } } }

OnUserStatsStored()

Paramètres : S. O.
Renvoie : rien
Action : cette méthode est un rappel qui est appelé chaque fois que vous essayez de stocker des statistiques sur Steam.
void CSteamAchievements::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( "Stats stockées pour Steam\n" ); } else { char buffer[128]; _snprintf( buffer, 128, "Échec de StatsStored, %d\n", pCallback->m_eResult ); OutputDebugString( buffer ); } } }

OnAchievementStored()

Paramètres : S. O.
Renvoie : rien
Action : cette méthode est un rappel qui est appelé chaque fois que des succès (Achievements) sont effectivement sauvegardés sur Steam.
void CSteamAchievements::OnAchievementStored( UserAchievementStored_t *pCallback ) { // Des rappels de statistiques provenant d'autres jeux peuvent arriver, ignorez-les if ( m_iAppID == pCallback->m_nGameID ) { OutputDebugString( "Succès stocké pour Steam\n" ); } }

É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

Vous trouverez ci-dessous la liste des fichiers en-tête qui sont nécessaires pour construire avec l'objet « Achievements », une enum de nos succès spécifiques au jeu et un pointeur global vers notre objet auxiliaire. Notez que les succès correspondent à ceux de la page d'administration sur Steamworks.
... #include "steam_api.h" // On définit nos succès enum EAchievements { ACH_WIN_ONE_GAME = 0, ACH_WIN_100_GAMES = 1, ACH_TRAVEL_FAR_ACCUM = 2, ACH_TRAVEL_FAR_SINGLE = 3, }; // Tableau des succès qui contient des données sur les succès et leur état Achievement_t g_Achievements[] = { _ACH_ID( ACH_WIN_ONE_GAME, "Vainqueur" ), _ACH_ID( ACH_WIN_100_GAMES, "Champion" ), _ACH_ID( ACH_TRAVEL_FAR_ACCUM, "Interstellaire" ), _ACH_ID( ACH_TRAVEL_FAR_SINGLE, "Étoile" ), }; // Accès global à l'objet Achievements CSteamAchievements* g_SteamAchievements = 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 succès et la taille du tableau.
... // Initialiser Steam bool bRet = SteamAPI_Init(); // Créer l'objet SteamAchievements si Steam a été initialisé avec succès. if (bRet) { g_SteamAchievements = new CSteamAchievements(g_Achievements, 4); } ...

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();

Déclenchement des succès

Pour déclencher un succès, il suffit tout simplement d'effectuer un seul appel en passant l'identifiant du succès.
... if (g_SteamAchievements) g_SteamAchievements->SetAchievement("ACH_WIN_100_GAMES");

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 SteamAchievements if (g_SteamAchievements) delete g_SteamAchievements; ...

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