> For the complete documentation index, see [llms.txt](/llms.txt)

# 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.

```mermaid
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.

```plantuml
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`.

```mermaid
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:
```json

{
  "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:
```json
{
  "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:
```json
{
  "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



**Unity**
```csharp

    var items = await gs2.Enhance.Namespace(
        namespaceName: "namespace-0001"
    ).RateModelsAsync(
    ).ToListAsync();
```
**Unreal Engine**
```cpp

    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`.



**Unity**
```csharp

    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();
```
**Unreal Engine**
```cpp

    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.



**Unity**
```csharp

    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,
            },
        }
    );
```
**Unreal Engine**
```cpp

    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.



**Unity**
```csharp

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

    var experienceValue = item.ExperienceValue;
    var rate = item.Rate;
```
**Unreal Engine**
```cpp

    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.



**Unity**
```csharp

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

    await result.WaitAsync();
```
**Unreal Engine**
```cpp

    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.



**Unity**
```csharp

    await gs2.Enhance.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Progress(
    ).DeleteProgressAsync();
```
**Unreal Engine**
```cpp

    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

[GS2-Enhance API Reference](../../api_reference/enhance)



