> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 制作游戏 第 3 部分 - 编码

> PlayFab Economy V2 制作游戏教程第 3 部分：编写调用 Economy V2 API 的 C# 代码，以管理库存、配方和制作物品。

# 第 3 部分 - 编码 + 示例

现在你已准备好环境并熟悉 Game Manager，我们可以开始编码游戏了。

## 先决条件

1. [第 1 部分 - 环境设置](/services/playfab/economy-monetization/economy-v2/tutorials/craftingGame/crafting-game-environment)
2. [第 2 部分 - 使用 Game Manager](/services/playfab/economy-monetization/economy-v2/tutorials/craftingGame/crafting-game-game-manager)

## 步骤 1 - 配置环境设置

我们建议你在开始编码后做的第一件事是配置你的环境设置。这样你就可以放心地知道你所做的每个调用都将链接到你的 Title 并使用你的特定 Developer Secret Key。

要完成此步骤，你可以在代码中的任何位置（希望是你容易找到的地方）指定 TitleId 和 DeveloperSecretKey 变量并为它们分配值。

通过添加两行单独的代码来做到这一点，如下所示：

```csharp theme={null}
PlayFabSettings.staticSettings.TitleId = "{Your Title ID}";
PlayFabSettings.staticSettings.DeveloperSecretKey = "{Your Developer Secret Key}";
```

## 步骤 2 - 进行身份验证

一旦你设置了环境、在你的项目中安装并配置了 PlayFab NuGet 包，并创建了你的 Studio 和 Title，我们就可以开始编码我们的身份验证了。

<Note>
  用户可以通过多种方式进行身份验证。在此示例中，我们将使用 **LoginWithCustomId** 方法。还有其他进行身份验证的方法，包括平台特定的方法。有关更多信息，请访问 [Login Basics](/services/playfab/identity/player-identity/login/login-basics-best-practices)。
</Note>

接下来是使用 C# 编写的示例代码，其中我们使用 **LoginWithCustomID** 对用户进行身份验证，这被归类为匿名登录。在调用 API 进行身份验证之前，我们必须首先声明一个全局变量，用于存储作为登录过程一部分生成的 **EntityKey**。

**EntityKey** 用于对 API 进行任何类型的调用，并且是将每个请求和响应链接到已登录用户的关键。

全局 EntityKey 变量的声明如下：

```csharp theme={null}
private static PlayFab.ClientModels.EntityKey entityKey;
```

***

然后，让用户进行身份验证的逻辑是：

### C# SDK

```csharp theme={null}
var request = new LoginWithCustomIDRequest { CustomId = username };
var loginTask = PlayFabClientAPI.LoginWithCustomIDAsync(request);
entityKey = loginTask.Result.Result.EntityToken.Entity;
```

### API

```json theme={null}
{
  "CustomId": "{{Username}}",
  "CreateAccount": false,
  "TitleId": "{{TitleId}}"
}
```

***

以上代码查找链接到你的游戏 title 的任何现有玩家。但如果没有具有匹配用户名的用户，它将失败。要绕过这一点，我们可以向请求正文添加 "CreateAccount = true" 参数。这使得如果没有与用户发送的用户名匹配的用户，PlayFab 会创建一个新的玩家。这将导致代码如下所示：

### C# SDK

```csharp theme={null}
var request = new LoginWithCustomIDRequest { CustomId = username, CreateAccount = true };
var loginTask = PlayFabClientAPI.LoginWithCustomIDAsync(request);
entityKey = loginTask.Result.Result.EntityToken.Entity;
```

### API

```json theme={null}
{
  "CustomId": "{{Username}}",
  "CreateAccount": true,
  "TitleId": "{{TitleId}}"
}
```

***

成功登录后，API 将返回一些数据集，例如 **SessionTicket**、用户的 **PlayFab ID** 和 **EntityToken**。这些可以从 API 的直接响应中看到，详情如下。

```json theme={null}
{
    "code": 200,
    "status": "OK",
    "data": {
        "SessionTicket": "{{SessionTicket}}",
        "PlayFabId": "{{PlayFabID}}",
        "NewlyCreated": false,
        "SettingsForUser": {
            "NeedsAttribution": false,
            "GatherDeviceInfo": true,
            "GatherFocusInfo": true
        },
        "LastLoginTime": "2023-08-01T17:09:54.508Z",
        "EntityToken": {
            "EntityToken": "{{EntityToken}}",
            "TokenExpiration": "2023-08-04T21:20:35Z",
            "Entity": {
                "Id": "{{Player ID}}",
                "Type": "title_player_account",
                "TypeString": "title_player_account"
            }
        },
        "TreatmentAssignment": {
            "Variants": [],
            "Variables": []
        }
    }
}
```

***

一旦你从 API 获得 `"code":200` 返回，或者从上面的 C# 示例中的 `loginTask` 获得信息，你就已通过身份验证，可以继续下一步了！

## 步骤 3 - 设置你的起始库存

现在你已使用有效玩家登录（或创建了新玩家），你的第一步应该是设置该玩家的起始库存。为此，我们将使用 [ExecuteInventoryOperations](https://learn.microsoft.com/en-us/rest/api/playfab/economy/inventory/execute-inventory-operations) API 调用。

<Note>
  ExecuteInventoryOperations 调用允许我们在玩家的库存上执行多个/批量 [InventoryOperations](https://learn.microsoft.com/en-us/rest/api/playfab/economy/inventory/execute-inventory-operations)。支持的操作类型有：- Add - Delete - Purchase - Subtract - Transfer - Update
</Note>

对于此示例，我们将添加与我们游戏对应的物品。它们是三个 Stone 实例、一个 Cream 实例和一个 Gold 实例（这假设你已创建了更多物品，如果没有，请在继续之前这样做）。但我们没有简单使用 **Add** 操作，而是使用 **Purchase** 操作，并且我们以免费的方式购买所需的实例。

<Note>
  要使此步骤正常工作，你必须首先在 Game Manager 中的你的 title 中创建物品。
</Note>

下面的代码片段将向你展示如何在 C# 和使用 PlayFab 的 API 中批量进行这些调用。

### C# SDK

在此 C# 示例中，你可以看到我们首先将 purchasePrice 设置为所有交易的标准值，这是因为我们将使它们的价格都为 0。

任何一个物品都可以有多个价格，因此 `purchasePrice` 变量的类型为 `List<PurchasePriceAmount>`。

你可能会注意到的下一个方面是，请求除了接受 `InventoryOperation` 列表外，还接受一个 Entity。为此，我们将使用我们之前从登录中获得的值创建一个新的 Entity。

最后，每个 `InventoryOperation` 都接受一个 `Purchase` 值，尽管这可能是 **ExecuteInventoryOperations** 调用下可用的每一个（Add、Delete、Purchase、Subtract、Transfer 和 Update）。在本例中，我们使用 `Purchase` 标识符，因此我们需要一个 `new PurchaseInventoryItemsOperation`。

你还需要清楚这是你要购买的物品。你通过使用 `InventoryItemReference` 来做到这一点，它以物品的 ID 作为其唯一参数。

在我们的代码中，我们有一个名为 **SearchItem(\{itemName})** 的方法，但你可以很容易地用表示物品 ID 的字符串替换它。确保将每个物品的名称（或 ID）与相应的数量匹配。

```csharp theme={null}
var purchasePrice = new List<PurchasePriceAmount> { new PurchasePriceAmount { ItemId = freeItemId, Amount = 0 } };
var request = new ExecuteInventoryOperationsRequest 
{ 
    Entity = new PlayFab.EconomyModels.EntityKey { Id = entityKey.Id, Type = entityKey.Type },
    Operations = new List<InventoryOperation> {
        new InventoryOperation
        {
            Purchase = new PurchaseInventoryItemsOperation { 
                Item = new InventoryItemReference {AlternateId = new AlternateId { Type = "FriendlyId", Value = "Stone" } }, 
                Amount = 3, 
                PriceAmounts = purchasePrice
            }
        },
        new InventoryOperation
        {
            Purchase = new PurchaseInventoryItemsOperation {
                Item = new InventoryItemReference { AlternateId = new AlternateId { Type = "FriendlyId", Value = "Gold" } },
                Amount = 1,
                PriceAmounts = purchasePrice
            }
        },``
        new InventoryOperation
        {
            Purchase = new PurchaseInventoryItemsOperation {
                Item = new InventoryItemReference {AlternateId = new AlternateId { Type = "FriendlyId", Value = "Cream" }},
                Amount = 1,
                PriceAmounts = purchasePrice
            }
        }
    }
};
await PlayFabEconomyAPI.ExecuteInventoryOperationsAsync(request);
```

在上述代码中，要在代码中成功使用 `AlternateId` 和 `FriendlyId`，你的物品必须在 Game Manager 中配置这些值。为此，我建议你查看 [第 2 部分 - 使用 Game Manager](/services/playfab/economy-monetization/economy-v2/tutorials/craftingGame/crafting-game-game-manager)，其中我们详细说明了你应遵循的步骤。

### API

使用下面显示的请求正文调用 **ExecuteInventoryOperations** API 端点。将 ID 替换为相应的 ID。请注意 `Operations` 是一个数组，你可以同时用多种类型的操作填充它。

重要的是要理解，对于你进行的每个 API 调用，你必须使用特定于你的活动会话或已登录用户的 **EntityToken** 设置 `X-EntityToken` 头。换句话说，在进行任何 API 调用之前，你应首先 **LoginWithCustomID**（在此示例中）并从返回消息中获取 **EntityToken** 以用作所有 API 调用中的头。

```json theme={null}
{
  "Operations": [
    {
      "Purchase": {
            "Item": {
                "Id": {Stone ID}
            },
            "Amount": 3,
            "PriceAmounts": [
                {
                "ItemId": {Free Item ID},
                "Amount": 0
                }
            ]
        }
    },
    {
      "Purchase": {
            "Item": {
                "Id": {Gold ID}
            },
            "Amount": 1,
            "PriceAmounts": [
                {
                "ItemId": {Free Item ID},
                "Amount": 0
                }
            ]
        }
    },
    {
      "Purchase": {
            "Item": {
                "Id": {Cream ID}
            },
            "Amount": 1,
            "PriceAmounts": [
                {
                "ItemId": {Free Item ID},
                "Amount": 0
                }
            ]
        }
    }
  ]
}
```

下一个 JSON 是在进行上述调用后的成功返回消息示例。你会看到返回三个不同的交易 ID，因为 ID 是按每次修改给出的，尽管这并不意味着有三个单独的交易。相反，它是作为一个单个交易处理的，但具有三个修改，因此我们只对整个交易返回一个成功或失败，无论修改的数量如何。

```json theme={null}
{
    "code": 200,
    "status": "OK",
    "data": {
        "IdempotencyId": {Idempotency ID},
        "TransactionIds": [
            "200",
            "201",
            "202"
        ],
        "ETag": "1/MjAy"
    }
}
```

***

## 步骤 4 - 创建捆绑包

捆绑包允许你将多个物品分组为一个单一物品。有关捆绑包的更多信息，请参见我们的**捆绑包文档**，请访问[此链接](/services/playfab/economy-monetization/economy-v2/catalog/bundles)。

对于我们的示例，我们将使用**捆绑包**对 **Kitchen** 返回的物品进行分组，这有助于我们维护 **Icebox** 物品。冰盒背后的想法是在购买冰淇淋时成为不可消耗的物品，即使冰盒是所需材料之一。

其工作原理的高级概述如下。想象一个玩家，其库存中有一个 Cream 和一个 Icebox。一旦访问 Kitchen 商店，该玩家必须使用这两个物品来购买/制作一个 Ice Cream。鉴于 Icebox 是不可消耗的，预期的功能是产生一个包含一个 Ice Cream 和一个 Icebox 的库存，只消耗了一个 Cream 物品。

我们在幕后处理它的方式是使用一个价格为一个 Icebox 和一个 Cream 的捆绑包，其返回物品是一个 Ice Cream 和一个 Icebox。这意味着玩家库存中的 Icebox 将被消耗，但消耗它的同一交易返回另一个，给玩家一种 Icebox 始终在库存中的印象，而实际上 Icebox 实例不同，但对玩家不可见。

要创建捆绑包，你必须转到 title 的 **Economy** 部分，就像你在创建新物品时所做的那样。会有一个名为 **Bundles** 的选项卡，位于 **Items**、**Currency** 等选项卡旁边。选中后，屏幕右上角会出现一个蓝色按钮，上面写着 **New bundle**。

然后将显示一个类似于创建新物品的表单，主要区别在于，如果你向下滚动，你会发现一个名为 **Items** 的部分。在这里你可以添加你希望捆绑包包含的物品，购买时这些物品将被转移到玩家的库存中。

单击 **Add** 按钮后，会弹出目录中所有物品的可搜索列表，在这里你可以选择要包含在捆绑包中的物品。选定物品并添加后，你可以继续 **Save and publish**，你的捆绑包现在将处于活动状态，并可从商店中选择作为购买价格。

## 步骤 5 - 创建商店

按照我们的制作游戏示例，我们必须让玩家从商店购买物品。将有三个不同的商店（在本例中是地点），**Science Machine**、**Alchemy Engine** 和 **Kitchen**。

我们将重点关注 **Kitchen**。在这里，玩家能够以 **1 Cream** 和 **1 Icebox**（应创建的新物品）的价格购买 **Ice Cream**（应创建的新物品）。之所以选择这个特殊情况，是因为它展示了**捆绑包**如何与商店和交易一起工作。

商店只能通过 [Game Manager](https://developer.playfab.com) 创建，方法是转到左侧导航栏的 **Economy** 部分，然后从不同的选项卡选项中选择 **Stores** 并选择蓝色 **New store** 按钮。

这将显示一个类似于创建新物品时使用的表单，其中唯一必填的字段是 Start Date 和你想赋予商店的 Title。向下滚动，你将

## 步骤 6 - 向商店添加捆绑包

现在你已经创建并发布了你的捆绑包和商店。你可以将捆绑包作为可返回物品添加到你的商店。为此，进入你的商店，向下滚动直到看到 **Items** 标题并选择 **Add** 按钮。

这会显示目录中的物品列表。在搜索栏的左侧，会有一个下拉菜单，其中包含不同类型的对象，例如 **Items**、**UGC Items**、**Bundles** 和 **Subscription**。如果你选择 **Bundles**，它会过滤列表以仅反映捆绑包类型的物品，在这里你应该会看到你之前创建的捆绑包。选择捆绑包名称旁边的 **Add** 按钮，然后选择窗口末尾的 **Add** 按钮，捆绑包将被添加为该特定商店的可能交易物品。

在继续之前还有最后一步，为你的捆绑包设置价格。此价格与任何其他物品定价一样，需要玩家在其库存中拥有所需的任何价格物品，然后才能接受购买。要设置价格，你可以选择捆绑包右侧的 **Add new price** 按钮，从物品列表中选择你希望作为价格的物品。在我们的例子中，我们希望价格是 **1 Icebox** 和 **1 Cream**。

现在你的捆绑包已添加到你的商店并已相应地定价，我们可以继续下一步。

## 步骤 7 - 购买捆绑包

一旦创建了你的捆绑包和商店，并且你的捆绑包已链接到你的商店，你现在可以购买该捆绑包并将结果物品放入你的库存。

要从玩家的角度购买捆绑包，你可以使用 PlayFab API 的 **PurchaseInventoryItems**。它不仅适用于捆绑包，也适用于单个物品。

### API

在以下情况中，我们希望以 **1 Icebox** 和 **1 Cream** 的价格购买 **1 个捆绑包**。我们将使用 **PriceAmount** 的数组属性将多个物品设置为价格。只需确保你给你的捆绑包一个 **FriendlyId**。

```json theme={null}
{
  "Item": {
    "AlternateId": {
        "Type": "FriendlyId",
        "Value": "Ice Cream and Ice Box"
    }
  },
  "Amount": 1,
  "PriceAmounts": [
    {
        "ItemId": "0d2ab329-2fc5-4ae1-9e3c-19f9fc9bbf86",
        "Amount": 1
    },
    {
        "ItemId": "e5276289-f839-4bde-acce-309ea7959e45",
        "Amount": 1
    }
  ],
  "DeleteEmptyStacks": true,
  "StoreId": "f116f1d4-64f9-4be7-9660-a3c1f021100b"
}
```

下一个片段是成功 API 调用后的预期返回。

```json theme={null}
{
    "code": 200,
    "status": "OK",
    "data": {
        "ETag": "1/MjEz",
        "IdempotencyId": "d710508f-defc-4382-bbd1-a3576417b3f7",
        "TransactionIds": [
            "212",
            "213"
        ]
    }
}
```

<Note>
  你会注意到在响应中，你会得到 2 个不同的 `TransactionIds`。这是因为 `DeleteEmptyStacks` 属性被作为额外的交易处理。在前面的示例中，交易 212 对应于捆绑包的购买，交易 213 对应于空 Cream 堆栈的删除（假设你的库存中只有 1 个 Cream）。
</Note>

### C# SDK

就 C# 代码应该是什么样子而言，下面你可能会找到我们示例的一个片段。

```csharp theme={null}
var purchaseRequest = new PurchaseInventoryItemsRequest
{
    Entity = new PlayFab.EconomyModels.EntityKey { Id = entityKey.Id, Type = entityKey.Type },
    Item = new InventoryItemReference { Id = "34167d9f-c8d7-4e17-9a87-b6af1fc389b2" }, //bundle id
    Amount = 1,
    PriceAmounts = new List<PurchasePriceAmount>() { 
        new PurchasePriceAmount { 
            ItemId = "e5276289-f839-4bde-acce-309ea7959e45", 
            Amount = 1 
        }, //cream id and quantity
        new PurchasePriceAmount { 
            ItemId =  "0d2ab329-2fc5-4ae1-9e3c-19f9fc9bbf86", 
            Amount = 1 
        } //icebox id and quantity
    }, 
    StoreId = "f116f1d4-64f9-4be7-9660-a3c1f021100b",
    DeleteEmptyStacks = true
};

var result = await PlayFabEconomyAPI.PurchaseInventoryItemsAsync(purchaseRequest);
```

***

## 另请参阅

* [Economy v2 概览](/services/playfab/economy-monetization/economy-v2/overview)
* [设置](/services/playfab/economy-monetization/economy-v2/settings)
* [Economy v2 商店](/services/playfab/economy-monetization/economy-v2/catalog/stores#creating-a-store)


## Related topics

- [制作游戏 第 1 部分 - 设置](/zh-CN/services/playfab/economy-monetization/economy-v2/tutorials/craftingGame/crafting-game-environment.md)
- [制作游戏 第 2 部分 - Game Manager](/zh-CN/services/playfab/economy-monetization/economy-v2/tutorials/craftingGame/crafting-game-game-manager.md)
- [制作游戏 - 上下文](/zh-CN/services/playfab/economy-monetization/economy-v2/tutorials/craftingGame/game-context.md)
- [Economy v2 概览](/zh-CN/services/playfab/economy-monetization/economy-v2/overview.md)
- [PlayFab Economy v2 文档](/zh-CN/services/playfab/economy-monetization/index.md)
