Group
1. Overview
PGOS Group is a service to create a persistent grouping mechanism for players to chat and interact with each other. A player can create or join in multiple groups. Roles of group members are provided to implement various group management features.
2. Group Management
2.1 Key Concepts of Group
Two structures are designed to describe a group in different scenarios.
- FClientGroupInfo: It can be accessed by players both in or not in the group.
- FClientGroupDetail: It can be only accessed by players in the group.
Key fields in FClientGroupInfo and FClientGroupDetail are as follows:
- group_id: The unique identifier of a group.
- name: Each group has a name to memorize or search. The maximum character limit is 300.
- icon: Uri of the group icon, player can configure a cool icon for groups they create. The maximum character limit is 1024.
- description: Descriptive text that introduces your group to other players, whether they are in the group or not. The maximum character limit is 1024.
- tags: Tags can be used to define the classification of groups.
- owner_info: The player info of group owner
- member_count: Current member count of the group.
- max_members: Max count of the group member. This field is fixed to 200 by PGOS.
- announcement: Announcement text that can be only accessed by group members.
- join_rule: The rules for players to join the group.
- Any: Means anyone with this group id can join the group.
- MemberInvite: Must be invited by group members to join the group.
- AdminInvite: Must be invited by group administrator or owner to join the group.
- Forbid: No one is allowed to join until the join rule changed.
- is_public: True if the group can be seen by player who are not in the group.
- is_offical: Identifies whether the group was created by the official staff of the game.
FClientGroupMember is designed to describe players in a group. Key fields in FClientGroupMember are as follows:
- player_info: Basic info of the group member with type of FPlayerInfo.
- nickname: Each group member could have a nick name.
- remark: Member's remark can be set by group owner or administrator. Remark can be used to customize the classification of group members.
- is_owner: True means the group is owned by this player.
- is_admin: True means the player is an administrator.
2.2 Create / Join / Leave a Group
A player can create up to 5 groups by calling UPgosGroupAPI::CreateGroup
API. The player who creates the group will be the group owner. A pointer to FClientGroupDetail
structure will be returned if the API executes successfully.
#include "PgosSDKCpp.h"
void SomeUObjectClass::SomeFunction()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
FClientCreatGroupParams params;
// Fill create group params
Group->CreateGroup(params, [](const FPgosResult& Ret, const FClientGroupDetail* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("CreateGroup Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("CreateGroup Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
A player can join a existing group by calling UPgosGroupAPI::JoinGroup
API. It should be noted that each player can join up to 100 groups, including the groups they created. A pointer to FClientGroupDetail structure will be returned if the API is called successfully.
#include "PgosSDKCpp.h"
void SomeUObjectClass::SomeFunction()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
FString GroupID;
Group->JoinGroup(GroupID, [](const FPgosResult& Ret, const FClientGroupDetail* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("JoinGroup Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("JoinGroup Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
A player can leave a group by calling UPgosGroupAPI::LeaveGroup
API. A group owner can not leave the group unless the ownership is transferred to another group member.
#include "PgosSDKCpp.h"
void SomeUObjectClass::SomeFunction()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
FString GroupID;
Group->LeaveGroup(GroupID, [](const FPgosResult& Ret, const FClientGroupDetail* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("LeaveGroup Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("LeaveGroup Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
A group owner can dismiss a group permanently by calling UPgosGroupAPI::DismissGroup
API. All group members except the owner will receive a OnGroupDismissed
event when the group is dismissed.
#include "PgosSDKCpp.h"
void SomeUObjectClass::SomeFunction()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
FString GroupID;
Group->DismissGroup(GroupID, [](const FPgosResult& Ret, const FClientGroupDetail* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("DismissGroup Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("DismissGroup Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
Key Error Codes
2.3 Create an Official Group
Official group is designed to assist game operators to manage and guide players to create a better social environment in game. The differences between the official group to the non-official group are as follows
- An official group can only be created via PGOS web portal.
- An official group has a larger limit on the number of group members.
- Official groups do not take up the group owner's group creation limit.
You can create an official group on the web portal as shown below.
2.4 Groups Searching
UPgosGroupAPI::SearchGroup
is provided to search public groups, no matter whether the groups are official or not.
Filters can be used when searching for groups:
- official_filter: filter the
is_official
field of the groups. - left_room_filter: use this filter to specify whether the retrieved group is full.
- tags_filter: filter groups with specified tags.
If no filters are specified, a set of PGOS recommended groups will be returned.
#include "PgosSDKCpp.h"
void SomeUObjectClass::SomeFunction()
{
FClientSearchGroupParams params;
params.official_filter = FClientGroupOfficialFilterType::Dummy;
params.left_room_filter = FClientGroupRoomFilterType::Dummy;
params.tags_filter = [];
params.order_by = FClientGroupOrderBy::Dummy;
params.order_type = FClientGroupOrderType::Dummy;
params.offset = 0;
params.count = 20;
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
Group->SearchGroup(params, [](const FPgosResult& Ret, const SearchGroupRsp* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("SearchGroup Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("SearchGroup Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
2.5 Group Invitation
Another way to join a group is being invited by group members. The invitation behavior is constrained by the join_rule parameter.
A OnGroupInvitation
event will be triggered if the invitee is online, PGOS will cache invitations for offline players. After a player logs in, the UPgosGroupAPI::GetGroupInvitations
API can be called to retrieve all invitations sent to the player.
Players can accept an invitation by calling UPgosGroupAPI::AcceptGroupInvitation
API, then the player will automatically join the group. Players can reject a invitation by calling UPgosGroupAPI::RejectGroupInvitation
API. The invitation that has been processed will be removed from the player's invitation list.
#include "PgosSDKCpp.h"
// Invite some players with msg 'Join us for having fun!'
void SomeUObjectClass::SomeFunction()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
FClientInvitePlayersToGroupParams Params;
// Fill invite players params
Group->InvitePlayersToGroup(Params, [](const FPgosResult& Ret) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("InvitePlayersToGroup Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("InvitePlayersToGroup Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
// Get group invitation list
void SomeUObjectClass::SomeFunction()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
Group->GetGroupInvitations(GroupID, [](const FPgosResult& Ret, const TArray<FClientGroupInvitation>* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("GetGroupInvitations Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("GetGroupInvitations Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
// Accept a group invitation
void SomeUObjectClass::SomeFunction()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
FString GroupID;
FString InvitationId;
Group->AcceptGroupInvitation(GroupID, [](const FPgosResult& Ret, const FClientAcceptGroupInvitationRsp* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("AcceptGroupInvitation Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("AcceptGroupInvitation Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
// Reject a group invitation
void SomeUObjectClass::SomeFunction()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
FString GroupID;
FString InvitationId;
Group->RejectGroupInvitation(GroupID, [](const FPgosResult& Ret, const FClientRejectGroupInvitationRsp* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("RejectGroupInvitation Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("RejectGroupInvitation Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
2.6 Modify Group Info
Only group owner or administrator can modify group info. The fields that can be modified are as follows:
Field | API |
---|---|
name | UPgosGroupAPI::SetGroupName |
icon | UPgosGroupAPI::SetGroupIcon |
description | UPgosGroupAPI::SetGroupDesc |
announcement | UPgosGroupAPI::SetGroupAnnouncement |
join_rule | UPgosGroupAPI::SetGroupJoinRule |
is_public | UPgosGroupAPI::SetGroupPublic |
The interfaces above follow the same pattern. The sample code is given below by taking SetGroupName
as an example.
#include "PgosSDKCpp.h"
// Invite some players with msg 'Join us for having fun!'
void SomeUObjectClass::SomeFunction()
{
FClientSetGroupNameParams Params;
// Fille set group name params;
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
Group->SetGroupName(Params, [](const FPgosResult& Ret, const FClientGroupDetail* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("SetGroupName Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("SetGroupName Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
2.7 Manage Group Members
Group members with different roles have different group management permissions:
Operation | Roles | Target People | Permission |
---|---|---|---|
Set remark | Owner | Any players in the group | ✅ |
Administrator | Any players in the group | ✅ | |
Mute | Owner | Any players in the group except himself | ✅ |
Owner | Himself | ❌ | |
Administrator | Any players in the group except himself and owner | ✅ | |
Administrator | Owner and himself | ❌ | |
Unmute | Owner | Any players in the group | ✅ |
Administrator | Any players in the group | ✅ | |
Remove | Owner | Any players in the group except himself | ✅ |
Owner | Himself | ❌ | |
Administrator | General group members | ✅ | |
Administrator | Owner, himself and other adminisrators | ❌ |
Examples of these interfaces are given below.
Use UPgosGroupAPI::GetGroupMembers
API to get the set of group members. The response data is a disordered map, so that the game should arrange the order of players in the member list on demand.
#include "PgosSDKCpp.h"
struct FClientGetGroupMembersRsp
{
/** Group members, key: player id, value: group member information. */
TMap<FString, FClientGroupMember> group_members;
/** Muted group members, key: player id, value: muted member information. */
TMap<FString, FClientMutedGroupMember> muted_members;
};
void SomeUObjectClass::SomeFunction()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
Group->GetGroupMembers(GroupID, [](const FPgosResult& Ret, const FClientGetGroupMembersRsp* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("GetGroupMembers Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("GetGroupMembers Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
Use UPgosGroupAPI::GetGroupMember
API to get a group member info.
#include "PgosSDKCpp.h"
struct FClientGetGroupMemberRsp
{
/** Whether the player is a member of a group. */
bool is_member;
/** Group member information. */
FClientMutedGroupMember member_info;
};
void SomeUObjectClass::SomeFunction()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
Group->GetGroupMember(GroupID, PlayerID, [](const FPgosResult& Ret, const FClientGetGroupMemberRsp* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("GetGroupMember Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("GetGroupMember Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
Use UPgosGroupAPI::SetMyGroupNickname
API to modify nick name of the currently logged in player.
#include "PgosSDKCpp.h"
void SomeUObjectClass::SomeFunction()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
SetMyGroupNickname Params;
// Fille set my group nickname params
Group->SetMyGroupNickname(Params, [](const FPgosResult& Ret) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("SetMyGroupNickName Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("SetMyGroupNickName Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
Use UPgosGroupAPI::RemoveGroupMember
API to remove player from a group.
#include "PgosSDKCpp.h"
void SomeUObjectClass::SomeFunction()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
FString GroupId;
FString PlayerId;
Group->RemoveGroupMember(GroupID, PlayerId, [](const FPgosResult& Ret) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("RemoveGroupMember Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("RemoveGroupMember Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
Use UPgosGroupAPI::SetGroupMemberRemark
API to set remark for group members. This API have a batch edition UPgosGroupAPI::BatchSetGroupMemberRemark
.
#include "PgosSDKCpp.h"
void SomeUObjectClass::SomeFunction()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
FClientSetGroupMemberRemarkParams Params;
// Fill params
Group->SetGroupMemberRemark(Params, [](const FPgosResult& Ret) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("SetGroupMemberRemark Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("SetGroupMemberRemark Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
Use UPgosGroupAPI::MuteGroupMember
and UPgosGroupAPI::UnmuteGroupMember
to mute or mute a groum member.
#include "PgosSDKCpp.h"
// Mute
void SomeUObjectClass::SomeFunction()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
FString GroupId;
FString PlayerId;
int32 MuteMins = 1;
Group->MuteGroupMember(GroupID, PlayerId, MuteMins, [](const FPgosResult& Ret, const FClientGroupMember* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("MuteGroupMember Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("MuteGroupMember Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
// Unmute
void SomeUObjectClass::SomeFunction()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
FString GroupId;
FString PlayerId;
Group->UnmuteGroupMember(GroupID, PlayerId, [](const FPgosResult& Ret) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("UnmuteGroupMember Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("UnmuteGroupMember Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
Use UPgosGroupAPI::GrantGroupAdmin
and UPgosGroupAPI::RevokeGroupAdmin
to grant or revoke administrator role. These API could only be by group owner.
#include "PgosSDKCpp.h"
// Grant
void SomeUObjectClass::SomeFunction()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
FString GroupId;
FString PlayerId;
Group->GrantGroupAdmin(GroupID, PlayerId, [](const FPgosResult& Ret) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("GrantGroupAdmin Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("GrantGroupAdmin Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
// Revoke
void SomeUObjectClass::SomeFunction()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
FString GroupId;
FString PlayerId;
Group->RevokeGroupAdmin(GroupID, PlayerId, [](const FPgosResult& Ret) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("RevokeGroupAdmin Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("RevokeGroupAdmin Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
User UPgosGroupAPI::TransferGroupOwnership
to transfer group owner role to a group member or administrators. These API could only be by group owner.
#include "PgosSDKCpp.h"
void SomeUObjectClass::SomeFunction()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
FString GroupId;
FString PlayerId;
Group->TransferGroupOwnership(GroupID, PlayerId, [](const FPgosResult& Ret) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("TransferGroupOwnership Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("TransferGroupOwnership Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
2.8 Get Group Info / Detail
Use UPgosGroupAPI::GetGroupInfo
to request basic information of a group that the player hasn't joined yet.
#include "PgosSDKCpp.h"
void SomeUObjectClass::SomeFunction()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
FString GroupId;
Group->GetGroupInfo(GroupID, [](const FPgosResult& Ret, const FClientGroupInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("GetGroupInfo Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("GetGroupInfo Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
Use UPgosGroupAPI::GetGroupDetail
to request detail information of a group that the player has joined. This API have a batch edition UPgosGroupAPI::BatchGetGroupDetail
.
#include "PgosSDKCpp.h"
void SomeUObjectClass::SomeFunction()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
FString GroupId;
Group->GetGroupDetail(GroupID, [](const FPgosResult& Ret, const FClientGroupDetail* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("GetGroupDetail Successfully"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("GetGroupDetail Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
Key Error Codes
2.9 Group Discovery
Use UPgosGroupAPI::GetGroupDiscoveryList
to paging to get the number of group discoveries. You can additionally obtain the specified number of recommendation groups configured on the portal.
- The Group service calculates a score for each group based on activity and other rules on a daily basis. The top 20,000 groups with the highest scores are selected and sorted in descending order. You can use the
offset
andcount
parameters ofGetGroupDiscoveryList
API to get groups by page. - Games can also obtain additional recommended groups. Game operators can configure a certain number of recommended groups on the portal, and some of these groups can be pinned to the top. Game developers can use the
recommend_count
parameter of theGetGroupDiscoveryList
API to retrieve a specified maximum number of recommended groups. During retrieval, the API will randomly selectrecommend_count
recommended groups from the configured ones on the portal, retrieve the top groups first. - The
GetGroupDiscoveryList
API also has anowner_os
parameter. Games can use this parameter to retrieve groups where the group owner's operating system matches the specified OS. In most cases, this parameter can be left empty.
Interface prototype:
struct FClientGetGroupDiscoveryListParams
{
/** Only obtain groups where the group owner's OS is the specified OS. Currently supports passing in at most one OS. Empty means no filtering based on OS. */
TArray<EClientOS> owner_os;
/**
* Get the number of recommended groups additionally, cannot exceed 50.
* Recommended groups can be configured on the portal.
*/
int32 recommend_count = 0;
/** The starting position of the list. */
int32 offset = 0;
/** The query count, cannot exceed 50. */
int32 count = 0;
};
/**
* Paging to get the number of group discoveries. You can additionally obtain the specified number of recommendation groups configured on the portal.
*
* @param Params
*/
void GetGroupDiscoveryList(
const FClientGetGroupDiscoveryListParams& Params,
TFunction<void(const FPgosResult& Ret, const FClientGetGroupDiscoveryListResult* Data)> Callback) const;
Example Code:
#include "PgosSDKCpp.h"
void SomeUObjectClass::SomeFunction()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
FClientGetGroupDiscoveryListParams Params;
Group->GetGroupDiscoveryList(Params, [](const FPgosResult& Ret, const FClientGetGroupDiscoveryListResult* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("GetGroupDiscoveryList Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("GetGroupDiscoveryList Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
2.10 Custom Data Handling
Group Custom Data is used to help game to extend the group. Each Group has two tiers of custom data: Global Custom Data
and Player Custom Data
. Game developers can store any data in there to implement the specific functionality.
Global Custom Data
is a k-v map, that stores the data for the global scope. All members can visit it, but only group owner and administer has permission to store and modify in the game client.
Player Custom Data
is a string->string (playerid -> data) map, that stores the data for every group members, the key is the playerid and the value is the data that is set by the owner member. All members can visit it, but the player only has permission to store and modify their own player custom data. Group owner and administer could modify all group members player custom data.
All members will receive the GroupGlobalCustomDataChangedEvt
or GroupPlayerCustomDataChangedEvt
event in the game client when any custom data was changed, including global custom data and player custom data.
Call SetGroupGlobalCustomData
to set global custom data for a group:
#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"
void SomeUObjectClass::SetGroupGlobalCustomData()
{
auto group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (group)
{
SetGroupGlobalCustomDataParams params;
group->SetGroupGlobalCustomData(params, [](
const FPgosResult& Ret, const SetGroupGlobalCustomDataResult * Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
Call DelGroupGlobalCustomData
to delete any fields of global custom data by keys:
#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"
void SomeUObjectClass::DelGroupGlobalCustomData()
{
auto group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (group)
{
DelGroupGlobalCustomDataParams params;
group->DelGroupGlobalCustomData(params, [](
const FPgosResult& Ret, const DelGroupGlobalCustomDataResult * Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
Call ClearGroupGlobalCustomData
to clear all group global custom data fields:
#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"
void SomeUObjectClass::ClearGroupGlobalCustomData()
{
auto group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (group)
{
ClearGroupGlobalCustomDataParams params;
group->ClearGroupGlobalCustomData(params, [](const FPgosResult& Ret) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
Call SetGroupMyPlayerCustomData
to set player owned custom data:
#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"
void SomeUObjectClass::SetGroupMyPlayerCustomData()
{
auto group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (group)
{
SetGroupMyPlayerCustomDataParams params;
group->SetGroupMyPlayerCustomData(params, [](
const FPgosResult& Ret, const SetGroupMyPlayerCustomDataResult * Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
Call BatchSetGroupPlayerCustomData
to batch set player owned custom data. Please note that only group owner or administer has permission to modify other group member's player custom data:
#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"
void SomeUObjectClass::BatchSetGroupPlayerCustomData()
{
auto group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (group)
{
BatchSetGroupPlayerCustomDataParams params;
group->BatchSetGroupPlayerCustomData(params, [](
const FPgosResult& Ret, const BatchSetGroupPlayerCustomDataResult * Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
2.11 Group Management Events
To summarize, the events that will be sent to players by group service are listed below:
Event Name | Event Description |
---|---|
OnGroupInvitation | The event will be triggered when received a group invitation. |
OnRemovedFromGroup | The event will be triggered when a player is removed from the group. |
OnMutedInGroup | The event will be triggered when a player is muted in the group. |
OnUnmutedInGroup | The event will be triggered when a player is unmuted in the group. |
OnGroupDismissed | The event will be triggered when the group is dismissed by group owner. |
OnBadgeNumOfGroupInvitation | The event will be triggered when a player logs in PGOS or the group invitation list changes. |
You can use UPgosClientEventDispatcher
to handle event binding issues for these events.
Bind dynamic delegate to OnGroupInvitation
as follows,
#include "PgosSDKCpp.h"
void SomeUObjectClass::SomeFunction()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
Group->OnGroupInvitation().AddUObject(this, &SomeUObjectClass::OnGroupInvitation);
}
}
void SomeUObjectClass::OnGroupInvitation(const FClientGroupInvitationEvt& event)
{
UE_LOG(LogTemp, Log, TEXT("OnGroupInvitation"));
}
#include "PgosClientEventDispatcher.h"
void SomeUObjectClass::SomeFunction()
{
auto pDispatcher = UPgosClientEventDispatcher::GetPgosClientEventDispatcher();
if (pDispatcher)
{
pDispatcher->OnPlayerSessionChanged.Clear();
// add delegate callback
UPgosClientEventDispatcher::GetPgosClientEventDispatcher()->OnGroupInvitation.AddDynamic(
this,
&SomeUObjectClass::OnGroupInvitation);
// Before current object is destroyed, you should call
// `UPgosClientEventDispatcher::GetPgosClientEventDispatcher()->RemoveAll(this)`
// to clear event bindings.
}
}
void SomeUObjectClass::OnGroupInvitation(const FClientGroupInvitationEvt& event)
{
UE_LOG(LogTemp, Log, TEXT("OnGroupInvitation"));
}
3. Group Chat
3.1 General Sequence
Here is a general sequence for using the group chat:
A possible group chat interaction is as follows:
- After successful login, the group entry icon shows the number of unread group messages.
- Click on the group icon to open the group chat window.
- The window first displays a list of the group chat conversations.
- Select a conversation to display the chat content with the corresponding group.
- Chat in group.
3.2 Data Structure
Group chat uses two import data structures: FClientGroupMsgInfo
and FClientGroupChatItem
.
FClientGroupMsgInfo
: used to display message content,FClientGroupChatItem
: used to display player conversations.
struct FClientGroupMsgInfo
{
/** The member who sends the message */
FClientGroupMember sender;
/** The time the message was sent */
int64 sent_time;
/** The type of messages */
EClientChatMsgType msg_type;
/** The message to be sent */
FClientGroupMsgContent content;
/** The sequence number of messages */
int64 seq;
/** Additional information added by the game */
FString custom_data;
/**
* The mentioned player list.
* The mentioned players will receive the corresponding events. When the value of player_id is '@ALL', it means mentioning all players.
*/
TArray<FClientMentionedPlayer> mentioned_players;
};
struct FClientGroupChatItem
{
/** Group brief introduction */
FClientGroupBrief group_brief;
/** Recent chat message info */
FClientGroupMsgInfo latest_msg;
/** Unread messages count */
int32 unread_count;
};
enum class EClientChatMsgType : uint8
{
/** Type of text message, sent via SendGroupTextMsg. */
MsgTypeText = 0,
/** Type of custom message, sent via SendGroupCustomMsg. */
MsgTypeCustom = 1,
/** Type of event message, sent by the system. */
MsgTypeEvent = 2
};
struct FClientGroupMsgContent
{
/** Take the value from here when msg type is MsgTypeText */
FString text_content;
/** Take the value from here when msg type is MsgTypeEvent */
FClientGroupMsgEventContent event_content;
/** Take the value from here when msg type is MsgTypeCustom */
FString custom_content;
};
The EClientChatMsgType
type corresponds to the fields in FClientGroupMsgContent
.
Currently, EClientChatMsgType
includes MsgTypeText , MsgTypeCustom and MsgTypeEvent.
- When
EClientChatMsgType
is MsgTypeText, the message content is in text_content ofFClientGroupMsgContent
. - When
EClientChatMsgType
is MsgTypeCustom, the message content is in custom_content ofFClientGroupMsgContent
. - When
EClientChatMsgType
is MsgTypeEvent, the message content is in event_content ofFClientGroupMsgContent
.
In addition to the data structures above, you may also want to understand the following concepts:
- seq: The sequence number of the message increases as players receive more messages from a given player.
- unread group chat messages: group chat messages that are not read.
3.2.1 Group Chat Storage
The sent and received messages in a group chat are stored in the client's local database. Each account uses a separate database file to save group chat messages. You can configure the chat_msg_cache_max_bytes
value to limit the max size of a single database file. We also provide the GetLocalCacheSize API to obtain the database file size and the ClearLocalCache API to clear chat records. You can use these APIs to prompt the user to clear chat records when the database file is too large.
Note:
The minimum value of
chat_msg_cache_max_bytes
is 1 MB (1048576). We do not recommend setting a value over 100 MB. If you do not specify a value, it takes the default value of 100 MB. When a single database file exceeds the value ofchat_msg_cache_max_bytes
, PGOS will automatically delete older messages to free up space.
3.2.2 Event Message Filtering
There are now a variety of event messages, and the game may require all or part of the types.
All event messages are supported by default, all event messages will trigger the OnReceiveGroupMsg event, and all event message types will also appear in the GetMyGroupChatList
, GetGroupMsgList
interfaces. If the game only needs some event message types and completely filter out other event messages, it can be modified through the configuration file (pgos_client.ini) or UPgosClientAPI::InitConfig
API:
- group_event_msg_filter is empty: all event message types are required.
group_event_msg_filter =
- group_event_msg_filter is 0 (the value of EClientGroupEventType::Dummy): Indicates that no event message is required, and all event messages are filtered out.
group_event_msg_filter = 0
- group_event_msg_filter for multiple event types: use "," to concatenate the value of the event type of the event message that needs to be supported.
; For example, only need GroupNameChanged, GroupDescChanged, GroupMemberJoined
group_event_msg_filter = 1,2,3
Note:
Event messages are not counted as unread.
3.3 Using Group Chat
3.3.1 Obtain My Group List
When players are preparing to initiate a group chat, they may need to use the GetMyGroupList
API to view the joined group list.
/**
* Get my group chat list
*/
void GetMyGroupChatList(TFunction<void(const FPgosResult& Ret, const FClientGetMyGroupChatListResult* Data)> Callback) const;
The returned result is saved in the FClientGetMyGroupChatListResult
structure. The priority of the return value list is as follows: Number of unread messages > time of the last message.
struct FClientGetMyGroupChatListResult
{
/** My group conversation list */
TArray<FClientGroupChatItem> group_chat_list;
};
struct FClientGroupChatItem
{
/** Group brief information */
FClientGroupBrief group_brief;
/** Recent chat message info */
FClientGroupMsgInfo latest_msg;
/** Unread message count */
int32 unread_count;
};
Call GetMyGroupChatList
from Group module, as follows:
#include "PgosSDKCpp.h"
void SomeUObjectClass::SomeFunction()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
Group->GetMyGroupChatList([](const FPgosResult& Ret, const FClientGetMyGroupChatListResult* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("GetMyGroupChatList "));
}
else
{
UE_LOG(LogTemp, Log, TEXT("GetMyGroupChatList Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
3.3.2 Obtain Group Chat Message List
PGOS stores the group chat messages locally. You can use the GetGroupMsgList
, paginated query function to obtain chat records of the specified group.
/**
* Get chat message list in a group
*
* @param GroupId The group ID
* @param StartSeq The start sequence number of the message to query, 0 means starting from the latest message.
* @param Count The count of messages to get
*/
void GetGroupMsgList(
const FString& GroupId,
int64 StartSeq,
int32 Count,
TFunction<void(const FPgosResult& Ret, const FClientGetGroupChatMsgListResult* Data)> Callback) const;
The returned results are saved in the FClientGetGroupChatMsgListResult
structure:
struct FClientGetGroupChatMsgListResult
{
/** Chat messages list */
TArray<FClientGroupMsgInfo> msg_list;
/** Whether there are more messages */
bool has_more;
/** The starting sequence for the next query */
int64 next_seq;
};
The mechanism to locally store chat records and obtain chat records is shown in the image below:
Call GetGroupMsgList
from Group module, as follows:
#include "PgosSDKCpp.h"
void SomeUObjectClass::SomeFunction()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
FString GroupId;
int64 StartSeq;
int32 Count;
Group->GetGroupMsgList(GroupId, StartSeq, Count, [](const FPgosResult& Ret, const FClientGetGroupChatMsgListResult* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("GetGroupMsgList "));
}
else
{
UE_LOG(LogTemp, Log, TEXT("GetGroupMsgList Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
3.3.3 Send Group Chat Message
Players can send messages to groups they have joined. After the group chat message is sent, other online players in the group will receive it. The group chat cannot get offline messages, that is, after the player goes online, he cannot get the messages sent in the group while he is offline.
There are two ways to send messages:
SendGroupTextMsg: Send a simple text message. The
msg_type
of the message isMsgTypeText
, and the text content of the message is stored incontent.text_content
.SendGroupCustomMsg: It is used to send game custom messages. The
msg_type
of the message isMsgTypeCustom
, and the content of the message is stored incontent.custom_content
./**
* Send group chat text messages
*
* @param TextMsgReq Request struct for sending text message
*/
void SendGroupTextMsg(
const FClientSendGroupMsgParams& Params,
TFunction<void(const FPgosResult& Ret, const FClientSendGroupMsgResult* Data)> Callback) const;
/**
* Send group chat custom messages
*
* @param CustomMsgReq Request struct for sending custom messages
*/
void SendGroupCustomMsg(
const FClientSendGroupMsgParams& Params,
TFunction<void(const FPgosResult& Ret, const FClientSendGroupMsgResult* Data)> Callback) const;
Here you need to pay attention to the input parameters. Take the parameter FClientSendGroupMsgParams
of the SendGroupTextMsg
interface as an example:
struct FClientSendGroupMsgParams
{
/** Group ID */
FString group_id;
/** Text content */
FString content;
/** Additional information added by the game */
FString custom_data;
/**
* The mentioned player list.
* The mentioned players will receive the corresponding events. When the value of player_id is '@ALL', it means mentioning all players.
*/
TArray<FClientMentionedPlayer> mentioned_players;
};
content is generally the input content of the user, which will be filtered by content moderation. custom_data is used for additional information added by game developers and will not be filtered by content moderation. The caveat here is not to store user input in custom_data.
mentioned_players is optional, used to mention specified players. Player_id
of FClientMentionedPlayer
is "@ALL" to mention all players. The mentioned players will receive the OnGroupNewMentioned
event.
The returned results are saved in the FClientGroupMsgInfo
structure, which is described in details above.
Call SendGroupTextMsg
/SendGroupCustomMsg
from Group module, as follows:
#include "PgosSDKCpp.h"
void SomeUObjectClass::SendGroupTextMsg()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
FClientSendGroupMsgParams Params;
Params.group_id = FString("1234");
Params.content = FString("hello");
Params.custom_data = FString("");
FClientMentionedPlayer MentionedAll;
MentionedAll.player_id = FString("@ALL"); // mention all members in the group
Params.mentioned_players.Add(MentionedAll);
Group->SendGroupTextMsg(Params, [](const FPgosResult& Ret, const FClientSendGroupMsgResult* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("SendGroupTextMsg "));
}
else
{
UE_LOG(LogTemp, Log, TEXT("SendGroupTextMsg Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
void SomeUObjectClass::SendGroupCustomMsg()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
FClientSendGroupMsgParams Params;
Params.group_id = FString("1234");
Params.content = FString("hello");
Params.custom_data = FString("");
FClientMentionedPlayer MentionedPlayer;
MentionedPlayer.player_id = FString("123456"); // mention player "123456"
MentionedPlayer.player_display_name = FString("Will");
Params.mentioned_players.Add(MentionedAll);
Group->SendGroupCustomMsg(Params, [](const FPgosResult& Ret, const FClientSendGroupMsgResult* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("SendGroupCustomMsg "));
}
else
{
UE_LOG(LogTemp, Log, TEXT("SendGroupCustomMsg Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
3.3.4 Activate a Group Chat
Players may activate a specified group chat via the ActiveGroupChat
API.
Generally, a player will constantly receive messages while in group chat. Each time they receive a message, the unread message count will increase, triggering an OnUnreadGroupMsgCountNotify
event and OnReceiveGroupMsg
event, notifying changes of total unread messages and unread messages for this group. When the player is in the group chat screen, new messages should be automatically marked as read. To avoid repeated changes in the total unread count triggers OnUnreadGroupMsgCountNotify
event again, we provide the ActiveGroupChat
API, which activates a specified group chat.
- Before activation, each new message changes the unread message count and triggers an
OnUnreadGroupMsgCountNotify
event. - After activation, the unread message count for the specified group will remain at 0, so new messages will not trigger
OnUnreadGroupMsgCountNotify
events.
As the image shown below, you are currently chatting with GroupB. When you receive messages from groupB, they are marked as read by default and do not change the total unread messages count. When you are in the chat screen with Jerry, the ActiveGroupChat
API activates the chat and Jerry's unread message count remains 0, so when you receive group chat messages from Jerry, it does not trigger OnUnreadGroupMsgCountNotify
event. When you leave the chat screen, call the API with null GroupId
so that the current conversation will be deactivated.
/**
* Set the current group chat. When setting, OnUnreadGroupMsgCountNotifyEvt for this group will NOT be pushed, and subsequent group chat messages currently in progress are automatically marked as read
*
* @param GroupId The group to set as active
*/
void ActiveGroupChat(const FString& GroupId) const;
Call ActiveGroupChat
from Group module, as follows:
#include "PgosSDKCpp.h"
void SomeClass::ActiveGroupChat(const FString& GroupId)
{
auto GroupChat = IPgosSDKCpp::Get().GetClientGroupAPI();
if (GroupChat)
{
GroupChat->ActiveGroupChat(GroupId);
}
}
Note:
- Only one group chat can be activated at a time.
- Call with empty
GroupId
to deactivate the current conversation.
3.3.5 Clear Unread Group Chat Messages Count
If all the group chat messages from a specified group are read, you can use the ClearGroupUnreadCount
API to set the unread messages count of this group to zero.
/**
* Mark messages in group as all read
*
* @param GroupId The group ID. If empty, it means all groups
*/
void ClearGroupUnreadCount(
const FString& GroupId,
TFunction<void(const FPgosResult& Ret)> Callback) const;
Call ClearGroupUnreadCount
from Group module, as follows:
#include "PgosSDKCpp.h"
void SomeClass::ClearGroupUnreadCount(const FString& GroupId)
{
auto group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (group)
{
group->ClearGroupUnreadCount(GroupId, [](const FPgosResult& Ret)
{
if (Ret.err_code == 0)
{
UE_LOG(LogTemp, Log, TEXT("ClearGroupUnreadCount "));
}
else
{
UE_LOG(LogTemp, Log, TEXT("ClearGroupUnreadCount Failed: err_code=(%d), err_msg=%s]"), Ret.err_code,
*Ret.msg);
}
});
}
}
3.3.6 Mention Players
Specified players can be mentioned when sending a message. For details, please view Send Group Chat Message
If someone in the group mentioned you, you will receive the OnGroupNewMentioned
event.
You can query the last mentioned record of the specified group by calling the interface GetGroupMentionedInfo
.
You can clear the records of the specified group mentioned you by calling the interface ClearGroupMentionedInfo
. When group_id
is empty, it means clearing the mentioned records of all groups.
Interface prototype:
/**
* Get latest record mentioning me in the group.
*
* @param GroupId Group ID.
* @param Dst The latest record mentioned me.
* @return True if there are any mentions of me.
*/
bool GetGroupMentionedInfo(
const FString& GroupId,
FClientGroupMentionedInfo& Dst) const;
/**
* Clear record mentioning me in the group.
*
* @param GroupId Group ID. If empty, it means all groups
*/
void ClearGroupMentionedInfo(const FString& GroupId) const;
Example Code:
#include "PgosSDKCpp.h"
void SomeUObjectClass::SomeFunction1()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
FString GroupId = TEXT("123");
FClientGroupMentionedInfo Dst;
auto result = Group->GetGroupMentionedInfo(GroupId, Dst);
if (result)
{
UE_LOG(LogTemp, Log, TEXT("%s mentioned you"), *Dst.msg.sender.player_info.display_name);
}
else
{
UE_LOG(LogTemp, Log, TEXT("No one mentioned you"));
}
}
}
void SomeUObjectClass::SomeFunction2()
{
auto Group = IPgosSDKCpp::Get().GetClientGroupAPI();
if (Group)
{
FString GroupId = TEXT("123");
Group->ClearGroupMentionedInfo(GroupId);
}
}
3.3.7 Monitor Group Chat Events
Some events will be triggered when using the group chat:
- OnUnreadGroupMsgCountNotify: Immediately triggered after login and when the total unread count changes. The event results are saved in
FClientUnreadMsgCountNotifyEvt
. - OnReceiveGroupMsg: Triggered when receiving a group chat message. The event results are saved in
FClientReceiveGroupMsgEvt
. - OnGroupNewMentioned Triggered when receiving a group chat message that mentioned you. The event results are saved in
FClientGroupNewMentionedEvt
.
struct FClientUnreadMsgCountNotifyEvt
{
/** Total unread count of personal chat or group chat */
int32 total_unread_count;
};
struct FClientReceiveGroupMsgEvt
{
/** Group chat message received */
FClientGroupMsgInfo msg;
/** Group brief info */
FClientGroupBrief group_brief;
/** Count of unread message from group */
int32 unread_count;
};
struct FClientGroupNewMentionedEvt
{
/** Group chat message received */
FClientGroupMsgInfo msg;
/** Group brief info */
FClientGroupBrief group_brief;
};
OnReceiveGroupMsg: Possible received message types can be distinguished according to msg_type
:
enum class EClientChatMsgType : uint8
{
/** Type of text message, sent via SendGroupTextMsg. */
MsgTypeText = 0,
/** Type of custom message, sent via SendGroupCustomMsg. */
MsgTypeCustom = 1,
/** Type of event message, sent by the system. */
MsgTypeEvent = 2
// New msg_types such as MsgTypeImage, MsgTypeVoice may be added in the future.
};
There are now three message types: MsgTypeText
, MsgTypeCustom
, MsgTypeEvent
. Where MsgTypeText
, MsgTypeCustom
are sent by the player, MsgTypeEvent
is sent by the system.
Messages of type MsgTypeEvent
are called event messages, and different event messages can be distinguished according to event_type
:
enum class EClientGroupEventType : uint8
{
Unknown = 0,
/** Group name has been changed. */
GroupNameChanged = 1,
/** Group description has been changed. */
GroupDescChanged = 2,
/** New member joined. */
GroupMemberJoined = 3,
/** Member left the group. */
GroupMemberLeft = 4,
/** Member removed. */
GroupMemberRemoved = 5,
/** Group announcement has been changed. */
GroupAnnouncementChanged = 6,
/** Group owner has changed. */
GroupOwnerChanged = 7
// New event_types may be added in the future.
};
Monitor group chat events from Group module, as follows:
#include "PgosSDKCpp.h"
void SomeClass::MonitorGroupChatEvents()
{
auto GroupChat = IPgosSDKCpp::Get().GetClientGroupAPI();
if (GroupChat)
{
GroupChat->OnUnreadGroupMsgCountNotify().AddUObject(this, &SomeClass::OnUnreadGroupMsgCountNotify);
GroupChat->OnReceiveGroupMsg().AddUObject(this, &SomeClass::OnReceiveGroupMsg);
}
}
void SomeClass::OnUnreadGroupMsgCountNotify(const FClientUnreadMsgCountNotifyEvt& Event)
{
UE_LOG(LogTemp, Log, TEXT("OnUnreadGroupMsgCountNotify"));
}
void SomeClass::OnReceiveGroupMsg(const FClientReceiveGroupMsgEvt& Event)
{
UE_LOG(LogTemp, Log, TEXT("OnReceiveGroupMsg"));
const auto MsgType = Event.msg.msg_type;
if (MsgType == EClientChatMsgType::MsgTypeText)
{
UE_LOG(LogTemp, Log, TEXT("receive text msg, content=(%s)"), *Event.msg.content.text_content);
} else if (MsgType == EClientChatMsgType::MsgTypeCustom) {
UE_LOG(LogTemp, Log, TEXT("receive custom msg, content=(%s)"), *Event.msg.content.custom_content);
} else if (MsgType == EClientChatMsgType::MsgTypeEvent) {
const auto EventType = Event.msg.content.event_content.event_type;
UE_LOG(LogTemp, Log, TEXT("receive event msg, event_type=(%d)"), *EventType);
if (EventType == EClientGroupEventType::GroupNameChanged) {
const auto GroupNameChanged = Event.msg.content.event_content.group_name_changed;
UE_LOG(LogTemp, Log, TEXT("group name changed, new group_name=(%s)"), *GroupNameChanged.group_name);
} else if (EventType == EClientGroupEventType::GroupMemberJoined) {
const auto GroupMemberJoined = Event.msg.content.event_content.group_member_joined;
UE_LOG(LogTemp, Log, TEXT("new member joined, name=(%s)"), *GroupMemberJoined.member_info.display_name);
}
// ......
}
}
4. Portal Operation
You can query group list on the web portal as shown below.
You can click Add Official Group
button to create an official group.
You can enter a specified group and click Dismiss
button to dismiss a group on the group detail page.
You can query group list of a specified player on the web portal as shown below.
5. Key Error Handling
Error Code | Relevant API | Handling Suggestion |
---|---|---|
PgosErrCode::kBackendProfaneName | CreateGroup ModifyGroupInfo | When there are sensitive words, the API will return an error. Please check the input data of the API. |
PgosErrCode::kBackendGroupNotPublic | GetGroupInfo | It means that the group information does not allow unjoined players to access. |
PgosErrCode::kBackendIMChatFrequencyLimit | SendGroupTextMsg SendGroupCustomMsg | It means that the operation frequency exceeds limit. It's recommended to retry with exponentially expanded interval: 5s, 10s, 20s, etc. |
PgosErrCode::kBackendIMChatMsgIsTooLong | SendGroupTextMsg SendGroupCustomMsg | It means that the message content is too long. The limit is 1000 characters. The game should prompt player with a message like "Message too long, please shorten it or split it in multiple messages." |
PgosErrCode::kBackendIMChatCustomDataIsTooLong | SendGroupTextMsg SendGroupCustomMsg | It means that the custom data is too long. The limit is 8000 bytes. The game catch this error and avoid using super long custom data. |
PgosErrCode::kBackendIMPlayerBlockedByAdmin | SendGroupTextMsg SendGroupCustomMsg | It means that the player is muted by admin. The game should prompt player with a message like "Muted by administrator, please retry later." |
PgosErrCode::kBackendProfaneWords | SendGroupTextMsg SendGroupCustomMsg CreateGroup ModifyGroupInfo | It means the message content contains profane words and cannot be masked. The game should prompt the player with a message like "Please remove profane words to send message." |
PgosErrCode::kBackendErrPlayerIsPunished | SendGroupTextMsg SendGroupCustomMsg ModifyGroupInfo | The player is punished. msg is the json serialized string of deadline(unix timestamp (in seconds) at the end of the punishment, <= 0 means permanent punishment) and reason. |