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

# GS2-Grade

Grade/rarity feature



A common specification for character and equipment development is to provide grade-up in addition to level-up as a short-term growth goal.
Grading up can raise the level cap and make it possible to develop characters and equipment more powerfully.

There are several possible methods of upgrading: some can be done by consuming growth materials, while others involve synthesizing characters or equipment of the same kind.
GS2-Grade does not care about the method. Its purpose is to make the operation of GS2-Experience's level cap simpler to implement by setting a level cap for each grade.

```mermaid
graph LR
  Player["Player's possessions"] -- Grade Up --> Grade["GS2-Grade<br/>(grade value increases)"]
  Grade -- ApplyRankCap --> Experience["GS2-Experience<br/>(rank cap is reflected)"]
  Experience -- Gain experience points --> LevelUp["Level Up"]
```

## Grades

For each grade, you can define the value to be set as the rank cap of GS2-Experience.
Grades are managed for each `propertyId` that uniquely points to a target such as a character or piece of equipment, and are held individually as `Status`.

| Field | Description |
| --- | --- |
| `gradeName` | Grade model name |
| `propertyId` | The GRN indicating the resource to which the grade is applied (e.g., a GS2-Inventory ItemSet) |
| `gradeValue` | The current grade value (integer starting from 0) |

### Initial values for a grade

You can set the initial grade value depending on whether the property ID matches a regular expression.
For example, by starting at grade 3 when the GS2-Inventory ItemModel name begins with SSR, and at grade 2 when it begins with SR, you can change the initial rank cap depending on the type of ItemModel.

You declare initial grades by registering multiple pairs of `propertyIdRegex` and `defaultGradeValue` in the master data's `defaultGrades`.

### Grade-up material determination

In the case of "synthesizing the same kind of character or equipment" as a method of upgrading, a feature is provided to support determining whether the resource being used as material is "the same kind of character or equipment."
This is achieved by using a regular expression to extract parameters from the property ID of the grade, constructing a regular expression, and determining whether the property ID of the resource to be used as material matches.

For example, to determine if an ItemSet in GS2-Inventory is from the same kind of ItemModel, set the regular expression as follows:
```
propertyIdRegex: grn:gs2:{region}:{ownerId}:inventory:namespace-0001:user:(.*):inventory:character:item:(.*):.*
gradeUpPropertyIdRegex: grn:gs2:{region}:{ownerId}:inventory:namespace-0001:user:$1:inventory:character:item:$2:.*
```

Now use propertyIdRegex to retrieve the "user ID" and the "ItemModel name".
If the user ID is "user-0001", the name of the ItemModel is "item-0001", and the name of the ItemSet is "item-set-0001", then the GRN (property ID) of the ItemSet is:
```
grn:gs2:{region}:{ownerId}:inventory:namespace-0001:user:user-0001:inventory:character:item:item-0001:item-set-0001
```
and the replaced value of gradeUpPropertyIdRegex becomes:
```
gradeUpPropertyIdRegex: grn:gs2:{region}:{ownerId}:inventory:namespace-0001:user:user-0001:inventory:character:item:item-0001:.*
```
This allows you to express the ability to specify items of the same kind as material.

## Reward multiplier table

The grade model can have `acquireActionRates` configured to adjust the reward amounts of acquire actions according to the grade.
Using this, you can incorporate growth elements such as "higher-grade characters earn more from quest rewards" or "the experience-point multiplier changes per grade".

| `mode` | Description |
| --- | --- |
| `double` | Multiplies by the multiplier set in `rates` as a floating-point value. Used for standard corrections of item acquisition amounts. |
| `big` | Treats the multiplier set in `bigRates` as a string value and supports cases dealing with massive rewards such as BigItem of GS2-Inventory, which can handle numbers exceeding int64. |

By incorporating `Gs2Grade:MultiplyAcquireActionsByUserId` into the acquire actions of a transaction, you can convert the actions into a list of acquire actions with the multiplier of the specified grade applied.

## Script Triggers

Setting `changeGradeScript` in the namespace allows custom scripts to be executed before and after grade changes.
Triggers support both synchronous and asynchronous execution. Asynchronous processing also supports external integration through GS2-Script or Amazon EventBridge.

The main event triggers and script setting names that can be configured are as follows:

- `changeGradeScript` (completion notification: `changeGradeDone`): before and after grade changes

## Transaction Actions

GS2-Grade provides the following transaction actions:

| Type | Action | Description |
| --- | --- | --- |
| Verify | `Gs2Grade:VerifyGradeByUserId` | Verify the grade value is the specified value |
| Verify | `Gs2Grade:VerifyGradeUpMaterialByUserId` | Verify whether a resource is valid as a grade-up material (matches `gradeUpPropertyIdRegex`) |
| Consume | `Gs2Grade:SubGradeByUserId` | Subtract from the grade |
| Acquire | `Gs2Grade:AddGradeByUserId` | Add to the grade |
| Acquire | `Gs2Grade:AddRankCapByUserId` | Reflect the rank cap corresponding to the grade into GS2-Experience |
| Acquire | `Gs2Grade:MultiplyAcquireActionsByUserId` | Convert into acquire actions with the multiplier from `acquireActionRates` applied according to the grade |

By using "Verify grade-up material" as a verify action, you can validate within a transaction whether the material being used for synthesis (another item or character) is actually possessed. This prevents grade-ups from being performed with illegitimate material specifications.

## Managing master data
By registering master data, you can configure the data and behavior available to the microservice.

The types of master data are as follows:

- `GradeModel`: rank caps and reward amounts per grade

Below is an example JSON of master data.

```json
{
  "version": "2022-06-01",
  "gradeModels": [
    {
      "name": "grade-0001",
      "metadata": "Character Grade",
      "experienceModelId": "grn:gs2:{region}:{ownerId}:experience:namespace-0001:model:experienceModel-0001",
      "defaultGrades": [
        {
          "propertyIdRegex": ".*:item:SSR.*",
          "defaultGradeValue": 3
        },
        {
          "propertyIdRegex": ".*:item:SR.*",
          "defaultGradeValue": 2
        }
      ],
      "gradeEntries": [
        { "metadata": "Grade 0", "rankCapValue": 30 },
        { "metadata": "Grade 1", "rankCapValue": 40 },
        { "metadata": "Grade 2", "rankCapValue": 50 },
        { "metadata": "Grade 3", "rankCapValue": 60 }
      ],
      "acquireActionRates": [
        {
          "name": "experience",
          "mode": "double",
          "rates": [1.0, 1.2, 1.5, 2.0]
        }
      ]
    }
  ]
}
```

Master data can be registered from the Management Console, or you can set up a workflow that reflects data from GitHub or registers via CI using GS2-Deploy.

## Example implementation

### Grade addition

Grade addition cannot be processed by the SDK for game engines.

Incorporate the transaction action `Gs2Grade:AddGradeByUserId` into the consumption of enhancement materials in GS2-Exchange, or as an enhancement reward in GS2-Enhance, to add to a grade.
This lets you implement growth elements while keeping server-side consistency and preventing grade-ups from being triggered by unauthorized client operations.

### Get a list of grades



**Unity**
```csharp

    var items = await gs2.Grade.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).StatusesAsync(
        gradeName: "grade-0001"
    ).ToListAsync();
```
**Unreal Engine**
```cpp

    const auto It = Gs2->Grade->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Statuses(
        "grade-0001" // gradeName
    );
    TArray<Gs2::UE5::Grade::Model::FEzStatusPtr> Result;
    for (auto Item : *It)
    {
        if (Item.IsError())
        {
            return false;
        }
        Result.Add(Item.Current());
    }
```


### Get the grade



**Unity**
```csharp

    var item = await gs2.Grade.Namespace(
        namespaceName: "namespace-0001"
    ).GradeModel(
        gradeName: "grade-0001"
    ).ModelAsync();
```
**Unreal Engine**
```cpp

    const auto Future = Gs2->Grade->Namespace(
        "namespace-0001" // namespaceName
    )->GradeModel(
        "grade-0001" // gradeName
    )->Model();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }
```


### Get an individual grade (Status)

Get the current grade value for a specific `propertyId` (character, equipment, etc.).



**Unity**
```csharp

    var item = await gs2.Grade.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Status(
        gradeName: "grade-0001",
        propertyId: "property-0001"
    ).ModelAsync();
```
**Unreal Engine**
```cpp

    const auto Future = Gs2->Grade->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Status(
        "grade-0001", // gradeName
        "property-0001" // propertyId
    )->Model();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }
```


### Synchronize rank caps in GS2-Experience

When a grade changes, the rank cap reflection in GS2-Experience is performed automatically.
However, when the grade model is updated and the rank cap value for a specific grade is changed, you can apply the updated rank cap by explicitly calling the following synchronization API.



**Unity**
```csharp

    var result = await gs2.Grade.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Status(
        gradeName: "grade-0001",
        propertyId: "property-0001"
    ).ApplyRankCapAsync(
    );
    var item = await result.ModelAsync();

```
**Unreal Engine**
```cpp

    const auto Future = Gs2->Grade->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Status(
        "grade-0001", // gradeName
        "property-0001" // propertyId
    )->ApplyRankCap(
    );
    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 Future2->GetTask().Error();
    }
    const auto Result = Future2->GetTask().Result();
```


## Detailed Reference

[GS2-Grade API Reference](../../api_reference/grade)



