跳到主要内容

即时聊天

1. 概述

本文档介绍游戏内即时聊天功能的使用。

即时聊天:用于多人之间的即时文字聊天。所有加入同一频道的玩家都可以互相聊天。当聊天中的所有玩家离开频道或下线后,该频道会自动删除。

即时聊天应用场景:可用于对战中同队玩家之间的聊天,或者玩家自定义发起的多人聊天功能。

除了即时聊天,部分 PGOS 服务也内置了文字聊天功能。详情请参见组队房间文档。

完成本教程后,开发者将了解:

  • PGOS 即时聊天的基本概念
  • 如何加入/离开即时聊天
  • 如何发送和接收即时聊天消息
  • 即时聊天事件介绍及如何监听

2. 流程

以下是使用即时聊天的流程:

img

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处理建议
kCltSdkChatChannelIdIsInvalidJoinInstantChatchannel_id 无效,不能超过127个字符且不能为空。游戏可以向玩家提示类似"输入不能超过127个字符且不能为空"的消息。
kBackendMemberIsInChatChannelJoinInstantChat玩家已在聊天频道中。游戏可以向玩家提示"请先退出当前即时频道,然后重试"
kBackendMemberIsNotInChatChannelLeaveInstantChat SendInstantChatTextMsg SendInstantChatCustomMsg GetInstantChatMembers该玩家已不在聊天频道中。游戏可以向玩家提示"您需要先加入一个即时频道。"
kBackendChatChannelNotExistLeaveInstantChat SendInstantChatTextMsg SendInstantChatCustomMsg GetInstantChatMembers聊天频道不存在。游戏可以向玩家提示"您需要先加入一个即时频道。"
kBackendProfaneWordsSendInstantChatTextMsg SendInstantChatCustomMsg该消息包含不当用语。游戏可以向玩家提示"请删除不当用语后再发送消息"