> ## 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) 配合的 S2S 调用模式，通过业务合作伙伴身份验证从游戏服务器管理 XBOX Live 会话。

本主题介绍如何将服务到服务 (S2S) 调用模式与多人游戏会话目录 (MPSD) 配合使用。

与其他服务一样，MPSD 支持 S2S 调用模式。这些模式扩展了客户端调用模式，允许游戏服务通过单次服务调用高效管理多个用户。

通过游戏服务而非客户端来管理多人游戏会话，可以简化错误处理逻辑，并避免会话写入操作的争用条件。这尤其适用于具有大量会话成员的大型会话类型。因此，对于大型多人在线游戏 (MMO) 和一个会话中包含许多玩家的游戏，最佳做法是通过游戏服务器管理 MPSD 会话。

有关 RESTful MPSD 调用模式的一般信息，请参阅 [XBOX services RESTful 参考](/reference/live/rest/atoc-xboxlivews-reference)。

## MPSD S2S 身份验证

XBOX services 多人游戏服务的 S2S 调用身份验证与其他 XBOX services 不同。不支持使用 `Delegation` 令牌的调用，只有使用服务身份验证的调用才能正常工作。这种身份验证类型可启用额外的 MPSD S2S 功能。

与其他 S2S 调用一样，需要业务合作伙伴证书。必须配置完全访问权限的 `Multiplayer.Manage` 策略。这是必需的，以便创建业务合作伙伴证书的 Web 服务能够为 S2S 调用提供正确的访问级别。

服务身份验证使用以下身份验证流程。

1. 使用业务合作伙伴证书调用 XBOX 服务授权服务，以检索 `S` 令牌。

2. 使用此 `S` 令牌和 `SandboxId` 调用 XBOX 安全令牌服务 (XSTS)，以接收 `X` 令牌。此步骤中不得使用 `Delegation` 令牌或 `User` 令牌。通过此流程指定的 `SandboxId` 还必须包含在创建业务合作伙伴证书期间指定的沙盒集合中。不支持没有特定沙盒的业务合作伙伴证书，将导致指示缺少沙盒的身份验证错误。

3. 使用 `X` 令牌和标头（如下一节所述）调用 MPSD 服务。

## MPSD S2S 标头

### 标题标头

要作为正确的游戏执行操作，需要使用以下格式的 `X-Xbl-OnBehalfOf-Title` 标头。

```json theme={null}
X-Xbl-OnBehalfOf-Title:[titleid in decimal]
```

#### 示例

```json theme={null}
Request.Headers["X-Xbl-OnBehalfOf-Title"] = "484921321";
```

必须指定此标头才能针对特定游戏进行调用。

### 用户标头

要作为特定用户或一组用户执行操作，需要使用以下格式的 `X-Xbl-OnBehalfOf-Users` 标头。

```json theme={null}
X-Xbl-OnBehalfOf-Users:[xuid][;privilege][,xuid[;privilege]]...
```

#### 示例

```json theme={null}
Request.Headers["X-Xbl-OnBehalfOf-Users"] = "741837829132;priv=multiplayer","8922333146718;priv=multiplayer"
```

当前唯一支持的权限是 `priv=multiplayer`。它表示用户拥有多人游戏权限。

使用 `X-Xbl-OnBehalfOf-Users` 标头时，就像标头中标识的用户直接从其控制台发出调用一样。因此，调用服务需要维护用户的安全性。

* 只能使用真实的 XUID。
* 为用户声明的权限必须正确。
* 用户必须已同意代表其执行的任何操作。

最后一个要求意味着该服务被允许执行只有控制台游戏本身才能执行的操作。

例如，仅当用户实际正在控制台上运行并与该游戏交互时，服务才能将用户设置为在游戏中处于活动状态。当用户不再在控制台上与游戏交互时，服务必须将用户设置为非活动状态。同样，只有当用户已采取明确操作发送邀请时，服务才能代表用户发送邀请。

### Deny-Scope 标头

`Multiplayer.Manage` 访问策略会覆盖 MPSD 服务 S2S 调用的用户访问权限。因此，任何会话访问都不会根据用户权限受到限制。要重新启用用户权限检查，可以使用 `X-Xbl-Deny-Scope` 标头，如下所示。

```json theme={null}
    X-Xbl-Deny-Scope: Multiplayer.Manage
```

#### 示例

```json theme={null}
    Request.Headers["X-Xbl-Deny-Scope"] = "Multiplayer.Manage";
```

此标头确保在检查用户对会话的访问权限（从用户标头）时，不会将 `Multiplayer.Manage` 访问策略用作覆盖。它可用于确保用户对会话具有正确的访问权限，并且服务器访问不会因可见性或加入限制而覆盖任何其他阻止。

<Note>设置此标头时，还必须为 Web 服务授予 `Multiplayer.Runtime` 访问权限作为后备。这允许访问，即使用户权限被拒绝。否则，在错误场景下不会授予任何服务访问权限，并返回 403 状态。`Multiplayer.Runtime` 访问需要执行操作的用户。`X-Xbl-Deny-Scope` 标头只能与 `X-Xbl-OnBehalfOf-Users` 或从 `DelegationToken` 声明中获取的用户声明一起使用。</Note>

### 会话成员管理

您可以通过在一次调用中处理多个用户来优化 S2S 调用的会话成员管理。

指定用户标头时，无法使用会话文档正文中的标准 "me" 成员。相反，可以使用以下选项。

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

        // (For example, me_59135345328) Requires a user principal with an xuid claim.
        "me_{xuid}": {
            "constants": { /* Property Bag */ },
            "properties": { /* Property Bag */ },
        },

        // Applies the requested change to each acting user's member.
        "me_all": {
            "constants": { /* Property Bag */ },
            "properties": { /* Property Bag */ },
        },

        // Applies the requested change to each acting user's member if they're 
        // already in the session.
        "me_allInSession": {
            "constants": { /* Property Bag */ },
            "properties": { /* Property Bag */ },

        // Requires a single user principal with an xuid claim.
        "me": {
            "constants": { /* Property Bag */ },
            "properties": { /* Property Bag */ },
        },

        }
    }
}
```

游戏服务应使用这些模式，通过单次 MPSD 调用对多个用户执行操作（例如添加或删除玩家）。

### 添加会话成员

您可以使用前面提到的模式之一添加或修改会话成员。通常，添加玩家的最低操作是设置一个属性或常量，通常是成员的活动状态属性。

<Note>未设置为活动状态的成员会由服务自动删除，该服务依赖 MPSD 会话的 `InactiveTimeout` 值。</Note>

您应通过同一次调用（根据需要）为用户设置其他必需的属性和常量。

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

        "me_{xuid}": {
            "constants": { /* Property Bag */ },
            "properties": { "system": { "active": true } 
                            /* Additional Properties */ },
        }
    }
}
```

#### 示例

```json theme={null}
{
     // Adding two session members with one call.
    "members": {

        "me_1234567890123456": {
            "properties": { "system": { "active": true }},
        },

        "me_2345678901234567": {
            "properties": { "system": { "active": true }},        
        } 
    }
}
```

### 删除会话成员

您可以通过将成员部分设置为 `null` 来删除会话成员。

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

        "me_{xuid}": {
            null,
        }
    }
}
```

#### 示例

```json theme={null}
{
     // Removing two session members with one call.
    "members": {

        "me_1234567890123456": {
            null,
        },

        "me_2345678901234567": {
            null,
        } 
    }
}
```

### 成员预留

一般来说，如果所有会话管理都由游戏服务执行，则不需要为会话成员预留席位。在这种情况下，您可以直接添加和删除会话成员，而无需预留。只有当创建的会话之后还由客户端管理时，才应使用会话成员的预留。

您可以按 `on-behalf-of-user` 标头中指定的用户顺序，为会话中的多个用户添加预留。以下模式仅在创建新会话时有效。

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

        // Reservation requests must start with zero.
        "reserve_0": {
            "constants": { "system": {"xuid": "{xuid}" }
                           /* additional constants */ }
        },

        "reserve_1": {
            "constants": { "system": {"xuid": "{xuid}" }
                           /* additional constants */ }
        },

        //...//

    }
}
```

#### 示例

```json theme={null}
{
     // Adding reservations for two session members with one call.
    "members": {

        "reserve_0": {
            "constants": { "system": {"xuid": "1234567890123456" }}
        },

        "reserve_1": {
            "constants": { "system": {"xuid": "2345678901234567" }}
        },
    }
}
```

<Note>大型会话不支持预留。不支持混合使用预留与添加或删除会话成员。</Note>

### 会话成员状态

游戏服务可以通过系统属性跟踪和设置会话成员的状态。这允许完全控制成员状态和信息。

### 成员活动状态

成员的活动状态是将玩家在会话中标记为活动状态。这可防止系统按照 `inactiveRemovalTimeout` 会话配置中的定义删除该成员，如下所示。

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

        // Member access through XUID.
        "me_{xuid}": {
            "properties": { "system": {"active": [true|false] }
                           /* additional constants */ }
        }
    }
}
```

一般情况下，添加会话成员时始终应将其设置为 `active`。仅在会话成员应临时留在会话中的流程中使用非活动成员，即使他们已断开连接。对于 S2S 流程，这也可以直接在游戏服务器中管理。

### 成员预留状态

您可以通过 `reserved member` 属性确定会话成员的预留状态。如果此属性设置为 `true`，则该会话成员处于预留状态，尚未在会话中激活。

以下是一个会话文档示例。

```json theme={null}
{
    /.../

    "members": {

        // First session member as an example.
        "1": {
            "constants": { /* Property Bag */ },
            "properties": { /* Property Bag */ },

            /.../

            "reserved": true,
            /.../
        }
    }
}
```

在 `reservedRemovalTimeout` 到期后，这些成员会由 MPSD 从会话中删除。

## 大型会话限制

启用大型功能的 MPSD 会话支持超过 100 名玩家。这些会话的功能与常规会话不同。有关详细信息，请参阅 [为多人游戏启用大型会话](/services/xbox-services/multiplayer/mpsd/concepts/live-large-sessions)。

对大型会话的操作始终作为单个用户执行。因此，对大型会话的 S2S 调用必须在 `X-Xbl-OnBehalfOf-Users` 标头中仅包含单个用户。不支持多用户操作。您必须为每个用户通过单独的调用添加或删除用户。按顺序执行这些 S2S 调用，以避免底层会话文档的锁定拥塞。对同一文档的并行操作会导致更长的调用时间，并不会加快总操作时间。

S2S 调用结果也无法访问大型会话的完整成员列表。仅返回调用中指定的用户的成员数据。

因此，游戏服务应在自己的逻辑中跟踪大型会话成员的用户信息，并使用 MPSD 成员资格来正确支持 XBOX 要求 (XR)。

### 遭遇和分组

启用大型功能的会话不会自动更新最近玩家列表。相反，其他玩家通过遭遇和分组直接添加到最近玩家列表中。有关更多详细信息，请参阅 [为多人游戏启用大型会话](/services/xbox-services/multiplayer/mpsd/concepts/live-large-sessions)。

使用以下模式将会话成员标记为遭遇的一部分。

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

        "me_{xuid}": {
            "properties": { 
                "system": { 
                    "encounters": [ "{uniqueEncounterID1}", 
                                    "{uniqueEncounterID2}",
                                    // ... //
                                  ] },
        }
    }
}
```

#### 示例

```json theme={null}
{
     // Marking two members as part of the same encounter.
    "members": {

        "me_1234567890123456": {
            "properties": {
                "system": {
                    "encounters": [ "757093D8-E41F-49D0-BB13-17A49B20C6B9" ] }},
        },

        "me_2345678901234567": {
            "properties": {
                "system": {
                    "encounters": [ "757093D8-E41F-49D0-BB13-17A49B20C6B9" ] }},
        },
    }
}
```

<Note>为了正确捕获遭遇，必须在 30 秒内将 `encounters` 属性写入所有参与的会话成员。遭遇集合是一个即时属性。它会立即被消费，并且在响应中不可见。</Note>

使用以下模式将会话成员标记为分组的一部分。

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

        "me_{xuid}": {
            "properties": { 
                "system": { 
                    "groups": [ "{uniqueGroupID1}", 
                                "{uniqueGroupID2}",
                                // ... //
                              ] },
        }
    }
}
```

#### 示例

```json theme={null}
{
     // Marking two members as part of the same group.
    "members": {

        "me_1234567890123456": {
            "properties": { 
                "system": { 
                    "groups": [ "group-ADFB431" ] }},
        },

        "me_2345678901234567": {
            "properties": { 
                "system": { 
                    "groups": [ "group-ADFB431" ] }},
        },
    }
}
```

每次写入操作都会替换分组列表。要从分组中删除成员，请从 `groups` 属性列表中删除该分组。带有空列表的写入操作会删除所有分组成员资格。

<Note>`groups` 属性是持久的，并在成员的响应中可见。</Note>

### 活动会话管理

用户的 MPSD 活动句柄决定了哪个会话用于平台邀请和加入正在进行的游戏。此句柄无法通过 S2S 调用设置，仅通过客户端 API 提供。游戏服务器可以与客户端共享会话名称，以便为 S2S 会话启用活动句柄创建。

有关句柄的更多信息，请参阅以下内容：

* 多人游戏概念概述主题中的 [会话句柄](/services/xbox-services/multiplayer/concepts/live-multiplayer-concepts#session-handles) 部分
* 多人游戏会话目录概述主题中的 [MPSD 会话句柄](/services/xbox-services/multiplayer/mpsd/live-mpsd-overview#mpsd-handles-to-sessions) 部分

要直接控制玩家活动，请参阅 [多人游戏活动服务 (MPA)](/services/xbox-services/multiplayer/mpa/live-mpa-overview)。请注意，MPA 和 MPSD 不能同时使用。

## 最佳实践

执行 MPSD S2S 调用时，游戏应遵循以下最佳实践以避免问题并提高性能。

* **合并多个用户的操作**
  只要有可能，对 MPSD 的 S2S 调用应作为多个用户的批量操作执行。这可以提高性能并减少网络流量。减少调用的一种有效方法是在游戏服务器上排队 MPSD 操作，并以五秒为间隔合并所有请求。这在效率和延迟之间提供了平衡。

* **合并多个会话和成员操作**
  游戏应确保尽可能合并用户操作。添加会话成员时应始终同时设置所有相关的成员属性。

* **对同一文档按顺序执行 S2S 调用**
  对同一 MPSD 文档的所有调用都应按顺序执行。执行并行操作可能会导致底层 MPSD 文档的锁定拥塞，并导致性能下降和请求失败。

* **在客户端响应句柄活动操作**
  MPSD 活动句柄仅通过客户端 API 支持。游戏服务必须使用客户端通过共享会话名称并使用相关的客户端 API 来创建这些句柄。

* **不需要客户端会话订阅和连接**
  对于所有完全通过 S2S 调用管理的 MPSD 会话，不需要连接功能。对于 S2S 调用流程，不需要与客户端建立 WebSocket 连接。相反，游戏服务应完全处理直接添加或删除会话成员的操作。

* **大型会话操作**
  大型会话的 S2S 逻辑必须与小型会话不同处理，因为多成员操作不可用。游戏服务应对同一会话文档的所有操作（包括添加或删除成员）按顺序执行。对于大量成员，这可能会导致成员操作延迟。这种延迟是可以接受的，不会违反平台要求。

  为了简化大型会话的成员逻辑，游戏可以使用 MPSD 会话仅跟踪玩家成员资格，并在内部处理所有其他玩家数据。

  最简单的方法是在服务器启动时为游戏服务器创建大型 MPSD 会话，即使其中没有任何玩家。这需要在 MPSD 会话常量中配置 `sessionEmptyTimeout`，如以下示例所示。

* **大型会话加入正在进行的游戏或邀请**
  大型会话通过 XBOX services 支持加入正在进行的游戏和邀请。对于大多数场景，使用常规会话来支持此功能更简单。此会话可由游戏服务器或客户端控制，应包含加入相关大型会话的信息。

* **大型会话遭遇**
  为确保正确捕获大型会话中的遭遇，所有 `encounters` 成员属性都应在 30 秒内写入。游戏服务应始终尝试将所有参与成员的 `encounters` 属性更新批量合并到单次服务调用中。遭遇必须使用唯一标识符。我们建议使用 GUID。

## S2S 会话模板示例

以下会话模板是通过 S2S 调用控制的会话的起点。

```json theme={null}
{
   "constants": {
        "system": {
            "version": 1,
            // Should be set to the maximum supported player number on the server.
            "maxMembersCount": 50,
            "visibility": "open",
            "inviteProtocol": "game",
            "capabilities": {
                "gameplay": true
            },
            // Optional: allows the session to linger for 60 minutes when it's empty.
            "sessionEmptyTimeout": 3600
        },
        "custom": {}
    }
}
```

## S2S 大型会话模板示例

以下会话模板是采用 S2S 调用流程的大型会话的起点。

```json theme={null}
{
   "constants": {
        "system": {
            "version": 1,
            // Should be set to the maximum supported player number on the server.
            "maxMembersCount": 5000,
            "visibility": "open",
            "capabilities": {
                "large": true,
                "gameplay": true
            },
            // Optional: allows the session to linger for 60 minutes when it's empty.
            "sessionEmptyTimeout": 3600
        },
        "custom": {}
    }
}
```

## 另请参阅

[XBOX services RESTful 参考](/reference/live/rest/atoc-xboxlivews-reference)

[从游戏服务向 XBOX services 发出的调用](/services/xbox-services/fundamentals/s2s-auth-calls/s2s-calls/live-title-service-calls-xbox-live)


## Related topics

- [服务到服务调用模式](/zh-CN/services/xbox-services/fundamentals/s2s-auth-calls/s2s-calls/s2s-call-patterns/live-s2s-call-patterns-nav.md)
- [多人游戏常见问题和故障排除](/zh-CN/services/xbox-services/multiplayer/mpsd/concepts/live-multiplayer-2015-faq.md)
- [多人游戏会话模板](/zh-CN/services/xbox-services/multiplayer/mpsd/concepts/live-session-templates.md)
- [XR-007 跨网络游戏 — 多人游戏实现](/zh-CN/publishing/certification/xr/xr-007-multiplayer.md)
- [跨网络多人游戏实现示例](/zh-CN/services/xbox-services/multiplayer/concepts/live-console-xr007-multiplayer-example.md)
