玩家信息
1. 概述
玩家信息是用于描述玩家的核心属性集合。具体来说,它包含两个部分:
- 基础信息是内置的不可修改字段,如
player_id、display_name和avatar_uri。 - 自定义信息是由游戏自定义的字段,这是来自玩家数据模板.的核心数据集。
 
完成本教程后,您将了解以下内容:
- 如何在网页端查看和修改玩家信息。
 - 如何在代码中查询和更新玩家信息。
 
2. 门户网站上的玩家信息
2.1 查看玩家信息
登录网页门户,进入控制台并前往玩家 > 查询:

点击玩家的ID以查看玩家详细信息:

2.2 玩家信息定义
玩家信息通常作为一个核心属性集合,用于在好友、组队和房间等服务模块中描述玩家。由于其基本信息是由 PGOS 以通用性为目标定义的,无法满足游戏描述玩家核心属性的所有需求。因此,PGOS 为游戏提供了一种扩展玩家信息的方式:从玩家数据模板中选择某些项作为玩家信息的一部分,这被称为自定义信息。
自定义信息旨在使玩家信息更加丰富,因为玩家信息可能不足以描述玩家的"基本信息"。例如,当玩家收到陌生人的好友请求时,游戏可能需要向玩家显示该陌生人的"等级",这可以从玩家数据中获取,但那将需要另一个 API 调用。如果游戏将"等级"添加到自定义信息中,使其成为玩家基本信息的一部分,游戏就不需要额外的 API 调用,这为开发带来了便利。
进入控制台并前往玩家 > 玩家信息定义:

点击"管理"按钮来选择要显示在玩家自定义信息中的项目:

开发者可以通过
FPlayerInfo::custom_info访问自定义信息,详见数据结构. >❗ 注意: > >玩家自定义信息中的数据项对所有玩家都是可见的。虽然您可以将任何数据项添加为自定义信息(无论其访问权限如何),但我们仍建议您谨慎考虑这样做。另外需要注意的是,如果向自定义信息中添加过多数据项,可能会导致不必要的性能问题。
3. 数据结构
3.1 玩家信息和玩家详情
玩家信息有两种数据结构:FPlayerInfo 和 FPlayerDetail。FPlayerDetail 继承自 FPlayerInfo 的数据。只有数据所有者和游戏服务器可以访问 FPlayerDetail。
struct FPlayerInfo
{
    FString player_id;
    FString display_name;
    FString gender;
    FString avatar_uri;
    int32 account_provider;
    FString account_platform;
    FString account_open_id;
    FString account_id;
    EClientOS os;
    TMap<FString, FKVDataValue> custom_info;
};
struct FPlayerDetail : public FPlayerInfo
{
    FString language;
    int64 first_login_time;
    int64 last_login_time;
    int64 last_logout_time;
    int64 total_time;
    FString last_login_ip;
    FString cur_login_ip;
};
除了以下由PGOS后端更新的数据成员外,其他数据成员在游戏中设置之前默认为空。
player_id:PGOS提供的游戏区服中唯一的玩家ID。
display_name:玩家的显示名称。
gender:玩家的性别。
avatar_uri:玩家的头像URI。
account_provider:账号服务提供商。0表示FAS,1表示INTL,2表示MSDK,3表示WeGame,4表示PlayFab,5表示Steam,6表示Epic,7表示XboxLive,8表示PlayStationNetwork,9表示Nintendo。
account_platform:账号平台名称,PGOS会在游戏调用
LoginPGOS时从传入的参数中获取并保存。它可以是以下值之一:
[
    "WeChat",
    "QQ",
    "Guest",
    "Facebook",
    "GameCenter",
    "Google",
    "IEGPassport",
    "Twitter",
    "Garena",
    "EGame",
    "Nintendo",
    "LINE",
    "Apple",
    "VK",
    "XboxLive",
    "Steam",
    "EpicGames",
    "Discord",
    "PlayStationNetwork",
    "DMM",
    "SquareEnix",
    "Supercell",
    "Kakao",
    "Instagram",
    "Whatsapp",
    "Sop",
    "LI PASS",
    "Amazon",
    "AndroidDevice",
    "Custom",
    "FacebookInstantGames",
    "GooglePlay",
    "IOSDevice",
    "Kongregate",
    "LoadTest",
    "OpenIdConnect",
    "Organic",
    "Parse",
    "ServerCustom",
    "Twitch",
    "Unknown"
]
account_open_id: 已登录账号服务提供商的 open ID。
account_id: 玩家所拥有的账号平台用户 ID(例如 Steam SteamID、PSN 账号 ID、Xbox XUID)。
custom_info: 来自玩家数据的自定义信息,key: 键名,value: 值。
language: 玩家的显示语言,如果您希望游戏支持多语言。
first_login_time: 玩家在游戏区服首次登录的 Unix 时间戳。
last_login_time: 玩家在游戏区服最后一次登录的 Unix 时间戳。
last_logout_time: 玩家在游戏区服最后一次登出的 Unix 时间戳。
total_time: 玩家的总在线时长,以秒为单位。
除非另有说明,PGOS 接口中的时间戳均为 Unix 时间戳。
3.2 玩家用户ID
下表通过几个示例展示了玩家拥有的各种用户ID:
| Account Service Provider used | Open ID | Account ID | Player ID | 
|---|---|---|---|
| PGOS FAS | FAS ID | FAS ID | PGOS Player ID | 
| Steamworks SDK | Steam ID | Steam ID | PGOS Player ID | 
| INTL SDK (e.g. Login on Steam) | INTL Open ID | Steam ID | PGOS Player ID | 
| PlayFab SDK (e.g. Login on Steam) | PlayFab ID | Steam ID | PGOS Player ID | 
4. 查询玩家信息
您可以一次性获取一个或多个玩家的信息。
4.1 游戏客户端
| API | Description | 
|---|---|
| GetMyInfo | 查询当前玩家的详细信息。结果以 FPlayerDetail 的形式封装。 | 
| GetPlayerInfo | 查询玩家信息。结果以 FPlayerInfo 的形式封装。 | 
| BatchGetPlayerInfo | 查询多个玩家的信息。结果以 FPlayerInfo 的形式封装。 | 
API 详情:
4.1.1 GetMyInfo Client API
Interface prototype:
/**
* Query the current player's profile.
*/
void GetMyInfo(TFunction<void(const FPgosResult& Ret, const FPlayerDetail* Data)> Callback) const;
Example Code:
#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"
void SomeUObjectClass::SomeFunction()
{
 auto PlayerProfile = IPgosSDKCpp::Get().GetClientPlayerProfileAPI();
 if (PlayerProfile)
 {
     PlayerProfile->GetMyInfo([](const FPgosResult& Ret, const FPlayerDetail* Data) {
         if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
         {
             UE_LOG(LogTemp, Log, TEXT("GetMyInfo Success"));
         }
         else
         {
             UE_LOG(LogTemp, Log, TEXT("GetMyInfo Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
         }
     });
 }
}
Key Error Codes
4.1.2 GetPlayerInfo Client API
Interface prototype:
/**
* Query a player's info
*
* @param PlayerId The player id to query.
*/
void GetPlayerInfo(
    const FString& PlayerId,
    TFunction<void(const FPgosResult& Ret, const FPlayerInfo* Data)> Callback) const;
Example Code:
#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"
void SomeUObjectClass::SomeFunction()
{
 auto PlayerProfile = IPgosSDKCpp::Get().GetClientPlayerProfileAPI();
 if (PlayerProfile)
 {
     FString PlayerId = "197117";
     PlayerProfile->GetPlayerInfo(PlayerId, [](const FPgosResult& Ret, const FPlayerInfo* Data) {
         if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
         {
             UE_LOG(LogTemp, Log, TEXT("GetPlayerInfo Success"));
         }
         else
         {
             UE_LOG(LogTemp, Log, TEXT("GetPlayerInfo Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
         }
     });
 }
}
Key Error Codes
4.1.3 BatchGetPlayerInfo Client API
Interface prototype:
/**
* Query multiple players' info
*
* @param PlayerIds The player_ids to query.
*/
void BatchGetPlayerInfo(
    const TArray<FString>& PlayerIds,
    TFunction<void(const FPgosResult& Ret, const FClientBatchGetPlayerInfoCltRsp* Data)> Callback) const;
Example Code:
#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"
void SomeUObjectClass::SomeFunction()
{
 auto PlayerProfile = IPgosSDKCpp::Get().GetClientPlayerProfileAPI();
 if (PlayerProfile)
 {
     TArray<FString> PlayerIds = {"197117", "197118"};
     PlayerProfile->BatchGetPlayerInfo(PlayerIds, [](const FPgosResult& Ret, const FClientBatchGetPlayerInfoCltRsp* Data) {
         if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
         {
             UE_LOG(LogTemp, Log, TEXT("BatchGetPlayerInfo Success"));
         }
         else
         {
             UE_LOG(LogTemp, Log, TEXT("BatchGetPlayerInfo Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
         }
     });
 }
}
Key Error Codes
4.2 For Game Server
| API | Description | 
|---|---|
| GetPlayerInfo | 查询玩家的详细信息。结果以 FPlayerDetail 的形式封装。 | 
| BatchGetPlayerInfo | 查询一个或多个玩家的详细信息。结果以 FPlayerDetail 的形式封装。 | 
API details:
4.2.1 GetPlayerInfo Server API
Interface prototype:
/**
* Query a player's player detail
*
* @param PlayerId The player to query.
*/
void GetPlayerInfo(
    const FString& PlayerId,
    TFunction<void(const FPgosResult& Ret, const FPlayerDetail* Data)> Callback) const;
Example Code:
#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"
void SomeUObjectClass::SomeFunction()
{
 auto PlayerProfile = IPgosSDKCpp::Get().GetServerPlayerProfileAPI();
 if (PlayerProfile)
 {
     FString PlayerId = TEXT("197117");
     PlayerProfile->GetPlayerInfo(PlayerId, [](const FPgosResult& Ret, const FPlayerDetail* Data) {
         if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
         {
             UE_LOG(LogTemp, Log, TEXT("GetPlayerInfo Success"));
         }
         else
         {
             UE_LOG(LogTemp, Log, TEXT("GetPlayerInfo Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
         }
     });
 }
}
Key Error Codes
4.2.2 BatchGetPlayerInfo Server API
Interface prototype:
/**
* Query one or more players' player detail
*
* @param PlayerIds The players to query.
*/
void BatchGetPlayerInfo(
    const TArray<FString>& PlayerIds,
    TFunction<void(const FPgosResult& Ret, const FServerBatchGetPlayerInfoSvrRsp* Data)> Callback) const;
Example Code:
#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"
void SomeUObjectClass::SomeFunction()
{
 auto PlayerProfile = IPgosSDKCpp::Get().GetServerPlayerProfileAPI();
 if (PlayerProfile)
 {
     TArray<FString> PlayerIds = {TEXT("197117"), TEXT("197118")};
     PlayerProfile->BatchGetPlayerInfo(PlayerIds, [](const FPgosResult& Ret, const FServerBatchGetPlayerInfoSvrRsp* Data) {
         if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
         {
             UE_LOG(LogTemp, Log, TEXT("BatchGetPlayerInfo Success"));
         }
         else
         {
             UE_LOG(LogTemp, Log, TEXT("BatchGetPlayerInfo Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
         }
     });
 }
}
Key Error Codes
5. 更新玩家信息
玩家只能更新自己的玩家信息,不能更新其他玩家的信息。
5.1 游戏客户端
| API | Description | 
|---|---|
| SetMyName | 更新当前玩家的显示名称。 | 
| SetMyAvatar | 更新当前玩家的头像 | 
| SetMyLanguage | 更新当前玩家的语言 | 
| SetMyGender | 更新当前玩家的性别 | 
API details:
5.1.1 SetMyName Client API
玩家昵称长度限制为2至64个字符。
Interface prototype:
/**
* Update current player's display name.
*
* @param display_name Set the current player's display name. The display name length is limited to 2 to 64 characters.
* @param result_callback The result callback after the API execution ends, and it will be called in an ASYNCHRONOUS CHILD THREAD.
*/
void SetMyName(
    const FString& DisplayName,
    TFunction<void(const FPgosResult& Ret)> Callback) const;
Example Code:
#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"
void SomeUObjectClass::SomeFunction()
{
 auto PlayerProfile = IPgosSDKCpp::Get().GetClientPlayerProfileAPI();
 if (PlayerProfile)
 {
     FString DisplayName = TEXT("ConfusedGirl");
     PlayerProfile->SetMyName(DisplayName, [](const FPgosResult& Ret) {
         if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
         {
             UE_LOG(LogTemp, Log, TEXT("SetMyName Success"));
         }
         else
         {
             UE_LOG(LogTemp, Log, TEXT("SetMyName Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
         }
     });
 }
}
5.1.2 SetMyAvatar Client API
Interface prototype:
/**
* Update the current player's avatar
*
* @param AvatarUri The new URI of the player avatar.
*/
void SetMyAvatar(
    const FString& AvatarUri,
    TFunction<void(const FPgosResult& Ret)> Callback) const;
Example Code:
#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"
void SomeUObjectClass::SomeFunction()
{
 auto PlayerProfile = IPgosSDKCpp::Get().GetClientPlayerProfileAPI();
 if (PlayerProfile)
 {
     FString AvatarUri = TEXT("https://images.app.goo.gl/BD9qYfdfYPsMLXW69");
     PlayerProfile->SetMyAvatar(AvatarUri, [](const FPgosResult& Ret) {
         if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
         {
             UE_LOG(LogTemp, Log, TEXT("SetMyAvatar Success"));
         }
         else
         {
             UE_LOG(LogTemp, Log, TEXT("SetMyAvatar Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
         }
     });
 }
}
Key Error Codes
5.1.3 SetMyLanguage Client API
Interface prototype:
/**
* Update the current player's language
*
* @param Language The new gender.
*/
void SetMyLanguage(
    const FString& Language,
    TFunction<void(const FPgosResult& Ret)> Callback) const;
Example Code:
#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"
void SomeUObjectClass::SomeFunction()
{
 auto PlayerProfile = IPgosSDKCpp::Get().GetClientPlayerProfileAPI();
 if (PlayerProfile)
 {
     FString Language = TEXT("en-GB");
     PlayerProfile->SetMyLanguage(Language, [](const FPgosResult& Ret) {
         if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
         {
             UE_LOG(LogTemp, Log, TEXT("SetMyLanguage Success"));
         }
         else
         {
             UE_LOG(LogTemp, Log, TEXT("SetMyLanguage Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
         }
     });
 }
}
Key Error Codes
5.1.4 SetMyGender Client API
Interface prototype:
/**
* Update the current player's gender
*
* @param Gender The new language.
*/
void SetMyGender(
    const FString& Gender,
    TFunction<void(const FPgosResult& Ret)> Callback) const;
Example Code:
#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"
void SomeUObjectClass::SomeFunction()
{
 auto PlayerProfile = IPgosSDKCpp::Get().GetClientPlayerProfileAPI();
 if (PlayerProfile)
 {
     FString Gender = TEXT("female");
     PlayerProfile->SetMyGender(Gender, [](const FPgosResult& Ret) {
         if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
         {
             UE_LOG(LogTemp, Log, TEXT("SetMyGender Success"));
         }
         else
         {
             UE_LOG(LogTemp, Log, TEXT("SetMyGender Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
         }
     });
 }
}
Key Error Codes
6. Key Error Handling
| Error Code | Relevant API | Handling Suggestion | 
|---|---|---|
| kBackendPlayerDisplayNameContainProfanityWords | SetMyName | 提交的新玩家昵称包含不当用语。游戏可以提示玩家输入合法的显示名称。 | 
| kBackendPlayerDisplayNameVerificationFailed | SetMyName | 在游戏区服内玩家的玩家昵称必须是唯一的,您要设置的玩家昵称已存在。 | 
| kBackendDisplayNameAlreadyExists | SetMyName | 玩家受到惩罚。msg是一个JSON序列化字符串,包含截止时间(惩罚结束时的Unix时间戳(以秒为单位),小于等于0表示永久惩罚)和原因。 | 
| kBackendErrPlayerIsPunished | SetMyName | 玩家受到惩罚。msg是一个JSON序列化字符串,包含截止时间(惩罚结束时的Unix时间戳(以秒为单位),小于等于0表示永久惩罚)和原因。 | 
| kSdkNetworkError | All Network API | 网络错误,请查看错误信息了解详情。 |