玩家物品库

物品库是用户可在游戏中购买、赚取或消耗的物品集合。

艾克索拉玩家物品库允许合作伙伴:

  • 同步用户在所有平台上的购买物和高级奖励。
  • 使用艾克索拉API向用户物品库中发放或撤回物品和货币。

运行机制

玩家物品库通过用户ID来管理用户的物品库。用户的身份识别通过艾克索拉登录管理器实现。如果已配置自己的身份识别系统,可为客户端API方法使用支付中心访问令牌

要使用玩家物品库API方法,必须配置认证

用户物品库可包含消耗品和非消耗品。消耗品可通过游戏客户端多次购买并添加到物品库或从物品库中删除。非消耗品只能被购买并添加到物品库一次。取消购买和从物品库中删除的操作通过游戏服务器执行。

上图显示了玩家物品库操作的以下原则:

    获取物品库

  1. 游戏通过用户的艾克索拉登录管理器帐户或您自己的身份识别方法来识别用户。
  2. 您的应用程序(客户端)调用Get user’s inventory方法获取购买物及用户奖励列表,调用Get user’s virtual balance方法获取虚拟货币的余额。
  3. 艾克索拉物品库服务器向客户端返回该用户当前拥有的购买物、奖励或余额。

    通过艾克索拉商店进行游戏内购买

  1. 游戏通过用户的艾克索拉登录管理器帐户或您自己的身份识别方法来识别用户。
  2. 用户通过艾克索拉商店进行购买。
  3. 该内容购买事件发送到艾克索拉物品库服务器,然后购买物即自动发放到用户的物品库。

Note
此算法完全在艾克索拉侧实现,无需游戏服务器侧的操作。

    通过第三方发布平台(Steam、PlayStation等)进行应用内购买

  1. 用户使用平台帐户登录游戏。
  2. 用户通过平台的支付系统进行购买。
  3. 游戏服务器调用Grant items by purchase to users方法通过发送用户在游戏内的唯一ID在艾克索拉物品库上发放购买物。
  4. 艾克索拉物品库服务器将购买物添加到指定ID的用户物品库。

Note
在游戏的服务器侧,必须确保多个发布平台用户帐户之间的同步。

    向用户发放奖励

  1. 游戏通过用户的艾克索拉登录管理器帐户或您自己的身份识别方法来识别用户。
  2. 您的服务器调用Grant items to users方法并发送用户在游戏内的唯一ID来发放奖励。
  3. 艾克索拉物品库服务器向指定ID的用户物品库添加奖励。

Note
在游戏的服务器侧,必须确保多个发布平台用户帐户之间的同步。

    物品库同步

  1. 游戏通过用户的艾克索拉登录管理器帐户、您自己的身份识别方法或第三方平台帐户来识别用户。
  2. 游戏服务器同步用户帐户(如需要)。
  3. 游戏客户端调用Get user’s inventory方法来检查哪些游戏内购买物可用并发送唯一用户ID。
  4. 艾克索拉物品库服务器返回指定ID的可用物品列表。

集成过程

要启用玩家物品库:

  1. 设置艾克索拉游戏内商店
  2. 设置认证方式。
  3. 实现物品库管理的方法。

认证设置

为确保安全性,发放和撤回方法由游戏服务器调用。必须实现基本认证才能使用这些方法。

获取用户物品库和消耗品由游戏客户端通过SDK或API调用。以下是几种可用的认证方式:

  1. 如果连接了艾克索拉登录管理器,可使用艾克索拉登录管理器JWT来认证请求。
  2. 如果设置了自己的身份识别系统,可使用支付中心访问令牌来认证请求。

Note
如果使用自己的用户识别方法,请向基于服务器的发放和撤回物品方法传入user.id。该ID必须与支付中心访问令牌中使用的user.id相同。

通过艾克索拉登录管理器进行认证

  1. 按照说明设置发布商帐户项目。
  2. 通过JSON Web令牌或OAuth 2.0协议实现授权方法的调用。

如果用户数据保存在艾克索拉数据存储中,请实现以下方法的调用:

如果用户数据保存在PlayFab数据存储中,请使用PlayFab高级诀窍。

如果用户数据保存在您自己一侧,请使用自定义存储高级诀窍。

通过支付中心访问令牌认证

认证过程:

  1. 应用程序(客户端)发送认证请求至您的服务器。
  2. 您的服务器发送商户ID和API密钥至艾克索拉服务器并请求access_token
  3. 艾克索拉服务器发送access_token至您的服务器。
  4. 您的服务器发送access_token至客户端。

返回的access_token用作授权令牌,用于在Commerce API中和生成商店界面时进行认证。

设置基本认证

向艾克索拉API物品库发放撤回物品的服务器命令使用基本认证。所有发送到API的请求必须包含Authorization: Basic <your_authorization_basic_key>头,其中<your_authorization_basic_key>是按照Base64标准加密的的merchant_id:api_key对。

艾克索拉发布商帐户中找到project_idapi_key参数的值:

  • project_id:项目设置 > Webhook
  • api_key:公司设置 > API密钥

Copy
Full screen
Small screen
http
  • http
  • curl
  • php
  • C#
  • python
  • ruby
  • java
  • js
POST https://store.xsolla.com/api/v2/project/{project_id}/inventory/reward
Headers:
  Authorization: Basic <your_authorization_basic_key>
curl --request POST \
--url 'https://store.xsolla.com/api/v2/project/{project_id}/inventory/reward' \
--header 'authorization: Basic <your_authorization_basic_key>'
<?php

// if you use Xsolla SDK for PHP
use Xsolla\SDK\API\XsollaClient;
$xsollaClient = XsollaClient::factory(array(
    'project_id' => PROJECT_ID,
    'api_key' => API_KEY
));
$eventsList = $client->ListEvents(array());

// if you don’t use Xsolla SDK for PHP
$client = new http\Client;
$request = new http\Client\Request;

$request->setRequestUrl('https://store.xsolla.com/api/v2/project/{project_id}/inventory/rewards');
$request->setRequestMethod('POST');
$request->setHeaders(array(
  'authorization' => 'Basic <your_authorization_basic_key>'
));

$client->enqueue($request)->send();
$response = $client->getResponse();

echo $response->getBody();
var client = new RestClient("https://store.xsolla.com/api/v2/project/{project_id}/inventory/reward");
var request = new RestRequest(Method.POST);
request.AddHeader("authorization", "Basic <your_authorization_basic_key>");
IRestResponse response = client.Execute(request);
import http.client

conn = http.client.HTTPSConnection("api.xsolla.com")

headers = { 'authorization': "Basic <your_authorization_basic_key>" }

conn.request("POST", "https://store.xsolla.com/api/v2/project/{project_id}/inventory/reward", headers=headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
require 'uri'
require 'net/http'

url = URI("https://store.xsolla.com/api/v2/project/{project_id}/inventory/reward
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Get.new(url)
request["authorization"] = 'Basic <your_authorization_basic_key>'

response = http.request(request)
puts response.read_body
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://store.xsolla.com/api/v2/project/{project_id}/inventory/reward")
  .post()
  .addHeader("authorization", "Basic <your_authorization_basic_key>")
  .build();

Response response = client.newCall(request).execute();
var data = null;

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://store.xsolla.com/api/v2/project/{project_id}/inventory/reward");
xhr.setRequestHeader("authorization", "Basic <your_authorization_basic_key>");

xhr.send(data);

物品库管理方法

物品库管理方法包括以下几组方法:

Grant items to users

实现Grant items to users API方法将指定物品添加到用户物品库或将虚拟货币添加到用户余额。

请求:

Copy
Full screen
Small screen
<?php
$uri = 'https://store.xsolla.com/api/v2/project/44056/inventory/reward';
$body = '
    [
        {
          "user": {
            "id": "0125760a-6810-11e9-84c0-42010aa80029"
          },
          "comment": "Quest completed",
          "platform": "xsolla",
          "items": [
            {
              "sku": "boots_1",
              "quantity": 5
            },
            {
              "sku": "crystal_pack_1",
              "quantity": 3
            }
          ]
        },
        {
          "user": {
            "id": "a7d10a4e-3f68-43cc-a6b2-893d2c68fd14"
          },
          "comment": "Daily reward",
          "platform": "xsolla",
          "items": [
            {
              "sku": "helmet_1",
              "quantity": 2
            },
            {
              "sku": "minigun_1",
              "quantity": 3
            }
          ]
        }
    ]';

$auth = base64_encode('44056:your_merchant_api_key');

$headers = [
    'Authorization: Basic ' . $auth,
    'Content-type: application/json'
];

$request = curl_init($uri);
curl_setopt($request, CURLOPT_RETURNTRANSFER, true);
curl_setopt($request, CURLOPT_POSTFIELDS, $body);
curl_setopt($request, CURLOPT_HTTPHEADER, $headers);

$response = curl_exec($request);

响应:

Copy
Full screen
Small screen
{
    "count": 2,
    "operations": [
        {
            "user_id": "0125760a-6810-11e9-84c0-42010aa80029",
            "platform": "xsolla",
            "comment": "Quest completed",
            "items": [
                {
                    "sku": "boots_1",
                    "quantity": 5
                },
                {
                    "sku": "crystal_pack_1",
                    "quantity": 3
                }
            ]
        },
        {
            "user_id": "a7d10a4e-3f68-43cc-a6b2-893d2c68fd14",
            "platform": "xsolla",
            "comment": "Daily reward",
            "items": [
                {
                    "sku": "helmet_1",
                    "quantity": 2
                },
                {
                    "sku": "minigun_1",
                    "quantity": 3
                }
            ]
        }
  ]
}

Revoke inventory items

实现Revoke Inventory Items API方法将指定物品从用户物品库中撤回或将虚拟货币从用户余额中撤回。

请求:

Copy
Full screen
Small screen
<?php
$uri = 'https://store.xsolla.com/api/v2/project/44056/inventory/revoke';
$body = '
    [
        {
          "user": {
            "id": "0125760a-6810-11e9-84c0-42010aa80029"
          },
          "comment": "Remove from inventory",        
          "items": [
            {
              "sku": "boots_1",
              "quantity": 5
            },
            {
              "sku": "crystal_pack_1",
              "quantity": 3
            }
          ]
        },
        {
          "user": {
            "id": "a7d10a4e-3f68-43cc-a6b2-893d2c68fd14"
          },
          "comment": "Cheater",
          "items": [
            {
              "sku": "helmet_1",
              "quantity": 2
            },
            {
              "sku": "minigun_1",
              "quantity": 3
            }
          ]
        }
    ]';

$auth = base64_encode('44056:your_merchant_api_key');

$headers = [
    'Authorization: Basic ' . $auth,
    'Content-type: application/json'
];

$request = curl_init($uri);
curl_setopt($request, CURLOPT_RETURNTRANSFER, true);
curl_setopt($request, CURLOPT_POSTFIELDS, $body);
curl_setopt($request, CURLOPT_HTTPHEADER, $headers);

$response = curl_exec($request);
print_r($response);

响应:

Copy
Full screen
Small screen
{
    "count": 2,
    "operations": [
        {
            "user_id": "0125760a-6810-11e9-84c0-42010aa80029",
            "platform": "xsolla",
            "comment": "Remove from inventory",
            "items": [
                {
                    "sku": "boots_1",
                    "quantity": 5
                },
                {
                    "sku": "crystal_pack_1",
                    "quantity": 3
                }
            ]
        },
        {
            "user_id": "a7d10a4e-3f68-43cc-a6b2-893d2c68fd14",
            "platform": "xsolla",
            "comment": "Cheater",
            "items": [
                {
                    "sku": "helmet_1",
                    "quantity": 2
                },
                {
                    "sku": "minigun_1",
                    "quantity": 3
                }
            ]
        }
    ]
}

Grant items by purchase to users

实现Grant items by purchase to users API方法将用户在第三方平台购买的物品添加到用户物品库。

请求:

Copy
Full screen
Small screen
<?php
$uri = 'https://store.xsolla.com/api/v2/project/44056/inventory/purchase';
$body = '
    [
        {
          "user": {
            "id": "0125760a-6810-11e9-84c0-42010aa80029"
          },
          "comment": "Purchase in App Store",
          "platform": "app_store_ios",
          "purchase": {
            "amount": "3.99",
            "currency": "USD",
            "external_purchase_id": "MS6TGW7023",
            "external_purchase_date": "2020-01-25T05:00:00+05:00"
          },        
          "items": [
            {
              "sku": "boots_1",
              "quantity": 5
            },
            {
              "sku": "crystal_pack_1",
              "quantity": 3
            }
          ]
        },
        {
          "user": {
            "id": "a7d10a4e-3f68-43cc-a6b2-893d2c68fd14"
          },
          "comment": "Purchase in Google Play",
          "platform": "google_play",
          "purchase": {
            "amount": "1.99",
            "currency": "EUR",
            "external_purchase_id": "GPA.3357-9348-5932-89841",
            "external_purchase_date": "2020-02-14T05:00:00+05:00"
          },
          "items": [
            {
              "sku": "helmet_1",
              "quantity": 2
            },
            {
              "sku": "minigun_1",
              "quantity": 3
            }
          ]
        }
    ]';

$auth = base64_encode('44056:your_merchant_api_key');

$headers = [
    'Authorization: Basic ' . $auth,
    'Content-type: application/json'
];

$request = curl_init($uri);
curl_setopt($request, CURLOPT_RETURNTRANSFER, true);
curl_setopt($request, CURLOPT_POSTFIELDS, $body);
curl_setopt($request, CURLOPT_HTTPHEADER, $headers);

$response = curl_exec($request);
print_r($response);

响应:

Copy
Full screen
Small screen
{
    "count": 2,
  "operations": [
    {
      "user_id": "0125760a-6810-11e9-84c0-42010aa80029",
      "platform": "app_store_ios",
      "comment": "Purchase in App Store",
      "items": [
        {
          "sku": "boots_1",
          "quantity": 5
        },
        {
          "sku": "crystal_pack_1",
          "quantity": 3
        }
      ],
      "order_id": 4125,
      "external_purchase_id": "MS6TGW7023",
      "external_purchase_date": "2020-01-25T05:00:00+05:00",
      "amount": "3.99",
      "currency": "USD"
    },
    {
      "user_id": "a7d10a4e-3f68-43cc-a6b2-893d2c68fd14",
      "platform": "google_play",
      "comment": "Purchase in Google Play",
      "items": [
        {
            "sku": "helmet_1",
          "quantity": 2
        },
        {
            "sku": "minigun_1",
          "quantity": 3
        }
      ],
      "order_id": 4126,
      "external_purchase_id": "GPA.3357-9348-5932-89841",
      "external_purchase_date": "2020-02-14T05:00:00+05:00",
      "amount": "1.99",
      "currency": "EUR"
    }
  ]
}

Get user’s inventory

实现Get user’s inventory API方法获取购买后添加到用户物品库的物品列表。

请求:

Copy
Full screen
Small screen
var data = null;

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://store.xsolla.com/api/v2/project/44056/user/inventory/items");
xhr.setRequestHeader("authorization", "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE5NjIyMzQwNDgsImlzcyI6Imh0dHBzOi8vbG9naW4ueHNvbGxhLmNvbSIsImlhdCI6MTU2MjE0NzY0OCwidXNlcm5hbWUiOiJ4c29sbGEiLCJ4c29sbGFfbG9naW5fYWNjZXNzX2tleSI6IjA2SWF2ZHpDeEVHbm5aMTlpLUc5TmMxVWFfTWFZOXhTR3ZEVEY4OFE3RnMiLCJzdWIiOiJkMzQyZGFkMi05ZDU5LTExZTktYTM4NC00MjAxMGFhODAwM2YiLCJlbWFpbCI6InN1cHBvcnRAeHNvbGxhLmNvbSIsInR5cGUiOiJ4c29sbGFfbG9naW4iLCJ4c29sbGFfbG9naW5fcHJvamVjdF9pZCI6ImU2ZGZhYWM2LTc4YTgtMTFlOS05MjQ0LTQyMDEwYWE4MDAwNCIsInB1Ymxpc2hlcl9pZCI6MTU5MjR9.GCrW42OguZbLZTaoixCZgAeNLGH2xCeJHxl8u8Xn2aI");

xhr.send(data);

响应:

Copy
Full screen
Small screen
{
  "items": [
    {
      "description": "Conquer your foes with vindication using the Basic Blaster! ",
      "image_url": "https://cdn.xsolla.net/img/misc/images/0c59a7698d4f66c1008b27ee752089b7.png",
      "instance_id": null,
      "long_description": "Conquer your foes with vindication using the Basic Blaster! Conquer your foes with vindication using the Basic Blaster! ",
      "name": "Xsolla Basic Blaster 1",
      "quantity": 22,
      "sku": "gun_1",
      "type": "virtual_good"
    },
    {
      "description": "Protect your noggin' with style",
      "image_url": "https://cdn.xsolla.net/img/misc/images/b79342cdf24f0f8557b63c87e8326e62.png",
      "instance_id": null,
      "long_description": "merchant_virtual_items_virtual_item_long_description_159429",
      "name": "Xsolla Helmet",
      "quantity": 18,
      "sku": "helmet_1",
      "type": "virtual_good"
    }
  ]
}

Get user’s virtual balance

实现Get user’s virtual balance API方法获取当前用户虚拟货币余额的信息。

请求:

Copy
Full screen
Small screen
var data = null;
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function () {
    if (this.readyState === this.DONE) {
        console.log(this.responseText);
    }
});
xhr.open("GET", "https://store.xsolla.com/api/v2/project/44056/user/virtual_currency_balance");
xhr.setRequestHeader("authorization", "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE5NjIyMzQwNDgsImlzcyI6Imh0dHBzOi8vbG9naW4ueHNvbGxhLmNvbSIsImlhdCI6MTU2MjE0NzY0OCwidXNlcm5hbWUiOiJ4c29sbGEiLCJ4c29sbGFfbG9naW5fYWNjZXNzX2tleSI6IjA2SWF2ZHpDeEVHbm5aMTlpLUc5TmMxVWFfTWFZOXhTR3ZEVEY4OFE3RnMiLCJzdWIiOiJkMzQyZGFkMi05ZDU5LTExZTktYTM4NC00MjAxMGFhODAwM2YiLCJlbWFpbCI6InN1cHBvcnRAeHNvbGxhLmNvbSIsInR5cGUiOiJ4c29sbGFfbG9naW4iLCJ4c29sbGFfbG9naW5fcHJvamVjdF9pZCI6ImU2ZGZhYWM2LTc4YTgtMTFlOS05MjQ0LTQyMDEwYWE4MDAwNCIsInB1Ymxpc2hlcl9pZCI6MTU5MjR9.GCrW42OguZbLZTaoixCZgAeNLGH2xCeJHxl8u8Xn2aI");
xhr.send(data);

响应:

Copy
Full screen
Small screen
{
  "items": [
    {
      "amount": 683,
      "description": "Main in-game currency",
      "image_url": "https://cdn3.xsolla.com/img/misc/images/91df536af4616519f639664854c13d75.png",
      "name": "Crystals",
      "sku": "crystal",
      "type": "virtual_currency"
    },
    {
      "amount": 450,
      "description": "Money for in-store purchases",
      "image_url": "https://cdn3.xsolla.com/img/misc/images/fda67a3feedaa706b4e4ae05a9edd6ab.png",
      "name": "Gold",
      "sku": "gold",
      "type": "virtual_currency"
    }
  ]
}

Consume Item

实现Consume item API方法消耗掉用户物品库中的相应物品。

请求:

Copy
Full screen
Small screen
let data = JSON.stringify({
  "sku": "gun_1",
  "quantity": 1,
  "instance_id": null
});

let xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://store.xsolla.com/api/v2/project/44056/user/inventory/item/consume");
xhr.setRequestHeader("content-type", "application/json");
xhr.setRequestHeader("authorization", "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE5NjIyMzQwNDgsImlzcyI6Imh0dHBzOi8vbG9naW4ueHNvbGxhLmNvbSIsImlhdCI6MTU2MjE0NzY0OCwidXNlcm5hbWUiOiJ4c29sbGEiLCJ4c29sbGFfbG9naW5fYWNjZXNzX2tleSI6IjA2SWF2ZHpDeEVHbm5aMTlpLUc5TmMxVWFfTWFZOXhTR3ZEVEY4OFE3RnMiLCJzdWIiOiJkMzQyZGFkMi05ZDU5LTExZTktYTM4NC00MjAxMGFhODAwM2YiLCJlbWFpbCI6InN1cHBvcnRAeHNvbGxhLmNvbSIsInR5cGUiOiJ4c29sbGFfbG9naW4iLCJ4c29sbGFfbG9naW5fcHJvamVjdF9pZCI6ImU2ZGZhYWM2LTc4YTgtMTFlOS05MjQ0LTQyMDEwYWE4MDAwNCIsInB1Ymxpc2hlcl9pZCI6MTU5MjR9.GCrW42OguZbLZTaoixCZgAeNLGH2xCeJHxl8u8Xn2aI");

xhr.send(data);

错误列表

用户或用户物品库管理错误:

代码描述操作
0401-5002添加商品至用户物品库的数据错误。必须指定item_id,且instance_idquantity的值必须为null
0401-5003未指定用户ID。检查请求中是否包含了用户ID。
0401-5004未在用户物品库中找到该物品。确保该物品在物品库中。可通过Get user's inventory方法检查物品库状态。
0401-5006虚拟货币不足,无法购买。-
0401-5007尝试消耗非消耗品。-
0401-5008找不到用户。-
0401-5009发放第三方平台购买物时未传入purchase-

物品管理错误:

代码描述操作
0401-4001找不到符合条件的物品。通过调用Get user's inventory方法检查物品列表。

Commerce API管理错误:

代码描述操作
0401-1101服务不可用(地址错误、连接问题)。检查status.xsolla.com上的系统状态;联系艾克索拉客户支持团队或您的帐户经理。
0401-1102请求项数据错误。检查API规范
0401-1016某个请求参数的编码错误。检查请求内容。
0401-1019不支持该方法。检查请求。可在响应中找到支持的方法。
0401-1020使用商户的密钥散列时发生授权错误。检查API密钥。
本文对您的有帮助吗?
谢谢!
我们还有其他可改进之处吗? 留言
非常抱歉
请说明为何本文没有帮助到您。 留言
感谢您的反馈!
我们会查看您的留言并运用它改进用户体验。
为此页面评分
为此页面评分
我们还有其他可改进之处吗?

不想回答

感谢您的反馈!
上次更新时间: 2021年6月25日

发现了错别字或其他内容错误? 请选择文本,然后按Ctrl+Enter。

报告问题
我们非常重视内容质量。您的反馈将帮助我们做得更好。
请留下邮箱以便我们后续跟进
感谢您的反馈!