combomatchmanager.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873
  1. package combomatch
  2. import (
  3. "os"
  4. "bet24.com/log"
  5. "bet24.com/servers/common"
  6. //gameHistory "bet24.com/servers/micros/gameHistory/proto"
  7. "encoding/json"
  8. "fmt"
  9. "sort"
  10. "strconv"
  11. "sync"
  12. "time"
  13. inventory "bet24.com/servers/micros/item_inventory/proto"
  14. item "bet24.com/servers/micros/item_inventory/proto"
  15. "bet24.com/servers/micros/matches/handler/matchbase"
  16. "bet24.com/servers/micros/matches/handler/pointmatch"
  17. "bet24.com/servers/micros/matches/handler/setsmatch"
  18. "bet24.com/servers/micros/matches/handler/simplematch"
  19. pb "bet24.com/servers/micros/matches/proto"
  20. platformconfig "bet24.com/servers/micros/platformconfig/proto"
  21. robot "bet24.com/servers/micros/userservices/proto"
  22. user "bet24.com/servers/micros/userservices/proto"
  23. )
  24. const config_key = "combomatch_config"
  25. const refresh_config_sec = 600
  26. const match_time_out_ended = 120
  27. type combomatchMgr struct {
  28. MatchConfigs []*matchconfig
  29. matches map[int][]*matchInfo
  30. lock *sync.RWMutex
  31. lockConfig *sync.RWMutex
  32. lockWating *sync.RWMutex
  33. waitingNextRoundMatches []*matchInfo
  34. lastConfigString string
  35. }
  36. var matchMgr *combomatchMgr
  37. func getMatchManager() *combomatchMgr {
  38. if matchMgr == nil {
  39. matchMgr = new(combomatchMgr)
  40. matchMgr.lock = &sync.RWMutex{}
  41. matchMgr.lockConfig = &sync.RWMutex{}
  42. matchMgr.matches = make(map[int][]*matchInfo)
  43. matchMgr.lockWating = &sync.RWMutex{}
  44. }
  45. return matchMgr
  46. }
  47. func (mm *combomatchMgr) run() {
  48. mm.loadConfig()
  49. go mm.checkTimeout()
  50. }
  51. func (mm *combomatchMgr) loadConfig() {
  52. defer func() {
  53. time.AfterFunc(refresh_config_sec*time.Second, mm.loadConfig)
  54. }()
  55. configString := platformconfig.GetConfig(config_key)
  56. if configString == "" {
  57. data, err := os.ReadFile("serviceconf/combomatch.json")
  58. if err != nil {
  59. log.Release("combomatch.combomatchMgr.loadData read json failed")
  60. return
  61. }
  62. configString = string(data)
  63. platformconfig.SetConfig(config_key, configString)
  64. }
  65. if configString == mm.lastConfigString {
  66. return
  67. }
  68. mm.lastConfigString = configString
  69. var configs []*matchconfig
  70. err := json.Unmarshal([]byte(configString), &configs)
  71. if err != nil {
  72. log.Release("combomatch.combomatchMgr.loadData Unmarshal failed err:%v", err)
  73. return
  74. }
  75. for _, v := range configs {
  76. v.calTotalPrize()
  77. mm.updateConfig(v)
  78. }
  79. // 有比赛删除
  80. mm.checkDeleteConfig(configs)
  81. }
  82. func (mm *combomatchMgr) updateConfig(config *matchconfig) {
  83. mm.lockConfig.Lock()
  84. defer mm.lockConfig.Unlock()
  85. for i := 0; i < len(mm.MatchConfigs); i++ {
  86. v := mm.MatchConfigs[i]
  87. if v.MatchId == config.MatchId {
  88. config.OnlineUser = v.OnlineUser
  89. mm.MatchConfigs[i] = config
  90. return
  91. }
  92. }
  93. // 没有
  94. mm.MatchConfigs = append(mm.MatchConfigs, config)
  95. }
  96. func (mm *combomatchMgr) checkDeleteConfig(configs []*matchconfig) {
  97. var toRemoveMatchIds []int
  98. mm.lockConfig.RLock()
  99. for _, v := range mm.MatchConfigs {
  100. found := false
  101. for _, v1 := range configs {
  102. if v.MatchId == v1.MatchId {
  103. found = true
  104. break
  105. }
  106. }
  107. if !found {
  108. toRemoveMatchIds = append(toRemoveMatchIds, v.MatchId)
  109. }
  110. }
  111. mm.lockConfig.RUnlock()
  112. if len(toRemoveMatchIds) == 0 {
  113. return
  114. }
  115. log.Release("combomatchMgr.checkDeleteConfig %v", toRemoveMatchIds)
  116. mm.lockConfig.Lock()
  117. for _, v := range toRemoveMatchIds {
  118. for i := 0; i < len(mm.MatchConfigs); {
  119. if mm.MatchConfigs[i].MatchId == v {
  120. mm.MatchConfigs = append(mm.MatchConfigs[:i], mm.MatchConfigs[i+1:]...)
  121. } else {
  122. i++
  123. }
  124. }
  125. }
  126. mm.lockConfig.Unlock()
  127. }
  128. func (mm *combomatchMgr) checkTimeout() {
  129. time.AfterFunc(30*time.Second, mm.checkTimeout)
  130. mm.lock.Lock()
  131. for k, v := range mm.matches {
  132. for i := 0; i < len(v); {
  133. if v[i].isTimeout() {
  134. v = append(v[:i], v[i+1:]...)
  135. } else {
  136. i++
  137. }
  138. }
  139. mm.matches[k] = v
  140. }
  141. mm.lock.Unlock()
  142. }
  143. func (mm *combomatchMgr) dump(param1, param2 string) {
  144. log.Release("-------------------------------")
  145. log.Release("combomatch.combomatchMgr.dump[%s,%s]", param1, param2)
  146. defer func() {
  147. log.Release("+++++++++++++++++++++++++++++++")
  148. log.Release("")
  149. }()
  150. if param1 == "config" {
  151. mm.lockConfig.RLock()
  152. defer mm.lockConfig.RUnlock()
  153. for _, v := range mm.MatchConfigs {
  154. v.dump()
  155. }
  156. return
  157. }
  158. if param1 == "history" {
  159. getHistoryManager().dump(param2)
  160. return
  161. }
  162. if param1 == "user" {
  163. userId, err := strconv.Atoi(param2)
  164. if err != nil {
  165. log.Release("invalid param %s", param2)
  166. return
  167. }
  168. ms := mm.getUserMatchId(userId)
  169. for _, v := range ms {
  170. log.Release(" %d,%d,%d", v.MatchId, v.MatchType, v.MatchNo)
  171. }
  172. return
  173. }
  174. if param1 == "dismiss" {
  175. matchNo, err := strconv.Atoi(param2)
  176. if err != nil {
  177. log.Release("invalid param %s", param2)
  178. return
  179. }
  180. mm.dismissMatch(matchNo)
  181. return
  182. }
  183. matchId, _ := strconv.Atoi(param1)
  184. mm.lock.RLock()
  185. for k, v := range mm.matches {
  186. if matchId != 0 && matchId != k {
  187. continue
  188. }
  189. config := mm.getConfig(k)
  190. startInfo := ""
  191. if config != nil && config.RangeTime != nil {
  192. startInfo = fmt.Sprintf("%d", config.RangeTime.Start)
  193. }
  194. log.Release(" MatchId[%d] %s", k, startInfo)
  195. for _, v1 := range v {
  196. v1.dump(matchId != 0)
  197. }
  198. log.Release(" -------------")
  199. }
  200. mm.lock.RUnlock()
  201. }
  202. func (mm *combomatchMgr) dismissMatch(matchNo int) {
  203. mi := mm.getMatchByMatchNo(matchNo)
  204. if mi == nil {
  205. log.Release("combomatchMgr.dismissMatch [%d] not found", matchNo)
  206. return
  207. }
  208. config := mm.getConfig(mi.MatchId)
  209. if config == nil {
  210. log.Release("combomatchMgr.dismissMatch matchId[%d] not found", mi.MatchId)
  211. return
  212. }
  213. if mi.getStatus() == matchbase.MatchStatus_Ended {
  214. log.Release("combomatchMgr.dismissMatch matchId[%d] ended", mi.MatchId)
  215. return
  216. }
  217. userList := mi.getUserList()
  218. for _, v := range userList {
  219. // 退钱
  220. if len(config.EnrollFee) > 0 {
  221. itm := mi.getAndRemoveUserFee(v)
  222. if itm.Count > 0 {
  223. inventory.AddItems(v, []item.ItemPack{itm},
  224. "combomatch fee return", common.LOGTYPE_COMBOMATCH_ENTER_RETURN)
  225. } else if config.DailyFreeCount > 0 {
  226. getFreeCountManager().reduceFreeCount(v, config.MatchId)
  227. }
  228. }
  229. }
  230. switch mi.getCurrentMatchType() {
  231. case matchbase.MatchType_SimpleMatch:
  232. simplematch.DismissMatch(matchNo)
  233. case matchbase.MatchType_PointMatch:
  234. pointmatch.DismissMatch(matchNo)
  235. case matchbase.MatchType_SetsMatch:
  236. setsmatch.DismissMatch(matchNo)
  237. }
  238. }
  239. func (mm *combomatchMgr) enrollComboMatch(matchId int, userId int, nickname string, faceId int, faceUrl string, feeIndex int, isRobot bool) (int, string) {
  240. config := mm.getConfig(matchId)
  241. if config == nil {
  242. log.Release("combomatchMgr.enrollComboMatch matchId[%d] not found", matchId)
  243. return 0, "Wrong MatchId"
  244. }
  245. if !config.IsInTime() {
  246. log.Debug("combomatchMgr.enrollComboMatch matchId[%d] not open", matchId)
  247. return 0, "Not in match time"
  248. }
  249. // 不是预报名的,不能同时报多个
  250. if !config.IsPreEnroll() && mm.isUserPlaying(userId) {
  251. return 0, "Already in a match"
  252. }
  253. mi := mm.getOrCreateMatch(matchId, config)
  254. if mi == nil {
  255. log.Release("combomatchMgr.enrollComboMatch matchId[%d] getOrCreateMatch failed", matchId)
  256. return 0, "Serve error"
  257. }
  258. // 预报名,并且已经到达上线
  259. if !mi.canEnroll() {
  260. return 0, "Quota is full"
  261. }
  262. if feeIndex >= len(config.EnrollFee) {
  263. feeIndex = len(config.EnrollFee) - 1
  264. }
  265. // 如果有免费次数
  266. if config.DailyFreeCount > 0 && getFreeCountManager().getUserFreeCount(userId, config.MatchId) < config.DailyFreeCount {
  267. getFreeCountManager().addFreeCount(userId, config.MatchId)
  268. } else {
  269. // 扣钱
  270. if len(config.EnrollFee) > 0 && !robot.IsRobot(userId) {
  271. ok, err := inventory.Consume(userId, config.EnrollFee[feeIndex].ItemId, common.LOGTYPE_COMBOMATCH_ENTER, config.EnrollFee[feeIndex].Count, 0)
  272. if !ok {
  273. errMsg := fmt.Sprintf("not enough fee[%v] for play err = %s", config.EnrollFee[feeIndex], err)
  274. log.Release("combomatch.enrollComboMatch failed %s", errMsg)
  275. return 0, errMsg
  276. }
  277. mi.setUserFee(userId, config.EnrollFee[feeIndex])
  278. }
  279. }
  280. // 如果是提前报名,则不创建比赛,本地保存
  281. //if config.IsPreEnroll() {
  282. mi.addEnrollUser(userId, nickname, faceId, faceUrl, isRobot)
  283. // 发送通知
  284. //postUserEnterNotification(userId, matchId, nickname, faceId, faceUrl)
  285. ni := ComboMatch_notificationInfo{Msg: ComboMatch_noti_userenter, UserId: userId, MatchId: matchId, FaceId: faceId, FaceUrl: faceUrl, Nickname: nickname}
  286. d, _ := json.Marshal(ni)
  287. mi.sendNotification(-1, string(d))
  288. return 1, "OK"
  289. //}
  290. /*
  291. // 玩家加入
  292. var retCode int
  293. var errMsg string
  294. if mi.isSimpleMatch() {
  295. retCode, errMsg = simplematch.EnrollMatch(userId, nickname, faceId, faceUrl, mi.getMatchNo())
  296. } else {
  297. retCode, errMsg = pointmatch.EnrollMatch(userId, nickname, faceId, faceUrl, mi.getMatchNo())
  298. }
  299. if retCode != 1 {
  300. return 0, errMsg
  301. }
  302. config.addOnline(1)
  303. return mi.getMatchNo(), "OK"
  304. */
  305. }
  306. func (mm *combomatchMgr) quitComboMatch(matchId int, userId int) bool {
  307. config := mm.getConfig(matchId)
  308. if config == nil {
  309. log.Release("combomatchMgr.quitComboMatch matchId[%d] not found", matchId)
  310. return false
  311. }
  312. // 查询我的比赛
  313. mm.lock.RLock()
  314. matches, ok := mm.matches[matchId]
  315. mm.lock.RUnlock()
  316. if !ok || len(matches) == 0 {
  317. log.Release("combomatchMgr.quitComboMatch matchId[%d] no match found", matchId)
  318. return false
  319. }
  320. for _, v := range matches {
  321. //if v.getStatus() == matchbase.MatchStatus_Free && v.isUserEnrolled(userId) {
  322. // 退出当前比赛
  323. if v.isUserEnrolled(userId) {
  324. return v.quitUser(userId, true)
  325. }
  326. }
  327. log.Release("quitComboMatch MatchId[%d] UserId[%d] not in match", matchId, userId)
  328. return false
  329. }
  330. func (mm *combomatchMgr) getConfig(matchId int) *matchconfig {
  331. mm.lockConfig.RLock()
  332. defer mm.lockConfig.RUnlock()
  333. for _, v := range mm.MatchConfigs {
  334. if v.MatchId == matchId {
  335. return v
  336. }
  337. }
  338. return nil
  339. }
  340. func (mm *combomatchMgr) getCurrentMatch(matchId int) *matchInfo {
  341. mm.lock.RLock()
  342. matches, ok := mm.matches[matchId]
  343. mm.lock.RUnlock()
  344. if ok {
  345. for _, v := range matches {
  346. if v.getStatus() == matchbase.MatchStatus_Free && !v.isFull() {
  347. return v
  348. }
  349. }
  350. }
  351. return nil
  352. }
  353. func (mm *combomatchMgr) createMatch(matchId int, config *matchconfig, mi *matchInfo, totalUser int) *matchInfo {
  354. round := 0
  355. if mi != nil {
  356. round = mi.CurrentRound + 1
  357. }
  358. var matchNo int
  359. var matchInstance matchbase.MatchInstance
  360. var err string
  361. // 创建一个比赛,报名期间,先不创建比赛实例,等人满后再创建
  362. if mi != nil {
  363. switch config.getMatchType(round) {
  364. case matchbase.MatchType_SimpleMatch:
  365. matchNo, err = simplematch.CreateMatch(-1, config.GameId, config.GameRule, totalUser, config.getTarget(round),
  366. config.TableUser, 0, 0, config.PlayTime, config.isEleminateByScore(round), config.getWinnerCount(round))
  367. if matchNo == 0 {
  368. log.Release("combomatchMgr.getOrCreateMatch simplematch.CreateMatch failed %s", err)
  369. return nil
  370. }
  371. matchInstance = simplematch.GetMatchInstance(matchNo)
  372. case matchbase.MatchType_PointMatch:
  373. e, ssec, sscore, w := config.getPointMatchParams(round)
  374. matchNo, err = pointmatch.CreateMatch(-1, config.GameId, config.GameRule, totalUser, config.TableUser, 0, 0, config.PlayTime,
  375. e, ssec, sscore, w)
  376. if matchNo == 0 {
  377. log.Release("combomatchMgr.getOrCreateMatch pointmatch.CreateMatch failed %s", err)
  378. return nil
  379. }
  380. matchInstance = pointmatch.GetMatchInstance(matchNo)
  381. case matchbase.MatchType_SetsMatch:
  382. matchNo, err = setsmatch.CreateMatch(-1, config.GameId, config.GameRule, totalUser, config.TableUser,
  383. 0, 0, config.PlayTime, config.getWinnerCount(round))
  384. if matchNo == 0 {
  385. log.Release("combomatchMgr.getOrCreateMatch setsmatch.CreateMatch failed %s", err)
  386. return nil
  387. }
  388. matchInstance = setsmatch.GetMatchInstance(matchNo)
  389. }
  390. if matchInstance == nil {
  391. log.Release("combomatchMgr.getOrCreateMatch GetMatchInstance == nil")
  392. return nil
  393. }
  394. matchInstance.RegisterReceiver(mm)
  395. }
  396. if mi == nil {
  397. mi = newMatchInfo(config.MatchId, mm, config.RobotConfig, config)
  398. } else {
  399. mi.addMatchInfo(matchNo, matchInstance)
  400. }
  401. return mi
  402. }
  403. func (mm *combomatchMgr) getOrCreateMatch(matchId int, config *matchconfig) *matchInfo {
  404. ret := mm.getCurrentMatch(matchId)
  405. if ret != nil {
  406. return ret
  407. }
  408. ret = mm.createMatch(matchId, config, nil, config.TotalUser)
  409. if ret == nil {
  410. return nil
  411. }
  412. mm.lock.Lock()
  413. mm.matches[matchId] = append(mm.matches[matchId], ret)
  414. mm.lock.Unlock()
  415. return ret
  416. }
  417. // MatchInstanceReceiver
  418. func (mm *combomatchMgr) OnMatchStart(matchNo int) {
  419. log.Debug("combomatchMgr.OnMatchStart [%d]", matchNo)
  420. mi := mm.getMatchByMatchNo(matchNo)
  421. if mi == nil {
  422. log.Release("combomatchMgr.OnMatchStart [%d] matchInfo not found", matchNo)
  423. return
  424. }
  425. mi.setStartTime(matchNo)
  426. }
  427. func (mm *combomatchMgr) OnMatchCancelled(matchNo int) {
  428. log.Debug("combomatchMgr.OnMatchCancelled [%d]", matchNo)
  429. mi := mm.getMatchByMatchNo(matchNo)
  430. if mi == nil {
  431. log.Release("combomatchMgr.OnMatchCancelled [%d] matchInfo not found", matchNo)
  432. return
  433. }
  434. config := mm.getConfig(mi.MatchId)
  435. if config == nil {
  436. log.Release("combomatchMgr.OnMatchCancelled [%d] config not found", matchNo)
  437. return
  438. }
  439. var matchInstance matchbase.MatchInstance
  440. switch mi.getCurrentMatchType() {
  441. case matchbase.MatchType_SimpleMatch:
  442. matchInstance = simplematch.GetMatchInstance(matchNo)
  443. case matchbase.MatchType_PointMatch:
  444. matchInstance = pointmatch.GetMatchInstance(matchNo)
  445. case matchbase.MatchType_SetsMatch:
  446. matchInstance = setsmatch.GetMatchInstance(matchNo)
  447. }
  448. if matchInstance == nil {
  449. log.Release("combomatchMgr.OnMatchCancelled [%d] matchInstance not found", matchNo)
  450. return
  451. }
  452. // 退费
  453. userList := matchInstance.GetUserList()
  454. for _, userId := range userList {
  455. // 退钱
  456. if len(config.EnrollFee) > 0 {
  457. itm := mi.getAndRemoveUserFee(userId)
  458. if itm.Count > 0 {
  459. inventory.AddItems(userId, []item.ItemPack{itm},
  460. "combomatch fee return", common.LOGTYPE_COMBOMATCH_ENTER_RETURN)
  461. } else if config.DailyFreeCount > 0 {
  462. getFreeCountManager().reduceFreeCount(userId, config.MatchId)
  463. }
  464. }
  465. }
  466. }
  467. func (mm *combomatchMgr) OnMatchEnd(matchNo int) {
  468. log.Debug("combomatchMgr.OnMatchEnd [%d]", matchNo)
  469. mi := mm.getMatchByMatchNo(matchNo)
  470. if mi == nil {
  471. log.Release("combomatchMgr.OnMatchEnd [%d] matchInfo not found", matchNo)
  472. return
  473. }
  474. mi.setEndTime(matchNo)
  475. config := mm.getConfig(mi.MatchId)
  476. if config == nil {
  477. log.Release("combomatchMgr.OnMatchEnd matchId[%d] not found", mi.MatchId)
  478. return
  479. }
  480. // 找出胜利者给发奖励
  481. var matchInstance matchbase.MatchInstance
  482. switch mi.getCurrentMatchType() {
  483. case matchbase.MatchType_SimpleMatch:
  484. matchInstance = simplematch.GetMatchInstance(matchNo)
  485. case matchbase.MatchType_PointMatch:
  486. matchInstance = pointmatch.GetMatchInstance(matchNo)
  487. case matchbase.MatchType_SetsMatch:
  488. matchInstance = setsmatch.GetMatchInstance(matchNo)
  489. }
  490. if matchInstance == nil {
  491. log.Release("combomatchMgr.OnMatchEnd [%d] matchInstance not found", matchNo)
  492. return
  493. }
  494. winners := matchInstance.GetWinners()
  495. if len(winners) == 0 {
  496. log.Release("combomatchMgr.OnMatchEnd [%d] no winners", matchNo)
  497. return
  498. }
  499. // 把名词更新一下
  500. currentMatchUsers := matchInstance.GetAllMatchUsers()
  501. for _, v := range currentMatchUsers {
  502. mi.updateRankAndScore(v.UserId, v.Rank, v.Score, v.WinCount)
  503. }
  504. if mi.isEnded() {
  505. config.addOnline(-mi.getOnline())
  506. // 加入历史记录
  507. var h combohistory
  508. h.Name = config.Name
  509. h.MatchId = config.MatchId
  510. h.GameId = config.GameId
  511. h.GameName = config.GameName
  512. h.GameRule = config.GameRule
  513. h.Prizes = config.Prizes
  514. h.TableUser = config.TableUser
  515. h.TotalUser = config.TotalUser
  516. h.EnrollFee = config.EnrollFee
  517. //h.matchconfig = *config
  518. for i := 0; i < len(config.Rounds); i++ {
  519. h.Rounds = append(h.Rounds, historyRound{
  520. MatchType: config.Rounds[i].MatchType,
  521. Target: config.Rounds[i].Target,
  522. WinnerCount: config.Rounds[i].WinnerCount,
  523. MatchNo: mi.Rounds[i].MatchNo,
  524. StartTime: mi.Rounds[i].StartTime,
  525. EndTime: mi.Rounds[i].EndTime,
  526. })
  527. }
  528. h.StartTime = mi.getStartTime()
  529. h.EndTime = mi.getEndTime()
  530. h.Winners = winners
  531. enrollUsers := mi.getAllMatchUsers()
  532. for _, v := range enrollUsers {
  533. h.EnrollUsers = append(h.EnrollUsers, historyUser{
  534. MatchUserBrief: *v.ToBrief(),
  535. enrollTime: int(v.EnrollTime),
  536. prize: config.getPrizes(v.Rank),
  537. })
  538. }
  539. // 所有参与人员
  540. sort.Slice(h.EnrollUsers, func(i, j int) bool {
  541. return h.EnrollUsers[i].Rank < h.EnrollUsers[j].Rank
  542. })
  543. for _, v := range h.EnrollUsers {
  544. // 已淘汰用户不再发奖励
  545. if mi.isUserAwarded(v.UserId) {
  546. continue
  547. }
  548. prize := config.getPrizes(v.Rank)
  549. if len(prize) > 0 {
  550. inventory.AddItems(v.UserId, prize, "配置赛奖励", common.LOGTYPE_COMBOMATCH_PRIZE)
  551. log.Debug("OnMatchEnd 发送通知和奖励 [%d] Rank:[%d] %v", v.UserId, v.Rank, prize)
  552. }
  553. mi.postUserRankNotification(v.UserId, v.Rank, prize)
  554. /*gameHistory.MyMatch_Write(v.UserId, &gameHistory.MyMatchInfo{
  555. UserId: v.UserId, //int `json:"UserId, omitempty"` // 用户ID
  556. NickName: v.NickName, //string `json:"NickName, omitempty"` // 昵称
  557. MatchName: config.Name, //string // 比赛名称
  558. Rank: v.Rank, //int // 名次
  559. Items: prize, //int // 道具ID
  560. })*/
  561. mi.setUserAwarded(v.UserId)
  562. }
  563. // 最后把所有报名记录都加上
  564. h.setAllEnrolledUsers(mi.enrolledUsers)
  565. getHistoryManager().addHistory(h)
  566. go writeRoomRecordToDB(&h)
  567. mi.dump(true)
  568. return
  569. }
  570. mi.setRoundWinners(winners)
  571. mm.lockWating.Lock()
  572. mm.waitingNextRoundMatches = append(mm.waitingNextRoundMatches, mi)
  573. mm.lockWating.Unlock()
  574. log.Debug("combomatchMgr.OnMatchEnd match[%d] waiting to enter next round", matchNo)
  575. mi.dump(false)
  576. time.AfterFunc(6*time.Second, mm.enterNextRound)
  577. }
  578. func (mm *combomatchMgr) OnUserEliminated(matchNo int, userId int, rank int) {
  579. log.Debug("combomatchMgr.OnUserEliminated [%d] UserId[%d] Rank[%d]", matchNo, userId, rank)
  580. mi := mm.getMatchByMatchNo(matchNo)
  581. if mi == nil {
  582. log.Release("combomatchMgr.OnUserEliminated [%d] matchInfo not found", matchNo)
  583. return
  584. }
  585. config := mm.getConfig(mi.MatchId)
  586. if config == nil {
  587. log.Release("combomatchMgr.OnUserEliminated matchId[%d] not found", mi.MatchId)
  588. return
  589. }
  590. prize := config.getPrizes(rank)
  591. if len(prize) > 0 {
  592. inventory.AddItems(userId, prize, "配置赛奖励", common.LOGTYPE_COMBOMATCH_PRIZE)
  593. mi.postUserRankNotification(userId, rank, prize)
  594. log.Debug("OnMatchEnd 发送通知和奖励 [%d] %v", userId, prize)
  595. }
  596. mi.setUserAwarded(userId)
  597. /*usr := mi.getUser(userId)
  598. var myInfo gameHistory.MyMatchInfo
  599. myInfo.UserId = userId
  600. myInfo.MatchName = config.Name
  601. myInfo.Rank = rank
  602. myInfo.Items = prize
  603. if usr != nil {
  604. myInfo.NickName = usr.NickName
  605. }
  606. gameHistory.MyMatch_Write(userId, &myInfo)*/
  607. }
  608. func (mm *combomatchMgr) getAWatingNextRoundMatch() *matchInfo {
  609. var ret *matchInfo
  610. mm.lockWating.Lock()
  611. defer mm.lockWating.Unlock()
  612. if len(mm.waitingNextRoundMatches) > 0 {
  613. ret = mm.waitingNextRoundMatches[0]
  614. mm.waitingNextRoundMatches = mm.waitingNextRoundMatches[1:]
  615. }
  616. return ret
  617. }
  618. func (mm *combomatchMgr) enterNextRound() {
  619. mi := mm.getAWatingNextRoundMatch()
  620. if mi == nil {
  621. log.Release("combomatchMgr.enterNextRound no match waiting to next round")
  622. return
  623. }
  624. log.Debug("combomatchMgr.enterNextRound find a wating match [%d]", mi.getMatchNo())
  625. config := mm.getConfig(mi.MatchId)
  626. if config == nil {
  627. log.Release("combomatchMgr.enterNextRound matchId[%d] not found", mi.MatchId)
  628. return
  629. }
  630. // 进行下一轮
  631. newMatch := mm.createMatch(mi.MatchId, config, mi, len(mi.currentRoundWinners))
  632. if newMatch == nil {
  633. log.Release("combomatchMgr.enterNextRound open new match failed")
  634. return
  635. } else {
  636. log.Debug("combomatchMgr.enterNextRound new match [%d] created userCount = %d", newMatch.getMatchNo(), len(mi.currentRoundWinners))
  637. }
  638. for i := 0; i < len(mi.currentRoundWinners); i++ {
  639. var retCode int
  640. var errMsg string
  641. matchUser := &mi.currentRoundWinners[i]
  642. if matchUser == nil {
  643. log.Release("combomatchMgr.enterNextRound winners %v not found", mi.currentRoundWinners[i])
  644. continue
  645. }
  646. switch mi.getCurrentMatchType() {
  647. case matchbase.MatchType_SimpleMatch:
  648. retCode, errMsg = simplematch.EnrollMatchWithInitialScore(matchUser.UserId, matchUser.NickName, matchUser.FaceId, matchUser.FaceUrl, mi.getMatchNo(), matchUser.Score)
  649. case matchbase.MatchType_PointMatch:
  650. retCode, errMsg = pointmatch.EnrollMatch(matchUser.UserId, matchUser.NickName, matchUser.FaceId, matchUser.FaceUrl, mi.getMatchNo())
  651. case matchbase.MatchType_SetsMatch:
  652. retCode, errMsg = setsmatch.EnrollMatch(matchUser.UserId, matchUser.NickName, matchUser.FaceId, matchUser.FaceUrl, mi.getMatchNo())
  653. }
  654. if retCode != 1 {
  655. log.Release("combomatchMgr.enterNextRound enrollMatch failed [%v] [%s]", mi.currentRoundWinners[i], errMsg)
  656. }
  657. }
  658. mi.setRoundWinners([]int{})
  659. }
  660. func (mm *combomatchMgr) getMatchByMatchNo(matchNo int) *matchInfo {
  661. mm.lock.RLock()
  662. defer mm.lock.RUnlock()
  663. for _, v := range mm.matches {
  664. for _, v1 := range v {
  665. if v1.getMatchNo() == matchNo {
  666. return v1
  667. }
  668. }
  669. }
  670. return nil
  671. }
  672. func (mm *combomatchMgr) getMatchList(userId int) string {
  673. var configs []matchconfig
  674. mm.lockConfig.RLock()
  675. for _, v := range mm.MatchConfigs {
  676. configs = append(configs, *v)
  677. }
  678. mm.lockConfig.RUnlock()
  679. for i := 0; i < len(configs); i++ {
  680. configs[i].setLeftFreeCount(userId)
  681. }
  682. d, _ := json.Marshal(configs)
  683. return string(d)
  684. }
  685. func (mm *combomatchMgr) getUserMatchId(userId int) []pb.UserComboMatchId {
  686. var ret []pb.UserComboMatchId
  687. mm.lock.RLock()
  688. defer mm.lock.RUnlock()
  689. for _, v := range mm.matches {
  690. for _, v1 := range v {
  691. if v1.isUserPlaying(userId) {
  692. ret = append(ret, pb.UserComboMatchId{
  693. MatchId: v1.MatchId,
  694. MatchType: v1.getCurrentMatchType(),
  695. MatchNo: v1.getMatchNo(),
  696. SecsToStart: v1.getStartSeconds(),
  697. })
  698. }
  699. }
  700. }
  701. return ret
  702. }
  703. func (mm *combomatchMgr) addARobot(matchId int) int {
  704. m := mm.getCurrentMatch(matchId)
  705. if m == nil {
  706. log.Release("combomatchMgr.addARobot matchId[%d] has no live match", matchId)
  707. return 0
  708. }
  709. // 如果比赛没那么快开始
  710. forceRemove := m.getStartSeconds() > 1800
  711. // 如果没有真人了
  712. if m.tryRemoveOneRobot(forceRemove) {
  713. return -1
  714. }
  715. if forceRemove {
  716. return 0
  717. }
  718. loopCount := 0
  719. for {
  720. loopCount++
  721. if loopCount > 20 {
  722. log.Release("combomatchMgr.addARobot matchId[%d] get a robot failed", matchId)
  723. return 0
  724. }
  725. robotId := robot.GetARobot()
  726. if mm.isUserPlaying(robotId) {
  727. continue
  728. }
  729. usr := user.GetUserInfo(robotId)
  730. if usr == nil {
  731. continue
  732. }
  733. mm.enrollComboMatch(matchId, robotId, usr.NickName, usr.FaceId, usr.FaceUrl, 0, true)
  734. break
  735. }
  736. return 1
  737. }
  738. func (mm *combomatchMgr) isUserPlaying(robotId int) bool {
  739. mm.lock.RLock()
  740. defer mm.lock.RUnlock()
  741. for _, m := range mm.matches {
  742. for _, mi := range m {
  743. if mi.isUserPlaying(robotId) {
  744. return true
  745. }
  746. }
  747. }
  748. return false
  749. }
  750. func (mm *combomatchMgr) getUserMatchInfo(matchId int, userId int) string {
  751. var mi *matchInfo
  752. mm.lock.RLock()
  753. matches, ok := mm.matches[matchId]
  754. mm.lock.RUnlock()
  755. if !ok {
  756. log.Debug("combomatchMgr.getUserMatchInfo matchId[%d] has no match instance", matchId)
  757. return ""
  758. }
  759. for _, v := range matches {
  760. if v.isUserPlaying(userId) {
  761. mi = v
  762. break
  763. }
  764. }
  765. if mi == nil {
  766. //log.Debug("combomatchMgr.getMatchInfo matchId[%d] userId[%d] has no match enrolled", matchId, userId)
  767. return ""
  768. }
  769. return mi.getMatchInfo()
  770. }
  771. func (mm *combomatchMgr) getConfirmCount(matchId int) int {
  772. mi := mm.getCurrentMatch(matchId)
  773. if mi == nil {
  774. //log.Release("combomatchMgr.getConfirmCount [%d] not found", matchId)
  775. return 0
  776. }
  777. return mi.getConfirmCount()
  778. }
  779. func (mm *combomatchMgr) confirmMatch(matchId int, userId int) bool {
  780. mi := mm.getCurrentMatch(matchId)
  781. if mi == nil {
  782. log.Release("combomatchMgr.confirmMatch [%d] not found", matchId)
  783. return false
  784. }
  785. return mi.confirmMatch(userId)
  786. }