玩家物品库

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

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

词汇表

物品库

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

消耗品

消耗品是物品库中可累积或重复购买的物品,且使用后在物品库中的数量会相应减少。用户可以补充这类物品的数量。例如:攻击敌人的弹药、金币等。

非消耗品

非消耗品是物品库中只能获得或购买一次的物品。非消耗品不会从物品库中消失。例如:某个地点的访问权限、状态、订阅等。

游戏内商店

游戏内商店是管理游戏内购买的一项服务。它为开发者提供了通过微交易增加游戏营收的机会,开发者可在其中销售各种各样的自定义虚拟物品。

运行机制

玩家物品库通过用户ID来管理用户的物品库。用户的身份识别通过艾克索拉登录管理器实现。如果已配置自己的身份识别系统,可为客户端API方法使用Pay Station Access Token

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

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

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

1 - 获取物品库

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

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

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

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

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

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

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

4 - 向用户发放奖励

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

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

5 - 物品库同步

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

集成过程

要启用玩家物品库,需要:

  1. 注册艾克索拉发布商帐户
  2. 在发布商帐户中创建并配置一个项目。
  3. 在发布商帐户中设置虚拟物品虚拟货币模块。
  4. 通过APIUnity/虚幻引擎SDK连接游戏内商店。
  5. 设置用户认证。
  6. 实现物品库管理的方法。

创建项目

  1. 前往项目,然后单击创建项目按钮。
  2. 添加项目名称,然后单击创建

  1. 前往项目设置 > 集成设置,然后连接商店API方法。

  1. 商店连接到项目。

设置虚拟物品

  1. 连接虚拟物品模块。

  1. 创建物品组(可选)。

  1. 创建物品。

设置虚拟货币

  1. 连接虚拟货币模块。

  1. 创建虚拟货币。

认证设置

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

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

  1. 如果连接了艾克索拉登录管理器,可使用艾克索拉登录管理器JWT来认证请求。
  2. 如果设置了自己的身份识别系统,可使用Pay Station Access Token来认证请求。

Note: 如果使用自己的用户识别方法,请向基于服务器的发放和撤回物品方法传入user.id。该ID必须与Pay Station Access Token中使用的user.id相同。

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

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

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

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

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

通过Pay Station Access Token认证

认证过程:

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

返回的access_token用作授权令牌,用于在商店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
  • 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方法将指定物品添加到用户物品库或将虚拟货币添加到用户余额。

请求

<?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);

响应

{
    "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方法将指定物品从用户物品库中撤回或将虚拟货币从用户余额中撤回。

请求

<?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);

响应

{
    "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方法将用户在第三方平台购买的物品添加到用户物品库。

请求

<?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);

响应

{
    "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方法获取购买后添加到用户物品库的物品列表。

请求

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);

响应

{
  "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方法获取当前用户虚拟货币余额的信息。

请求

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);

响应

{
  "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 itemAPI方法消耗掉用户物品库中的相应物品。

请求

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方法检查物品列表。

商店API管理错误:

代码 描述 操作
0401-1101 服务不可用(地址错误、连接问题)。 检查status.xsolla.com上的系统状态;联系艾克索拉客户支持团队或您的帐户经理。
0401-1102 请求项数据错误。 检查API规范
0401-1016 某个请求参数的编码错误。 检查请求内容。
0401-1019 不支持该方法。 检查请求。可在响应中找到支持的方法。
0401-1020 使用商户的密钥散列时发生授权错误。 检查API密钥。