游戏内集成 IM 指南
在游戏中,即时通信需求很常见,在多人游戏中即时聊天也成为了必不可少的功能。由于游戏平台本身所涉及到的多种群组类型、自定义消息类型(如游戏内道具赠送、交易等业务)、全球接入等需求往往比较复杂,本文梳理了在搭建游戏聊天时过程中常见的需求的实现方法,以及可能遇到的问题、需要注意的细节等,希望能帮助开发者们快速的理解业务,实现需求。
准备工作
使用密钥计算 UserSig
在 IM 的账号体系中,用户登录需要的密码由用户服务端使用 IM 提供的密钥计算,用户可参见 UserSig计算 文档,在开发阶段,为了不阻塞客户端开发,也可在 控制台计算 UserSig ,如下图所示:
配置管理员账号
在管理游戏内即时通信过程中,可能需要管理员向游戏发送邮件公告、管理临时组队消息等,这时就需要使用 即时通信 IM 服务端 API 来进行相应的处理,调用服务端api前需要 创建 IM 管理员账号,IM 默认提供一个 UserID 为 administrator 的账号供开发者使用,开发者也可以根据业务的场景,创建多个管理员账号。需要注意的是,IM 最多创建五个管理员账号。
配置回调地址以及开通回调
集成客户端 SDK
接下来文章梳理了游戏中集成IM时常见的功能点,提供最佳实践方案供开发者参见,并附上相关实现代码。
游戏聊天室各功能开发指引
用户资料
常见用户资料
游戏业务中保存的常见用户资料可分为基本信息资料和其他信息资料。
基本信息 | 其他信息 |
用户名,性别,生日,等级,角色,手机号等 | 其他游戏内需要的资料 |
资料存储
游戏业务内有众多的用户,而存储庞大的用户资料也是较大的难点。腾讯云 IM 开放了用户资料托管能力,提供资料相关的一套完整解决方案。下面对比保存到 腾讯云 IM 与保存到业务后台的区别。
对比项 | IM | 业务后台 |
存储容量 | 可自动扩容/缩容 | 容量有限,增减容量较困难 |
用户资料 | 提供标配字段和自定义字段,字段的长度和命名有限制 | 可自行定义,更加灵活 |
资料读写 | 提供简单易用的服务接口和帮助指引 | 需自行开发 |
接口 | 有调用接口频率限制:最高200次/秒 | 接口调用等能力可按照自己需求自行开发 |
安全性 | 可异地容灾、多地部署 | 需自行维护 |
综上,使用 IM 用户资料托管服务除可获得资料的存储、读写能力外还有以下优点:
1. IM 提供异地容灾、多地部署和自动扩容/缩容的能力,帮助您从服务器宕机、多拷贝主从复制和扩容缩容等复杂处理流程中得到完全地解放。
2. IM 提供业界通用的业务处理流程,帮助您在用户资料的业务逻辑上彻底地解放。
3. IM 提供专业的运营流程和运营团队,全年99.99%的稳定服务质量,帮助您为用户提供具有稳定口碑的服务。
4. IM 提供简单易用的服务接口和快捷接入的帮助指引,全程为您提供星级服务。
IM 存储用户资料的方式
IM 存储方案包含资料的存储和其读写能力。下面介绍 IM 存储用户资料、好友资料和拓展资料的方式。所有资料均以
Key-Value
形式表示。其中Key
为String
类型,仅支持英文大小写字母、数字、下划线。Value
有以下几种类型:类型 | 说明 |
uint64_t | 整数(自定义字段不支持) |
string | 字符串,长度不得超过500字节 |
bytes | 一段 buffer,长度不得超过500字节 |
string 数组 | 字符串数组,每个字符串长度不得超过500字节,仅供好友表的 Tag_SNS_IM_Group 字段使用 |
用户资料:用户资料包含标配字段和自定义字段。自定义字段可见下文的拓展资料。目前即时通信 IM 支持的用户资料标配字段可参见 用户资料标配资料字段。
好友资料:好友资料支持标配好友字段和自定义好友字段。即时通信 IM 好友列表最多允许添加3000个好友。其中,标配好友字段如下:
字段名称 | 类型 | 描述 |
Tag_SNS_IM_Group | Array | 好友分组,为字符串数组 |
Tag_SNS_IM_Remark | string | 好友备注 |
Tag_SNS_IM_AddSource | string | 加好友来源 |
Tag_SNS_IM_AddWording | string | 加好友附言 |
Tag_SNS_IM_AddTime | Integer | 加好友时间戳 |
更详细内容请参见
。
自定义资料:自定义资料字段可以通过即时通信 IM 控制台 > 应用配置 > 功能配置 申请,提交申请后,自定义资料字段将在5分钟内生效。
更多关于用户资料管理,请参见 用户资料管理。
更多关于好友关系链自定义资料管理,请参见 好友自定义字段。
IM 用户资料存储限制
业务特性限制
存储数据:string 和 buffer 类型的恶存储长度不得超过500自解
自定义字段:自定义字段的关键字必须是英文字母且长度不得超过8字节,自定义字段的值最长不能超过500字节
好友关系链:单个用户支持3000个好友
接口相关限制
账号管理:单次最多倒入100个用户名,一次请求最多可以查询500个用户状态
其他调用频率:最高200次/秒
邮件系统
现在游戏中,邮件系统几乎是必备的功能。邮件包含文字消息,也可以包含游戏道具、奖励等邮件附件。邮件可以发送给一个人、也可以像发放活动奖励群发邮件 。下面从玩家接收邮件、邮件列表、邮件未读计数、全员邮件、邮件有效期等几个方面详细介绍邮件系统的功能实现。
收发邮件
玩家接收邮件:当系统邮件发送成功并且玩家正处联网状态时,玩家能够正确接收到系统邮件。接收到的邮件可通过获取邮件会话的消息列表取得历史/最新邮件,同时可以增加/删除接收新消息的回调监听接收所有类型的消息(包含文本、自定义、富媒体消息等)。以Unity为例的示例代码如下所示:
// 设置接收消息事件监听器TencentIMSDK.AddRecvNewMsgCallback((List<Message> messages, string user_data)=>{foreach(Message message in messages){foreach (Elem elem in message.message_elem_array){// 有下一个消息if (elem.elem_type == TIMElemType.kTIMElem_Text){string text = elem.text_elem_content;}}}})// 监听 `RecvNewMsgCallback`回调,在其中接受消息// 希望停止接收消息,调用 `RemoveRecvNewMsgCallback`移除舰艇。该步骤非必需,可按照业务需求调用。
系统发送邮件:系统向用户发系统邮件可以通过 服务端 API 的几种方式,下面列出不同方法的特点:
方法 | 特点 | 应用场景 |
向指定账号发消息,接收方看到的发送着不是管理员,而是管理员指定的账号 | 向某个特定用户发送消息,如段位赛奖励等 | |
支持一次最多对500个用户单发消息,最高调用频率为200次/秒 | 向某些特定用户发送消息,因无需创建组使用比较灵活,但若发送用户较多则需要分批发送 | |
向群组发送普通消息,需要将用户添加到同一个组内 | 向较多用户发送消息可以系统创建群组发送普通消息,群组最大人数限制为 社交群(community) 10万人 | |
向 App 内全员推送消息,可指定用户标签和属性发送消息 | 向 App 内全员推送消息或人数非常多且有特征属性时可使用,如活动推送邮件等 |
其中,在群组中发送普通消息的请求包基础形式示例如下所示:
{"GroupId": "@TGS#2C5SZEAEF","Random": 8912345, // 随机数字,五分钟数字相同认为是重复消息"MsgBody": [ // 消息体,由一个 element 数组组成,详见字段说明{"MsgType": "TIMTextElem", // 文本"MsgContent": {"Text": "red packet"}},{"MsgType": "TIMCustomElem", // 自定义"MsgContent": {"Data": "message","Desc": "notification","Ext": "url","Sound":"dingdong.aiff"}}],}
MsgBody
(消息体)为一个消息数组,可以将文本消息和自定义消息放入 MsgBody 中发送消息。邮件列表
历史邮件列表存储同消息存储,可分为
C2C 单聊历史消息存储
和 群聊历史消息存储
。由于群聊最小人数为2人,可以将管理者指定账号与收到邮件的用户创建新的组进行存储。在网络正常下会拉取最新的云端数据,若网络异常则返回本地存储的历史消息。本接口支持分页拉取。拉取历史邮件列表的 Unity 示例代码如下:
// 拉取单聊历史消息// 首次拉取,msg_getmsglist_param_last_msg 设置为 null// 再次拉取时,msg_getmsglist_param_last_msg 可以使用返回的消息列表中的最后一条消息var get_message_list_param = new MsgGetMsgListParam{msg_getmsglist_param_last_msg = LastMessage};TIMResult res = TencentIMSDK.MsgGetMsgList(conv_id, TIMConvType.kTIMConv_C2C, get_message_list_param, (int code, string desc, string user_data) => {// 处理回调逻辑});
邮件未读计数
一个用户-系统邮件的记录相当于一个聊天中的会话。腾讯云 IM 提供会话未读计数功能,提醒用户尚未阅读消息。用户点进该会话后退回会话列表时,未读消息数会被清空。Unity示例代码如下:
// 获取全部未读数TIMResult res = TencentIMSDK.ConvGetTotalUnreadMessageCount((int code, string desc, GetTotalUnreadNumberResult unread, string user_data)=>{// 处理异步逻辑});// 未读计数变更通知TencentIMSDK.SetConvTotalUnreadMessageCountChangedCallback((int total_unread_count, string user_data)=>{// 处理回调逻辑});// 清空所有会话的未读消息数TIMResult res = TencentIMSDK.MsgMarkAllMessageAsRead((int code, string desc, string user_data)=>{// 处理异步逻辑});
全员邮件
全员邮件相当于对游戏内所有玩家发送邮件消息。腾讯云 IM 提供服务端
全员推送
功能。示例代码如下:https://console.tim.qq.com/v4/all_member_push/im_push?usersig=xxx&identifier=admin&sdkappid=88888888&random=99999999&contenttype=json
请求包示例如下:
{"From_Account": "admin","MsgRandom": 56512,"MsgLifeTime": 120, // 离线保存120s(2分钟)"MsgBody": [{"MsgType": "TIMTextElem","MsgContent": {"Text": "hi, beauty"}}]}
全员推送可以设置消息离线存储时间,这样即便某些用户不在线,但在离线存储的时间范围内,不在线用户也能收到消息。若需要设置离线保存时间,可设置
MsgLifeTime
,单位秒,最多保存7天(604800s)。默认为0,表示不离线存储。邮件有效期
对于历史邮件,邮件存储有效期为:体验版/专业版为7天,旗舰版为30天,专业版和旗舰版支持延长时长。对于历史存储的更多内容请参见 历史消息存储时长配置。
此外,在服务端发送消息时,可通过在请求包内设置
MsgLifeTime
设置消息离线保存时长(最长为7天)。若该字段为0,则表示消息只发在线用户,不离线保存。 更多内容请参见 服务端 API。临时组队
多人联网游戏中临时组队必不可少。下面从组队场景和后台、队伍内成员分别所需获取的队内信息讲解临时组队的内容。
组队场景
组队场景一般分为如下几点:创建组队、退出临时组队、成为队长、邀请加入组队、解散组队等。下面通过一些代码示例分别解释不同场景的实现方法。
游戏开始前创建组队:当第一个人进入游戏时,在服务端自动创建群组并可以设置最大群成员数量。请求时如果指定了群组或群成员,那么在创建时群主或群成员回自动加入到该群中。请求 URL 示例如下:
https://console.tim.qq.com/v4/group_open_http_svc/create_group?sdkappid=88888888&identifier=admin&usersig=xxx&random=99999999&contenttype=json
请求包基础形式示例如下:
{"Owner_Account": "leckie", // 群主的 UserId(选填)"Type": "Public", // 群组类型:Private/Public/ChatRoom/AVChatRoom/Community"Name": "TestGroup", // 群名称(必填)"MaxMemberCount":5 // 最大群成员数量(选填)}
增加群成员:创建群聊后后续有新的玩家进入游戏则需要在原来群组的基础上添加新的群成员。请求 URL 示例如下:
https://console.tim.qq.com/v4/group_open_http_svc/add_group_member?sdkappid=88888888&identifier=admin&usersig=xxx&random=99999999&contenttype=json
请求包如下:
{"GroupId": "@TGS#2J4SZEAEL", // 要操作的群组(必填)"MemberList": [ // 一次最多添加300个成员{"Member_Account": "tommy" // 要添加的群成员ID(必填)},{"Member_Account": "jared"}]}
组队成功回调:当在创建群组时设置了最大群成员数量,则当组队需要人数全部进群后可以开始游戏。可以通过
群组满员之后回调
感知并开始游戏。请求 URL 示例如下:https://www.example.com?SdkAppid=$SDKAppID&CallbackCommand=$CallbackCommand&contenttype=json&ClientIP=$ClientIP&OptPlatform=$OptPlatform
请求包示例如下:
{"CallbackCommand": "Group.CallbackAfterGroupFull", // 回调命令"GroupId": "@TGS#2J4SZEAEL" // 群组 ID}
新成员入群通知:当有新的玩家进入游戏(群聊)后,通过
新成员入群之后回调
可通知其他群成员入群成功。请求 URL 示例如下:https://www.example.com?SdkAppid=$SDKAppID&CallbackCommand=$CallbackCommand&contenttype=json&ClientIP=$ClientIP&OptPlatform=$OptPlatform
请求包示例如下:
{"CallbackCommand": "Group.CallbackAfterNewMemberJoin", // 回调命令"GroupId" : "@TGS#2J4SZEAEL","Type": "Public", // 群组类型"JoinType": "Apply", // 入群方式:Apply(申请入群);Invited(邀请入群)"Operator_Account": "leckie", // 操作者成员"NewMemberList": [ // 新入群成员列表{"Member_Account": "jared"},{"Member_Account": "tommy}]}
游戏途中退出组队:当玩家自主退出游戏或由于网络问题退出游戏时,服务端可以通过
群成员离开之后回调
通知组内其他玩家有人退出群聊,也可以对因网络问题退出游戏的玩家发送消息。群成员离开之后回调 的请求 URL 示例如下:https://www.example.com?SdkAppid=$SDKAppID&CallbackCommand=$CallbackCommand&contenttype=json&ClientIP=$ClientIP&OptPlatform=$OptPlatform
请求包示例如下:
{"CallbackCommand": "Group.CallbackAfterMemberExit", // 回调命"GroupId": "@TGS#2J4SZEAEL", // 群组 ID"Type": "Public", // 群组类型"ExitType": "Kicked", // 成员离开方式:Kicked-被踢;Quit-主动退群"Operator_Account": "leckie", // 操作者"ExitMemberList": [ // 离开群的成员列表{"Member_Account": "jared"},{"Member_Account": "tommy"}]}
游戏结束后解散群聊:游戏结束后,服务端可直接解散群聊。解散群聊 的请求 URL 示例如下:
https://console.tim.qq.com/v4/group_open_http_svc/destroy_group?sdkappid=88888888&identifier=admin&usersig=xxx&random=99999999&contenttype=json
请求包示例如下:
{"GroupId": "@TGS#2J4SZEAEL"}
对于临时组队内语音或视频聊天,内容比较复杂,下文有详细说明。
后台获取队内情况
获取群内详细信息:对于群内详细信息(包含当前群成员数量,群内成员基本信息等)可以通过服务端 API
获取群详细资料
获取。可以在请求包中设定Filter字段拉取置顶的信息。示例代码如下所示:https://console.tim.qq.com/v4/group_open_http_svc/get_group_info?sdkappid=88888888&identifier=admin&usersig=xxx&random=99999999&contenttype=json
请求包示例如下:
{"GroupIdList": [ // 群组列表(必填)"@TGS#1NVTZEAE4","@TGS#1CXTZEAET"]}
获取群成员详细信息:若只需要群成员信息(包含自定义字段),则可使用
获取群成员详细资料
获取到群成员的信息。示例代码如下所示:https://console.tim.qq.com/v4/group_open_http_svc/get_group_member_info?sdkappid=88888888&identifier=admin&usersig=xxx&random=99999999&contenttype=json
请求包示例如下:
{"GroupId":"@TGS#1NVTZEAE4" // 群组 ID(必填)}
返回字段中
MemberNum
可获取本群组的群成员总数,AppMemberDefinedData
可获取群成员自定义字段信息。说明:
队内成员获取队内情况
对于队内成员,可通过
获取群成员资料
获取到队内其他成员的资料,如成员的角色、准备状态等。示例代码如下:GroupGetMemberInfoListParam param = new GroupGetMemberInfoListParam{group_get_members_info_list_param_group_id = "group_id",group_get_members_info_list_param_identifier_array = new List<string>{"user_id"}};TIMResult res = TencentIMSDK.GroupGetMemberInfoList(param, (int code, string desc, GroupGetMemberInfoListResult result, string user_data)=>{// 处理异步逻辑});
敏感信息过滤
过滤敏感内容也是游戏即时通信中非常重要的功能,实现方案如下:
1. 绑定用户群发消息前回调
2. 判断通过回调数据判断消息类型,将消息数据传递给天御或者其他第三方检测服务
3. 如消息为普通文本消息,可等天御检测同步返回,再将是否下发消息的数据包返回给 IM 后台
发送消息前回调数据示例:
{"CallbackCommand": "Group.CallbackBeforeSendMsg", // 回调命令"GroupId": "@TGS#2J4SZEAEL", // 群组 ID"Type": "Public", // 群组类型"From_Account": "jared", // 发送者"Operator_Account":"admin", // 请求的发起者"Random": 123456, // 随机数"OnlineOnlyFlag": 1, //在线消息,为1,否则为0;直播群忽略此属性,为默认值0。"MsgBody": [ // 消息体,参见 TIMMessage 消息对象{"MsgType": "TIMTextElem", // 文本"MsgContent": {"Text": "red packet"}}],"CloudCustomData": "your cloud custom data"}
说明:
开发者可以选择对不合法的消息进行不一样的处理,可在回调中回包给 IM 后台来控制。
{"ActionStatus": "OK","ErrorInfo": "","ErrorCode": 0 // 不同的ErrorCode有不同的含义}
ErrorCode | 含义 |
0 | 允许发言,正常下发消息 |
1 | 拒绝发言,客户端返回10016 |
2 | 静默丢弃,客户端返回正常 |
说明:
开发者可根据自身业务进行选择使用。
自定义消息类型(如道具赠送、交易)
在游戏聊天环境中,不仅只使用文本消息、表情消息、语音消息等简单的消息类型。自定义消息类型可提供开发者自定义客制化消息内容格式的功能,可通过自定义消息类型完成游戏聊天室内游戏道具的赠送、交易等更多的聊天室功能。
腾讯云 IM 提供 9 种基本消息类型,包含文本消息、表情消息、地理位置消息、图片消息、语音消息、文件消息、短视频消息、系统通知和自定义消息。其中除了自定义消息之外的其他消息格式已经确定,只需要填入相应的信息即可。更多关于消息类型的具体描述请参见 消息类型,关于消息类型的格式请参见 消息格式描述。
{"GroupId": "@TGS#2C5SZEAEF","Random": 8912345, // 随机数字,五分钟数字相同认为是重复消息"MsgBody": [ // 消息体,由一个 element 数组组成,详见字段说明{"MsgType": "TIMTextElem", // 文本"MsgContent": {"Text": "red packet"}},{"MsgType": "TIMFaceElem", // 表情"MsgContent": {"Index": 6,"Data": "abc\u0000\u0001"}}],"CloudCustomData": "your cloud custom data","SupportMessageExtension": 0,}
其中,可以修改
CloudCustomData
定义消息自定义数据(云端保存),并将自定义消息填入MsgBody
(消息体)发送。组内语音/视频聊天
说明:
为了更好的体验音视频通话功能,我们面为为每个 SDKAppID 提供了音视频通话能力7天体验版。您可以在 IM 控制台 中为您的应用领取体验版进行体验使用,每个 SDKAppID 有且仅有一次领取体验版的机会。
更多关于 TUICallKit 的内容,请参见 含 UI 集成方法-音视频通话。
游戏聊天室类型
游戏聊天室类型一般分为如下几种:
类型 | 特点 |
频道 | 聊天人数非常多,无固定成员列表,无需申请加入群聊,可随时加入、退出。无需发送离线消息推送。 |
大厅 | 聊天人数较多,可随时加入、退出。支持历史消息查询。 |
组队 | 聊天人数较少,聊天对象可能为陌生人,游戏结束时聊天室销毁。无需发送离线消息推送。 |
好友 | 为 C2C 聊天,聊天记录保存,聊天对象存在于好友列表。 |
私信 | 为 C2C 聊天,聊天对象可能为陌生人。 |
直播群 | 聊天人数无上限,可随时加入、退出。 |
IM 提供的聊天室类型分为以下几种:
类型 | 特点 |
好友工作群(work) | 创建后仅支持已在群内的好友申请加群,无需被邀请访同意或群组审批。 |
陌生人社交群(Public) | 创建后群主可以指定群主管理员,用户搜索群ID发起群申请后,需要群主或管理员审批通过才能入群。 |
临时会议群(Meeting) | 创建后可以随意进出,且支持查看入群前消息;适合用于音视频会议场景、在线教育场景等与实时音视频产品结合的场景,同旧版本中的 ChatRoom。 |
直播群(AVChatRoom) | 创建后可以随意进出,没有群成员数量上限,但不支持历史消息存储;适合与直播产品结合,用于弹幕聊天场景。 |
社群(Community) | 创建后可以随意进出,最多支持10w人,支持历史消息存储,用户搜索群 ID 发起加群申请后,无需管理员审批即可进群。 |
根据 IM 的群特性,这里提供示例解决方案,请按照需求应用到您的游戏中:
类型 | 解决方案 | 特点 |
频道、大厅 | 社群(Community) | 聊天人数较多,创建后可随意进出,无需审批 |
好友 | 单聊+权限控制(只允许给好友发送消息) | 支持仅好友发送消息 |
私信 | 单聊+权限控制(App 内任意两个用户之间发送单聊消息) | 支持任意两个陌生人发送消息 |
组队 | 陌生人社交群(Public)、临时会议群(Meeting) | 只有游戏内组队人员能够进入聊天群,支持音视频聊天 |
直播群 | 直播群(AVChatRoom) | 没有群成员上线,可随时进出群 |