actor_player.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. package player
  2. import (
  3. actorRemote "f1-game/internal/actor_remote"
  4. capp "f1-game/internal/cherry_app"
  5. "f1-game/internal/code"
  6. "f1-game/internal/component/rate"
  7. "f1-game/internal/constant"
  8. "f1-game/internal/data"
  9. "f1-game/internal/event"
  10. nameLocal "f1-game/internal/name/local"
  11. nameRemote "f1-game/internal/name/remote"
  12. "f1-game/internal/pb"
  13. "f1-game/internal/sessions"
  14. "f1-game/nodes/game/internal/db"
  15. gameFacade "f1-game/nodes/game/internal/facade"
  16. ao "f1-game/nodes/game/player/asset/origin"
  17. "fmt"
  18. "math/rand/v2"
  19. ctime "github.com/cherry-game/cherry/extend/time"
  20. cfacade "github.com/cherry-game/cherry/facade"
  21. cproto "github.com/cherry-game/cherry/net/proto"
  22. )
  23. var (
  24. kickRsp = &pb.I32{
  25. Value: code.AccountLoginTimeout,
  26. }
  27. )
  28. // actorPlayer 每个玩家一个PlayerActor
  29. type actorPlayer struct {
  30. capp.ActorLogger
  31. playerID int64 // 当前玩家id
  32. isOnline bool // 玩家是否在线
  33. now *ctime.CherryTime // 玩家当前时间
  34. loggerPrefix string // logger prefix
  35. funcLimiter rate.FuncLimiter // 函数访问限速
  36. funcErrCode int32 // 函数访问的错误码
  37. }
  38. func newActorPlayer(playerID int64) actorPlayer {
  39. return actorPlayer{
  40. ActorLogger: capp.NewLoggerPrefix("playerID", playerID),
  41. playerID: playerID,
  42. isOnline: false,
  43. now: nil,
  44. loggerPrefix: fmt.Sprintf("[playerID = %d] ", playerID),
  45. funcLimiter: rate.NewFuncLimiter(30, 3, code.NodeRateLimiter),
  46. funcErrCode: code.NodeRateLimiter,
  47. }
  48. }
  49. func (p *actorPlayer) OnInit() {
  50. p.updateNowTime()
  51. p.initRateLimits()
  52. p.initRemote()
  53. p.initPlayer()
  54. p.initGM()
  55. p.initCharge()
  56. p.initItem()
  57. p.initQuest()
  58. p.initHero()
  59. p.initEquip()
  60. p.initRecruit()
  61. p.initLineup()
  62. p.initAsset()
  63. p.initFriend()
  64. p.initChat()
  65. p.initChapter()
  66. p.initShop()
  67. p.initLord()
  68. p.initMarquee()
  69. p.initVip()
  70. p.initMiniGame()
  71. }
  72. func (p *actorPlayer) initRemote() {
  73. p.Remote().Register(nameRemote.Player_OnEnter, p.enter)
  74. p.Remote().Register(nameRemote.Player_OnSessionClosed, p.onSessionClosed)
  75. p.Remote().Register(nameRemote.Player_OnCheckExit, p.onCheckExit)
  76. }
  77. func (p *actorPlayer) OnStop() {
  78. p.Info("[actorPlayer] OnStop() playerID = %d", p.playerID)
  79. p.Timer().RemoveAll()
  80. p.ActorLogger.Destory()
  81. }
  82. func (p *actorPlayer) OnLocalReceived(m *cfacade.Message) (bool, bool) {
  83. if !p.isOnline {
  84. p.Kick(m.Session, kickRsp, true)
  85. return false, false
  86. }
  87. p.funcErrCode = p.funcLimiter.Check(m.BuildTime, m.FuncName)
  88. if code.IsFail(p.funcErrCode) {
  89. p.ResponseCode(m.Session, p.funcErrCode)
  90. return false, false
  91. }
  92. return true, false
  93. }
  94. func (p *actorPlayer) updateNowTime() {
  95. now := ctime.Now()
  96. p.now = &now
  97. }
  98. func (p *actorPlayer) initRateLimits() {
  99. //p.limiter.Add(playerName.ChatChannelList, chatConst.SendFrequency, code.ChatGetListTooFast)
  100. //p.limiter.Add(playerName.ChatSend, chatConst.SendFrequency, code.ChatSendTextTooFast)
  101. // 举报频率限制
  102. p.funcLimiter.Add(nameLocal.Player_Complaint, constant.ComplaintFrequency, 1, code.ComplaintTooFast)
  103. }
  104. // enter 玩家进入游戏
  105. func (p *actorPlayer) enter(session *cproto.Session) {
  106. p.updateNowTime()
  107. p.playerID = sessions.GetPlayerID(session)
  108. isNewPlayer := session.Contains(sessions.IsNewPlayer)
  109. if isNewPlayer {
  110. // TODO 随机名字功能应该由客户端实现
  111. isMale := rand.Float32() < 0.5
  112. name := data.LordName.RandomName(isMale)
  113. playerTable, ok := db.NewPlayer(p.playerID, session, name)
  114. if !ok {
  115. p.ResponseCode(session, code.PlayerCreateFail)
  116. return
  117. }
  118. // 抛出玩家创建事件
  119. p.PostEvent(event.NewPlayerCreate(playerTable.PlayerID, playerTable.Lord.Name))
  120. } else {
  121. _, found := db.GetPlayerTable(p.playerID)
  122. if !found {
  123. p.ResponseCode(session, code.PlayerIDError)
  124. return
  125. }
  126. }
  127. p.Debug("[onEnter] sid = %s, isNewPlayer = %v", session.Sid, isNewPlayer)
  128. playerTable := p.PlayerTable()
  129. // TODO 先放这里,后面再看看放哪里合理
  130. if isNewPlayer {
  131. p.onNewPlayer()
  132. }
  133. p.onReset(playerTable, true)
  134. gameFacade.ServiceOnLogin(playerTable, session)
  135. p.onEnterResponse(playerTable, session)
  136. gameFacade.ServiceOnLogined(playerTable, session)
  137. }
  138. func (p *actorPlayer) onNewPlayer() {
  139. // 添加初始道具
  140. for _, asset := range data.Const.PlayerInitItems {
  141. gameFacade.Asset.Add(p.playerID, asset.ID, asset.Num, ao.CreatePlayer, false)
  142. }
  143. // 添加初始英雄
  144. for _, asset := range data.Const.PlayerInitHeros {
  145. gameFacade.Hero.AddOne(p.playerID, asset.ID, int32(asset.Num), ao.CreatePlayer, false)
  146. }
  147. // 添加初始装备
  148. for _, asset := range data.Const.PlayerInitEquips {
  149. gameFacade.Equip.Add(p.playerID, asset.ID, asset.Num, ao.CreatePlayer, false)
  150. }
  151. }
  152. // logout gate发送网络断开请求
  153. func (p *actorPlayer) onSessionClosed() {
  154. p.Info("[onLogout] playerID = %d", p.playerID)
  155. // 不在线则忽略
  156. if !p.isOnline {
  157. return
  158. }
  159. // 设置为离线状态
  160. // 必需设置为 false,如果玩家被顶号,actor 不会被销毁,不设置会导致玩家无法登录
  161. p.isOnline = false
  162. //移除当前玩家所有定时器
  163. p.Timer().RemoveAll()
  164. if playerTable := p.PlayerTable(); playerTable != nil {
  165. gameFacade.ServiceOnLogout(playerTable)
  166. }
  167. p.Info("[onLogout] finished! playerID = %d", p.playerID)
  168. }
  169. // 父actor检测到当前子actor很久收到消息,确认是否要退出
  170. func (p *actorPlayer) onCheckExit() {
  171. // 不在线则销毁当前actor
  172. if !p.isOnline {
  173. p.Exit()
  174. }
  175. }
  176. // setSession 设置gate的session属性
  177. func (p *actorPlayer) setSession(playerTable *db.PlayerTable, session *cproto.Session) {
  178. // 更新gate节点的session
  179. sessionProto := pb.StrStrList{}
  180. sessionProto.Add(sessions.GameNodeID, p.App().NodeID())
  181. sessionProto.Add(sessions.PlayerID, p.playerID)
  182. if playerTable.Map.MapNodeID != "" {
  183. sessionProto.Add(sessions.MapNodeID, playerTable.Map.MapNodeID)
  184. }
  185. actorRemote.GateUser.SetSession(session.ActorPath(), &sessionProto)
  186. }
  187. // onReset 重置处理(每次登录、跨天触发)
  188. func (p *actorPlayer) onReset(playerTable *db.PlayerTable, byLogin bool) {
  189. playerTable.Stats.CheckReset(p.now)
  190. // 无需重置,则跳过
  191. if !playerTable.Stats.IsCanReset() {
  192. return
  193. }
  194. p.Debug("[onReset] playerID = %d", p.playerID)
  195. // 各系统模块执行重置
  196. gameFacade.ServiceOnReset(playerTable, p.now, byLogin)
  197. // 发送跨天重置事件
  198. p.PostEvent(event.NewPlayerReset(p.playerID))
  199. p.Warn("daily reset finish. playerID=%d", p.playerID)
  200. }
  201. // onEnterEnd 推送各模块数据给客户端
  202. func (p *actorPlayer) onEnterResponse(playerTable *db.PlayerTable, session *cproto.Session) {
  203. // 推送数据列表
  204. gameFacade.ServicePush(playerTable, session)
  205. // 推送完各个模块数据后再设置session
  206. p.setSession(playerTable, session)
  207. // 推送 玩家进入游戏响应结果 客户端收到表示登录数据推送完成
  208. playerPB := playerTable.ToPlayerProto()
  209. response := &pb.PlayerEnterResponse{
  210. Player: &playerPB,
  211. }
  212. p.Response(session, response)
  213. // 登录完成后,设置玩家在线状态
  214. p.isOnline = true
  215. // 在线状态设置后,再启动定时器
  216. p.startTimer()
  217. // 提交 玩家登录事件
  218. p.PostEvent(event.NewPlayerLogin(p.playerID, session))
  219. p.Debug("[onEnterResponse]")
  220. }