無所属

ホーム ドキュメントとヘルプ
Steamworks ドキュメンテーション
データと実績

概要

Steamデータと実績は、ゲームに永続的でさまざまな実績を提供するための簡単な方法を提供し、ユーザーの統計と実績情報を追跡します。 Steamアカウントと関連付けられたユーザーのデータや、個々のユーザーの実績およびデータは、フォーマットを整えられ、各ユーザーのSteamのコミュニティプロフィールに表示されます。

利点

プレイヤーに価値のある報酬を付与する以外にも、実績はチームワークとプレイヤー同士の対話を奨励し、ゲームの目的に深みを与え、ゲーム内で時間を過ごすことに対して満足感を提供できます。

データはプレイ時間、パワーアップ使用回数など、きめ細かい情報を追跡します。 または、ゲームの内部データの追跡に使用することもできます。そうすることで、たとえば複数台のコンピュータを使用する1人のユーザの、すべてのセッションにわたるゲームプレイのデータを収集して、実績を付与するというようなことも可能です。

実装概要

ゲームデータと実績の定義付け

実績はアプリケーション固有で、Steamworksパートナーサイトの「アプリ管理」ページで設定します。

ゲームでは3種類のデータを保存可能です:
  • INT-32ビットの符号付き整数(例:プレイしたゲーム数)
  • FLOAT-32ビットの浮動小数点値(例:運転した距離)
  • AVGRATE-移動平均。 次のドキュメントを参照:AVGRATEデータタイプ

SteamworksのパートナーWebサイトは、ゲームのデータと実績を定義しアップデートするためのインターフェイスを提供します。 これを利用することで、次が可能になります:
  • 初期統計データと実績の定義
  • 統計データと実績の追加
  • 実績の名称、説明、アイコンのアップデート
  • データパラメーターと制約(最大/最小値、画面サイズの移動平均など)のアップデート
データには、次のプロパティが用意されています:
  • ID-各データ用に自動的に生成される数値ID
  • Type-このデータの種類-INT、FLOAT、またはAVGRATE
  • API Name-APIを使って、このデータにアクセスするために使用される文字列
  • Set By-データを修正できる人を設定。 初期値は、クライアントに設定されています。 詳細は、 Game Server Stats を参照してください。
  • Increment Only-データは時間と共に増加することのみが可能になります。
  • Max Change-1つのSetStatコールから次のコールまでに変化できるデータ値の限度を設定します。
  • Min Value-このデータが受け入れる最小値を表します。 初期値では、最小値は基となる数値タイプの最小値になります(INT_MIN、またはFLT_MAX)。
  • Max Value-このデータが受け入れる最大値を表します。 初期値では、最大値は基本的な数値タイプの最大値になります(INT_MAX、またはFLT_MAX)。
  • Default Value-新規ユーザー用に最初に設定される初期値。 設定されない場合、初期値はゼロになります。
  • Aggregated-Steamはこのデータのグローバル合計を保持します。 詳細は、以下の「グローバルデータ」を参照してください。
  • Display Name-Steamコミュニティに表示されるデータの名称です。 ローカライズ可。
AVGRATE データには、以下の追加プロパティがあります:
  • Window-データの平均化に使用される「スライディングウィンドウ」のサイズ。
AVGRATEはSteamにより自動的に平均化されるデータです。 詳細は、以下のAVGRATEセクションを参照してください。

実績には、次のようなプロパティが用意されています:
  • ID-各実績用に自動的に生成される数値ID
  • API Name-APIで実績にアクセスするために使用される文字列
  • Progress Stat-この実績に対してコミュニティ上でプログレスバーとして使用されるデータを指定します。 データがアンロック値に達すると、実績も自動的にアンロックされます。
  • Display Name-クライアントの通知ポップアップやコミュニティで表示される実績の名前です。 ローカライズ可。
  • Description-コミュニティで表示される実績の説明です。 ローカライズ可。
  • Set By-実績をアンロックできる人を設定。 初期値は、クライアントに設定されています。 詳細は、 Game Server Statsを参照してください。
  • Hidden-trueの場合、「非表示」の実績は、達成するまでユーザーのコミュニティ ページ上に全く表示されません。
  • Achieved Icon-達成時に表示されるアイコン
  • Unachieved Icon-未達成時に表示されるアイコン

以下、Steamworks API Example Application (SpaceWar)からの実績のリストです:
achievements_spacewar.png

使用方法

ゲーム内からのデータと実績へのアクセス:

  • Steamworks APIの初期化後、ISteamUserStatsに含まれるStatsおよびAchievements APIの使用を開始できます。
  • ゲームセッションの開始時にISteamUserStats::RequestCurrentStatsを呼び出し、Steamのバックエンドからユーザーの統計データおよび実績を取得します。 データの準備が出来次第、ISteamUserStats::UserStatsReceived_tコールバックを受信します。
  • ISteamUserStats::GetStatおよびISteamUserStats::GetAchievementを使用して、データの反復処理を行い、ゲームの状態を初期化します。
  • ゲーム内で実績を表示するには、ISteamUserStats::GetAchievementDisplayAttributeを使用して、名前(「name」)や説明(「desc」)を含む、ユーザーが読める実績のプロパティデータを取得します。 これらのプロパティは、SteamworksパートナーのWebサイト上でローカライズでき、返送されるデータはユーザーがゲームを実行している言語によって異なります。 さらに、ISteamUserStats::GetAchievementIconを使用して実績のアイコンを取得や、ISteamUserStats::GetAchievementAndUnlockTimeでアンロックされた各実績の時間を取得することができます。
  • データの変更時、特にユーザーに表示されるデータの変更があった場合には、ISteamUserStats::SetStatまたは ISteamUserStats::UpdateAvgRateStatを呼び出してください。 この呼び出しは、Steamの内部メモリ状態だけを変更するもので、低コストです。 これにより、ゲームがクラッシュしたとしてもSteamはセッション間で変更を維持することができます。
  • ゲーム内の適切なポイント(チェックポイント、レベル遷移時など)にISteamUserStats::StoreStatsを呼び出し、変更をアップロードします。 完了すると、ISteamUserStats::UserStatsStored_tコールバックを受信します。
  • プログレスバーを持つ実績には、重大点においての進行状況のポップアップ表示のためにISteamUserStats::IndicateAchievementProgressを使用してください。 たとえば、20勝する必要がある場合に10回勝った時点で半分達成したことをユーザーに示す呼び出しに使うことができます。
  • 1つ以上の実績がアンロックされた際には、それぞれのアンロックされた実績に対してISteamUserStats::SetAchievementを呼び出し、次に実績をただちにアップロードするために ISteamUserStats::StoreStatsを呼び出します。 ゲームはISteamUserStats::UserStatsStored_tコールバックに加え、アンロックされた個々の実績に対して1つのISteamUserStats::UserAchievementStored_tコールバックを取得します。 その際、Steamのゲームオーバーレイはユーザーに通知パネルを表示します。

AVGRATEデータタイプ

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. 制限があるので、統計データの設定をラウンドの終わりまで待たないほうがいいでしょう。 継続的に設定し、ユーザーが終了すると同時に保存するようにしましょう。

クライアントはゲームサーバーが統計データを変更した際には自動的にアップデートを取得します。 しかし、クライアントと同様、サーバーが他のユーザー用にロードした統計データは自動的に更新されず、データが古い場合があります。

統計データの再設定

開発中には、テストのために1つのアカウント、またはすべてのアカウントの統計データや実績を完全に消去しなければならない場合があります。 To wipe stats for an account, call ISteamUserStats::ResetAllStats with bAchievementsToo set to true to wipe achievements as well. 呼び出しが完了したら、統計データと実績に対して反復処理を行い、メモリ内のゲーム状態を必ずリセットしてください。 ユーザー全員の統計データと実績を一括消去する方法はありません。 その理由の1つは、一括消去を実行しても、実行中のゲームはその消去に気付かず、メモリ内の値を書き戻すかもしれないためです。 幸いにも、ゲーム内に一括消去システムを構築する簡単な方法があります。 そのためには以下を実行してください:
  • 「バージョン」などのような名前で統計データを定義します。
  • ゲーム内にハードコードされた統計データのバージョン番号を設置します。
  • データがロードされたら、「バージョン」の統計データと、ハードコードされたバージョン番号を比較します。
  • それらが一致しない場合には、ISteamUserStats::ResetAllStatsを呼び出し、続いてハードコードされた番号に「バージョン」の統計データを設定します。
こうすれば、一括消去を実行しなければならない際に、ハードコードされたデータのバージョン番号を変更するだけでよくなります。 この一括消去は、ユーザーが新しいビルドを取得した際に実行されます。

統計データの一貫性

関連データの整合性が失われた状態を想定することは重要です。 たとえば、「GamesWon」「GamesLost」「GamesPlayed」という3つのデータがあるとします。 そして、最善を尽くしたにもかかわらず、統計データの同期に失敗したとしましょう。 この例の場合、ゲームの勝敗数の合計がプレイされたゲームの総数に合致しなくなってしまったとします。 解決策として「GamesLost」の統計データを除去し、代わりに「GamesPlayed」から「GamesWon」を引いて計算した場合、不整合によって「GamesLost」の数がマイナスになってしまうかもしれません。 この場合の最善策は、「GamesPlayed」のデータを破棄し、「GamesWon」 +「GamesLost」で算出することでしょう。

グローバル統計データ

統計データは管理ページで「総計済み」とマークすることで、そのデータのユーザー全員の総数を保管するようSteamに指示することができます。 これは、エコノミーでの総通貨量、総合キル数、お気に入りの武器、お気に入りのマップ、実績が良かったチームなどのデータの取得に使用することができます。 逆に言えば、「MostKills」のような統計には使用しないでください。複数のユーザーの数値を加算しても意味がありません。 統計データがユーザーの手にある場合、このデータは改変されてしまうことがあります。 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