Documentazione di Steamworks
Stats and Achievements

Panoramica

Steam Stats and Achievements provides an easy way for your game to provide persistent, roaming achievement and statistics tracking for your users. The user's data is associated with their Steam account, and each user's achievements and statistics can be formatted and displayed in their Steam Community Profile.

Utilità

Oltre a consentire agli utenti di ottenere ricompense di grande valore, gli achievement forniscono un'ulteriore dimensione agli obiettivi di gioco. Sono utili per incoraggiare e premiare il lavoro di squadra e l'interazione tra giocatori, ma anche per ricompensare gli utenti per il tempo passato a giocare.

Grazie alle statistiche è possibile monitorare informazioni dettagliate quali il tempo di gioco, il numero di potenziamenti utilizzati e così via. Puoi scegliere di utilizzare le statistiche per il semplice monitoraggio interno dei dati di gioco. In questo modo, ad esempio, consentirai all'utente di ottenere un achievement in base alle statistiche accumulate in più sessioni di gioco e da computer diversi.

Panoramica sull'implementazione

Definire le statistiche e gli achievement del gioco

Gli achievement sono elementi specifici dell'applicazione e vengono configurati dalla pagina Amministratore applicazione del sito Steamworks per i partner.

Il gioco può conservare informazioni su tre tipi di statistiche:
  • INT - A 32-bit (signed) integer (e.g. number of games played)
  • FLOAT - A 32-bit floating point value (e.g. number of miles driven)
  • AVGRATE: una media mobile. See: The AVGRATE stat type

Il sito web di Steamworks per i partner fornisce un'interfaccia per la definizione e l'aggiornamento delle statistiche e degli achievement del gioco. Tramite l'interfaccia è possibile:
  • Define the initial statistics and achievements
  • Add additional stats and achievements
  • Update achievement names, descriptions, and icons
  • Update statistic parameters and constraints (max/min values, moving-average window sizes, etc)
Proprietà delle statistiche:
  • ID - An automatically-generated numerical ID for each stat.
  • Tipo: il tipo di statistica (INT, FLOAT o AVGRATE).
  • Nome API: la stringa utilizzata per accedere alla statistica utilizzando l'API.
  • Impostata da: stabilisce chi può modificare la statistica. L'impostazione predefinita è "Client". Per ulteriori informazioni, consulta Game Server Stats.
  • Solo incremento: impostando questa proprietà, il valore della statistica può solo aumentare nel tempo.
  • Variazione max: impostando questa proprietà si configura il limite di variazioni che il valore della statistica può subire tra due chiamate SetStat.
  • Valore min: se impostato, indica il valore numerico minimo che la statistica può assumere. Per impostazione predefinita, il valore minimo corrisponde al valore minimo del tipo numerico sottostante (INT_MIN o FLT_MAX).
  • Valore max: se impostato, indica il valore numerico massimo che la statistica può assumere. Per impostazione predefinita, il valore massimo corrisponde al valore massimo del tipo numerico sottostante (INT_MAX o FLT_MAX).
  • Valore predefinito: se impostato, indica il valore predefinito iniziale della statistica per un nuovo utente. Se non viene impostato, il valore predefinito è zero.
  • Aggregata: impostando questa proprietà, Steam tiene traccia del totale globale della statistica. Per ulteriori informazioni, consulta la sezione relativa alle statistiche globali riportata più in basso.
  • Nome visualizzato: il nome della statistica visualizzato nella Comunità di Steam. Può essere tradotto.
Proprietà aggiuntive delle statistiche AVGRATE stats have the following additional properties:
  • Finestra: le dimensioni della finestra mobile utilizzata per calcolare la media dei dati.
Per le statistiche AVGRATE la media viene calcolata automaticamente da Steam. Per ulteriori informazioni, consulta la sezione AVGRATE riportata di seguito.

Proprietà degli achievement:
  • ID: un ID numerico generato automaticamente per ogni achievement.
  • Nome API: la stringa utilizzata per accedere all'achievement utilizzando l'API.
  • Statistica di avanzamento: specifica la statistica usata nella Comunità come barra di avanzamento per l'achievement. L'achievement verrà sbloccato automaticamente quando la statistica raggiunge il valore di sblocco.
  • Nome visualizzato: il nome dell'achievement visualizzato nelle notifiche pop-up del client e nella Comunità. Può essere tradotto.
  • Description - A description of this achievement, for displaying in the Community. Può essere tradotta.
  • Impostato da: stabilisce chi può sbloccare l'achievement. L'impostazione predefinita è "Client". Per ulteriori informazioni, consulta Game Server Stats.
  • Nascosto: se l'achievement possiede questa proprietà, verrà completamente nascosto dalla pagina della Comunità dell'utente fino a quando non verrà completato.
  • Icona achievement completato: l'icona che viene visualizzata quando l'achievement viene completato.
  • Icona achievement in corso: l'icona che viene visualizzata quando l'achievement non è ancora stato completato.

The following is the list of achievements from the Steamworks API Example Application (SpaceWar):
achievements_spacewar.png

Come usare statistiche e achievement

Per accedere a statistiche e achievement dall'interno del gioco:

The AVGRATE stat type

This type of stat provides some unique and very useful functionality, but it requires a little bit more detail to explain.

Consider the case where you'd like to track an average statistic, such as "Points earned per hour". One approach would be to have two stats, an INT "TotalPoints" and a FLOAT "TotalPlayTimeHours", and then divide points by time to get Points per Hour.

The downside to this implementation is that, once the player has accumulated a significant amount of playtime, the calculated average will change extremely slowly. In fact, the more the user plays the game, the less responsive that average will be. If the user has spent 100 hours playing the game, the calculated average will "lag" by about 50 hours of that. If they increase their skill, they will not see the increase in Points Per Hour that they expect.

The AVGRATE stat type lets you implement a "sliding window" effect on the average. For instance, you can utilize only the previous few hours of gameplay, so the statistic will more accurately reflect the player's current skill level.

Let's set up an AVGRATE stat to implement "points per hour" where only the previous 20 hours of gameplay affect the value. To do this, you would:
  • Note that, because the average will be "per hour", the time units on all time parameters associated with this stat will be "hours". This applies to the Window property on the stat itself, and also for the "dSessionLength" parameter passed in to UpdateAvgRateStat below.
  • Create an AVGRATE stat named "AvgPointsPerHour", and a Window property of 20.0 (remember, that's in "hours")
  • At appropriate points during your game, call ISteamUserStats::UpdateAvgRateStat with the following parameters:
    • pchName - "AvgPointsPerHour"
    • flCountThisSession - The number of points the player earned since the last call to UpdateAvgRateStat.
    • dSessionLength - The amount of game time since the last call to UpdateAvgRateStat. The unit should be the same as the unit on the stat's Window property. In this case, it is "hours".
  • For instance, if the player earned 77 points in the last round, which lasted 0.225 hours (13.5 minutes), that would be SteamUserStats()->UpdateAvgRateStat( "AvgPointsPerHour", 77, 0.225 )
In the above example, Steam will take the current rounds average of 342.2 points per hour ( 77 divided by 0.225 ) and blend it with the previous value. The result will reflect the total average over the player's last 20 hours of game time. If this were the first time the stat was updated for the current user, the current value would be 342.2.

This example uses "hours" as the time unit, but you may use whatever time unit you wish. Just keep in mind that you must consistently use that unit as your base for "dSessionLength", as well as the Window property.

Getting stats for other users

You can use ISteamUserStats::RequestUserStats to get the stats for another user. You can then use ISteamUserStats::GetUserStat, ISteamUserStats::GetUserAchievement, and ISteamUserStats::GetUserAchievementAndUnlockTime to get data for that user. This data is not updated automatically as the other user uploads new stats, so to refresh the data just call ISteamUserStats::RequestUserStats again.

To keep from using too much memory, a Least Recently Used (LRU) cache is maintained and other user's stats will occasionally be unloaded. When this happens a ISteamUserStats::UserStatsUnloaded_t callback is automatically sent. When this callback is sent then the specified user's stats will be unavailable until ISteamUserStats::RequestUserStats is called again.

Offline mode

Steam keeps a local cache of the stats and achievement data so that the APIs can be used as normal in offline mode. Any stats unable to be committed are saved for the next time the user is online. In the event that there have been modifications on more than one machine, Steam will automatically merge achievements and choose the set of stats that has had more progress. Because Steam keeps a local cache of stats data it is not necessary for the game to also keep a local cache of the data on disk. Such caches often come in conflict and when they do it looks to a users as if their progress has been reverted, which is a frustrating experience.

Game Server Stats

Parallel to ISteamUserStats is ISteamGameServerStats for game servers. These can get stats for users in the same way as clients can (described above). They can also set stats and award achievements, but only if "Set by" is set to GS (game server) or Official GS. The difference between game servers and official game servers is that official game servers are servers that you host and control. Using official game servers to set stats offers enhanced security against cheating, as users may be able to modify their own game servers or spoof being a game server. To define official game servers, enter the IP ranges of the servers here.

Stats and achievements that are settable by game servers cannot be set by clients. Game servers can only set stats and achievements for users currently playing on the server. If the user leaves the server there is a short grace period to set any final stats, but then any new uploads will be denied. This is to help ensure consistency and to avoid making it possible for a malicious game server to set anyone's stats at any time. Given the restriction, it is important not to wait until the end of a round to set stats. Set them continuously so you can store them as a user quits.

Clients will get automatic updates when a game server changes their stats. However, like clients, stats loaded by the server for other users are not refreshed automatically and can age out.

Resetting stats

During development, it is often the case that a complete wipe of stats and achievements on an account or all accounts is desirable for testing. To wipe stats for an account, call ISteamUserStats::ResetAllStats with bAchievementsToo set to true to wipe achievements as well. Once called remember to reiterate your stats and achievements and reset your in-memory game state. There is no way to globally wipe stats and achievements for all users. One of the reasons for this is that even if a global wipe were to be done, games in-progress may not notice the wipe and write back in-memory values. Fortunately, there is an easy way to build a global wipe system into your game. To do so:
  • Define a stat with a name like "Version"
  • Put a hardcoded stats version number in the game
  • Once stats have been loaded, compare the "Version" stat against your hardcoded version number
  • If they don't match, call ISteamUserStats::ResetAllStats and then set the "Version" stat to the hardcoded number.
This way, whenever you want a global wipe just change the hardcoded stats version number. The global wipe will then happen as people get the new build.

Stat consistency

It's a best practice to think about how related stats could become inconsistent. For instance, you may have three stats "GamesWon", "GamesLost", and "GamesPlayed". Despite the best of intentions, stats can and do get out of sync with each other. In this case, that could lead to games won and lost not adding up to the total of games played. If this was resolved by removing the "GamesLost" stat and instead computing it as "GamesPlayed" - "GamesWon", an inconsistency could cause "GamesLost" to be negative. In this case, it's best to drop the "GamesPlayed" stat and compute it as "GamesWon" + "GamesLost".

Global Stats

Stats can be marked as aggregated on the admin page to tell Steam to keep a global total of all users' values for the stat. This can be used to get data on total money in the economy, total kills, favorite weapons, favorite maps, and which team tends to do better. On the flip side, this should not be used for stats like "MostKills" as adding that up for multiple users would be meaningless. As stats are in the hands of users, this data is subject to being manipulated. Therefore it's crucial when using aggregated stats to set good bounds for min value, max value, increment only (if appropriate), and max change. Max change has a special meaning for aggregated stats. When a new value is uploaded, the global value will change no more than the max change value. This limits how quickly a cheater can influence the global totals.

To access the global totals, call ISteamUserStats::RequestGlobalStats and then ISteamUserStats::GetGlobalStat for each global stat. You can also ask for ISteamUserStats::RequestGlobalStats for a specified number of days of history. The history is the amount that stat changed every day. You can access that history with ISteamUserStats::GetGlobalStatHistory.

You can also request global achievement completion percentages from the client. To do so first call ISteamUserStats::RequestGlobalAchievementPercentages. Then, iterate the achievements in order of most completed to least completed by calling ISteamUserStats::GetMostAchievedAchievementInfo and ISteamUserStats::GetNextMostAchievedAchievementInfo. You can also get the completion percentage for a particular achievement by calling ISteamUserStats::GetAchievementAchievedPercent.

The Steam Community

After your game has been released then information about individual and global achievement progress will be displayed in the Steam Community. Each player will have a link from their Community profile that goes to a page showcasing what they have achieved, and which they have yet to unlock.
NOTE: Your achievements will not be shown until your app is somewhat visible to the community.

Each achievement is listed with the appropriate icon, and the name and description as set in the Steamworks control panel. If the achievement name and description have been localized into the language the user has selected, then they will display in that language.

There will also be a link from this page, and one from your game's main Steam page, to a set of global achievement statistics for your game. It displays the percentage of Steam players of the game that have achieved each one, ordered from most common to the rarest achievement. This is fun for players to see, and also a great resource for you as a developer: are your special challenges hard enough? Or maybe too hard? (this information is also available on the Sales and Activations Reports site).

More Questions?

Ask questions on the Stats and Achievements discussion board