role_manager.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. package model
  2. import (
  3. "math/rand"
  4. "rocommon"
  5. "rocommon/service"
  6. "rocommon/util"
  7. "roserver/baseserver/model"
  8. "roserver/baseserver/set"
  9. "roserver/serverproto"
  10. )
  11. type RoleManager struct {
  12. rocommon.UpdateModule
  13. onlineNum int
  14. channelRoleList map[uint64]RoleOuter //[channelid,Role]
  15. uuidRoleList map[uint64]RoleOuter //[uuid,role]
  16. offlineRoleList map[uint64]RoleOuter //[uuid,role]
  17. openRoleList map[string]RoleOuter //[openid,rol]
  18. updateTimer util.ServerTimer //主循环定时器
  19. lastResetTime uint64
  20. playerFifoList set.Interface //最近在线玩家列表 FIFO
  21. noticeInfo *serverproto.SSWebGMNoticeNtf //走马灯公告
  22. tw *util.TimeWheel
  23. allGameOnlineNum int32 //所有game服务器当前在线的玩家数量
  24. }
  25. func NewRoleManager() *RoleManager {
  26. rm := &RoleManager{
  27. channelRoleList: make(map[uint64]RoleOuter),
  28. uuidRoleList: make(map[uint64]RoleOuter),
  29. offlineRoleList: make(map[uint64]RoleOuter),
  30. openRoleList: make(map[string]RoleOuter),
  31. lastResetTime: util.GetTimeMilliseconds(),
  32. }
  33. //rm.updateTimer = util.NewDurationTimer(util.GetCurrentTime(), 500)
  34. rm.updateTimer = util.NewDurationTimer(util.GetCurrentTime(), 2000)
  35. rm.playerFifoList = set.New(set.NonThreadSafe)
  36. rm.tw = util.NewTimeWheel(100, 32)
  37. rm.tw.Callback = rm.UpdateWithTimeTimeWheelTask
  38. return rm
  39. }
  40. var updateCount = 0
  41. var ResetCount = 0
  42. func (this *RoleManager) Update(ms uint64) {
  43. if !this.updateTimer.IsStart() || !this.updateTimer.IsExpired(ms) {
  44. return
  45. }
  46. //注意不能5点后停服,5点后启服(不会触发隔天重置)
  47. dailyResetHour5 := model.IsDailyResetHour5(this.lastResetTime)
  48. if dailyResetHour5 {
  49. rand.Seed(int64(ms))
  50. }
  51. //dailyReset := model.IsDailyReset(this.lastResetTime)
  52. //if dailyReset {
  53. // rand.Seed(int64(util.GetTimeMilliseconds()))
  54. //}
  55. //已经离线的玩家处理
  56. for key, offRole := range this.offlineRoleList {
  57. //offRole.Update(ms)
  58. if offRole.IsLogout(ms) {
  59. offRole.Logout()
  60. delete(this.offlineRoleList, key)
  61. delete(this.openRoleList, offRole.GetOpenId())
  62. util.DebugF("Role delete offline=%v uid=%v", key, offRole.GetUUid())
  63. }
  64. }
  65. this.onlineNum = 0
  66. ResetCount = 0
  67. for key, chRole := range this.channelRoleList {
  68. switch chRole.GetState() {
  69. case ROLE_STATE_OFFLINE:
  70. chRole.Update(ms)
  71. delete(this.channelRoleList, key)
  72. delete(this.uuidRoleList, chRole.GetUUid())
  73. //放到离线处理中
  74. this.addOfflineRole(chRole.GetUUid(), chRole)
  75. util.DebugF("Role delete ROLE_STATE_OFFLINE clid=%v uid=%v", key, chRole.GetUUid())
  76. case ROLE_STATE_ZOMBIE:
  77. //需要做删除操作
  78. delete(this.channelRoleList, key)
  79. delete(this.uuidRoleList, chRole.GetUUid())
  80. delete(this.offlineRoleList, chRole.GetUUid())
  81. delete(this.openRoleList, chRole.GetOpenId())
  82. chRole.Logout()
  83. util.DebugF("Role delete ROLE_STATE_ZOMBIE clid=%v uid=%v", key, chRole.GetUUid())
  84. case ROLE_STATE_ONLINE:
  85. chRole.Update(ms)
  86. this.onlineNum++
  87. //每日重置
  88. if dailyResetHour5 {
  89. //设置reset标记,在每个玩家自身的update中处理
  90. //chRole.DailyReset(true)
  91. chRole.SetUpdateDailyReset(ms, true)
  92. //ResetCount++
  93. }
  94. }
  95. }
  96. updateCount++
  97. //if updateCount > 50 {
  98. // updateCount = 0
  99. // //util.InfoF("RoleManager update onlineNum=%v offlineNum=%v", this.onlineNum, len(this.offlineRoleList))
  100. //}
  101. if ResetCount > 0 {
  102. util.InfoF("RoleManager dailyreset online=%v resetnum=%v", this.onlineNum, ResetCount)
  103. }
  104. //12表示1分钟(60表示5分钟)
  105. if this.onlineNum > 0 && updateCount >= 60 {
  106. updateCount = 0
  107. model.ElasticPutLogInfo(&model.ElasticLogST{
  108. LogType: "RoleOnlineNum",
  109. LogDesc: "RoleOnlineNum",
  110. Param1: this.onlineNum,
  111. })
  112. tmpNode := service.GetServiceConfig().Node
  113. //netease log
  114. nLog := &NeteaseLogOnlineRoleNum{
  115. Server: service.GetServiceConfig().Node.Zone*100 + service.GetServiceConfig().Node.Id,
  116. Online: this.onlineNum,
  117. OnLineTime: uint64(util.GetTimeSeconds()),
  118. }
  119. nLog.Log(nil)
  120. //添加到mysql log
  121. logData := &serverproto.SSRoleLogData{
  122. Type: int32(serverproto.MysqlLogType_LType_OnlineNum),
  123. ParamList: []int32{int32(tmpNode.Zone), int32(tmpNode.Id), int32(this.onlineNum)}, //zoneid,subid,onlinenum
  124. }
  125. mysqlOnlineNumNtf := &serverproto.SSRoleLogNtf{}
  126. mysqlOnlineNumNtf.LogList = append(mysqlOnlineNumNtf.LogList, logData)
  127. SendDb(mysqlOnlineNumNtf)
  128. }
  129. if dailyResetHour5 {
  130. this.lastResetTime = ms
  131. }
  132. }
  133. func (this *RoleManager) UpdateWithTimeWheel(ms uint64) {
  134. this.tw.Update(ms)
  135. }
  136. //task tick
  137. func (this *RoleManager) UpdateWithTimeTimeWheelTask(twTask *util.TWTask, ms uint64) {
  138. chRole, ok := this.uuidRoleList[twTask.Uid]
  139. if !ok {
  140. chRole, ok = this.offlineRoleList[twTask.Uid]
  141. if !ok {
  142. util.WarnF("uid=%v UpdateWithTimeTimeWheelTask save but role data not find", twTask.Uid)
  143. return
  144. }
  145. }
  146. chRole.Save()
  147. if chRole.GetState() == ROLE_STATE_ONLINE ||
  148. chRole.GetState() == ROLE_STATE_OFFLINE {
  149. chRole.Save()
  150. }
  151. }
  152. //bool表示给定的cid是否已经存在role, bool是否已经存在
  153. func (this *RoleManager) AddRole(cid model.ClientID, openId string, selectZone int32) (RoleOuter, bool, bool) {
  154. role, ok := this.channelRoleList[cid.SessID]
  155. if ok {
  156. util.WarnF("channel role exist id=", cid)
  157. return role, true, false
  158. }
  159. util.WarnF("AddRole openid=%v", openId)
  160. bHas := false
  161. role, ok = this.openRoleList[openId]
  162. if !ok {
  163. role = NewRole(cid)
  164. } else {
  165. bHas = true
  166. if role.GetSelectZone() != selectZone {
  167. delete(this.channelRoleList, role.CliID().SessID)
  168. delete(this.uuidRoleList, role.GetUUid())
  169. delete(this.openRoleList, openId)
  170. role.SwitchState(ROLE_STATE_ZOMBIE, nil)
  171. role = NewRole(cid)
  172. bHas = false
  173. }
  174. }
  175. this.channelRoleList[cid.SessID] = role
  176. this.openRoleList[openId] = role
  177. return role, false, bHas
  178. }
  179. func (this *RoleManager) AddRoleObj(role RoleOuter) bool {
  180. //if _, ok := this.channelRoleList[role.CliID().SessID]; ok {
  181. // return false
  182. //}
  183. //if _, ok := this.uuidRoleList[role.GetUUid()]; ok {
  184. // return false
  185. //}
  186. if role.GetUUid() == 0 {
  187. util.InfoF("AddRoleObj uid=0")
  188. }
  189. this.channelRoleList[role.CliID().SessID] = role
  190. this.uuidRoleList[role.GetUUid()] = role
  191. return true
  192. }
  193. func (this *RoleManager) RemoveRoleObj(role RoleOuter) bool {
  194. delete(this.channelRoleList, role.CliID().SessID)
  195. delete(this.uuidRoleList, role.GetUUid())
  196. return true
  197. }
  198. func (this *RoleManager) RemoveRoleObjByOpenId(openId string) {
  199. delete(this.openRoleList, openId)
  200. }
  201. //添加到uuid角色列表中
  202. func (this *RoleManager) Resolve(role *Role) {
  203. if role.GetUUid() == 0 {
  204. util.InfoF("AddRoleObj uid=0")
  205. }
  206. if _, ok := this.uuidRoleList[role.GetUUid()]; ok {
  207. //log.Println("channel role exist id:", role.GetUUid())
  208. return
  209. }
  210. this.uuidRoleList[role.GetUUid()] = role
  211. }
  212. func (this *RoleManager) GetRole(cid model.ClientID) RoleOuter {
  213. if role, ok := this.channelRoleList[cid.SessID]; ok {
  214. return role
  215. } else {
  216. if role, ok := this.uuidRoleList[cid.SessID]; ok {
  217. return role
  218. }
  219. }
  220. util.InfoF("role not found id=%v", cid)
  221. return nil
  222. }
  223. func (this *RoleManager) GetRoleOrKick(cid model.ClientID, ev rocommon.ProcEvent) RoleOuter {
  224. role := this.GetRole(cid)
  225. if role == nil {
  226. ev.Session().Send(&serverproto.SSUserKickNtf{
  227. Error: int32(serverproto.ErrorCode_ERROR_OK),
  228. ClientId: cid.SessID,
  229. })
  230. } else if ev.SeqId() > 0 {
  231. //序列号处理
  232. msgInfo := rocommon.MessageInfoByMsg(ev.Msg())
  233. role.ReqAckConfirm(uint32(msgInfo.ID), ev.SeqId())
  234. }
  235. return role
  236. }
  237. func (this *RoleManager) GetRoleFromChannel(id uint64) RoleOuter {
  238. if role, ok := this.channelRoleList[id]; ok {
  239. return role
  240. }
  241. return nil
  242. }
  243. func (this *RoleManager) RemoveRoleFromChannel(id uint64) bool {
  244. delete(this.channelRoleList, id)
  245. return true
  246. }
  247. func (this *RoleManager) RemoveOfflineRole(id uint64) bool {
  248. delete(this.offlineRoleList, id)
  249. return true
  250. }
  251. func (this *RoleManager) GetRoleFromUUid(id uint64) RoleOuter {
  252. if role, ok := this.uuidRoleList[id]; ok {
  253. return role
  254. }
  255. util.InfoF("role not found uid=%v", id)
  256. return nil
  257. }
  258. func (this *RoleManager) GetRoleByOpenId(openId string) RoleOuter {
  259. if role, ok := this.openRoleList[openId]; ok {
  260. return role
  261. }
  262. return nil
  263. }
  264. func (this *RoleManager) GetRoleUUIdList() map[uint64]RoleOuter {
  265. return this.uuidRoleList
  266. }
  267. func (this *RoleManager) GetRoleFromOffline(id uint64) RoleOuter {
  268. if role, ok := this.offlineRoleList[id]; ok {
  269. return role
  270. }
  271. return nil
  272. }
  273. func (this *RoleManager) GetRoleOfflineList() map[uint64]RoleOuter {
  274. return this.offlineRoleList
  275. }
  276. func (this *RoleManager) AddFIFOList(uid uint64) {
  277. if this.playerFifoList.Size() >= 200 {
  278. this.playerFifoList.Pop()
  279. }
  280. if !this.playerFifoList.Has(uid) {
  281. this.playerFifoList.Add(uid)
  282. }
  283. }
  284. func (this *RoleManager) GetFIFOList(idx, num int32, role *Role, exceptUidList map[uint64]struct{}) (bool, []uint64) {
  285. var retUidList []uint64
  286. if role == nil {
  287. return false, retUidList
  288. }
  289. if idx <= 0 {
  290. idx = 1
  291. }
  292. var retSetList = set.New(set.NonThreadSafe)
  293. var count int32 = 0
  294. for _, data := range this.playerFifoList.List() {
  295. count++
  296. tmpUid := data.(uint64)
  297. if tmpUid <= 0 {
  298. continue
  299. }
  300. if count >= idx && num > 0 {
  301. if role.GetRoleSocial().isInSubList(tmpUid) || tmpUid == role.GetUUid() {
  302. continue
  303. }
  304. if _, ok := exceptUidList[tmpUid]; ok {
  305. continue
  306. }
  307. num--
  308. retSetList.Add(data)
  309. retUidList = append(retUidList, tmpUid)
  310. if num <= 0 {
  311. break
  312. }
  313. }
  314. }
  315. if num > 0 {
  316. for _, data := range this.playerFifoList.List() {
  317. tmpUid := data.(uint64)
  318. if tmpUid <= 0 {
  319. continue
  320. }
  321. if role.GetRoleSocial().isInSubList(tmpUid) || tmpUid == role.GetUUid() {
  322. continue
  323. }
  324. if _, ok := exceptUidList[tmpUid]; ok {
  325. continue
  326. }
  327. //表示之前已经遍历过,不需要继续
  328. if retSetList.Has(data) {
  329. break
  330. }
  331. num--
  332. retUidList = append(retUidList, tmpUid)
  333. if num <= 0 {
  334. break
  335. }
  336. }
  337. return false, retUidList
  338. }
  339. return true, retUidList
  340. }
  341. //[sessionId]clientuse channelid
  342. //[serviceID] 所在的网关节点
  343. func (this *RoleManager) KickFromGate(sessionId uint64, serviceID string) {
  344. if tmpRole, ok := this.channelRoleList[sessionId]; ok {
  345. if tmpRole.CliID().SessID == sessionId && tmpRole.GetState() == ROLE_STATE_ONLINE {
  346. util.InfoF("uid=%v KickFromGate sessionId=%v", tmpRole.GetUUid(), sessionId)
  347. tmpRole.SwitchState(ROLE_STATE_OFFLINE, nil)
  348. }
  349. } else {
  350. //服务器重启,客户端没有关闭的情况下会有该错误
  351. //发送CSLoginReq请求到达比断开连接到达要快
  352. util.ErrorF("KickFromGate sessionId=%v err=not find", sessionId)
  353. }
  354. }
  355. func (this *RoleManager) addOfflineRole(uid uint64, role RoleOuter) bool {
  356. if _, ok := this.offlineRoleList[uid]; ok {
  357. return false
  358. }
  359. //清空玩家对应的gate相关信息
  360. role.(*Role).SetCliIDSessionID(0)
  361. this.offlineRoleList[uid] = role
  362. return true
  363. }
  364. func (this *RoleManager) SendMsg2OnlinePlayer(msg interface{}, fromUid uint64) {
  365. var clientIdLIstMap = map[string][]uint64{}
  366. //var clientIdList []uint64
  367. for _, data := range this.uuidRoleList {
  368. if data.GetState() != ROLE_STATE_ONLINE {
  369. continue
  370. }
  371. if fromUid != 0 && data.(*Role).GetRoleSocial().IsInBlackList(fromUid) {
  372. continue
  373. }
  374. serviceId := data.CliID().ServiceID
  375. clientIdLIstMap[serviceId] = append(clientIdLIstMap[serviceId], data.CliID().SessID)
  376. if len(clientIdLIstMap[serviceId]) > 20 {
  377. ReplayGateList(msg, clientIdLIstMap[serviceId], serviceId, true)
  378. clientIdLIstMap[serviceId] = clientIdLIstMap[serviceId][:0]
  379. }
  380. }
  381. for sid, val := range clientIdLIstMap {
  382. if len(val) > 0 {
  383. ReplayGateList(msg, val, sid, true)
  384. }
  385. }
  386. }
  387. func (this *RoleManager) SetGMNoticeInfo(info *serverproto.SSWebGMNoticeNtf) {
  388. this.noticeInfo = info
  389. this.noticeInfo.NoticeTime = uint64(util.GetTimeMilliseconds())
  390. scMsg := &serverproto.SCWebGMNoticeNtf{
  391. NoticeInfo: this.noticeInfo.NoticeInfo,
  392. }
  393. this.SendMsg2OnlinePlayer(scMsg, 0)
  394. }
  395. func (this *RoleManager) NoticeInfoNtf(role *Role) {
  396. if this.noticeInfo == nil {
  397. return
  398. }
  399. //持续一小时
  400. if this.noticeInfo.NoticeTime+uint64(60*60*1000) > util.GetTimeMilliseconds() {
  401. scMsg := &serverproto.SCWebGMNoticeNtf{
  402. NoticeInfo: this.noticeInfo.NoticeInfo,
  403. }
  404. role.ReplayGate(scMsg, true)
  405. }
  406. }
  407. func (this *RoleManager) ServerMaintain(state int32) {
  408. for _, data := range this.uuidRoleList {
  409. if data.GetState() != ROLE_STATE_ONLINE {
  410. continue
  411. }
  412. data.KickWithSave(int32(serverproto.ErrorCode_ERROR_SERVER_MAINTAIN))
  413. }
  414. }
  415. //gate端口后,game上对应role的处理
  416. func (this *RoleManager) GateCloseKickRole(serviceId string) {
  417. for _, chRole := range this.channelRoleList {
  418. if chRole.GetState() == ROLE_STATE_ONLINE && chRole.CliID().ServiceID == serviceId {
  419. chRole.SwitchState(ROLE_STATE_OFFLINE, nil)
  420. util.DebugF("GateCloseKickRole role=%v %v", chRole.GetUUid(), chRole.GetOpenId())
  421. }
  422. }
  423. }
  424. //social通知game当前在线的玩家数量
  425. func (this *RoleManager) PlayerOnlineNumFromSocial(onlineNum int32) {
  426. this.allGameOnlineNum = onlineNum
  427. }
  428. func (this *RoleManager) IsGameOnlineNumLimit() bool {
  429. if this.allGameOnlineNum >= 6000 {
  430. return true
  431. }
  432. return false
  433. }
  434. func (this *RoleManager) SendRushReward(rushType, rushRound int32) {
  435. for _, chRole := range this.channelRoleList {
  436. if chRole.GetState() != ROLE_STATE_ONLINE {
  437. continue
  438. }
  439. if rushType == model.Rush_Type_Tower {
  440. chRole.(*Role).GetRoleTower().GetFightCountMailReward(rushRound)
  441. } else if rushType == model.Rush_Type_Arena {
  442. chRole.(*Role).GetRoleArena().GetFightCountMailReward(rushRound)
  443. } else if rushType == model.Rush_Type_Map {
  444. chRole.(*Role).GetRoleBattle().GetFightCountMailReward(rushRound)
  445. } else if rushType == model.Rush_Type_Pet {
  446. chRole.(*Role).GetRolePet().GetFightCountMailReward(rushRound)
  447. } else if rushType == model.Rush_Type_Skill {
  448. chRole.(*Role).GetRoleRush().GetFightCountMailReward(rushRound)
  449. }
  450. }
  451. }
  452. func (this *RoleManager) GuildBattleBeginNtf(inBattle bool) {
  453. ntfMsg := &serverproto.SCGuildBattleStageNtf{
  454. InGuildBattle: inBattle,
  455. }
  456. for _, chRole := range this.channelRoleList {
  457. if chRole.GetState() != ROLE_STATE_ONLINE {
  458. continue
  459. }
  460. chRole.(*Role).ReplayGate(ntfMsg, true)
  461. }
  462. }
  463. //文件热加载通知操作(调用该方法时文件已经重新加载,转换部分需要这边重新处理)
  464. func (this *RoleManager) ServerReloadConfigNtf(cfgList []string) {
  465. //转换
  466. for _, cfgData := range cfgList {
  467. if cfgData == "CombinedServiceCfg" {
  468. model.ConvertCombinedServer()
  469. this.CombineServerNtf()
  470. }
  471. }
  472. }
  473. func (this *RoleManager) CombineServerNtf() {
  474. ntfMsg := &serverproto.SCCombineServerOnlineNtf{
  475. CombineTime: 0,
  476. }
  477. data, ok := model.ConvertCombineServerData[1]
  478. for _, chRole := range this.channelRoleList {
  479. if chRole.GetState() != ROLE_STATE_ONLINE {
  480. continue
  481. }
  482. if ok {
  483. zoneId := chRole.GetSelectZone()
  484. for _, server := range data.ServerList {
  485. if server.Key <= zoneId && zoneId <= server.Value {
  486. ntfMsg.CombineTime = data.CombineTime
  487. break
  488. }
  489. }
  490. }
  491. chRole.ReplayGate(ntfMsg, true)
  492. }
  493. }