コマース

【PlayFab】UGCのモデレート【アイテムの報告、状態の変更】

ugc-moderation

UGC(User Generated Contents) のモデレートまわりについて解説をしていきます。

ユーザーが自由にコンテンツを生成できるということは、内容に問題があるコンテンツも公開されてしまうリスクがあるということです。

たとえばウイルスに感染しているファイルであったり、スパム的な内容などですね。

問題のあるコンテンツを放置しておくと他のユーザーにも影響がでたり、せっかく遊んでくれているユーザーが離れてしまうかもしれません。

そこで PlayFab では、ユーザーが問題がありそうなコンテンツを発見した場合に、報告してもらう仕組みが用意されています。

本記事では、ユーザーから報告してもらう機能と、管理者がモデレート(承認したり、否認したりすること)をする機能について解説しました。

最後まで読むことで、実装イメージが湧いてくると思います。

それではさっそく見ていきましょう。

アイテムの報告

問題がありそうなアイテムをユーザーから報告してもらうには、ReportItem を使用します。

private void ReportItem()
{
    PlayFabEconomyAPI.ReportItem(new ReportItemRequest
    {
        Id = "f464bc98-09ae-4bc8-a218-3a6100b6755e",
        Reason = "誤解を招く内容です。",
        ConcernCategory = ConcernCategory.MisleadingApp
    }, result =>
    {
        Debug.Log("アイテムの報告成功");
    }, error =>
    {
        Debug.Log(error.GenerateErrorReport());
    });
}

Id には、アイテム ID を指定します。今回は固定値としましたが、本来であればアイテムの一覧を取得して、そこから個別の ID を取得するのが望ましいです。

Reason に理由を入力し、任意で ConcernCategory に報告内容のカテゴリを指定します。

ConcernCategory の種類は以下のとおりです。

列挙体 意味
None なし(初期値)
OffensiveContent 攻撃的な内容
ChildExploitation 児童虐待に関する内容
MalwareOrVirus マルウェアやウイルス
PrivacyConcerns プライバシーの侵害
MisleadingApp 誤解を招く内容
PoorPerformance パフォーマンスの低下
ReviewResponse レビューの回答
SpamAdvertising スパム広告
Profanity 冒とく的な内容

アイテムの報告がされたかどうかは、データエクスプローラーから確認ができます。

アイテムの報告をしても何か通知がくるわけではないので、定期的に確認したほうがいいでしょう。

クエリで「item_reported」を指定して実行をすると、ReportItem を実行したログのみが抽出されます。

ugc-moderation
ugc-moderation

このログの内容をもとに、報告されたアイテムをどう扱うかについて検討することになります。

{
    "SchemaVersion": "2.0.1",
    "FullName": {
        "Namespace": "playfab.catalog",
        "Name": "item_reported"
    },
    "Id": "02d12302b1ab4902ad88f2465a4d8d62",
    "Timestamp": "2021-12-06T12:38:58.0076469Z",
    "Entity": {
        "Id": "9CED3069C7EC37C0",
        "Type": "title_player_account"
    },
    "Originator": {
        "Id": "9CED3069C7EC37C0",
        "Type": "title_player_account"
    },
    "OriginInfo": null,
    "Payload": {
        "ItemId": "f464bc98-09ae-4bc8-a218-3a6100b6755e",
        "ItemType": "ugc",
        "CreatorEntityKey": {
            "Id": "9CED3069C7EC37C0",
            "Type": "title_player_account"
        },
        "ConcernCategory": "MisleadingApp",
        "Reason": "誤解を招く内容です。"
    },
    "EntityLineage": {
        "namespace": "XXXXXXXXXXXXXXX",
        "title": "XXXXX",
        "master_player_account": "2B416FE1BB5AEE86",
        "title_player_account": "9CED3069C7EC37C0"
    },
    "ExperimentVariants": null
}

 

モデレーション状態の変更

モデレーション状態の変更は、SetItemModerationState を使用します。

ただし、この API はタイトルエンティティの権限が必要なため、クライアント側から処理することはできません。

ちなみにクライアントから実行してみると「タイトル権限が必要です」とエラーが出て、やはり実行できません。

ugc-moderation

ということで、Azure Fucntions と連携したサーバー処理で書いていきましょう。

Azure Functions の環境構築ができていない人は、【PlayFab】Azure関数を呼び出すための環境構築をご覧ください。

以下がサーバー側の処理になります。

[FunctionName("SetItemModerationState")]
public static async Task<dynamic> SetItemModerationState(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
        ILogger log)
{
    string body = await req.ReadAsStringAsync();
    var context = JsonConvert.DeserializeObject<FunctionExecutionContext<dynamic>>(body);
    var args = context.FunctionArgument;
    string playFabId = context.CallerEntityProfile.Lineage.MasterPlayerAccountId;

    var authApi = GetAuthInstance(context.TitleAuthenticationContext);
    var auth = await authApi.GetEntityTokenAsync(new PlayFab.AuthenticationModels.GetEntityTokenRequest
    {
        Entity = new PlayFab.AuthenticationModels.EntityKey
        {
            Id = context.TitleAuthenticationContext.Id,
            Type = "title"
        }
    });

    var economyApi = GetEconomyInstance(context.TitleAuthenticationContext, authApi.authenticationContext);
    var result = await economyApi.SetItemModerationStateAsync(new PlayFab.EconomyModels.SetItemModerationStateRequest
    {
        Id = args["ItemId"],
        Status = ModerationStatus.Approved,
        Reason = "特に問題なかったため。"
    });

    return new
    {
        error = PluginManager.GetPlugin<ISerializerPlugin>(PluginContract.PlayFab_Serializer).SerializeObject(result.Error),
        result = PluginManager.GetPlugin<ISerializerPlugin>(PluginContract.PlayFab_Serializer).SerializeObject(result.Result)
    };
}


private static PlayFabEconomyInstanceAPI GetEconomyInstance(TitleAuthenticationContext titleAuthenticationContext, PlayFabAuthenticationContext authContext)
{
    var apiSettings = new PlayFabApiSettings
    {
        TitleId = titleAuthenticationContext.Id,
        DeveloperSecretKey = Environment.GetEnvironmentVariable("PLAYFAB_DEV_SECRET_KEY", EnvironmentVariableTarget.Process),
    };

    return new PlayFabEconomyInstanceAPI(apiSettings, authContext);
}

private static PlayFabAuthenticationInstanceAPI GetAuthInstance(TitleAuthenticationContext titleAuthenticationContext)
{
    var apiSettings = new PlayFabApiSettings
    {
        TitleId = titleAuthenticationContext.Id,
        DeveloperSecretKey = Environment.GetEnvironmentVariable("PLAYFAB_DEV_SECRET_KEY", EnvironmentVariableTarget.Process),
    };
    return new PlayFabAuthenticationInstanceAPI(apiSettings);
}

全体の流れとしては以下のとおりです。

  1. GetEntityTokenAsync でタイトルの実行権限に昇格する
  2. エコノミー API を実行するためのインスタンスを生成する
  3. SetItemModerationState を実行する

サーバー処理としたからといって、タイトル権限の実行にならない点にも注意が必要です。

実行するときの ModerationStatus の種類は以下のとおりです。

列挙体 意味
AwaitingModeration モデレートを待機しています
Rejected 拒否されました
Approved 承認済み
Unknown 不明

AwaitingModeration は、ReportItem で報告されたアイテムをモデレーション中に変更するときに使用するといいでしょう。

Approved は内容として特に問題がなかったときに設定し、逆に問題があった場合は Rejected を設定します。

Unknown は特に使用しなくていいと思います。

Approved 以外のステータスでは、他のプレイヤーからは見えなくなります。

次にクライアント側からの呼び出し処理についてです。

private void SetItemModerationStateResponse()
{
    CallAzureFunctions<SetItemModerationStateResponse>(
    "SetItemModerationState",
    new { ItemId = "2e9a6eb9-fe21-4597-b802-6f0e10290d50" },
    funcResult =>
    {
        Debug.Log("アイテムのモデレーション状態の更新成功");
    }, funcError =>
    {
        Debug.Log("実行時にエラーが発生しました。");
        Debug.Log(funcError.GenerateErrorReport());
    });
}

/// <summary>
/// Azure Functions の呼び出し
/// </summary>
/// <typeparam name="T">取得結果の型</typeparam>
/// <param name="funcName">呼び出す関数名</param>
/// <param name="funcParam">サーバーに渡すパラメータ</param> 
/// <param name="onSuccess">成功時コールバック</param>
/// <param name="onError">失敗時コールバック</param>
public void CallAzureFunctions<T>(
        string funcName,
        object funcParam,
        Action<T> onSuccess = null,
        Action<PlayFabError> onError = null)
{
    PlayFabCloudScriptAPI.ExecuteFunction(new ExecuteFunctionRequest()
    {
        Entity = new PlayFab.CloudScriptModels.EntityKey()
        {
            Id = PlayFabSettings.staticPlayer.EntityId,
            Type = PlayFabSettings.staticPlayer.EntityType
        },
        FunctionName = funcName,
        FunctionParameter = funcParam,
        GeneratePlayStreamEvent = true
    }, result =>
    {
        Debug.Log("Azure Functions 実行成功! ");
        // 返り値の取り出し
        var jsonResult = (JsonObject)result.FunctionResult;
        var funcSuccess = PluginManager.GetPlugin<ISerializerPlugin>(PluginContract.PlayFab_Serializer).DeserializeObject<T>(jsonResult["result"].ToString());
        var funcError = PluginManager.GetPlugin<ISerializerPlugin>(PluginContract.PlayFab_Serializer).DeserializeObject<PlayFabError>(jsonResult["error"].ToString());
        if (result.FunctionResultTooLarge != null && (bool)result.FunctionResultTooLarge)
        {
            onError?.Invoke(funcError);
            return;
        }
        if (funcError == null)
            onSuccess?.Invoke(funcSuccess);
        else
            onError?.Invoke(funcError);
    }, error =>
    {
        onError.Invoke(error);
    });
}

引数としてモデレーション更新対象の ItemId を渡して SetItemModerationState を呼び出しているだけですね。

実行して、以下のようにログが出れば実行成功です。

ugc-moderation

更新したアイテムのモデレート状態を見てみると、指定したとおり「承認済み」として更新されていることが確認できました。

ugc-moderation

最後に

ユーザーから報告してもらう機能と、管理者がモデレートする機能について解説しました。

やはり運営していく上でも、問題のあるコンテンツを放置しておくとユーザーが離脱することにもつながります。

本記事の内容をもとに、コンテンツを管理する機能も取り入れてみましょう。

PlayFab の書籍も好評発売中!
playfab-book

PlayFab のことをもっと皆さんに知ってもらいたくて、合計500ページ以上にもなる書籍を5冊に分けて執筆しました。

私の知識をすべて詰め込んでいるので、ゲーム開発をさらに加速させたい方はぜひご覧ください。

COMMENT

メールアドレスが公開されることはありません。