GS2-Account

アカウント管理機能

Game Server Services が提供するアカウントシステムは「匿名アカウント」という種類のアカウントシステムです。 日本ではメジャーな仕組みですが、多くの地域では奇妙に感じるアカウントシステムかもしれません。

しかし、このアカウントシステムはゲームにおいて非常に理にかなったアカウントシステムです。

匿名アカウントとはなんですか?

通常イメージするアカウント管理は、ログインIDがありパスワードがあるものでしょう。 匿名アカウントもその点は変わりません。

しかし、ログインIDとパスワードの両方がシステムによってランダムに決定されるというのが最大の特徴です。

システムによって発行されたログインID・パスワードをデバイスのローカルストレージに保存し、2回目以降はその情報を利用してログインすることでゲームを再開できます。

graph TD
  Startup --> LoadSave{"デバイスストレージから\n匿名アカウントを読み込み"}
  LoadSave -- Not Exists --> CreateAccount["匿名アカウントを作成"]
  CreateAccount --> SaveAccount["匿名アカウントを保存"]
  SaveAccount --> Login["ログイン"]
  LoadSave -- Exists --> Login
  Login --> InGame

匿名アカウントのメリット

  • 簡単な登録:ユーザーは煩雑な登録プロセスを経ずにゲームをすぐに開始することができます。特に、無料で遊べるF2Pスタイルのゲームでは、多くのユーザーがゲームを試してもらうためには登録の手間を減らすことが重要です。
  • プレイヤー情報の保護:ログインIDやパスワードを自分で設定する必要がないため、個人情報やプライバシーが保護されます。また、パスワードの再設定や変更なども必要ありません。
  • 引き継ぎのしやすさ:引き継ぎ情報に各種プラットフォームのID基盤やSNSのアカウントなどを利用することができ、異なるデバイスやアプリ間での引き継ぎがスムーズに行えます。
  • 匿名でのプレイ体験:プレイヤーは匿名でゲームをプレイすることができるため、リアルネームやニックネームを使用しなくてもよく、より自由なプレイ体験を楽しむことができます。

引き継ぎ

デバイスのローカルストレージほど信頼性の低い場所は他にはありません。 デバイスを落としてしまうかもしれませんし、デバイスを壊してしまうかもしれません。 そのとき、ゲームデータを全て失ってしまうとしたら、それは絶望的な状況です。

ゲームプレイヤーは、匿名アカウントでゲームを体験し、本当に気に入ったら「引き継ぎ情報」を登録できます。 引き継ぎ情報には各種プラットフォーマーのID基盤の情報を利用してもいいですし、SNSのアカウントを設定してもいいでしょう。ゲームパブリッシャーのID基盤も良さそうです。

引き継ぎ情報には各種ID基盤で認証した結果得られるユーザーIDなどを記録します。 そして、全く新しいデバイスで引き継ぎを実行します。各種ID基盤にログインし、得られたユーザーIDで引き継ぎを実行すると 過去に引き継ぎ情報を設定した匿名アカウントでログインするための情報を取得することができます。

この情報を再びデバイスのローカルストレージに保存して、今後のログインに利用します。

graph TD
  InGame -- ゲームを気に入った --> AddTakeOverSetting["引き継ぎ情報を登録"]
  AddTakeOverSetting --> BrokenDevice["スマホが壊れた"]
  NewDevice["新しいスマホ"] --> DoTakeOver["引き継ぎ情報を入力して引き継ぎを実行"]
  DoTakeOver -- 匿名アカウントを復元 --> SaveAccount["匿名アカウントを保存"]
  SaveAccount --> Login["ログイン"]

実装例

匿名アカウントの作成

GS2-Account はネームスペースという階層をもち、1つのプロジェクト内に複数のアカウントプールを持つことができます。 ネームスペースの用途は特に定めていません、配信地域ごとにネームスペースを分けるなど必要に応じて活用することができます。

    var result = await gs2.Account.Namespace(
        namespaceName: "namespace-0001"
    ).CreateAsync();

    var item = await result.ModelAsync();
    var userId = item.UserId;
    var password = item.Password;
    const auto NamespaceName = "namespace-0001";

    const auto Future = Gs2->Account->Namespace(
        NamespaceName
    )->Create();

    Future->StartSynchronousTask();
    if (Future->GetTask().IsError()) return false;
    const auto Result = Future->GetTask().Result();

    const auto Future2 = Result.Model();
    Future2->StartSynchronousTask();
    if (Future2->GetTask().IsError()) return false;
    const auto Result2 = Future2->GetTask().Result();

    var UserId = Result2.UserId;
    var Password = Result2.Password;

匿名アカウントを使用したログイン

GS2-Account の認証処理は、一定期間でやりなおす必要があります。 そのような処理を自動的に行ってくれるユーティリティクラスである Gs2AccountAuthenticator を使用したログイン例を示します。

GS2 のAPIクライアントに対して、Gs2AccountAuthenticatorと作成した匿名アカウントのユーザーID、パスワードを指定することでログイン中のセッション情報を表す GameSession インスタンスを取得できます。 以降、ログイン中のプレイヤーの情報にアクセスするにはこの GameSession インスタンスを使用することになります。

    var gameSession = await gs2.LoginAsync(
        new Gs2AccountAuthenticator(
            accountSetting: new AccountSetting {
                accountNamespaceName = this.accountNamespaceName,
            }
        ),
        account.UserId,
        account.Password
    );
    const auto NamespaceName = "namespace-0001";
    const auto KeyId = "grn:gs2:{region}:{yourOwnerId}:key:namespace-0001:key:key-0001";

    const auto Future = Profile->Login(
        MakeShareable<Gs2::UE5::Util::IAuthenticator>(
            new Gs2::UE5::Util::FGs2AccountAuthenticator(
                NamespaceName,
                KeyId
            )
        ),
        UserId,
        Password
    );

    Future->StartSynchronousTask();
    if (Future->GetTask().IsError()) return false;
    const auto Result = Future->GetTask().Result();

引き継ぎ情報の登録

スロット番号 に異なる値を指定することで、1つのアカウントに対して複数の 引き継ぎ設定 を保持できます。

たとえば、 スロット番号:0 にメールアドレス・パスワード を、 スロット番号:1 にソーシャルメディアのID情報を格納するようにし、 ゲームプレイヤーは好みの引き継ぎ手段を選択できるようにする といった運用が可能です。

    var result = await gs2.Account.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).TakeOver(
        type: 0,
        userIdentifier: "user-0001@gs2.io"
    ).AddTakeOverSettingAsync(
        password: "password-0001"
    );
    const auto NamespaceName = "namespace-0001";
    const auto Type = 0;
    const auto UserIdentifier = "user-0001@gs2.io";
    const auto Password = "password-0001";

    const auto Future = Gs2->Account->Namespace(
        NamespaceName
    )->Me(
        AccessToken
    )->TakeOver(
        Type,
        UserIdentifier
    )->AddTakeOverSettingAsync(
        Password
    );

    Future->StartSynchronousTask();
    if (Future->GetTask().IsError()) return false;
    const auto Result = Future->GetTask().Result();

登録済みの引き継ぎ情報一覧取得

    var items = await gs2.Account.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).TakeOversAsync(
    ).ToListAsync();
    const auto NamespaceName = "namespace-0001";

    const auto It = Gs2->Account->Namespace(
        NamespaceName
    )->Me(
        AccessToken
    )->TakeOvers();
    TArray<Gs2::UE5::Account::Model::FEzTakeOverPtr> Result;
    for (auto Item : *It)
    {
        if (Item.IsError())
        {
            return false;
        }
        Result.Add(Item.Current());
    }

引き継ぎの実行

    string userId;
    string password;
    try {
        var result = await gs2.Account.Namespace(
            namespaceName: "namespace-0001"
        ).DoTakeOverAsync(
            type: 0,
            userIdentifier: "user-0001@gs2.io",
            password: "password-0001"
        );

        var item = await result.ModelAsync();
        userId = item.UserId;
        password = item.Password;
    } catch(Gs2.Gs2Account.Exception.PasswordIncorrect e) {
        // Incorrect password specified.
    }
    const auto NamespaceName = "namespace-0001";
    const auto Type = 0;
    const auto UserIdentifier = "user-0001@gs2.io";
    const auto Password = "password-0001";

    const auto Future = Gs2->Account->Namespace(
        NamespaceName
    )->DoTakeOver(
        Type,
        UserIdentifier,
        Password
    );

    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        auto e = Future->GetTask().Error();
        if (e->IsChildOf(Gs2::Account::Error::FPasswordIncorrectError::Class))
        {
            // Incorrect password specified.
        }
        return false;
    }
    // obtain changed values / result values
    const auto Future2 = Future->GetTask().Result()->Model();
    Future2->StartSynchronousTask();
    if (Future2->GetTask().IsError()) return false;
    const auto Result = Future2->GetTask().Result();

その他の機能

プレイヤーごとの時刻オフセット設定

Game Server Services のアカウント情報には時刻のオフセットを持たせることが可能です。 このオフセットには未来に向けて、プレイヤーが何分間先の状態として振る舞うかを設定することが可能です。

この機能を利用すると、本番環境内でもQA担当者は1時間未来の状態でゲームを遊ばせるようなことを実現できます。 こうすることで、イベントの開始時刻になってもイベントがオープンされないといった問題にいち早く気づくことができます。

アカウントの利用停止

ゲーム内での素行が悪いプレイヤーを利用停止にすることが可能です。

詳細なリファレンス