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

# GS2-Inventory

所持品管理機能




プレイヤーが所持しているアイテムの情報を管理します。

アイテムの管理には3種類の方式があります。
1つ目はスタンダードインベントリ、2つ目はシンプルインベントリ、3つ目は巨大インベントリです。

スタンダードインベントリは以下のような機能を有します
- インベントリの容量制限
- 同一アイテムを一定数量ごとに複数のスタックに分割
- アイテムに有効期限を設定

シンプルインベントリはスタンダードインベントリが持つような機能は持ちません
しかし、その代わりに複数のアイテムの増減処理をまとめて行うことができます。
シンプルインベントリをうまく利用することで、APIのコール数を削減することが可能です。

巨大インベントリはシンプルインベントリと同じくスタンダードインベントリが持つような機能は持ちません。
シンプルインベントリのように複数のアイテムの増減処理をまとめて行うこともできません。
その代わり、アイテムの所持数量を 64bit 整数の範囲を超えて保持することができます。

## スタンダードインベントリ

### インベントリ

プレイヤーが所持するカバンに相当するエンティティです。
カバンには容量が設定可能で、その容量を超えるアイテムを格納することはできません。

### アイテム

アイテムは所持品の種類を定義します。
アイテムには、スタック可能な最大数量を指定できます。

たとえば、ポーションというアイテムの種類が存在し、最大99個スタック可能とした場合
インベントリの容量の消費量1で99個までポーションを所持することが可能となります。

さらに、アイテムには複数スタックを所持可能かを指定できます。
複数スタック所持を可能に設定すると、100個以上のポーションを所持できるようになり、
例えば、150個のポーションを所持している場合は 99 個スタックされたポーションと、51個スタックされたポーションの2つのエントリが作成され、
インベントリの容量が 2 消費されます。

複数スタック所持を不可能の設定した場合、99個を超えるポーションを所持することはできなくなり
それ以上ポーションを入手しても破棄されます。

#### アイテムの有効期限

アイテムには有効期限を設定できます。
有効期限を設定したアイテムは、設定時刻をすぎると自動的にインベントリから消去されます。

有効期限の設定されたアイテムは有効期限ごとに異なるスタックが作成され、それぞれインベントリの容量を消費します。
そのため、複数スタックを所持できないアイテムに有効期限をつけて配布すると、最初に入手した有効期限のアイテム（あるは最初に入手した有効期限のないアイテム）以外は破棄されます。

アイテムを使用する際には明示的に有効期限（アイテムセット名）を指定しなければ、有効期限の近いアイテムから優先して消費されます。

#### アイテムセット

1種類のアイテムを複数スタック管理できるよう、アイテムの種類をまとめたアイテムセットというエンティティが存在します。
このエンティティはスタックごとにアイテムの種類を表すIDとは別に、スタック固有のIDをもちます。
このスタック固有のIDを使用すれば、「ポーション x 99」と「ポーション x 51」のそれぞれのスタックを明確に区別することができます。

#### 参照元 (Reference Of)

アイテムセットには「参照元」情報を付与することができます。これは、特定のアイテムが他のエンティティ（例：キャラクターの装備、パーティへの編成、マーケットへの出品など）から使用されていることを示すために利用されます。
参照元が1つ以上設定されているアイテムセットは、たとえ所持数量が十分であっても消費したり削除したりすることができなくなります。これにより、装備中のアイテムを誤って売却したり、強化素材にしてしまうといったミスをシステムレベルで防ぐことができます。

ポーションを消費する際に、ポーションを示すアイテムIDに加えてスタック固有のIDを指定することで、どちらのスタックから消費するかを明示することができます。
スタック固有のIDは省略可能で、省略した場合は最も少ないスタックから優先して使用されます。

## シンプルインベントリ

### シンプルインベントリ

プレイヤーが所持するカバンに相当するエンティティです。
複数のシンプルアイテムを束ねる存在で、シンプルインベントリでは特にプロパティを持ちません。

### シンプルアイテム

アイテムは所持品の種類を定義します。

## 巨大インベントリ

### 巨大インベントリ

プレイヤーが所持するカバンに相当するエンティティです。
複数の巨大アイテムを束ねる存在で、巨大インベントリでは特にプロパティを持ちません。

### 巨大アイテム

アイテムは所持品の種類を定義します。

## スクリプトトリガー

ネームスペースに `acquireScript`・`overflowScript`・`consumeScript`・`simpleItemAcquireScript`・`simpleItemConsumeScript`・`bigItemAcquireScript`・`bigItemConsumeScript` を設定すると、アイテムの入手・消費処理の前後でカスタムスクリプトを呼び出せます。スクリプトは同期・非同期の実行方式を選択でき、非同期では GS2-Script や Amazon EventBridge を介した外部処理にも対応します。

設定できる主なイベントトリガーとスクリプト設定名は以下の通りです。

- `acquireScript`（完了通知: `acquireDone`）: スタンダードアイテム入手の前後
- `overflowScript`（完了通知: `overflowDone`）: 容量超過時の前後
- `consumeScript`（完了通知: `consumeDone`）: スタンダードアイテム消費の前後
- `simpleItemAcquireScript`（完了通知: `simpleItemAcquireDone`）: シンプルアイテム入手の前後
- `simpleItemConsumeScript`（完了通知: `simpleItemConsumeDone`）: シンプルアイテム消費の前後
- `bigItemAcquireScript`（完了通知: `bigItemAcquireDone`）: 巨大アイテム入手の前後
- `bigItemConsumeScript`（完了通知: `bigItemConsumeDone`）: 巨大アイテム消費の前後

## マスターデータ運用
マスターデータを登録することでマイクロサービスで利用可能なデータや振る舞いを設定できます。

マスターデータの種類には以下があります。

- `InventoryModel`: インベントリ容量や種類を定義
- `ItemModel`: スタック上限や有効期限を定義

マスターデータの登録はマネージメントコンソールから登録する他、GitHubからデータを反映したり、GS2-Deployを使ってCIから登録するようなワークフローを組むことが可能です。

## バフによる補正

GS2-Buff と連携すると、インベントリの `currentInventoryMaxCapacity` や `AcquireItemSetByUserId`・`ConsumeItemSetByUserId`・`AcquireSimpleItemsByUserId`・`ConsumeSimpleItemsByUserId`・`AcquireBigItemByUserId`・`ConsumeBigItemByUserId` の入手量・消費量をバフで補正できます。イベントやキャンペーンに応じて容量や入手・消費量を柔軟に調整できます。

## トランザクションアクション

GS2-Inventory では以下のトランザクションアクションを提供しています。

### スタンダードインベントリ
- 検証アクション: インベントリ最大容量の検証、アイテム所持数量の検証、参照元の検証
- 消費アクション: アイテムセットの消費
- 入手アクション: キャパシティの加算・設定、アイテムセットの入手（グレード指定含む）、参照元の追加・削除

「参照元の追加・削除」を入手アクションとして利用することで、装備の変更や編成の更新をトランザクション内で安全に行い、同時にアイテムの保護状態を切り替えることが可能になります。

### シンプルインベントリ
- 検証アクション: シンプルアイテム所持数量の検証
- 消費アクション: シンプルアイテムの消費
- 入手アクション: シンプルアイテムの入手・設定

### 巨大インベントリ
- 検証アクション: 巨大アイテム所持数量の検証
- 消費アクション: 巨大アイテムの消費
- 入手アクション: 巨大アイテムの入手・設定

## 実装例

### アイテムを入手

アイテムの入手はゲームエンジン用の SDK では処理できません。

### アイテムを消費

このAPIでアイテムの消費処理を行うことは推奨していません。

GS2-Exchange / GS2-Showcase / GS2-Quest といったサービスを通してアイテムの消費を行う代わりに 何らかの処理を実行することを推奨します。

#### スタンダード



**Unity**
```csharp

    var result = await gs2.Inventory.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Inventory(
        inventoryName: "inventory-0001"
    ).ItemSet(
        itemName: "item-0001",
        itemSetName: null
    ).ConsumeAsync(
        consumeCount: 1L
    );
```
**Unreal Engine**
```cpp

    const auto Future = Gs2->Inventory->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->Inventory(
        "inventory-0001" // inventoryName
    )->ItemSet(
        "item-0001", // itemName
        nullptr // itemSetName
    )->Consume(
        1L
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError()) return false;
```


#### シンプル



**Unity**
```csharp

    var result = await gs2.Inventory.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).SimpleInventory(
        inventoryName: "inventory-0001"
    ).SimpleItem(
        itemName: "item-0001"
    ).ConsumeAsync(
        consumeCount: 1L
    );
```
**Unreal Engine**
```cpp

    const auto Future = Gs2->Inventory->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->SimpleInventory(
        "inventory-0001" // inventoryName
    )->SimpleItem(
        "item-0001" // itemName
    )->Consume(
        1L
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError()) return false;
```


#### 巨大



**Unity**
```csharp

    var result = await gs2.Inventory.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).BigInventory(
        inventoryName: "inventory-0001"
    ).BigItem(
        itemName: "item-0001"
    ).ConsumeAsync(
        consumeCount: "1"
    );
```
**Unreal Engine**
```cpp

    const auto Future = Gs2->Inventory->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->BigInventory(
        "inventory-0001" // inventoryName
    )->BigItem(
        "item-0001" // itemName
    )->Consume(
        "1"
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError()) return false;
```


### インベントリの情報を取得

#### スタンダード



**Unity**
```csharp

    var item = await gs2.Inventory.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Inventory(
        inventoryName: "inventory-0001"
    ).ModelAsync();
```
**Unreal Engine**
```cpp

    const auto item = Gs2->Inventory->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->Inventory(
        "inventory-0001" // inventoryName
    )->Model();
```


#### シンプル

シンプルインベントリにこの機能はありません

#### 巨大

巨大インベントリにこの機能はありません

### インベントリ内のアイテム一覧を取得

#### スタンダード



**Unity**
```csharp

    var items = await gs2.Inventory.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Inventory(
        inventoryName: "item"
    ).ItemSetsAsync(
    ).ToListAsync();
```
**Unreal Engine**
```cpp

    const auto It = Gs2->Inventory->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->Inventory(
        "item" // inventoryName
    )->ItemSets(
    );
    TArray<Gs2::UE5::Inventory::Model::FEzItemSetPtr> Result;
    for (auto Item : *It)
    {
        if (Item.IsError())
        {
            return false;
        }
        Result.Add(Item.Current());
    }
```


#### シンプル



**Unity**
```csharp

    var items = await gs2.Inventory.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).SimpleInventory(
        inventoryName: "item"
    ).SimpleItemsAsync(
    ).ToListAsync();
```
**Unreal Engine**
```cpp

    const auto It = Gs2->Inventory->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->SimpleInventory(
        "item" // inventoryName
    )->SimpleItems(
    );
    TArray<Gs2::UE5::Inventory::Model::FEzSimpleItemPtr> Result;
    for (auto Item : *It)
    {
        if (Item.IsError())
        {
            return false;
        }
        Result.Add(Item.Current());
    }
```


#### 巨大



**Unity**
```csharp

    var items = await gs2.Inventory.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).BigInventory(
        inventoryName: "item"
    ).BigItemsAsync(
    ).ToListAsync();
```
**Unreal Engine**
```cpp

    const auto It = Gs2->Inventory->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->BigInventory(
        "item" // inventoryName
    )->BigItems(
    );
    TArray<Gs2::UE5::Inventory::Model::FEzBigItemPtr> Result;
    for (auto Item : *It)
    {
        if (Item.IsError())
        {
            return false;
        }
        Result.Add(Item.Current());
    }
```


### インベントリの容量を拡大

インベントリの容量を拡大はゲームエンジン用の SDK では処理できません。

### 所持証明署名の取得

GS2 内の他のマイクロサービスと連携する際に、本当に GS2-Inventory でアイテムを所有していることを保証したデータを求められることがあります。

たとえば、GS2-Inventory でキャラクターの所持状態を管理しており、GS2-Formation でパーティの編成状態を管理するとします。
GS2-Formation にパーティメンバーを設定する際に「character-0001」というキャラクターを設定するよう APIリクエストを出すことになりますが
GS2-Formation は所持証明署名をとあわせて「character-0001」を指定するよう要求します。

これによって、GS2-Formation は裏で GS2-Inventory と通信して、本当に所持しているキャラクターかを判断する必要がなくなります。

#### スタンダード



**Unity**
```csharp

    var result = await gs2.Inventory.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Inventory(
        inventoryName: "inventory-0001"
    ).ItemSet(
        itemName: "item-0001",
        itemSetName: "item-set-0001"
    ).GetItemWithSignatureAsync(
        keyId: "grn:gs2:{region}:{yourOwnerId}:key:namespace-0001:key:key-0001"
    );
    var item = await result.ModelAsync();
    var body = result.Body;
    var signature = result.Signature;
```
**Unreal Engine**
```cpp

    const auto Future = Gs2->Inventory->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->Inventory(
        "inventory-0001" // inventoryName
    )->ItemSet(
        "item-0001", // itemName
        "item-set-0001" // itemSetName
    )->GetItemWithSignature(
        "key-0001"
    );
    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();
    const auto Body = Result->Body;
    const auto Signature = Result->Signature;
```


#### シンプル



**Unity**
```csharp

    var result = await gs2.Inventory.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).SimpleInventory(
        inventoryName: "inventory-0001"
    ).SimpleItem(
        itemName: "item-0001"
    ).GetSimpleItemWithSignatureAsync(
        keyId: "grn:gs2:{region}:{yourOwnerId}:key:namespace-0001:key:key-0001"
    );
    var item = await result.ModelAsync();
    var body = result.Body;
    var signature = result.Signature;
```
**Unreal Engine**
```cpp

    const auto Future = Gs2->Inventory->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->SimpleInventory(
        "inventory-0001" // inventoryName
    )->SimpleItem(
        "item-0001" // itemName
    )->GetSimpleItemWithSignature(
        "key-0001"
    );
    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();
    const auto Body = Result->Body;
    const auto Signature = Result->Signature;
```


#### 巨大

巨大インベントリにはこの機能はありません。

## 詳細なリファレンス

[GS2-Inventory API リファレンス](../../api_reference/inventory)



