共有グループ データの使用

共有グループ データは、プレイヤーがいくつかの情報を厳しく制約された他のプレイヤーの一覧と共有するための簡単な方法です。

注意

共有グループ データは当初、ほとんどの場合サーバーが権限を付与するように設計され、以前はプレイヤーを共有グループ データに直接追加しないことが推奨されていました。読み取り/書き込みアクセス許可を付与するためです (不正行為が可能になる)。 ただし、新しい API アクセス ポリシーにより、元の設計から機能が大幅に変更され、セキュリティが向上しました。 詳しくは、このドキュメントの詳細セクションをご覧ください。

Warning

共有グループ データは、プレイヤーが十数人を超えるグループでは使わないでください。 1 つの問題として、同時に同じデータを読み取ろうとするプレイヤーが多すぎると、データの読み取り遅延が発生します (共有グループ データは、多くのプレイヤーが一度に読み取ることを意図したタイトル データのようにシャードまたはキャッシュされるわけではありません)。 プレイヤーが互いのデータを上書きしないように特に注意してください。 複数のプレイヤーが同じキーを同時に書き込もうとするインスタンスでは、これらの書き込みの 1 つだけが「勝ち」、他のユーザーのデータは失われます。

例: ターンベースのマルチプレイヤー非同期ゲーム

共有グループ データの当初の (かつベストな) ユース ケースを最もよく表す表現は、オンライン ボード ゲームの状態の保存です。 プレイヤーは、CloudScript を通じてデータを交代で変更します。ターンの順序は明確です。

ゲームの状態がクラウドに保存されているため、プレイヤーはログオフして後でプレイを再開できます。

次の CloudScript の例は、一般的なボード ゲームのターン ベースの構造です。 ボード ゲーム自体は、疑似コードとしてスタブ アウトされます。

前提

ゲームを表す共有グループ データが既に開始されており、そのメンバーシップは既に定義されています。

// CloudScript/Javascript
const MY_GAME_GROUP_KEYS: Array<string> = ["gameState", "currentPlayerTurn"];
interface PlayerTurnArgs {
    sharedGroupId: string;
    nextPlayerTurn: string;
    turnData: any;
}
handlers.TakePlayerTurn = function (args: PlayerTurnArgs) {
    var getRequest: PlayFabServerModels.GetSharedGroupDataRequest = { SharedGroupId: args.sharedGroupId, GetMembers: true, Keys: MY_GAME_GROUP_KEYS };
    var gameData: PlayFabServerModels.GetSharedGroupDataResult = server.GetSharedGroupData(getRequest);
    CheckValidPlayer(currentPlayerId, args.sharedGroupId, gameData.Members, gameData.Data["currentPlayerTurn"].Value, args.nextPlayerTurn);
    var newGameStateJson = UpdateGameState(args.turnData, gameData.Data["gameState"].Value);
    var updateRequest: PlayFabServerModels.UpdateSharedGroupDataRequest = {
        SharedGroupId: args.sharedGroupId,
        Data: {
            "gameState": newGameStateJson,
            "currentPlayerTurn": args.nextPlayerTurn
        }
    };
    server.UpdateSharedGroupData(updateRequest);
}
function CheckValidPlayer(playFabId: string, sharedGroupId: string, members: Array<string>, currentPlayerTurn: string, nextPlayerTurn: string): void {
    var validCurPlayer = false;
    var validNextPlayer = false;
    for (var m = 0; m < members.length; m++) {
        if (members[m] === playFabId)
            validCurPlayer = true;
        if (members[m] === nextPlayerTurn)
            validNextPlayer = true;
    }
    if (!validCurPlayer || !validNextPlayer) // Take extreme action against a player trying to cheat
    {
        server.BanUsers({ Bans: [{ PlayFabId: playFabId, Reason: "Trying to play a game you don't belong to: " + sharedGroupId }] });
        throw "You have been banned";
    }

    if (playFabId !== currentPlayerTurn)
        // May wish to additionally implement a spam-counter here and potentially take more extreme action for high-spam count
        throw "Not your turn";
}
function UpdateGameState(turnData: any, currentState: string): string {
    // PSEUDO-CODE-STUB: Update the turn-based game state according to the rules of this game
    return JSON.stringify({});
}

大まかに言うと、共有グループ データを使ってパーティー/レイドを実装したり、説明のとおりグループ サイズが比較的小さければ、他の半永続的なプレイヤー グループを実装したりできます。

現在のところ制限は厳密に適用されるわけではありませんが、多数のプレイヤーでの使用はサポートされおらず、極端なケースではサービスの他のタイトルへの影響を防ぐためにタイトルの機能が調整される可能性があります。

主な制限

  • 共有グループ データ:
    • シンプルなキー/値ペア データ (文字列) のみが含まれます。 他のデータ型 (インベントリ アイテム、統計情報、仮想通貨など) に使う場合、タイトルは必要な変換を行う必要があります。
    • シャードキャッシュもされないため、複数のプレイヤーが同時にアクセスすると応答しなくなります。 これを使う機能は、少数のプレイヤーを念頭に置いて設計し、同時書き込みを許可しないでください。

クライアントのアクセス許可の懸念事項

グループ内にロール/ランク システムはありません。つまり、グループ内のどのメンバーもグループ内で絶対的な権利を持ちます (定義済みのリーダーはいません)。

端的に言うと、API アクセスポリシーでクライアント共有グループ データのメソッドを無効にしない限り、クライアントはデータを完全にコントロールすることになり、データの悪用につながる可能性があるということです。

ベスト プラクティスとして、ゲームプレイに影響を与えるデータに共有グループ データを使わないか、クライアント API で共有グループ データの手法を無効にすることをお勧めします。