GS2-Account

account management features

The account system provided by Game Server Services is an “anonymous account” type of account system. This is a major system in Japan, but may seem strange in many other regions.

However, this account system makes a lot of sense for games.

What is an anonymous account?

When you think of account management, you usually think of having a login ID and a password. Anonymous accounts are no different.

However, the most important feature is that both the login ID and password are randomly generated by the system.

The login ID and password issued by the system can be saved to the local storage of the device, and the game can be resumed by logging in with this information for the second and subsequent times.

graph TD
  Startup --> LoadSave{"Load Anonymouse Account\nfrom Device Storage"}
  LoadSave -- Not Exists --> CreateAccount["Create Anonymouse Account"]
  CreateAccount --> SaveAccount["Save Anonymouse Account"]
  SaveAccount --> Login
  LoadSave -- Exists --> Login
  Login --> InGame

Advantages of Anonymous Account

  • Easy registration: Users can start playing games immediately without going through a complicated registration process. Especially in free-to-play (F2P) style games, reducing the registration process is important for encouraging more users to try the game.
  • Protection of player information: Since users do not need to set their own login IDs or passwords, personal information and privacy are protected. In addition, there is no need to reset or change passwords.
  • Easy transfer of game data: Users can use various platform IDs or social media accounts as transfer information, making it easy to transfer data between different devices or applications.
  • Anonymous gameplay experience: Players can enjoy a more free gameplay experience by playing games anonymously without using their real names or nicknames.

TakeOver

No other place is as unreliable as your device’s local storage. You could drop your device or destroy it. If you lose all your game data, you are in a no-win situation.

Players can experience the game with an anonymous account, and if they really like it, they can register “takeover setting”. You can use information from various game publishers’ ID bases for the takeover setting, or you can set up a social networking account. Game publishers’ ID bases can also be a good choice.

The takeover setting will include user IDs and other information obtained as a result of authentication with the various ID platforms. Then perform the takeover on an entirely new device. Log in to the various ID platforms and perform the takeover using the user ID you received. Information can be obtained to log in with an anonymous account created in the past with the takeover setting.

This information is stored in the local storage of the device and will be used for future logins.

graph TD
  InGame -- Loved the game very much! --> AddTakeOverSetting["Add TakeOver Setting"]
  AddTakeOverSetting --> BrokenDevice["Broken Device"]
  NewDevice["New Device"] --> DoTakeOver["Execute TakeOver\n(Enter TakeOver Setting)"]
  DoTakeOver -- Restore Anonymouse Account --> SaveAccount["Save Anonymouse Account"]
  SaveAccount --> Login

Example Implementation

Creating an Anonymous Account

GS2-Account has a hierarchy of namespaces that allows multiple pools of accounts within a single project. There is no specific purpose for namespaces, and they can be used as needed, for example to separate namespaces for different deployment regions.

    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;

Logging in using an anonymous account

The GS2-Account authentication process must be redone at regular intervals. Here is an example of a login using Gs2AccountAuthenticator, a utility class that automatically performs such processing.

By specifying Gs2AccountAuthenticator and the user ID and password of the anonymous account you created to the GS2 API client, you can obtain a GameSession instance that represents the session information during login. From now on, this GameSession instance will be used to access the information of the logged-in player.

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

Registering takeover setting

You can maintain multiple takeover settings for an account by specifying different values for the slot number.

For example, you can specify Slot Number:0 to store the email address/password, Slot Number:1 to store the social media ID information, and Slot Number:2 to store the password. The player can choose their preferred takeover method.

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

Get list of registered takeover setting

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

Perform takeover

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

Other functions

Setting per-player time offsets

Game Server Services account information can have a time offset. This offset can be set to how many minutes into the future the player will behave as a state.

This feature can be used to let QA staff play the game in a state one hour into the future, even within the production environment. This way, problems such as an event not being opened when it is time to start the event can be quickly noticed.

Account Suspension

It is possible to suspend a player for bad behavior in the game.

Detailed Reference