Steamworks-dokumentation
Trinvis vejledning: Statistikker

Introduktion

Det følgende er en hurtig trinvis vejledning til at integrere helt grundlæggende Steam-statistikker i din applikation på under ti minutter og med under ti linjers kode intregreret i din kodebase. Steamworks-SDK'en har et godt applikationseksempel kaldet Spacewar, som viser Steam-funktionernes fulde bredde, og du bør starte her for at se, hvordan alle Steam-funktionerne fungerer. Denne introduktion koger oplysninger i Spacewar og statistik- og præstations-API'en ned til de mest nødvendige oplysninger til Steam-statistikker for at gøre det så overskueligt som muligt. Bemærk, at der er et betydeligt overlap mellem statistikker og præstationer, så hvis du integrerer begge dele, skal du være opmærksom på, at mange kald kan konsolideres.

Trin 1 – Definering af dit spils statistikker

Statistikker er applikationsspecifikke og er konfigureret på siden Statistikkonfiguration i App-administratoren i Steamworks-backend. Det følgende er en liste over statistikker fra Steamworks-applikationseksemplet Spacewar:
spacewar_achievements.png

Trin 2 – Indkapsling af statistikarbejde

Den følgende kode er spiluafhængig, og du kan tilføje den til dit spil, som du synes. Klassen er fuldt ud funktionel, som den er, men kan nemt udvides for at opfylde yderligere behov. Al koden er taget direkte fra Spacewar-fileksemplerne StatsAndAchievements.cpp/h.

Headerfil

Vi definerer først en struktur, hvori vores statistikdata ligger, som modtages fra Steam. Dernæst definerer vi statistiktyper i en smart opremsning, og så laver vi en makro til oprettelse af statistikobjekter. Disse data henviser direkte til det, som findes på siden Statistikkonfiguration.
#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; };

Derefter definerer vi en hjælperklasse, som ombryder alle kald til Steam-statistik-API'en samt opretter alle Steam-tilbagekald.
class CSteamStats { private: int64 m_iAppID; // Vores nuværende app-ID Stat_t *m_pStats; // Statistikdata int m_iNumStats; // Antallet af statistikker bool m_bInitialized; // Har vi kaldt Request stats og modtaget et tilbagekald? 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 ); };

Kodefil

Konstruktør

Parametre: Konstruktøren indeholder en reference til et array af statistikker samt længden af arrayet. Formateringen af arrayet dækkes i den primære spilkode senere.
Returværdier: Ingen.
Hvad det gør: Konstruktøren initialiserer et antal medlemmer og tager app-ID'et for den aktuelle applikation. Derudover forbinder den tilbagekaldsmetoderne til at håndtere asynkrone kald til Steam. Endelig foretager den det første kald til RequestStats() for at få statistikker og præstationer for den aktuelle bruger.
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()

Parametre: Ingen.
Returværdier: En boolsk værdi, som viser, om kaldet lykkedes eller ej. Hvis kaldet mislykkedes, er Steam sandsynligvis ikke initialiseret. Sørg for, at Steam-klienten er åben, når du prøver at foretage dette kald, og at SteamAPI_Init er blevet kaldt forinden.
Hvad det gør: Denne metode ombryder et kald til ISteamUserStats::RequestCurrentStats, som er et asynkront kald til Steam, der anmoder om statistikker for den aktuelle bruger. Dette kald skal foretages, før du kan angive nogen statistikker eller præstationer. Det første kald til denne metode foretages i konstruktøren. Du kan foretage kaldet igen når som helst bagefter, hvis du vil tjekke opdaterede statistikker eller præstationer.
bool CSteamStats::RequestStats() { // Er Steam indlæst? Hvis ikke, kan vi ikke få statistikker. if ( NULL == SteamUserStats() || NULL == SteamUser() ) { return false; } // Er brugeren logget på? Hvis ikke, kan vi ikke få statistikker. if ( !SteamUser()->BLoggedOn() ) { return false; } // Anmoder om brugerstatistikker. return SteamUserStats()->RequestCurrentStats(); }

StoreStats()

Parametre: Ingen.
Returværdier: En boolsk værdi, som viser, om kaldet lykkedes eller ej. Hvis kaldet mislykkedes, er Steam sandsynligvis ikke initialiseret. Sørg for, at Steam-klienten er åben, når du prøver at foretage dette kald, og at SteamAPI_Init er blevet kaldt forinden.
Hvad det gør: Denne metode ombryder et kald til ISteamUserStats::StoreStats, som er et asynkront kald til Steam, der lagrer statistikkerne for den aktuelle bruger på serveren. Dette kald skal foretages, når som helst du vil opdatere brugerens statistikker.
bool CSteamStats::StoreStats() { if ( m_bInitialized ) { // Indlæs statistikker 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 ); // Det gennemsnitlige resultat beregnes for os SteamUserStats()->GetStat(stat.m_pchStatName, &stat.m_flValue ); break; default: break; } } return SteamUserStats()->StoreStats(); } }

OnUserStatsReceived()

Parametre: Ingen.
Returværdier: Ingen.
Hvad det gør: Denne metode er et tilbagekald, som kaldes, hver gang du forsøger at anmode om statistikker. Anmodninger om statistikker foretages vha. RequestStats(). Metoden opdaterer medlemsvariablen m_Stats, så den afspejler de seneste statistikdata, som er returneret fra Steam.
void CSteamStats::OnUserStatsReceived( UserStatsReceived_t *pCallback ) { // Vi får måske tilbagekald for andre spils indkommende statistikker – ignorer dem if ( m_iAppID == pCallback->m_nGameID ) { if ( k_EResultOK == pCallback->m_eResult ) { OutputDebugString( "Received stats and achievements from Steam\n" ); // load stats 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, "RequestStats - failed, %d\n", pCallback->m_eResult ); OutputDebugString( buffer ); } } }

OnUserStatsStored()

Parametre: Ingen.
Returværdier: Ingen.
Hvad det gør: Denne metode er et tilbagekald, som kaldes, hver gang du forsøger at lagre statistikker på Steam. Hvis nogen af de statistikker, vi forsøgte at angive, har overtrådt en begrænsning, gendannes den gamle værdi, så vi genindlæser deres værdier.
void CSteamStats::OnUserStatsStored( UserStatsStored_t *pCallback ) { // Vi får måske tilbagekald for andre spils indkommende statistikker – ignorer dem if ( m_iAppID == pCallback->m_nGameID ) { if ( k_EResultOK == pCallback->m_eResult ) { OutputDebugString( "StoreStats - success\n" ); } else if ( k_EResultInvalidParam == pCallback->m_eResult ) { // En eller flere statistikker, som vi angav, overskred en begrænsning. De er blevet tilbageført, // og vi skal gentage værdierne nu af hensyn til synkronisering. OutputDebugString( "StoreStats - some failed to validate\n" ); // Fake up a callback here so that we re-load the values. UserStatsReceived_t callback; callback.m_eResult = k_EResultOK; callback.m_nGameID = m_iAppID; OnUserStatsReceived( &callback ); } else { char buffer[128]; _snprintf( buffer, 128, "StoreStats - failed, %d\n", pCallback->m_eResult ); OutputDebugString( buffer ); } } }

Trin 3 – Integrering i dit spil

Det følgende er en komplet liste over kodestykker, som du skal integrere på de relevante steder i dit spil.

Definitioner og globale variabler

Det følgende er en liste over include-data, som kræves for at bygge med Stats, et array for vores spilspecifikke statistikker og en global reference til vores hjælperobjekt. Bemærk, at statistikkerne matcher dem på administratorsiden i Steamworks.
... #include "steam_api.h" #include "isteamuserstats.h" #include "SteamStats.h" // Stats-arrayet, som vil indeholde data om statistikkerne og deres tilstand 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"), }; // Global adgang til Stats-objektet CSteamStats* g_SteamStats = NULL; ...

Initialisering

Kaldet til SteamAPI_Init initialiserer hele Steam og skal kaldes før noget andet. Hvis kaldet lykkedes, opretter vi hjælperobjektet ved at sende arrayet af statistikker med størrelsen på arrayet.
... // Initialiser Steam bool bRet = SteamAPI_Init(); // Opret SteamStats-objektet, hvis Steam blev initialiseret if (bRet) { g_SteamStats = new CSteamStats(g_Stats, 6); } ...

Behandling af tilbagekald

For at sikre, at vi behandler alle Steam-tilbagekald, skal vi jævnligt tjekke, om der er nye beskeder. Dette gøres ved at tilføje dette kald til spilløkken.
... SteamAPI_RunCallbacks(); ...

Lagring af statistikker

Statistikker lagres ved at foretage et enkelt kald til StoreStats().
... if (g_SteamStats) g_SteamStats->StoreStats(); ...

Nedlukning

Kaldet til SteamAPI_Shutdown er sikkert noget, du allerede har i din kode. Den lukker Steam ned og skal kaldes, før applikationen lukker. Til sidst sletter vi det hjælperobjekt, vi oprettede.
... // Luk Steam ned SteamAPI_Shutdown(); // Slet SteamStats-objektet if (g_SteamStats) delete g_SteamStats; ...

Trin 4 – Testning og fejlfinding

Denne eksempelkode giver fejlfindingsinformation til fejlfindingskonsollen, som kan hjælpe dig med at forstå, hvilke kald der lykkes og mislykkes. Det følgende er nogle typiske fejlbeskeder og løsninger:

Denne applikation kunne ikke starte, fordi steam_api.dll ikke kunne findes. Geninstallering af applikationen løser muligvis dette problem.
Sørg for, at steam_api.dll er i samme mappe som den eksekverbare fil.

[S_API FAIL] SteamAPI_Init() mislykkedes. Kunne ikke lokalisere en kørende instans af Steam eller en lokal steamclient.dll
Steam-klienten kører sandsynligvis ikke. Start Steam, og log på.

[S_API FAIL] SteamAPI_Init() mislykkedes. Intet app-ID fundet.
steam_appid.txt-filen er sandsynligvis ikke i den rigtige mappe. Placer den i kildemappen, og kontrollér, at den indeholder dit app-ID.