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

# 用户身份与 XUser

> 用户身份与 XUser

XBOX One 使用 `XUser` 对象管理与游戏交互的用户身份。每个 `XUser` 实例代表一个已登录到游戏的用户。每个用户由 `XUserHandle` 表示。游戏可以使用 `XUserHandle` 完成以下操作。

* 查询 XBOX 服务登录状态。
* 获取用户的 gamertag(玩家代号)。
* 获取用户的玩家头像。
* 确定用户的年龄组。
* 确定用户被允许进行实时通信或参与多人会话的权限。
* 获取已认证的令牌。

## XUser 标识符

与给定的 `XUser` 相关联的有两种不同的标识符:本地 ID 和 XBOX 服务 ID(XUID)。

*本地 ID* 是在游戏会话内伴随用户整个生命周期的标识符。在游戏派生的任何进程之间使用本地 ID,或者在游戏调用 `XLaunchNewGame` 时使用。但是,不要使用<br />本地 ID 跨游戏会话标识用户。

要获取用户的本地 ID,请使用 `XUserGetLocalId` 函数。

*Xbox 服务 ID(XUID)* 是与 XBOX 服务通信或调用游戏可调用 UI(TCUI)时必须使用的标识符。要获取用户的 XUID,请使用 `XUserGetId` 函数。获取 XUID 可能需要用户同意。如果需要该同意但未被授予,则 `XUserGetId` 会返回 E\_GAMEUSER\_RESOLVE\_USER\_ISSUE\_REQUIRED。要解决此问题并收集同意,游戏应调用 `XUserResolveIssueWithUiAsync`。

## XUser 状态

用户可以处于以下三种状态之一:已登录 XBOX 服务、正在从 XBOX 服务注销,或已完全注销。游戏可以使用 `XUserGetState` 函数查询指定用户的此状态。游戏还可以使用 `XUserRegisterForChangeEvent` 函数注册变更通知。

不要根据 `XUser` 状态判断网络连接。如果 `XUserState` 为 `SignedIn`,则表明该用户在某个时间点已通过 XBOX 服务的认证,可以被视为活动用户。然而,网络可能并未连接。

## 向游戏添加或移除用户

与 XBOX One ERA 的模型不同,游戏只能与其通过调用 `XUserAddAsync` 函数请求的用户进行交互。例如,假设主机上有两个用户已登录:用户 A 和用户 B。

1. 有人启动游戏。在此场景中,是谁启动的并不重要。
2. 游戏使用 `XUserRegisterForChangeEvent` 注册用户状态变化。
3. 游戏调用 `XUserAddAsync`,用户 A 登录到游戏。
4. 游戏现在拥有一个代表用户 A 的 `XUserHandle`。
5. 从指南中,用户 B 选择注销。
6. 游戏不会收到登录状态变化事件。游戏从未知晓用户 B。
7. 从指南中,用户 A 选择注销。
8. 游戏首先收到一个变化事件,表明用户 A 正在注销;最终收到另一个不同的事件,表明用户 A 现在已注销。

尽管游戏能够向其游戏中添加用户,但只有几种方式可以通过下列方法之一移除用户。

* 游戏可以使用 `XUserCloseHandle` 函数关闭所有代表该用户的句柄。
* 用户使用指南从主机注销。
* 用户登录到另一台设备。

## 用户类型

XBOX One 支持两种用户类型:XBOX 玩家和访客。

*Xbox 玩家* 在系统上作为用户具有全部功能。他们最初是通过在 Account Picker(系统提供的用于登录用户的 UI)中添加新账户创建的。XBOX 玩家会一直保留在主机上,直到通过 Settings 应用显式移除为止。

*Xbox 访客* 在主机上仅有一个会话。当他们在 Account Picker 中选择以访客身份游玩,并由另一位已登录的 XBOX 玩家做出赞助时被创建。访客会一直保留,直到他们注销、赞助的 XBOX 玩家注销,或主机关闭为止。

希望允许访客的游戏在调用 `XUserAddAsync` 时必须指定 `AllowGuest` 选项。

## 添加用户的模式<a id="pattern_for_adding" />

游戏必须始终尝试建立初始用户。有两种主要方式来实现这一点。

#### 选项 1:在不显示 UI 的情况下尽快确定用户

1. 使用 `AddDefaultUserSilently` 调用 `XUserAddAsync`。此函数会在不显示任何 UI 的情况下尝试确定是谁启动了游戏。
2. 对 `XUserAddAsync` 的调用可能会以 `E\_GAMEUSER\_NO\_DEFAULT\_USER` 失败。如果发生这种情况,则说明游戏首次启动时没有用户登录。要建立初始用户,游戏需要在不使用 `AddDefaultUserSilently` 标志的情况下调用 `XUserAddAsync`。与“静默”选项不同,此调用会确保所有同意相关的问题被完全解决,并且如果调用成功,则用户已登录到 XBOX 服务。游戏可以为该用户创建 XBOX 上下文。

#### 选项 2:允许显示 UI 的情况下确定用户

使用 `AddDefaultUserAllowingUI` 调用 `XUserAddAsync`。就像前一个选项(“静默”)一样,此函数会尝试确定是谁启动了游戏。与前一个选项不同,如果无法确定默认用户,它会显示 UI 以允许玩家登录或选择自己。如果 `XUserAddResult` 成功,则游戏有一个完全登录到 XBOX 服务的用户,游戏可以为该用户创建 XBOX 上下文。

有关演示这些步骤的示例代码,请参见 [如何:登录用户的最佳实践](/build/core-features/common/user/xuser_howto_best_practice_signing_in)。

## 管理 XUserHandle

每个 `XUserHandle` 代表一个用户。然而,可能有多个此类句柄同时代表同一个用户。游戏应遵循以下基本模式。

1. 维护一个 `XUserHandle` 实例的集合,代表游戏关心的用户集合。
2. 通过调用 `XUserRegisterForChangeEvent` 注册 `XUser` 状态变化。当你看到某个用户正在被注销时,更新你的用户集合。
3. 当你从 `XUserAddAsync` 获得新的 `XUserHandle` 时,请务必检查它是否代表一个新用户。你可以直接使用 `XUserCompare` 比较句柄。你也可以通过调用 `XUserGetLocalId` 获得的本地 ID 进行比较。
4. 如果你有多个代表同一用户的 `XUserHandle` 实例,请使用 `XUserCloseHandle` 移除多余的实例。

*本地 ID* 是在游戏会话内伴随用户整个生命周期的标识符。在游戏派生的任何进程之间使用本地 ID,或者在游戏调用 `XLaunchNewGame` 时使用。但是,不要使用本地 ID 跨游戏会话标识用户。


## Related topics

- [GDK 中的用户身份与 XUser API](/zh-CN/build/core-features/common/user/index.md)
- [如何:登录用户的最佳实践](/zh-CN/build/core-features/common/user/xuser_howto_best_practice_signing_in.md)
- [访客用户概述](/zh-CN/build/core-features/common/user/users-guest-overview.md)
- [用户](/zh-CN/build/core-features/common/user/user-toc.md)
- [GDK 快速入门](/zh-CN/services/playfab/sdks/c/quickstart-gdk.md)
