package player import ( actorRemote "f1-game/internal/actor_remote" "f1-game/internal/code" "f1-game/internal/component/redis" "f1-game/internal/data" "f1-game/internal/enum" nameLocal "f1-game/internal/name/local" nameRemote "f1-game/internal/name/remote" nameRoute "f1-game/internal/name/route" "f1-game/internal/pb" "f1-game/internal/sessions" dbChat "f1-game/nodes/game/internal/db/data/chat" "f1-game/nodes/game/player/chat" ctime "github.com/cherry-game/cherry/extend/time" cproto "github.com/cherry-game/cherry/net/proto" ) func (p *actorPlayer) initFriend() { p.Local().Register(nameLocal.Player_FriendSearch, p.friendSearch) p.Local().Register(nameLocal.Player_FriendAdd, p.friendAdd) p.Local().Register(nameLocal.Player_FriendConfirm, p.friendConfirm) p.Local().Register(nameLocal.Player_FriendDel, p.friendDel) p.Local().Register(nameLocal.Player_BlackSetting, p.blackSetting) p.Remote().Register(nameRemote.Player_FriendAddSend, p.friendAddSend) p.Remote().Register(nameRemote.Player_FriendAddSendBack, p.friendAddSendBack) p.Remote().Register(nameRemote.Player_FriendConfirmSend, p.friendConfirmSend) p.Remote().Register(nameRemote.Player_FriendConfirmBack, p.friendConfirmBack) } // 查询玩家信息 func (p *actorPlayer) friendSearch(session *cproto.Session, req *pb.I64) { if req.Value < 1 { p.ResponseCode(session, code.IllegalArgument) return } chatPlayer := redis.Game.GetChatPlayer(req.Value) if chatPlayer == nil { p.ResponseCode(session, code.PlayerDetailNotFound) return } p.Response(session, chatPlayer) } // 添加好友 func (p *actorPlayer) friendAdd(session *cproto.Session, req *pb.I64) { toPlayerID := req.Value if toPlayerID < 1 { p.ResponseCode(session, code.IllegalArgument) return } if toPlayerID == p.playerID { p.ResponseCode(session, code.FriendAddSelf) return } var ( playerTable = p.PlayerTable() chatTable = p.ChatTable() ) if playerTable.Lord.Level < data.Const.FriendAddOpenLv { p.ResponseCode(session, code.FriendAddLvNotEnough) return } if chatTable.IsBlack(toPlayerID) { p.ResponseCode(session, code.FriendBlackListed) return } if chatTable.GetFriendCount() >= data.Const.FriendNumLimit { p.ResponseCode(session, code.FriendNumLimit) return } if chatTable.IsFriend(toPlayerID) { p.ResponseCode(session, code.FriendRepeatAdd) return } chatPlayerMap := redis.Game.GetChatPlayerMap(p.playerID, toPlayerID) if len(chatPlayerMap) != 2 { p.ResponseCode(session, code.PlayerDetailNotFound) return } var ( chatPlayer = chatPlayerMap[p.playerID] toChatPlayer = chatPlayerMap[toPlayerID] ) // 发起好友邀请 errCode := actorRemote.GamePlayer.Call(toChatPlayer.GameNodeID, toPlayerID, nameRemote.Player_FriendAddSend, chatPlayer) if code.IsFail(errCode) { p.ResponseCode(session, errCode) return } p.ResponseCode(session, code.OK) } // 收到好友申请 func (p *actorPlayer) friendAddSend(req *pb.ChatPlayer) { chatTable := p.ChatTable() // 已经是好友了 if chatTable.IsFriend(req.PlayerID) { // 可能存在单向好友的情况,直接返回 p.callFriendAddSendBack(req.GameNodeID, req.PlayerID, code.FriendAddSuccess, true) return } // 判断是否在黑名单中 if chatTable.IsBlack(req.PlayerID) { p.callFriendAddSendBack(req.GameNodeID, req.PlayerID, code.FriendTargetInBlackList, false) return } // 拒绝添加好友 if !chatTable.IsFriendInviteMute { p.callFriendAddSendBack(req.GameNodeID, req.PlayerID, code.FriendRefuseAdd, false) return } // 等级不够 if p.PlayerTable().Lord.Level < data.Const.FriendAddOpenLv { p.callFriendAddSendBack(req.GameNodeID, req.PlayerID, code.FriendTargetLvNotEnough, false) return } // 已经在邀请列表中了 if _, found := chatTable.GetFriendInvite(req.PlayerID); found { p.callFriendAddSendBack(req.GameNodeID, req.PlayerID, code.FriendApplyRepeatAdd, false) return } newInvite := dbChat.NewFriendInvite(req.PlayerID) chatTable.AddFriendInvite(newInvite) chatTable.Save2Queue() p.callFriendAddSendBack(req.GameNodeID, req.PlayerID, code.FriendAddSendSuccess, false) rsp := &pb.FriendInvite{ InvitePlayer: req, InviteTime: newInvite.InviteTime, } sessions.PushPlayer(p.playerID, nameRoute.PushGamePlayer_FriendInviteNewPush, rsp) } // 添加好友返回消息发送 func (p *actorPlayer) callFriendAddSendBack(toPlayerGameNodeID string, toPlayerID int64, errCode int32, result bool) { retCode := actorRemote.GamePlayer.Call(toPlayerGameNodeID, toPlayerID, nameRemote.Player_FriendAddSendBack, &pb.AddFriendResult{ PlayerID: p.playerID, ErrCode: errCode, Result: result, }) if code.IsFail(retCode) { p.Warn("callFriendAddSendBack failed, toPlayerID: %d, retCode: %d, errCode: %d, result: %v", toPlayerID, retCode, errCode, result) } } // 好友申请返回处理 func (p *actorPlayer) friendAddSendBack(req *pb.AddFriendResult) { var ( toPlayerID = req.PlayerID errCode = req.ErrCode result = req.Result ) // 单方好友,直接添加成功 if result { chatPlayer := redis.Game.GetChatPlayer(toPlayerID) p.onAddFriend(chatPlayer) } sessions.PushPlayer(p.playerID, nameRoute.PushGamePlayer_FriendAddBack, &pb.I64I32{ Key: toPlayerID, Value: errCode, }) } // 添加好友的逻辑处理 func (p *actorPlayer) onAddFriend(chatPlayer *pb.ChatPlayer) { var ( chatTypeConfig, _ = data.ChatType.GetByChatType(enum.ChatType_Private) param = &pb.ParamsTemplate{ Type: int32(enum.ChatMsgType_FriendAdd), } chatMsg = chat.Service().BuildMsgProto(chatPlayer, enum.ChatMsgType_FriendAdd, "", ctime.Now().ToSecond(), param) toPlayerID = chatPlayer.PlayerID ) // 添加私聊消息 redis.Chat.AddPrivateMsg(p.playerID, toPlayerID, chatTypeConfig.MsgLimit, chatMsg) var ( chatTable = p.ChatTable() // 最近聊天内容 lastChatContent = dbChat.NewChatContent(chatMsg.MsgID, chatMsg.SendTime, chatMsg.Type, chatMsg.Text, chatMsg.Params) // 好友关系 newFriendRelation = dbChat.NewFriendRelation(toPlayerID, lastChatContent) ) // 添加好友关系 chatTable.FriendList.Add(newFriendRelation) // 如果加了好友就从私聊列表里面移除 chatTable.RemovePrivate(toPlayerID) // 从发起列表中移除 chatTable.RemoveFriendSend(toPlayerID) chatTable.Save2Queue() if p.isOnline { toChatPlayer := redis.Game.GetChatPlayer(toPlayerID) if toChatPlayer == nil { return } rsp := &pb.FriendRelation{ FriendPlayer: toChatPlayer, CreateTime: newFriendRelation.CreateTime, LastContent: lastChatContent.ToProto(), } sessions.PushPlayer(p.playerID, nameRoute.PushGamePlayer_FirendNew, rsp) } } // 删除好友 func (p *actorPlayer) friendDel(session *cproto.Session, req *pb.I64) { if req.Value < 1 { p.ResponseCode(session, code.IllegalArgument) return } if !p.ChatTable().IsFriend(req.Value) { p.ResponseCode(session, code.FriendNotFound) return } // 解除好友关系 p.removeFriendRelation(req.Value, false) p.ResponseCode(session, code.OK) } // 好友申请确认 func (p *actorPlayer) friendConfirm(session *cproto.Session, req *pb.FriendInviteConfirm) { chatTable := p.ChatTable() // 一键拒绝所有申请 if req.IsRejectAll { chatTable.FriendRecvList.Clear() chatTable.Save2Queue() p.ResponseCode(session, code.OK) return } if req.PlayerID < 1 { p.ResponseCode(session, code.IllegalArgument) return } var ( toPlayerID = req.PlayerID // 好友ID isAccept = req.IsAccept // 是否接受 ) if _, found := chatTable.GetFriendInvite(toPlayerID); !found { p.ResponseCode(session, code.FriendInviteNotFound) return } if !isAccept { chatTable.RemoveFriendInvite(toPlayerID) chatTable.Save2Queue() p.ResponseCode(session, code.OK) return } if chatTable.IsFriend(toPlayerID) { // 已经是好友,直接删除邀请 chatTable.RemoveFriendInvite(toPlayerID) chatTable.Save2Queue() p.ResponseCode(session, code.OK) // 给客户端统一异步接收的通知吧 sessions.PushPlayer(p.playerID, nameRoute.PushGamePlayer_FriendConfirmBack, &pb.I64I32{ Key: toPlayerID, Value: code.FriendRepeatAdd, }) return } if chatTable.GetFriendCount() >= data.Const.FriendNumLimit { p.ResponseCode(session, code.FriendNumLimit) return } chatPlayerMap := redis.Game.GetChatPlayerMap(p.playerID, toPlayerID) if len(chatPlayerMap) != 2 { p.ResponseCode(session, code.PlayerDetailNotFound) return } var ( chatPlayer = chatPlayerMap[p.playerID] toChatPlayer = chatPlayerMap[toPlayerID] ) // 异步请求,把自己的信息带过去 retCode := actorRemote.GamePlayer.Call(toChatPlayer.GameNodeID, toPlayerID, nameRemote.Player_FriendConfirmSend, chatPlayer) if code.IsFail(retCode) { p.ResponseCode(session, retCode) return } // 记录发送过好友确认的状态 if !chatTable.HasFriendSend(toPlayerID) { newComfirmSend := dbChat.NewFriendInvite(toPlayerID) chatTable.FriendSendList.Add(newComfirmSend) } // 删除申请列表 chatTable.RemoveFriendInvite(toPlayerID) chatTable.Save2Queue() p.ResponseCode(session, code.OK) } // 好友确认返回 func (p *actorPlayer) callFriendConfirmBack(toPlayerGameNodeID string, toPlayerID int64, errCode int32, result bool) { retCode := actorRemote.GamePlayer.Call(toPlayerGameNodeID, toPlayerID, nameRemote.Player_FriendConfirmBack, &pb.AddFriendResult{ PlayerID: p.playerID, ErrCode: errCode, Result: result, }) if code.IsFail(retCode) { p.Warn("callFriendConfirmBack failed, toPlayerID: %d,retCode: %d, errCode: %d, result: %v", toPlayerID, retCode, errCode, result) } } // 收到好友确认通知 func (p *actorPlayer) friendConfirmSend(req *pb.ChatPlayer) { var ( chatTable = p.ChatTable() toPlayerID = req.PlayerID toPlayerGameNodeID = req.GameNodeID ) // 拉黑了 if chatTable.IsBlack(p.playerID) { p.callFriendConfirmBack(toPlayerGameNodeID, toPlayerID, code.FriendBlackListed, false) return } // 好友数量 friendCount := chatTable.GetFriendCount() // 如果已经预留了位置就减去1 if chatTable.HasFriendSend(toPlayerID) { friendCount -= 1 } if friendCount >= data.Const.FriendNumLimit { p.callFriendConfirmBack(toPlayerGameNodeID, toPlayerID, code.FriendTargetNumLimit, false) return } // 已经是好友了,直接返回成功 if chatTable.IsFriend(toPlayerID) { // 如果也发起确认请求,就删除发送确认记录 chatTable.RemoveFriendSend(toPlayerID) chatTable.Save2Queue() p.callFriendConfirmBack(toPlayerGameNodeID, toPlayerID, code.FriendAddSuccess, true) return } p.onAddFriend(req) p.callFriendConfirmBack(toPlayerGameNodeID, toPlayerID, code.FriendAddSuccess, true) } // 好友确认发送返回 func (p *actorPlayer) friendConfirmBack(req *pb.AddFriendResult) { var ( chatTable = p.ChatTable() toPlayerID = req.PlayerID errCode = req.ErrCode result = req.Result ) // 添加失败和成功都删除发送确认记录(删除预留位置) chatTable.RemoveFriendSend(toPlayerID) chatTable.Save2Queue() if result { if !chatTable.IsFriend(toPlayerID) { chatPlayer := redis.Game.GetChatPlayer(toPlayerID) p.onAddFriend(chatPlayer) } } sessions.PushPlayer(p.playerID, nameRoute.PushGamePlayer_FriendConfirmBack, &pb.I64I32{ Key: toPlayerID, Value: errCode, }) } // 黑名单设置 func (p *actorPlayer) blackSetting(session *cproto.Session, req *pb.BlackSetting) { if req.PlayerID < 1 || req.PlayerID == p.playerID { p.ResponseCode(session, code.IllegalArgument) return } if !req.IsBlack { p.blackCancel(session, req.PlayerID) return } chatTable := p.ChatTable() if chatTable.IsBlack(req.PlayerID) { p.ResponseCode(session, code.BlackListRepeatAdd) return } if chatTable.GetBlackCount() >= data.Const.FriendBlacklistLimit { p.ResponseCode(session, code.BlackListNumLimit) return } toChatPlayer := redis.Game.GetChatPlayer(req.PlayerID) if toChatPlayer == nil { p.ResponseCode(session, code.PlayerDetailNotFound) return } newBlack := dbChat.NewBlack(req.PlayerID, ctime.Now().ToSecond()) chatTable.AddBlack(newBlack) // 删除预留的位置,避免发起确认里面拉黑导致一直预留位置不释放 chatTable.RemoveFriendSend(req.PlayerID) // 如果在私聊列表中,则删除私聊记录 chatTable.RemovePrivate(req.PlayerID) chatTable.Save2Queue() p.ResponseCode(session, code.OK) // 如果在好友列表中,则解除单方好友状态 p.removeFriendRelation(req.PlayerID, true) // 拉黑就删除单方的私聊记录 redis.Chat.DelPrivateMsg(p.playerID, req.PlayerID) } // 解除好友关系 func (p *actorPlayer) removeFriendRelation(toPlayerID int64, isBlack bool) { var ( chatTable = p.ChatTable() now = ctime.Now() ) if friendRelation, found := chatTable.RemoveFriend(toPlayerID); found { if !isBlack { // 最近三天内有聊天记录 if ctime.NewSecond(friendRelation.LastContent.SendTime).DiffInDaysWithAbs(&now) <= data.Const.FriendPrivateChatSaveTime { chatTable.AddPrivate(toPlayerID, friendRelation.LastContent, friendRelation.LastSendTime) } } chatTable.Save2Queue() sessions.PushPlayer(p.playerID, nameRoute.PushGamePlayer_FirendDel, &pb.I64{ Value: toPlayerID, }) } } // 取消黑名单 func (p *actorPlayer) blackCancel(session *cproto.Session, playerID int64) { chatTable := p.ChatTable() if !chatTable.IsBlack(playerID) { p.ResponseCode(session, code.BlackListNotFound) return } chatTable.BlackCancel(playerID) chatTable.Save2Queue() p.ResponseCode(session, code.OK) } // 检查好友确认记录,避免异步发送没有收到好友的确认返回导致一直占用预留位置 func (p *actorPlayer) checkFriendSend() { chatTable := p.ChatTable() if chatTable.CheckFriendSend() { chatTable.Save2Queue() } }