PC ゲームといえば、Steam というサービスが世界で大人気ですよね。
規模としては、数百万人もの人が同時に接続しているほどです。
Unity を使えば、Steam にも自分で作ったゲームを出すことができます。
実は PlayFab では、Steam のゲーム内アイテムをリアルマネーで購入させたい、という場合にも対応しているんです。
しかし、手順が少し難しいため、この記事でわかりやすくまとめました。
この記事を読むことで、PlayFab と Steam をすぐに連携できるはずです。
Steamworks でリリースできるアプリがないと、この先の作業ができません。
今から登録する人は、英語の電子資料をマイナンバー付きで提出したり、アプリ登録料で1万円かかったりするのでご注意ください。
では、さっそく見ていきましょう。
Steam アカウントで PlayFab にログインする
リアルマネーでアイテムを購入する前に、PlayFab と Steam を紐付けして上げる必要があります。
まずは、ログインが正常にできるところまでやっていきましょう。
Steam のインストール
まずは Steam がないと何も始まらないので、インストールをしましょう。
アカウントがない人は、同時に登録も必要です。
Steam アドオンの導入
PlayFab 管理画面左のアドオンより、Steam を選択して Steam を有効にします。
アプリケーション ID は7桁の数値、Web API キーは Guid となっていて、これらは Steamworks で確認できます。
そもそもこのページにたどり着けない人は、Web API キーを使用した認証を参照してください。
PlayFab 管理画面で入力が終わったら、「Steam をインストール」を押して完了です。
Steam アカウントで Unity にログインする
アドオンを使う上で Steam アカウントの紐付けが必要なので、Steam アカウントで PlayFab にログインします。
まずは、Steam SDK の unitypackage をダウンロードしましょう。
これを Unity プロジェクトにインポートします。
インポートできたら、いったん Unity を閉じて、Unity プロジェクトのルートにある「steam_appid.txt」を開きます。
ID を自分のアプリケーション ID に書き換えた後、再度 Unity プロジェクトを開きましょう。
次はログインの処理を書いていきます。
名前は何でもいいですが、SteamScript というクラスを作成しました。
using System;
using System.Collections.Generic;
using System.Text;
using PlayFab;
using PlayFab.ClientModels;
using Steamworks;
using UnityEngine;
using UnityEngine.UI;
public class SteamScript : MonoBehaviour
{
private void Start()
{
if (SteamManager.Initialized)
{
PlayFabClientAPI.LoginWithSteam(new LoginWithSteamRequest
{
CreateAccount = true,
SteamTicket = GetSteamAuthTicket()
}, result =>
{
Debug.Log("Success!");
}
, error => { Debug.Log("Failed: " + error.GenerateErrorReport()); });
}
}
public string GetSteamAuthTicket()
{
byte[] ticketBlob = new byte[1024];
// Retrieve ticket; hTicket should be a field in the class so you can use it to cancel the ticket later
// When you pass an object, the object can be modified by the callee. This function modifies the byte array you've passed to it.
HAuthTicket hTicket = SteamUser.GetAuthSessionTicket(ticketBlob, ticketBlob.Length, out uint ticketSize);
// Resize the buffer to actual length
Array.Resize(ref ticketBlob, (int)ticketSize);
// Convert bytes to string
StringBuilder sb = new StringBuilder();
foreach (byte b in ticketBlob)
{
sb.AppendFormat("{0:x2}", b);
}
return sb.ToString();
}
}
Login With Steam を使うことで、PlayFab のアカウントを作成すると同時に、Steam のアカウントを紐付けることができます。
このスクリプトと、SteamManager をアタッチすればログインの準備は完了です。
ログインの動作確認
Unity エディタ上で実行しただけでは、正常に動作しません。
まず最初に、インストールした Steam を起動してログインする必要があります。
Steam のアプリ上でログインが完了したら、Unity エディター上で実行をしましょう。
ログに「Success!!」が表示され、PlayFab のアカウントが作成されれば成功です。
リアルマネーでアイテムを購入する
ログインができたので、ここからはリアルマネーでアイテムを購入する手順について解説します。
全体の流れが少し難しいので、図で整理してみました。
リストにするとこんな感じ。
- Start Purchase を実行
- Pay For Purchase を実行
- Steam Overlay が自動で表示
- 購入されたら Confirm Purchase を実行
- アイテムがプレイヤーに反映
少し長いですが、やることは難しくないので、まずは全体のプログラムを見てみましょう。
using System;
using System.Collections.Generic;
using System.Text;
using PlayFab;
using PlayFab.ClientModels;
using Steamworks;
using UnityEngine;
public class SteamScript : MonoBehaviour
{
private string orderId;
// Steam のオーバーレイでアイテムを購入した場合のコールバック
protected Callback<MicroTxnAuthorizationResponse_t> m_MicroTxnAuthorizationResponse;
private void OnMicroTxnAuthorizationResponse(MicroTxnAuthorizationResponse_t callBack)
{
PlayFabClientAPI.ConfirmPurchase(new ConfirmPurchaseRequest()
{
OrderId = orderId,
}, result =>
{
Debug.Log("ConfirmPurchase Success!!");
}, error =>
{
Debug.Log("ConfirmPurchase Failed..." + error.GenerateErrorReport());
});
}
private void Start()
{
if (SteamManager.Initialized)
{
m_MicroTxnAuthorizationResponse = Callback<MicroTxnAuthorizationResponse_t>.Create(OnMicroTxnAuthorizationResponse);
PlayFabClientAPI.LoginWithSteam(new LoginWithSteamRequest
{
CreateAccount = true,
SteamTicket = GetSteamAuthTicket()
}, result =>
{
Debug.Log("Success!");
}
, error => { Debug.Log("Failed: " + error.GenerateErrorReport()); });
}
}
public void PurchaseGem()
{
Debug.Log("StartPurchase!!");
PlayFabClientAPI.StartPurchase(new StartPurchaseRequest
{
CatalogVersion = "Main",
Items = new List<ItemPurchaseRequest>
{
new ItemPurchaseRequest()
{
ItemId = "gem_10_bundle",
Quantity = 1,
Annotation = "Purchased via in-game store"
}
},
}, startPurchaseResult =>
{
Debug.Log("StartPurchase Success!!");
PlayFabClientAPI.PayForPurchase(new PayForPurchaseRequest
{
OrderId = startPurchaseResult.OrderId,
ProviderName = "Steam",
Currency = "RM"
}, payForPurchaseResult =>
{
orderId = payForPurchaseResult.OrderId;
Debug.Log("Status: " + payForPurchaseResult.Status + ", Currency: " + payForPurchaseResult.PurchaseCurrency +
", Price: " + payForPurchaseResult.PurchasePrice + ", ProviderData: " + payForPurchaseResult.ProviderData);
}, error =>
{
Debug.Log("PayForPurchase Failed..." + error.GenerateErrorReport());
});
}, error =>
{
Debug.Log("StartPurchase Failed..." + error.GenerateErrorReport());
});
}
public string GetSteamAuthTicket()
{
byte[] ticketBlob = new byte[1024];
// Retrieve ticket; hTicket should be a field in the class so you can use it to cancel the ticket later
// When you pass an object, the object can be modified by the callee. This function modifies the byte array you've passed to it.
HAuthTicket hTicket = SteamUser.GetAuthSessionTicket(ticketBlob, ticketBlob.Length, out uint ticketSize);
// Resize the buffer to actual length
Array.Resize(ref ticketBlob, (int)ticketSize);
// Convert bytes to string
StringBuilder sb = new StringBuilder();
foreach (byte b in ticketBlob)
{
sb.AppendFormat("{0:x2}", b);
}
return sb.ToString();
}
}
細かく見ていきます。
StartPurchase を実行
PlayFabClientAPI.StartPurchase(new StartPurchaseRequest
{
CatalogVersion = "Main",
Items = new List<ItemPurchaseRequest>
{
new ItemPurchaseRequest()
{
ItemId = "gem_10_bundle",
Quantity = 1,
Annotation = "Purchased via in-game store"
}
},
}, startPurchaseResult =>
日本語でいうと、「Main カタログで登録されている gem_10_bundle というアイテムを、これから1つ買うぞ!」という処理です。
今回は、「10ジェムが入ったバンドルアイテム」を100円で登録してみました。
RM という通貨はリアルマネー(Real Money)のことで、PlayFab で最初から定義されています。
PayForPurchase を実行
PlayFabClientAPI.PayForPurchase(new PayForPurchaseRequest
{
OrderId = startPurchaseResult.OrderId,
ProviderName = "Steam",
Currency = "RM"
}, payForPurchaseResult =>
{
orderId = payForPurchaseResult.OrderId;
支払先は Steam、通貨はリアルマネーなので RM とします。
StartPurchase で実行したときに取得した OrderId は最後まで使うので、クラス変数として取っておきましょう。
Steam Overlay が自動で表示
PayForPurchase が正常に終了したタイミングで、Steam の購入確認がオーバーレイ表示されます。
少し小さいので拡大します。
先ほど指定した数量とアイテムの名前、金額が表示されているのがわかります。
PlayFab コミュニティの記事によると、将来的にはできるようになる予定ですが、具体的な日程は未定とのことです。
2年半前くらいの投稿なので、対応は年単位で先のような気がします。
購入されたら ConfirmPurchase を実行
// Steam のオーバーレイでアイテムを購入した場合のコールバック
protected Callback<MicroTxnAuthorizationResponse_t> m_MicroTxnAuthorizationResponse;
private void OnMicroTxnAuthorizationResponse(MicroTxnAuthorizationResponse_t callBack)
{
PlayFabClientAPI.ConfirmPurchase(new ConfirmPurchaseRequest()
{
OrderId = orderId,
}, result =>
{
Debug.Log("ConfirmPurchase Success!!");
}, error =>
{
Debug.Log("ConfirmPurchase Failed..." + error.GenerateErrorReport());
});
}
「購入されたら」というを判断するのに、コールバック関数を登録しておく必要があります。
上記のコールバック関数を、Start メソッドで紐付けをしています。
m_MicroTxnAuthorizationResponse = Callback<MicroTxnAuthorizationResponse_t>.Create(OnMicroTxnAuthorizationResponse);
これで、実際に購入された場合にだけ ComfirmPurchase を実行することができます。
取っておいた OrderId をキーに処理を呼び出してあげれば、アイテムの購入が完了です。
アイテムがプレイヤーに反映
以下は PlayStream のログです。
こんな感じで、購入したバンドルが展開され、1ドルと引き換えに10ジェムが付与されていることがわかります。
また、「プレイヤー > 購入」と進んでいくと、購入履歴の確認も可能です。
ここまでで、ひと通りの流れを確認しました。
通しで動作確認をする
ログインの確認だけであれば、Steam にログインした上で Unity エディタ上でデバッグ実行をすれば OK でした。
しかし、Steam のオーバーレイ表示をするとなると、ビルドしたものを Steam にアップロードする必要があります。
ビルド方法については、公式のSteam へのアップロードを参照してください。
ビルドの難易度が高いので、容量が 1024 MB 以下の人は、HTTP で直接アップロードできるので、その方法を強くおすすめします。
無事にビルドして公開ができたら、Steam のアプリを起動すると、ライブラリに自分のゲームが追加されています。
ここからインストールしましょう。
インストールができたら「プレイ」のボタンに変わるので、プレイしましょう。
ここから起動すると、PlayFab と Steam が裏で正しく連携されて、オーバーレイ表示も出るようになります。
これですべての流れを確認しました。
お疲れさまでした!
最後に
PlayFab と Steam を連携する方法について解説してきました。
Steam SDK の使い方や、ビルドしてアップロードするところが少し難しいですが、一度やってしまえば大丈夫です。
Steam でアイテムを販売して PlayFab に連携したいときは、ぜひこの記事を参考に試してみてください。
PlayFab のことをもっと皆さんに知ってもらいたくて、合計500ページ以上にもなる書籍を5冊に分けて執筆しました。
私の知識をすべて詰め込んでいるので、ゲーム開発をさらに加速させたい方はぜひご覧ください。
最初のSteamScriptのコードだと下記エラーが出てしまいました。
Assets/Scripts/SteamScript.cs(34,97): error CS1644: Feature `out variable declaration’ cannot be used because it is not part of the C# 4.0 language specification
以下のあたりをチェックしてみてください。
Unityのバージョンを上げた時に「Feature out variable declaration cannot be used…」というエラー
https://unity-yuji.xyz/feature-out-variable-declaration-cannot-be-used-textmeshpro-package-cache/
Unity Error: Feature ‘out variable declaration’
https://stackoverflow.com/questions/56068615/unity-error-feature-out-variable-declaration
.NET 4.0に変更すると、AstarPathfindingProjectで設定したモンスターが動かなくなるので、変更を躊躇してました(-_-;)
あと、
$”result.OrderId = {r.OrderId}”
.NET 3.5だと、こういうのもエラーが出るっぽいです(・_・;)