ソーシャル

【PlayFab】友達の紹介コードから特典を付与する方法

playfab-referral-code

スマホゲームには「必ずある」と言っても過言ではない、紹介コードの特典機能

よくあるのが、以下のような機能ですね。

playfab-referral-code

PlayFab を使うことで、この機能が簡単にできてしまうんです。

本記事では、サンプルコードをベースに独自のアレンジを加え、丁寧に実装方法を解説しました。

ほぼコピペで動作するので、実装時間をかなり短縮することができると思います。

公式 GitHub の Referral Codes を参考にしました。

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

友達の紹介コードから特典を付与する方法

まず全体の流れがどうなるのか、というところから説明していきますね。

大まかには以下の流れで処理をしていきます。

全体の流れ
  1. 紹介特典アイテムを登録
  2. 紹介コードを入力
  3. 入力内容チェック
  4. 相手の紹介者リストに自分を追加
  5. 相手に紹介特典の付与
  6. 自分に紹介コード入力特典の付与

少し長いですが、丁寧に解説していくので安心してください。

さらに細かく見ていきましょう。

1.  紹介特典アイテムを登録

まずは、「紹介コードを入力した人が受け取るアイテム」を登録します。

今回は「コンテナ」を紹介特典アイテムとしました。

コンテナについては、コンテナを自由自在に操る方法で解説をしています。

また、仮想通貨やアイテムについてはストアのアイテムを一覧表示して購入する手順 で解説していますので、合わせてご覧ください。

登録内容は何でもいいのですが、中身は「100,000 G と10,000 ジェム」にしています。

playfab-referral-code
playfab-referral-code

次に、「一度でも紹介コードを入力したかどうかが判別できるアイテム」を登録します。

これは何かというと、紹介コードというのは「誰から紹介されたかを登録するコード」なので、何回も入力されては困りますよね。

なので、一度入力したら「紹介コードを入力した」という情報をその人に登録しておくようにします。

こうすることで、何回も入力されたとしてもエラーとすることができるんです。

方法はいろいろありますが、今回は「永続アイテムを付与する」という方法を取ります。

消費型を「永続型」にしたアイテムを1つ登録しましょう。

playfab-referral-code

これでアイテムの準備は完了です。

2. 紹介コードを入力

友達から教えてもらった紹介コードを入力するシーンです。

入力欄を用意して、特にエラーがなければ完了メッセージを表示する感じですね。

playfab-referral-code

クライアント側のコードは以下のようにしておけばよいでしょう。

[SerializeField] TMP_InputField referralCode; // 入力するコード
[SerializeField] Button referralSearch; // 決定ボタン

// 決定ボタンの入力可否
public void ChangeReferralButtonEnabled()
{
    referralSearch.interactable = referralCode.text.Length == 16;
}

// 決定ボタンを押したときの処理
public void SearchReferralCode()
{
    CallExecuteFunction("RedeemReferral", new { ReferralCode = referralCode.text }, (result) =>
    {
        // 返り値の中身の取り出し
        var funcResult = PlayFabSimpleJson.DeserializeObject<JsonObject>(result.FunctionResult.ToString());
        // 文字列が空以外の場合は、エラーメッセージを表示
        if (!string.IsNullOrEmpty(funcResult["result"].ToString()))
        {
            ShowMessage(funcResult["result"].ToString());
            return;
        }

        ShowMessage("紹介コード入力特典を獲得しました。通知ボックスを確認してください。");
    });
}

今回、紹介コードは PlayFabId を使用するため、入力欄は16桁入力されていないと決定ボタンを押せないようにします。

実際の処理は CloudScript を呼び出し、エラーの場合はエラーメッセージを表示するようにしました。

続いて、サーバー側の処理を見ていきましょう。

ねこじょーかー
ねこじょーかー
Azure関数を使うので、Azure関数でCloudScriptを実行する方法を読んでから戻ってきてね!

サーバー処理全体の確認

ここからはサーバー側の処理になります。

とにかく結論が気になる人のために、全体の処理を最初に書いておきますね。(長いので折りたたみました)

サーバー処理の全体

const string PLAYER_REFERRAL_KEY = "Referrals"; // 紹介コードを入力されたPlayerのIDを保持しておくキー
const int MAXIMUM_REFERRALS = 10; // 紹介の上限数
const string REFERRAL_BADGE = "ReferralBadge"; // 紹介コードを入力したかどうかを判別するための永続アイテム
const string REFERRAL_BUNDLE = "con_referral_badge"; // コンテナのアイテムID
const string VC_GM = "GM"; // 紹介者に付与する仮想通貨

[FunctionName("RedeemReferral")]
public static async Task<dynamic> RedeemReferral(
[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;
  var serverApi = new PlayFabServerInstanceAPI(context.ApiSettings, context.AuthenticationContext);

  // 紹介コード(相手のPlayFabId)
  var referralCode = args["ReferralCode"];
  // 自分のPlayFabId
  var playFabId = context.CallerEntityProfile.Lineage.MasterPlayerAccountId;

  // 紹介用コードが自分の場合はエラー
  if (playFabId == referralCode)
    return new { result = "自分のコードは入力できません。" };

  // 自分のインベントリの取得
  var inventryResult = await serverApi.GetUserInventoryAsync(new GetUserInventoryRequest
  {
    PlayFabId = playFabId
  });

  // 紹介コードの入力済みチェック
  if (inventryResult.Result.Inventory.Any(x => x.ItemId == REFERRAL_BADGE))
    return new { result = "すでに紹介コードを入力済みです。" };

  // 相手の読み取り専用データの取得
  var readOnlyResult = await serverApi.GetUserReadOnlyDataAsync(new GetUserDataRequest
  {
    PlayFabId = referralCode,
    Keys = new List<string> { PLAYER_REFERRAL_KEY }
  });

  // 入力された招待コードのチェック
  if (readOnlyResult.Error != null)
  {
    return new { result = "紹介コードが正しくありません。" };
  }

  var idList = new List<string>();

  // 初めて紹介コードを入力される場合
  if (!readOnlyResult.Result.Data.ContainsKey(PLAYER_REFERRAL_KEY))
  {
    idList.Add(playFabId);
    ProcessReferrer(referralCode, idList, serverApi);
  }
  else
  {
    idList = PlayFabSimpleJson.DeserializeObject<List<string>>(readOnlyResult.Result.Data[PLAYER_REFERRAL_KEY].Value);
    // 紹介の上限数に達している場合はエラー
    if (idList.Count < MAXIMUM_REFERRALS)
    {
      idList.Add(playFabId);
      ProcessReferrer(referralCode, idList, serverApi);
    }
    else
    {
      return new { result = "この紹介コードは上限に達しているため、入力できません。" };
    }
  }

  // 自分に紹介特典アイテムとコンテナを付与
  var result = await serverApi.GrantItemsToUserAsync(new GrantItemsToUserRequest()
  {
    PlayFabId = playFabId,
    ItemIds = new List<string> { REFERRAL_BUNDLE, REFERRAL_BADGE },
    Annotation = "Referred by : " + referralCode
  });

  return new { result = "" };
}

private static async void ProcessReferrer(string referralCode, List<string> referrals, PlayFabServerInstanceAPI serverApi)
{
  // 相手の読み取り専用データを更新
  var updateUserReadOnlyDataResult = await serverApi.UpdateUserReadOnlyDataAsync(new UpdateUserDataRequest
  {
    PlayFabId = referralCode,
    Data = new Dictionary<string, string> { { PLAYER_REFERRAL_KEY, PlayFabSimpleJson.SerializeObject(referrals) } }
  });
  // 相手の仮想通貨を増やす
  var result = await serverApi.AddUserVirtualCurrencyAsync(new AddUserVirtualCurrencyRequest()
  {
    PlayFabId = referralCode,
    VirtualCurrency = VC_GM,
    Amount = 10000
  });
}

細かい処理の内容は、次から確認していきます。

3. 入力内容のチェック

ユーザーはどんな値を入力するかわからないので、入力内容のチェックは必須です。

どんなチェック処理を入れているのか見ていきます。

自分のコードかどうか

紹介コードに自分のコードを入れた場合はエラーとする必要があります。

  // 紹介コード(相手のPlayFabId)
  var referralCode = args["ReferralCode"];
  // 自分のPlayFabId
  var playFabId = context.CallerEntityProfile.Lineage.MasterPlayerAccountId;

  // 紹介用コードが自分の場合はエラー
  if (playFabId == referralCode)
    return new { result = "自分のコードは入力できません。" };

自分で自分を紹介する、というケースはおかしいですからね。

ここでは、エラー内容は文字列としてクライアント側に返すようにします。

すでに紹介コードを入力済みかどうか

先ほども書きましたが、紹介コードというのは「誰から紹介されたかを登録するコード」なので、何回も入力されては困りますよね。

自分のインベントリに、「一度でも紹介コードを入力したかどうかが判別できるアイテム」がないか検索をしています。

  // 自分のインベントリの取得
  var inventryResult = await serverApi.GetUserInventoryAsync(new GetUserInventoryRequest
  {
    PlayFabId = playFabId
  });

  // 紹介コードの入力済みチェック
  if (inventryResult.Result.Inventory.Any(x => x.ItemId == REFERRAL_BADGE))
    return new { result = "すでに紹介コードを入力済みです。" };

これで何回も紹介コードを入力されることを防ぐことができます。

もちろん、サーバー処理の前に、クライアント側でチェックしてしまっても問題ありません。

入力された紹介コードが正しいかどうか

入力された内容が正しいかどうかについては、「実際に PlayFabId を入れて検索した結果でエラーになるかどうか」で確認します。

  // 相手の読み取り専用データの取得
  var readOnlyResult = await serverApi.GetUserReadOnlyDataAsync(new GetUserDataRequest
  {
    PlayFabId = referralCode,
    Keys = new List<string> { PLAYER_REFERRAL_KEY }
  });

  // 入力された招待コードのチェック
  if (readOnlyResult.Error != null)
    return new { result = "紹介コードが正しくありません。" };

入力したコードと一致する PlayFabId のプレイヤーがいない場合は、エラーを返すようにしています。

また、ここで検索しているのは「相手が何人紹介しているか」を管理している項目です。

紹介した人のPlayFabId を、以下のように Json 形式で保持しておきます。

playfab-referral-code

以上で事前の入力チェックは完了です。

4. 相手の紹介者リストに自分を追加

相手の紹介者リストに自分を追加していきます。

相手が初めて紹介する場合は、まだ読み取り専用データに Referrals というキーが存在しません。

なので、キーが存在する場合のみ、取得した値に自分を追加する形にしています。

  // 初めて紹介コードを入力される場合
  if (!readOnlyResult.Result.Data.ContainsKey(PLAYER_REFERRAL_KEY))
  {
    idList.Add(playFabId);
    ProcessReferrer(referralCode, idList, serverApi);
  }
  else
  {
    idList = PlayFabSimpleJson.DeserializeObject<List<string>>(readOnlyResult.Result.Data[PLAYER_REFERRAL_KEY].Value);
    // 紹介の上限数に達している場合はエラー
    if (idList.Count < MAXIMUM_REFERRALS)
    {
      idList.Add(playFabId);
      ProcessReferrer(referralCode, idList, serverApi);
    }
    else
    {
      return new { result = "この紹介コードは上限に達しているため、入力できません。" };
    }
  }

また、紹介者は無限に紹介できてしまうと、無限に紹介特典を受け取れることになってしまいます。

そこで紹介の上限人数を設定し、上限に達している場合はエラーとするようにするのがよいでしょう。

5. 相手に紹介特典の付与

紹介者に紹介特典を付与していきます。

今回は、10,000 ジェムを紹介特典としました。

private static async void ProcessReferrer(string referralCode, List<string> referrals, PlayFabServerInstanceAPI serverApi)
{
  // 相手の読み取り専用データを更新
  var updateUserReadOnlyDataResult = await serverApi.UpdateUserReadOnlyDataAsync(new UpdateUserDataRequest
  {
    PlayFabId = referralCode,
    Data = new Dictionary<string, string> { { PLAYER_REFERRAL_KEY, PlayFabSimpleJson.SerializeObject(referrals) } }
  });
  // 相手の仮想通貨を増やす
  var result = await serverApi.AddUserVirtualCurrencyAsync(new AddUserVirtualCurrencyRequest()
  {
    PlayFabId = referralCode,
    VirtualCurrency = VC_GM,
    Amount = 10000
  });
}

この特典は自由に変更して構いません。

6. 自分に紹介コード入力特典の付与

最後に、自分に紹介コード入力特典の付与をしていきます。

事前に用意しておいたコンテナと、「一度でも紹介コードを入力したかどうかが判別できるアイテム」を同時に付与します。

  // 自分に紹介特典アイテムとコンテナを付与
  var result = await serverApi.GrantItemsToUserAsync(new GrantItemsToUserRequest()
  {
    PlayFabId = playFabId,
    ItemIds = new List<string> { REFERRAL_BUNDLE, REFERRAL_BADGE },
    Annotation = "Referred by : " + referralCode
  });

これでひと通り完了です。

お疲れさまでした!

ペンギンくん
ペンギンくん
けっこう長かったな…繰り返し読んで理解しようっと。

最後に

友達の紹介コードから特典を付与する方法について解説しました。

処理全体としては長いですが、細かく分割して見ていくと、理解しやすかったのではないでしょうか。

長いソースコードを見ると「うわ、難しそうだな」と感じてしまう人も多いと思います。

そんなときは、落ち着いて上から順に1つずつ確認していけば大丈夫です。

この記事を参考に、ぜひ紹介コードの特典機能を実装してみてください。

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

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

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

COMMENT

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