Steamworks Belgeleri
Adım Adım: Başarımlar

Giriş

Aşağıda verilen adımları takip ederek 10 dakikada ve 10 satır kodla oldukça temel Steam başarımlarını 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 başarımlarını tanımlamak

Başarımlar uygulamaya özgüdür ve Steamworks uygulama yöneticisi arka ucundaki Başarım Yapılandırması sayfasında yapılır. Aşağıdaki başarımlar örnek uygulama olan Spacewar'dan alınmıştır:
spacewar_achievements.png

2. Adım - Başarımları 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 başarım verilerini tutacak bir yapı tanımlıyoruz ve bu tür objelerin yaratılması için bir makro sağlıyoruz. Bu veri doğrudan Başarım Yapılandırması sayfasında bulunanlarla eşleşir.
#define _ACH_ID( id, name ) { id, #id, name, "", 0, 0 } struct Achievement_t { int m_eAchievementID; const char *m_pchAchievementID; char m_rgchName[128]; char m_rgchDescription[256]; bool m_bAchieved; int m_iIconImage; };

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 CSteamAchievements { private: int64 m_iAppID; // Our current AppID Achievement_t *m_pAchievements; // Başarım verileri int m_iNumAchievements; // Başarım sayısı bool m_bInitialized; // "Request stats" çağrımı yaptık mı? Evetse geri çağrım alındı mı? public: CSteamAchievements(Achievement_t *Achievements, int NumAchievements); ~CSteamAchievements(); bool RequestStats(); bool SetAchievement(const char* ID); STEAM_CALLBACK( CSteamAchievements, OnUserStatsReceived, UserStatsReceived_t, m_CallbackUserStatsReceived ); STEAM_CALLBACK( CSteamAchievements, OnUserStatsStored, UserStatsStored_t, m_CallbackUserStatsStored ); STEAM_CALLBACK( CSteamAchievements, OnAchievementStored, UserAchievementStored_t, m_CallbackAchievementStored ); };

Kod Dosyası

Kurucu

Parametreler - Kurucu, bir başarı 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.
CSteamAchievements::CSteamAchievements(Achievement_t *Achievements, int NumAchievements): m_iAppID( 0 ), m_bInitialized( false ), m_CallbackUserStatsReceived( this, &CSteamAchievements::OnUserStatsReceived ), m_CallbackUserStatsStored( this, &CSteamAchievements::OnUserStatsStored ), m_CallbackAchievementStored( this, &CSteamAchievements::OnAchievementStored ) { m_iAppID = SteamUtils()->GetAppID(); m_pAchievements = Achievements; m_iNumAchievements = NumAchievements; 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 istatistik ve başarımlarını isteyen ISteamUserStats::RequestCurrentStats'e yapılan bir çağrıyı 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 CSteamAchievements::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(); }

SetAchievement()

Parametreler - Belirlemek istediğiniz başarımın tanıtıcı dizisi (yani "ACH_WIN_ONE_GAME")
Geri dönüş - çağrımın başarılı olup olmadığını temsil eden bir boole. Eğer çağrı başarısız olursa bunun nedeni ya Steam'in başlatılmamış olması ya da RequestStats'e yapılan çağrı sonucu alınan geri çağrıyı henüz işlememiş olmanızdır. Bu geri çağrı alınana kadar herhangi bir başarım belirleyemezsiniz.
Eylem - Bu yöntem bir başarımı başarıldı olarak değiştirir ve sonuçlarını Steam'e gönderir. Bir başarımı birden fazla kez belirleyebilirsiniz. Böylece henüz elde edilmemiş başarımları belirlemek zorunda kalmazsınız. Bu iki geri çağrıyı tetikleyen asenkron bir çağrıdır: OnUserStatsStored() ve OnAchievementStored().
bool CSteamAchievements::SetAchievement(const char* ID) { // Steam'den bir geri çağrı aldık mı? if (m_bInitialized) { SteamUserStats()->SetAchievement(ID); return SteamUserStats()->StoreStats(); } // Almadıysak başarımları belirleyemeyiz return false; }

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. İstatistik ve başarımlar RequestStats() kullanılarak istenir. Bu yöntem üye değişken m_pAchievements'ı, Steam'den dönen en son istatistik ve başarım verilerini yansıtacak şekilde günceller.
void CSteamAchievements::OnUserStatsReceived( UserStatsReceived_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("Received stats and achievements from Steam\n"); m_bInitialized = true; // başarımları yükle for ( int iAch = 0; iAch < m_iNumAchievements; ++iAch ) { Achievement_t &ach = m_pAchievements[iAch]; SteamUserStats()->GetAchievement(ach.m_pchAchievementID, &ach.m_bAchieved); _snprintf( ach.m_rgchName, sizeof(ach.m_rgchName), "%s", SteamUserStats()->GetAchievementDisplayAttribute(ach.m_pchAchievementID, "name")); _snprintf( ach.m_rgchDescription, sizeof(ach.m_rgchDescription), "%s", SteamUserStats()->GetAchievementDisplayAttribute(ach.m_pchAchievementID, "desc")); } } 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.
void CSteamAchievements::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( "Stored stats for Steam\n" ); } else { char buffer[128]; _snprintf( buffer, 128, "StatsStored - failed, %d\n", pCallback->m_eResult ); OutputDebugString( buffer ); } } }

OnAchievementStored()

Parametreler - Mevcut Değil
Geri dönüş - Hiçbir şey
Eylem - Bu yöntem, başarımları başarılı bir şekilde Steam'de sakladığınız zaman çağrılan bir geri çağrıdır.
void CSteamAchievements::OnAchievementStored( UserAchievementStored_t *pCallback ) { //diğer oyunlardan gelen istatistikler için geri çağrılar alabiliriz, bunları yok say if ( m_iAppID == pCallback->m_nGameID ) { OutputDebugString( "Stored Achievement for Steam\n" ); } }

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 "Achievements" ile derlenmesi gereken içerikler vardır; oyunumuza özgü başarımların sıralaması ve yardımcı objemiz için küresel bir işaretleyici. Başarımların Steamworks'teki yönetici sayfasındakilerle eşleştiğini unutmayın.
... #include "steam_api.h" // Başarımlarımızı tanımlamak enum EAchievements { ACH_WIN_ONE_GAME = 0, ACH_WIN_100_GAMES = 1, ACH_TRAVEL_FAR_ACCUM = 2, ACH_TRAVEL_FAR_SINGLE = 3, }; // Başarımlar ve durumlarıyla ilgili veri tutan başarım dizini Achievement_t g_Achievements[] = { _ACH_ID( ACH_WIN_ONE_GAME, "Winner" ), _ACH_ID( ACH_WIN_100_GAMES, "Champion" ), _ACH_ID( ACH_TRAVEL_FAR_ACCUM, "Interstellar" ), _ACH_ID( ACH_TRAVEL_FAR_SINGLE, "Orbiter" ), }; // "Achievements" öğesine küresel erişim CSteamAchievements* g_SteamAchievements = 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, başarımlar 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 "SteamAchievements" objesini oluştur if (bRet) { g_SteamAchievements = new CSteamAchievements(g_Achievements, 4); } ...

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(); ...

Başarımların Tetiklenmesi

Başarım tanımlayıcısı içeren tek bir çağrıyla bir başarım tetiklenebilir.
... if (g_SteamAchievements) g_SteamAchievements->SetAchievement("ACH_WIN_100_GAMES"); ...

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(); // "SteamAchievements" objelerini sil if (g_SteamAchievements) delete g_SteamAchievements; ...

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.