package main import ( "errors" "fmt" "strconv" "time" "mongo.games.com/goserver/core/basic" "mongo.games.com/goserver/core/logger" "mongo.games.com/goserver/core/module" "mongo.games.com/goserver/core/task" "mongo.games.com/game/common" "mongo.games.com/game/model" "mongo.games.com/game/proto" "mongo.games.com/game/protocol/friend" "mongo.games.com/game/worldsrv/internal" ) // 列表类型 const ( ListTypeFriend int32 = iota // 0.好友列表 ListTypeApply // 1.申请列表 ListTypeRecommend // 2.推荐列表 ) // 好友操作 const ( OpTypeApply int32 = iota // 0.申请,申请添加好友 OpTypeAgree // 1.同意,同意添加好友 OpTypeRefuse // 2.拒绝,拒绝添加好友 OpTypeDelete // 3.删除,删除好友 ) // 是否同意邀请进入游戏 const ( InviteAgree int = iota // 0.同意 InviteRefuse // 1.拒绝 ) const FriendMaxNum = 200 // 好友最大数量 const ShieldMaxNum = 10000 // 最大屏蔽人数 const FriendApplyMaxNum = 1000 // 好友申请上限 const FriendWrite = "FriendWrite" // 好友数据修改线程名称 var FriendMgrSingleton = &FriendMgr{ FriendList: make(map[string]map[int32]*model.Friend), TsInviteCd: make(map[string]map[string]int64), } type FriendMgr struct { FriendList map[string]map[int32]*model.Friend // 平台id:snid:好友信息 TsInviteCd map[string]map[string]int64 // 平台id:邀请人id_被邀请人id:邀请cd时间 } func (this *FriendMgr) ModuleName() string { return "FriendMgr" } func (this *FriendMgr) Init() { } // Add 缓存玩家信息 func (this *FriendMgr) Add(platform string, snid int32) { logger.Logger.Trace("(this *FriendMgr) Add ", snid) if this.FriendList[platform] == nil { this.FriendList[platform] = make(map[int32]*model.Friend) } if _, exist := this.FriendList[platform][snid]; !exist { p := PlayerMgrSington.GetPlayerBySnId(snid) if p != nil { this.FriendList[platform][snid] = model.NewFriend(p.Platform, p.SnId) this.UpdateInfo(p.Platform, p.SnId) } } } // Del 删除玩家缓存 func (this *FriendMgr) Del(platform string, snid int32) { if this.FriendList[platform] == nil { return } if _, exist := this.FriendList[platform][snid]; exist { delete(this.FriendList[platform], snid) } } // CanInvite 是否可以邀请,邀请冷却 // snid 发起人 // fsnid 被邀请人 func (this *FriendMgr) CanInvite(platform string, snid, fsnid int32) bool { if this.TsInviteCd[platform] == nil { this.TsInviteCd[platform] = make(map[string]int64) } strSnid := strconv.FormatInt(int64(snid), 10) + "_" + strconv.FormatInt(int64(fsnid), 10) if _, exist := this.TsInviteCd[platform][strSnid]; !exist { this.TsInviteCd[platform][strSnid] = time.Now().Unix() return true } if this.TsInviteCd[platform][strSnid] == 0 { this.TsInviteCd[platform][strSnid] = time.Now().Unix() return true } if time.Now().Unix()-this.TsInviteCd[platform][strSnid] > 30 { this.TsInviteCd[platform][strSnid] = time.Now().Unix() return true } return false } // AgreeApply 同意好友申请 func (this *FriendMgr) AgreeApply(platform string, snid int32, bf *model.BindFriend) friend.OpResultCode { logger.Logger.Trace("(this *FriendMgr) AgreeApply ", snid, " BindFriend: ", bf) if bf == nil || bf.Platform != platform { return friend.OpResultCode_OPRC_Friend_NoPlayer } if this.FriendList[platform] == nil { this.FriendList[platform] = make(map[int32]*model.Friend) } // 是否为好友 if this.IsFriend(platform, snid, bf.SnId) { return friend.OpResultCode_OPRC_Friend_AlreadyAdd } // 检查好友数量 dflDest := this.GetFriendList(platform, snid) if dflDest != nil { if len(dflDest) >= FriendMaxNum { return friend.OpResultCode_OPRC_Friend_DestFriendMax } } dfl := this.GetFriendList(platform, bf.SnId) if dfl != nil { if len(dfl) >= FriendMaxNum { return friend.OpResultCode_OPRC_Friend_FriendMax } } bf.CreateTime = time.Now().Unix() this.FriendList[platform][snid].BindFriend = append(this.FriendList[platform][snid].BindFriend, bf) this.FriendList[platform][snid].Dirty = true return friend.OpResultCode_OPRC_Sucess } // RemoveFriend 删除好友 func (this *FriendMgr) RemoveFriend(platform string, snid, destSnid int32) bool { logger.Logger.Trace("(this *FriendMgr) RemoveFriend ", snid, " destSnid: ", destSnid) if this.FriendList[platform] == nil { return false } if fl, exist := this.FriendList[platform][snid]; exist { for i, f := range fl.BindFriend { if f.SnId == destSnid { fl.BindFriend = append(fl.BindFriend[:i], fl.BindFriend[i+1:]...) fl.Dirty = true return true } } } return false } func (this *FriendMgr) UpdateInfo(platform string, snid int32) { logger.Logger.Trace("(this *FriendMgr) UpdateInfo ", snid) if this.FriendList[platform] == nil { return } p := PlayerMgrSington.GetPlayerBySnId(snid) if p == nil { return } info, ok := this.FriendList[platform][snid] if !ok { return } info.Name = p.Name info.Head = p.Head info.HeadUrl = p.HeadUrl info.Sex = p.Sex info.Coin = p.Coin info.Diamond = p.Diamond item := BagMgrSingleton.GetItem(p.SnId, common.ItemIDVCard) if item != nil { info.VCard = item.ItemNum } info.Roles = p.Roles.ModUnlock info.Pets = p.Pets.ModUnlock info.Age = p.Age info.Signature = p.Signature info.GameID = p.GameID info.UpdateTime = time.Now().Unix() info.Dirty = true for _, v := range info.BindFriend { if v == nil { continue } in := this.FriendList[platform][v.SnId] if in == nil { continue } for _, vv := range in.BindFriend { if vv != nil && vv.SnId == snid { vv.Name = p.Name vv.Head = p.Head vv.HeadUrl = p.HeadUrl vv.Sex = p.Sex vv.LogoutTime = p.LastLogoutTime.Unix() vv.RoleId = p.Roles.ModId in.Dirty = true break } } } } // GetPlayer 获取玩家信息 func (this *FriendMgr) GetPlayer(platform string, snid int32) *model.Friend { if this.FriendList[platform] == nil { return nil } if fi, exist := this.FriendList[platform][snid]; exist { this.UpdateInfo(platform, snid) return fi } return nil } // GetFriendList 获取好友列表 func (this *FriendMgr) GetFriendList(platform string, snid int32) []*model.BindFriend { var allFriend []*model.BindFriend if this.FriendList[platform] == nil { return nil } if f, exist := this.FriendList[platform][snid]; exist { if f != nil && f.BindFriend != nil { for _, bindFriend := range f.BindFriend { allFriend = append(allFriend, bindFriend) } } } return allFriend } // IsFriend 是否好友关系 func (this *FriendMgr) IsFriend(platform string, snid, destSnid int32) bool { logger.Logger.Trace("(this *FriendMgr) IsFriend ", snid, " -> ", destSnid) dfl := this.GetFriendList(platform, snid) if dfl != nil && len(dfl) != 0 { for _, df := range dfl { if df.SnId == destSnid { return true } } } return false } // ApplyList 查询好友申请列表 func (this *FriendMgr) ApplyList(platform string, snid int32) { var err error list := &model.ApplyList{} ret := &model.FriendApply{} task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { ret, err = model.QueryFriendApplyBySnid(platform, snid) if err != nil { logger.Logger.Errorf("(this *FriendMgr) ApplyList QueryFriendApplyBySnid %v", err) } list, err = model.QueryFriendApplyListBySnid(platform, snid) if err != nil { logger.Logger.Errorf("(this *FriendMgr) ApplyList QueryFriendApplyListBySnid %v", err) } return ret }), task.CompleteNotifyWrapper(func(data interface{}, tt task.Task) { if ret != nil && ret.ApplySnids != nil { pack := &friend.SCFriendApplyData{} for _, as := range ret.ApplySnids { p := PlayerMgrSington.GetPlayerBySnId(as.SnId) if p != nil { as.Name = p.Name } fa := &friend.FriendApply{ Snid: proto.Int32(as.SnId), Name: proto.String(as.Name), CreateTs: proto.Int64(as.CreateTs), } pack.FriendApplys = append(pack.FriendApplys, fa) } if len(pack.FriendApplys) > 0 { proto.SetDefaults(pack) p := PlayerMgrSington.GetPlayerBySnId(snid) if p != nil { p.SendToClient(int(friend.FriendPacketID_PACKET_SCFriendApplyData), pack) logger.Logger.Trace("SCFriendApplyData: 好友申请列表 pack: ", pack) } } } if list != nil && list.List != nil { p := PlayerMgrSington.GetPlayerBySnId(snid) if p != nil { p.ApplyList = list.List this.SendApplyList(p) } } })).StartByFixExecutor("QueryFriendApplyBySnid") } // AddShield 屏蔽好友消息 // snid屏蔽ssnid的消息 func (this *FriendMgr) AddShield(platform string, snid, ssnid int32) { if this.FriendList[platform] == nil { return } if fl, exist := this.FriendList[platform][snid]; exist { if fl.Shield == nil { fl.Shield = []int32{} } if len(fl.Shield) > ShieldMaxNum { return } fl.Shield = append(fl.Shield, ssnid) fl.Dirty = true } } // DelShield 解除消息屏蔽 func (this *FriendMgr) DelShield(platform string, snid, ssnid int32) { if this.FriendList[platform] == nil { return } if fl, exist := this.FriendList[platform][snid]; exist { if fl.Shield == nil { return } if len(fl.Shield) == 0 { return } fl.Shield = common.DelSliceInt32(fl.Shield, ssnid) fl.Dirty = true } } // IsShield 是否屏蔽消息 // snid的玩屏蔽ssnid的消息 func (this *FriendMgr) IsShield(platform string, snid, ssnid int32) bool { if this.FriendList[platform] == nil { return false } if fl, exist := this.FriendList[platform][snid]; exist { if fl.Shield == nil { return false } if len(fl.Shield) == 0 { return false } return common.InSliceInt32(fl.Shield, ssnid) } return false } // UpdateLogoutTime 更新玩家下线时间 func (this *FriendMgr) UpdateLogoutTime(platform string, snid int32) { if this.FriendList[platform] == nil { return } if fl, exist := this.FriendList[platform][snid]; exist { fl.LogoutTime = time.Now().Unix() fl.Dirty = true if fl.BindFriend != nil { for _, bf := range fl.BindFriend { if this.FriendList[bf.Platform] != nil { if data, ok := this.FriendList[bf.Platform][bf.SnId]; ok { if data.BindFriend != nil { for _, bindFriend := range data.BindFriend { if bindFriend.SnId == snid { bindFriend.LogoutTime = time.Now().Unix() break } } } } } } } } } func (this *FriendMgr) FriendOp(opcode int32, p *Player, destP *model.BindFriend) { switch opcode { case OpTypeApply: logger.Logger.Trace("@Apply friend", p.SnId, " -> ", destP.SnId) this.FriendApply(p, destP) case OpTypeAgree: logger.Logger.Trace("@AgreeApply friend", p.SnId, " -> ", destP.SnId) this.FriendAgree(p, destP) case OpTypeRefuse: logger.Logger.Trace("@Refuse friend", p.SnId, " -> ", destP.SnId) this.FriendRefuse(p, destP) case OpTypeDelete: logger.Logger.Trace("@Delete friend", p.SnId, " -> ", destP.SnId) this.FriendDelete(p, destP) } } // FriendApply 好友申请 // 记录在数据库 // p 发起方 // destP 接收方 func (this *FriendMgr) FriendApply(p *Player, destP *model.BindFriend) { var applyList []int32 SendToClick := func(retCode friend.OpResultCode, self ...bool) { pack := &friend.SCFriendOp{ OpCode: proto.Int32(OpTypeApply), SnId: proto.Int32(destP.SnId), OpRetCode: retCode, } if len(self) == 0 { p.SendToClient(int(friend.FriendPacketID_PACKET_SCFriendOp), pack) if applyList != nil { p.ApplyList = applyList this.SendApplyList(p) } } else { destPs := PlayerMgrSington.GetPlayerBySnId(destP.SnId) if destPs != nil && destPs.IsOnLine() { roleId := common.DefaultRoleId if p.Roles != nil { roleId = int(p.Roles.ModId) } pack.Friend = &friend.FriendInfo{ SnId: proto.Int32(p.SnId), Name: proto.String(p.Name), Sex: proto.Int32(p.Sex), Head: proto.Int32(p.Head), HeadUrl: proto.String(p.HeadUrl), CreateTs: proto.Int64(time.Now().Unix()), LogoutTs: proto.Int64(p.LastLogoutTime.Unix()), RoleId: int32(roleId), } destPs.SendToClient(int(friend.FriendPacketID_PACKET_SCFriendOp), pack) } } logger.Logger.Tracef(">>FriendApply %d -> %d, %v", p.SnId, destP.SnId, pack) } if FriendMgrSingleton.IsFriend(p.Platform, p.SnId, destP.SnId) { SendToClick(friend.OpResultCode_OPRC_Friend_AlreadyAdd) return } task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { ret, err := model.QueryFriendApplyBySnid(p.Platform, destP.SnId) if err != nil { return friend.OpResultCode_OPRC_Error } if ret != nil { //在申请列表 if ret.ApplySnids != nil { if len(ret.ApplySnids) > FriendApplyMaxNum { return friend.OpResultCode_OPRC_Friend_DestApplyFriendMax //对方好友申请已达上限 } for _, as := range ret.ApplySnids { if as.SnId == p.SnId { return friend.OpResultCode_OPRC_Friend_AlreadyApply //已经申请过好友 } } } } else { //不在申请列表 新增 ret = model.NewFriendApply(destP.SnId) } roleId := common.DefaultRoleId if p.Roles != nil { roleId = int(p.Roles.ModId) } ret.ApplySnids = append(ret.ApplySnids, &model.FriendApplySnid{ SnId: p.SnId, Name: p.Name, Head: p.Head, HeadUrl: p.HeadUrl, CreateTs: time.Now().Unix(), RoleId: int32(roleId), }) model.UpsertFriendApply(p.Platform, destP.SnId, ret) data, err := model.QueryFriendApplyListBySnid(p.Platform, p.SnId) if err != nil { logger.Logger.Errorf("QueryFriendApplyListBySnid err:%v", err) } else { if data == nil { data = model.NewApplyList(p.SnId) } if !common.InSliceInt32(data.List, destP.SnId) { data.List = append(data.List, destP.SnId) model.UpsertApplyList(p.Platform, data) applyList = data.List } } return friend.OpResultCode_OPRC_Sucess }), task.CompleteNotifyWrapper(func(data interface{}, tt task.Task) { SendToClick(friend.OpResultCode_OPRC_Sucess, false) // 对方 SendToClick(data.(friend.OpResultCode)) // 自己 })).StartByFixExecutor(FriendWrite) } // FriendAgree 同意好友申请 // p 同意者 // destP 申请者 func (this *FriendMgr) FriendAgree(p *Player, destP *model.BindFriend) { var applyList, meApplyList []int32 SendToClick := func(retCode friend.OpResultCode, self ...bool) { pack := &friend.SCFriendOp{ OpCode: proto.Int32(OpTypeAgree), SnId: proto.Int32(destP.SnId), OpRetCode: retCode, } if len(self) == 0 { roleId := common.DefaultRoleId if destP.RoleId != 0 { roleId = int(destP.RoleId) } pack.Friend = &friend.FriendInfo{ SnId: proto.Int32(destP.SnId), Name: proto.String(destP.Name), Sex: proto.Int32(destP.Sex), Head: proto.Int32(destP.Head), HeadUrl: proto.String(destP.HeadUrl), CreateTs: proto.Int64(time.Now().Unix()), LogoutTs: proto.Int64(destP.LogoutTime), RoleId: int32(roleId), } p.SendToClient(int(friend.FriendPacketID_PACKET_SCFriendOp), pack) if meApplyList != nil { p.ApplyList = meApplyList this.SendApplyList(p) } } else { destPs := PlayerMgrSington.GetPlayerBySnId(destP.SnId) if destPs != nil && destPs.IsOnLine() { roleId := common.DefaultRoleId if p.Roles != nil { roleId = int(p.Roles.ModId) } pack.Friend = &friend.FriendInfo{ SnId: proto.Int32(p.SnId), Name: proto.String(p.Name), Sex: proto.Int32(p.Sex), Head: proto.Int32(p.Head), HeadUrl: proto.String(p.HeadUrl), CreateTs: proto.Int64(time.Now().Unix()), LogoutTs: proto.Int64(p.LastLogoutTime.Unix()), RoleId: int32(roleId), } destPs.SendToClient(int(friend.FriendPacketID_PACKET_SCFriendOp), pack) if applyList != nil { destPs.ApplyList = applyList this.SendApplyList(destPs) } } } logger.Logger.Tracef(">>FriendAgree %d -> %d, %v", p.SnId, destP.SnId, pack) } me := FriendMgrSingleton.GetPlayer(p.Platform, p.SnId) if me == nil { SendToClick(friend.OpResultCode_OPRC_Error) return } if FriendMgrSingleton.IsFriend(p.Platform, p.SnId, destP.SnId) { //已经是好友了 SendToClick(friend.OpResultCode_OPRC_Friend_AlreadyAdd) return } //验证自己 if len(me.BindFriend) >= FriendMaxNum { SendToClick(friend.OpResultCode_OPRC_Friend_FriendMax) return } destPFriend := FriendMgrSingleton.GetPlayer(destP.Platform, destP.SnId) if destPFriend != nil { if len(destPFriend.BindFriend) >= FriendMaxNum { SendToClick(friend.OpResultCode_OPRC_Friend_DestFriendMax) return } } var friendDB *model.Friend // 申请者好友列表 var err error task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { if destPFriend == nil { // 不在线 friendDB, err = model.QueryFriendBySnid(destP.Platform, destP.SnId) if err != nil { logger.Logger.Error("QueryFriendBySnid:", err, destP.SnId) return friend.OpResultCode_OPRC_Error } if friendDB == nil || friendDB.SnId != destP.SnId { friendDB = model.NewFriend(destP.Platform, destP.SnId) } if len(friendDB.BindFriend) >= FriendMaxNum { return friend.OpResultCode_OPRC_Friend_FriendMax } for _, v := range friendDB.BindFriend { if v.SnId == p.SnId { return friend.OpResultCode_OPRC_Friend_AlreadyAdd } } } // 删除申请者的申请列表 delApplyListFunc := func(plt string, snid int32, applySnid int32) friend.OpResultCode { // 删除被申请者的申请列表 list1, err := model.QueryFriendApplyBySnid(plt, snid) if err != nil { logger.Logger.Errorf("QueryFriendApplyBySnid %v error: %v", snid, err) return friend.OpResultCode_OPRC_Error } if list1 != nil { k := 0 for k < len(list1.ApplySnids) { if list1.ApplySnids[k].SnId == applySnid { list1.ApplySnids = append(list1.ApplySnids[:k], list1.ApplySnids[k+1:]...) model.UpsertFriendApply(plt, snid, list1) } else { k++ } } } // 删除发起方的申请列表 list2, err := model.QueryFriendApplyListBySnid(plt, applySnid) if err != nil { logger.Logger.Errorf("QueryFriendApplyListBySnid %v error: %v", applySnid, err) return friend.OpResultCode_OPRC_Error } if list2 != nil { k := 0 for k < len(list2.List) { if list2.List[k] == snid { list2.List = append(list2.List[:k], list2.List[k+1:]...) model.UpsertApplyList(plt, list2) } else { k++ } } } if applySnid == destP.SnId && list2 != nil { applyList = list2.List } if applySnid == p.SnId && list2 != nil { meApplyList = list2.List } return friend.OpResultCode_OPRC_Sucess } //查看是否在申请列表 code := delApplyListFunc(p.Platform, p.SnId, destP.SnId) if code != friend.OpResultCode_OPRC_Sucess { return code } code = delApplyListFunc(p.Platform, destP.SnId, p.SnId) if code != friend.OpResultCode_OPRC_Sucess { return code } // 保存好友关系 if friendDB != nil { friendDB.BindFriend = append(friendDB.BindFriend, &model.BindFriend{ SnId: p.SnId, CreateTime: time.Now().Unix(), }) model.UpsertFriend(friendDB) } return nil }), task.CompleteNotifyWrapper(func(data interface{}, tt task.Task) { if data != nil { logger.Logger.Error("FriendAgree data:", data) SendToClick(data.(friend.OpResultCode)) return } //同意者加入到被同意者好友里 if destPlayer := FriendMgrSingleton.GetPlayer(destP.Platform, destP.SnId); destPlayer != nil { roleId := common.DefaultRoleId if p.Roles != nil { roleId = int(p.Roles.ModId) } result := FriendMgrSingleton.AgreeApply(destP.Platform, destP.SnId, &model.BindFriend{ SnId: p.SnId, CreateTime: time.Now().Unix(), Platform: p.Platform, Name: p.Name, Head: p.Head, HeadUrl: p.HeadUrl, Sex: p.Sex, LogoutTime: p.LastLogoutTime.Unix(), RoleId: int32(roleId), }) if result != friend.OpResultCode_OPRC_Sucess && result != friend.OpResultCode_OPRC_Friend_AlreadyAdd { logger.Logger.Warn("AgreeApply error: ", result) SendToClick(result) return } } // 被同意者加入到同意者好友里 result := FriendMgrSingleton.AgreeApply(p.Platform, p.SnId, destP) if result != friend.OpResultCode_OPRC_Sucess { SendToClick(result, false) SendToClick(result) return } SendToClick(friend.OpResultCode_OPRC_Sucess, false) SendToClick(friend.OpResultCode_OPRC_Sucess) })).StartByFixExecutor(FriendWrite) } func (this *FriendMgr) FriendRefuse(p *Player, destP *model.BindFriend) { var applyList []int32 SendToClick := func(retCode friend.OpResultCode, self ...bool) { pack := &friend.SCFriendOp{ OpCode: proto.Int32(OpTypeRefuse), SnId: proto.Int32(destP.SnId), OpRetCode: retCode, } if len(self) == 0 { p.SendToClient(int(friend.FriendPacketID_PACKET_SCFriendOp), pack) } else { destPs := PlayerMgrSington.GetPlayerBySnId(destP.SnId) if destPs != nil && destPs.IsOnLine() { destPs.SendToClient(int(friend.FriendPacketID_PACKET_SCFriendOp), pack) } } logger.Logger.Tracef(">>FriendRefuse %d -> %d, %v", p.SnId, destP.SnId, pack) } if FriendMgrSingleton.IsFriend(p.Platform, p.SnId, destP.SnId) { SendToClick(friend.OpResultCode_OPRC_Friend_AlreadyAdd) return } task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { ret, _ := model.QueryFriendApplyBySnid(p.Platform, p.SnId) if ret != nil { if ret.ApplySnids != nil { for i, as := range ret.ApplySnids { if as.SnId == destP.SnId { ret.ApplySnids = append(ret.ApplySnids[:i], ret.ApplySnids[i+1:]...) model.UpsertFriendApply(p.Platform, p.SnId, ret) data, err := model.QueryFriendApplyListBySnid(p.Platform, destP.SnId) if err != nil { logger.Logger.Errorf("QueryFriendApplyListBySnid err:%v", err) } else { if data == nil { data = model.NewApplyList(destP.SnId) } for k, v := range data.List { if v == p.SnId { data.List = append(data.List[:k], data.List[k+1:]...) model.UpsertApplyList(p.Platform, data) applyList = data.List break } } } return nil } } } } return errors.New("not in apply") }), task.CompleteNotifyWrapper(func(data interface{}, tt task.Task) { //拒绝了不提醒 if data != nil { logger.Logger.Error("FriendRefuse data:", data) SendToClick(friend.OpResultCode_OPRC_Error) return } SendToClick(friend.OpResultCode_OPRC_Sucess) // 刷新发起者的申请好友列表 destPs := PlayerMgrSington.GetPlayerBySnId(destP.SnId) if destPs != nil && destPs.IsOnLine() { if applyList != nil { destPs.ApplyList = applyList this.SendApplyList(destPs) } } })).StartByFixExecutor(FriendWrite) } func (this *FriendMgr) FriendDelete(p *Player, destP *model.BindFriend) { SendToClick := func(retCode friend.OpResultCode, self ...bool) { pack := &friend.SCFriendOp{ OpCode: proto.Int32(OpTypeDelete), SnId: proto.Int32(destP.SnId), OpRetCode: retCode, } if len(self) == 0 { pack.SnId = destP.SnId p.SendToClient(int(friend.FriendPacketID_PACKET_SCFriendOp), pack) logger.Logger.Tracef(">>FriendDelete %d -> %d, %v", p.SnId, destP.SnId, pack) } else { destPs := PlayerMgrSington.GetPlayerBySnId(destP.SnId) if destPs != nil && destPs.IsOnLine() { pack.SnId = p.SnId destPs.SendToClient(int(friend.FriendPacketID_PACKET_SCFriendOp), pack) logger.Logger.Tracef(">>FriendDelete dest %d -> %d, %v", p.SnId, destP.SnId, pack) } } } f := FriendMgrSingleton.GetPlayer(p.Platform, destP.SnId) if f != nil { //发起者删除被删除者 isok1 := FriendMgrSingleton.RemoveFriend(p.Platform, p.SnId, f.SnId) if !isok1 { logger.Logger.Warn("RemoveFriend error: ", p.SnId, " del friend:", f.SnId) SendToClick(friend.OpResultCode_OPRC_Error) return } //被删除者删除发起者 isok2 := FriendMgrSingleton.RemoveFriend(f.Platform, f.SnId, p.SnId) if !isok2 { logger.Logger.Warn("RemoveFriend error: ", f.SnId, " del friend:", p.SnId) //删除失败不用通知 } else { SendToClick(friend.OpResultCode_OPRC_Sucess, false) } SendToClick(friend.OpResultCode_OPRC_Sucess) ChatMgrSington.DelChat(p.Platform, p.SnId, f.SnId) } else { task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { ret, _ := model.QueryFriendBySnid(p.Platform, destP.SnId) if ret != nil { //被删除者删除发起者 if ret.BindFriend != nil { for i, bindFriend := range ret.BindFriend { if bindFriend.SnId == p.SnId { ret.BindFriend = append(ret.BindFriend[:i], ret.BindFriend[i+1:]...) model.UpsertFriend(ret) SendToClick(friend.OpResultCode_OPRC_Sucess, false) return nil } } } } return errors.New("not in apply") }), task.CompleteNotifyWrapper(func(data interface{}, tt task.Task) { if data != nil { logger.Logger.Error("FriendDelete data:", data) SendToClick(friend.OpResultCode_OPRC_Error) return } else { //发起者删除被删除者 isok1 := FriendMgrSingleton.RemoveFriend(p.Platform, p.SnId, destP.SnId) if !isok1 { logger.Logger.Warn("RemoveFriend error: ", p.SnId, " del friend:", destP.SnId) //SendToClick(friend.OpResultCode_OPRC_Error) //return } SendToClick(friend.OpResultCode_OPRC_Sucess) } ChatMgrSington.DelChat(p.Platform, p.SnId, destP.SnId) })).StartByFixExecutor(FriendWrite) } } func (this *FriendMgr) Update() { } func (this *FriendMgr) Shutdown() { module.UnregisteModule(this) } func (this *FriendMgr) UpdateName(snId int32, name string) { p := PlayerMgrSington.GetPlayerBySnId(snId) if p != nil { this.UpdateInfo(p.Platform, p.SnId) } } func (this *FriendMgr) UpdateHead(snId, head int32) { p := PlayerMgrSington.GetPlayerBySnId(snId) if p != nil { this.UpdateInfo(p.Platform, p.SnId) } } func (this *FriendMgr) SendApplyList(p *Player) { pack := &friend.SCRequestAddFriend{} for _, v := range p.ApplyList { pack.RequestAddFriend = append(pack.RequestAddFriend, v) } p.SendToClient(int(friend.FriendPacketID_PACKET_SCRequestAddFriend), pack) logger.Logger.Tracef("SCRequestAddFriend:%v %v", pack, p.SnId) } //========================implement IPlayerLoad ============================== func (this *FriendMgr) Load(platform string, snid int32, player any) *internal.PlayerLoadReplay { return nil } func (this *FriendMgr) Callback(player any, ret *internal.PlayerLoadReplay) { } func (this *FriendMgr) LoadAfter(platform string, snid int32) *internal.PlayerLoadReplay { ret := &internal.PlayerLoadReplay{ Platform: platform, Snid: snid, } // 查询好友列表 friendDB, err := model.QueryFriendBySnid(platform, snid) if err != nil { logger.Logger.Error("QueryFriendBySnid:", err, snid) ret.Err = err return ret } if friendDB == nil { return ret } // 查询好友信息 var offSnID []int32 for _, v := range friendDB.BindFriend { roleId := common.DefaultRoleId if v.RoleId != 0 { roleId = int(v.RoleId) } p := PlayerMgrSington.GetPlayerBySnId(v.SnId) if p != nil { v.Platform = p.Platform v.Name = p.Name v.Head = p.Head v.HeadUrl = p.HeadUrl v.Sex = p.Sex if !p.IsOnLine() { v.LogoutTime = p.LastLogoutTime.Unix() } v.RoleId = int32(roleId) } else { offSnID = append(offSnID, v.SnId) } } if len(offSnID) > 0 { offFriends, err := model.QueryFriendsBySnids(platform, offSnID) if err != nil { logger.Logger.Error("QueryFriendsBySnids is err:", err) ret.Err = err return ret } for _, offFriend := range offFriends { for _, v := range friendDB.BindFriend { roleId := common.DefaultRoleId if v.RoleId != 0 { roleId = int(v.RoleId) } if v.SnId == offFriend.SnId { v.Platform = offFriend.Platform v.Name = offFriend.Name v.Head = offFriend.Head v.HeadUrl = offFriend.HeadUrl v.Sex = offFriend.Sex v.LogoutTime = offFriend.LogoutTime v.RoleId = int32(roleId) break } } } } ret.Data = friendDB return ret } func (this *FriendMgr) CallbackAfter(ret *internal.PlayerLoadReplay) { if ret == nil || ret.Platform == "" || ret.Snid <= 0 { return } if ret.Err != nil { logger.Logger.Error("(this *FriendMgr) CallbackAfter err:", ret.Err) return } if ret.Data == nil { this.Add(ret.Platform, ret.Snid) logger.Logger.Infof("(this *FriendMgr) LoadFriendData New: %+v", *this.GetPlayer(ret.Platform, ret.Snid)) return } data, ok := ret.Data.(*model.Friend) if !ok { logger.Logger.Error("bug") return } if this.FriendList[ret.Platform] == nil { this.FriendList[ret.Platform] = make(map[int32]*model.Friend) } this.FriendList[ret.Platform][ret.Snid] = data logger.Logger.Infof("(this *FriendMgr) LoadFriendData db: %+v", *data) p := PlayerMgrSington.GetPlayerBySnId(ret.Snid) if p != nil { this.UpdateInfo(ret.Platform, ret.Snid) } FriendUnreadMgrSington.LoadFriendUnreadData(ret.Platform, ret.Snid) this.ApplyList(ret.Platform, ret.Snid) } func (this *FriendMgr) Save(platform string, snid int32, isSync, force bool) { logger.Logger.Trace("(this *FriendMgr) SaveFriendData ", snid) ret := this.GetPlayer(platform, snid) if ret == nil || (!ret.Dirty && !force) { return } var res bool f := func() { res = model.UpsertFriend(ret) != nil } cf := func() { if res { ret.Dirty = false } } if isSync { f() cf() return } task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { f() return nil }), task.CompleteNotifyWrapper(func(i interface{}, t task.Task) { cf() })).StartByFixExecutor(fmt.Sprintf("player%v", ret.SnId)) } func (this *FriendMgr) Release(platform string, snid int32) { this.Del(platform, snid) } func init() { module.RegisteModule(FriendMgrSingleton, time.Hour, 0) internal.RegisterPlayerLoad(FriendMgrSingleton) }