跳到主要内容

玩家信息

1. 概述

玩家信息是用于描述玩家的核心属性集合。具体来说,它包含两个部分:

  • 基础信息是内置的不可修改字段,如player_iddisplay_nameavatar_uri
  • 自定义信息是由游戏自定义的字段,这是来自玩家数据模板.的核心数据集。

完成本教程后,您将了解以下内容:

  • 如何在网页端查看和修改玩家信息。
  • 如何在代码中查询和更新玩家信息。

2. 门户网站上的玩家信息

2.1 查看玩家信息

登录网页门户,进入控制台并前往玩家 > 查询

image-20210809163842712

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

image-20211111172326538

2.2 玩家信息定义

玩家信息通常作为一个核心属性集合,用于在好友、组队和房间等服务模块中描述玩家。由于其基本信息是由 PGOS 以通用性为目标定义的,无法满足游戏描述玩家核心属性的所有需求。因此,PGOS 为游戏提供了一种扩展玩家信息的方式:从玩家数据模板中选择某些项作为玩家信息的一部分,这被称为自定义信息。

自定义信息旨在使玩家信息更加丰富,因为玩家信息可能不足以描述玩家的"基本信息"。例如,当玩家收到陌生人的好友请求时,游戏可能需要向玩家显示该陌生人的"等级",这可以从玩家数据中获取,但那将需要另一个 API 调用。如果游戏将"等级"添加到自定义信息中,使其成为玩家基本信息的一部分,游戏就不需要额外的 API 调用,这为开发带来了便利。

进入控制台并前往玩家 > 玩家信息定义

image-20211117164858714

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

image-20211111192443475

开发者可以通过 FPlayerInfo::custom_info 访问自定义信息,详见数据结构. >❗ 注意: > >玩家自定义信息中的数据项对所有玩家都是可见的。虽然您可以将任何数据项添加为自定义信息(无论其访问权限如何),但我们仍建议您谨慎考虑这样做。另外需要注意的是,如果向自定义信息中添加过多数据项,可能会导致不必要的性能问题。

3. 数据结构

3.1 玩家信息和玩家详情

玩家信息有两种数据结构:FPlayerInfoFPlayerDetailFPlayerDetail 继承自 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 usedOpen IDAccount IDPlayer ID
PGOS FASFAS IDFAS IDPGOS Player ID
Steamworks SDKSteam IDSteam IDPGOS Player ID
INTL SDK (e.g. Login on Steam)INTL Open IDSteam IDPGOS Player ID
PlayFab SDK (e.g. Login on Steam)PlayFab IDSteam IDPGOS Player ID

4. 查询玩家信息

您可以一次性获取一个或多个玩家的信息。

4.1 游戏客户端

APIDescription
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);
}
});
}
}
提示

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);
}
});
}
}
提示

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);
}
});
}
}
提示

4.2 For Game Server

APIDescription
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);
}
});
}
}
提示

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);
}
});
}
}
提示

5. 更新玩家信息

玩家只能更新自己的玩家信息,不能更新其他玩家的信息。

5.1 游戏客户端

APIDescription
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);
}
});
}
}
提示

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);
}
});
}
}
提示

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);
}
});
}
}
提示

6. Key Error Handling

Error CodeRelevant APIHandling Suggestion
kBackendPlayerDisplayNameContainProfanityWordsSetMyName提交的新玩家昵称包含不当用语。游戏可以提示玩家输入合法的显示名称。
kBackendPlayerDisplayNameVerificationFailedSetMyName在游戏区服内玩家的玩家昵称必须是唯一的,您要设置的玩家昵称已存在。
kBackendDisplayNameAlreadyExistsSetMyName玩家受到惩罚。msg是一个JSON序列化字符串,包含截止时间(惩罚结束时的Unix时间戳(以秒为单位),小于等于0表示永久惩罚)和原因。
kBackendErrPlayerIsPunishedSetMyName玩家受到惩罚。msg是一个JSON序列化字符串,包含截止时间(惩罚结束时的Unix时间戳(以秒为单位),小于等于0表示永久惩罚)和原因。
kSdkNetworkErrorAll Network API网络错误,请查看错误信息了解详情。