即时聊天
1. 概述
本文档介绍游戏内即时聊天功能的使用。
即时聊天:用于多人之间的即时文字聊天。所有加入同一频道的玩家都可以互相聊天。当聊天中的所有玩家离开频道或下线后,该频道会自动删除。
即时聊天应用场景:可用于对战中同队玩家之间的聊天,或者玩家自定义发起的多人聊天功能。
除了即时聊天,部分 PGOS 服务也内置了文字聊天功能。详情请参见组队和房间文档。
完成本教程后,开发者将了解:
- PGOS 即时聊天的基本概念
- 如何加入/离开即时聊天
- 如何发送和接收即时聊天消息
- 即时聊天事件介绍及如何监听
2. 流程
以下是使用即时聊天的流程:
3. 定义
- 聊天频道: 即时聊天的频道。频道ID用于区分不同的频道。加入同一频道的玩家可以互相聊天。
4. 使用即时聊天
4.1 加入即时聊天
在调用其他即时聊天功能之前,玩家必须先加入一个频道,否则这些功能将无法使用。玩家可以通过调用JoinInstantChat
接口来加入频道。
/**
* Join a text channel chat
*
* @param ChatChannelId A custom unique ID used to identify the channel (in game scope), must be 127 characters or less, can use battle-session-id which base on UUID with 36 characters.
*/
void JoinInstantChat(
const FString& ChatChannelId,
TFunction<void(const FPgosResult& Ret, const FClientJoinInstantChatResult* Data)> Callback) const;
开发者可以根据使用即时聊天服务的Instance ID生成即时聊天频道ID。
典型应用场景: 在对战中使用即时聊天。
battle_session_id
是一个36个字符的UUID。您可以使用battle_session_id
拼接其他信息作为ChatChannelId
。如果对战中的玩家需要加入多个即时聊天频道,您可以通过在battle_session_id
末尾添加不同信息来设置多个ChatChannelId
值。
struct FClientBattleSessionInfo
{
/** The battle session id to query */
FString battle_session_id;
...
};
按照以下方式调用 InstantChat 模块中的 JoinInstantChat
:
#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"
void SomeClass::JoinInstantChat(const FString& ChatChannelId)
{
auto instant_chat = IPgosSDKCpp::Get().GetClientInstantChatAPI();
if (instant_chat)
{
instant_chat->JoinInstantChat(ChatChannelId, [](const FPgosResult& Ret, const FClientJoinInstantChatResult* Result)
{
if (Ret.err_code == 0)
{
UE_LOG(LogTemp, Log, TEXT("JoinInstantChat Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("JoinInstantChat Failed: err_code=(%d), err_msg=%s]"), Ret.err_code, *Ret.msg);
}
});
}
}
注意: 单个玩家最多可同时加入20个频道。
4.2 退出即时聊天
如果玩家不想继续在某个即时聊天频道中聊天,可以通过调用LeaveInstantChat
接口退出当前频道。
当玩家离线时,PGOS会自动将其从已加入的即时聊天频道中移除。
/**
* Leave a text channel chat
*
* @param ChatChannelId The chat channel id to leave
*/
void LeaveInstantChat(
const FString& ChatChannelId,
TFunction<void(const FPgosResult& Ret)> Callback) const;
按照以下方式调用 InstantChat 模块中的 LeaveInstantChat
:
#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"
void SomeClass::LeaveInstantChat(const FString& ChatChannelId)
{
auto instant_chat = IPgosSDKCpp::Get().GetClientInstantChatAPI();
if (instant_chat)
{
instant_chat->LeaveInstantChat(ChatChannelId, [](const FPgosResult& Ret)
{
if (Ret.err_code == 0)
{
UE_LOG(LogTemp, Log, TEXT("LeaveInstantChat Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("LeaveInstantChat Failed: err_code=(%d), err_msg=%s]"), Ret.err_code, *Ret.msg);
}
});
}
}
4.3 发送即时聊天消息
加入即时聊天频道后,玩家可以向频道发送消息,频道内的其他玩家将会收到这些消息。
/**
* Send instant text chat message
*
* @param Params Request struct for sending instant chat message
*/
void SendInstantChatTextMsg(
const FClientSendInstantChatMsgParams& Params,
TFunction<void(const FPgosResult& Ret, const FClientChatMsgInfo* Data)> Callback) const;
/**
* Send instant custom chat message
*
* @param Params Request struct for sending instant chat message
*/
void SendInstantChatCustomMsg(
const FClientSendInstantChatMsgParams& Params,
TFunction<void(const FPgosResult& Ret, const FClientChatMsgInfo* Data)> Callback) const;
按照如下方式调用 InstantChat 模块中的 SendInstantChatTextMsg
/SendInstantChatCustomMsg
:
#include "PgosSDKCpp.h"
void SomeUObjectClass::SendInstantChatTextMsg()
{
auto InstantChat = IPgosSDKCpp::Get().GetClientInstantChatAPI();
if (InstantChat)
{
FClientSendInstantChatMsgParams Params;
InstantChat->SendInstantChatTextMsg(Params, [](const FPgosResult& Ret, const FClientChatMsgInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("SendInstantChatTextMsg Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("SendInstantChatTextMsg Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
void SomeUObjectClass::SendInstantChatCustomMsg()
{
auto InstantChat = IPgosSDKCpp::Get().GetClientInstantChatAPI();
if (InstantChat)
{
FClientSendInstantChatMsgParams Params;
InstantChat->SendInstantChatCustomMsg(Params, [](const FPgosResult& Ret, const FClientChatMsgInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("SendInstantChatCustomMsg Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("SendInstantChatCustomMsg Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
4.4 获取频道内所有成员
加入频道后,玩家可以查看频道内的所有成员及成员数量。
/**
* Get all members in a channel
*
* @param ChatChannelId The chat channel id
*/
void GetInstantChatMembers(
const FString& ChatChannelId,
TFunction<void(const FPgosResult& Ret, const FClientGetInstantChatMembersResult* Data)> Callback) const;
/**
* Get all member IDs in a channel.
*
* @param ChatChannelId The chat channel id.
*/
void GetInstantChatMemberIDs(
const FString& ChatChannelId,
TFunction<void(const FPgosResult& Ret, const FClientGetInstantChatMemberIDsResult* Data)> Callback) const;
/**
* Get the num of members in a channel.
*
* @param ChatChannelId The chat channel id.
*/
void GetInstantChatMemberCount(
const FString& ChatChannelId,
TFunction<void(const FPgosResult& Ret, const FClientGetInstantChatMemberCountResult* Data)> Callback) const;
按照以下方式从 InstantChat 模块调用 GetInstantChatMembers
/GetInstantChatMemberIDs
/GetInstantChatMemberCount
:
#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"
void SomeClass::GetInstantChatMembers(const FString& ChatChannelId)
{
auto instant_chat = IPgosSDKCpp::Get().GetClientInstantChatAPI();
if (instant_chat)
{
instant_chat->GetInstantChatMembers(ChatChannelId, [](const FPgosResult& Ret, const FClientGetInstantChatMembersResult* Data)
{
if (Ret.err_code == 0)
{
UE_LOG(LogTemp, Log, TEXT("GetInstantChatMembers Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("GetInstantChatMembers Failed: err_code=(%d), err_msg=%s]"), Ret.err_code, *Ret.msg);
}
});
}
}
void SomeUObjectClass::GetInstantChatMemberIDs()
{
auto InstantChat = IPgosSDKCpp::Get().GetClientInstantChatAPI();
if (InstantChat)
{
FString ChatChannelId;
InstantChat->GetInstantChatMemberIDs(ChatChannelId, [](const FPgosResult& Ret, const FClientGetInstantChatMemberIDsResult* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("GetInstantChatMemberIDs Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("GetInstantChatMemberIDs Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
void SomeUObjectClass::GetInstantChatMemberCount()
{
auto InstantChat = IPgosSDKCpp::Get().GetClientInstantChatAPI();
if (InstantChat)
{
FString ChatChannelId;
InstantChat->GetInstantChatMemberCount(ChatChannelId, [](const FPgosResult& Ret, const FClientGetInstantChatMemberCountResult* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("GetInstantChatMemberCount Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("GetInstantChatMemberCount Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
4.5 监控即时聊天事件
使用即时聊天时会触发以下事件:
- OnInstantChatMemberJoined: 当有人加入即时聊天频道时触发。事件结果保存在
FClientInstantChatMemberJoinedEvt
中。 - OnInstantChatMemberLeft: 当有人离开即时聊天频道时触发。事件结果保存在
FClientInstantChatMemberLeftEvt
中。 - OnReceiveInstantChatMsg: 当收到即时聊天消息时触发。事件结果保存在
FClientReceiveInstantChatMsgEvt
中。
struct FClientInstantChatMemberJoinedEvt
{
/** Instant chat channel the player joined */
FString chat_channel_id;
/** Players added to the instant chat */
TArray<FPlayerInfo> added_members;
};
struct FClientInstantChatMemberLeftEvt
{
/** Instant chat channel the player left */
FString chat_channel_id;
/** Players left from the channel */
TArray<FPlayerInfo> left_members;
};
struct FClientChatMsgInfo
{
/** The player who sent the message */
FPlayerInfo sender;
/** The time the message was sent */
int64 sent_time;
/** The type of the message */
EClientChatMsgType msg_type;
/** The message to be sent */
FClientChatMsgContent content;
/** The sequence number of the message */
int64 seq;
/** Additional information added by the game */
FString custom_data;
}
struct FClientReceiveInstantChatMsgEvt
{
/** ID of chat channel where the message was received */
FString chat_channel_id;
/** Instant chat message received */
FClientChatMsgInfo chat_msg_info;
};
按照以下方式监控来自 InstantChat 模块的即时聊天事件:
#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"
void SomeClass::MonitorInstantChatEvents()
{
auto instant_chat = IPgosSDKCpp::Get().GetClientInstantChatAPI();
if (instant_chat)
{
instant_chat->OnInstantChatMemberJoined().AddUObject(this, &SomeClass::OnInstantChatMemberJoined);
instant_chat->OnInstantChatMemberLeft().AddUObject(this, &SomeClass::OnInstantChatMemberLeft);
instant_chat->OnReceiveInstantChatMsg().AddUObject(this, &SomeClass::OnReceiveInstantChatMsg);
}
}
void SomeClass::OnInstantChatMemberJoined(const FClientInstantChatMemberJoinedEvt& Event)
{
UE_LOG(LogTemp, Log, TEXT("OnInstantChatMemberJoined"));
}
void SomeClass::OnInstantChatMemberLeft(const FClientInstantChatMemberLeftEvt& Event)
{
UE_LOG(LogTemp, Log, TEXT("OnInstantChatMemberLeft"));
}
void SomeClass::OnReceiveInstantChatMsg(const FClientReceiveInstantChatMsgEvt& Event)
{
UE_LOG(LogTemp, Log, TEXT("OnReceiveInstantChatMsg"));
}
5. 关键错误处理
Error Code | 相关 API | 处理建议 |
---|---|---|
kCltSdkChatChannelIdIsInvalid | JoinInstantChat | channel_id 无效,不能超过127个字符且不能为空。游戏可以向玩家提示类似"输入不能超过127个字符且不能为空"的消息。 |
kBackendMemberIsInChatChannel | JoinInstantChat | 玩家已在聊天频道中。游戏可以向玩家提示"请先退出当前即时频道,然后重试" |
kBackendMemberIsNotInChatChannel | LeaveInstantChat SendInstantChatTextMsg SendInstantChatCustomMsg GetInstantChatMembers | 该玩家已不在聊天频道中。游戏可以向玩家提示"您需要先加入一个即时频道。" |
kBackendChatChannelNotExist | LeaveInstantChat SendInstantChatTextMsg SendInstantChatCustomMsg GetInstantChatMembers | 聊天频道不存在。游戏可以向玩家提示"您需要先加入一个即时频道。" |
kBackendProfaneWords | SendInstantChatTextMsg SendInstantChatCustomMsg | 该消息包含不当用语。游戏可以向玩家提示"请删除不当用语后再发送消息" |