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

# GS2-Exchange トランザクションアクション

検証/消費/入手の各トランザクションアクションの仕様




## アクションの組み合わせと同時実行

すべてのサービスに共通する前提は [トランザクションアクションの組み合わせ]() にまとめています。先にそちらを読んでください。この節の残りは GS2-Exchange 固有の内容です。

GS2-Exchange のトランザクションアクションは、交換待ちを介するものと一度に交換するものの 2 つに分かれます。交換待ちはネームスペース・ユーザー・交換待ち名の組で決まります。

操作 | 同じ行を重ねたとき | 入れ子越し | 別の対象になる境界 | 直列実行モード有効時
--- | --- | --- | --- | ---
交換待ちの作成<br>`CreateAwaitByUserId` | 同じ交換レートなら統合され、数が合算される | 失敗する | ネームスペース・ユーザー・交換レート | 成立する。ただし統合はされない。交換待ちの名前はサーバーが採番するため、入れ子から届いた作成は 1 件目の数に足されるのではなく、2 件目の交換待ちとして増える
交換待ちのスキップ<br>`SkipByUserId` | `skipType` が同じなら統合される。違うと発行時にエラー | 失敗する | ネームスペース・ユーザー・交換待ち | 入れ子越しでも成立する。2 件目のスキップは 1 件目が残した状態の交換待ちに適用される。並べて書いた `skipType` 違いを弾く挙動は、発行時に働くので変わらない
交換待ちの結果の受け取り<br>`AcquireForceByUserId` | 1 件に統合される | 失敗する | ネームスペース・ユーザー・交換待ち | 引き続き失敗する。1 件にまとめられなくなるため、2 件目は 1 件目がすでに消した交換待ちに対して実行され、見つからない (404) として弾かれる
交換待ちの破棄<br>`DeleteAwaitByUserId` | 1 件に統合される | 失敗する | ネームスペース・ユーザー・交換待ち | 結果の受け取りと同じ理由で引き続き失敗する。2 件目の破棄はすでに無くなった交換待ちに対して実行され、見つからない (404) として弾かれる
一度に交換<br>`ExchangeByUserId` `IncrementalExchangeByUserId` | 同じレートなら統合され、数が合算される | 交換待ちを触らない | ネームスペース・ユーザー・交換レート | 変わらない。交換待ちを触らない

スキップの合成のしかたは `skipType` によって変わります。分の指定どうしは合算され、総時間に対する割合どうしは加算され、残り時間に対する割合どうしは順に適用したのと同じ結果になるよう合成されます。完了指定どうしは 1 件にまとめられます。

**`skipType` が違うスキップは同じ交換待ちに並べられません。** 先に指定したほうの `skipType` が全体に適用されると意味が変わってしまうため、発行時にエラーになります。

結果の受け取りと破棄はどちらも交換待ちを消し、作成は交換待ちを増やすので、これらのうち 2 つを 1 つのトランザクションに入れると衝突します。スキップしてから結果を受け取る流れも 1 つのトランザクションではできません。結果の受け取りはトランザクション開始時点の状態を基準に判定されるため、スキップがまだ見えていないからです。**直列実行モード（`enableSequentialExecution` または `TransactionSettingV2`）を有効にしても、後者は解消しません。アクションは名前の順に実行され、`AcquireForceByUserId` は `SkipByUserId` より必ず先に実行されるため、結果の受け取りはスキップを見られないままです。後から実行されるスキップは、すでに無くなった交換待ちを見つけられずに失敗します。解消するのは破棄の後に作成を続ける場合です。破棄は消費アクションであり、入手アクションである作成より必ず先に実行され、作成は破棄された交換待ちに書き込むのではなく自分の交換待ちを新しく作るためです。**

`ExchangeByUserId` と `IncrementalExchangeByUserId` は交換待ちをまったく触りません。何を消費して何を入手するかを算出し、それらを自身のトランザクションとして発行するため、それらが属するサービスの制限がそのまま当てはまり、下記も当てはまります。増分交換は交換のたびにレートも上げますが、これも発行するものの一部です。

### 入れ子になったトランザクションに注意

内側から作成された交換待ちと、外側から受け取られたり破棄されたりした交換待ちが衝突して、トランザクションが失敗します。**直列実行モードを有効にすると、外側が破棄する場合は解消します。内側のトランザクションは外側と同じ直列実行の区間で実行されるようになり、破棄は消費アクションとして必ず先に実行されるため、後に続く作成は破棄された交換待ちと衝突する代わりに自分の交換待ちを新しく作ります。外側が結果を受け取る場合は解消しません。受け取りと作成はどちらも入手アクションで、`AcquireForceByUserId` が先に実行されるため、引き続き失敗します。**

### 制限を回避したい場合

交換待ちの作成・スキップ・結果の受け取り、および一度に交換は入手アクション、交換待ちの破棄は消費アクションです。入手アクションどうしの衝突は `acquireActionUseJobQueue` を有効にすれば解消できます。破棄との同居は `enableAtomicCommit` を無効にすれば解消し、このとき破棄は入手アクションより先に実行されます。

### 同時実行とリトライ

同じ交換待ちを複数のリクエストが同時に触った場合、後から確定した側がコンフリクト (409) になります。リトライすると最新の状態で判定し直されるので、交換待ちがまだ残っていれば成功し、すでに受け取られたり破棄されたりしていればエラーが返ります。

交換待ち名が違えば別の対象なので、違う交換待ちへのリクエストどうしはコンフリクトしません。

---



## Consume Action

消費アクション

### Gs2Exchange:DeleteAwaitByUserId

ユーザーIDを指定して交換待機を削除<br>

指定されたユーザーの交換待機レコードを削除します。<br>
保留中の交換がキャンセルされ、まだ取得されていない報酬は放棄されます。

**数量指定可能なアクション：いいえ**

**反転可能なアクション：いいえ**

|  | 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128文字 | ネームスペース名<br>ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。 |
| userId | string |  | ✓|  |  ~ 128文字 | ユーザーID<br>`#{userId}` と設定することでログイン中のユーザーIDに置換されます。 |
| awaitName | string |  | ✓| UUID |  ~ 36文字 | 交換待機の名前<br>交換待機の一意な名前を保持します。<br>名前は UUID（Universally Unique Identifier）フォーマットで自動的に生成され、交換待機を識別するために使用されます。 |
| timeOffsetToken | string |  | |  |  ~ 1024文字 | タイムオフセットトークン |




**JSON**
```json
{
    "action": "Gs2Exchange:DeleteAwaitByUserId",
    "request": {
        "namespaceName": "[string]ネームスペース名",
        "userId": "[string]ユーザーID",
        "awaitName": "[string]交換待機の名前",
        "timeOffsetToken": "[string]タイムオフセットトークン"
    }
}
```

**YAML**
```yaml

action: Gs2Exchange:DeleteAwaitByUserId
request:
  namespaceName: "[string]ネームスペース名"
  userId: "[string]ユーザーID"
  awaitName: "[string]交換待機の名前"
  timeOffsetToken: "[string]タイムオフセットトークン"
```

**GS2-Script**
```lua

transaction.service("exchange").consume.delete_await_by_user_id({
    namespaceName="[string]ネームスペース名",
    userId="[string]ユーザーID",
    awaitName="[string]交換待機の名前",
    timeOffsetToken="[string]タイムオフセットトークン",
})
```


---

## Acquire Action

入手アクション

### Gs2Exchange:ExchangeByUserId

ユーザーIDを指定して交換を実行<br>

指定されたユーザーに対して、指定された交換レートモデルに基づいてリソース交換を実行します。<br>
レートモデルのタイミングタイプを検証します：`immediate` タイミングの場合はネームスペースで直接交換が有効である必要があり、`await` タイミングの場合は待機交換が有効である必要があります。<br>
レートモデルで定義された消費・検証・入手アクションを指定回数分実行するトランザクションが発行されます。

**数量指定可能なアクション：はい**

**反転可能なアクション：いいえ**

|  | 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128文字 | ネームスペース名<br>ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。 |
| rateName | string |  | ✓|  |  ~ 128文字 | 交換レートモデル名<br>交換レートモデルの種類固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。 |
| userId | string |  | ✓|  |  ~ 128文字 | ユーザーID<br>`#{userId}` と設定することでログイン中のユーザーIDに置換されます。 |
| count | int |  | ✓|  | 1 ~ 1073741821 | 交換回数 |
| config | [List&lt;Config&gt;](../sdk/#config) |  | | [] | 0 ~ 32 items | トランザクションの変数に適用する設定値 |
| timeOffsetToken | string |  | |  |  ~ 1024文字 | タイムオフセットトークン |




**JSON**
```json
{
    "action": "Gs2Exchange:ExchangeByUserId",
    "request": {
        "namespaceName": "[string]ネームスペース名",
        "rateName": "[string]交換レートモデル名",
        "userId": "[string]ユーザーID",
        "count": "[int]交換回数",
        "config": [
            {
                "key": "[string]名前",
                "value": "[string]値"
            }
        ],
        "timeOffsetToken": "[string]タイムオフセットトークン"
    }
}
```

**YAML**
```yaml

action: Gs2Exchange:ExchangeByUserId
request:
  namespaceName: "[string]ネームスペース名"
  rateName: "[string]交換レートモデル名"
  userId: "[string]ユーザーID"
  count: "[int]交換回数"
  config: 
    - key: "[string]名前"
      value: "[string]値"
  timeOffsetToken: "[string]タイムオフセットトークン"
```

**GS2-Script**
```lua

transaction.service("exchange").acquire.exchange_by_user_id({
    namespaceName="[string]ネームスペース名",
    rateName="[string]交換レートモデル名",
    userId="[string]ユーザーID",
    count="[int]交換回数",
    config={
        {
            key="[string]名前",
            value="[string]値"
        }
    },
    timeOffsetToken="[string]タイムオフセットトークン",
})
```


---

### Gs2Exchange:IncrementalExchangeByUserId

ユーザーIDを指定してコスト上昇型交換を実行<br>

指定されたユーザーに対して、指定されたコスト上昇型交換レートモデルに基づいて、実行回数に応じてコストが段階的に上昇するリソース交換を実行します。<br>
消費コストはモデルの計算タイプ（線形計算式またはGS2-Script）と現在の交換回数に基づいて計算されます。<br>
消費・入手アクションを実行するトランザクションが発行されます。

**数量指定可能なアクション：はい**

**反転可能なアクション：いいえ**

|  | 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128文字 | ネームスペース名<br>ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。 |
| rateName | string |  | ✓|  |  ~ 128文字 | コスト上昇型交換レートモデルの名前<br>コスト上昇型交換レートモデルの種類固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。 |
| userId | string |  | ✓|  |  ~ 128文字 | ユーザーID<br>`#{userId}` と設定することでログイン中のユーザーIDに置換されます。 |
| count | int |  | ✓|  | 1 ~ 1073741821 | 交換回数 |
| config | [List&lt;Config&gt;](../sdk/#config) |  | | [] | 0 ~ 32 items | トランザクションの変数に適用する設定値 |
| timeOffsetToken | string |  | |  |  ~ 1024文字 | タイムオフセットトークン |




**JSON**
```json
{
    "action": "Gs2Exchange:IncrementalExchangeByUserId",
    "request": {
        "namespaceName": "[string]ネームスペース名",
        "rateName": "[string]コスト上昇型交換レートモデルの名前",
        "userId": "[string]ユーザーID",
        "count": "[int]交換回数",
        "config": [
            {
                "key": "[string]名前",
                "value": "[string]値"
            }
        ],
        "timeOffsetToken": "[string]タイムオフセットトークン"
    }
}
```

**YAML**
```yaml

action: Gs2Exchange:IncrementalExchangeByUserId
request:
  namespaceName: "[string]ネームスペース名"
  rateName: "[string]コスト上昇型交換レートモデルの名前"
  userId: "[string]ユーザーID"
  count: "[int]交換回数"
  config: 
    - key: "[string]名前"
      value: "[string]値"
  timeOffsetToken: "[string]タイムオフセットトークン"
```

**GS2-Script**
```lua

transaction.service("exchange").acquire.incremental_exchange_by_user_id({
    namespaceName="[string]ネームスペース名",
    rateName="[string]コスト上昇型交換レートモデルの名前",
    userId="[string]ユーザーID",
    count="[int]交換回数",
    config={
        {
            key="[string]名前",
            value="[string]値"
        }
    },
    timeOffsetToken="[string]タイムオフセットトークン",
})
```


---

### Gs2Exchange:CreateAwaitByUserId

ユーザーIDを指定して交換待機を作成<br>

時間待機型交換の新しい交換待機レコードを作成します。<br>
指定されたレートモデルのタイミングタイプは `await` である必要があり、そうでない場合はリクエストが拒否されます。<br>
待機はスキップ秒数ゼロで開始され、レートモデルで定義されたロック時間が報酬取得までのユーザーの待機時間を決定します。<br>
作成時にデフォルトの設定値を指定でき、取得時に提供される設定値とマージされます。

**数量指定可能なアクション：はい**

**反転可能なアクション：いいえ**

|  | 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128文字 | ネームスペース名<br>ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。 |
| userId | string |  | ✓|  |  ~ 128文字 | ユーザーID<br>`#{userId}` と設定することでログイン中のユーザーIDに置換されます。 |
| rateName | string |  | ✓|  |  ~ 128文字 | 交換レートモデル名<br>交換レートモデルの種類固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。 |
| count | int |  | | 1 | 1 ~ 10000 | 交換数<br>この交換を実行する回数です。複数回の交換を1つの待機にまとめることができ、消費されるコストと受け取る報酬の両方が乗算されます。 |
| config | [List&lt;Config&gt;](../sdk/#config) |  | | [] | 0 ~ 32 items | 報酬取得時に適用するデフォルト設定値 |
| timeOffsetToken | string |  | |  |  ~ 1024文字 | タイムオフセットトークン |




**JSON**
```json
{
    "action": "Gs2Exchange:CreateAwaitByUserId",
    "request": {
        "namespaceName": "[string]ネームスペース名",
        "userId": "[string]ユーザーID",
        "rateName": "[string]交換レートモデル名",
        "count": "[int]交換数",
        "config": [
            {
                "key": "[string]名前",
                "value": "[string]値"
            }
        ],
        "timeOffsetToken": "[string]タイムオフセットトークン"
    }
}
```

**YAML**
```yaml

action: Gs2Exchange:CreateAwaitByUserId
request:
  namespaceName: "[string]ネームスペース名"
  userId: "[string]ユーザーID"
  rateName: "[string]交換レートモデル名"
  count: "[int]交換数"
  config: 
    - key: "[string]名前"
      value: "[string]値"
  timeOffsetToken: "[string]タイムオフセットトークン"
```

**GS2-Script**
```lua

transaction.service("exchange").acquire.create_await_by_user_id({
    namespaceName="[string]ネームスペース名",
    userId="[string]ユーザーID",
    rateName="[string]交換レートモデル名",
    count="[int]交換数",
    config={
        {
            key="[string]名前",
            value="[string]値"
        }
    },
    timeOffsetToken="[string]タイムオフセットトークン",
})
```


---

### Gs2Exchange:AcquireForceByUserId

交換待機の報酬を、待機時間の判定を行わず強制取得<br>

ロック時間が経過しているかどうかに関係なく、交換待機の報酬を強制的に取得します。<br>
通常の待機時間チェックをバイパスし、即時に報酬を取得できます。<br>
提供された設定値は待機作成時に設定されたデフォルト設定値とマージされます。<br>
レートモデルで定義された入手アクションを実行するトランザクションが発行されます。

**数量指定可能なアクション：いいえ**

**反転可能なアクション：いいえ**

|  | 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128文字 | ネームスペース名<br>ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。 |
| userId | string |  | ✓|  |  ~ 128文字 | ユーザーID<br>`#{userId}` と設定することでログイン中のユーザーIDに置換されます。 |
| awaitName | string |  | ✓| UUID |  ~ 36文字 | 交換待機の名前<br>交換待機の一意な名前を保持します。<br>名前は UUID（Universally Unique Identifier）フォーマットで自動的に生成され、交換待機を識別するために使用されます。 |
| config | [List&lt;Config&gt;](../sdk/#config) |  | | [] | 0 ~ 32 items | トランザクションの変数に適用する設定値 |
| timeOffsetToken | string |  | |  |  ~ 1024文字 | タイムオフセットトークン |




**JSON**
```json
{
    "action": "Gs2Exchange:AcquireForceByUserId",
    "request": {
        "namespaceName": "[string]ネームスペース名",
        "userId": "[string]ユーザーID",
        "awaitName": "[string]交換待機の名前",
        "config": [
            {
                "key": "[string]名前",
                "value": "[string]値"
            }
        ],
        "timeOffsetToken": "[string]タイムオフセットトークン"
    }
}
```

**YAML**
```yaml

action: Gs2Exchange:AcquireForceByUserId
request:
  namespaceName: "[string]ネームスペース名"
  userId: "[string]ユーザーID"
  awaitName: "[string]交換待機の名前"
  config: 
    - key: "[string]名前"
      value: "[string]値"
  timeOffsetToken: "[string]タイムオフセットトークン"
```

**GS2-Script**
```lua

transaction.service("exchange").acquire.acquire_force_by_user_id({
    namespaceName="[string]ネームスペース名",
    userId="[string]ユーザーID",
    awaitName="[string]交換待機の名前",
    config={
        {
            key="[string]名前",
            value="[string]値"
        }
    },
    timeOffsetToken="[string]タイムオフセットトークン",
})
```


---

### Gs2Exchange:SkipByUserId

ユーザーIDを指定して交換待機をスキップ<br>

交換待機の待機時間を加速またはスキップします。<br>
4つのスキップタイプをサポートしています：`complete` は残りの待機時間を全てスキップし、`minutes` は指定した分数をスキップ秒数に加算し、`totalRate` は全体のロック時間の割合をスキップし、`remainRate` は残りの待機時間の割合をスキップします。<br>
スキップ秒数は合計ロック時間が上限となり、それを超えることはできません。

**数量指定可能なアクション：はい**

**反転可能なアクション：いいえ**

|  | 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128文字 | ネームスペース名<br>ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。 |
| userId | string |  | ✓|  |  ~ 128文字 | ユーザーID<br>`#{userId}` と設定することでログイン中のユーザーIDに置換されます。 |
| awaitName | string |  | ✓| UUID |  ~ 36文字 | 交換待機の名前<br>交換待機の一意な名前を保持します。<br>名前は UUID（Universally Unique Identifier）フォーマットで自動的に生成され、交換待機を識別するために使用されます。 |
| skipType | 文字列列挙型<br>enum {<br>"complete",<br>"minutes",<br>"totalRate",<br>"remainRate"<br>}<br> |  | | "complete" |  | スキップ方法complete: 完全にスキップ / minutes: 時間を指定してスキップ(分) / totalRate: 全体の待機時間の割合を指定してスキップ / remainRate: 残りの待機時間の割合を指定してスキップ /  |
| minutes | int | {skipType} == "minutes" | |  | 0 ~ 2147483646 | スキップする分数<br>※ skipType が "minutes" であれば有効 |
| rate | float | {skipType} == "totalRate" or {skipType} == "remainRate" | |  | 0 ~ 1 | スキップする待機時間の割合 |
| timeOffsetToken | string |  | |  |  ~ 1024文字 | タイムオフセットトークン |




**JSON**
```json
{
    "action": "Gs2Exchange:SkipByUserId",
    "request": {
        "namespaceName": "[string]ネームスペース名",
        "userId": "[string]ユーザーID",
        "awaitName": "[string]交換待機の名前",
        "skipType": "[string]スキップ方法",
        "minutes": "[int]スキップする分数",
        "rate": "[float]スキップする待機時間の割合",
        "timeOffsetToken": "[string]タイムオフセットトークン"
    }
}
```

**YAML**
```yaml

action: Gs2Exchange:SkipByUserId
request:
  namespaceName: "[string]ネームスペース名"
  userId: "[string]ユーザーID"
  awaitName: "[string]交換待機の名前"
  skipType: "[string]スキップ方法"
  minutes: "[int]スキップする分数"
  rate: "[float]スキップする待機時間の割合"
  timeOffsetToken: "[string]タイムオフセットトークン"
```

**GS2-Script**
```lua

transaction.service("exchange").acquire.skip_by_user_id({
    namespaceName="[string]ネームスペース名",
    userId="[string]ユーザーID",
    awaitName="[string]交換待機の名前",
    skipType="[string]スキップ方法",
    minutes="[int]スキップする分数",
    rate="[float]スキップする待機時間の割合",
    timeOffsetToken="[string]タイムオフセットトークン",
})
```


---



