GS2-Enhance

Enhancement feature

This feature may be completely incomprehensible to some developers.

However, it is a feature that is always present in the de facto standard game systems of mobile games, starting with those in Japan. This game mechanic itself should be useful knowledge for realizing Game as a Service, so for developers who do not understand it we add an explanation of the game mechanism.

If you already have sufficient knowledge of the game mechanics of the enhancement feature, you can safely skip the rest of this explanation section.

Game mechanics of the enhancement feature

Enhancement itself is a very simple game system in which material items can be consumed to add experience to a target. In addition to the method of gaining experience by participating in battle, characters and equipment can be grown in a variety of ways. (Equipment also has levels.)

Now let us explain why this game system plays a role in realizing Game as a Service.

In a nutshell, it is used to pad play time.

You all surely understand that the speed of game play is overwhelmingly faster than the speed of game development. A game that we game developers spent three years building, players finish in 10 hours. But Game as a Service cannot be sustained if this gap is not closed. In other words, it is necessary to debuff the rate at which players consume content. That magic is the enhancement game system.

A typical Game as a Service game holds an event once per month. In each event there is some kind of boss, and the player keeps defeating that boss repeatedly throughout the event period. The bosses come in multiple difficulties matched to the player’s growth stage, and defeating them yields character and equipment enhancement materials.

Using the enhancement materials they have gathered, players convert them into experience for characters and equipment to grow them. As characters and equipment grow, they can challenge higher difficulties of the boss.

In this way, while all players participate in the event, they obtain enhancement materials suited to their character’s growth stage and enjoy the gameplay of growing characters and equipment.

In reality, bosses rarely drop enhancement materials directly. Instead, there may be a gacha that can only be challenged during the event period and players collect points to draw it and obtain materials through the gacha, or there may be a shop open only during the event period where players collect in-game currency from defeating bosses and purchase enhancement materials from the shop. There are various designs that let players decide where to prioritize their growth, but ultimately what is happening is that the time a player needs to grow their character is being stretched to pad play time.

What remains consistent throughout the event is that the player’s character becomes stronger. Once the event ends, the stronger character is used to enjoy higher-difficulty permanent content, leading into the next form of fun.

graph TD
  BossBattle["Boss Battle"] -- Acquire Event Point --> Shop
  Shop -- Buy Enhance Materials --> Enhance["Enhance Character"]
  Enhance -- More Formidable --> BossBattle

Architecture

Enhancement is realized by GS2-Enhance operating on GS2-Inventory, which manages the items used as materials, and either GS2-Inventory or GS2-Dictionary, which manages the target character or equipment, plus GS2-Experience, which manages the experience and levels of that character or equipment.

In the current GS2, enhancement via DirectEnhance, which completes the consumption and experience addition in a single API request, is recommended. Previously, because automatic transaction execution was not available, a multi-step enhancement process (Progress) divided into preparation, execution, and completion reporting was recommended to prevent acts such as cutting off communication and retrying until a great success appeared. Now that automatic transaction execution and atomic commit mechanisms are in place, that concern has been resolved.

actor Player
participant "GS2-Enhance#Namespace"
participant "GS2-Inventory#ItemSet(Material)"
participant "GS2-Experience#Status"
Player -> "GS2-Enhance#Namespace" : Direct Enhance(Materials/Target Character)
"GS2-Enhance#Namespace" -> "GS2-Inventory#ItemSet(Material)" : Get experience value from metadata
"GS2-Enhance#Namespace" -> "GS2-Inventory#ItemSet(Material)" : Consume
"GS2-Enhance#Namespace" -> "GS2-Experience#Status": Add experience(Key: Target Character/Equipment Id)
"GS2-Enhance#Namespace" -> Player : Enhance result

You call the enhancement execution API (DirectEnhance) on GS2-Enhance with the parameters of “enhancement target” and “materials used for enhancement”.

GS2-Enhance then retrieves the master data of the material item from GS2-Inventory and obtains, from its metadata, the amount of experience to gain when used as material. Once the amount of experience is determined, the item is consumed and the experience-addition process is executed on GS2-Experience.

Although an enhancement target is specified, it is only used as the key for the experience managed by GS2-Experience; the enhancement target’s information itself is not used directly.

Differences between DirectEnhance and Progress

GS2-Enhance provides two enhancement flows.

Item DirectEnhance Progress (Start / End)
Number of API calls 1 2 (start / end)
Recommended use All enhancement processing When you want to obtain a draw result in advance to reflect outcomes such as great success in your effects
Atomicity Consumption and experience addition complete within the request The draw result is held on the server and confirmed by a subsequent End
Abuse via disconnect None An in-progress Progress can only be held one at a time; retries are only possible via DeleteProgress

Unless there is a special requirement, we recommend using DirectEnhance.

sequenceDiagram
  participant Player
  participant Enhance as GS2-Enhance
  participant Inventory as GS2-Inventory
  participant Experience as GS2-Experience
  Player ->> Enhance: DirectEnhance(rateName, targetItemSetId, materials)
  Enhance ->> Inventory: Obtain experience amount from metadata
  Enhance ->> Inventory: Consume material items
  Enhance ->> Experience: Add experience
  Enhance -->> Player: Added experience and great-success multiplier

Enhancement Rate

To limit the materials that can be used for enhancement and the enhancement target, the enhancement rate must be set as master data.

Master data records information such as the GS2-Inventory namespace and inventory name of items that can be used as materials, and the GS2-Inventory namespace and inventory name of items that can be enhancement targets.

Master data is managed in JSON format.

Here is an example of setting metadata for an ItemModel in JSON format such as { "experience": 50 }.

Define the JSON key (experience in the example above) in the acquireExperienceHierarchy of the RateModel. acquireExperienceHierarchy can also define a hierarchical structure. For example, if you want to set metadata with a data structure such as { "aaa": { "bbb": { "experienceValue": 100 } } }, specify [ "aaa", "bbb", "experienceValue" ] in acquireExperienceHierarchy.

Main configuration items of RateModel

Item Description
name Enhancement rate name
targetInventoryModelId Inventory model ID of the GS2-Inventory holding items to be enhanced
materialInventoryModelId Inventory model ID of the GS2-Inventory holding material items
acquireExperienceHierarchy JSON path used to extract the experience amount from the material item’s metadata
acquireExperienceSuffix Suffix appended to the experience model name key (e.g. :level)
experienceModelId Experience model ID of the GS2-Experience to which experience is added
bonusRates Multipliers and weights for great-success draws

GS2-Enhance RateModel master data — example of setting experience in metadata:


{
  "version": "2020-08-22",
  "rateModels": [
    {
      "name": "enhanceRate",
      "description": "",
      "metadata": "",
      "targetInventoryModelId": "grn:gs2:ap-northeast-1:YourOwnerId:inventory:enhance-inventory:model:character",
      "acquireExperienceSuffix": ":level",
      "materialInventoryModelId": "grn:gs2:ap-northeast-1:YourOwnerId:inventory:enhance-inventory:model:material",
      "acquireExperienceHierarchy": [
        "experience"
      ],
      "experienceModelId": "grn:gs2:ap-northeast-1:YourOwnerId:experience:enhance-experience:model:character",
      "bonusRates": [
        {
          "rate": 2,
          "weight": 1
        },
        {
          "rate": 1,
          "weight": 1
        }
      ]
    }
  ]
}

bonusRates can hold multiple entries; each entry has a draw weight (weight) and multiplier (rate). In the example above, “2x experience” and “1x experience” are drawn at the same weight, so a great success (2x) occurs roughly 50% of the time.

GS2-Experience ExperienceModel master data example:

{
  "version": "2019-01-11",
  "experienceModels": [
    {
      "name": "character",
      "metadata": "CHARACTER",
      "defaultExperience": 0,
      "defaultRankCap": 50,
      "maxRankCap": 80,
      "rankThreshold": {
        "metadata": "RANK_THRESHOLD",
        "values": [
          100,
          300,
          500,
          1000
        ]
      }
    }
  ]
}

GS2-Inventory ItemModel master data — example of setting experience in metadata:

{
  "version": "2019-02-05",
  "inventoryModels": [
    {
      "name": "character",
      "initialCapacity": 1,
      "maxCapacity": 1,
      "protectReferencedItem": false,
      "itemModels": [
        {
          "name": "character-0001",
          "stackingLimit": 1,
          "allowMultipleStacks": false,
          "sortValue": 0
        }
      ]
    },
    {
      "name": "material",
      "metadata": "",
      "initialCapacity": 10,
      "maxCapacity": 10,
      "protectReferencedItem": false,
      "itemModels": [
        {
          "name": "material-0001",
          "metadata": "{\"experience\":50}",
          "stackingLimit": 99,
          "allowMultipleStacks": false,
          "sortValue": 0
        }
      ]
    }
  ]
}

Limit Break (Unleash)

A “limit break” feature is also provided that consumes items such as duplicates of the same kind as materials to raise the target’s level cap. It is a mechanism for raising the rankCap managed by GS2-Experience one stage at a time, configured through the master data of UnleashRateModel with the following:

  • The inventory model that is the limit-break target
  • The associated grade model (GS2-Grade)
  • The material items and quantities required to reach each grade

This makes it possible to implement game mechanics such as “collect 4 of the same character to limit-break” or “consume N of a specific material item to unlock the level cap”.

Script Triggers

By configuring enhanceScript on the namespace, you can call custom scripts before and after enhancement execution. You can allow/deny the process or override the gained experience, and choose synchronous or asynchronous execution. Asynchronous execution also supports external integration via GS2-Script or Amazon EventBridge.

Main event triggers and script setting names are:

  • enhanceScript (completion notification: enhanceDone): before and after enhancement execution

In the script you can reference the enhancement target, the material items, and the multiplier being drawn. This is useful for purposes such as game balance adjustment or changing the boost multiplier during an event period.

Master data operations

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

Master data types include:

  • RateModel: Definition of enhancement materials and targets
  • UnleashRateModel: Rate definitions for limit break

Master data can be registered via the management console, imported from GitHub, or registered from CI using GS2-Deploy or various language CDKs.

Transaction Actions

GS2-Enhance provides the following transaction actions:

  • Consume action: Delete the in-progress enhancement progress information (Progress)
  • Acquire action: Execute immediate enhancement (DirectEnhance), execute limit break (Unleash), start enhancement (Progress)

By using “Execute immediate enhancement (DirectEnhance)” as an acquire action, you can perform operations such as directly granting experience to characters or equipment as a reward for clearing a specific quest or purchasing an item from a shop. Also, by setting “Limit break (Unleash)” as a reward, you can implement operations such as automatically raising the level cap when a specific mission is completed.

Example implementation

Getting a list of enhancement rates

    var items = await gs2.Enhance.Namespace(
        namespaceName: "namespace-0001"
    ).RateModelsAsync(
    ).ToListAsync();
    const auto It = Gs2->Enhance->Namespace(
        "namespace-0001" // namespaceName
    )->RateModels();
    TArray<Gs2::UE5::Enhance::Model::FEzRateModelPtr> Result;
    for (auto Item : *It)
    {
        if (Item.IsError())
        {
            return false;
        }
        Result.Add(Item.Current());
    }

Executing enhancement (DirectEnhance)

Specify the ItemSetId and quantity of the material items to consume in materials. Pass the ItemSetId of the character/equipment you want to enhance as targetItemSetId.

    var result = await gs2.Enhance.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Enhance(
    ).EnhanceAsync(
        rateName: "rate-0001",
        targetItemSetId: "item-set-0001",
        materials: new [] {
            new Gs2.Unity.Gs2Enhance.Model.EzMaterial
            {
                MaterialItemSetId = "material-0001",
                Count = 1,
            },
        }
    );

    var transaction = result;
    await transaction.WaitAsync();
    const auto Domain = Gs2->Enhance->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->Enhance(
    );
    const auto Future = Domain->Enhance(
        "rate-0001",
        "item-set-0001",
        []
        {
            const auto v = MakeShared<TArray<TSharedPtr<Gs2::Enhance::Model::FMaterial>>>();
            v->Add(MakeShared<Gs2::Enhance::Model::FMaterial>()
                ->WithMaterialItemSetId(TOptional<FString>("material-0001"))
                ->WithCount(TOptional<int32>(1)));
            return v;
        }()
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError()) return false;

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

Starting enhancement (Progress)

This is the flow when you want to obtain the draw result in advance. Only one in-progress Progress can be held per user.

    var result = await gs2.Enhance.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Progress(
    ).StartAsync(
        rateName: "rate-0001",
        targetItemSetId: "item-set-0001",
        materials: new [] {
            new Gs2.Unity.Gs2Enhance.Model.EzMaterial
            {
                MaterialItemSetId = "material-0001",
                Count = 1,
            },
        }
    );
    const auto Future = Gs2->Enhance->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->Progress(
    )->Start(
        "rate-0001", // rateName
        "item-set-0001", // targetItemSetId
        []
        {
            const auto v = MakeShared<TArray<TSharedPtr<Gs2::Enhance::Model::FMaterial>>>();
            v->Add(MakeShared<Gs2::Enhance::Model::FMaterial>()
                ->WithMaterialItemSetId(TOptional<FString>("material-0001"))
                ->WithCount(TOptional<int32>(1)));
            return v;
        }()
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError()) return false;

Getting in-progress enhancement information

You can obtain the drawn multiplier (great-success flag) and the amount of experience gained, and use them in enhancement effects.

    var item = await gs2.Enhance.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Progress(
    ).ModelAsync();

    var experienceValue = item.ExperienceValue;
    var rate = item.Rate;
    const auto Domain = Gs2->Enhance->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->Progress(
    );
    const auto Future = Domain->Model();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError()) return false;

    const auto Result = Future->GetTask().Result();
    const auto ExperienceValue = Result->GetExperienceValue();
    const auto Rate = Result->GetRate();

Completing enhancement (Progress)

Finalize the enhancement started by Start with End, executing consumption and experience addition.

    var result = await gs2.Enhance.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Progress(
    ).EndAsync();

    await result.WaitAsync();
    const auto Future = Gs2->Enhance->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->Progress(
    )->End();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError()) return false;

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

Discarding in-progress enhancement information

Used for recovery in cases such as when communication is interrupted and the completion report cannot be made.

    await gs2.Enhance.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Progress(
    ).DeleteProgressAsync();
    const auto Future = Gs2->Enhance->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->Progress(
    )->DeleteProgress();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError()) return false;

Other features

Great success in enhancement

In some enhancement specifications, a “great success” occurs at a certain probability, multiplying the gained experience by 1.5x or 2x. With GS2-Enhance you can configure the probability of great success and the experience multiplier in that case as part of the enhancement rate.

The ratio of each entry’s weight to the total of bonusRates weight is the probability of that multiplier being drawn.

Passing parameters to scripts using Config

EnhanceAsync / StartAsync accept a config parameter, which lets you pass arbitrary key-value pairs at script trigger time. You can convey information such as an in-game event boost state or the enhancement mode the player selected to the script.

Speculative Execute

When the speculativeExecute argument (default true) is enabled, the client-side cache is updated before waiting for the API response, allowing the UI to immediately display the post-experience-addition state. This delivers a snappy operational feel that is less affected by communication latency.

Detailed Reference