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:

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 pointer 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-objektet, et array for vores spilspecifikke statistikker og en global pointer 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.dllSteam-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.