玩家身份认证
1. 概述
本文档详细说明了玩家身份验证的使用方法,这是访问PGOS服务的前提条件。当游戏需要识别玩家身份并管理玩家会话状态时,您需要使用玩家身份验证服务。
完成本教程后,开发人员将了解以下内容:
- 创建玩家会话的流程。
- 如何监控玩家会话事件。
- 如何处理玩家会话异常。
- 如何使用新账号开始新的玩家会话(切换账号)。
2. 基本流程
2.1 时序图
玩家认证服务包含两个部分:
- 玩家身份验证
- 玩家会话状态管理
在使用PGOS服务之前,您需要使用账号服务登录一个身份,然后使用账号提供商返回的open_id和token登录PGOS(创建PGOS玩家会话)。之后,您就可以访问所有PGOS服务。基本流程如下图所示:
2.2 关键字定义
账号提供商:支持玩家登录和认证的账号提供商,常见的账号提供商有PlayFab、INTL、Steam等,游戏一般需要集成其HTTP API或者SDK才能使用其账号服务。 账号提供商有两种类型:
第1类:只支持一个账号平台,以账号提供商Steam为例,其只支持自己的账号平台,即使用账号提供商Steam时只支持Steam账号。
第2类:支持多个账号平台,以账号提供商PlayFab为例,其支持Steam、Google、PSN等账号平台。
账号平台:管理用户账号、身份认证的平台体系,常见的账号平台有Steam、Google、Apple等,一个账号平台可以同时是一个账号提供商,比如Steam。且一个账号提供商可以支持多个账号平台,比如账号提供商 INTL 支持 Steam、Google、XBoxLive 等账号平台。
临时账号服务:提供临时账号服务(FAS),帮助在游戏与真实账号服务对接前,在游戏开发阶段可以使用 FAS 临时替代真实账号服务来访问PGOS服务。
open ID :账号服务提供商提供的用户身份标识。
token:账号服务提供商提供的 open_id 对应的有效 ticket。
player id:PGOS 提供的游戏区服唯一玩家 ID。
player session:游戏客户端与 PGOS 后端之间的会话,玩家会话过期后,游戏客户端将无法访问 PGOS 服务。
3. 使用玩家鉴权
3.1 登录 PGOS
在使用账号服务的身份登录 PGOS 之前,您需要确保已启用相应的鉴权插件。之后,您可以调用 PlayerAuth::LoginPGOS
API 来登录 PGOS 并创建玩家会话。如果登录成功,您就可以访问所有 PGOS 服务;如果登录失败,请查看错误代码和错误信息以了解发生了什么。
3.1.1 登录参数
FClientLoginPGOSParams
结构参数作为登录过程的输入。
struct FClientLoginPGOSParams: public FBaseBackendEventParams
{
int32 account_provider = -1;
FString account_open_id;
FString account_token;
FString title_region_id;
TMap<FString, FString> extra_param;
};
struct FBaseBackendEventParams
{
/**
* [Optional] A game-defined custom value pass to PGOS backend event.
* If you need to get a custom value in the event, pass it in, otherwise, ignore this field.
* The API parameter structures inherited from this structure all support passing a custom data to the related events.
* The size is limited to 4096 bytes in a narrow-character string, if it is a wide-character string, it should be converted to a utf-8 narrow-character string before calculating its length.
* Detail for PGOS backend event: https://pgos.intlgame.com/pgosdoc/manual/service_manual/extensions/event.html.
* Detail for how to reference the 'event_custom_data':https://pgos.intlgame.com/pgosdoc/manual/service_manual/extensions/virtual_server_v2.html#43-the-request-and-response-protocol.
*/
FString event_custom_data;
};
FClientLoginPGOSParams
结构体中的字段:
- account_provider: 账号服务提供商,游戏客户端使用其 SDK/API 进行账号登录。默认值为 -1(未设置),此时
PgosSDK
将尝试从配置中读取该值:account_provider。
const int32 FAS = 0; /** Fake account service provided by PGOS. */
const int32 INTL = 1; /** Account service provided by Proxima for overseas games. */
const int32 MSDK = 2; /** Account service provided by Tencent for China mainland games. */
const int32 WeGame = 3; /** Account service provided by WeGame. */
const int32 PlayFab = 4; /** Account service provided by PlayFab. */
const int32 Steam = 5; /** Account service provided by Steam. */
const int32 Epic = 6; /** Account service provided by Epic(EOS), only epicgames identity is supported. */
const int32 XboxLive = 7; /** Account service provided by XboxLive. */
const int32 PlayStationNetwork = 8; /** Account service provided by PlayStationNetwork. */
const int32 Nintendo = 9; /** Account service provided by Nintendo. */
account_open_id: 已登录账号的 open id。从账号服务获取玩家用户ID
account_token: 账号 token。从账号服务获取。
title_region_id: 玩家想要登录的游戏区服 ID,可以从 PGOS控制台获取。
extra_param: [可选] 账号服务的额外参数,其值取决于用于登录的账号服务。
event_custom_data: [可选] 传递给 PGOS 后端事件:
event_player_login_pgos
的游戏自定义值。如果需要在事件中获取自定义值,请传入该值,否则忽略此字段。大小限制为 4096 字节(将字符串转换为 utf8 格式后)。点击此处查看如何在云函数中引用event_custom_data
。
在接下来的章节中,我们将详细介绍如何使用这些账号提供商登录 PGOS。
3.1.2 使用FAS登录
在游戏开发阶段,开发者可以使用FAS来测试所有PGOS服务,然后再集成真实的账号服务。以下是示例代码:
#include "PgosSDKCpp.h"
// call after a successful FAS login
// and the FASAuthRet is obtained from FAS Login
void SomeUObjectClass::LoginPGOS(const FClientFasLoginInfo& FASAuthRet)
{
auto playerAuth = IPgosSDKCpp::Get().GetClientPlayerAuthAPI();
if (playerAuth)
{
FClientLoginPGOSParams Params;
Params.account_provider = (int32)EAccountProvider::FAS;
Params.account_open_id = FASAuthRet.open_id;
Params.account_token = FASAuthRet.token;
Params.title_region_id = TEXT("region_id_to_login"); // Obtained from PGOS portal console.
playerAuth->LoginPGOS(Params, [](const FPgosResult& Ret, const FClientAuthenticationInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("OnLoginPGOSSuccess: player_id=%s"), *Data->player_id);
}
else
{
UE_LOG(LogTemp, Log, TEXT("OnLoginPGOSFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
以下是使用 FAS 登录时关于 FClientLoginPGOSParams 字段的提示:
- extra_param:使用 FAS 登录时可忽略此字段。
- event_custom_data:如果您需要在 PGOS Event: event_player_login_pgos 中获取自定义值,请传入该值,如不需要则可忽略此字段。
3.1.3 使用INTLSDK登录(Player Network)
要使用INTLSDK(Player Network)登录PGOS,您必须先在门户控制台上安装INTLSDK 插件,然后才能开始编码工作,以下是示例代码:
#include "PgosSDKCpp.h"
// call after a successful INTLSDK login
// and the INTLAuthRet is obtained from INTLSDK Login
void SomeUObjectClass::LoginPGOS(const FINTLAuthResult& INTLAuthRet)
{
auto playerAuth = IPgosSDKCpp::Get().GetClientPlayerAuthAPI();
if (playerAuth)
{
FClientLoginPGOSParams Params;
Params.account_provider = (int32)EAccountProvider::INTL;
Params.account_open_id = INTLAuthRet.OpenID;
Params.account_token = INTLAuthRet.Token;
Params.title_region_id = TEXT("region_id_to_login"); // Obtained from PGOS portal console.
Params.extra_param.Add(TEXT("account_channel"), INTLAuthRet.ChannelID);
playerAuth->LoginPGOS(Params, [](const FPgosResult& Ret, const FClientAuthenticationInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("OnLoginPGOSSuccess: player_id=%s"), *Data->player_id);
}
else
{
UE_LOG(LogTemp, Log, TEXT("OnLoginPGOSFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
以下是使用 INTL SDK 登录时关于 ClientLoginPGOSParams 字段的提示:
- extra_param:添加key
"account_channel"
,并将其值设置为从 INTL SDK 认证结果中获取的ChannelID
。
Params.extra_param.Add(TEXT("account_channel"), INTLAuthRet.ChannelID);
- event_custom_data:如果您需要在 PGOS 事件:event_player_login_pgos 中获取自定义值,请传入该值,如不需要则可忽略此字段。
3.1.4 通过 WeGame 登录
要使用 WeGame 登录 PGOS,您必须先在门户控制台上安装 WeGame 插件,然后才能开始编写代码,以下是示例代码:
#include "PgosSDKCpp.h"
// call after a successful WeGame login
// and the RailId and SessionTicket are obtained from the Rail API 'AsyncAcquireSessionTicket' response
void SomeUObjectClass::LoginPGOS(const FString& RailId, const FString& SessionTicket)
{
auto playerAuth = IPgosSDKCpp::Get().GetClientPlayerAuthAPI();
if (playerAuth)
{
FClientLoginPGOSParams Params;
Params.account_provider = (int32)EAccountProvider::WeGame;
Params.account_open_id = RailId;
Params.account_token = SessionTicket;
Params.title_region_id = TEXT("region_id_to_login"); // Obtained from PGOS portal console.
playerAuth->LoginPGOS(Params, [](const FPgosResult& Ret, const FClientAuthenticationInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("OnLoginPGOSSuccess: player_id=%s"), *Data->player_id);
}
else
{
UE_LOG(LogTemp, Log, TEXT("OnLoginPGOSFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
以下是使用WeGame登录时关于ClientLoginPGOSParams字段的提示:
- extra_param:使用WeGame登录时请忽略此字段。
- event_custom_data:如果您需要在PGOS事件:event_player_login_pgos中获取自定义值,请传入该值,如果不需要则忽略此字段。
3.1.5 使用 PlayFab 登录
要使用 PlayFab 登录 PGOS,您必须先在门户控制台上安装 PlayFab 插件,然后才能开始编写代码,以下是示例代码:
#include "PgosSDKCpp.h"
// call after a successful PlayFab login
// and the PlayFabId and SessionTicket are obtained from PlayFab Login
void SomeUObjectClass::LoginPGOS(const FString& PlayFabId, const FString& SessionTicket)
{
auto playerAuth = IPgosSDKCpp::Get().GetClientPlayerAuthAPI();
if (playerAuth)
{
FClientLoginPGOSParams Params;
Params.account_provider = (int32)EAccountProvider::PlayFab;
Params.account_open_id = PlayFabId;
Params.account_token = SessionTicket;
Params.title_region_id = TEXT("region_id_to_login"); // Obtained from PGOS portal console.
playerAuth->LoginPGOS(Params, [](const FPgosResult& Ret, const FClientAuthenticationInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("OnLoginPGOSSuccess: player_id=%s"), *Data->player_id);
}
else
{
UE_LOG(LogTemp, Log, TEXT("OnLoginPGOSFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
以下是使用 PlayFab 登录时关于 ClientLoginPGOSParams 字段的提示:
- extra_param:使用 PlayFab 登录时请忽略此字段。
- event_custom_data:如果您需要在 PGOS Event: event_player_login_pgos 中获取自定义值,请传入该值,如果不需要则忽略此字段。
3.1.6 通过 Steam 登录
要使用 Steam 登录 PGOS,您必须先在门户控制台上安装 Steam 插件,然后才能开始您的编码工作,以下是示例代码:
#include "PgosSDKCpp.h"
// call after a successful Steam login
// and the SteamId and SessionTicket are obtained from the steamworks API 'ISteamUser::GetAuthSessionTicket'
void SomeUObjectClass::LoginPGOS(const FString& SteamId, const FString& SessionTicket)
{
auto playerAuth = IPgosSDKCpp::Get().GetClientPlayerAuthAPI();
if (playerAuth)
{
FClientLoginPGOSParams Params;
Params.account_provider = (int32)EAccountProvider::Steam;
Params.account_open_id = SteamId;
Params.account_token = SessionTicket;
Params.title_region_id = TEXT("region_id_to_login"); // Obtained from PGOS portal console.
playerAuth->LoginPGOS(Params, [](const FPgosResult& Ret, const FClientAuthenticationInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("OnLoginPGOSSuccess: player_id=%s"), *Data->player_id);
}
else
{
UE_LOG(LogTemp, Log, TEXT("OnLoginPGOSFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
以下是使用Steam登录时关于ClientLoginPGOSParams字段的提示:
- extra_param:使用Steam登录时请忽略此字段。
- event_custom_data:如果您需要在PGOS事件:event_player_login_pgos中获取自定义值,请传入该值,如果不需要则忽略此字段。
3.1.7 使用 Epic 登录
目前,PGOS 仅支持 epic games 身份验证,不支持 EOS 上的其他身份提供商。要使用 Epic 登录 PGOS,您必须先在门户控制台上安装 Epic 插件,然后才能开始编写代码,以下是示例代码:
#include "PgosSDKCpp.h"
// call after login to Epic
void SomeUObjectClass::LoginPGOS(const FString& EpicAccountId, const FString& JWT_IDToken)
{
auto playerAuth = IPgosSDKCpp::Get().GetClientPlayerAuthAPI();
if (playerAuth)
{
FClientLoginPGOSParams Params;
Params.account_provider = (int32)EAccountProvider::Epic;
Params.account_open_id = EpicAccountId;
Params.account_token = JWT_IDToken;
Params.title_region_id = TEXT("region_id_to_login"); // Obtained from PGOS portal console.
playerAuth->LoginPGOS(Params, [](const FPgosResult& Ret, const FClientAuthenticationInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("OnLoginPGOSSuccess: player_id=%s"), *Data->player_id);
}
else
{
UE_LOG(LogTemp, Log, TEXT("OnLoginPGOSFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
以下是使用Epic登录时关于ClientLoginPGOSParams字段的提示:
- extra_param:使用Steam登录时请忽略此字段。
- event_custom_data:如果您需要在PGOS事件:event_player_login_pgos中获取自定义值,请传入该值,如果不需要则可以忽略此字段。
3.1.8 使用 XboxLive 登录
要使用 XboxLive 登录 PGOS,您必须先在控制台上安装 XboxLive 插件,然后才能开始编码工作,以下是示例代码:
#include "PgosSDKCpp.h"
// call after login to XboxLive
// The endpoint URL should be "https://xboxlive.com/" when obtaining an XSTSToken by calling `XUserGetTokenAndSignatureAsync`.
void SomeUObjectClass::LoginPGOS(const FString& Xuid, const FString& XSTSToken)
{
auto playerAuth = IPgosSDKCpp::Get().GetClientPlayerAuthAPI();
if (playerAuth)
{
FClientLoginPGOSParams Params;
Params.account_provider = (int32)EAccountProvider::XboxLive;
Params.account_open_id = Xuid;
Params.account_token = XSTSToken;
Params.title_region_id = TEXT("region_id_to_login"); // Obtained from PGOS portal console.
playerAuth->LoginPGOS(Params, [](const FPgosResult& Ret, const FClientAuthenticationInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("OnLoginPGOSSuccess: player_id=%s"), *Data->player_id);
}
else
{
UE_LOG(LogTemp, Log, TEXT("OnLoginPGOSFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
以下是使用 XboxLive 登录时关于 ClientLoginPGOSParams 字段的提示:
- extra_param:使用 XboxLive 登录时请忽略此字段。
- event_custom_data:如果您需要在 PGOS Event: event_player_login_pgos 中获取自定义值,请传入该值,如果不需要则忽略此字段。
3.1.9 使用 PlayStationNetwork 登录
要使用 PlayStationNetwork 登录 PGOS,您必须先在门户控制台上安装 PlayStationNetwork 插件,然后才能开始编码工作,以下是示例代码:
#include "PgosSDKCpp.h"
// call after login to PlayStationNetwork
void SomeUObjectClass::LoginPGOS(const FString& UserId, const FString& AuthorizationCode)
{
auto playerAuth = IPgosSDKCpp::Get().GetClientPlayerAuthAPI();
if (playerAuth)
{
FClientLoginPGOSParams Params;
Params.account_provider = (int32)EAccountProvider::PlayStationNetwork;
Params.account_open_id = UserId;
Params.account_token = AuthorizationCode;
Params.title_region_id = TEXT("region_id_to_login"); // Obtained from PGOS portal console.
playerAuth->LoginPGOS(Params, [](const FPgosResult& Ret, const FClientAuthenticationInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("OnLoginPGOSSuccess: player_id=%s"), *Data->player_id);
}
else
{
UE_LOG(LogTemp, Log, TEXT("OnLoginPGOSFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
以下是使用 PlayStationNetwork 登录时关于 ClientLoginPGOSParams 字段的提示:
- extra_param:使用 PlayStationNetwork 登录时请忽略此字段。
- event_custom_data:如果您需要在 PGOS Event: event_player_login_pgos 中获取自定义值,请传入该值,如果不需要则忽略此字段。
3.1.10 使用Nintendo登录
要使用Nintendo登录PGOS,您必须先在门户控制台上安装Nintendo 插件,然后才能开始编码工作,以下是示例代码:
#include "PgosSDKCpp.h"
// call after login to Nintendo
void SomeUObjectClass::LoginPGOS(const FString& Naid, const FString& NsaIdToken)
{
auto playerAuth = IPgosSDKCpp::Get().GetClientPlayerAuthAPI();
if (playerAuth)
{
FClientLoginPGOSParams Params;
Params.account_provider = (int32)EAccountProvider::Nintendo;
Params.account_open_id = Naid;
Params.account_token = NsaIdToken;
Params.title_region_id = TEXT("region_id_to_login"); // Obtained from PGOS portal console.
playerAuth->LoginPGOS(Params, [](const FPgosResult& Ret, const FClientAuthenticationInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("OnLoginPGOSSuccess: player_id=%s"), *Data->player_id);
}
else
{
UE_LOG(LogTemp, Log, TEXT("OnLoginPGOSFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
以下是使用任天堂账号登录时关于ClientLoginPGOSParams字段的提示:
- extra_param:使用任天堂账号登录时请忽略此字段。
- event_custom_data:如果您需要在PGOS事件:event_player_login_pgos中获取自定义值,请传入该值,如果不需要则忽略此字段。
LoginPGOS Key Error Codes
- PgosErrCode::kBackendYouAreBanned
- PgosErrCode::kBackendAuthClientSecretIsNull
- PgosErrCode::kBackendAddonAuthCfgIsNull
- PgosErrCode::kBackendFasNotAllowedLoginProd
- PgosErrCode::kBackendTitleRegionIsClosed
- PgosErrCode::kBackendGeoRestricted
- PgosErrCode::kBackendAccountIDCanNotChangeAfterSet
- PgosErrCode::kBackendOtherPlayerHasOccupiedTheAccountID
- PgosErrCode::kCltSdkPlayerAlreadyLoginPgos
- PgosErrCode::kSdkLastOperationNotCompleted
- PgosErrCode::kSdkNetworkError
3.2 登出PGOS
当游戏客户端想要退出或不再需要访问PGOS服务时,开发者应调用LogoutPGOS
来结束玩家会话。
FClientLogoutPGOSParams
结构参数作为登出过程的输入。
struct FClientLogoutPGOSParams
{
FString event_custom_data;
};
FClientLogoutPGOSParams
结构中的字段:
- event_custom_data:[可选] 传递给 PGOS 后端事件:
event_player_logout_pgos
的游戏自定义值。如果您需要在事件中获取自定义值,请传入该值,否则可以忽略此字段。大小限制为 4096 字节(将字符串转换为 utf8 格式后)。点击此处查看如何在云函数中引用event_custom_data
。
以下是登出 PGOS 的示例代码:
#include "PgosSDKCpp.h"
void SomeUObjectClass::LogoutPGOS()
{
auto PlayerAuth = IPgosSDKCpp::Get().GetClientPlayerAuthAPI();
if (PlayerAuth) {
FClientLogoutPGOSParams Params;
PlayerAuth->LogoutPGOS(Params, [](const FPgosResult &Ret) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess) {
UE_LOG(LogTemp, Log, TEXT("LogoutPGOS Success"));
} else {
UE_LOG(LogTemp, Log, TEXT("LogoutPGOS Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
3.3 切换账号
如果玩家想要切换并登录新账号,请按照以下流程操作:
- 调用
LogoutPGOS
函数终止当前玩家会话。 - 通过账号服务切换至新账号。
- 调用
LoginPGOS
函数创建新的玩家会话。
3.4 监听玩家会话变更事件
在玩家会话的生命周期内可能会触发一些事件。开发者需要了解这些事件并正确处理。要监听玩家会话事件,请按以下方式将动态委托绑定到OnPlayerSessionChanged
:
#include "PgosSDKCpp.h"
void SomeUObjectClass::MonitorPlayerSessionEvent()
{
auto playerAuth = IPgosSDKCpp::Get().GetClientPlayerAuthAPI();
if (playerAuth)
{
playerAuth->OnPlayerSessionChanged().AddUObject(this, &SomeUObjectClass::OnPlayerSessionChanged);
}
}
void SomeUObjectClass::OnPlayerSessionChanged(const FClientPlayerSessionChangedEvt& event)
{
/*
struct FClientPlayerSessionChangedEvt{
EClientPlayerSessionEvt evt;
FString msg;
}
*/
UE_LOG(LogTemp, Log, TEXT("OnPlayerSessionChanged"));
}
PGOS中定义了6种玩家会话事件,这些事件会在玩家会话状态发生变化时触发:
enum class EClientPlayerSessionEvt : uint8
{
Dummy = 0,
SessionExpired_NetworkAbnormal = 1,
SessionExpired_TokenExpired = 2,
SessionExpired_KickoutByGame = 3,
SessionExpired_KickoutByBan = 4,
SessionExpired_KickoutByAnotherLogin = 5,
SessionExpired_KickoutByTitleRegionClosed = 6,
SessionExpired_KickoutByAccountCanceled = 7,
SessionStart = 8,
SessionEnd = 9,
};
Type: SessionExpired_NetworkAbnormal: 网络异常时触发。建议游戏客户端静默调用ReLoginPGOS API 创建新的玩家会话以重新获得对 PGOS 服务的访问权限。如果 ReLoginPGOS API 仍然失败,则通知玩家检查本地网络环境。
Type: SessionExpired_TokenExpired: 当 PGOS PLAYER TOKEN 过期时会触发。这通常发生在:游戏客户端长时间断网(例如,App 在移动设备上进入后台模式),然后重新获得网络(App 进入前台模式)并重新与 PGOS 连接。建议游戏客户端默默调用 ReLoginPGOS API 创建新的玩家会话以重新获得对 PGOS 服务的访问权限。如果 ReLoginPGOS API 仍然失败,则通知玩家使用账号服务重新登录。
Type: SessionExpired_KickoutByGame: 当游戏行为将玩家踢出时(通过 virtual_server API:
KickOutPlayer()
)将会触发。当这种情况发生时,建议通知玩家检查账号状态。 本段末尾有关于如何处理玩家被踢出的情况的建议。Type: SessionExpired_KickoutByBan:当玩家被 virtual_server API:
BanPlayer(kickout=true)
封禁时将会触发,点击查看封禁 事件.当发生这种情况时,建议通知玩家检查账户状态。 本段末尾有关于如何处理玩家被踢出的情况的建议。Type: SessionExpired_KickoutByAnotherLogin:当账户执行另一次登录(可能是在另一台设备上)时会触发。 当发生这种情况时,建议通知玩家检查账户状态。 本段末尾有关于如何处理玩家被踢出的情况的建议。
Type: SessionExpired_KickoutByTitleRegionClosed: 在 关闭游戏区服的工作流程中,如果设置为踢出玩家,那么在指定的时间,玩家将会离线并收到此事件 。当这种情况发生时,建议通知玩家游戏区服已关闭,玩家可以找到可以访问的游戏区服登录或者直接退出游戏。
Type: SessionExpired_KickoutByAccountCanceled:当登录账号被取消时会触发。当这种情况发生时,建议通知玩家检查账号状态。 本段末尾有关于如何处理玩家被踢出的情况的建议
Type: SessionEnd:当玩家会话结束时会触发。一旦玩家会话过期,游戏客户端将无法访问 PGOS 服务。
处理玩家被踢出时,通常有两种方式:
- 立即退出游戏:由于游戏客户端无法访问 PGOS 服务,可能无法提供完整的游戏功能,因此游戏可以在通知玩家后退出游戏客户端。
- 如果玩家正在进行战斗,等待战斗结束后再退出游戏:虽然当前游戏客户端无法访问 PGOS 服务,但承载战斗会话的 DS 不受影响,因此当前玩家仍然可以完成当前战斗,等待战斗结束后再退出游戏会是一种相对友好的方式。(注意:依赖 PGOS 服务的功能,如文字聊天,在当前游戏客户端将无法继续使用。)
3.5 监控玩家封禁事件
在玩家会话期间可能会触发玩家封禁事件,开发者可以通过调用虚拟服务器API:BanPlayer()
来触发封禁事件。如果BanPlayer()
的布尔参数kickout
设置为true,还会触发PlayerSessionChangedEvt (SessionExpired_KickoutByBan)
事件。开发者需要注意此事件并妥善处理。要监控玩家封禁事件,请按以下方式绑定动态委托到OnPlayerBanned
:
#include "PgosSDKCpp.h"
void SomeUObjectClass::MonitorPlayerBannedEvent()
{
auto playerAuth = IPgosSDKCpp::Get().GetClientPlayerAuthAPI();
if (playerAuth)
{
playerAuth->OnPlayerBanned().AddUObject(this, &SomeUObjectClass::OnPlayerBanned);
}
}
void SomeUObjectClass::OnPlayerBanned(const FClientPlayerBannedEvt& event)
{
UE_LOG(LogTemp, Log, TEXT("OnPlayerBanned"));
}
开发者可以通过 FClientPlayerBannedEvt
获取封禁详情:
struct FClientPlayerBannedEvt{
/** Reason for ban. */
FString ban_reason;
/** Ban creation time. */
int64 ban_created_time;
/** Ban duration */
int64 ban_duration;
/** Ban expiration time, 0 means forever */
int64 ban_expired_time;
}
ban_expired_time 表示封禁结束的时间,如果为0则表示永久封禁。
ban_duration 表示封禁的持续时间。如果是永久封禁,其值为0。
被封禁后,在调用 LoginPGOS
时会在回调中返回 FClientAuthBanInfo
,类似于 FClientPlayerBannedEvt
。
struct FClientAuthBanInfo{
/** Whether the player is banned. */
bool is_banned = false;
/** Reason for ban. */
FString ban_reason;
/** Ban creation time. */
int64 ban_created_time;
/** Ban duration */
int64 ban_duration;
/** Ban expiration time, 0 means forever */
int64 ban_expired_time;
}
3.6 监控游戏区服关闭事件
游戏可以根据需要关闭游戏区服,您可以在游戏区服开启与关闭了解更多信息。当游戏区服关闭时,玩家将无法进行新的登录、新的匹配或新的战斗会话分配。开发者可以将动态委托绑定到OnTitleRegionClosed
来监控该事件:
#include "PgosSDKCpp.h"
void SomeUObjectClass::MonitorRegionClosedEvent()
{
auto playerAuth = IPgosSDKCpp::Get().GetClientPlayerAuthAPI();
if (playerAuth)
{
playerAuth->OnTitleRegionClosed().AddUObject(this, &SomeUObjectClass::OnRegionClosed);
}
}
void SomeUObjectClass::OnRegionClosed(const FClientTitleRegionClosedEvt& event)
{
UE_LOG(LogTemp, Log, TEXT("OnRegionClosed"));
}
该事件的相关信息如下:
struct FClientTitleRegionClosedEvt
{
/** The current UTC timestamp of the backend server. (in seconds) */
int64 current_time = 0;
/**
* The approximate Unix timestamp at which the player will be kicked offline. (in seconds)
* If the value is 0, the PGOS backend will kick the player offline soon.
* If the value is -1, the PGOS backend will still allow the current player to remain online, and battle sessions the player is in will not be affected.
*/
int64 kicked_offline_time = 0;
};
由于OnTitleRegionClosed
事件是针对所有在线玩家的事件,出于性能考虑,该事件通过持久连接心跳的方式通知到玩家客户端,心跳间隔为每30秒一次。需要特别注意的是,OnTitleRegionClosed
事件的推送行为会根据Close Title Region
操作的不同而有所不同。
存在3种场景:
- 选择
不踢下线
选项:
玩家客户端将在下一次持久连接心跳中收到
OnTitleRegionClosed
事件,且FClientTitleRegionClosedEvt
的kicked_offline_time
字段值为-1
。选择
踢下线
选项:关闭开始后
0
分钟:
设置为0会使PGOS后端立即将玩家踢下线,因此持久连接将断开,玩家客户端可能没有机会通过心跳接收到
OnTitleRegionClosed
事件。如果幸运地收到该事件,kicked_offline_time
字段值将为0
。- 关闭开始后
n
分钟(n
> 0):
玩家客户端将在下一次持久连接心跳中收到
OnTitleRegionClosed
事件。无论如何,当玩家被踢下线时,都会触发一个原因为
SessionExpired_KickoutByTitleRegionClosed
的PlayerSessionChangedEvt
事件。- 选择
3.7 监控事件通道状态变更事件
事件通道作为数据管道,用于PGOS后端向客户端发送事件通知(如聊天消息/好友请求)。当事件通道状态发生变化时,将触发该事件。事件通道状态可能受到API调用(如登录/登出)和网络环境波动等因素的影响。在某些情况下,该事件有助于游戏/玩家了解PGOS/游戏服务质量下降的可能原因。例如,当事件通道不可用时,游戏客户端可以在适当的位置向玩家显示消息,如:"聊天功能暂时不可用,正在维护中..."。
开发者可以绑定动态委托到OnEventChannelStatusChanged
来监控该事件:
#include "PgosSDKCpp.h"
void SomeUObjectClass::MonitorEventChannelStatusChanged()
{
auto playerAuth = IPgosSDKCpp::Get().GetClientPlayerAuthAPI();
if (playerAuth)
{
playerAuth->OnEventChannelStatusChanged().AddUObject(this, &SomeUObjectClass::OnEventChannelStatusChanged);
}
}
void SomeUObjectClass::OnEventChannelStatusChanged(const FClientEventChannelStatusChangedEvt& event)
{
UE_LOG(LogTemp, Log, TEXT("OnEventChannelStatusChanged"));
}
开发者可以通过 FClientEventChannelStatusChangedEvt
获取事件详情:
struct FClientEventChannelStatusChangedEvt
{
/** Indicate the current status of the event channel. */
EClientPgosEventChannelStatus current_status = EClientPgosEventChannelStatus::Dummy;
/** Indicate the status of the event channel in the previous StatusChanged event. If there is no previous event (meaning it is the first event), its value is set to 'Dummy'. */
EClientPgosEventChannelStatus last_status = EClientPgosEventChannelStatus::Dummy;
};
enum class EClientPgosEventChannelStatus : uint8
{
/** Invalid status. */
Dummy = 0,
/** When the client is connecting or reconnecting to the backend in order to establish the channel, the status is set to 'Creating'. */
Creating = 1,
/** When the channel is successfully established, the status is set to 'Available', indicating that the event notification service is functioning properly. */
Available = 2,
/**
* When the client expectedly(logout) or unexpectedly(network exception) disconnects from the backend, the status is set to 'Unavailable', and the event notification service stops working.*/
Unavailable = 3
};
当事件通道的状态变为Unavailable
时,PGOS事件通知服务将停止工作。这意味着游戏客户端将无法接收聊天消息、好友请求以及其他依赖后端推送通知的事件。如果这不是预期的状态(例如,玩家已登出),PgosSDK将自动尝试重建通道,直到成功为止,重试频率会逐渐降低。最初每3秒尝试重建一次,最终频率会降低到每5分钟一次。
3.8 重新登录 PGOS
ReLoginPGOS
API 将尝试使用内存中缓存的 LoginPGOSParams
重新登录 PGOS,如果执行成功,将创建一个新的玩家会话并触发 PlayerSessionEvt::SessionStart
事件。建议在发生 PlayerSessionEvt::SessionExpired_NetworkAbnormal
或 PlayerSessionEvt::SessionExpired_TokenExpired
事件时调用此 API。
以下是示例代码:
#include "PgosSDKCpp.h"
void SomeUObjectClass::SomeFunction()
{
auto PlayerAuth = IPgosSDKCpp::Get().GetClientPlayerAuthAPI();
if (PlayerAuth)
{
PlayerAuth->ReLoginPGOS([](const FPgosResult& Ret, const FClientAuthenticationInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("ReLoginPGOS Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("ReLoginPGOS Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
3.9 游戏服务器上的玩家验证
在某些场景下,游戏服务器可能需要验证来自游戏客户端的玩家身份。PGOS提供以下方法来帮助游戏完成这项工作:
- 相关 API:
- 相关客户端 SDK API:
FPgosPlayerAuthAPI::MyAuthTicket
- 相关客户端 SDK API:
/**
* Get the current player's PGOS authenticated ticket which can be used to authenticate the player via the HTTP Backed API.
* The ticket has a reliable validity period of 60 seconds. Please retrieve it from SDK when needed and avoid caching it.
* If the player is not logged in, an empty string will be returned.
*
* @return The current player's ticket, valid after a successful LoginPGOS.
*/
FString MyAuthTicket() const;
- 相关的 PGOS HTTP 后端 API:VerifyAuthTicket
ReLogin Key Error Codes
- PgosErrCode::kBackendYouAreBanned
- PgosErrCode::kBackendAuthClientSecretIsNull
- PgosErrCode::kBackendAddonAuthCfgIsNull
- PgosErrCode::kBackendFasNotAllowedLoginProd
- PgosErrCode::kBackendTitleRegionIsClosed
- PgosErrCode::kBackendGeoRestricted
- PgosErrCode::kCltSdkPlayerNotLoginPgos
- PgosErrCode::kCltSdkPlayerAlreadyLoginPgos
- PgosErrCode::kSdkLastOperationNotCompleted
- PgosErrCode::kSdkNetworkError
4. 使用临时账号服务
我们提供临时账号服务(FAS)来帮助您在集成真实账号服务之前体验所有PGOS服务。真实账号服务会包含许多功能,而PGOS临时账号服务仅提供一些简单的关键功能:
API | Description |
---|---|
Login | 使用指定的账号登录。 |
AutoLogin | 使用本地历史账号登录(如果没有历史账号,系统将自动创建一个)。 |
4.1 登录客户端 API
玩家可以使用指定的 FAS 账号登录,FAS 账号无需提前注册,可以是任意不包含换行符('\r'、'\n')的字符串。FAS 账号可由游戏工作室进行管理。以下是示例代码:
#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"
void SomeUObjectClass::SomeFunction()
{
auto FakeAccount = IPgosSDKCpp::Get().GetClientFakeAccountAPI();
if (FakeAccount)
{
FString Account = TEXT("any_string_as_account"); // account can be any string without line breaks ('\r', '\n').
FakeAccount->Login(Account, [](const FPgosResult& Ret, const FClientFasLoginInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("Login Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("Login Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
4.2 自动登录客户端 API
生成的临时账号将保存在本地,并可在登录时自动使用。临时账号保存在文件 (/fas/account) 中,如果您想使用此临时账号登录其他设备,可以分发或替换该文件。以下是示例代码:
#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"
void SomeUObjectClass::SomeFunction()
{
auto FakeAccount = IPgosSDKCpp::Get().GetClientFakeAccountAPI();
if (FakeAccount)
{
FakeAccount->AutoLogin([](const FPgosResult& Ret, const FClientFasLoginInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("AutoLogin Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("AutoLogin Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
5. 关键错误处理
Error Code | 相关 API | Handling Suggestion |
---|---|---|
kBackendYouAreBanned | LoginPGOS ReLoginPGOS | 这表示玩家已被封禁。游戏可以向玩家显示提示消息,如"您已被封禁,解封时间为xxxx" |
kBackendAuthClientSecretIsNull | LoginPGOS ReLoginPGOS | 这表示客户端密钥配置不存在。您需要使用门户网站创建一个客户端密钥(如果客户端密钥配置已存在,请联系 pgos 团队)。 |
kBackendAddonAuthCfgIsNull | LoginPGOS ReLoginPGOS | 这表示当前账户的认证方式不受支持。您需要确保已启用相应的认证插件。 |
kBackendFasNotAllowedLoginProd | LoginPGOS ReLoginPGOS | 禁止在production region使用FAS。 |
kBackendTitleRegionIsClosed | LoginPGOS ReLoginPGOS | 该游戏区服已关闭登录,请在门户网站上查看游戏区服状态。 |
kBackendGeoRestricted | LoginPGOS ReLoginPGOS | 由于地理位置限制导致登录失败。请检查门户网站上的地理位置限制设置。 |
kCltSdkPlayerNotLoginPgos | ReLoginPGOS | 当前玩家尚未登录PGOS,因此"重新登录"将无法生效。 |
kCltSdkPlayerAlreadyLoginPgos | LoginPGOS ReLoginPGOS | 当前玩家已登录PGOS,此操作不适用。 |
kSdkLastOperationNotCompleted | LoginPGOS ReLoginPGOS | 当前玩家已登录PGOS,此操作不适用。 |
kSdkNetworkError | All Network API | 网络错误,请查看错误信息了解详情。 |