package chat import ( actorRemote "f1-game/internal/actor_remote" "f1-game/internal/code" "f1-game/internal/component/redis" "f1-game/internal/enum" nameActor "f1-game/internal/name/actor" nameRedis "f1-game/internal/name/redis" nameRemote "f1-game/internal/name/remote" nameRoute "f1-game/internal/name/route" "f1-game/internal/pb" "f1-game/internal/types" cherrySlice "github.com/cherry-game/cherry/extend/slice" ctime "github.com/cherry-game/cherry/extend/time" clog "github.com/cherry-game/cherry/logger" ) type ( actorGroup struct { RoomTypeList } ) func NewActorGroup() *actorGroup { return &actorGroup{ RoomTypeList: newRoomTypeList(enum.ChatType_Group), } } func (p *actorGroup) OnInit() { p.Remote().Register(nameRemote.Chat_GroupJoin, p.groupJoin) p.Remote().Register(nameRemote.Chat_GroupQuit, p.groupQuit) p.Remote().Register(nameRemote.Chat_GroupPlayerChange, p.groupPlayerChange) p.Remote().Register(nameRemote.Chat_Send, p.send) p.Remote().Register(nameRemote.Chat_Push, p.Push) p.Remote().Register(nameRemote.Chat_Destory, p.destory) p.Remote().Register(nameRemote.Chat_DelMsg, p.DelMsg) p.initCleanRoomTimer() } func (p *actorGroup) AliasID() string { return nameActor.Chat_Group } // 在列表同意加入群组 func (p *actorGroup) groupJoin(req *pb.I64I64) int32 { var ( chatID = req.Key playerID = req.Value ) memberCount := redis.Chat.GetGroupMemberCount(chatID) if memberCount == 0 { // 群组解散没有成员了 return code.ChatGroupNotFound } // 群组满员了 if p.playerLimit > 0 && memberCount >= p.playerLimit { return code.ChatGroupMemberLimit } chatRoom := p.GetChatRoom(chatID) p.flushPlayerIDList(chatRoom) chatRoom.PlayerIDList.Add(playerID) redis.Chat.AddGroupMember(chatID, playerID) return code.OK } // 主动退出群组 func (p *actorGroup) groupQuit(req *pb.I64I64) { var ( chatID = req.Key playerID = req.Value chatRoom = p.GetChatRoom(chatID) ) // 直接清理,下次会从redis中重新加载 chatRoom.PlayerIDList.Clear() redis.Chat.DelGroupMember(chatID, playerID) } func (p *actorGroup) send(req *pb.ChatMsgList) { chatRoom := p.GetChatRoom(req.ChatID) p.flushPlayerIDList(chatRoom) p.AddChatMsg(req) // 通知该群成员有人发言 p.Broadcast2Client(chatRoom, nameRoute.PushChat_MsgList, req) // update last send time chatRoom.LastSendTime = ctime.Now() } // 群组成员只有为空的时候从redis中加载 func (p *actorGroup) flushPlayerIDList(chatRoom *ChatRoom) { if chatRoom.LastSendTime.NowDiffSecond() < 1 { return } if members, found := redis.Chat.GetGroupMembers(chatRoom.ChatID); found { chatRoom.PlayerIDList = types.NewList(members...) } } func (p *actorGroup) destory(req *pb.I64) { memberList, found := redis.Chat.GetGroupMembers(req.Value) if !found { return } if len(memberList) > 0 { rsp := &pb.I64Bool{ Key: req.Value, Value: true, } // 通知所有成员销毁群组 playerDataMap := redis.Game.GetPlayerDataMap(memberList, nameRedis.PlayerGameNodeFields...) for _, memberID := range memberList { playerData, found := playerDataMap[memberID] if !found { clog.Warnf("destory get playerData is nil, chatId: %d, memberID: %d", req.Value, memberID) continue } actorRemote.GamePlayer.Call(playerData.GameNodeID, playerData.PlayerID, nameRemote.Player_ChatGroupMemberRemove, rsp) } // 删除redis中的群组成员 redis.Chat.DelAllGroupMembers(req.Value) } p.Destory(req) } // 群组玩家变更 func (p *actorGroup) groupPlayerChange(req *pb.ChatGroupPlayerChange) { var ( removeList []int64 // 移除的成员 inviteList []int64 // 邀请的成员 allIDList []int64 // 所有需要查询的成员ID列表 ) memberList, _ := redis.Chat.GetGroupMembers(req.ChatID) // 不在原成员列表中的PlayerID则发出邀请 for _, playerID := range req.PlayerIDList { if _, ok := cherrySlice.Int64In(playerID, memberList); !ok { inviteList = append(inviteList, playerID) } } // 原成员列表的PlayerID在新成员列表中找不到的则移除 for _, oldPlayerID := range memberList { // 过滤群组创建者 if oldPlayerID == req.OwnerPlayerID { continue } if _, ok := cherrySlice.Int64In(oldPlayerID, req.PlayerIDList); !ok { removeList = append(removeList, oldPlayerID) } } // 所有需要查询的成员ID列表:邀请人,移除的人,群主 allIDList = append(allIDList, inviteList...) allIDList = append(allIDList, removeList...) allIDList = append(allIDList, req.OwnerPlayerID) // 一次性把需要查询成员数据都查出来 chatPlayerMap := redis.Game.GetChatPlayerMap(allIDList...) if chatPlayerMap == nil { clog.Warnf("groupPlayerChange GetPlayerDataMap is nil, allIDList len: %v", len(allIDList)) return } // 发起邀请 p.inviteSend(req.ChatID, req.Name, req.OwnerPlayerID, inviteList, chatPlayerMap) // 移除成员 p.playerRemoveSend(req.ChatID, removeList, chatPlayerMap) } // 发起群组邀请 func (p *actorGroup) inviteSend(chatID int64, name string, ownerPlayerID int64, invitePlayerIDList []int64, chatPlayerMap map[int64]*pb.ChatPlayer) { if len(invitePlayerIDList) < 1 { return } inviteReq := &pb.GroupInvite{ ChatID: chatID, Name: name, InvitePlayer: chatPlayerMap[ownerPlayerID], } for _, invitePlayerID := range invitePlayerIDList { playerData, found := chatPlayerMap[invitePlayerID] if !found { clog.Warnf("inviteSend playerData is nil, chatID: %d, invitePlayerID: %d", chatID, invitePlayerID) continue } actorRemote.GamePlayer.Call(playerData.GameNodeID, playerData.PlayerID, nameRemote.Player_ChatGroupInvite, inviteReq) } } // 发起踢出群组聊天的成员 func (p *actorGroup) playerRemoveSend(chatID int64, removePlayerIDList []int64, chatPlayerMap map[int64]*pb.ChatPlayer) { if len(removePlayerIDList) < 1 { return } rsp := &pb.I64Bool{ Key: chatID, Value: false, } for _, removePlayerID := range removePlayerIDList { chatPlayer, found := chatPlayerMap[removePlayerID] if !found { clog.Warnf("playerRemoveSend chatPlayer is nil, chatID: %d, removePlayerID: %d", chatID, removePlayerID) continue } actorRemote.GamePlayer.Call(chatPlayer.GameNodeID, chatPlayer.PlayerID, nameRemote.Player_ChatGroupMemberRemove, rsp) } redis.Chat.DelGroupMember(chatID, removePlayerIDList...) chatRoom := p.GetChatRoom(chatID) // 清理成员缓存,下次从redis重新拉取新的 chatRoom.PlayerIDList.Clear() }