PC ゲームといえば、Steam というサービスが世界で大人気ですよね。
規模としては、数百万人もの人が同時に接続しているほどです。
Unity を使えば、Steam にも自分で作ったゲームを出すことができます。
実は PlayFab では、Steam のゲーム内アイテムをリアルマネーで購入させたい、という場合にも対応しているんです。
しかし、手順が少し難しいため、この記事でわかりやすくまとめました。
この記事を読むことで、PlayFab と Steam をすぐに連携できるはずです。
Steamworks でリリースできるアプリがないと、この先の作業ができません。
今から登録する人は、英語の電子資料をマイナンバー付きで提出したり、アプリ登録料で1万円かかったりするのでご注意ください。
では、さっそく見ていきましょう。
Steam アカウントで PlayFab にログインする
リアルマネーでアイテムを購入する前に、PlayFab と Steam を紐付けして上げる必要があります。
まずは、ログインが正常にできるところまでやっていきましょう。
Steam のインストール
まずは Steam がないと何も始まらないので、インストールをしましょう。
アカウントがない人は、同時に登録も必要です。
Steam アドオンの導入
PlayFab 管理画面左のアドオンより、Steam を選択して Steam を有効にします。
![playfab-payment-steam](https://playfab-master.com/wp-content/uploads/2020/05/7b4042c08f72882acd01f38ff3e5f69f.png)
アプリケーション ID は7桁の数値、Web API キーは Guid となっていて、これらは Steamworks で確認できます。
![playfab-payment-steam](https://playfab-master.com/wp-content/uploads/2020/05/53ca952ee26cc13d53d859352a406231.png)
そもそもこのページにたどり着けない人は、Web API キーを使用した認証を参照してください。
PlayFab 管理画面で入力が終わったら、「Steam をインストール」を押して完了です。
Steam アカウントで Unity にログインする
アドオンを使う上で Steam アカウントの紐付けが必要なので、Steam アカウントで PlayFab にログインします。
まずは、Steam SDK の unitypackage をダウンロードしましょう。
これを Unity プロジェクトにインポートします。
![playfab-payment-steam](https://playfab-master.com/wp-content/uploads/2020/05/a9bb095f811386f3e2bb1a1b5af4918f.png)
インポートできたら、いったん Unity を閉じて、Unity プロジェクトのルートにある「steam_appid.txt」を開きます。
![playfab-payment-steam](https://playfab-master.com/wp-content/uploads/2020/05/f5087c7b7a76506ecf82f2fd4ec019be.png)
ID を自分のアプリケーション ID に書き換えた後、再度 Unity プロジェクトを開きましょう。
![playfab-payment-steam](https://playfab-master.com/wp-content/uploads/2020/05/a70478facb406f9ad789b6797bb16233.png)
次はログインの処理を書いていきます。
名前は何でもいいですが、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 をアタッチすればログインの準備は完了です。
![playfab-payment-steam](https://playfab-master.com/wp-content/uploads/2020/05/e081fb64c11e12366854500fa09c67c6.png)
ログインの動作確認
Unity エディタ上で実行しただけでは、正常に動作しません。
まず最初に、インストールした Steam を起動してログインする必要があります。
Steam のアプリ上でログインが完了したら、Unity エディター上で実行をしましょう。
ログに「Success!!」が表示され、PlayFab のアカウントが作成されれば成功です。
![playfab-payment-steam](https://playfab-master.com/wp-content/uploads/2020/05/3a58232cd994eb45cd0a331e1578e689.png)
リアルマネーでアイテムを購入する
ログインができたので、ここからはリアルマネーでアイテムを購入する手順について解説します。
全体の流れが少し難しいので、図で整理してみました。
![playfab-payment-steam](https://playfab-master.com/wp-content/uploads/2020/05/bc2f2e13dabf2f96144cfab196d68fab-1.png)
リストにするとこんな感じ。
- 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円で登録してみました。
![playfab-payment-steam](https://playfab-master.com/wp-content/uploads/2020/05/7cd11ee52362aedce6b3d85fc05fa919.png)
![playfab-payment-steam](https://playfab-master.com/wp-content/uploads/2020/05/fc13f104438e9a948a0160e44a9dd478.png)
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-payment-steam](https://playfab-master.com/wp-content/uploads/2020/05/bc6c99f23e302be82729af135b01fc54.png)
少し小さいので拡大します。
![playfab-payment-steam](https://playfab-master.com/wp-content/uploads/2020/05/steam-confirm-dialog-min.png)
先ほど指定した数量とアイテムの名前、金額が表示されているのがわかります。
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 のログです。
![playfab-payment-steam](https://playfab-master.com/wp-content/uploads/2020/05/df02778a7ab046b86aaac969d9039138.png)
こんな感じで、購入したバンドルが展開され、1ドルと引き換えに10ジェムが付与されていることがわかります。
また、「プレイヤー > 購入」と進んでいくと、購入履歴の確認も可能です。
![playfab-payment-steam](https://playfab-master.com/wp-content/uploads/2020/05/cccc721cfd1d1a4f18fee36ab8f2366a.png)
ここまでで、ひと通りの流れを確認しました。
通しで動作確認をする
ログインの確認だけであれば、Steam にログインした上で Unity エディタ上でデバッグ実行をすれば OK でした。
しかし、Steam のオーバーレイ表示をするとなると、ビルドしたものを Steam にアップロードする必要があります。
ビルド方法については、公式のSteam へのアップロードを参照してください。
ビルドの難易度が高いので、容量が 1024 MB 以下の人は、HTTP で直接アップロードできるので、その方法を強くおすすめします。
![playfab-payment-steam](https://playfab-master.com/wp-content/uploads/2020/05/f05b4e09a6a9e1a38bb56abc9bf6972c.png)
無事にビルドして公開ができたら、Steam のアプリを起動すると、ライブラリに自分のゲームが追加されています。
ここからインストールしましょう。
![playfab-payment-steam](https://playfab-master.com/wp-content/uploads/2020/05/85c7860934de6f80612578765435f8f7.png)
インストールができたら「プレイ」のボタンに変わるので、プレイしましょう。
![playfab-payment-steam](https://playfab-master.com/wp-content/uploads/2020/05/73558b7c11a1f68836de975e40414ed7.png)
ここから起動すると、PlayFab と Steam が裏で正しく連携されて、オーバーレイ表示も出るようになります。
これですべての流れを確認しました。
お疲れさまでした!
最後に
PlayFab と Steam を連携する方法について解説してきました。
Steam SDK の使い方や、ビルドしてアップロードするところが少し難しいですが、一度やってしまえば大丈夫です。
Steam でアイテムを販売して PlayFab に連携したいときは、ぜひこの記事を参考に試してみてください。
![playfab-book](https://playfab-master.com/wp-content/uploads/2020/08/bcc891b63849bb6819125040123a3817.jpg)
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だと、こういうのもエラーが出るっぽいです(・_・;)