GS2-Version
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 major → minor → micro, 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.