player_friend.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. package player
  2. import (
  3. actorRemote "f1-game/internal/actor_remote"
  4. "f1-game/internal/code"
  5. "f1-game/internal/component/redis"
  6. "f1-game/internal/data"
  7. "f1-game/internal/enum"
  8. nameLocal "f1-game/internal/name/local"
  9. nameRemote "f1-game/internal/name/remote"
  10. nameRoute "f1-game/internal/name/route"
  11. "f1-game/internal/pb"
  12. "f1-game/internal/sessions"
  13. dbChat "f1-game/nodes/game/internal/db/data/chat"
  14. "f1-game/nodes/game/player/chat"
  15. ctime "github.com/cherry-game/cherry/extend/time"
  16. cproto "github.com/cherry-game/cherry/net/proto"
  17. )
  18. func (p *actorPlayer) initFriend() {
  19. p.Local().Register(nameLocal.Player_FriendSearch, p.friendSearch)
  20. p.Local().Register(nameLocal.Player_FriendAdd, p.friendAdd)
  21. p.Local().Register(nameLocal.Player_FriendConfirm, p.friendConfirm)
  22. p.Local().Register(nameLocal.Player_FriendDel, p.friendDel)
  23. p.Local().Register(nameLocal.Player_BlackSetting, p.blackSetting)
  24. p.Remote().Register(nameRemote.Player_FriendAddSend, p.friendAddSend)
  25. p.Remote().Register(nameRemote.Player_FriendAddSendBack, p.friendAddSendBack)
  26. p.Remote().Register(nameRemote.Player_FriendConfirmSend, p.friendConfirmSend)
  27. p.Remote().Register(nameRemote.Player_FriendConfirmBack, p.friendConfirmBack)
  28. }
  29. // 查询玩家信息
  30. func (p *actorPlayer) friendSearch(session *cproto.Session, req *pb.I64) {
  31. if req.Value < 1 {
  32. p.ResponseCode(session, code.IllegalArgument)
  33. return
  34. }
  35. chatPlayer := redis.Game.GetChatPlayer(req.Value)
  36. if chatPlayer == nil {
  37. p.ResponseCode(session, code.PlayerDetailNotFound)
  38. return
  39. }
  40. p.Response(session, chatPlayer)
  41. }
  42. // 添加好友
  43. func (p *actorPlayer) friendAdd(session *cproto.Session, req *pb.I64) {
  44. toPlayerID := req.Value
  45. if toPlayerID < 1 {
  46. p.ResponseCode(session, code.IllegalArgument)
  47. return
  48. }
  49. if toPlayerID == p.playerID {
  50. p.ResponseCode(session, code.FriendAddSelf)
  51. return
  52. }
  53. var (
  54. playerTable = p.PlayerTable()
  55. chatTable = p.ChatTable()
  56. )
  57. if playerTable.Lord.Level < data.Const.FriendAddOpenLv {
  58. p.ResponseCode(session, code.FriendAddLvNotEnough)
  59. return
  60. }
  61. if chatTable.IsBlack(toPlayerID) {
  62. p.ResponseCode(session, code.FriendBlackListed)
  63. return
  64. }
  65. if chatTable.GetFriendCount() >= data.Const.FriendNumLimit {
  66. p.ResponseCode(session, code.FriendNumLimit)
  67. return
  68. }
  69. if chatTable.IsFriend(toPlayerID) {
  70. p.ResponseCode(session, code.FriendRepeatAdd)
  71. return
  72. }
  73. chatPlayerMap := redis.Game.GetChatPlayerMap(p.playerID, toPlayerID)
  74. if len(chatPlayerMap) != 2 {
  75. p.ResponseCode(session, code.PlayerDetailNotFound)
  76. return
  77. }
  78. var (
  79. chatPlayer = chatPlayerMap[p.playerID]
  80. toChatPlayer = chatPlayerMap[toPlayerID]
  81. )
  82. // 发起好友邀请
  83. errCode := actorRemote.GamePlayer.Call(toChatPlayer.GameNodeID, toPlayerID, nameRemote.Player_FriendAddSend, chatPlayer)
  84. if code.IsFail(errCode) {
  85. p.ResponseCode(session, errCode)
  86. return
  87. }
  88. p.ResponseCode(session, code.OK)
  89. }
  90. // 收到好友申请
  91. func (p *actorPlayer) friendAddSend(req *pb.ChatPlayer) {
  92. chatTable := p.ChatTable()
  93. // 已经是好友了
  94. if chatTable.IsFriend(req.PlayerID) {
  95. // 可能存在单向好友的情况,直接返回
  96. p.callFriendAddSendBack(req.GameNodeID, req.PlayerID, code.FriendAddSuccess, true)
  97. return
  98. }
  99. // 判断是否在黑名单中
  100. if chatTable.IsBlack(req.PlayerID) {
  101. p.callFriendAddSendBack(req.GameNodeID, req.PlayerID, code.FriendTargetInBlackList, false)
  102. return
  103. }
  104. // 拒绝添加好友
  105. if !chatTable.IsFriendInviteMute {
  106. p.callFriendAddSendBack(req.GameNodeID, req.PlayerID, code.FriendRefuseAdd, false)
  107. return
  108. }
  109. // 等级不够
  110. if p.PlayerTable().Lord.Level < data.Const.FriendAddOpenLv {
  111. p.callFriendAddSendBack(req.GameNodeID, req.PlayerID, code.FriendTargetLvNotEnough, false)
  112. return
  113. }
  114. // 已经在邀请列表中了
  115. if _, found := chatTable.GetFriendInvite(req.PlayerID); found {
  116. p.callFriendAddSendBack(req.GameNodeID, req.PlayerID, code.FriendApplyRepeatAdd, false)
  117. return
  118. }
  119. newInvite := dbChat.NewFriendInvite(req.PlayerID)
  120. chatTable.AddFriendInvite(newInvite)
  121. chatTable.Save2Queue()
  122. p.callFriendAddSendBack(req.GameNodeID, req.PlayerID, code.FriendAddSendSuccess, false)
  123. rsp := &pb.FriendInvite{
  124. InvitePlayer: req,
  125. InviteTime: newInvite.InviteTime,
  126. }
  127. sessions.PushPlayer(p.playerID, nameRoute.PushGamePlayer_FriendInviteNewPush, rsp)
  128. }
  129. // 添加好友返回消息发送
  130. func (p *actorPlayer) callFriendAddSendBack(toPlayerGameNodeID string, toPlayerID int64, errCode int32, result bool) {
  131. retCode := actorRemote.GamePlayer.Call(toPlayerGameNodeID, toPlayerID, nameRemote.Player_FriendAddSendBack, &pb.AddFriendResult{
  132. PlayerID: p.playerID,
  133. ErrCode: errCode,
  134. Result: result,
  135. })
  136. if code.IsFail(retCode) {
  137. p.Warn("callFriendAddSendBack failed, toPlayerID: %d, retCode: %d, errCode: %d, result: %v", toPlayerID, retCode, errCode, result)
  138. }
  139. }
  140. // 好友申请返回处理
  141. func (p *actorPlayer) friendAddSendBack(req *pb.AddFriendResult) {
  142. var (
  143. toPlayerID = req.PlayerID
  144. errCode = req.ErrCode
  145. result = req.Result
  146. )
  147. // 单方好友,直接添加成功
  148. if result {
  149. chatPlayer := redis.Game.GetChatPlayer(toPlayerID)
  150. p.onAddFriend(chatPlayer)
  151. }
  152. sessions.PushPlayer(p.playerID, nameRoute.PushGamePlayer_FriendAddBack, &pb.I64I32{
  153. Key: toPlayerID,
  154. Value: errCode,
  155. })
  156. }
  157. // 添加好友的逻辑处理
  158. func (p *actorPlayer) onAddFriend(chatPlayer *pb.ChatPlayer) {
  159. var (
  160. chatTypeConfig, _ = data.ChatType.GetByChatType(enum.ChatType_Private)
  161. param = &pb.ParamsTemplate{
  162. Type: int32(enum.ChatMsgType_FriendAdd),
  163. }
  164. chatMsg = chat.Service().BuildMsgProto(chatPlayer, enum.ChatMsgType_FriendAdd, "", ctime.Now().ToSecond(), param)
  165. toPlayerID = chatPlayer.PlayerID
  166. )
  167. // 添加私聊消息
  168. redis.Chat.AddPrivateMsg(p.playerID, toPlayerID, chatTypeConfig.MsgLimit, chatMsg)
  169. var (
  170. chatTable = p.ChatTable()
  171. // 最近聊天内容
  172. lastChatContent = dbChat.NewChatContent(chatMsg.MsgID, chatMsg.SendTime, chatMsg.Type, chatMsg.Text, chatMsg.Params)
  173. // 好友关系
  174. newFriendRelation = dbChat.NewFriendRelation(toPlayerID, lastChatContent)
  175. )
  176. // 添加好友关系
  177. chatTable.FriendList.Add(newFriendRelation)
  178. // 如果加了好友就从私聊列表里面移除
  179. chatTable.RemovePrivate(toPlayerID)
  180. // 从发起列表中移除
  181. chatTable.RemoveFriendSend(toPlayerID)
  182. chatTable.Save2Queue()
  183. if p.isOnline {
  184. toChatPlayer := redis.Game.GetChatPlayer(toPlayerID)
  185. if toChatPlayer == nil {
  186. return
  187. }
  188. rsp := &pb.FriendRelation{
  189. FriendPlayer: toChatPlayer,
  190. CreateTime: newFriendRelation.CreateTime,
  191. LastContent: lastChatContent.ToProto(),
  192. }
  193. sessions.PushPlayer(p.playerID, nameRoute.PushGamePlayer_FirendNew, rsp)
  194. }
  195. }
  196. // 删除好友
  197. func (p *actorPlayer) friendDel(session *cproto.Session, req *pb.I64) {
  198. if req.Value < 1 {
  199. p.ResponseCode(session, code.IllegalArgument)
  200. return
  201. }
  202. if !p.ChatTable().IsFriend(req.Value) {
  203. p.ResponseCode(session, code.FriendNotFound)
  204. return
  205. }
  206. // 解除好友关系
  207. p.removeFriendRelation(req.Value, false)
  208. p.ResponseCode(session, code.OK)
  209. }
  210. // 好友申请确认
  211. func (p *actorPlayer) friendConfirm(session *cproto.Session, req *pb.FriendInviteConfirm) {
  212. chatTable := p.ChatTable()
  213. // 一键拒绝所有申请
  214. if req.IsRejectAll {
  215. chatTable.FriendRecvList.Clear()
  216. chatTable.Save2Queue()
  217. p.ResponseCode(session, code.OK)
  218. return
  219. }
  220. if req.PlayerID < 1 {
  221. p.ResponseCode(session, code.IllegalArgument)
  222. return
  223. }
  224. var (
  225. toPlayerID = req.PlayerID // 好友ID
  226. isAccept = req.IsAccept // 是否接受
  227. )
  228. if _, found := chatTable.GetFriendInvite(toPlayerID); !found {
  229. p.ResponseCode(session, code.FriendInviteNotFound)
  230. return
  231. }
  232. if !isAccept {
  233. chatTable.RemoveFriendInvite(toPlayerID)
  234. chatTable.Save2Queue()
  235. p.ResponseCode(session, code.OK)
  236. return
  237. }
  238. if chatTable.IsFriend(toPlayerID) {
  239. // 已经是好友,直接删除邀请
  240. chatTable.RemoveFriendInvite(toPlayerID)
  241. chatTable.Save2Queue()
  242. p.ResponseCode(session, code.OK)
  243. // 给客户端统一异步接收的通知吧
  244. sessions.PushPlayer(p.playerID, nameRoute.PushGamePlayer_FriendConfirmBack, &pb.I64I32{
  245. Key: toPlayerID,
  246. Value: code.FriendRepeatAdd,
  247. })
  248. return
  249. }
  250. if chatTable.GetFriendCount() >= data.Const.FriendNumLimit {
  251. p.ResponseCode(session, code.FriendNumLimit)
  252. return
  253. }
  254. chatPlayerMap := redis.Game.GetChatPlayerMap(p.playerID, toPlayerID)
  255. if len(chatPlayerMap) != 2 {
  256. p.ResponseCode(session, code.PlayerDetailNotFound)
  257. return
  258. }
  259. var (
  260. chatPlayer = chatPlayerMap[p.playerID]
  261. toChatPlayer = chatPlayerMap[toPlayerID]
  262. )
  263. // 异步请求,把自己的信息带过去
  264. retCode := actorRemote.GamePlayer.Call(toChatPlayer.GameNodeID, toPlayerID, nameRemote.Player_FriendConfirmSend, chatPlayer)
  265. if code.IsFail(retCode) {
  266. p.ResponseCode(session, retCode)
  267. return
  268. }
  269. // 记录发送过好友确认的状态
  270. if !chatTable.HasFriendSend(toPlayerID) {
  271. newComfirmSend := dbChat.NewFriendInvite(toPlayerID)
  272. chatTable.FriendSendList.Add(newComfirmSend)
  273. }
  274. // 删除申请列表
  275. chatTable.RemoveFriendInvite(toPlayerID)
  276. chatTable.Save2Queue()
  277. p.ResponseCode(session, code.OK)
  278. }
  279. // 好友确认返回
  280. func (p *actorPlayer) callFriendConfirmBack(toPlayerGameNodeID string, toPlayerID int64, errCode int32, result bool) {
  281. retCode := actorRemote.GamePlayer.Call(toPlayerGameNodeID, toPlayerID, nameRemote.Player_FriendConfirmBack, &pb.AddFriendResult{
  282. PlayerID: p.playerID,
  283. ErrCode: errCode,
  284. Result: result,
  285. })
  286. if code.IsFail(retCode) {
  287. p.Warn("callFriendConfirmBack failed, toPlayerID: %d,retCode: %d, errCode: %d, result: %v", toPlayerID, retCode, errCode, result)
  288. }
  289. }
  290. // 收到好友确认通知
  291. func (p *actorPlayer) friendConfirmSend(req *pb.ChatPlayer) {
  292. var (
  293. chatTable = p.ChatTable()
  294. toPlayerID = req.PlayerID
  295. toPlayerGameNodeID = req.GameNodeID
  296. )
  297. // 拉黑了
  298. if chatTable.IsBlack(p.playerID) {
  299. p.callFriendConfirmBack(toPlayerGameNodeID, toPlayerID, code.FriendBlackListed, false)
  300. return
  301. }
  302. // 好友数量
  303. friendCount := chatTable.GetFriendCount()
  304. // 如果已经预留了位置就减去1
  305. if chatTable.HasFriendSend(toPlayerID) {
  306. friendCount -= 1
  307. }
  308. if friendCount >= data.Const.FriendNumLimit {
  309. p.callFriendConfirmBack(toPlayerGameNodeID, toPlayerID, code.FriendTargetNumLimit, false)
  310. return
  311. }
  312. // 已经是好友了,直接返回成功
  313. if chatTable.IsFriend(toPlayerID) {
  314. // 如果也发起确认请求,就删除发送确认记录
  315. chatTable.RemoveFriendSend(toPlayerID)
  316. chatTable.Save2Queue()
  317. p.callFriendConfirmBack(toPlayerGameNodeID, toPlayerID, code.FriendAddSuccess, true)
  318. return
  319. }
  320. p.onAddFriend(req)
  321. p.callFriendConfirmBack(toPlayerGameNodeID, toPlayerID, code.FriendAddSuccess, true)
  322. }
  323. // 好友确认发送返回
  324. func (p *actorPlayer) friendConfirmBack(req *pb.AddFriendResult) {
  325. var (
  326. chatTable = p.ChatTable()
  327. toPlayerID = req.PlayerID
  328. errCode = req.ErrCode
  329. result = req.Result
  330. )
  331. // 添加失败和成功都删除发送确认记录(删除预留位置)
  332. chatTable.RemoveFriendSend(toPlayerID)
  333. chatTable.Save2Queue()
  334. if result {
  335. if !chatTable.IsFriend(toPlayerID) {
  336. chatPlayer := redis.Game.GetChatPlayer(toPlayerID)
  337. p.onAddFriend(chatPlayer)
  338. }
  339. }
  340. sessions.PushPlayer(p.playerID, nameRoute.PushGamePlayer_FriendConfirmBack, &pb.I64I32{
  341. Key: toPlayerID,
  342. Value: errCode,
  343. })
  344. }
  345. // 黑名单设置
  346. func (p *actorPlayer) blackSetting(session *cproto.Session, req *pb.BlackSetting) {
  347. if req.PlayerID < 1 || req.PlayerID == p.playerID {
  348. p.ResponseCode(session, code.IllegalArgument)
  349. return
  350. }
  351. if !req.IsBlack {
  352. p.blackCancel(session, req.PlayerID)
  353. return
  354. }
  355. chatTable := p.ChatTable()
  356. if chatTable.IsBlack(req.PlayerID) {
  357. p.ResponseCode(session, code.BlackListRepeatAdd)
  358. return
  359. }
  360. if chatTable.GetBlackCount() >= data.Const.FriendBlacklistLimit {
  361. p.ResponseCode(session, code.BlackListNumLimit)
  362. return
  363. }
  364. toChatPlayer := redis.Game.GetChatPlayer(req.PlayerID)
  365. if toChatPlayer == nil {
  366. p.ResponseCode(session, code.PlayerDetailNotFound)
  367. return
  368. }
  369. newBlack := dbChat.NewBlack(req.PlayerID, ctime.Now().ToSecond())
  370. chatTable.AddBlack(newBlack)
  371. // 删除预留的位置,避免发起确认里面拉黑导致一直预留位置不释放
  372. chatTable.RemoveFriendSend(req.PlayerID)
  373. // 如果在私聊列表中,则删除私聊记录
  374. chatTable.RemovePrivate(req.PlayerID)
  375. chatTable.Save2Queue()
  376. p.ResponseCode(session, code.OK)
  377. // 如果在好友列表中,则解除单方好友状态
  378. p.removeFriendRelation(req.PlayerID, true)
  379. // 拉黑就删除单方的私聊记录
  380. redis.Chat.DelPrivateMsg(p.playerID, req.PlayerID)
  381. }
  382. // 解除好友关系
  383. func (p *actorPlayer) removeFriendRelation(toPlayerID int64, isBlack bool) {
  384. var (
  385. chatTable = p.ChatTable()
  386. now = ctime.Now()
  387. )
  388. if friendRelation, found := chatTable.RemoveFriend(toPlayerID); found {
  389. if !isBlack {
  390. // 最近三天内有聊天记录
  391. if ctime.NewSecond(friendRelation.LastContent.SendTime).DiffInDaysWithAbs(&now) <= data.Const.FriendPrivateChatSaveTime {
  392. chatTable.AddPrivate(toPlayerID, friendRelation.LastContent, friendRelation.LastSendTime)
  393. }
  394. }
  395. chatTable.Save2Queue()
  396. sessions.PushPlayer(p.playerID, nameRoute.PushGamePlayer_FirendDel, &pb.I64{
  397. Value: toPlayerID,
  398. })
  399. }
  400. }
  401. // 取消黑名单
  402. func (p *actorPlayer) blackCancel(session *cproto.Session, playerID int64) {
  403. chatTable := p.ChatTable()
  404. if !chatTable.IsBlack(playerID) {
  405. p.ResponseCode(session, code.BlackListNotFound)
  406. return
  407. }
  408. chatTable.BlackCancel(playerID)
  409. chatTable.Save2Queue()
  410. p.ResponseCode(session, code.OK)
  411. }
  412. // 检查好友确认记录,避免异步发送没有收到好友的确认返回导致一直占用预留位置
  413. func (p *actorPlayer) checkFriendSend() {
  414. chatTable := p.ChatTable()
  415. if chatTable.CheckFriendSend() {
  416. chatTable.Save2Queue()
  417. }
  418. }