Bevezetés
Az alábbi egy gyors, lépésenkénti útmutató nagyon alapszintű Steam Statisztikák integrálásához az alkalmazásodba kevesebb mint tíz perc alatt, és kevesebb, mint tíz sornyi kód integrálásával a kódbázisodba. A
Steamworks SDK tartalmaz egy nagyszerű,
Spacewar nevű példaalkalmazást, amely bemutatja a Steam szolgáltatások teljes skáláját, és érdemes ezzel kezdeni, hogy lásd az összes Steam funkciót működés közben. Ez az oktatás leszűkíti a Spacewarban és a Statisztikák és Teljesítmények API-ban található információkat a csak a Steam Statisztikához szükségesekre, hogy a dolgok a lehető legegyszerűbbek legyenek. Figyelj rá, hogy jelentős átfedés van a statisztikák és a teljesítmények között, így ha mindkettőt integrálod, sok hívás konszolidálható.
1. lépés – A játékod statisztikáinak meghatározása
A statisztikák alkalmazásspecifikusak, és a Steamworks alkalmazás-adminisztrációs háttérrendszer
Statisztikák beállítása oldalán állíthatók be. Alább látható a Spacewar Steamworks példaalkalmazás statisztikalistája:
2. lépés – A statisztikabeágyazási munka
Az alábbi kód játékfüggetlen, és tetszés szerint hozzáadható a játékodhoz. Az osztály jelen állapotában is teljesen működőképes, de könnyen bővíthető bármilyen további igény kielégítésére. Ezt a kódot közvetlenül a Spacewar példafájljaiból vettük:
StatsAndAchievements.cpp/h
.
Fejléc fájl
Először definiálunk egy struktúrát a Steamtől kapott statisztikaadatok tárolására, definiáljuk a statisztikákat egy enumban, majd adunk egy makrót a statisztikaobjektumok létrehozásához. Ezek az adatok közvetlenül a
Statisztikák beállítása oldalon találhatókra képeződnek le.
#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;
};
Ezután definiálunk egy segítő osztályt, amely becsomagolja az összes Steam Statisztikák API-hívást, valamint létrehozza az összes
Steam callbacket.
class CSteamStats
{
private:
int64 m_iAppID; // a jelenlegi AppID-nk
Stat_t *m_pStats; // statisztikaadatok
int m_iNumStats; // a statisztikák száma
bool m_bInitialized; // meghívtuk már a statisztikakérést, és megkaptuk a callbacket?
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 );
};
Kódfájl
Konstruktor
Paraméterek: A konstruktor egy, a statisztikák tömbjére mutató mutatót fogad, valamint a tömb hosszát. E tömb formázásával majd később, a játék fő kódja foglalkozik.
Visszatérési érték: nincs.
Mit csinál: A konstruktor számos tagot inicializál, valamint elkapja az AppID-t, amely alatt jelenleg futunk. Továbbá felcsatolja a callback metódusokat a Steam felé indított aszinkron hívások kezelésére. Végül végrehajtja az első
RequestStats()
hívást a jelenlegi felhasználó statisztikáinak és teljesítményeinek lekérésére.
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éterek: nincs.
Visszatérési érték: A hívás sikerességét vagy sikertelenségét jelző bool. Ha a hívás sikertelen volt, akkor a Steam valószínűleg nincs inicializálva. Győződj meg róla, hogy van nyitott Steam kliens, amikor megpróbálkozol ezzel a hívással, és hogy a
SteamAPI_Init meg volt hívva előtte.
Mit csinál: Ez a metódus lényegében becsomagol egy
ISteamUserStats::RequestCurrentStats hívást, amely egy aszinkron hívás a Steamhez a jelenlegi felhasználó statisztikáinak lekérésére. Ezt a hívást végre kell hajtani, mielőtt bármilyen statisztikát vagy teljesítményt tudnál beállítani. E metódus első hívása a konstruktorban történik. Ezt követően bármikor újra meghívhatod, ha a frissült statisztikákat vagy teljesítményeket szeretnéd ellenőrizni.
bool CSteamStats::RequestStats()
{
// Be van töltve a Steam? Ha nem, nem tudunk statisztikákat kérni.
if ( NULL == SteamUserStats() || NULL == SteamUser() )
{
return false;
}
// Be van jelentkezve a felhasználó? Ha nem, nem tudunk statisztikákat kérni.
if ( !SteamUser()->BLoggedOn() )
{
return false;
}
// Request user stats.
return SteamUserStats()->RequestCurrentStats();
}
StoreStats()
Paraméterek: nincs.
Visszatérési érték: A hívás sikerességét vagy sikertelenségét jelző bool. Ha a hívás sikertelen volt, akkor a Steam valószínűleg nincs inicializálva. Győződj meg róla, hogy van nyitott Steam kliens, amikor megpróbálkozol ezzel a hívással, és hogy a
SteamAPI_Init meg volt hívva előtte.
Mit csinál: Ez a metódus lényegében becsomagol egy
ISteamUserStats::StoreStats hívást, amely egy aszinkron hívás a Steamhez a jelenlegi felhasználó statisztikáinak tárolására a szerveren. Ezt a hívást kell végrehajtani, valahányszor frissíteni akarod a felhasználó statisztikáit.
bool CSteamStats::StoreStats()
{
if ( m_bInitialized )
{
// statisztikák betöltése
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 );
// az átlagolt értéket kiszámítják nerkünk
SteamUserStats()->GetStat(stat.m_pchStatName, &stat.m_flValue );
break;
default:
break;
}
}
return SteamUserStats()->StoreStats();
}
}
OnUserStatsReceived()
Paraméterek: nincs.
Visszatérési érték: semmi.
Mit csinál: Ez a metódus egy callback, amely meghívódik, valahányszor statisztikákat próbálsz lekérni. A statisztikák a
RequestStats()
használatával kérhetők le. A metódus frissíti az m_Stats tagváltozót, hogy az tükrözze a Steam által visszaküldött legfrissebb statisztikaadatokat.
void CSteamStats::OnUserStatsReceived( UserStatsReceived_t *pCallback )
{
// kaphatunk callbacket más játékok statisztikáinak beérkezésekor, ezekkel nem törődünk
if ( m_iAppID == pCallback->m_nGameID )
{
if ( k_EResultOK == pCallback->m_eResult )
{
OutputDebugString( "Received stats and achievements from Steam\n" );
// statisztikák betöltése
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()
Paraméterek: nincs.
Visszatérési érték: semmi.
Mit csinál: Ez a metódus egy callback, amely meghívódik, valahányszor statisztikákat próbálsz tárolni a Steamen. Ha valamelyik statisztika, amelyet megpróbáltunk beállítani, megszegte a korlátozást, akkor visszaáll a régi értékére, így újratöltjük az értékét.
void CSteamStats::OnUserStatsStored( UserStatsStored_t *pCallback )
{
// kaphatunk callbacket más játékok statisztikáinak beérkezésekor, ezekkel nem törődünk
if ( m_iAppID == pCallback->m_nGameID )
{
if ( k_EResultOK == pCallback->m_eResult )
{
OutputDebugString( "StoreStats - success\n" );
}
else if ( k_EResultInvalidParam == pCallback->m_eResult )
{
// Egy vagy több beállított statisztikánk megszegett egy korlátozást. Ezek vissza lettek állítva,
// ezért most végig kellene mennünk az értékeken a szinkronban tartásukhoz.
OutputDebugString( "StoreStats - some failed to validate\n" );
// Itt hamisítunk egy callbacket az értékek újratöltéséhez.
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 );
}
}
}
3. lépés – Integrálás a játékba
Az alábbi mindazon kódrészletek felsorolása, amelyeket a megfelelő helyeken integrálnod kell a játékba.
Defines és Globals
Az alábbi azon include-ok listája, amelyek szükségesek a Statisztikákkal végzett buildhez, egy tömb a játékspecifikus statisztikáinknak és egy, a helper objektumunkra mutató globális mutató. Vedd észre, hogy a statisztikák megegyeznek a Steamworks adminisztrációs oldalán levőkkel.
...
#include "steam_api.h"
#include "isteamuserstats.h"
#include "SteamStats.h"
// A statisztikákról és azok állapotáról adatokat tartalmazó statisztikatömb
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"),
};
// Globális hozzáférés a Stats objektumhoz
CSteamStats* g_SteamStats = NULL;
...
Inicializálás
Az
SteamAPI_Init meghívása inicializálja a teljes Steamet, és minden más előtt kell meghívni. Ha ez a hívás sikeres, akkor létrehozzuk a helper objektumot, átadva neki a statisztikák tömbjét és a tömb méretét.
...
// A Steam inicializálása
bool bRet = SteamAPI_Init();
// A SteamStats objektum létrehozása, ha a Steam inicializálása sikeres volt
if (bRet)
{
g_SteamStats = new CSteamStats(g_Stats, 6);
}
...
Callbackek feldolgozása
Az összes Steam callback feldolgozásának biztosítására rendszeresen keresnünk kell az új üzeneteket. Ezt az alábbinak a játékhurokhoz adásával érjük el:.
...
SteamAPI_RunCallbacks();
...
Statisztikák mentése
A statisztikák mentése a
StoreStats()
egyetlen hívásával történik.
...
if (g_SteamStats)
g_SteamStats->StoreStats();
...
Leállítás
A
SteamAPI_Shutdown meghívása már valószínűleg szerepel a kódodban. Ez állítja le a Steamet, és az alkalmazásod kilépése előtt meg kell hívni. Végül töröljük az általunk létrehozott helper objektumot.
...
// Steam leállítása
SteamAPI_Shutdown();
// A SteamStats objektum törlése
if (g_SteamStats)
delete g_SteamStats;
...
4. lépés – Tesztelés és hibaelhárítás
Ez a mintakód hibakeresési információkat ad ki a hibakereső konzolra, amelyek segíthetnek megérteni, mely hívások sikeresek vagy sikertelenek. Alább látható néhány jellegzetes hibaüzenet és javításuk:
This application has failed to start because steam_api.dll was not found. Az alkalmazás újratelepítése megoldhatja ezt a problémát.Győződj meg róla, hogy a steam_api.dll ugyanabban a könyvtárban van, mint a végrehajtható fájl.
[S_API FAIL] SteamAPI_Init() failed; unable to locate a running instance of Steam, or a local steamclient.dll.Valószínűleg nem fut Steam kliens. Indítsd el a Steamet, és jelentkezz be.
[S_API FAIL] SteamAPI_Init() failed; no appID found.Valószínűleg nincs a helyén a steam_appid.txt fájl. Helyezd el a forrásmappába, és győződj meg róla, hogy benne van az AppID számod.