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

# 多人游戏会话目录

> 深入了解 MPSD 指南,涵盖会话模板属性、协定 v107 架构、QoS 模板、成员初始化以及多人游戏故障排除。

本文概述了在 XBOX 360 之后的平台上使用 XBOX services 多人游戏会话目录 (MPSD) 服务创建多人游戏会话。

本文主要面向直接向 Partner Center 提交其会话模板的 XBOX 游戏开发人员。

本文介绍多人游戏会话的 MPSD 配置、用法和故障排除。

**目录:**

* [修订摘要](#rs)
* [简介](#intro)
* [本文档中使用的术语](#tuitd)
* [多人游戏会话目录](#tmsd)
* [MPSD 会话](#mpsds)
* [会话模板属性](#sta)
* [协定架构更新](#csu)
* [会话文档中的成员初始化](#miisd)
* [匹配票证会话](#mts)
* [服务质量 (QoS) 模板](#qost)
* [QoS 阶段和会话初始化详细信息](#qospasid)
* [XBOX 云计算会话](#xccs)
* [原始会话和自定义游戏属性](#rsactp)
* 活动成员衰减
* [常见问题和故障排除](#fat)

## 修订摘要

客户端 XBOX Services API (XSAPI) 库当前在与 MPSD 服务通信时使用协定版本 104。
本文档的这个版本将会话模板架构更新至协定版本 107,这是 MPSD 服务支持的最新协定版本。
版本 104 和 107 之间的更改在下面的[协定架构更新](#_Contract_schema_update)一节中进行了总结。

请注意,为协定版本 104 编写的模板如果作为 107 重新发布,则需要更新。
但是,这些服务是向后兼容的,因此你可以继续使用当前的库,这些库将在未来的版本中更新。

本文档的上一个修订版更新了有关服务器会话的信息,并增加了关于 XSAPI 和 RESTful 服务调用的新章节。
此外,"查询会话状态信息"一节中的表已更新,并且"服务质量 (QoS) 模板"一节也已修订。

## 简介

多人游戏会话是位于多人游戏会话目录 (MPSD) 上的云中的安全文档,此文档表示一组玩游戏的人。
具体而言,多人游戏会话具有以下特性:

* 每个会话都有一个唯一的 URI。

* 会话文档包含当前成员、游戏设置、引导数据和游戏服务器信息。

* 游戏创建并管理自己的会话。

* 会话支持其成员之间的连接。

多人游戏会话目录 (MPSD) 在所有客户端之间集中管理游戏会话元数据。
MPSD 提供有关会话的基本信息,以帮助设置客户端之间的安全设备关联。

MPSD 还为客户端提供基本的首次启动元数据,以便在开始传递更具体的游戏数据之前连接到游戏。

由于进程生命周期管理 (PLM) 以及 XBOX One 及更高版本上应用程序的任务切换特性,MPSD 确保客户端拥有联系被识别为活动游戏会话一部分的对等方和服务器的正确信息,并与外壳和主机操作系统协调以保留、激活和管理游戏会话的玩家生命周期。

## 本文档中使用的术语

| 术语 | 定义 |
| - | - |
| 多人游戏会话 | 位于 XBOX services 云中的安全文档,表示在 XBOX One 或更高版本(包括 PC)上玩游戏时(或将要)一起连接的一组用户。多人游戏的所有方面(如对战匹配、聚会、进行中加入等)都利用多人游戏会话。 |
| 游戏会话 | 这是实际的游戏会话,在 MPSD 中公开,用户在其中一起玩游戏。所有多人游戏方案最终都会进入游戏会话。 |
| 匹配票证会话 | 这是用于在对战匹配期间跟踪匹配票证提交的会话。 |
| 非活动玩家 | 在会话中已设置为非活动状态的玩家。当游戏受约束、挂起或按游戏定义处于其他非活动状态时,游戏会将用户设置为非活动状态。 |

## 多人游戏会话目录

MPSD 有助于在在线玩家之间协调会话信息。
可以创建不同类型的会话来完成多人游戏的不同任务。

下表列出了在 XBOX 360 上完成此类任务与在 XBOX One 或更高版本(包括 PC)上完成的方式之间的差异。

| 功能或任务 | XBOX 360 | XBOX One 或更高版本 |
| - | - | - |
| **获取游戏会话信息** | **XSessionGetDetails**、**XSessionSearchByID**,或自行跟踪。 | 从服务请求会话信息。 |
| **迁移主机** | 需要时,游戏调用 **XSessionMigrateHost**。 | 无需创建新会话,只需为 SessionID 分配一个新主机。 |
| **管理多个玩家会话** | 一次处理多个会话较为棘手。例如,**XNetReplaceKey** 与 **XNetUnregisterKey**。 | 基于服务的会话使得管理单个会话更简洁,并简化了处理多个会话。 |
| **处理注销和断开连接** | 必须分别处理断开连接和注销,分别使用 **XCloseHandle** 或 **XSessionDelete**。 | 集中式服务简化了注销和断开连接的处理,超时在游戏配置中设置。 |

### 会话模式

* 游戏会话

  * 包含玩家的 XUID、安全设备地址数据和属性状态的会话。这被视为实际的游戏玩法会话。

  * 可以是对等、点对主机、点对服务器或混合。

* 匹配票证会话

  * 提交给对战匹配以找到其他玩家共同游戏的会话。请注意,如果游戏在寻找更多玩家,游戏会话也可以是票证会话。

* 服务器会话

  * 通过 XBOX Compute 处理创建和使用的游戏会话。

图 1 演示了 MPSD 会话的用法,其中蓝框代表 MPSD 会话,红框代表使用它们的服务。

**图 1. MPSD 会话使用:**(图缺失)

## MPSD 会话

会话维护两个相关实体列表:

1. 已加入或被邀请加入会话的成员(用户)。

2. 已加入会话的服务器(云服务器或专用服务器)。

每个实体具有:

1. 创建时设置的常量值。

2. 可变属性。

3. 只读元数据。

### XSAPI 和 RESTful 服务调用

有两种方式与 XBOX services Sessions 和 Matchmaking 服务连接。

* 标准 HTTPS 调用
* XSAPI 包装器

#### 使用对 RESTful 服务的标准 HTTPS 调用

对于 XBOX One 及更高版本,与 XBOX services Sessions 和 Matchmaking 服务连接的第一种方式是对 RESTful XBOX services URI 使用标准 HTTPS 调用。
这为游戏调用和连接这些服务提供了灵活性,具体取决于其服务器和游戏配置。

有关这些 URI 的列表,请参阅 [XBOX services RESTful 参考](/zh-CN/reference/live/rest/atoc-xboxlivews-reference)。

#### 使用 RESTful 服务的 XSAPI 包装器

与 Sessions 和 Matchmaking 服务连接的第二种方式是使用充当 RESTful 服务 URI 包装器的 XSAPI。
这些允许在代码中使用 API 的更传统方法,而无需为每次调用处理 HTTPS 流量。

有关 XSAPI 的更多信息,请参阅 [xbox-live-api GitHub 页面](https://github.com/microsoft/xbox-live-api)。

该参考文档包括:

* JSON 分析 API 参考 - JSON 分析 API 的参考资料。
* Windows.Web 命名空间 - Windows.Web 命名空间成员。
* XBOX Compute SDK 参考 - 用于为 XBOX Compute 创建游戏服务器实例的 API。

### MPSD 会话和模板

MPSD 会话是使用通过 Partner Center 引入的模板创建的。
模板是定义所创建会话框架的 JSON 文档。
模板为新会话提供常量。

以下摘录是模板配置示例。

```json theme={null}
// Used for creating the session that you then pass into your match ticket request. This *should* not have any QoS requirements.
MatchTicketSession (Contract Version: 107)
{
    "constants": {
        "system": {
            "version": 1,
            "maxMembersCount": 10,
            "visibility": "private",
            "capabilities": {},
            "memberInitialization": {
                "joinTimeout": 20000,
                "externalEvaluation": false,
                "membersNeededToStart": 1
            }
        },
        "custom": {}
    }
}

// This is the new game session that is returned after you've been matched.
// Note: This is used for in-game QoS. For out-of-game QoS, you will need P2P/HTP requirements.
GameSession (Contract Version:107)
{
    "constants": {
        "system": {
            "maxMembersCount": 12,
            "capabilities": {"connectivity": true }
        },
        "memberInitialization": {
         "joinTimeout": 20000,
         "measurementTimeout": 15000,
         "externalEvaluation": false,
         "membersNeededToStart": 4
         },

   "custom": {}
  }
}
```

匹配票证会话应与游戏会话模板一起使用,该模板在其 **memberInitialization** 对象中设置了 QoS 超时值。

**图 2. 示例料斗:**

![料斗编辑对话框](https://mintcdn.com/microsoft-4404708b/ktEik-YaZoen6Rhy/images/gdk/services/mpsd_image1.png?fit=max\&auto=format\&n=ktEik-YaZoen6Rhy\&q=85\&s=2413f594f853c2fbf7cd196028f2f33b)

以下代码摘录是对等游戏会话模板(游戏管理的 QoS)的示例。

```json theme={null}
{
    "constants": {
        "system": {
            "version": 1,
            "maxMembersCount": 10,
            "visibility": "private",
            "capabilities": {
                "connectivity": true
            },
            "memberInitialization": {
                "joinTimeout": 20000,
                "externalEvaluation": false,
                "membersNeededToStart": 2
            }
        },
        "custom": {}
    }
}

```

这是点对服务器会话和 RAW 模板的示例。

```json theme={null}
{
    "constants": {
        "system": {
            "version": 1,
            "maxMembersCount": 10,
            "visibility": "private",
            "capabilities": {}
        },
        "custom": {}
    }
}
```

以下代码显示了用于 Smart Match 的匹配票证会话模板的示例。

```json theme={null}
{
    "constants": {
        "system": {
            "version": 1,
            "maxMembersCount": 10,
            "visibility": "private",
            "capabilities": {},
            "memberInitialization": {
                "joinTimeout": 20000,
                "externalEvaluation": false,
                "membersNeededToStart": 1
            }
        },
        "custom": {}
    }
}

```

### 检查为 SCID 配置的模板

#### 会话模板

可以从 MPSD 检索 SCID 中存在的会话模板列表,以及特定会话模板的详细信息:

```uri theme={null}
GET /serviceconfigs/{scid}/sessiontemplates

GET /serviceconfigs/{scid}/sessiontemplates/{session-template-name}
```

#### 查询会话状态信息

可以在服务配置和会话模板级别查询会话:

```uri theme={null}
GET /serviceconfigs/{scid}/sessions

GET /serviceconfigs/{scid}/sessiontemplates/{session-template-name}/sessions
```

默认情况下,这将返回最多 100 个非私有会话。
可以使用以下查询字符串参数修改查询:

| 查询字符串 | 效果 | 说明 |
| - | - | - |
| keyword=foo | 仅包含具有关键字 "foo" 的会话。 | |
| XUID=123 | 仅包含用户 "123" 所在的会话。 | 默认情况下,用户必须在会话中处于活动状态才能被包含。 |
| *reservations*=**true** | 包含用户被设置为保留玩家但尚未加入成为活动玩家的会话。 | 仅当查询自己的会话时,或以服务器到服务器方式查询特定用户的会话时。 |
| *inactive*=**true** | 包含用户已接受但未积极参与游戏的会话。 | 用户处于"就绪"但不是"活动"的会话被计为非活动。 |
| *private*=**true** | 包含私有会话。 | 仅当查询自己的会话时,或以服务器到服务器方式查询时。 |
| *visibility*=open | 仅包含"open"的会话。 | 如果设置为"private",还必须设置 "private=true" 指令。 |
| *take*=5 | 返回最多 5 个会话。 | 必须在 0 到 100 之间。 |

结果是会话引用的 JSON 数组。
一些会话数据以内联方式包含在内。

**注意** 每个查询必须包含关键字筛选器、XUID 筛选器或两者。

将 *private*(返回私有会话)或 *reservations*(返回用户尚未加入的会话)设置为 **true** 需要调用方具有对会话的服务器级访问权限,或者调用方的 XUID 声明与 URI 中的 XUID 筛选器匹配。
否则,将返回 403 Forbidden(无论此类会话是否实际存在)。

以下代码摘录显示了查询响应的示例。

```json theme={null}
{
"results": [ {
"xuid": "9876",  // If the session was found from a xuid, that xuid.
"startTime": "2009-06-15T13:45:30.0900000Z",
"sessionRef": {
  "scid": "foo",
  "templateName": "bar",
  "name": "session-seven"
},
"accepted": 4,        // Approximate number of non-reserved members.
"status": "active",   // or "reserved" or "inactive". This is the state of the user in the session, not the session itself. Only present if the session was found using a xuid.
"visibility": "open", // or "private", "visible", or "full"
"myTurn": true,       // Not present is the same as 'false'. Only present if the session was found using a xuid.
"keywords": [ "one", "two" ]
} ]
}

```

## 会话模板属性

## 协定架构更新

如本文档开头所述,最新的会话模板协定版本为 107,它对之前版本 104 的架构进行了一些更改。
为协定版本 104 编写的模板如果作为 107 重新发布,则需要更新。

以下是这些更改的摘要。

* **/constants/system/managedInitialization** 已重命名为 **/constants/system/memberInitialization**。

  * **autoEvaluate** 字段已重命名为 **externalEvaluation**,其极性发生变化,但 **false** 仍为默认值。

  * **membersNeededToStart** 的默认值从 2 变为 1。

  * **joinTimeout** 的默认值从 5 秒变为 10 秒。

  * **measurementTimeout** 的默认值从 5 秒变为 30 秒。

* **/constants/system/timeouts** 已删除,超时被重命名并重新定位到 **/constants/system** 下。

  * **reserved** 超时变为 **reservedRemovalTimeout**。

  * **inactive** 超时变为 **inactiveRemovalTimeout**,其新默认值为 0 而非 2 小时。

  * **ready** 超时变为 **readyRemovalTimeout**。

  * **sessionEmpty** 超时变为 **sessionEmptyTimeout**。

* **/constants/system/capabilities/gameplay** 必须在表示实际游戏玩法的会话(而不是辅助会话,如匹配和大厅会话)上指定为 **true**,以启用最近玩家和信誉报告。

### 系统对象

会话文档中的每个系统对象都有一个由 MPSD 强制执行和解释的固定架构。

在 PUT 请求的正文中,系统对象像自定义对象一样进行验证和合并。
但与自定义对象不同,合并后系统对象会根据这些架构进一步验证并执行操作。

**/constants/system**

```json theme={null}
{
"version": 1,  //Document Version (FAL release version 1, service contract 107)
"maxMembersCount": 100,  // Defaults to 100 if not set on creation. Must be between 1 and 100.
"visibility": "private",  // Or "visible" or "open", defaults to "open" if not set on creation.

"initiators": [ "1234" ],  // If specified on a new session, the creators xuid must be in the list (or the creator must be a server).
"inviteProtocol": "party",  // Optional URI scheme of the launch URI for invite toasts.

"reservedRemovalTimeout": 10000, // Default is 30 seconds. Member is removed from the session.
"inactiveRemovalTimeout": 0, // Default is zero. Member is removed from the session.
"readyRemovalTimeout": 60000, // Default is three minutes. Member is removed from the session.
"sessionEmptyTimeout": 0, // Default is zero. Session is deleted.

// Capabilities are boolean values that are optionally set in the session template. If no capabilities are needed, an empty "capabilities" object should be in the template in order to prevent capabilities from being specified on session creation, unless the title desires dynamic session capabilities.
"capabilities": {
"clientMatchmaking": true,
"connectivity": true, // Cannot be set if 'large' is specified.
     "suppressPresenceActivityCheck": false,
     "gameplay": false,
     "large": false
},
/* If a "memberInitialization" object is set, the session expects the client system or title to perform initialization following session creation and/or as new members join the session. The timeouts and initialization stages are automatically tracked by the session, including QoS measurements if any metrics are set. These timeouts override the session's reservation and ready timeouts for members that have 'initializationEpisode' set. */
"memberInitialization": {
"joinTimeout": 20000,  // Milliseconds. Unspecified counts as 10 seconds.
"externalEvaluation": false,
"membersNeededToStart": 2  // Unspecified counts as 1. Must be between 0 and maxMembersCount. Only applies to episode 1. If 00 and the session is created with no members to initialize, episode 1 is skipped..
},
```

**/properties/system**

```json theme={null}
{
// Optional array of case-insensitive strings. Cannot be set if the session's visibility is "private".
"keywords": [ "hello" ],

// Array of integer indices of members whose turn it is. Defaults to empty. Can't be set (and doesn't appear) on large sessions.
"turn": [ 0 ],

/* Restricts who can join "open" sessions. (Has no effect on reservations, which means it has no impact on "private" and "visible" sessions.) Defaults to "none". On large sessions, "none" is the only valid value.
If "local", only users whose token's DeviceId matches someone else already in the session and "active": true.
If "followed", only local users (as defined above) and users who are followed by an existing (not reserved) member of the session can join without a reservation. */
"joinRestriction": "none",

// Device token of the host. Must match the "deviceToken" of at least one member, otherwise this field is deleted.
// If "peerToHostRequirements" is set and "host" is set, the measurement stage assumes the given host is the correct host and only measures metrics to that host.
// Can't be set on large sessions.
"host": "99e4c701",

// Can only be set while "initializing/stage" is "evaluating". True indicates success, and false indicates failure. Once set, "initializing/stage" is immediately updated, and this field is removed.
"initializationSucceeded": true,

/* The ordered list of case-insensitive connection strings that the session could use to connect to a game server. Generally titles should use the first on the list, but sophisticated titles could use a custom mechanism (e.g. Thunderhead) for choosing one of the others (e.g. based on load). */
"serverConnectionStringCandidates": [ "datacenter b", "serverfarm a" ],

"matchmaking": {
    "targetSessionConstants": { },
    // Force a specific connection string to be used (useful in preserveSession=always cases).
    "serverConnectionString": "datacenter b",
},

// True if the match that was found didn't work out and needs to be resubmitted. Set to false to signal that the match did work, and the matchmaking service can release the session.
"matchmakingResubmit": true
}

```

### 超时

会话可以由计时器和其他外部事件更改。
MPSD 中的 **Timeouts** 对象提供了一种管理会话生命周期和成员的基本机制。

会话的 **nextTimer** 字段给出下一个计时器的时间。
客户端可以使用此信息为下一次轮询选择良好的间隔。
此值也会在 **Expires** HTTP 标头中返回。

超时以毫秒为单位指定。
允许零,表示应立即超时。

如果未指定给定的超时,则将其视为无限。
因为超时具有默认值,所以会话模板应显式指定"null"表示无限超时。

#### SessionEmptyTimeout

**/constants/system/sessionEmptyTimeout** 值配置会话变为空后被删除之前的毫秒数。
默认值为零,表示将立即删除会话。
如果未指定该值,则空会话将无限期存在。

#### 成员超时

**/constants/system** 中的另外三个超时控制成员在特定状态下可以保持的时间量:

* **reservedRemovalTimeout**

  * 超时到期时删除保留。默认值为 30 秒。

* **inactiveRemovalTimeout**

  * 非活动成员在默认情况下 2 小时后从会话中删除。

* **readyRemovalTimeout**

  * 处于"就绪"状态的成员默认在 3 分钟后恢复为非活动状态。

## 会话文档中的成员初始化

### 成员初始化

**memberInitialization** 对象控制会话创建后和/或新成员加入会话时的初始化阶段。
会话会自动跟踪超时和初始化阶段,如果设置了任何指标,还包括 QoS 测量。

对于设置了 **initializationEpisode** 属性的成员,这些超时会覆盖会话的保留和就绪超时。

示例:

```json theme={null}
"memberInitialization": {
        "joinTimeout": 5000,
        "measurementTimeout": 5000,
        "evaluationTimeout": 5000,    // only specify for external evaluation
        "externalEvaluation": true,
         "membersNeededToStart": 2
    },
```

**图 3. 成员初始化流程:**

![成员初始化流程图](https://mintcdn.com/microsoft-4404708b/ktEik-YaZoen6Rhy/images/gdk/services/mpsd_image2.png?fit=max\&auto=format\&n=ktEik-YaZoen6Rhy\&q=85\&s=e5001dd95e5ffc9dc9be2449160aaa0a)

成员初始化的三个阶段中的每一个都可能超时:

1. **joiningTimeout**

   * 用户加入会话所需的时间(以毫秒为单位)。未能加入的成员的保留将被删除。

2. **measuringTimeout**

   * 成员必须上传其测量结果的时间量。未能上传测量结果的成员将标记为 *failureReason* 为 "timeout"。

3. **evaluationTimeout**

   * 成员做出并上传评估决定的时间量。如果没有收到决定,则被视为失败。

**externalEvaluation**

* MPSD 可以基于会话模板中提供的要求进行自动 QoS 评估。当 externalEvaluation 设置为 false 时执行评估。当设置 **evaluationTimeout** 时,**externalEvaluation** 需要为 **true**。如果有两个对等或点对主机要求,你仍然应将 **externalEvaluation** 设置为 **false**,以便让会话自动完成初始化。

**membersNeededToStart**

* 这是需要存在并通过 QoS 才能使自动评估成功的成员保留的最小数量,这些保留具有 "initialize":"true"。

### 初始化情节

设置 **memberInitialization** 对象时,MPSD 将按情节推进初始化阶段。
第一个情节在创建会话时启动,将包括模板中定义的所有阶段。

在情节已在运行时被邀请或加入的任何新成员将被标记用于下一个情节。
一般而言,情节或 **memberInitialization** 的状态可以从会话的 **initializing** 对象中检索。

**注意** 请注意,此对象在初始化完成后会被删除。

示例:

```json theme={null}
"initializing": {
    "stage": "measuring",
    "stageStartTime": "2009-06-15T13:45:30.0900000Z",
    "episode": 1
},

```

阶段从加入到测量再到评估。
如果情节失败,则将阶段设置为 *failed*,无法初始化会话。
否则,当初始化情节完成时,**initializing** 对象将被删除。

还可以为每个成员跟踪初始化失败。
如果该成员未通过,则在退出加入或测量阶段时设置。

示例:

```json theme={null}
"initializationFailure": "latency",
```

按优先级顺序,此属性的值可以设置为 *timeout、latency、bandwidthdown、bandwidthup、network、group* 或 *episode*。
network 值表示网络配置和/或条件(如冲突的网络地址转换 \[NAT])阻止了 QoS 指标的测量。

在加入结束时唯一可能的值是 *group*。
(在加入超时时,保留将被删除。)

如果设置了 **memberInitialization** 并且成员是使用 "initialize": true 添加的,则将其设置为成员将参与的初始化情节。对于在创建时添加到新会话的成员,使用值 1,当初始化情节结束时将其删除。

```json theme={null}
"initializationEpisode": 1,
```

## 匹配票证会话

当 MPSD 会话用作匹配票证会话时,将使用一些特殊的会话属性和常量。

**/members/{index}/constants/system**

```json theme={null}
{

  {
  "xuid": "12345678",

  "initialize": "false", // Run initialization for this user (if "memberInitialization" is set). Defaults to false.

```

当 Matchmaking 服务将用户添加到会话时,它会在 **matchmakingResult** 字段中提供有关他们如何以及为何被匹配到该会话中的一些上下文。

```json theme={null}
"matchmakingResult": {
```

这是用户来自对战匹配会话的 **serverMeasurements** 的副本。

```json theme={null}
"serverMeasurements": {
    "east.thunderhead.azure.com": {
        "latency": 233  // Milliseconds
      }
    }
  }
}

```

## 服务质量 (QoS) 模板

对于游戏会话模板,可以添加告知 MPSD 与网络层和主机社交功能协调的值。
这种协调的目的是在创建会话之前以及在告知用户游戏已准备好加入之前验证连接状态的质量。

以下代码摘录是带有 QoS 的点对主机游戏会话模板的示例:

```json theme={null}
{
    "constants": {
        "system": {
            "version": 1,
            "maxMembersCount": 20,
            "visibility": "private",
            "capabilities": {
                "connectivity": true
            },
            "memberInitialization": {
                "joinTimeout": 20000,
                "externalEvaluation": false,
                "membersNeededToStart": 1
            },
            "peerToHostRequirements": {
                "latencyMaximum": 350,
                "bandwidthDownMinimum": 1000,
                "bandwidthUpMinimum": 100,
                "hostSelectionMetric": "latency"
            }
        },
        "custom": {}
    }
}
```

以下代码摘录是带有 QoS 的对等游戏会话模板的示例:

```json theme={null}
{
    "constants": {
        "system": {
            "version": 1,
            "maxMembersCount": 20,
            "visibility": "private",
            "capabilities": {
                "connectivity": true
            },
            "memberInitialization": {
                "joinTimeout": 20000,
                "externalEvaluation": false,
                "membersNeededToStart": 1
            },
            "peerToPeerRequirements": {
                "latencyMaximum": 250,
                "bandwidthMinimum": 10000
            }
        },
        "custom": {}
    }
}

```

### QoS 会话模板属性

如果设置了 **memberInitialization** 对象,则会话期望客户端系统或游戏在会话创建后和/或新成员加入会话时执行初始化。

会话会自动跟踪超时和初始化阶段,如果设置了任何指标,还包括 QoS 测量。

对于设置了 **initializationEpisode** 属性的成员,这些超时会覆盖会话的保留和就绪超时。

```json theme={null}
"memberInitialization": {
"joinTimeout": 5000,  // Milliseconds. Unspecified counts as 10 seconds.
"measurementTimeout": 5000,  // Milliseconds. Unspecified counts as 30 seconds.
"evaluationTimeout": 5000,  // Milliseconds. Can only be set if 'externalEvaluation' is true. Unspecified counts as 5 seconds.
"externalEvaluation": true,
"membersNeededToStart": 2  // Unspecified counts as 1. Must be between 0 and maxMembersCount. Only applies to episode 1. If 0 and the session is created with no members to initialize, episode 1 is skipped.
},

```

带有 QoS 的游戏会话需要连接能力。
如果未指定指标,则默认为满足 QoS 要求所需的指标。
如果指定,则必须足以满足 QoS 要求。

```json theme={null}
"metrics": {
    "latency": true,
    "bandwidthDown": true,
    "bandwidthUp": true,
    "custom": true

```

以下阈值适用于会话中所有成员的每个成对连接:

```json theme={null}
"peerToPeerRequirements": {
    "latencyMaximum": 250,  // Milliseconds
    "bandwidthMinimum": 10000  // Kilobits per second
},

```

以下阈值适用于来自主机候选者的每个连接:

```json theme={null}
"peerToHostRequirements": {
    "latencyMaximum": 250,  // Milliseconds
    "bandwidthDownMinimum": 100000,  // Kilobits per second
    "bandwidthUpMinimum": 1000,  // Kilobits per second
    "hostSelectionMetric": "bandwidthup"  // Or "bandwidthdown" or "latency". Not specified is the same as "latency".
},

```

应评估以下潜在的服务器连接字符串(请注意,连接字符串必须为小写):

```json theme={null}
"measurementServerAddresses": {
        "east.thunderhead.azure.com": {
            "secureDeviceAddress": "r5Y="  // Base-64 encoded secure-device-address
        },
        "west.thunderhead.azure.com": {
            "secureDeviceAddress": "rwY="
        }
    }
}

```

**members/{index}/properties/system**

这些标志控制成员状态和 **activeTitle**,并且它们互斥(将两者都设置为 **true** 是错误的)。
对于每个,**false** 与"不存在"相同。默认状态是"非活动",即两者都不存在。

```json theme={null}
"ready": true,
"active": false,

// Base-64 blob, or not present. Empty-string is the same as not present.
// 'capabilities/connectivity' must be enabled in order for this to be set.
"secureDeviceAddress": "ryY=",

// List of members in my group, by index. Each element must be an integer 0 <= n < 'membersInfo/next'.  
// During member initialization, if any members in the list fail, this member will also fail.
"group": [ 5 ],

// QoS measurements by lower-case device token.
// Like all fields, "measurements" must be updated as a whole. It should be set once when measurement is complete, not incrementally.
// Metrics can me omitted if they weren't successfully measured, i.e. the peer is unreachable.
// If a "measurements" object is set, it can't contain an entry for the member's own address.
"measurements": {
"e69c43a8": {
"latency": 5953,  // Milliseconds
"bandwidthDown": 19342,  // Kilobits per second
"bandwidthUp": 944,  // Kilobits per second
"custom": { }
     }
},

// QoS measurements by game-server connection string. Like all fields, "serverMeasurements" must be updated as a whole, so it should be set once when measurement is complete.
// If empty, it means that none of the measurements completed within the "serverMeasurementTimeout".
    "serverMeasurements": {
        "east.thunderhead.azure.com": {
            "latency": 233  // Milliseconds
        }
    },

// Subscriptions for shoulder taps on session changes. The 'profile' indicates which session changes to tap as well as other properties of the registration like the min time between taps.
// The subscription is named with a client-generated GUID that is also sent back with the tap as a context ID.
// Subscriptions can be added and removed individually, without affecting other subscriptions in the "subscriptions" object.
// To remove a subscription, set its context ID to null.
// (Like the "ready" and "active" flags, the "subscriptions" data is copied out and maintained internally, so the normal replace-all rule on system fields doesn't apply to "subscriptions".)
"subscriptions": {
"961dc162-3a8c-4982-b58b-0347ed086bc9": {
"profile": "party",  // Or "matchmaking", "initialization", "roster", "queueHost", or "queue"
"onBehalfOfTitleId": "3948320593",  // Optional decimal title ID of the registered channel.  If not set the title ID is taken from the token.
},
"709fef70-4638-4b94-905b-24cb02706eb5": null
}
}

```

## QoS 阶段和会话初始化详细信息

模板完成成员初始化后,MPSD 将跟踪并报告游戏创建的 QoS 结果。
此操作的进度将由会话文档中的 *initializing* 对象表示,如上文[成员初始化](#_Member_initialization_in)一节所述。

*initializing* 对象具有 *stage* 属性,表示初始化的当前阶段。
阶段从 *joining* 进展到 *measuring* 再到 *evaluating*。

* 如果初始化情节 #1 失败,则将阶段设置为 *failed*,无法初始化会话。否则,当初始化情节完成时,将删除 "initializing" 对象。如果 **externalEvaluation** 设置为 **false**,则跳过评估阶段。如果既未设置 **metrics** 也未设置 **measurementServerAddresses**,则跳过测量阶段。

```json theme={null}
"initializing": {
    "stage": "measuring",
    "stageStartTime": "2009-06-15T13:45:30.0900000Z",
    "episode": 1
},

```

* 主机候选者是按优先级顺序列出的设备令牌。如果设置了 **peerToHostRequirements** 且未设置 **/properties/system/host**,则在初始化情节 #1 的 *measuring* 阶段之后设置它们。它们在设置 **/properties/system/host** 对象后被清除。

```json theme={null}
"hostCandidates": [ "ab90a362", "99582e67" ],

"constants": { /* Property Bag */ },
"properties": { /* Property Bag */ },
"members": {
    "1": {
        "constants": { /* Property Bag */ },
        "properties": { /* Property Bag */ },

```

* *gamertag* 属性仅在成员已接受且找到该成员的玩家代号声明时才会设置。

```json theme={null}
"gamertag": "stacy",
```

* *deviceToken* 属性在成员上传安全设备地址时设置。它是一个不区分大小写的字符串,可用于相等性比较。

```json theme={null}
"deviceToken": "9f4032ba7",
```

* *reserved* 值在用户对会话文档执行第一个 PUT 请求后被删除。当玩家被保留时,这意味着他们已被邀请加入游戏会话,但既未接受,其连接也未被评估。

```json theme={null}
"reserved": true,
```

* 如果成员处于活动状态,*activeTitleId* 是成员活跃的游戏,以十进制表示。

```json theme={null}
"activeTitleId": "8397267",
```

* 此属性指的是用户加入会话的时间。如果 *reserved* 为 **true**,则 *joinTime* 将是保留的时间。

```json theme={null}
"joinTime": "2009-06-15T13:45:30.0900000Z",
```

* 如果此成员在 properties/system/turn 数组中则存在,否则不存在。

```json theme={null}
"turn": true,
```

* 如果成员未成功通过阶段,则在退出加入或测量阶段时,在成员对象上设置 *initializationFailure* 属性。按优先级顺序,可以将其设置为 *timeout*、*latency*、*bandwidthdown*、*bandwidthup*、*network*、*group* 或 *episode*。
  *network* 值表示网络配置和/或条件(如冲突的网络地址转换 \[NAT])阻止了 QoS 指标的测量。在加入结束时唯一可能的值是 *group*。(在加入超时时,保留将被删除。)*episode* 值在评估阶段失败后,在初始化情节中没有在加入或测量期间失败的所有成员上设置。

```json theme={null}
"initializationFailure": "latency",
```

* 如果设置了 **memberInitialization** 并且成员是使用 "initialize": true 添加的,则将其设置为成员将参与的初始化情节。对于创建时添加到新会话的成员,使用值 1。初始化情节结束时删除。

```json theme={null}
"initializationEpisode": 1,
```

* *next* 属性表示会话中下一个成员的索引值。如果没有更多成员要添加,它将与下面 **membersInfo** 对象中的 *next* 属性具有相同的值。

```json theme={null}
            "next": 4
        },
        "4": { "next": 5 /* etc */ }
    },
    "membersInfo": {
        "first": 1,  // The first member's index.
        "next": 5,  // The index that the next member added will get.
        "count": 2,  // The number of members.
        "accepted": 1  // The number of members that are no longer 'pending'.
    },
    "servers": {
        "name": {
            "constants": { /* Property Bag */ },
            "properties": { /* Property Bag */ }
        }
    }
}

```

## XBOX 云计算会话(已弃用)

XBOX 云计算会话包含会话可用于连接到游戏服务器的不区分大小写连接字符串的有序列表。
通常,游戏应使用列表中的第一个字符串,但复杂的游戏可能使用自定义机制来选择其他字符串之一(例如,基于负载)。

```json theme={null}
    "serverConnectionStringCandidates": [ "west.thunderhead.azure.com", "east.thunderhead.azure.com" ],

    "matchmaking": {
        "clientResult": {  // Requires the clientMatchmaking property.
            "status": "searching",  // Or "expired", "found", "failed", or "canceled".
            "statusDetails": "Description",  // Default is empty string.
            "typicalWait": 30,  // The expected number of seconds waiting as a non-negative integer.
            "targetSessionRef": {
                "scid": "1ECFDB89-36EB-4E59-8901-11F7393689AE",
                "templateName": "capture-the-flag",
                "name": "2D58F65F-0E3C-4F1F-8277-2BC9873FDB23"
            }
        },

        "targetSessionConstants": { },

        // Force a specific connection string to be used (useful in preserveSession=always cases).
        "serverConnectionString": "west.thunderhead.azure.com",

        // True if the match that was found didn't work out and needs to be resubmitted. Set to false
        // to signal that the match did work, and the matchmaking service can release the session.
        "resubmit": true
    }
}

```

\*\*/servers/{server-name}/properties/system \*\*

```json theme={null}
{
    "lockId": "opaque56789",  // If set, a matchmaking service is servicing this session.
    "status": "searching",  // Or "expired", "found", "failed", or "canceled". Optional.
    "statusDetails": "Description",  // Optional free-form text. Default is empty string.
    "typicalWait": 30,  // Optional. The expected number of seconds waiting as a non-negative integer.
    "targetSessionRef": {  // Optional.
        "scid": "1ECFDB89-36EB-4E59-8901-11F7393689AE",
        "templateName": "capture-the-flag",
        "name": "2D58F65F-0E3C-4F1F-8277-2BC9873FDB23"
    }
}

```

## 原始会话和自定义游戏属性

会话可用于存储多人游戏的自定义管理信息(元数据)。
游戏数据或保存的信息应存储在 TMS++ 中。

### 属性包

上述每个标记为属性包的对象由两个可选的内部对象组成:system 和 custom。

自定义对象可以包含任何 JSON。

```json theme={null}
"custom": {
    "myField1": true,
    "myField2": "string",
    "myField3": 5.5,
    "myField4": { "myObject": null },
    "myField5": [ "my", "array" ]
}

```

## 活动成员衰减

当 MPSD 检测到用户不再参与游戏时,活动成员会自动标记为非活动。
例如,如果 Presence 使用户记录超时,则可能会发生这种情况。

此机制只是后备;也就是说,游戏仍然需要在成员离开或切换离开游戏、注销或以其他方式变得不参与时,主动将成员标记为非活动(或将其从会话中删除)。

## 常见问题和故障排除

### 如何调用 MPSD?

使用证书身份验证:client-sessiondirectory.xboxlive.com

示例:

```uri theme={null}
PUT https://client-sessiondirectory-stress.xboxlive.com/serviceconfigs/8cvda84-2606-4bab-8eda-d12313e65143/sessiontemplates/teamDeathmatch/sessions/3baafc35-816d-49cd-9656-5772506c988a
```

使用 XToken 身份验证:sessiondirectory.xboxlive.com

示例:

```uri theme={null}
PUT https://sessiondirectory-stress.xboxlive.com/serviceconfigs/8cvda84-2606-4bab-8eda-d12313e65143/sessiontemplates/teamDeathmatch/sessions/3baafc35-816d-49cd-9656-5772506c988a
```

### 如何找出要使用的 SCID、会话模板和沙盒?

此信息可以在 Partner Center 上你的游戏页面找到。
如果你尚未获得 Partner Center 的访问权限,请联系你的开发人员帐户经理,他可以协助你获取信息。

### 是否有可以与我自己的请求正文进行比较的示例?

### 调用 MPSD 时收到 404 错误。

收集 Fiddler 跟踪以获取更多信息,然后执行以下操作:

1. 检查作为 HttpResponse 正文一部分返回的消息,查找常见的 404 消息:

   * *The requested service config is either invalid or not configured for sessions*。验证正在使用的 SCID 是否正确。

   * *The requested session wasn't found*。在检索之前,验证会话已创建且会话模板正确。你可以使用 PUT 调用创建会话。

2. 检查你正在使用的 URI。

3. 重新启动主机和/或尝试使用新用户。

### 调用 MPSD 时收到 403 错误。

这通常是权限或范围问题。
收集 Fiddler 跟踪以获取更多信息,然后执行以下操作:

1. 检查作为 HttpResponse 正文一部分返回的消息,查找常见的 403 消息:

* *The requested service config cannot be accessed.*

  * 验证你使用的是有权访问该沙盒的帐户。

  * 验证你处于正确的沙盒中。

  * 如果你正在使用证书身份验证并收到此错误,请联系你的 DAM。

* *The requested session cannot be accessed. Private Sessions can only be read by members of the session.*

  * 你正在尝试访问可见性为 "private" 的会话。只有会话中的成员才能读取会话文档。

* *The request body can't contain existing member references unless the authentication principal includes a server.*

  * 你不能代表用户将另一个用户加入会话。你只能邀请。将索引设置为 "reserve\_\<number>" 以邀请玩家。

### 我收到 412 Precondition Failed 错误。

如果会话已存在,将返回 412 Precondition Failed:

```http theme={null}
> PUT /serviceconfigs/00000000-0000-0000-0000-000000000000/sessiontemplates/quick/sessions/foo HTTP/1.1
> Content-Type: application/json
> If-None-Match: \*
```

如果会话 etag 与 If-Match 标头不匹配,将返回 412 Precondition Failed:

```http theme={null}
> PUT /serviceconfigs/00000000-0000-0000-0000-000000000000/sessiontemplates/quick/sessions/foo HTTP/1.1
> Content-Type: application/json
> If--Match: 9555A7DE-8B91-40E4-8CFB-0629312C9C7D
```

### 调用 MPSD 时收到诸如 405、409、503 和 400 之类的错误。

收集 Fiddler 跟踪以获取更多信息,然后检查作为 HttpResponse 正文一部分返回的消息。

如果你使用的是 XSAPI,也可以通过将 [HCSettingsSetTraceLevel](/zh-CN/reference/live/httpclient/trace/functions/hcsettingssettracelevel) 属性设置为 [HCTraceLevel](/zh-CN/reference/live/httpclient/trace/enums/hctracelevel)::Information 来获取响应正文,如果设置了 [HCTraceSetTraceToDebugger](/zh-CN/reference/live/httpclient/trace/functions/hctracesettracetodebugger),这将在调试输出中输出信息,或者你可以使用 [HCTraceSetClientCallback](/zh-CN/reference/live/httpclient/trace/functions/hctracesetclientcallback) 获取回调,你可以在其中将跟踪日志添加到游戏自己的跟踪日志记录中。你还可以使用 [XblAddServiceCallRoutedHandler](/zh-CN/reference/live/xsapi-c/xbox_live_global_c/functions/xbladdservicecallroutedhandler) 为每次服务调用调用,你可以将其路由到自己的日志记录。

### 我可以或应该在游戏的模板中更改什么?

会话模板不是默认值,而更像是一个模具。
但是,你不能覆盖模板中已设置的常量,尽管你可以向其添加内容。

### 我收到错误消息,称我的会话未初始化。

当模板中存在成员初始化(通常是游戏、聚会和匹配票证方案)时,你需要确保为足够多的成员保留(启动所需的成员)设置 "initialize=true",以通过 QoS 来解决此问题。

### 我的会话未被创建,并且我收到 HTTP 204 错误。

这表示在你创建会话时没有向其添加用户。
如果在创建时会话没有用户,则不会创建会话。

请确保在创建时至少将一个玩家添加到会话。

对于专用服务器方案,获取正在尝试创建匹配或需要创建匹配的玩家,并使该用户成为该匹配中的初始玩家。
或者,你可以更改或删除 **sessionEmptyTimeout**。

### 我应该何时轮询 MPSD?

你应该避免轮询 MPSD 会话。
从较高的层面来看,你可以通过设计代码,让 MPSD 会话仅用于为每个客户端初始建立网络连接,以及为丢失连接的一个或多个客户端重新建立网络状态。

同样重要的是利用 MPSD 基于 etag 的同步原语,以消除刷新会话状态以解决竞争条件的需要。

这些原则的一个常见应用是当你有一组 N 个客户端都需要连接在一起并在对等网状网络中玩游戏时。
每个成员可以加入会话,连接到已经在会话中的成员,并假设任何后来的加入者都会执行相同的操作,而不是定期查询会话中的新成员。有关如何实现这一点的示例,请参阅 Chat and Player Rendezvous 示例。

在极少数情况下,可能需要短时间轮询;如果你认为需要这样做,请联系你的开发人员帐户经理。


## Related topics

- [多人游戏会话目录 (MPSD)](/zh-CN/services/xbox-services/multiplayer/mpsd/live-mpsd-nav.md)
- [多人游戏会话目录 (MPSD) 概念（目录）](/zh-CN/services/xbox-services/multiplayer/mpsd/concepts/live-mpsd-concepts-nav.md)
- [多人游戏会话目录概述](/zh-CN/services/xbox-services/multiplayer/mpsd/live-mpsd-overview.md)
- [多人游戏会话目录 (MPSD) 示例代码](/zh-CN/services/xbox-services/multiplayer/mpsd/how-to/live-mpsd-howto-nav.md)
- [XBOX services 多人游戏概述](/zh-CN/services/xbox-services/multiplayer/overviews/live-multiplayer-intro.md)
