Store #

The Store system is for creating store catalogs. Each entry describes what is paid and what is received for both stackable and instanced items. Stores can be individually managed, enabling special events like limited-time content sales.

Stores are defined entirely as content data and require no plugin code. The rules for exchange are:

  • Paying currencies or materials (defined as instanced or stackable items) are withdrawn from available stacks automatically.
  • Instanced items are created by invoking the Instanced Item Plugin, which supplies the unique attributes of granted items.
  • Sell-back features are easy to implement, allowing you to trade instanced items for currencies or materials.

To learn more about store purchases, as well as how to access store content catalogs in Portal, visit the Content Data Concepts page.

Store Plugin #

The Inventory service verifies if a player meets the cost requirements of a purchase. Additional custom logic for store requests can be defined within the Store Plugin.

Add new conditions #

The StorePlugin.meetsRequirements function is used to create custom requirements when checking a store purchase.

ParameterDescription
storeIdID of the store the attempted purchase is being made from
storeEntryfull store entry of the attempted purchase
inventoryDatafull inventory of the purchaser

Return the result #

The plugin returns true when the purchase meets the conditions set in the meetsRequirements function, else the Inventory service returns an error message:

PragmaException(
      PragmaError.InventoryService_RequirementsNotMetError,
      "Requirements not met for player '$playerId' to purchase '${constraints.storeId}:${constraints.storeEntry.id}'."
)

Quick Guides #

Create a store and purchase items #

Once you’ve defined items you can add them to a store.

Create a store #

Define a store in 5-ext/content/src/Stores.json:

[
  {
    "id": "freeVendor",
    "name": "Free Vendor",
    "storeEntries": [
      {
        "id": "starterBundle",
        "receivedQuantityByCatalogId": {
          "coins": 1000,
          "diamonds": 100
        }
      }
    ]
  }
]

Purchase an item from the store #

Send storePurchaseV4 to purchase a starterBundle from the store:

{
  "requestId": 1,
  "type": "InventoryRpc.StorePurchaseV4Request",
  "payload": {
    "data": {
      "ext": {},
      "storeId": "freeVendor",
      "storeEntryId": "starterBundle",
      "amount": 1
    }
  }
}

Sample response contains the recieved items:

{
  "sequenceNumber": 0,
  "response": {
    "requestId": 1,
    "type": "InventoryRpc.StorePurchaseV4Response",
    "payload": {
      "segment": {
        "stackables": [
          {
            "catalogId": "coins",
            "instanceId": "87bb142b-341f-4437-b16c-5f95843c883a",
            "amount": "1000"
          },
          {
            "catalogId": "diamonds",
            "instanceId": "7be19678-39b4-4dbd-958a-5c4ebdf2a5d1",
            "amount": "100"
          }
        ],
        "instanced": [],
        "removedStackables": [],
        "removedInstanced": [],
        "previousVersion": "1",
        "version": "2"
      },
      "delta": {
        "stackables": [
          {
            "catalogId": "coins",
            "tags": [],
            "amountChanged": "1000"
          },
          {
            "catalogId": "diamonds",
            "tags": [],
            "amountChanged": "100"
          }
        ],
        "instanced": []
      }
    }
  }
}

Check all store details #

Send GetCatalogOperatorV1 and define the catalog you want to view (in this case, we’re looking at stores).

{
  "requestId": 1,
  "type": "InventoryRpc.GetCatalogOperatorV1Request",
  "payload": {
    "catalog": "Stores"
  }
}

Sample response with data about all stores:

{
  "sequenceNumber": 0,
  "response": {
    "requestId": 1,
    "type": "InventoryRpc.GetCatalogOperatorV1Response",
    "payload": {
      "name": "",
      "stores": {
        "stores": [
          {
            "id": "freeVendor",
            "name": "Free Vendor",
            "storeEntries": [
              {
                "id": "starterBundle",
                "receivedQuantityByCatalogId": {
                  "coins": "1000",
                  "diamonds": "100"
                },
                "costByCatalogId": {},
                "tags": []
              }
            ]
          }
        ]
      }
    }
  }
}