> 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 raises the grade managed by GS2-Grade by one, which in turn raises the `rankCap` managed by GS2-Experience. It is configured through the master data of `UnleashRateModel` with the following:

- The inventory model that is the limit-break target (`targetInventoryModelId`)
- The associated grade model (GS2-Grade `gradeModelId`)
- The materials required to reach each grade (`gradeEntries`)

This makes it possible to implement game mechanics such as "collect 4 of the same character to limit-break" or "merge equipment by consuming either equipment of the same slot or a dedicated material".

The `gradeValue` of each entry in `gradeEntries` is the **grade reached** by the limit break. If the target's current grade is 2, the conditions of the entry whose `gradeValue` is 3 are used.
GS2-Grade grades start at 1 (a target that matches none of the `defaultGrades` starts at grade 1).

### Types of material conditions

Each entry chooses how its material conditions are written with `type`. Different grades can use different types.

| `type` | Description |
| --- | --- |
| `simple` (default) | Consumes `needCount` items of the same kind as the target. The item sets to consume are specified with `materials` at execution time. Whether an item is of the same kind is determined by `gradeUpPropertyIdRegex` of GS2-Grade. |
| `recipe` | The player chooses one of the recipes defined in `recipes` and executes it. All the materials of the chosen recipe are consumed. |

### Recipes

Each recipe material chooses how it is consumed with `materialType`, and holds the setting for that type.

| `materialType` | How it is consumed | Setting |
| --- | --- | --- |
| `individual` | Consumes item sets chosen by the player (such as duplicate equipment), one each. The materials must belong to the same inventory model as the target. | `individualSetting` |
| `quantity` | Consumes a quantity of an item decided by the setting (such as a general-purpose enhancement material). The player does not choose the item. Both standard inventories and simple inventories can be used. | `quantitySetting` |

The fields of `individualSetting` are as follows.

| Field | Description |
| --- | --- |
| `matchType` | `sameItem`: only the same item model as the target. `sameGroup`: item models with the same group key as the target. |
| `gradeCondition` | `any`: the material's grade is not checked. `sameAsTarget`: the material's grade must equal the target's current grade. `equal`: the material's grade must equal `gradeValue`. The material's grade is verified by GS2-Grade within the transaction. |
| `count` | The number of item sets to consume |

The fields of `quantitySetting` are as follows.

| Field | Description |
| --- | --- |
| `matchType` | `specified`: consumes the item specified by `itemModelId`. `sameGroup`: consumes the item in the `materialInventoryModelId` inventory that has the same group key as the target (exactly one item model must match). |
| `itemModelId` / `materialInventoryModelId` | The item model to consume / the inventory model to search for the material. Simple inventory GRNs can also be specified. |
| `count` | The quantity to consume |

When `targetGroupKeys` of a recipe is specified, the recipe can be used only when the target's group key is included in it. When it is empty, the recipe can be used for any target.

### Group keys

Classifications such as "the same slot" are expressed with a group key written in the item model's metadata (JSON).
`groupKeyHierarchy` of `UnleashRateModel` specifies at which level of the metadata the group key is stored. The value must be a string.

For example, if the item model's metadata is as follows, specify `["unleash", "group"]` for `groupKeyHierarchy`.

```json
{ "unleash": { "group": "weapon" } }
```

If the item models of slot-specific general-purpose materials also carry a group key in the same form, `sameGroup` of `quantitySetting` can express "the general-purpose material for the target's slot" with a single recipe.

### Master data example

An example where reaching grade 2 consumes one copy of the same equipment, and reaching grade 3 consumes either equipment of the same slot (grade 1) or two slot-specific general-purpose materials.

```json
{
  "name": "equipment",
  "targetInventoryModelId": "grn:gs2:{region}:{ownerId}:inventory:namespace-0001:model:equipment",
  "gradeModelId": "grn:gs2:{region}:{ownerId}:grade:namespace-0001:model:equipment",
  "groupKeyHierarchy": ["unleash", "group"],
  "gradeEntries": [
    {
      "gradeValue": 2,
      "type": "recipe",
      "recipes": [
        {
          "name": "merge",
          "materials": [
            {
              "name": "same",
              "materialType": "individual",
              "individualSetting": { "matchType": "sameItem", "gradeCondition": "sameAsTarget", "count": 1 }
            }
          ]
        }
      ]
    },
    {
      "gradeValue": 3,
      "type": "recipe",
      "recipes": [
        {
          "name": "fodder",
          "materials": [
            {
              "name": "fodder",
              "materialType": "individual",
              "individualSetting": { "matchType": "sameGroup", "gradeCondition": "equal", "gradeValue": 1, "count": 1 }
            }
          ]
        },
        {
          "name": "material",
          "targetGroupKeys": ["weapon", "armor"],
          "materials": [
            {
              "name": "material",
              "materialType": "quantity",
              "quantitySetting": {
                "matchType": "sameGroup",
                "materialInventoryModelId": "grn:gs2:{region}:{ownerId}:inventory:namespace-0001:simple:model:unleash-material",
                "count": 2
              }
            }
          ]
        }
      ]
    }
  ]
}
```

### Parameters at execution time

For an entry whose `type` is `recipe`, specify the recipe with `recipeName` when executing the limit break, and specify the item sets to consume for each `individual` material with `recipeMaterials`. `quantity` materials do not need to be specified.

```json
{
  "targetItemSetId": "grn:...:item:sword-0001:itemSet:target",
  "recipeName": "merge",
  "recipeMaterials": [
    { "name": "same", "itemSetIds": ["grn:...:item:sword-0001:itemSet:material"] }
  ]
}
```

An error is returned before the transaction is issued in the following cases.

- The target itself is included in the materials, or the same item set is specified more than once
- The number of materials does not match the recipe's `count`, or a material name not in the recipe is specified
- A material belongs to an inventory model other than the target's, or does not satisfy the `matchType` condition
- The target's group key is not included in `targetGroupKeys`, or the target's group key cannot be read from the metadata
- For `sameGroup` of `quantitySetting`, zero or two or more item models match

The experience or grade held by item sets consumed as materials is not carried over to the target.

## 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 5**
```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());
    }
```
**Godot**
```gdscript

var iterator = ez.enhance.namespace_(
        "namespace-0001"
    ).rate_models(
    )

var async_result = await iterator.load()
if async_result.error != null:
    # Handle the error
    push_error(str(async_result.error))
    return

var items = async_result.result

```


### 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 5**
```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;
```
**Godot**
```gdscript

var domain = ez.enhance.namespace_(
        "namespace-0001"
    ).me(game_session).enhance(
    )

var async_result = await domain.enhance(
    "rate-0001", # rate_name
    "item-set-0001", # target_item_set_id
    [
        Gs2EnhanceEzMaterial.new()
            .with_material_item_set_id("material-0001")
            .with_count(1),
    ], # materials
    null # config
)
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result

```


### 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 5**
```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;
```
**Godot**
```gdscript

var domain = ez.enhance.namespace_(
        "namespace-0001"
    ).me(game_session).progress(
    )

var async_result = await domain.start(
    "character-level", # rate_name
    "item-set-0001", # target_item_set_id
    [
        Gs2EnhanceEzMaterial.new()
            .with_material_item_set_id("material-0001")
            .with_count(1),
    ], # materials
    null, # force
    null # config
)
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result

```


### 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 5**
```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();
```
**Godot**
```gdscript

var domain = ez.enhance.namespace_(
        "namespace-0001"
    ).me(game_session).progress(
    )

var async_result = await domain.model()
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result

```


### 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 5**
```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;
```
**Godot**
```gdscript

var domain = ez.enhance.namespace_(
        "namespace-0001"
    ).me(game_session).progress(
    )

var async_result = await domain.end(
    null # config
)
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result

```


### 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 5**
```cpp

    const auto Future = Gs2->Enhance->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->Progress(
    )->DeleteProgress();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError()) return false;
```
**Godot**
```gdscript

var domain = ez.enhance.namespace_(
        "namespace-0001"
    ).me(game_session).progress(
    )

var async_result = await domain.delete_progress(
)
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result

```


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



