カスタム CloudScript の記述
CloudScript は、PlayFab の最も汎用的の高い機能の 1 つです。 これにより、クライアント コードは実装可能なあらゆるカスタムのサーバー側の機能を実行するようにリクエストできます。また、実質的にあらゆるものに使用できます。 CloudScript は、クライアントまたはサーバー コードからの明示的な実行要求に加えて、PlayStream イベントに応答して (ルールを作成することによって)、またはスケジュールされたタスクの一部として実行できます。
注意
Azure 関数を使った CloudScript では、サポートされる言語が増え、デバッグ ワークフローが改善され、CloudScript が向上します。
このチュートリアルでは、CloudScript コードについて説明します。 CloudScript ファイルをタイトルにアップロードする方法については、「CloudScript クイックスタート」を参照してください。
注意
このチュートリアルでは Unity コード サンプルを実演しますが、CloudScript はすべての SDK で同様に機能します。
このチュートリアルの前提条件
-
PlayFab Unity SDK で設定した Unity 環境
- タイトル ID は
PlayFabSharedSettings
オブジェクトに設定されています。 - プロジェクトが正常にユーザーをログインできること。
- タイトル ID は
概要: helloWorld
helloWorld
の例は、ゲーム マネージャーで変更を加えていない完全に新しいタイトルに対して機能します。 新しいタイトルの 既定の CloudScript ファイルには、helloWorld
というハンドラーが含まれています。 このハンドラーはいくつかの基本的な機能、入力パラメーター、ログ記録、currentPlayerId、返却パラメータを使用します。
以下のサンプルは、既定の helloWorld
関数コード (コメントを除く) を示しています。
// CloudScript (JavaScript)
handlers.helloWorld = function (args, context) {
var message = "Hello " + currentPlayerId + "!";
log.info(message);
var inputValue = null;
if (args && args.hasOwnProperty("inputValue"))
inputValue = args.inputValue;
log.debug("helloWorld:", { input: inputValue });
return { messageValue: message };
}
コードを分解する
ハンドラー オブジェクトは、PlayFab CloudScript 環境で事前に定義されています。 このオブジェクトにいずれかの CloudScript 機能を追加する必要があります。
helloWorld
は、ハンドラー オブジェクトで定義されているため、タイトルおよび SDK で使用できる関数です。args
は、呼び出し元から取得される任意のオブジェクトです。 これは JSON から解析され、あらゆる形式のあらゆるデータを含めることができます。
次のセクションの FunctionParameter を参照してください。
Warning
このオブジェクトは、ゼロ トラストで扱う必要があります。 ハッキングされたクライアントまたは悪意のあるユーザーは、あらゆる情報をあらゆる形式でここに提供できます。
Context
は高度なパラメーターです。 この例では、null です。 このパラメーターはサーバーによって制御され、安全です。currentPlayerId
はグローバルな変数で、この呼び出しをリクエストするプレイヤーの PlayFabId に設定されます。 このパラメーターはサーバーによって制御され、安全です。 注: ExecuteEntityCloudScript API を使用する場合、このパラメーターは、エンティティがそのエンティティ チェーンに MasterPlayerID を持っていない限り、NULL になります。log.info
:log
はグローバル オブジェクトです。 主に、CloudScript のデバッグに使用されます。log
オブジェクトは、info
、debug
、error
のメソッドを公開します。 詳細については、このチュートリアルの後半で説明します。return
: 返却するあらゆるオブジェクトは JSON としてシリアル化され、呼び出し元に返されます。 JSON のシリアル化されたオブジェクトと任意のデータを返すことができます。
Warning
CloudScript が機密データをクライアントに返した場合は、自身の責任です。 通常のゲーム プレイでユーザーに公開しない場合でも、ハッキングされたクライアントや悪意のあるユーザーは返されたデータを調べることができます。
Unity ゲーム クライアントから CloudScript 機能を実行する
クライアント内から CloudScript 機能を呼び出すことは簡単です。 まず ExecuteCloudScriptRequest
を作成し、ActionId
プロパティを実行する CloudScript 機能の名前に設定する必要があります (今回は helloWorld
)。次に、API によってオブジェクトを PlayFab に送信します。
注意
ハンドラーの JavaScript オブジェクトにアタッチされた CloudScript メソッドのみを呼び出すことができます。
CloudScript メソッドを実行するには、クライアントで以下のコード行が必要です。
// Build the request object and access the API
private static void StartCloudHelloWorld()
{
PlayFabClientAPI.ExecuteCloudScript(new ExecuteCloudScriptRequest()
{
FunctionName = "helloWorld", // Arbitrary function name (must exist in your uploaded cloud.js file)
FunctionParameter = new { inputValue = "YOUR NAME" }, // The parameter provided to your function
GeneratePlayStreamEvent = true, // Optional - Shows this event in PlayStream
}, OnCloudHelloWorld, OnErrorShared);
}
// OnCloudHelloWorld defined in the next code block
コードを分解する
ExecuteCloudScriptRequestは、PlayFabClientAPI.ExecuteCloudScript に対するすべての呼び出しのリクエスト タイプです。
ExecuteCloudScriptRequest.FunctionName
は、文字列です。 値は、CloudScript で定義されている関数の名前と一致する必要があります。 今回はhelloWorld
です。ExecuteCloudScriptRequest.FunctionParameter
は任意のオブジェクトとすることができ、JSON にシリアル化できます。 これは、helloWorld
関数の最初の args パラメーターになります (前のセクションの args を参照してください)。ExecuteCloudScriptRequest.GeneratePlayStreamEvent
はオプションです。 True の場合イベントは PlayStream に投稿され、ゲーム マネージャーで表示するか、他の PlayStream トリガーに使用できます。
言語に応じて、ExecuteCloudScript
行の最後の部分には、PlayFab CloudScript サーバーに要求を行い、言語に固有の Result と Error のハンドリング部分も含まれます。
たとえば、Unity、JavaScript、AS3 では、Error と Result のハンドリングはコールバック機能を使用して提供されます。
エラー処理方法の例を次に示します。
private static void OnCloudHelloWorld(ExecuteCloudScriptResult result) {
// CloudScript returns arbitrary results, so you have to evaluate them one step and one parameter at a time
Debug.Log(JsonWrapper.SerializeObject(result.FunctionResult));
JsonObject jsonResult = (JsonObject)result.FunctionResult;
object messageValue;
jsonResult.TryGetValue("messageValue", out messageValue); // note how "messageValue" directly corresponds to the JSON values set in CloudScript
Debug.Log((string)messageValue);
}
private static void OnErrorShared(PlayFabError error)
{
Debug.Log(error.GenerateErrorReport());
}
中級の概要: グローバルおよび高度な引数
CloudScript は、V8 でコンパイルされ、PlayFab のサーバーにホストされる一連の JavaScript 関数です。 PlayFab API リファレンス ドキュメント にリストされるあらゆるサーバー API と、ロガー、CloudScript リクエストを実行しているプレイヤーの PlayFab ID、リクエストに含まれるあらゆる情報に、プリセット オブジェクトの形式でアクセスできます。
CloudScript 機能自体は、グローバル ハンドラー オブジェクトのプロパティです。 以下の表は、これらの事前定義された変数の完全な一覧を示しています。
名前 | 使用 |
---|---|
サーバー |
PlayFab API リファレンス ドキュメント にリストされるすべてのサーバー側 API にアクセスできます。 これらは、(同時に) 以下のように呼ばれます。var result = server.AuthenticateUserTicket(request); |
http | 同期 HTTP 要求を実行し、以下のようになります: http.request(url, method, content, contentType, headers, logRequestAndResponse) 。
headers オブジェクトには、さまざまなヘッダーに対応するプロパティとその値が含まれます。
logRequestAndResponse は、タイトルが応答の一部としてリクエストのエラーをログ記録するべきかどうかを決定するブール値です。 |
log | ログ ステートメントを作成し、応答に追加します。 ログには、log.info() 、log.debug() 、log.error() の 3 つのレベルがあります。 3 つすべてのレベルがメッセージ文字列と、ログに含める追加データを含むオプションのオブジェクトを取得します。 たとえば、log.info('hello!', { time: new Date() }); のように指定します。 |
currentPlayerId | CloudScript 呼び出しをトリガーしたプレイヤーの PlayFab ID です。 |
handler | タイトルのすべての CloudScript 機能を含むグローバル オブジェクトです。 関数はこのオブジェクトを使用して追加するか呼び出すことができます。 たとえば、handlers.pop = function() {}; 、handlers.pop(); などがあります。 |
script |
Revision と titleId を含むグローバル オブジェクトです。
Revision は、現在実行している CloudScript のリビジョン番号を表し、titleId は、現在のタイトルの ID を表します。 |
さらに、すべてのハンドラー関数は 2 つのパラメーターを渡されます。以下に詳細を記載します。
名前 | 使用 |
---|---|
args | ハンドラー関数に渡される最初のパラメーターです。
ExecuteCloudscript リクエストの FunctionParameter フィールドのオブジェクトの表現です。 |
context | ハンドラー関数に渡される 2 つ目のパラメーターです。 アクションをトリガーした イベントからのデータ (context.playStreamEvent) と関連するプレイヤーのプロファイル データ を含む、PlayStream イベント アクションからトリガーされたリクエストに関する追加情報です。 (context.playerProfile) |
CloudScript 機能は ExecuteCloudScript
API を通じて、または事前設定された PlayStream イベントアクションによって呼び出すことができます。
ExecuteCloudScript
への応答に関する完全な詳細については、ExecuteCloudScriptResult を参照してください。
中級: FunctionParameter と args
前のセクションではrequest.FunctionParameter
に入力する方法と、args
パラメーターでその情報を表示する方法について説明しました。
CloudScript クイック スタートでは、新しい CloudScript をアップロードする方法を実演しています。
両方を合わせて、クライアントからの引数を CloudScript に渡す方法の別の例を提供します。 前の例の CloudScript コードとクライアント コードを以下のように変更します。
handlers.helloWorld = function (args) {
// ALWAYS validate args parameter passed in from clients (Better than we do here)
var message = "Hello " + args.name + "!"; // Utilize the name parameter sent from client
log.info(message);
return { messageValue: message };
}
// Build the request object and access the API
private static void StartCloudHelloWorld()
{
PlayFabClientAPI.ExecuteCloudScript(new ExecuteCloudScriptRequest()
{
FunctionName = "helloWorld", // Arbitrary function name (must exist in your uploaded cloud.js file)
FunctionParameter = new { name = "YOUR NAME" }, // The parameter provided to your function
GeneratePlayStreamEvent = true, // Optional - Shows this event in PlayStream
}, OnCloudHelloWorld, OnErrorShared);
}
private static void OnCloudHelloWorld(ExecuteCloudScriptResult result) {
// CloudScript returns arbitrary results, so you have to evaluate them one step and one parameter at a time
Debug.Log(JsonWrapper.SerializeObject(result.FunctionResult));
JsonObject jsonResult = (JsonObject)result.FunctionResult;
object messageValue;
jsonResult.TryGetValue("messageValue", out messageValue); // note how "messageValue" directly corresponds to the JSON values set in CloudScript
Debug.Log((string)messageValue);
}
private static void OnErrorShared(PlayFabError error)
{
Debug.Log(error.GenerateErrorReport());
}
これらの変更を行うと、CloudScript とクライアントの間で簡単にデータを送受信できるようになります。
注意
クライアントから送られるデータは、すべてハッキングと悪用の対象になりやすいことに注意することが重要です。
バックエンドを更新する前に、常に入力パラメータを検証してください。 入力パラメーターを検証するプロセスはタイトルに応じて異なりますが、最も基本的な検証は、入力が許容される範囲と期間内にあることを確認することです。
中級: サーバー API の呼び出し
前述のように、CloudScript メソッド内で、完全なサーバー API 呼び出しのセットにアクセスできます。 これにより、クラウド コードは専用サーバーとして機能できます。
一般的なサーバー タスク
- プレイヤー統計とデータを更新する。
- アイテムと仮想通貨を付与する。
- ゲーム データをランダムに生成する。
- バトルの結果を安全に計算する、など。
必要なパラメータとオブジェクト構造については、PlayFab API のリファレンス ドキュメント にリストされるサーバー API をご覧ください。
以下の例は、潜在的な CloudScript ハンドラー内からのものです。
// CloudScript (JavaScript)
//See: JSON.parse, JSON.stringify, parseInt and other built-in javascript helper functions for manipulating data
var currentState; // here we are calculating the current player's game state
// here we are fetching the "SaveState" key from PlayFab,
var playerData = server.GetUserReadOnlyData({"PlayFabId" : currentPlayerId, "Keys" : ["SaveState"]});
var previousState = {}; //if we return a matching key-value pair, then we can proceed otherwise we will need to create a new record.
if(playerData.Data.hasOwnProperty("SaveState"))
{
previousState = playerData.Data["SaveState"];
}
var writeToServer = {};
writeToServer["SaveState"] = previousState + currentState; // pseudo Code showing that the previous state is updated to the current state
var result = server.UpdateUserReadOnlyData({"PlayFabId" : currentPlayerId, "Data" : writeToServer, "Permission":"Public" });
if(result)
{
log.info(result);
}
else
{
log.error(result);
}
上級: PlayStream イベント アクション
CloudScript 関数は、PlayStream イベントに応答して実行するように構成できます。
- 任意のブラウザーで以下を実行します。
- PlayFab ゲーム マネージャー を開きます。
- 自分のタイトル を見つけます。
- サイド バーの [ビルド] の [オートメーション] タブに移動します。
- [ルール] タブに移動します。
ページは以下の例のようになります。
[新しいルール] ボタンを使用して、新しいルールを作成します。
- 新しいルールに名前を付けます。
- 条件またはアクションのトリガーとして使用される [イベントの種類] を選択します。
- ルールが CloudScript 関数をトリガーするようにするには、そのセクションのボタンでアクションを追加します。
- 次に、[Type (タイプ)] ドロップダウン メニューでオプションを選択します。
- [Cloud Script Function] ドロップダウン メニューで、[helloWorld] 関数を選択します。
- [アクションの保存] ボタンを選択します。
このルールは、選択した種類のイベントに対してトリガーするように設定されました。 テストするには以下を実行します。
- [Publish results as PlayStream Event (PlayStream イベントとして結果を公開)] ボックスを確認します。
- アクションを保存します。
- 次に、イベントをトリガーします。
- [PlayStream モニター] で、CloudScript の実行に対応する新しいイベントが存在し、適切な情報が含まれている必要があります。
- デバッガーで PlayStream イベントを確認する方法の詳細は、次の 上級: CloudScript のデバッグセクションを参照してください。
注意
CloudScript 機能を呼び出す際、イベント アクションはライブ リビジョンのみを使用できます。 ドロップダウンで helloWorld 関数が見つからない場合、これが最も一般的な原因です。
上級: CloudScript のデバッグ
注意
Azure 関数を使用した CloudScript を使用すると、デバッグがはるかに簡単になります。 Azure 関数を使用して CloudScript のローカル デバッグを使用する方法について説明します。
ログ記録
コードをデバッグするための最も重要なツールの 1 つはログ記録です。 CloudScript は、関数を実行するためのユーティリティを提供します。
これは、log
オブジェクトの形式を取ります。Info
、Debug
、Error
メソッドを使用して、必要なあらゆるメッセージをログ記録できます。
また、HTTP オブジェクトは logRequestAndResponse
パラメーターを設定することで、リクエストの実行中に発生したすべてのエラーをログ記録します。 これらのログの設定は簡単ですが、それらのアクセスするには少し手間がかかります。
これは、4 つすべてのタイプのログを使用する CloudScript 機能の例です。
handlers.logTest = function(args, context) {
log.info("This is a log statement!");
log.debug("This is a debug statement.");
log.error("This is... an error statement?");
// the last parameter indicates we want logging on errors
http.request('https://httpbin.org/status/404', 'post', '', 'text/plain', null, true);
};
この例を実行するには、続行する前に、この関数をライブ リビジョンに追加します。
以下に示すように、logTest
関数は ExecuteCloudScript
を使用して呼び出されます。
// Invoke this on start of your application
void Login() {
PlayFabClientAPI.LoginWithCustomID(new LoginWithCustomIDRequest {
CreateAccount = true,
CustomId = "Starter"
}, result => RunLogTest(), null);
}
void RunLogTest() {
PlayFabClientAPI.ExecuteCloudScript(new ExecuteCloudScriptRequest {
FunctionName = "logTest",
// duplicates the response of the request to PlayStream
GeneratePlayStreamEvent = true
}, null, null);
}
// Logs evaluated in next code block
GeneratePlayStreamEvent
を設定すると、CloudScript 機能の呼び出しによって、応答の内容が含まれる PlayStream イベントが生成されます。 PlayStream イベントの内容を見つけるには以下を実行します。
タイトルのゲーム マネージャーのホーム ページまたは [PlayStream] タブに移動します。
[PlayStream Debugger (PlayStream デバッガー)]に、発生したイベントが表示されます。
イベントが発生したら、以下に示すように、イベントの右上で小さい青色の [Info] アイコンを選択します。
これを選択すると、各イベントに対して詳細化された、イベントの未加工の JSON がここに表示されます。 この JSON の例は、以下の例で確認できます。
シーンに
LogScript
MonoBehavior を追加する場合、ゲームの実行によって PlayStream でこれが発生します。
ExecuteCloudScript
呼び出しの結果には、Logs
と呼ばれるフィールドが含まれています。これは、CloudScript 機能によって生成されたログ オブジェクトのリストです。
3 つのログ呼び出しと、無効な HTTP リクエストによるログを確認できます。 また、HTTP リクエスト ログは、ログ呼び出しと違って Data
フィールドを使用しています。
このフィールドは、ログ ステートメントに関連する情報が入力される JavaScript オブジェクトです。 以下に示すように、ログへの呼び出しも、2 番目のパラメーターを使ってこのフィールドを使用できます。
handlers.logTest = function(args, context) {
log.info("This is a log statement!", { what: "Here on business." });
log.debug("This is a debug statement.", { who: "I am a doctor, sir" });
log.error("This is... an error statement?", { why: "I'm here to fix the plumbing. Probably.", errCode: 123 });
};
これらの呼び出しはすべて、結果で Data
フィールドに 2 番目のパラメーターを入力します。
結果にはログが含まれるため、クライアント側のコードはログ ステートメントに応答できます。
logTest
関数でのエラーが強制されますが、クライアント コードはそれに応答するように適合されます。
void RunLogTest()
{
PlayFabClientAPI.ExecuteCloudScript(
new ExecuteCloudScriptRequest
{
FunctionName = "logTest",
// handy for logs because the response will be duplicated on PlayStream
GeneratePlayStreamEvent = true
},
result =>
{
var error123Present = false;
foreach (var log in result.Logs)
{
if (log.Level != "Error") continue;
var errData = (JsonObject) log.Data;
object errCode;
var errCodePresent = errData.TryGetValue("errCode", out errCode);
if (errCodePresent && (ulong) errCode == 123) error123Present = true;
}
if (error123Present)
Debug.Log("There was a bad, bad error!");
else
Debug.Log("Nice weather we're having.");
}, null);
}
このコードが実行されると、出力でエラーの存在が示されます。 現実的なエラーの対応は、UI でエラーを表示するか、ログ ファイルに値を保存することです。
上級: エラー
開発中、CloudScript のエラーは log.error
の場合のように、通常は手動でトリガーされません。
幸い、ExecuteCloudScript への応答には ExecuteCloudScriptResultが含まれる、ScriptExecutionError フィールドが含まれています。 ログ記録セクションの最後の例を使い、以下のように使用します。
void RunLogTest() {
PlayFabClientAPI.ExecuteCloudScript(new ExecuteCloudScriptRequest {
FunctionName = "logTest",
// handy for logs because the response will be duplicated on PlayStream
GeneratePlayStreamEvent = true
}, result => {
if(result.Error != null) {
Debug.Log(string.Format("There was error in the CloudScript function {0}:\n Error Code: {1}\n Message: {2}"
, result.FunctionName, result.Error.Error, result.Error.Message));
}
},
null);
}
エラーが発生した場合、このコードによってログに表示されます。