スタンプシート

Game Server Services のトランザクションシステムである スタンプシート の解説

GS2 には各サービス間を連携させる仕組みとして、 スタンプシート というシステムがあります。 ほかのサービスが受け持つリソース操作等を実行の条件とする処理の実装を可能にします。

スタンプシートは、企業における稟議書のような仕組みです。 各サービスが承認をするとスタンプ(署名)を押し、すべてが揃った状態であれば処理を実行できます。

承認に必要なリソースの消費等の処理を、スタンプタスクとよびます。 各サービスで要求されたスタンプタスクの実行が可能であれば、スタンプが得られます。 スタンプシートにすべてのスタンプが押された状態で、そのスタンプシートの処理と 各スタンプタスクの処理が実行できます。

たとえば、クエストのクリア報酬の処理であれば、 スタミナ値の減少 や 受注可能な回数の減少を スタンプタスクで設定し、 その消費に対する報酬として 経験値を入手、クエストクリアフラグの書き換え という 処理を最後にまとめて実行する、といった流れになります。

クエストのマスターデータの例

{
  "version": "2019-05-14",
  "groups": [
    {
      "name": "main",
      "metadata": "Main Scenario",
      "quests": [
        {
          "name": "chapter-0001",
          "metadata": "Chapter 1. The beginning of the adventure",
          "contents": [
            {
              "metadata": "NORMAL",
              "completeAcquireActions": [
                {
                  "action": "Gs2Money:DepositByUserId",
                  "request": "{\"namespaceName\": \"money-0001\", \"userId\": \"#{userId}\", \"slot\": \"#{slot}\", \"price\": \"0\", \"count\": \"10\"}"
                },
                {
                  "action": "Gs2Money:DepositByUserId",
                  "request": "{\"namespaceName\": \"money-0001\", \"userId\": \"#{userId}\", \"slot\": \"#{slot}\", \"price\": \"0\", \"count\": \"10\"}"
                }
              ],
              "weight": 95
            },
            {
              "metadata": "RARE",
              "completeAcquireActions": [
                {
                  "action": "Gs2Money:DepositByUserId",
                  "request": "{\"namespaceName\": \"money-0001\", \"userId\": \"#{userId}\", \"slot\": \"#{slot}\", \"price\": \"0\", \"count\": \"20\"}"
                },
                {
                  "action": "Gs2Money:DepositByUserId",
                  "request": "{\"namespaceName\": \"money-0001\", \"userId\": \"#{userId}\", \"slot\": \"#{slot}\", \"price\": \"0\", \"count\": \"10\"}"
                }
              ],
              "weight": 5
            }
          ],
          "consumeActions": [
            {
              "action": "Gs2Stamina:ConsumeStaminaByUserId",
              "request": "{\"namespaceName\": \"stamina-0001\", \"staminaName\": \"main\", \"userId\": \"#{userId}\", \"consumeValue\": \"10\"}"
            }
          ],
          "failedAcquireActions": [
            {
              "action": "Gs2Stamina:RecoverStaminaByUserId",
              "request": "{\"namespaceName\": \"stamina-0001\", \"staminaName\": \"main\", \"userId\": \"#{userId}\", \"recoverValue\": \"10\"}"
            }
          ],
          "premiseQuestNames": [],
          "questModelId": "grn:gs2:ap-northeast-1:sampleproject:quest:quest-0001:group:main:quest:chapter-0001"
        }

      ],
      "questGroupModelId": "grn:gs2:ap-northeast-1:sampleproject:quest:quest-0001:group:main"
    }
  ]
}

スタンプシートの変数

スタンプシートやスタンプタスクは GS2 のそれぞれのサービスへリクエストを発行します。

スタンプタスクは、スタンプシートの対象サービスのAPIの実行に必要な条件を満たすためのタスクで、 ユーザーのリソースを減らすアクション(consumeActions)を設定できます。

スタンプシートには完了時にユーザーのリソースを増やすアクション(completeAcquireActions)、 失敗時にユーザーのリソースを戻すアクション(failedAcquireActions)を設定できます。

スタンプシート発行時のパラメータ設定

各サービスへのリクエストには、どのユーザーのリソースを操作するかという情報が必要ですが、 ゲーム内ストアやクエストのマスターデータに、あらかじめユーザーIDを静的に指定することができません。 そのためスタンプシートのリクエストに変数を埋め込むことができます。

マスターデータのアクションのリクエストに、#{userId} というプレースホルダー文字列を設定すると、 その部分はスタンプシートを発行する際にスタンプシートの発行をおこなったユーザーのユーザーIDに置換されます。

Config

スタンプシートの発行リクエストには Config(EzConfig)というパラメータが渡せるようになっています。 Config(EzConfig) はキー・バリュー形式で、渡したパラメータで #{Config で指定したキー値} のプレースホルダー文字列を置換することができます。

スタンプタスクの実行結果 アクションのリクエストの記述内容に、例として ${Gs2Money:WithdrawByUserId.price} というプレースホルダー文字列を設定すると、 その部分はスタンプタスクの実行結果に置換され、変数として利用することができます。 例に示したケースでは、実行したタスクのうち Gs2Money:WithdrawByUserId の実行結果を参照し、戻り値の price を値として使用します。 子要素を参照する場合は ${Gs2Money:WithdrawByUserId.item.paid} のようにドットで繋ぐことで参照できます。

同一のアクションがスタンプタスクとして複数登録されている場合に採用される値は不定です。

ウォレットに残高を加算するスタンプシートの例

{
  "name": "currency-120-jpy",
  "metadata": "price: 120 currencyCount: 50",
  "consumeActions": [
    {
      "action": "Gs2Money:RecordReceipt",
      "request": "{\"namespaceName\": \"money-0001\", \"contentsId\": \"io.gs2.sample.currency120\", \"userId\": \"#{userId}\", \"receipt\": \"#{receipt}\"}"
    }
  ],
  "acquireActions": [
    {
      "action": "Gs2Money:DepositByUserId",
      "request": "{\"namespaceName\": \"money-0001\", \"userId\": \"#{userId}\", \"slot\": \"#{slot}\", \"price\": 120, \"count\": 50}"
    }
  ]
}

Unity から Config の値を設定する例


    var result = await gs2.Showcase.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Showcase(
        showcaseName: "showcase-0001"
    ).BuyAsync(
        displayItemId: "display-item-0001",
        quantity: 1,
        config: new [] {
           new EzConfig
           {
               Key = "slot",
               Value = Slot.ToString(),
           },
           new EzConfig
           {
               Key = "receipt",
               Value = receipt,
           },
       }
    );