> ## 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.

# 使用可重置的统计信息和排行榜

> 配置带版本控制的 PlayFab 统计信息和排行榜，按设定的时间间隔重置，并使用 Admin、Client 和 Server API 查询当前或存档版本。

本教程提供了如何配置和管理带版本控制的统计信息的完整演练——这允许*重置*统计信息，并延伸到排行榜。

我们将重点介绍如何使用 Admin API 方法，并提供有关如何使用客户端和 Server API 方法查询数据（当前版本以及旧版本）的其他信息。

我们的目标是为你提供 PlayFab 中可重置统计信息如何工作的技术评审，以及可以在游戏中使用它们的所有方式。

## 统计信息和排行榜

首先，值得注意的是，PlayFab 中为游戏中的玩家定义的所有统计信息都属于一个排行榜。因此，定义统计信息也会定义你的排行榜。

统计信息不一定对玩家可见，但它们是存在的。你可以使用它们通过你定义的分数获取玩家列表——无论是查找所有分数的最高、最低、以当前玩家为中心的玩家，还是用户好友列表上的玩家。

许多游戏中的统计信息都旨在成为*终身*值——这意味着玩家不断更新其分数，旧的分数会保留，直到每个玩家超越自己的个人最好成绩。然而，对于某些玩家体验来说，能够不时“清空”排行榜非常重要。

这可以鼓励用户在给定时间段内成为排名靠前的玩家，或者简单地从排名中删除一段时间内不活跃的玩家。

如本教程所述，PlayFab 中的统计信息可以配置为按预定的时间间隔重置。

这不仅对上述情境有用——它还可以用于需要拥有独立的最近分数排行榜的标题，可用于游戏挑战等场景，你希望让玩家向具有类似技能水平的人发出邀请。

设置重置周期意味着在调用 [GetLeaderboardAroundPlayer](xref:titleid.playfabapi.com.client.playerdatamanagement.getleaderboardaroundplayer) 时返回的玩家（例如）是最近玩过游戏且与本地玩家分数相似的玩家。

也可以将统计信息重置作为手动操作。这是清除你从预发布测试或 alpha/beta 玩法中获得的任何数据的方便系统。

对于最糟糕的情况也很有用，即游戏代码中引入了导致失控分数的 bug。在每种情况下，你都需要能够*彻底*清空排行榜，让玩家觉得他们有公平的机会上榜。

<Note>
  重置统计信息不会删除这些值，你将在下面看到。重置时，PlayFab 中的统计信息会进行版本化，使新版本成为权威版本，同时保留以前的版本以供以后分析（这样你可以根据玩家的旧分数奖励他们）。
</Note>

## 配置可重置的统计信息

统计信息的重置周期使用 Admin API 集或 Game Manager 进行配置。然后，可以通过 Game Manager、Server API 和 Client API 更新和查询它们（尽管从客户端发布统计信息确实需要在 Game Manager 的游戏 **Settings**->**API Features** 选项卡中设置 **allow client to post statistics** 选项）。

我们将描述用于此操作的 API 方法，尽管此处定义的参数与在 Game Manager 本身中使用的参数相同。

若要设置统计信息，可以使用 Admin 的 `CreatePlayerStatisticDefinition` 方法，并使用 `UpdatePlayerStatisticDefinition` 方法在之后进行更改。

在这两种情况下，只有两个参数：

* `StatisticName` - 玩家统计信息的字符串标识符。
* `VersionChangeInterval` - 定义应何时自动重置统计信息的周期。

`VersionChangeInterval` 是此功能的关键，它可以定义为每小时、每日、每周或每月。如果你稍后决定不再希望统计信息定期重置，还可以将其设置为 never。

在下面的示例中，对 `CreatePlayerStatisticDefinition` 方法的调用设置了 Headshots 统计信息，并设定每日重置，这意味着游戏中此统计信息的排行榜将在每天 00:00 UTC 重置。

```csharp theme={null}
public void CreatePlayerStatisticDefinition() {
    PlayFabAdminAPI.CreatePlayerStatisticDefinition(
        new CreatePlayerStatisticDefinitionRequest() {
            StatisticName = "Headshots",
            VersionChangeInterval = StatisticResetIntervalOption.Day
        },
        result => Debug.Log("Complete"),
        error => Debug.Log(error.GenerateErrorReport())
    );
}
```

以下显示了上述 API 调用的响应。

```json theme={null}
{
    "code": 200,
    "status": "OK",
    "data":
    {
        "Statistic":
        {
            "StatisticName": "Headshots",
            "CurrentVersion": 0,
            "VersionChangeInterval": "Day"
        }
    }
}
```

下面显示的代码是另一个示例。

```csharp theme={null}
public void UpdatePlayerStatisticDefinition() {
    PlayFabAdminAPI.UpdatePlayerStatisticDefinition(
        new UpdatePlayerStatisticDefinitionRequest() {
            StatisticName = "Headshots",
            VersionChangeInterval = StatisticResetIntervalOption.Week
        },
        result => Debug.Log("Complete"),
        error => Debug.Log(error.GenerateErrorReport())
    );
}
```

该调用演示了将统计信息的重置周期设置为每周，响应如下所示。

```json theme={null}
{
    "code": 200,
    "status": "OK",
    "data":
    {
        "Statistic":
        {
            "StatisticName": "Headshots",
            "CurrentVersion": 0,
            "VersionChangeInterval": "Week"
        }
    }
}
```

在每种情况下，结果是 `PlayerStatisticDefinition`，包含：

* 统计信息的字符串 ID (`StatisticName`)。
* 统计信息已重置的次数 (`CurrentVersion`)。
* 定义的统计信息重置周期 (`VersionChangeInterval`)。

重置周期在定义后立即生效，因此在这种情况下，第二次调用意味着重置现在被定义为 00:00 UTC，星期一早上（星期日晚上/星期一凌晨的午夜，使用 UTC 时区），无论调用之前是什么。

其余重置间隔也使用 UTC 定义，其中 Month 使重置在每个月的第一天 00:00 UTC 发生。

对于完整的列表，重置周期为：

* **Never**：停止基于时间对统计信息进行版本化。
* **Hour**：在每个小时的开始（XX:00 UTC）对统计信息进行版本化。
* **Day**：每天午夜（00:00 UTC）对统计信息进行版本化。
* **Week**：每周一午夜（00:00 UTC）对统计信息进行版本化。
* **Month**：每个月第一天午夜（00:00 UTC）对统计信息进行版本化。

## 预先存在的统计信息

无论是否设置为重置的统计信息，都可以查询游戏中定义的所有统计信息的定义。

值得注意的是，可以使用 [UpdatePlayerStatistics](xref:titleid.playfabapi.com.client.playerdatamanagement.updateplayerstatistics) 调用创建统计信息。任何未使用重置周期 (`VersionChangeInterval`) 创建的统计信息一开始都没有重置周期，因此对统计信息配置的查询将返回此参数设置为 `Never`。

使用上面的示例，如果该标题还有一个名为 `FlagsCaptured` 的统计信息，它使用 [UpdatePlayerStatistics](xref:titleid.playfabapi.com.client.playerdatamanagement.updateplayerstatistics)（或直接在 Game Manager 中的玩家上创建），并且过了几周，它将如下面所示的调用中出现。

```csharp theme={null}
public void GetPlayerStatisticDefinitions() {
    PlayFabAdminAPI.GetPlayerStatisticDefinitions(
        new GetPlayerStatisticDefinitionsRequest(),
        result => Debug.Log("Complete"),
        error => Debug.Log(error.GenerateErrorReport())
    );
}
```

将产生以下结果。

```json theme={null}
{
    "code": 200,
    "status": "OK",
    "data":
    {
        "Statistics": [
        {
            "StatisticName": "Headshots",
            "CurrentVersion": 2,
            "VersionChangeInterval": "Week"
        },
        {
            "StatisticName": "FlagsCaptured",
            "CurrentVersion": 0,
            "VersionChangeInterval": “Never”
        }]
    }
}
```

在这种情况下，名为 `Headshots` 的统计信息已定义重置间隔，而 `CurrentVersion` 表示统计信息已重置两次。

与此同时，`FlagsCaptured` 没有 `VersionChangeInterval`，这也是 `CurrentVersion` 为 **0** 的原因（因为它从未进行过版本化）。

通过 [UpdatePlayerStatistics](xref:titleid.playfabapi.com.client.playerdatamanagement.updateplayerstatistics)（或 PlayFab Game Manager）创建的统计信息仍可以使用 `UpdatePlayerStatisticDefinition` 定义为具有重置周期，如上所述。

一旦完成，它们将完全按照最初使用 `CreatePlayerStatisticDefinition` 定义时的方式在该间隔重置。

## 手动重置统计信息

对于游戏 bug 允许在统计信息上作弊的情况，或者你只需要重置以从预发布游戏玩法中删除分数的情况，可以在 Game Manager 中强制重置统计信息，或通过调用 `IncrementPlayerStatisticVersion` 强制重置。

这会立即重置你指定的当前统计信息，清空游戏的排行榜，并为报告新值提供空白页面。

对于我们的示例，此调用可能类似于下面所示的调用。

```csharp theme={null}
public void IncrementPlayerStatisticVersion() {
    PlayFabAdminAPI.IncrementPlayerStatisticVersion(
        new IncrementPlayerStatisticVersionRequest() {
            StatisticName = "Headshots"
        },
        result => Debug.Log("Complete"),
        error => Debug.Log(error.GenerateErrorReport())
    );
}
```

这会再一次递增 `Headshots` 统计信息，返回有关刚刚变为活动状态的版本的信息。

```json theme={null}
{
    "code": 200,
    "status": "OK",
    "data":
    {
        "StatisticVersion":
        {
            "StatisticName": "Headshots",
            "Version": 3,
            "ActivationTime": "2016-02-03T08:02:29.864Z",
            "ArchivalStatus": "NotScheduled"
        }
    }
}
```

在这种情况下，返回 `PlayerStatisticVersion` 信息，其中包含统计信息的 ID (`StatisticName`)，以及其版本号、变为权威版本的时间 (`ActivationTime`) 和 `ArchivalStatus`（对于当前版本，它始终为 `NotScheduled`）。

但是，对于同时具有 `VersionChangeInterval` 的统计信息，手动重置*不会*更改下一次计划的重置时间。如果统计信息计划每日重置——并在 UTC 时间下午 11:30 手动重置——它*仍将*在 UTC 时间午夜再次重置。

### 重置何时发生

如前所述，当重置间隔发生时，统计信息将进行版本化，因此新版本立即可用，而该统计信息的旧版本被存档以供以后检索。

一旦重置间隔发生（或执行手动重置），并且统计信息已被版本化，将接受对旧版本的写入长达十分钟。超过该时间点，统计信息将被*锁定*，防止未来更新。

一旦过期，统计信息将开始存档过程，以便标题可以稍后检索它们。

统计信息存档过程的阶段是：

* **NotScheduled** - 统计信息的存档尚未开始（通常仅对当前活动的统计信息版本）。
* **Scheduled** - 存档过程已计划，但尚未进行。
* **InProgress** - 统计信息正在备份到存档。
* **Failed** - 发生了意外故障（在这种情况下，请联系我们的[支持论坛](https://community.playfab.com/)）。
* **Complete** - 此版本的统计信息已被存档。

可以使用 `GetPlayerStatisticVersions` 查询统计信息的所有过去和当前版本。这将返回每个版本的信息，如前面的手动重置示例所示。

换句话说，此调用应类似于下面显示的调用。

```csharp theme={null}
public void GetPlayerStatisticVersions() {
    PlayFabAdminAPI.GetPlayerStatisticVersions(
        new GetPlayerStatisticVersionsRequest() {
            StatisticName = "Headshots"
        },
        result => Debug.Log("Complete"),
        error => Debug.Log(error.GenerateErrorReport())
    );
}
```

这可能导致我们的示例标题返回以下信息。

```json theme={null}
{
    "code": 200,
    "status": "OK",
    "data":
    {
        "StatisticVersions": [
        {
            "StatisticName": "Headshots",
            "Version": 0,
            "ActivationTime": "2015-01-20T05:47:27.17Z",
            "DeactivationTime": "2016-01-25T00:00:00.000Z",
            "ArchivalStatus": "Complete",
            "ArchiveDownloadUrl": {{URL}}
        },
        {
            "StatisticName": "Headshots",
            "Version": 1,
            "ActivationTime": "2016-01-25T00:00:00.000Z",
            "DeactivationTime": "2016-02-01T00:00:00.000Z",
            "ArchivalStatus": "Complete",
            "ArchiveDownloadUrl": {{URL}}
        },
        {
            "StatisticName": "Headshots",
            "Version": 2,
            "ActivationTime": "2016-02-01T00:00:00.000Z",
            "DeactivationTime": "2016-02-03T08:02:29.864Z",
            "ArchivalStatus": "InProgress"
        },
        {
            "StatisticName": "Headshots",
            "Version": 3,
            "ActivationTime": "2016-02-03T08:02:29.864Z",
            "ArchivalStatus": "NotScheduled"
        }]
    }
}
```

除了 `IncrementPlayerStatisticVersion` 返回的值外，响应还包括当前活动版本之前的每个版本何时过期 (`DeactivationTime`) 的时间戳，以及一旦存档过程完成，用于下载包含旧排行榜完整记录的 CSV 的 URL (`ArchiveDownloadUrl`)。

### 读取和写入统计信息版本

最后，从服务器和客户端 API 方面来看，调用与你从原始 PlayFab 用户和角色统计信息调用中所了解的非常相似。

区别在于，现在，版本是请求或响应的一部分。

检索统计信息时，将返回当前统计信息版本的值以及版本号本身。

以下示例显示了对 `Headshots` 统计信息进行调用以及返回的数据。

#### 服务器请求

```csharp theme={null}
public void GetPlayerStatistics() {
    PlayFabServerAPI.GetPlayerStatistics(
        new GetPlayerStatisticsRequest() {
            PlayFabId= "_PlayFabId_",
            StatisticNames = new List<string>() { "Headshots" }
        },
        result => Debug.Log("Complete"),
        error => Debug.Log(error.GenerateErrorReport())
    );
}
```

#### 服务器响应

```json theme={null}
{
    "code": 200,
    "status": "OK",
    "data":
    {
        "PlayFabId": {{PlayFabId}},
        "Statistics": [
        {
            "StatisticName": "Headshots",
            "Value": 10,
            "Version": "3"
        }]
    }
}
```

#### 客户端请求

```csharp theme={null}
public void GetPlayerStatistics() {
    PlayFabClientAPI.GetPlayerStatistics(
        new GetPlayerStatisticsRequest() {
            StatisticNames = new List<string>() { "Headshots" }
        },
        result => Debug.Log("Complete"),
        error => Debug.Log(error.GenerateErrorReport())
    );
}
```

#### 客户端响应

```json theme={null}
{
    "code": 200,
    "status": "OK",
    "data": {
        "Statistics": [
        {
            "StatisticName": "Headshots",
            "Value": 10,
            "Version": "3"
        }]
    }
}
```

与此同时，`Update` 调用采用可选版本，以允许标题控制正在更新的版本，以应对版本可能在游戏过程中递增的情况。

<Note>
  在此示例中，如果标题在仍然可能的情况下写入*前一个*版本，则将写入版本 2，如下所示。
</Note>

#### 服务器请求

```csharp theme={null}
public void UpdatePlayerStatistics() {
    PlayFabServerAPI.UpdatePlayerStatistics(
        new UpdatePlayerStatisticsRequest() {
            PlayFabId= "_PlayFabId_",
            Statistics = new List<StatisticUpdate>() {
                new StatisticUpdate() {
                    StatisticName = "Headshots",
                    Version = 2,
                    Value = 10
                }
            }
        },
        result => Debug.Log("Complete"),
        error => Debug.Log(error.GenerateErrorReport())
    );
}
```

#### 服务器响应

```json theme={null}
{
    "code": 200,
    "status": "OK",
    "data": {}
}
```

#### 客户端请求

```csharp theme={null}
public void UpdatePlayerStatistics() {
    PlayFabClientAPI.UpdatePlayerStatistics(
        new UpdatePlayerStatisticsRequest() {
            Statistics = new List<StatisticUpdate>() {
                new StatisticUpdate() {
                    StatisticName = "Headshots",
                    Version = 2,
                    Value = 10
                }
            }
        },
        result => Debug.Log("Complete"),
        error => Debug.Log(error.GenerateErrorReport())
    );
}
```

#### 客户端响应

```json theme={null}
{
    "code": 200,
    "status": "OK",
    "data": {}
}
```

但请记住——尽管过期版本可以在长达 10 分钟内写入，但*超出*该时间对该版本的任何写入尝试都将失败，其响应如下所示。

```json theme={null}
{
    "code": 400,
    "status": "BadRequest",
    "error": "StatisticVersionClosedForWrites",
    "errorCode": 1197,
    "errorMessage": "The statistic version is not current and is no longer accepting updates"
}
```

## 资源

为完整起见，本节提供上面描述的所有枚举、类和 API 方法的列表，并附有简要说明。

### 基本枚举

* **Interval** - 统计信息（排行榜）将被重置的周期：
  * **Never**
  * **Hour**
  * **Day**
  * **Week**
  * **Month**

* **StatisticVersionArchivalStatus** - 将某个版本的玩家统计信息值保存到可下载存档的过程状态：
  * **NotScheduled**
  * **Scheduled**
  * **InProgress**
  * **Failed**
  * **Complete**

### 基本类及其成员

* **PlayerStatisticDefinition**
  * **StatisticName** (string) - 统计信息的唯一名称。
  * **CurrentVersion** (string) - 统计信息的当前活动版本，每次统计信息重置时递增。
  * **VersionChangeInterval** (Interval) - 所有玩家的统计信息值重置的间隔。

* **PlayerStatisticVersion**
  * **StatisticName** (string) - 版本变为活动状态时统计信息的名称。
  * **Version** (string) - 统计信息的版本（编码为字符串的十六进制数）。
  * **ScheduledVersionChangeIntervalTime** (DateTime) - 根据配置的 **ResetInterval**，计划统计信息版本变为活动状态的时间。
  * **CreatedTime** (DateTime) - 统计信息版本变为活动状态的时间。
  * **ArchivalStatus** (**StatisticVersionArchivalStatus**) - 如果配置，将此版本的玩家统计信息值保存到可下载存档的过程状态。
  * **ResetInterval** (Interval) - 触发版本变为活动状态的重置间隔（如果已配置）。

* **StatisticValue**
  * **StatisticName** (string) - 统计信息的唯一名称。
  * **Value** (Int32) - 该玩家的统计信息值。
  * **Version** (string) - 对于玩家的现有统计信息值，加载时的统计信息版本。

* **StatisticUpdate**
  * **StatisticName** (string) - 统计信息的唯一名称。
  * **Version** (string) - 对于玩家的统计信息值更新，要更新的统计信息版本
  * Value (Int32) - 该玩家的统计信息值。

### Admin API 方法

* **CreatePlayerStatisticDefinition**
  * **CreatePlayerStatisticDefinitionRequest**
    * **Name** (string) - 最小长度 1，最大长度 128 - 统计信息的唯一名称。
    * (**VersionChangeInterval**) (Interval) - 所有玩家的统计信息值重置的间隔（重置从下一个间隔边界开始）。

  * **CreatePlayerStatisticDefinitionResult**
    * **Statistic** (**PlayerStatisticDefinition**) - 已创建统计信息的定义。

* **UpdatePlayerStatisticDefinition**
  * **UpdatePlayerStatisticDefinitionRequest**
    * **StatisticName** (string) - 统计信息的唯一名称。
    * **VersionChangeInterval** (Interval) - 所有玩家的统计信息值重置的间隔（重置从下一个间隔边界开始）。

  * **UpdatePlayerStatisticDefinitionResult**
    * **Statistic** (**PlayerStatisticDefinition**) - 已创建统计信息的定义。

* **GetPlayerStatisticDefinitions**
  * **GetPlayerStatisticDefinitionsRequest**（无参数）。
  * **GetPlayerStatisticDefinitionsResult**
    * **Statistics** (**PlayerStatisticDefinition\[]**) - 用于重置的定义数组。

* **GetPlayerStatisticVersions**
  * **GetPlayerStatisticVersionsRequest**
    * **StatisticName** (string) - 统计信息的唯一名称。

  * **GetPlayerStatisticVersionsResult**
    * **StatisticVersions** (**PlayerStatisticVersion\[]**) - 统计信息的版本更改历史记录（所有版本）。

* **IncrementPlayerStatisticVersion**
  * **IncrementPlayerStatisticVersionRequest**
    * **StatisticName** (string) - 统计信息的唯一名称。

  * **IncrementPlayerStatisticVersionResult**
    * **StatisticVersion** (**PlayerStatisticVersion**) - 由于此操作而过期的统计信息版本（及其存档状态）。

### Client API 方法

* **GetPlayerStatistics**
  * **GetPlayerStatisticsRequest**
    * **StatisticNames** (string\[]) - 要返回的统计信息数组，按其唯一名称。

  * **GetPlayerStatisticsResult**
    * **Statistics** (**StatisticValue\[]**) - 请求的所有统计信息的 **StatisticValue** 数据数组。

* **UpdatePlayerStatistics**
  * **UpdatePlayerStatisticsRequest**
    * **Statistics** (**StatisticUpdate\[]**) - 要使用提供的值更新的统计信息。

  * **UpdatePlayerStatisticsResult**（无参数）。

### Server API 方法

* **GetPlayerStatistics**
  * **GetPlayerStatisticsRequest**
    * **PlayFabId** (string) - 正在更新其统计信息的玩家的 PlayFab ID。
    * **StatisticNames** (string\[]) - 要返回的统计信息数组，按其唯一名称。

  * **GetPlayerStatisticsResult**
    * **Statistics** (**StatisticValue\[]**) - 请求的所有统计信息的 **StatisticValue** 数据数组。

* **UpdatePlayerStatistics**
  * **UpdatePlayerStatisticsRequest**
    * **PlayFabId** (string) - 正在更新其统计信息的玩家的 PlayFab ID。
    * **Statistics** (**StatisticUpdate\[]**) - 要使用提供的值更新的统计信息。

  * **UpdatePlayerStatisticsResult**（无参数）。


## Related topics

- [使用玩家统计信息](/zh-CN/services/playfab/community/leaderboards/tournaments-leaderboards/using-player-statistics.md)
- [使用奖品表](/zh-CN/services/playfab/community/leaderboards/tournaments-leaderboards/using-prize-tables.md)
- [统计信息和排行榜](/zh-CN/services/xbox-services/player-data/stats-leaderboards/live-stats-leaderboards-nav.md)
- [配置标题管理的统计信息和排行榜](/zh-CN/services/xbox-services/player-data/stats-leaderboards/title-managed/config/live-tm-leaderboards-portal.md)
- [基于事件的统计信息和排行榜](/zh-CN/services/xbox-services/player-data/stats-leaderboards/event-based/live-statslb-eb-nav.md)
