Въведение
The following is a quick step by step guide to integrating very basic Steam Stats into your application in under 10 minutes and under 10 lines of code integrated into your code base.
Steamworks SDK се предоставя със страхотно примерно приложение, наречено
Spacewar, което демонстрира пълната гама от Steam характеристики и трябва да бъде първата Ви стъпка, за да видите всички тях в действие. Това упътване съкращава информацията, намерена в Spacewar и API за статистики и постижения, само до нужната информация, изисквана за Steam статистиките, така че нещата да са възможно най-ясни. Моля, обърнете внимание, че статистиките и постиженията се припокриват в значителна степен, така че ако интегрирате и двете, имайте предвид, че много заявки могат да бъдат консолидирани.
Step 1 - Defining your game's Stats
Stats are application specific and are setup on the
Stats Configuration page in the Steamworks App Admin backend. The following is the list of stats from the Steamworks sample app Spacewar:

Step 2 - Encapsulating Stats work
Следният код е независим от играта и може да бъде добавен към нея по Ваше усмотрение. Класът е напълно функционален в този си вид, но може лесно да бъде разширен, за да отговаря на всякакви допълнителни изисквания. All of this code was taken directly from the Spacewar example files
StatsAndAchievements.cpp/h
.
Файл на заглавната част
We first define a structure to hold our stats data received from steam, define stat types in a handy enum and then provide a macro for creating stats objects. This data maps directly to what is found on the
Stats Configuration page.
#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;
};
Next we define a helper class that will wrap all of the Steam Stats API calls as well as creating all of the
Steam callbacks.
class CSteamStats
{
private:
int64 m_iAppID; // Our current AppID
Stat_t *m_pStats; // Stats data
int m_iNumStats; // The number of Stats
bool m_bInitialized; // Have we called Request stats and received the callback?
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 );
};
Файл с код
Конструктор
Параметри - The constructor takes a pointer to an array of stats along with the length of the array. The formating of that array will be covered in the main game code later.
Връща — Не е налично
Какво прави - The constructor initializes a number of members along with grabbing the app ID we are currently running as. In addition it hooks up the call back methods to handle asynchronous calls made to Steam. Finally it makes an initial call to
RequestStats()
to get stats and achievements for the current user.
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()
Параметри — Няма;
Връща - a bool representing if the call succeeded or not. If the call failed then most likely Steam is not initialized. Make sure you have a steam client open when you try to make this call and that
SteamAPI_Init has been called before it.
Какво прави - This method basically wraps a call to
ISteamUserStats::RequestCurrentStats which is an asynchronous call to steam requesting the stats of the current user. This call needs to be made before you can set any stats or achievements. Първоначалното повикване към този метод се прави в конструктора. You can call it again any time after that if you want to check on updated stats or achievements.
bool CSteamStats::RequestStats()
{
// Is Steam loaded? If not we can't get stats.
if ( NULL == SteamUserStats() || NULL == SteamUser() )
{
return false;
}
// Is the user logged on? If not we can't get stats.
if ( !SteamUser()->BLoggedOn() )
{
return false;
}
// Request user stats.
return SteamUserStats()->RequestCurrentStats();
}
StoreStats()
Параметри — Няма;
Връща - a bool representing if the call succeeded or not. If the call failed then most likely Steam is not initialized. Make sure you have a steam client open when you try to make this call and that
SteamAPI_Init has been called before it.
Какво прави - This method basically wraps a call to
ISteamUserStats::StoreStats which is an asynchronous call to steam that stores the stats of the current user on the server. This call needs to be made anytime you want to update the stats of the user.
bool CSteamStats::StoreStats()
{
if ( m_bInitialized )
{
// load stats
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 );
// The averaged result is calculated for us
SteamUserStats()->GetStat(stat.m_pchStatName, &stat.m_flValue );
break;
default:
break;
}
}
return SteamUserStats()->StoreStats();
}
}
OnUserStatsReceived()
Параметри — Не е налично
Връща — Нищо.
Какво прави - This method is a callback that is called anytime you attempt to request stats. Статистиките се изискват, като се използва
RequestStats()
. The method updates the member variable m_Stats to reflect the latest stats data returned from Steam.
void CSteamStats::OnUserStatsReceived( UserStatsReceived_t *pCallback )
{
// we may get callbacks for other games' stats arriving, ignore them
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()
Параметри — Не е налично
Връща — Нищо.
Какво прави - This method is a callback that is called anytime you attempt to store stats on Steam. If any of the stats that we tried to set broke a constraint they will be reverted to their old value so we reload their values.
void CSteamStats::OnUserStatsStored( UserStatsStored_t *pCallback )
{
// we may get callbacks for other games' stats arriving, ignore them
if ( m_iAppID == pCallback->m_nGameID )
{
if ( k_EResultOK == pCallback->m_eResult )
{
OutputDebugString( "StoreStats - success\n" );
}
else if ( k_EResultInvalidParam == pCallback->m_eResult )
{
// One or more stats we set broke a constraint. They've been reverted,
// and we should re-iterate the values now to keep in sync.
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 );
}
}
}
Step 3 - Integrating into your game
The following is a complete listing of code snippets that you would need to integrate into your game in the appropriate locations.
Определения и глобални променливи
The following is the list of includes that are needed to build with Stats, an array for our game specific stats and a global pointer to our helper object. Please note that the stats match those of the Admin page on Steamworks.
...
#include "steam_api.h"
#include "isteamuserstats.h"
#include "SteamStats.h"
// Stats array which will hold data about the stats and their state
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 access to Stats Object
CSteamStats* g_SteamStats = NULL;
...
Инициализация
The call to
SteamAPI_Init initializes all of Steam and must be called before anything else. If that call succeeds then we create the helper object by passing in the array of stats along with the size of the array.
...
// Initialize Steam
bool bRet = SteamAPI_Init();
// Create the SteamStats object if Steam was successfully initialized
if (bRet)
{
g_SteamStats = new CSteamStats(g_Stats, 6);
}
...
Обработване на обратни повиквания
To ensure that we process all Steam callbacks we need to regularly pump for new messages. This is achieved by adding the this call to the game loop.
...
SteamAPI_RunCallbacks();
...
Запазване на статистики
Stats are saved by making an single call to
StoreStats()
.
...
if (g_SteamStats)
g_SteamStats->StoreStats();
...
Изключване
The call to
SteamAPI_Shutdown is probably something you already have in your code. It shuts down steam and must be called before you application exits. Finally we delete the helper object we created.
...
// Shutdown Steam
SteamAPI_Shutdown();
// Delete the SteamStats object
if (g_SteamStats)
delete g_SteamStats;
...
Step 4 - Testing and Troubleshooting
This sample code outputs debug information to the debug console that can help you understand what calls are succeeding or failing. The following are some typical failure messages and fixes:
This application has failed to start because steam_api.dll was not found. Re-installing the application may fix this problem.Make sure steam_api.dll is in the same directory as the executable.
[S_API FAIL] SteamAPI_Init() failed; unable to locate a running instance of Steam, or a local steamclient.dllYou most likely don't have a Steam client running. Start Steam and log in.
[S_API FAIL] SteamAPI_Init() failed; no appID found.You most likely don't have the steam_appid.txt file in place. Place it in your source folder and ensure that it has your appID number in it.