概要
Steamworks APIは、APIを通じて提供されるすべての基盤システムにアクセスすることで、ゲームがSteamを最大限に活用できるようにします。 これには、ユーザーが
Steamオーバーレイを開いた際のゲームの一時停止、プレイへのフレンド招待、プレイヤーの
Steam実績アンロック、プレイヤー同士の
Steamランキング争いなどが含まれます。
Steamworks API リファレンス に、APIでサポートされるすべてのインターフェイス、関数、コールバック、型の一覧と説明があります。
Steamで製品を配信するにあたり、Steamworks APIとの統合は必須ではありませんが、Steamユーザーが期待する多くのインタラクションを実現できるため、強く推奨されます。
はじめに
注: Steamworks APIはC++を公式にサポートし、Microsoft WindowsのMicrosoft Visual Studio 2008以降、macOSとSteamOS/LinuxのGCC 4.6以降およびClang3.0以降を使用します。 サードパーティーのエンジンまたはC++以外のプログラミング言語を使用している場合は、まず
商用エンジンと非C++言語のサポートを参照の上、選択したエンジンや言語で開発を開始するための具体的な説明があるかどうかを確認してください。 場合によっては、これらの手順の多くは省略できます。
- まだお済みでない場合、Steamworks SDKをダウンロードして解凍します。
- Steamworks APIヘッダーフォルダー
public/steam
をアプリケーションのソースツリーの適切な場所にコピーします。
-
redistributable_bin
から関連する再頒布可能ファイルをプロジェクトフォルダーの適切な場所にコピーします。
- Windows
Visual Studioプロジェクトにsteam_api[64].lib
をリンクさせる必要があります。 これは、プライマリ実行可能ファイル、またはSteamを使用するモジュールにリンクできます。 これにより、SteamworksAPIヘッダーを介して公開されるsteam_api[64].dll
に含まれる機能にアクセスできます。 参考:DLLと実行形式のリンク
また、ランタイムディレクトリ(プログラム実行可能ファイルと共に、またはdll検索パス内)にsteam_api[64].dll
を入れて配布する必要があります。
- macOS
libsteam_api.dylib
は、SteamAPIのx86バージョンとx64バージョンの両方を提供します。 Xcodeプロジェクトでこれにリンクする必要があり、実行可能ファイルと一緒にこれを配布する必要があります。
参考:ダイナミックライブラリの使用
- Linux
libsteam_api.so
これにリンクして、実行可能ファイルと一緒に配布する必要があります。
初期化とシャットダウン
SteamAPI_Init
プロジェクト内にSteamworks APIをセットアップしたら、
SteamAPI_Init関数を呼び出してAPIを初期化することで、使用を開始できます。 これによりグローバル状態が設定され、インターフェイスの名前に一致するグローバル関数を介してアクセス可能なインターフェイスポインターが設定されます。 これは
Steamworksインターフェイスにアクセスする前に、
必ず呼び出され、正常に返される必要があります!
Steamworks APIはゲームのApp IDが不明な場合は初期化されません。 アプリをSteamから起動すると、アプリは自動で利用可能なApp IDを持ちます。 開発中は、テキストファイルでSteamにこれを示唆する必要があります。 App IDのみを含む実行可能ファイルの横に、
steam_appid.txt
というテキストファイルを作成してください。 これはSteamが提供する値を上書きします。 これはビルドと一緒に配信しないでください。 例:
480
falseの戻り値は、次の条件のいずれかを示します。
- Steamクライアントが実行されていない。 さまざまなSteamworksインターフェイスの実装には実行中のSteamクライアントが必要です。
- SteamクライアントがゲームのApp IDを特定できない。 実行ファイルまたはデバッガーから直接アプリケーションを実行している場合、ゲームディレクトリ内には、実行ファイルとApp IDのみを記述した
steam_appid.txt
というファイルが存在する必要があります。 Steamは現在使用中のディレクトリ内からこのファイルを探します。 実行可能ファイルを別のディレクトリから実行している場合は、そこにsteam_appid.txt
を配置してください。
- OSのユーザーが異なる、または管理のアクセスレベルが異なる等の理由で、アプリケーションを実行中のOSユーザーコンテキストと、Steamクライアントが異なる場合。
- 現在実行中のSteamアカウント上にそのappIDのライセンスを所有を確認する。 ゲームがあなたのSteamライブラリ内に表示されている必要があります。
- AppIDの設定が完了していない。例えばアプリのリリース状態が
利用不可
の場合や、デフォルトパッケージを未設定の場合。
初期化で問題が発生している場合、
Steamworks APIのデバッグドキュメントで、Steamworks APIをデバッグするさまざまな方法を参照してください。
SteamAPI_RestartAppIfNecessary
SteamAPI_RestartAppIfNecessaryは、実行可能ファイルがSteam経由で起動されたかどうかを確認し、当てはまらない場合にはSteam経由で再起動します。
これはオプションですが、ユーザーが実行ファイルを直接起動すると、アプリケーションに関連付けられているSteamコンテキスト(App ID含む)が設定されないことから、強く推奨しています。 推奨オプションを使用せずに直接起動した場合、
SteamAPI_Init
は失敗し、Steamworks APIは使用できなくなります。
このオプションを使用することを選択する場合は、
SteamAPI_Initの直前に、最初に実行するSteamworks関数として呼び出してください。
trueを返す場合、必要に応じてSteamクライアントが起動され、Steamを介してゲームを再起動します。できるだけ早く既存のプロセスを終了する必要があります。 これは実質的には
steam://run/<AppID>
を実行するため、この関数を呼び出した実行可能ファイルそのものを再起動しない場合があります (例:デバッガーから実行している場合など)。 これは常に、Steamライブラリフォルダーにインストールされているバージョンから再起動します。
それ以外は
falseを返し、ゲームはSteamクライアントによって起動されたことを意味し、他に必要なアクションはありません。 唯一の例外は
steam_appid.txt
ファイルが存在する場合で、この場合はどんな状態でも
falseを返します。 これによって、ゲームをSteamクライアントを介さずに起動して開発やテストを行えます。 Steamデポにゲームをアップロードするときには
steam_appid.txt
ファイルを必ず取り除いてください。
注: プライマリ実行可能ファイルにSteam DRMラッパーを使用する場合、DRMラッパーがこれを内部で実行するため、このチェックは不要です。
SteamAPI_Shutdown
Steamworks APIの使用が完了したら、
SteamAPI_Shutdownを呼び出して、Steam内でアプリケーションが使用しているリソースを解放する必要があります。 可能であればシャットダウンプロセスの最中にこれを呼び出します。
レンダリングAPIで使用が完了したという保証がないため、ゲームから
Steamオーバーレイをフック解除しません。
Steamworksインターフェイス
Steamworks APIは限られた特定の機能を公開する複数のインターフェイスで構成されています。
Steamworksが正常に初期化されたら、グローバル関数を介してインターフェイスにアクセスできます。 関数は常にインターフェイスの名前と一致します。
ISteamAppsには
SteamApps()
アクセサーを介して、
ISteamFriendsには
SteamFriends()
を介してアクセスできます。
これらのインターフェイスを使用して、次のような呼び出しを行うことができます。
// 現在のユーザーのSteam名を取得します。
const char *name = SteamFriends()->GetPersonaName();
Steamworks API リファレンスや、Steamworks APIヘッダーファイルからインターフェイスの完全なリストを見ることができます。
コールバック
Steamworksの最も重要な側面の1つであるコールバックは、ゲームをロックすることなく、Steamから非同期にデータを取得できるようにします。 コールバックの目的は、リスナーとして登録されたオブジェクトに非同期イベントを発生させる、シンプルかつ軽量、タイプセーフ、スレッドセーフな方法を提供することです。
通常、コールバックは、フレンドがログインまたはログオフした時などにSteamから発生するイベントや、一部のAPI関数の非同期結果を介してトリガーされます。 各コールバックは、一意の識別子と小さなデータセットを含む構造体で構成されます。 コールバックは
ISteam*.h
ヘッダーファイルで宣言され、最も密接に属するインターフェイスでグループ化されます。
コールバックをリッスンするには、構造体やクラスは宣言の中でマクロ
STEAM_CALLBACK( :classname, :functionname, :callbackname )
を使用する必要があります。
-
:classname
は、これを定義している構造体やクラスの名前でなければなりません。 (例: CGameManager
)
-
:functionname
はコールバックを受け取る関数の名前です。 (例: OnGameOverlayActivated
)
-
:callbackname
はコールバックの名前です。 (例: GameOverlayActivated_t
)
これは
void :functionname( :callbackname *pCallback )
として自動的にプロトタイプ化されるクラスのローカルメンバー関数を定義します。 オブジェクトの新しいインスタンスを作成すると、このメンバー関数はSteamworks APIでリスナーとして自身を登録します。オブジェクトが破棄されると、登録が解除されます。
注: コールバックをリッスンするオブジェクトを作成する前に、必ずSteamが初期化されていることを確認してください。
登録済みのリスナーにコールバックをディスパッチするには、
]steam_api::SteamAPI_RunCallbacksを呼び出す必要があります。 呼び出し間の時間が長いほど、Steamworks APIからイベントや結果を受け取る間の遅延が長くなるため、これは頻繁に呼び出すことが最適です。 ほとんどのゲームはフレームをレンダリングする度に呼び出します。少なくとも1秒に1度は呼び出すことを強くお勧めします。 登録されたすべてのリスナー関数は、この呼び出し中に、
SteamAPI_RunCallbacks
が呼び出されたスレッドコンテキストで呼び出されます。
例
よく使用されるコールバックのひとつが、
ISteamFriends::GameOverlayActivated_tです。 名前が示すように、ユーザーが
Steamオーバーレイを有効化または無効化する度に、コールバックを送信します。
class CGameManager
{
private:
STEAM_CALLBACK( CGameManager, OnGameOverlayActivated, GameOverlayActivated_t );
};
void CGameManager::OnGameOverlayActivated( GameOverlayActivated_t* pCallback )
{
if ( pCallback->m_bActive )
printf( "Steam overlay now active\n" );
else
printf( "Steam overlay now inactive\n" );
}
人気で推奨される使用法として、オーバーレイが開く時にゲームを一時停止するための
ISteamFriends::GameOverlayActivated_tコールバックの呼び出しがあります。
呼び出し結果
多くのSteamworksメソッドは、コールバックの代わりに呼び出し結果を使用して、関数呼び出しから非同期的に結果を返します。 コールバックと呼び出し結果の違いは、呼び出し結果は特定のリスナーのみをターゲットにするのに対して、コールバックはすべてのリスナーにブロードキャストされることです。 コールバックと同様に、ゲームは
SteamAPI_RunCallbacksを呼び出して、呼び出し結果をリスナーにディスパッチする必要があります。
戻り値を調べることで、呼び出し結果を提供する関数を識別できます。
SteamAPICall_tを返し、
CALL_RESULT()
属性がある場合、呼び出し結果を受け取るには登録する必要があります。 CCallResultに登録されたコールバックは、それに設定された最新の
SteamAPICall_tに対してのみトリガーされます。再利用する場合は注意してください。
注: コールバックと呼び出し結果は代替できません。 イベントは両方からではなく、どちらか一方からのみ受け取ります。 正しいイベントタイプに登録していることを必ず確認してください。
呼び出し結果は、CCallResultタイプを使用して、構造体/クラスのメンバーとして作成する必要があります。また、コールバックを受け取るメンバー関数も作成する必要があります。
void func( :callresultname *pCallback, bool bIOFailure );
CCallResult< :classname, :callresultname > m_callresultname;
-
:classname
は、これを定義している構造体やクラスの名前でなければなりません。 (例: CGameManager
)
-
:callbackname
はコールバックの名前です。 (例: NumberOfCurrentPlayers_t
)
関数、関数パラメーター、およびCCallResultタイプには、任意の名前を付けることができます。
例
以下は、
ISteamUserStats::NumberOfCurrentPlayers_t呼び出し結果を生成する
ISteamUserStats::GetNumberOfCurrentPlayers APIの使用例です。
// クラス定義内
class CGameManager
{
public:
void GetNumberOfCurrentPlayers();
private:
void OnGetNumberOfCurrentPlayers( NumberOfCurrentPlayers_t *pCallback, bool bIOFailure );
CCallResult< CGameManager, NumberOfCurrentPlayers_t > m_NumberOfCurrentPlayersCallResult;
};
// 現在のプレイヤー数を受け取るための非同期リクエストを作成します。
void CGameManager::GetNumberOfCurrentPlayers()
{
printf( "Getting Number of Current Players\n" );
SteamAPICall_t hSteamAPICall = SteamUserStats()->GetNumberOfCurrentPlayers();
m_NumberOfCurrentPlayersCallResult.Set( hSteamAPICall, this, &CGameManager::OnGetNumberOfCurrentPlayers );
}
// SteamAPI_RunCallbacks()の呼び出し後、SteamUserStats()->GetNumberOfCurrentPlayers()が非同期に返す時に呼び出されます。
void CGameManager::OnGetNumberOfCurrentPlayers( NumberOfCurrentPlayers_t *pCallback, bool bIOFailure )
{
if ( bIOFailure || !pCallback->m_bSuccess )
{
printf( "NumberOfCurrentPlayers_t failed!\n" );
return;
}
printf( "Number of players currently playing: %d\n", pCallback->m_cPlayers );
}
注: CCallResultシステムを使用できない場合、
ISteamUtils::IsAPICallCompleted、
ISteamUtils::GetAPICallResult、
ISteamUtils::GetAPICallFailureReasonを使用して、呼び出し結果のステータスを追跡できる場合があります。
手動コールバックディスパッチ
コールバックの登録に使用されるクラスとマクロは、C++コードで便利ですが、 コールバックを処理するための低レベルのメカニズムもあります。 このメカニズムは、Windowsのイベントループのように機能します。 すべてのコールバックと呼び出し結果をアクティブなリスナーにディスパッチする単一の関数の代わりに、ループ内で次に使用可能なコールバックを取得し、任意のメカニズムを使用してディスパッチします。 手動ディスパッチモードは、Steamworks SDKをC++以外の言語に公開するレイヤーをバインドする場合に特に便利です。 詳細は、
steam_api.h
内の
SteamAPI_ManualDispatch_Init()
を参照してください。
Steamゲームサーバー
Steamworks APIには、通常のクライアントだけでなく、ゲームサーバーの実行のサポートも含まれています。 Steamworks APIでは、ゲームサーバーとは、通常のユーザーがマルチプレイヤーゲームをプレイするために接続するシステム内のエンティティのことを指します。 これは、インターネットを介したリモートゲームサーバーへの接続でも、クライアントと同じプロセスにあるゲームサーバーへのローカル接続の場合もあります。 ゲームサーバーには独立したAPI関数のセットと、他のユーザーがそれを参照するための一意のSteamIDがあります。
SteamゲームサーバーAPIを使用するには、最初に
steam_api.h
ではなく、
steam_gameserver.h
をインクルードする必要があります。
ゲームサーバーAPIの初期化と使用は、通常のAPIと非常によく似ています。
ゲームサーバーを初期化すると、
ISteamGameServerと
ISteamGameServerStatsの2つのゲームサーバー専用インターフェイスにアクセスできるようになります。
ゲームサーバーから、以下の通常のインターフェイスにアクセスすることもできます。
- ISteamClient:グローバルインターフェイス
SteamGameServerClient()
経由でアクセスできます。
- ISteamUtils:グローバルインターフェイス
SteamGameServerUtils()
経由でアクセスできます
- ISteamNetworking:グローバルインターフェイス
SteamGameServerNetworking()
経由でアクセスできます
- ISteamHTTP:グローバルインターフェイス
SteamGameServerHTTP()
経由でアクセスできます
- ISteamUGC:グローバルインターフェイス
SteamGameServerUGC()
経由でアクセスできます
- ISteamApps:グローバルインターフェイス
SteamGameServerApps()
経由でアクセスできます
専用ゲームサーバー(クライアントコンポーネントを持たないサーバー)を実行する場合は、初期化するのはゲームサーバーAPIだけでよく、通常のユーザーAPIを初期化する必要はありません。
Steamworks APIのサンプルアプリケーション(SpaceWar)ではゲームサーバーAPIをフルに活用した例を紹介しています。
ゲームとは異なり、専用サーバーは通常、最新のSteamworksバイナリを提供するためのSteamクライアントがインストールされていない環境で実行されます。 専用サーバーに最新のSteamバイナリを含めるには、アプリに専用サーバーの再頒布可能ファイルを含める必要があります。
Partner.steamgames.comにログインし、アプリの技術設定に移動します。次に、「インストール/再頒布可能ファイル」の下の「専用サーー再頒布可能ファイル」をチェックします。
商用エンジンと非C++言語のサポート
商用ゲームエンジン、またはC/C++以外の言語を使用している場合、Steamworks APIのサポートのレベルを確認する必要があります。
一部のエンジンは、ネイティブの組み込みサポートを提供しますが、他のエンジンでは、サードパーティーのソリューションが必要になる場合があります。
お使いのエンジンにネイティブサポートがない場合は、
Steam Web APIを使用して、Steamがサポートする多くの機能にアクセスできます。
Steamworks SDKがエンジンにどのように実装されているかにかかわらず、
アプリケーションをSteamにアップロードするには最新のSteamworks SDKが必要です。
注: Steamで配信するソフトウェアの一部が、制限付きのオープンソースライセンスで利用できる場合は、
オープンソースアプリケーションをSteamで配信を参照してください。
以下は、Steamでゲームを配信するために頻繁に使用されるいくつかの一般的なエンジンと、そのエンジンと共にSteamworks SDKの使用を開始する方法についての関連ドキュメントです。
注: Valveがこれらのエンジンやサードパーティーのソリューションを推奨しているわけではありません。 このリストは純粋にアルファベット順に表示され、包括的なものではなく、スタートガイドとしてのみ存在します。 エンジンは、ネイティブサポートを含む場合、またはガイドラインに適合するサードパーティーソリューションがある場合にのみリストされます。 サードパーティーのソリューションは、Steamworks SDKに対して合理的な最新状態を保ち、パーミッシブライセンスの下で無料で利用でき(
オープンソースアプリケーションをSteamで配信参照)、
Steamworks掲示板にスレッドがある場合にのみリストされます。 自身のゲームの設定に最適なオプションを探すには、コミュニティのアドバイスを参考にすることを推奨します。
エンジン:
言語:
- ActionScript(Adobe Flash、AIR)
- C#
- D
- Java
- JavaScript
- Python
- Rust
他の言語にバインドするためのフラットインターフェイス
SDKには、他の言語のバインディングレイヤーの作成を容易にするための機能があります。
-
steam_api_flat.h
は、SDKのインターフェイス関数をミラーリングする一連のフラット関数を宣言します。 これは純粋なC言語コードではありませんが、平易なC言語リンケージと呼び出し規約を使用しているため、他の言語と簡単に相互運用できます。 これらの関数はsteam_api[64][.dll/.so/dylib]
によってエクスポートされます。
-
Steam_api.json
は、SDKの(ほとんどすべての)インターフェイス、型、および関数を記述します。 このファイルは、バインディングレイヤーの自動生成プロセスで使用するためのものです。 これを使用することにより、作業の95%を自動化できることを願っていますが、手動で処理する必要のある特殊なケースもまだいくつかあります。 特に、CSteamIDとCGameIDを効率的にするには、バインディングレイヤーで特別な処理が必要になることがあります。
技術詳細
Steamは、さまざまな手法でアプリケーションに機能を提供します。 Steamworks APIの仕組みを完全に理解する必要はありませんが、非常にシンプルであり、Steamとの統合を念頭に置いてゲームのコードを書く際に役立ちます。
steam_api[64][.dll/.so/dylib]
にリンクすると、
S_API
マクロのプレフィックスを持つ
少数のC言語関数へのアクセスを提供します。これらの関数はすべて、
steam_api.h
と
steam_gameserver.h
内で公開されています。
steam_api
モジュール自体は非常に小さく、Steamworks APIの初期化とシャットダウンのための基本機能のみを公開しています。
Steamworks APIの初期化時に、実行中のアクティブなSteamクライアントプロセスを検出し、そのパスから
steamclient.dll
を読み込みます。
steamclient.dll
は、基本的にSteamクライアントのコアエンジンです。 Steamの実行に必要な情報を含み管理します。 SteamクライアントUIは、ここで公開されているのと同様の一連の関数を使用して、
steamclient.dll
が提供するデータにアクセスします。 このデータはSteamプロセス内にあるため、すべてのSteam API呼び出しは透過的にマーシャリングされ、RPC/IPCメカニズムを介して送信されます。 (クロスプロセスパイプ、
ISteamClient::HSteamPipe)
Steamのプロセスは、
steamclient.dll
を介して、Steamのバックエンドサーバーとの常時接続を維持します。 この接続を通じて、すべての認証、マッチメイキング、フレンドリスト、VACシステムとの通信が行われます。 ユーザーにネットワークの問題がある場合や、接続しているSteamサーバーがアップデートを受信した場合、この接続が切断されることがあります。 接続が切断、または再確立されると、実行中のアプリケーションにコールバックが送信されます。 Steamクライアントは自動的に再接続を試みます。アプリを実行しているクライアントが優先されるため、通常の再接続時間は10秒未満ですが、まれに最大5分になることもあります。
Steamworks APIは、COMのようなメカニズムでバージョン管理されており、インターフェイスの文字列名とバージョンを
steamclient.dll
に渡すと、インターフェイスの正しいバージョンを呼び出し元に返します。
steamclient.dll
には、リリースされたすべてのバージョンのインターフェイスに対応する一連のアダプターが含まれており、古い関数呼び出しをリダイレクトしたり、最新のインターフェイスのコンテキストで再解釈したりします。 アダプターはSteamクライアント内に存在するため、問題が発生した場合も簡単に更新できます。