カスタム CloudScript の記述

CloudScript は、PlayFab の最も汎用的の高い機能の 1 つです。 これにより、クライアント コードは実装可能なあらゆるカスタムのサーバー側の機能を実行するようにリクエストできます。また、実質的にあらゆるものに使用できます。 CloudScript は、クライアントまたはサーバー コードからの明示的な実行要求に加えて、PlayStream イベントに応答して (ルールを作成することによって)、またはスケジュールされたタスクの一部として実行できます。

注意

Azure 関数を使った CloudScript では、サポートされる言語が増え、デバッグ ワークフローが改善され、CloudScript が向上します。

このチュートリアルでは、CloudScript コードについて説明します。 CloudScript ファイルをタイトルにアップロードする方法については、「CloudScript クイックスタート」を参照してください。

注意

このチュートリアルでは Unity コード サンプルを実演しますが、CloudScript はすべての SDK で同様に機能します。

このチュートリアルの前提条件

概要: 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 オブジェクトは、infodebugerror のメソッドを公開します。 詳細については、このチュートリアルの後半で説明します。

  • 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 サーバーに要求を行い、言語に固有の ResultError のハンドリング部分も含まれます。

たとえば、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 RevisiontitleId を含むグローバル オブジェクトです。 Revision は、現在実行している CloudScript のリビジョン番号を表し、titleId は、現在のタイトルの ID を表します。

さらに、すべてのハンドラー関数は 2 つのパラメーターを渡されます。以下に詳細を記載します。

名前 使用
args ハンドラー関数に渡される最初のパラメーターです。 ExecuteCloudscript リクエストの FunctionParameter フィールドのオブジェクトの表現です。
context ハンドラー関数に渡される 2 つ目のパラメーターです。 アクションをトリガーした イベントからのデータ (context.playStreamEvent) と関連するプレイヤーのプロファイル データ を含む、PlayStream イベント アクションからトリガーされたリクエストに関する追加情報です。 (context.playerProfile)

CloudScript 機能は ExecuteCloudScriptAPI を通じて、または事前設定された 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 イベントに応答して実行するように構成できます。

  1. 任意のブラウザーで以下を実行します。
    • PlayFab ゲーム マネージャー を開きます。
    • 自分のタイトル を見つけます。
    • サイド バーの [ビルド][オートメーション] タブに移動します。
    • [ルール] タブに移動します。

ページは以下の例のようになります。

ゲーム マネージャー - PlayStream - イベント アクション

  1. [新しいルール] ボタンを使用して、新しいルールを作成します。

    • 新しいルールに名前を付けます。
    • 条件またはアクションのトリガーとして使用される [イベントの種類] を選択します。
    • ルールが CloudScript 関数をトリガーするようにするには、そのセクションのボタンでアクションを追加します。
    • 次に、[Type (タイプ)] ドロップダウン メニューでオプションを選択します。
    • [Cloud Script Function] ドロップダウン メニューで、[helloWorld] 関数を選択します。
    • [アクションの保存] ボタンを選択します。

    ゲーム マネージャー - PlayStream - アクションの保存

  2. このルールは、選択した種類のイベントに対してトリガーするように設定されました。 テストするには以下を実行します。

    • [Publish results as PlayStream Event (PlayStream イベントとして結果を公開)] ボックスを確認します。
    • アクションを保存します。
    • 次に、イベントをトリガーします。
    • [PlayStream モニター] で、CloudScript の実行に対応する新しいイベントが存在し、適切な情報が含まれている必要があります。
    • デバッガーで PlayStream イベントを確認する方法の詳細は、次の 上級: CloudScript のデバッグセクションを参照してください。

    注意

    CloudScript 機能を呼び出す際、イベント アクションはライブ リビジョンのみを使用できます。 ドロップダウンで helloWorld 関数が見つからない場合、これが最も一般的な原因です。

上級: CloudScript のデバッグ

注意

Azure 関数を使用した CloudScript を使用すると、デバッグがはるかに簡単になります。 Azure 関数を使用して CloudScript のローカル デバッグを使用する方法について説明します。

ログ記録

コードをデバッグするための最も重要なツールの 1 つはログ記録です。 CloudScript は、関数を実行するためのユーティリティを提供します。

これは、log オブジェクトの形式を取ります。InfoDebugError メソッドを使用して、必要なあらゆるメッセージをログ記録できます。

また、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] アイコンを選択します。

    ゲーム マネージャー - PlayStream - デバッガー

これを選択すると、各イベントに対して詳細化された、イベントの未加工の JSON がここに表示されます。 この JSON の例は、以下の例で確認できます。

  • シーンに LogScript MonoBehavior を追加する場合、ゲームの実行によって PlayStream でこれが発生します。

    ゲーム マネージャー - PlayStream - JSON イベント ログ

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);
}

エラーが発生した場合、このコードによってログに表示されます。