GS2-Version

Version check feature

Provides the ability to determine the version of the application, the version of any additional assets, and the version of the terms of service the player has agreed to.

If the version check passes, a new temporary GS2 client ID/secret can be issued.

By using this feature, the GS2 client ID/secret embedded in the application only has the authority to call the APIs that perform login and version check, and only after passing the version check can it receive a client ID/secret with the privileges sufficient to actually play the game.

graph TD
  Boot["App startup"] --> Login["Log in with GS2-Account"]
  Login -- "minimum-privilege<br/>client ID/secret" --> Check["GS2-Version<br/>CheckVersion"]
  Check -- "OK" --> Token["Obtain a new ProjectToken<br/>(intended privileges)"]
  Check -- "Warning" --> Notify["Prompt the player to update"]
  Check -- "Error" --> Force["Force version up"]
  Notify --> Token
  Token --> Game["Main game"]

Version Model

Up to 10 version models can be declared in a namespace. Multiple items can be configured for a version check, and the check is passed only when all the version checks pass.

There are two kinds of version models: “perform the version check based on the version sent by the application,” and “perform the version check based on the version of the agreement that the logged-in user has agreed to in the past."
The former is called “passive version check” and the latter is called “active version check.”

Master item Description
name Version model name (identifier at check time)
scope passive (passive) / active (active)
type simple (single threshold) / schedule (switch threshold by time)
currentVersion The version automatically considered approved on first participation in an active version check
warningVersion Version threshold that triggers a warning (returns warnings at or below this version)
errorVersion Version threshold that triggers an error (returns errors at or below this version)
scheduleVersions Defines per-time thresholds when type: schedule
needSignature Whether a signature is required on version information
signatureKeyId Key ID of GS2-Key used for signature verification
approveRequirement Approval requirement for active version checks (required / optional)

Version number format

{major}.{minor}.{micro}
format version numbers can be used, and each element can be specified as an integer value. Version values are compared in the order majorminormicro, and they are compared as numbers, not lexicographically.

Passive Version Check

Used to check the version of the game’s executable binaries and each asset downloaded by the game.

In the master data, you can set a “version threshold for warnings” and a “version threshold for errors” for each version model.
The client sends the current app build number and downloaded asset versions to the CheckVersion API, and receives the threshold-determined result from the server.

The result is one of the following:

Result Condition Expected behavior
Passed All items exceed warningVersion Proceed to the main game
Warning (warnings) Any is at or below warningVersion, and above errorVersion Prompt the player to update, but allow proceeding
Error (errors) Any is at or below errorVersion Force version up

Active Version Check

Used for cases such as the EULA, privacy policy, or terms revisions in specific regions, to determine “which version the player has agreed to.”

By calling the AcceptVersion API, the user can put an arbitrary version into the approved state. The threshold determination targets the approval version recorded on the server, not the version sent from the client, so impersonation cannot be used to bypass terms agreement.

Threshold switching by schedule

When you choose type: schedule, you can configure GS2-Schedule event IDs and the version during their event period in scheduleVersions. For example, you can reserve operations like “starting December 1, terms of service v2 is required” without a deploy.

Signature verification

By enabling needSignature, you can require signed version information at CheckVersion. Since the signature is verified with a key issued by GS2-Key (signatureKeyId), tampered version information can be rejected.

Script Triggers

By setting checkVersionTriggerScriptId and acceptVersionScript on the namespace, you can execute custom scripts at the time of a version check or version approval.

The main configurable event triggers and script setting names are as follows:

  • checkVersionTriggerScriptId: Script invoked during version check processing. You can add dynamic determination logic.
  • acceptVersionScript: Script invoked when a version is approved.

Transaction Actions

GS2-Version provides the following transaction actions:

Acquire actions

Action Purpose
Gs2Version:AcceptByUserId Puts the specified version into the approved state (for active version checks).

By using “approve a specified version” as an acquire action, you can perform processing such as automatically marking specific terms or versions as approved when a particular item is obtained or a mission is achieved.

Master Data Operation

Registering master data allows you to configure data and behaviors available to the microservice.

Master data types include the following:

  • VersionModel: Version model definition

The following is a JSON example of master data.

{
  "version": "2019-08-19",
  "versionModels": [
    {
      "name": "app",
      "metadata": "Application body",
      "scope": "passive",
      "type": "simple",
      "warningVersion": { "major": 1, "minor": 2, "micro": 0 },
      "errorVersion":   { "major": 1, "minor": 0, "micro": 0 }
    },
    {
      "name": "eula",
      "metadata": "Terms of service",
      "scope": "active",
      "type": "simple",
      "currentVersion": { "major": 1, "minor": 0, "micro": 0 },
      "warningVersion": { "major": 1, "minor": 0, "micro": 0 },
      "errorVersion":   { "major": 1, "minor": 0, "micro": 0 },
      "approveRequirement": "required"
    }
  ]
}

Master data can be registered via the Management Console, by reflecting data from GitHub, or by setting up workflows to register via CI using GS2-Deploy.

Example Implementation

Execute a version check

The result of CheckVersion includes the items that match warnings (Warnings), the items that match errors (Errors), and the ProjectToken issued on success. When you receive a ProjectToken, by re-authenticating with it you can obtain a session with the privileges actually required to play the game.

    var result = await gs2.Version.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Checker(
    ).CheckVersionAsync(
        targetVersions: new [] {
            new Gs2.Unity.Gs2Version.Model.EzTargetVersion
            {
                VersionName = "app",
                Version = new Gs2.Unity.Gs2Version.Model.EzVersion
                {
                    Major = 1,
                    Minor = 2,
                    Micro = 3,
                },
            },
            new Gs2.Unity.Gs2Version.Model.EzTargetVersion
            {
                VersionName = "asset",
                Version = new Gs2.Unity.Gs2Version.Model.EzVersion
                {
                    Major = 1,
                    Minor = 2,
                    Micro = 3,
                },
            },
        }
    );
    var projectToken = result.ProjectToken;
    var warnings = result.Warnings;
    var errors = result.Errors;

    if (errors != null && errors.Count > 0) {
        // Force version up
    } else if (warnings != null && warnings.Count > 0) {
        // Show an update-recommended dialog but continue
    }
    const auto Future = Gs2->Version->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->Checker(
    )->CheckVersion(
        []
        {
            const auto v = MakeShared<TArray<TSharedPtr<Gs2::Version::Model::FTargetVersion>>>();
            v->Add({'versionName': 'app', 'version': {'major': 1, 'minor': 2, 'micro': 3}});
            v->Add({'versionName': 'asset', 'version': {'major': 1, 'minor': 2, 'micro': 3}});
            return v;
        }() // targetVersions
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError()) return false;
    const auto ProjectToken = Result->ProjectToken;
    const auto Warnings = Result->Warnings;
    const auto Errors = Result->Errors;

Agree to an active version check

Call AcceptAsync when the user presses the agree button on the terms of service, for example. The agreed version is recorded per user in the AcceptVersion model and is referenced by subsequent calls to CheckVersion.

    var result = await gs2.Version.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).AcceptVersion(
        versionName: "eula"
    ).AcceptAsync(
    );
    const auto Future = Gs2->Version->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->AcceptVersion(
        "eula" // versionName
    )->Accept(
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError()) 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();

Get the version model

You can fetch the version model itself to display the “current terms version” and “warning threshold” in the UI.

    var item = await gs2.Version.Namespace(
        namespaceName: "namespace-0001"
    ).VersionModel(
        versionName: "eula"
    ).ModelAsync();
    const auto Domain = Gs2->Version->Namespace(
        "namespace-0001" // namespaceName
    )->VersionModel(
        "eula" // versionName
    );
    const auto Future = Domain->Model();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError()) return false;
    const auto Item = Future->GetTask().Result();

More practical information

Version update operating procedures

When updating a version, you may want to kick out all players currently playing so they can only play with the latest version.
GS2-Version can stop new logins, but for already-logged-in players it is possible to continue access until the expiration of the client ID/client secret temporarily issued after the version check.

Therefore, disconnect the always-on notification session provided by GS2-Gateway for all players, and have the game handle the session disconnection and perform a reconnection process after the version check.
If the version check fails, the game enters the version-up sequence directly.

This allows you to update the version and force a version check on all players in play as well.

Leveraging temporary client IDs

By combining with ProjectToken, you can adopt a two-stage authentication configuration in which the client ID/secret embedded in the app at startup is granted only the minimum privileges (sufficient only for login and version check), and the powerful privileges required for actual gameplay are exercised via the ProjectToken obtained after passing the version check. With this, even if the client ID/secret is leaked via reverse engineering of the app, the damage can be limited to bypassing the version check.

Detailed Reference