Dokumentasi Steamworks
Langkah demi Langkah: Statistik

Pendahuluan

Berikut ini adalah panduan lengkap untuk mengintegrasikan Statistik Steam yang paling dasar ke aplikasi dalam waktu kurang dari 10 menit dan mengintegrasikan kurang dari 10 baris kode ke kode dasarmu. SDK Steamworks hadir dengan contoh aplikasi yang sangat bagus, yaitu Spacewar, yang menunjukkan beragamnya pilihan fitur Steam dan seharusnya menjadi tempat pertamamu untuk melihat kerja seluruh fitur Steam. Tutorial ini merangkum informasi yang ditemukan di Spacewar dan API Statistik dan Pencapaian, sehingga hanya menyajikan informasi yang diperlukan untuk memahami cara kerja Statistik Steam. Harap diingat bahwa ada banyak tumpang tindih antara statistik dan pencapaian, sehingga jika kamu mengintegrasikan keduanya, banyak panggilan yang akan terkonsolidasi.

Langkah 1 - Mendefinisikan Statistik game-mu

Statistik bersifat khusus untuk aplikasi dan diatur di halaman Konfigurasi Statistik di backend Admin Aplikasi Steamworks. Berikut adalah daftar statistik dari aplikasi Spacewar di Steamworks:
stats_spacewar.png

Langkah 2 - Mengenkapsulasi kerja Statistik

Kode berikut bisa diterapkan pada game apa pun dan bisa ditambahkan ke game-mu sesuai kebutuhan. Kelasnya berfungsi penuh tanpa harus diubah, tapi bisa diekstensi untuk memenuhi kebutuhan lebih lanjut. Semua kode ini diambil langsung dari file Spacewar StatsAndAchievements.cpp/h.

File Tajuk

Kita mulai dengan mendefinisikan stuktur untuk menyimpan data statistik yang kita terima dari Steam dan menyediakan makro untuk membuat objek jenis ini. Data ini memetakan langsung apa yang ditemukan di halaman Konfigurasi Statistik.
#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; };

Kemudian, definisikan kelas helper yang akan membungkus panggilan API Statistik Steam, dan akan membuat semua callback Steam.
class CSteamStats { private: int64 m_iAppID; // AppID kita saat ini Stat_t *m_pStats; // Data Statistik int m_iNumStats; // Jumlah Statistik bool m_bInitialized; // Sudahkah kita memanggil statistik Permintaan dan menerima 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 ); };

File Kode

Konstruktor

Parameter - Konstruktor menyertakan penunjuk ke array statistik beserta panjang array. Format array ini tercakup dalam kode utama game di bawah ini.
Hasil - N/A
Fungsi - Konstruktor menginisialisasi sejumlah anggota sambil mengambil AppID yang sedang kita gunakan. Metode callback juga disertakan untuk memproses panggilan asinkron ke Steam. Terakhir, panggilan awal ke RequestStats() dilakukan untuk mengambil statistik dan pencapaian pengguna saat ini.
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()

Parameter - Tidak ada
Hasil - nilai boolean menunjukkan apakah panggilan berhasil atau gagal. Jika panggilan gagal, maka kemungkinan besar Steam tidak diinisialisasi. Pastikan Steam Client terbuka ketika melakukan panggilan ini dan bahwa SteamAPI_Init telah dipanggil sebelumnya.
Fungsi - Metode ini pada dasarnya membungkus panggilan ISteamUserStats::RequestCurrentStats yang merupakan panggilan asinkron ke Steam untuk meminta statistik dari pemain saat ini. Panggilan ini harus dibuat sebelum kamu mengatur statistik dan pencapaian. Panggilan awal untuk metode ini dibuat di konstruktor. Kamu bisa memanggilnya lagi kapan pun setelahnya jika kamu ingin melihat pembaruan statistik atau pencapaian.
bool CSteamStats::RequestStats() { // Apakah Steam dimuat? Kita tidak bisa mendapatkan statistik jika tidak. if ( NULL == SteamUserStats() || NULL == SteamUser() ) { return false; } // Apakah pengguna login? Kita tidak bisa mendapatkan statistik jika tidak. if ( !SteamUser()->BLoggedOn() ) { return false; } // Meminta statistik pengguna. return SteamUserStats()->RequestCurrentStats(); }

StoreStats()

Parameter - Tidak ada
Hasil - nilai boolean menunjukkan apakah panggilan berhasil atau gagal. Jika panggilan gagal, maka kemungkinan besar Steam tidak diinisialisasi. Pastikan Steam Client terbuka ketika melakukan panggilan ini dan bahwa SteamAPI_Init telah dipanggil sebelumnya.
Fungsi - Metode ini pada dasarnya membungkus panggilan ISteamUserStats::StoreStats yang merupakan panggilan asinkron ke Steam untuk menyimpan statistik dari pemain saat ini di server. Panggilan ini perlu dilakukan kapan saja kamu ingin memperbarui statistik pengguna.
bool CSteamStats::StoreStats() { if ( m_bInitialized ) { // muat statistik 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 ); // Hasil rata-ratanya sudah dihitung SteamUserStats()->GetStat(stat.m_pchStatName, &stat.m_flValue ); break; default: break; } } return SteamUserStats()->StoreStats(); } }

OnUserStatsReceived()

Parameter - N/A
Hasil - Tidak ada
Fungsi - Metode ini adalah callback yang dipanggil kapan saja kamu mencoba meminta statistik. Statistik diminta menggunakan RequestStats(). Metode ini memperbarui variabel anggota m_Stats untuk mencerminkan data statistik yang paling terkini yang didapatkan dari Steam.
void CSteamStats::OnUserStatsReceived( UserStatsReceived_t *pCallback ) { // kita mungkin akan mendapatkan callback untuk statistik game lain yang datang, abaikanlah if ( m_iAppID == pCallback->m_nGameID ) { if ( k_EResultOK == pCallback->m_eResult ) { OutputDebugString( "Received stats and achievements from Steam\n" ); // muat statistik 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()

Parameter - N/A
Hasil - Tidak ada
Fungsi - Metode ini adalah callback yang dipanggil kapan saja kamu mencoba untuk menyimpan statistik di Steam. Jika statistik yang telah ditetapkan melanggar batasan, statistik tersebut akan dikembalikan ke nilai lamanya agar nilainya dapat dimulai ulang.
void CSteamStats::OnUserStatsStored( UserStatsStored_t *pCallback ) { // kita mungkin akan mendapatkan callback untuk statistik game lain yang datang, abaikanlah if ( m_iAppID == pCallback->m_nGameID ) { if ( k_EResultOK == pCallback->m_eResult ) { OutputDebugString( "StoreStats - success\n" ); } else if ( k_EResultInvalidParam == pCallback->m_eResult ) { // Satu atau lebih statistik melanggar batasan yang ditetapkan. Aturan telah dikembalikan, // sekarang, kita harus mengulangi nilai untuk menyinkronkan. OutputDebugString( "StoreStats - some failed to validate\n" ); // Buat callback palsu sehingga nilai dapat dimulai ulang. 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 ); } } }

Langkah 3 - Mengintegrasikan ke game-mu

Berikut adalah daftar lengkap cuplikan kode yang harus kamu integrasikan ke game-mu di lokasi yang sesuai.

Definisi dan Global

Berikut ini adalah daftar pernyataan penyertaan yang dibutuhkan untuk membuat Statistik, penghitungan dari statistik khusus game kita, dan penunjuk global ke objek helper kita. Pastikan bahwa statistiknya sesuai dengan yang ada di halaman Admin di Steamworks.
... #include "steam_api.h" #include "isteamuserstats.h" #include "SteamStats.h" // Array statistik menyimpan data tentang statistik dan statusnya 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"), }; // Akses global ke Objek Statistik CSteamStats* g_SteamStats = NULL; ...

Inisialisasi

Panggilan ke SteamAPI_Init menginisialisasi keseluruhan Steam dan harus dipanggil sebelum yang lainnya. Jika panggilannya berhasil, buat objek helper dengan meneruskan array statistik dan ukuran array.
... // Menginisialisasi Steam bool bRet = SteamAPI_Init(); // Buat objek Pencapaian Steam jika Steam berhasil diinisialisasi if (bRet) { g_SteamAchievements = new CSteamAchievements(g_Achievements, 4); } ...

Memproses Callback

Untuk memastikan bahwa kita sudah memproses semua callback Steam, kita harus mengirimkan pesan baru secara teratur. Ini dicapai dengan menambahkan panggilan ini ke loop game.
... SteamAPI_RunCallbacks(); ...

Menyimpan Statistik

Statistik disimpan dengan melakukan satu panggilan ke StoreStats().
... if (g_SteamStats) g_SteamStats->StoreStats(); ...

Mematikan

Panggilan ke SteamAPI_Shutdown adalah sesuatu yang mungkin sudah ada di kodemu. Ini akan menutup Steam dan harus dipanggil sebelum aplikasimu tertutup. Terakhir, hapus objek helper yang kita buat.
... // Matikan Steam SteamAPI_Shutdown(); // Hapus objek SteamStats if (g_SteamStats) delete g_SteamStats; ...

Langkah 4 - Pengujian dan Troubleshoot

Kode contoh ini mengeluarkan informasi debug ke konsol debug yang dapat membantumu mengidentifikasi panggilan mana yang berhasil dan gagal. Berikut ini adalah beberapa pesan kegagalan umum dan perbaikannya:

Aplikasi ini gagal dijalankan karena steam_api.dll tidak ditemukan. Menginstal ulang aplikasi dapat memperbaiki masalah ini.
Pastikan steam_api.dll berada di direktori yang sama dengan executable.

[S_API FAIL] SteamAPI_Init() failed; tidak dapat menemukan Steam yang sedang dijalankan, atau steamclient.dll lokal
Kemungkinan besar tidak ada Steam Client yang sedang dijalankan. Buka Steam dan login.

[S_API FAIL] SteamAPI_Init() failed; tidak menemukan AppID.
Kemungkinan besar file steam_appid.txt tidak ada. Tempatkan file di folder source dan pastikan file tersebut berisi AppID aplikasimu.