Steamworks Belgeleri
Adım Adım: İstatistikler

Giriş

Aşağıda verilen adımları takip ederek 10 dakikada ve 10 satır kodla oldukça temel Steam istatistiklerini uygulamanızın kod tabanına entegre edebilirsiniz. Steamworks SDK'in beraberinde örnek bir uygulama olan ve Steam özelliklerinin kapsayıcılığını gösteren Spacewar ile gelir. Bütün Steam özelliklerini çalışırken gözlemlemek istiyorsanız yapmanız gereken ilk şey bu uygulamayı incelemektir. Bu rehberde; Spacewar'da, İstatistikler ve Başarımlar API'ında bulunan bilgiler sadece Steam İstatistikleri ile ilgili olacak şekilde süzülmüştür. İstatistikler ve başarımlar arasında oldukça fazla kesişen nokta olduğunu lütfen aklınızda bulundurun. Yani eğer bu ikisini entegre edecekseniz birçok çağırma birleştirilebilir.

1. Adım - Oyununuzun istatistiklerini tanımlamak

İstatistikler uygulamaya özgüdür ve Steamworks uygulama yöneticisi arka ucundaki İstatistik Yapılandırması sayfasında yapılır. Aşağıdaki istatistikler örnek uygulama olan Spacewar'dan alınmıştır:
stats_spacewar.png

2. Adım - İstatistikleri hazırlamak

Aşağıdaki kod oyundan bağımsızdır ve oyununuza istediğiniz şekilde eklenebilir. Sınıf olduğu şekliyle işlevseldir fakat diğer ihtiyaçlarınıza uyum sağlayacak şekilde genişletilebilir. Bu kodun tamamı doğrudan Spacewar'un örnek StatsAndAchievements.cpp/h dosyalarından alınmıştır.

Üstbilgi Dosyası

Öncelikle Steam'den alınan istatistik verilerini tutacak bir yapı tanımlıyoruz, ardından bir sıralamada istatistik türlerini tanımlıyoruz ve istatistik objelerinin yaratılması için bir makro sağlıyoruz. Bu veri doğrudan İstatistik Yapılandırması sayfasında bulunanlarla eşleşir.
#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; };

Ardından bütün Steam İstatistik API'ı çağırmalarını saracak ve bütün Steam geri çağırmalarını yapacak yardımcı bir sınıf tanımlıyoruz.
class CSteamStats { private: int64 m_iAppID; // Şimdiki AppID Stat_t *m_pStats; // İstatistik verileri int m_iNumStats; // İstatistik sayısı bool m_bInitialized; // "Request stats" çağrımı yaptık mı? Evetse geri çağrım alındı mı? 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 ); };

Kod Dosyası

Kurucu

Parametreler - Kurucu, bir istatistik dizininden dizinin uzunluğunu da içeren bir işaretleyici alır. Bu dizinin biçimi daha sonra ana oyunun koduyla dolacaktır.
Geri dönüş - Mevcut Değil
Eylem - Kurucu birçok üyeyi başlatır ve aynı zamanda şu anda çalıştırdığımız AppID'yi de alır. Buna ek olarak, Steam'e yapılan asenkron çağrımları işleyebilmek için geri dönüş yöntemlerine bağlanır. Son olarak, mevcut kullanıcının istatistik ve başarımlarını almak için RequestStats()'e ilk çağrımı yapar.
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()

Parametreler - Hiçbiri
Geri dönüş - çağrımın başarılı olup olmadığını temsil eden bir boole. Eğer çağrım başarısız olmuşsa bunun en muhtemel sebebi Steam'in başlatılmamış olmasıdır. Bu çağrımı yaparken Steam istemcisinin çalışıyor olduğundan ve önceden SteamAPI_Init'i çağırdığından emin olun.
Eylem - Bu yöntem, Steam'e asenkron çağrı yaparak mevcut kullanıcının istatistiklerini isteyen ISteamUserStats::RequestCurrentStats'e yapılan bütün çağrımları sarar. Bu çağrı, siz herhangi bir istatistik veya başarım belirlemeden önce yapılmalıdır. Bu yönteme yapılan ilk çağrı kurucuda yapılır. Bundan sonra eğer güncellenen istatistik veya başarımlara bakmak isterseniz bunu tekrar çağırabilirsiniz.
bool CSteamStats::RequestStats() { // Steam yüklü mü? Değilse istatistikleri alamayız. if ( NULL == SteamUserStats() || NULL == SteamUser() ) { return false; } // Kullanıcı giriş yapmış mı? Değilse istatistikleri alamayız. if ( !SteamUser()->BLoggedOn() ) { return false; } // Kullanıcı istatistiklerini iste. return SteamUserStats()->RequestCurrentStats(); }

StoreStats()

Parametreler - Hiçbiri
Geri dönüş - çağrımın başarılı olup olmadığını temsil eden bir boole. Eğer çağrım başarısız olmuşsa bunun en muhtemel sebebi Steam'in başlatılmamış olmasıdır. Bu çağrımı yaparken Steam istemcisinin çalışıyor olduğundan ve önceden SteamAPI_Init'i çağırdığından emin olun.
Eylem - Bu yöntem, mevcut kullanıcının istatistiklerini sunucuda saklayan Steam'e asenkron çağrı yapan ISteamUserStats::StoreStats'e yapılan bir çağrıyı sarar. Kullanıcının istatistiklerini güncellemek istediğiniz zaman bu çağrımı yapmalısınız.
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 ); // Ortalaması alınmış bir sonuç bizim için hesaplanır SteamUserStats()->GetStat(stat.m_pchStatName, &stat.m_flValue ); break; default: break; } } return SteamUserStats()->StoreStats(); } }

OnUserStatsReceived()

Parametreler - Mevcut Değil
Geri dönüş - Hiçbir şey
Eylem - Bu yöntem, istatistik istediğiniz zaman çağrılan bir geri çağrıdır. İstatistikler RequestStats() kullanılarak istenir. Bu yöntem üye değişken m_Stats'i, Steam'den dönen en son istatistik verilerini yansıtacak şekilde günceller.
void CSteamStats::OnUserStatsReceived( UserStatsReceived_t *pCallback ) { // diğer oyunlardan gelen istatistikler içi geri çağrılar alabiliriz, bunları yok say if ( m_iAppID == pCallback->m_nGameID ) { if ( k_EResultOK == pCallback->m_eResult ) { OutputDebugString( "Received stats and achievements from Steam\n" ); // istatistikleri yükle 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()

Parametreler - Mevcut Değil
Geri dönüş - Hiçbir şey
Eylem - Bu yöntem, Steam'de istatistik saklamaya çalıştığınız zaman çağrılan bir geri çağrıdır. Ayarlamaya çalıştığımız bir istatistiklerden biri bir kısıtlamayı bozarsa bunları eski değerlerine dönecek şekilde tekrar yükleriz.
void CSteamStats::OnUserStatsStored( UserStatsStored_t *pCallback ) { // diğer oyunlardan gelen istatistikler için geri çağrılar alabiliriz, bunları yok say if ( m_iAppID == pCallback->m_nGameID ) { if ( k_EResultOK == pCallback->m_eResult ) { OutputDebugString( "StoreStats - success\n" ); } else if ( k_EResultInvalidParam == pCallback->m_eResult ) { // Ayarladığımız bir veya daha fazla istatistik bir kısıtlamayı bozdu. Eski hâllerine geri çevrildiler. // Bunları senkronize tutabilmek için değerlerini yenilemeliyiz. OutputDebugString( "StoreStats - some failed to validate\n" ); // Değerleri tekrar yükleyebilmemiz için burada sahte bir geri çağrıda bulunun. 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. Adım - Oyununuza entegre etmek

Aşağıda oyununuzun uygun yerlerine entegre etmeniz gereken kod parçalarının tam bir listesi yer almaktadır.

Tanımlamalar ve Küreseller

Aşağıda "Stats" ile derlenmesi gereken içerikler vardır; oyunumuz için belirli istatistikler ve yardımcı objemiz için küresel bir işaretleyici. İstatistiklerin Steamworks'teki yönetici sayfasındakilerle eşleştiğini unutmayın.
... #include "steam_api.h" #include "isteamuserstats.h" #include "SteamStats.h" // İstatistikler ve durumlarıyla ilgili veri tutan istatistik dizini 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"), }; // "Stats" objesine küresel erişim CSteamStats* g_SteamStats = NULL; ...

Başlatma

SteamAPI_Init'e yapılan çağrı Steam'i tamamen başlatır ve bu çağrı diğer her şeyden önce yapılmalıdır. Eğer bu çağrı başarılı olursa, istatistikler dizininden geçerken dizinin boyutuyla birlikte bir yardımcı obje oluştururuz.
... // Steam'i başlat bool bRet = SteamAPI_Init(); // Eğer Steam başarılı bir şekilde başladıysa "SteamStats" objesini oluştur if (bRet) { g_SteamStats = new CSteamStats(g_Stats, 6); } ...

Geri Çağrıların İşlenmesi

Bütün Steam geri çağrılarını işleyebilmemiz için düzenli olarak yeni mesajlar göndermeliyiz. Bunun başarılabilmesi için şu çağrıyı oyunun döngüsüne eklemelisiniz.
... SteamAPI_RunCallbacks(); ...

İstatistikleri Kaydetmek

İstatistikler StoreStats()'e tek bir çağrıda bulunularak kaydedilir.
... if (g_SteamStats) g_SteamStats->StoreStats(); ...

Kapatma

SteamAPI_Shutdown'a yapılan çağrı muhtemelen kodunuzda zaten mevcuttur. Steam'i kapatır ve uygulamadan çıkmadan önce çağrılması gereklidir. Son olarak da oluşturduğumuz yardımcı objeyi siliyoruz.
... // Steam'i kapat SteamAPI_Shutdown(); // "SteamStats" objelerini sil if (g_SteamStats) delete g_SteamStats; ...

4. Adım - Test etme ve sorun giderme

Bu örnek kod, hangi çağrıların başarılı hangilerinin başarısız olduğunu hata ayıklama konsolunda hata ayıklama bilgisi olarak gösterir. Aşağıda bazı tipik hata mesajları ve çözüm yolları yer almaktadır:

steam_api.dll bulunamadığı için bu uygulama başlatılamadı. Uygulamayı tekrar yükleyerek bu sorunu çözebilirsiniz.
steam_api.dll'in yürütülebilirle aynı dizinde olduğundan emin olun.

[S_API FAIL] SteamAPI_Init() başarısız: Çalışan bir Steam örneği ya da ya da yerel bir steamclient.dll bulunamadı.
Muhtemelen bir Steam istemcisi çalıştırmıyorsunuz. Steam'i başlatın ve giriş yapın.

[S_API FAIL] SteamAPI_Init() başarısız: herhangi bir appID bulunamadı.
Muhtemelen steam_appid.txt dosyası olması gereken yerde değil. Kaynak klasöre bu dosyayı yerleştirin ve içinde appID numaranızın oluğundan emin olun.