pointmatchinstance.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912
  1. package pointmatch
  2. import (
  3. "bet24.com/log"
  4. "bet24.com/servers/common"
  5. game "bet24.com/servers/micros/game/proto"
  6. "bet24.com/servers/micros/matches/handler/matchbase"
  7. cash "bet24.com/servers/micros/money/proto"
  8. notification "bet24.com/servers/micros/notification/proto"
  9. privateroom "bet24.com/servers/micros/privateroom/proto"
  10. task "bet24.com/servers/micros/task/proto"
  11. robot "bet24.com/servers/micros/userservices/proto"
  12. "encoding/json"
  13. "fmt"
  14. _ "math/rand"
  15. "sort"
  16. "sync"
  17. "time"
  18. )
  19. const match_timeoff_sec = 5
  20. type matchinstance struct {
  21. Owner int
  22. GameId int
  23. GameRule string
  24. TotalUser int
  25. TableUser int
  26. PlayTimeout int
  27. Fee int
  28. Prize int
  29. MatchNo int
  30. StartTime string
  31. startTime int64
  32. endTime int64
  33. Status int
  34. createTime int64
  35. UserList []*matchuser `json:",omitempty"`
  36. EliminateUsers []*matchuser `json:",omitempty"` // 已淘汰玩家
  37. liveRooms []*matchroom // 目前正在进行的私人房间号
  38. lock *sync.RWMutex
  39. RoomHistory []matchbase.RoomHistory
  40. receivers []matchbase.MatchInstanceReceiver
  41. EliminateScore int // 起始淘汰分数
  42. ShrinkSec int // 改变淘汰分数时间
  43. ShrinkScore int // 改变淘汰分数delta
  44. WinnerCount int // 最终剩下多少人赢
  45. config *matchconfig
  46. currentRound int
  47. lastShrink int64 // 上一次缩圈时间
  48. SecToShrink int // 还有多少秒缩圈
  49. lastArrageTime int64
  50. timerArrageUser *time.Timer
  51. }
  52. func newMatchInstance(matchNo, userId int, gameId int,
  53. gameRule string, totalUserCount int,
  54. tableUserCount int, enrollFee int, prize int, playTimeout int,
  55. config *matchconfig, eliminateScore, shringSec, shrinkScore, winnerCount int) *matchinstance {
  56. mi := &matchinstance{
  57. MatchNo: matchNo,
  58. Owner: userId,
  59. GameId: gameId,
  60. GameRule: gameRule,
  61. TotalUser: totalUserCount,
  62. TableUser: tableUserCount,
  63. Fee: enrollFee,
  64. Prize: prize,
  65. createTime: time.Now().Unix(),
  66. lock: &sync.RWMutex{},
  67. Status: matchbase.MatchStatus_Free,
  68. config: config,
  69. PlayTimeout: playTimeout,
  70. EliminateScore: eliminateScore,
  71. ShrinkSec: shringSec,
  72. ShrinkScore: shrinkScore,
  73. WinnerCount: winnerCount,
  74. }
  75. return mi
  76. }
  77. func (mi *matchinstance) getCopy() matchinstance {
  78. var ret matchinstance
  79. d, _ := json.Marshal(mi)
  80. json.Unmarshal(d, &ret)
  81. return ret
  82. }
  83. func (mi *matchinstance) nextRound() {
  84. if mi.Status == matchbase.MatchStatus_Ended {
  85. return
  86. }
  87. mi.currentRound++
  88. mi.EliminateScore += mi.ShrinkScore
  89. mi.lastShrink = time.Now().Unix()
  90. mi.SecToShrink = mi.ShrinkSec
  91. log.Debug("pointmatch matchNo[%d] EliminateScore[%d]", mi.MatchNo, mi.EliminateScore)
  92. // 检查一下是否存在没有玩的玩家并且已达淘汰分数
  93. /*
  94. mi.lock.RLock()
  95. leftUserCount := len(mi.UserList)
  96. mi.lock.RUnlock()
  97. users := mi.getFreeUsers()
  98. flag := false
  99. for _, mu := range users {
  100. if mu.getTotalScore() < mi.EliminateScore && leftUserCount > mi.WinnerCount {
  101. rank := mi.addEleminatedUser(mu.UserId)
  102. postUserEliminationNotification(mu.UserId, mi.MatchNo, rank)
  103. leftUserCount--
  104. flag = true
  105. }
  106. }
  107. // 如果有淘汰,则延迟检查是否结束
  108. if flag && mi.checkRoundEnd() {
  109. return
  110. }
  111. */
  112. time.AfterFunc(time.Second*time.Duration(mi.ShrinkSec), mi.nextRound)
  113. ni := matchbase.Match_notificationInfo{Msg: matchbase.Match_noti_shrink, ShrinkScore: mi.EliminateScore}
  114. d, _ := json.Marshal(ni)
  115. mi.sendNotification(-1, string(d))
  116. }
  117. func (mi *matchinstance) isTimeout(timeoutFree, timeoutPlay, timeoutEnd int64) bool {
  118. if mi.Status == matchbase.MatchStatus_Playing {
  119. return time.Now().Unix()-mi.createTime >= timeoutPlay
  120. } else if mi.Status == matchbase.MatchStatus_Ended {
  121. return time.Now().Unix()-mi.endTime >= timeoutEnd
  122. }
  123. return time.Now().Unix()-mi.createTime >= timeoutFree
  124. }
  125. func (mi *matchinstance) dump() {
  126. log.Release(" MatchNo[%d] Owner[%d] Idled[%d] Rule[%s] TotalUser[%d] TableUser[%d] Fee[%d] Status[%d] Start[%s]",
  127. mi.MatchNo, mi.Owner, mi.getIdle(), mi.GameRule, mi.TotalUser, mi.TableUser, mi.Fee, mi.Status, mi.StartTime)
  128. log.Release(" Round[%d] EliminateScore[%d] ShrinkScore[%d] ShrinkSec[%d] WinnerCount[%d]",
  129. mi.currentRound, mi.EliminateScore, mi.ShrinkScore, mi.ShrinkSec, mi.WinnerCount)
  130. //common.TimeStampToString(mi.StartTime))
  131. mi.lock.RLock()
  132. defer mi.lock.RUnlock()
  133. if len(mi.UserList) > 0 {
  134. log.Release(" UserList:")
  135. for _, v := range mi.UserList {
  136. log.Release(" UserId[%d],NickName[%s],Score[%d],Room[%d],Chair[%d]", v.UserId, v.NickName, v.Score, v.RoomNo, v.ChairId)
  137. }
  138. }
  139. if len(mi.EliminateUsers) > 0 {
  140. log.Release(" EliminateUsers:")
  141. for _, v := range mi.EliminateUsers {
  142. log.Release(" UserId[%d],NickName[%s],Score[%d],Room[%d],Chair[%d]", v.UserId, v.NickName, v.Score, v.RoomNo, v.ChairId)
  143. }
  144. }
  145. if len(mi.liveRooms) > 0 {
  146. log.Release(" liveRooms:")
  147. for _, v := range mi.liveRooms {
  148. v.dump()
  149. }
  150. }
  151. if len(mi.RoomHistory) > 0 {
  152. log.Release(" RoomHistory:")
  153. for _, v := range mi.RoomHistory {
  154. v.Dump()
  155. }
  156. }
  157. }
  158. func (mi *matchinstance) getIdle() int64 {
  159. return time.Now().Unix() - mi.createTime
  160. }
  161. func (mi *matchinstance) getUser(userId int) *matchuser {
  162. mi.lock.RLock()
  163. defer mi.lock.RUnlock()
  164. return mi.getUserWithoutLock(userId)
  165. }
  166. func (mi *matchinstance) getUserWithoutLock(userId int) *matchuser {
  167. for _, v := range mi.UserList {
  168. if v.UserId == userId {
  169. return v
  170. }
  171. }
  172. return nil
  173. }
  174. func (mi *matchinstance) getUserScore(userId int) int {
  175. mu := mi.getUser(userId)
  176. if mu == nil {
  177. return 0
  178. }
  179. return mu.getTotalScore()
  180. }
  181. func (mi *matchinstance) addUser(userId int, nickname string, faceId int, faceUrl string) (ok bool, errMsg string) {
  182. ok = false
  183. errMsg = "ok"
  184. if mi.Status != matchbase.MatchStatus_Free {
  185. errMsg = "Match has Started"
  186. log.Release("matchinstance.addUser[%d] failed %s", userId, errMsg)
  187. return
  188. }
  189. // 已存在?
  190. mu := mi.getUser(userId)
  191. if mu != nil {
  192. ok = true
  193. return
  194. }
  195. if len(mi.UserList) >= mi.TotalUser {
  196. errMsg = "full of users"
  197. log.Release("matchinstance.addUser[%d] failed %s", userId, errMsg)
  198. return
  199. }
  200. // 扣钱
  201. if mi.Fee > 0 && !cash.ReduceMoney(userId, mi.Fee, common.LOGTYPE_POINTMATCH_ENTER, "pointmatch", "enter", "") {
  202. errMsg = fmt.Sprintf("not enough cash[%d] for play", mi.Fee)
  203. log.Release("matchinstance.addUser failed %s", errMsg)
  204. return
  205. }
  206. mi.lock.Lock()
  207. mi.UserList = append(mi.UserList, newMatchUser(userId, nickname, faceId, faceUrl))
  208. mi.lock.Unlock()
  209. ok = true
  210. mi.checkAndStartMatch()
  211. return
  212. }
  213. func (mi *matchinstance) removeUser(userId int) bool {
  214. if mi.Status == matchbase.MatchStatus_Playing {
  215. log.Release("matchinstance.removeUser[%d] failed match playing", userId)
  216. return false
  217. }
  218. idx := -1
  219. mi.lock.RLock()
  220. for i := 0; i < len(mi.UserList); i++ {
  221. if mi.UserList[i].UserId == userId {
  222. idx = i
  223. break
  224. }
  225. }
  226. mi.lock.RUnlock()
  227. if idx == -1 {
  228. log.Release("matchinstance.removeUser[%d] not found", userId)
  229. return false
  230. }
  231. if mi.Fee > 0 && mi.Status == matchbase.MatchStatus_Free {
  232. cash.GiveMoney(userId, mi.Fee, common.LOGTYPE_POINTMATCH_ENTER_RETURN, "pointmatch", "fee return", "")
  233. }
  234. mi.lock.Lock()
  235. mi.UserList = append(mi.UserList[:idx], mi.UserList[idx+1:]...)
  236. mi.lock.Unlock()
  237. return true
  238. }
  239. func (mi *matchinstance) closeByOwner(userId int) (bool, string) {
  240. if userId != mi.Owner {
  241. return false, "Not match owner"
  242. }
  243. if mi.Status >= matchbase.MatchStatus_Playing {
  244. return false, "Match has started"
  245. }
  246. mi.closeMatch("owner close")
  247. return true, "ok"
  248. }
  249. func (mi *matchinstance) closeMatch(reason string) {
  250. isCancelled := false
  251. // 如果有玩家,也退费
  252. if mi.Status < matchbase.MatchStatus_Playing {
  253. mi.lock.RLock()
  254. for _, v := range mi.UserList {
  255. if v == nil {
  256. continue
  257. }
  258. if mi.Fee > 0 {
  259. cash.GiveMoney(v.UserId, mi.Fee, common.LOGTYPE_POINTMATCH_ENTER_RETURN,
  260. "pointmatch", "fee return", "")
  261. }
  262. }
  263. mi.lock.RUnlock()
  264. if mi.Prize > 0 && mi.Owner > 0 {
  265. cash.GiveMoney(mi.Owner, mi.Prize, common.LOGTYPE_POINTMATCH_CREATE_RETURN, "pointmatch", "create return", "")
  266. }
  267. isCancelled = true
  268. }
  269. if mi.Status != matchbase.MatchStatus_Ended {
  270. mi.Status = matchbase.MatchStatus_Ended
  271. if !isCancelled {
  272. mi.postOnMatchEndToReceivers()
  273. } else {
  274. mi.postOnMatchCancelledToReceivers()
  275. }
  276. }
  277. mi.lock.Lock()
  278. mi.UserList = nil
  279. mi.EliminateUsers = nil
  280. mi.lock.Unlock()
  281. }
  282. // 检查比赛开始
  283. func (mi *matchinstance) checkAndStartMatch() {
  284. mi.lock.RLock()
  285. userCount := len(mi.UserList)
  286. mi.lock.RUnlock()
  287. // 第一轮必须人满
  288. if userCount < mi.TotalUser {
  289. return
  290. }
  291. if userCount < mi.TableUser {
  292. log.Release("matchinstance.checkAndStartMatch userCount[%d] < mi.TableUser[%d]", userCount, mi.TableUser)
  293. return
  294. }
  295. // 需要几桌?
  296. tableCount := userCount / mi.TableUser
  297. if tableCount == 0 {
  298. log.Release("matchinstance.checkAndStartMatch tableCount == 0")
  299. mi.dump()
  300. return
  301. }
  302. time.AfterFunc(time.Second*time.Duration(mi.ShrinkSec), mi.nextRound)
  303. // 人满了,可以开始
  304. oldStatus := mi.Status
  305. mi.Status = matchbase.MatchStatus_Playing
  306. // 把报名费给Owner
  307. now := time.Now()
  308. mi.startTime = now.Unix()
  309. mi.StartTime = common.TimeStampToString(mi.startTime)
  310. if mi.Fee > 0 && mi.currentRound == 0 && mi.Owner > 0 {
  311. cash.GiveMoney(mi.Owner, mi.Fee*userCount, common.LOGTYPE_POINTMATCH_OWNER_COLLECT, "pointmatch", "owner", "")
  312. }
  313. if oldStatus != mi.Status {
  314. go postMatchStatusChangedNotificaiton(mi.MatchNo, oldStatus, mi.Status)
  315. }
  316. if oldStatus == matchbase.MatchStatus_Free {
  317. mi.lastShrink = time.Now().Unix()
  318. mi.SecToShrink = mi.ShrinkSec
  319. mi.postOnMatchStartToReceivers()
  320. }
  321. mi.arrangeUsers()
  322. }
  323. func (mi *matchinstance) getFreeUsers() []*matchuser {
  324. var ret []*matchuser
  325. mi.lock.RLock()
  326. for _, v := range mi.UserList {
  327. if mi.isUserFree(v.UserId, v.lastEndTime) {
  328. ret = append(ret, v)
  329. }
  330. }
  331. mi.lock.RUnlock()
  332. return ret
  333. }
  334. func (mi *matchinstance) isUserFree(userId int, lastEndTime int) bool {
  335. for _, v := range mi.liveRooms {
  336. if v.isEnded() {
  337. continue
  338. }
  339. if v.isUserExist(userId) {
  340. return false
  341. }
  342. }
  343. // 判断下最短时间
  344. return int(time.Now().Unix())-lastEndTime >= match_timeoff_sec
  345. }
  346. func (mi *matchinstance) arrangeUsers() {
  347. mi.timerArrageUser = nil
  348. if mi.Status == matchbase.MatchStatus_Ended {
  349. log.Debug("pointmatch.matchinstance.arrangeUsers Ended")
  350. return
  351. }
  352. // 检查一下间隔
  353. now := time.Now().Unix()
  354. if now-mi.lastArrageTime < 2 {
  355. time.AfterFunc(2*time.Second, mi.arrangeUsers)
  356. return
  357. }
  358. mi.lastArrageTime = now
  359. am := createArrangeManager(mi.TableUser)
  360. users := mi.getFreeUsers()
  361. var freeUserIds []int
  362. am.setTotalUserCount(len(mi.UserList))
  363. for _, v := range users {
  364. am.addUser(v.UserId, v.GameCount, "", false)
  365. freeUserIds = append(freeUserIds, v.UserId)
  366. }
  367. log.Debug("pointmatch.matchinstance.arrangeUsers users %v", freeUserIds)
  368. tableUsers := am.checkAndArrange()
  369. tableCount := len(tableUsers)
  370. if tableCount == 0 {
  371. log.Release("pointmatch.matchinstance.arrangeUsers tableCount == 0")
  372. return
  373. }
  374. log.Debug("pointmatch.matchinstance.arrangeUsers arranged %v", tableUsers)
  375. rooms := make([]*matchroom, tableCount)
  376. for i := 0; i < tableCount; i++ {
  377. // 创建私人场
  378. roomNo, err := privateroom.CreatePrivateRoomByUser(mi.Owner, mi.GameId, mi.GameRule, 1, mi.TableUser,
  379. 0, 0, privateroom.RoomType_SimpleMatch, mi.PlayTimeout, false, "")
  380. if roomNo == 0 {
  381. log.Release("matchinstance.arrangeUsers createRoom failed %s", err)
  382. mi.closeMatch("normal end")
  383. return
  384. }
  385. rooms[i] = newMatchRoom(roomNo, mi)
  386. }
  387. // 玩家都分配好了,加入私人场
  388. //mi.lock.RLock()
  389. for r := 0; r < len(rooms); r++ {
  390. for u := 0; u < mi.TableUser; u++ {
  391. usr := mi.getUserWithoutLock(tableUsers[r][u])
  392. if usr == nil {
  393. log.Release("matchinstance.arrangeUsers user [%d] not found", tableUsers[r][u])
  394. return
  395. }
  396. rooms[r].addUser(usr.UserId)
  397. go func(roomIndex int, chairId int) {
  398. var ret struct {
  399. ErrMsg string
  400. ServerAddr string
  401. TableId int
  402. ChairId int
  403. }
  404. retString := privateroom.UserRequestSit(rooms[roomIndex].RoomNo,
  405. usr.UserId, usr.NickName, usr.FaceId, usr.FaceUrl, chairId, usr.Score, usr.BaseScore, usr.GameCount)
  406. if err := json.Unmarshal([]byte(retString), &ret); err != nil {
  407. log.Release("matchinstance.checkAndStartMatch try enter privateroom unmarshal failed %v", err)
  408. return
  409. }
  410. if ret.ServerAddr == "" {
  411. log.Release("matchinstance.checkAndStartMatch try enter privateroom failed %s", ret.ErrMsg)
  412. return
  413. }
  414. log.Debug("%d user[%d] enter room %d chair %d", mi.MatchNo, usr.UserId, rooms[roomIndex].RoomNo, ret.ChairId)
  415. usr.arrangeRoom(rooms[roomIndex].RoomNo, ret.ServerAddr, ret.TableId, ret.ChairId)
  416. go postUserMatchRoomNotification(usr.UserId, mi.MatchNo, ret.ServerAddr, ret.TableId, ret.ChairId)
  417. sec := 10
  418. if robot.IsRobot(usr.UserId) {
  419. sec = 5
  420. }
  421. privateroom.ForceUserEnter(usr.UserId, usr.RoomNo, ret.ChairId, sec)
  422. }(r, u)
  423. }
  424. }
  425. //mi.lock.RUnlock()
  426. mi.lock.Lock()
  427. mi.liveRooms = append(mi.liveRooms, rooms...)
  428. mi.lock.Unlock()
  429. }
  430. func (mi *matchinstance) getRoom(roomNo int) *matchroom {
  431. for _, v := range mi.liveRooms {
  432. if v.RoomNo == roomNo {
  433. return v
  434. }
  435. }
  436. return nil
  437. }
  438. // 比赛进程
  439. func (mi *matchinstance) OnRoomStart(roomNo int) {
  440. mr := mi.getRoom(roomNo)
  441. if mr == nil {
  442. return
  443. }
  444. mr.Status = privateroom.PrivateRoomStatus_Playing
  445. }
  446. func (mi *matchinstance) OnRoomEnd(roomNo int, winners []int) {
  447. mr := mi.getRoom(roomNo)
  448. if mr == nil {
  449. log.Debug("pointmatch.matchinstance.OnRoomEnd[%d] room not found", roomNo)
  450. return
  451. }
  452. if !mr.isValidUsers(winners) {
  453. log.Release("matchinstance[%d].onRoomEnd[%d] winners not exist", mi.MatchNo, roomNo)
  454. return
  455. }
  456. mr.Status = privateroom.PrivateRoomStatus_Ended
  457. var rh matchbase.RoomHistory
  458. rh.RoomNo = roomNo
  459. rh.EndTime = time.Now().Unix()
  460. mi.lock.RLock()
  461. leftUserCount := len(mi.UserList)
  462. mi.lock.RUnlock()
  463. // 发淘汰信息
  464. for _, v := range mr.Users {
  465. mu := mi.getUser(v)
  466. if mu == nil {
  467. continue
  468. }
  469. go task.DoTaskAction(v, task.TaskAction_playmatch, 1, task.TaskScope{GameName: game.GetGameNameByGameId(mi.GameId)})
  470. mu.GameCount++
  471. rh.Users = append(rh.Users, matchbase.RoomHistoryUser{UserId: v, Score: mi.getUserScore(v)})
  472. if mu.getTotalScore() < mi.EliminateScore && leftUserCount > mi.WinnerCount {
  473. rank := mi.addEleminatedUser(v)
  474. postUserEliminationNotification(v, mi.MatchNo, rank)
  475. mi.postOnUserEliminatedToReceivers(v, rank)
  476. leftUserCount--
  477. } else {
  478. mu.clearRoomInfo()
  479. }
  480. if mi.isUserIn(v, winners) {
  481. mu.WinCount++
  482. }
  483. }
  484. mi.RoomHistory = append(mi.RoomHistory, rh)
  485. mi.removeLiveRoom(roomNo)
  486. //mi.arrangeUsers()
  487. // 延迟以下,继续分配
  488. if !mi.checkRoundEnd() && leftUserCount > mi.WinnerCount && mi.timerArrageUser == nil {
  489. mi.timerArrageUser = time.AfterFunc(time.Second*match_timeoff_sec, mi.arrangeUsers)
  490. }
  491. }
  492. func (mi *matchinstance) removeLiveRoom(roomNo int) {
  493. mi.lock.Lock()
  494. defer mi.lock.Unlock()
  495. for i := 0; i < len(mi.liveRooms); i++ {
  496. if mi.liveRooms[i].RoomNo == roomNo {
  497. mi.liveRooms = append(mi.liveRooms[:i], mi.liveRooms[i+1:]...)
  498. return
  499. }
  500. }
  501. log.Release("poingmatch.matchinstance.removeLiveRoom %d not found", roomNo)
  502. }
  503. func (mi *matchinstance) OnRoomUserScoreChanged(roomNo int, userId int, score int) {
  504. mr := mi.getRoom(roomNo)
  505. if mr == nil {
  506. return
  507. }
  508. mu := mi.getUser(userId)
  509. if mu == nil {
  510. log.Release("matchinstance[%d].OnRoomUserScoreChanged[%d] user not exist", mi.MatchNo, userId)
  511. return
  512. }
  513. mu.Score += score
  514. }
  515. func (mi *matchinstance) OnRoomStatusChanged(roomNo int, old, new int) {
  516. }
  517. func (mi *matchinstance) addEleminatedUser(userId int) int {
  518. ret := 0
  519. mu := mi.getUser(userId)
  520. if mu == nil {
  521. return ret
  522. }
  523. mu.clearRoomInfo()
  524. mi.lock.Lock()
  525. //for _, v := range mi.UserList {
  526. for i := 0; i < len(mi.UserList); i++ {
  527. v := mi.UserList[i]
  528. if v.UserId == userId {
  529. mi.EliminateUsers = append(mi.EliminateUsers, v)
  530. v.Rank = len(mi.UserList)
  531. ret = v.Rank
  532. // delete
  533. mi.UserList = append(mi.UserList[:i], mi.UserList[i+1:]...)
  534. }
  535. }
  536. mi.lock.Unlock()
  537. return ret
  538. }
  539. func (mi *matchinstance) checkRoundEnd() bool {
  540. if mi.Status == matchbase.MatchStatus_Ended {
  541. return true
  542. }
  543. // 结束了,把非晋级玩家清理
  544. mi.lock.Lock()
  545. leftUserCount := len(mi.UserList)
  546. mi.lock.Unlock()
  547. if leftUserCount > mi.WinnerCount {
  548. return false
  549. }
  550. // 看下是否所有房间都结束了
  551. for _, v := range mi.liveRooms {
  552. if !v.isEnded() {
  553. return false
  554. }
  555. }
  556. if leftUserCount < mi.WinnerCount {
  557. mi.lock.Lock()
  558. for i := 0; i < mi.WinnerCount-leftUserCount; i++ {
  559. // 把淘汰的人补充进来
  560. if len(mi.EliminateUsers) > 0 {
  561. mi.UserList = append(mi.UserList, mi.EliminateUsers[len(mi.EliminateUsers)-1])
  562. mi.EliminateUsers = mi.EliminateUsers[:len(mi.EliminateUsers)-1]
  563. }
  564. }
  565. mi.lock.Unlock()
  566. }
  567. // 如果人数已经不足开桌,那么比赛就结束了
  568. mi.lock.Lock()
  569. sort.Slice(mi.UserList, func(i, j int) bool {
  570. return mi.UserList[i].getTotalScore() > mi.UserList[j].getTotalScore()
  571. })
  572. for i := 0; i < len(mi.UserList); i++ {
  573. mi.UserList[i].Rank = i + 1
  574. }
  575. mi.lock.Unlock()
  576. mi.onMatchEnded(mi.WinnerCount)
  577. return true
  578. }
  579. func (mi *matchinstance) isUserIn(userId int, userIds []int) bool {
  580. for _, v := range userIds {
  581. if userId == v {
  582. return true
  583. }
  584. }
  585. return false
  586. }
  587. func (mi *matchinstance) onMatchEnded(winnerCount int) {
  588. mi.Status = matchbase.MatchStatus_Ended
  589. mi.endTime = time.Now().Unix()
  590. if winnerCount == 0 {
  591. log.Release("matchinstance.onMatchEnded winnerCount == 0")
  592. return
  593. }
  594. // 给最后的用户发奖金
  595. prize := mi.Prize / winnerCount
  596. tax := prize * getMatchManager().TaxRate / 100
  597. prize -= tax
  598. mi.lock.RLock()
  599. for _, v := range mi.UserList {
  600. if prize > 0 {
  601. cash.ModifyMoneyWithTax(v.UserId, prize, tax, common.LOGTYPE_POINTMATCH_PRIZE, "pointmatch", "prize", "")
  602. }
  603. go task.DoTaskAction(v.UserId, task.TaskAction_matchpromote, 1, task.TaskScope{GameName: game.GetGameNameByGameId(mi.GameId)})
  604. // 发通知
  605. go postUserRankNotification(v.UserId, mi.MatchNo, 1, prize)
  606. }
  607. mi.lock.RUnlock()
  608. getHistoryManager().addHistory(*mi)
  609. mi.postOnMatchEndToReceivers()
  610. }
  611. func (mi *matchinstance) SendNotification(userId int, data string) {
  612. mi.sendNotification(userId, data)
  613. }
  614. func (mi *matchinstance) GetUserList() []int {
  615. var ret []int
  616. mi.lock.RLock()
  617. for _, v := range mi.UserList {
  618. ret = append(ret, v.UserId)
  619. }
  620. mi.lock.RUnlock()
  621. return ret
  622. }
  623. func (mi *matchinstance) sendNotification(userId int, data string) {
  624. if userId == -1 {
  625. // send all
  626. mi.lock.RLock()
  627. for _, v := range mi.UserList {
  628. notification.AddNotification(v.UserId, notification.Notification_Match, data)
  629. }
  630. mi.lock.RUnlock()
  631. return
  632. }
  633. notification.AddNotification(userId, notification.Notification_Match, data)
  634. }
  635. func (mi *matchinstance) setPrizeAndTax(userId int, prize, tax int) {
  636. mi.lock.Lock()
  637. defer mi.lock.Unlock()
  638. for _, v := range mi.UserList {
  639. if v == nil {
  640. continue
  641. }
  642. if v.UserId == userId {
  643. v.tax = tax
  644. v.prize = prize
  645. return
  646. }
  647. }
  648. }
  649. func (mi *matchinstance) getUsersDesc() string {
  650. type userDesc struct {
  651. UserId int
  652. Score int
  653. Prize int
  654. }
  655. var users []userDesc
  656. mi.lock.Lock()
  657. for _, v := range mi.UserList {
  658. if v == nil {
  659. continue
  660. }
  661. users = append(users, userDesc{UserId: v.UserId, Score: v.Score, Prize: v.prize})
  662. }
  663. mi.lock.Unlock()
  664. d, _ := json.Marshal(users)
  665. return string(d)
  666. }
  667. func (mi *matchinstance) getUsersDescForDB() string {
  668. var ret string
  669. mi.lock.Lock()
  670. for _, v := range mi.UserList {
  671. if v == nil {
  672. continue
  673. }
  674. ret = fmt.Sprintf("%s%d,%d,%d,%d;", ret, v.UserId, mi.Fee, v.tax, v.prize)
  675. }
  676. mi.lock.Unlock()
  677. return ret
  678. }
  679. func (mi *matchinstance) getTotalTax() int {
  680. ret := 0
  681. mi.lock.RLock()
  682. defer mi.lock.RUnlock()
  683. for _, v := range mi.UserList {
  684. if v == nil {
  685. continue
  686. }
  687. ret += v.tax
  688. }
  689. return ret
  690. }
  691. // MatchInstance
  692. func (mi *matchinstance) GetStatus() int {
  693. return mi.Status
  694. }
  695. func (mi *matchinstance) IsFull() bool {
  696. mi.lock.RLock()
  697. defer mi.lock.RUnlock()
  698. return len(mi.UserList) == mi.TotalUser
  699. }
  700. func (mi *matchinstance) IsUserEnrolled(userId int) bool {
  701. return mi.getUser(userId) != nil
  702. }
  703. func (mi *matchinstance) RegisterReceiver(receiver matchbase.MatchInstanceReceiver) {
  704. for _, v := range mi.receivers {
  705. if v == receiver {
  706. return
  707. }
  708. }
  709. mi.receivers = append(mi.receivers, receiver)
  710. }
  711. func (mi *matchinstance) GetWinners() []int {
  712. var ret []int
  713. if mi.Status == matchbase.MatchStatus_Ended {
  714. mi.lock.RLock()
  715. for _, v := range mi.UserList {
  716. if v == nil {
  717. continue
  718. }
  719. ret = append(ret, v.UserId)
  720. }
  721. mi.lock.RUnlock()
  722. }
  723. return ret
  724. }
  725. func (mi *matchinstance) postOnMatchEndToReceivers() {
  726. for _, v := range mi.receivers {
  727. v.OnMatchEnd(mi.MatchNo)
  728. }
  729. }
  730. func (mi *matchinstance) postOnMatchStartToReceivers() {
  731. for _, v := range mi.receivers {
  732. v.OnMatchStart(mi.MatchNo)
  733. }
  734. }
  735. func (mi *matchinstance) postOnMatchCancelledToReceivers() {
  736. for _, v := range mi.receivers {
  737. v.OnMatchCancelled(mi.MatchNo)
  738. }
  739. }
  740. func (mi *matchinstance) postOnUserEliminatedToReceivers(userId, rank int) {
  741. for _, v := range mi.receivers {
  742. v.OnUserEliminated(mi.MatchNo, userId, rank)
  743. }
  744. }
  745. func (mi *matchinstance) GetAllMatchUsers() []matchbase.MatchUser {
  746. var ret []matchbase.MatchUser
  747. mi.lock.RLock()
  748. for _, v := range mi.UserList {
  749. ret = append(ret, v.MatchUser)
  750. }
  751. for _, v := range mi.EliminateUsers {
  752. ret = append(ret, v.MatchUser)
  753. }
  754. mi.lock.RUnlock()
  755. return ret
  756. }
  757. func (mi *matchinstance) GetUser(userId int) *matchbase.MatchUser {
  758. ret := mi.getUser(userId)
  759. if ret == nil {
  760. return nil
  761. }
  762. return &ret.MatchUser
  763. }
  764. func (mi *matchinstance) isLastRound() bool {
  765. mi.lock.RLock()
  766. defer mi.lock.RUnlock()
  767. return len(mi.UserList) <= mi.TableUser
  768. }
  769. func (mi *matchinstance) dismiss() {
  770. isCancelled := false
  771. if mi.Status < matchbase.MatchStatus_Ended {
  772. mi.lock.RLock()
  773. for _, v := range mi.UserList {
  774. if v == nil {
  775. continue
  776. }
  777. if mi.Fee > 0 {
  778. cash.GiveMoney(v.UserId, mi.Fee, common.LOGTYPE_POINTMATCH_ENTER_RETURN,
  779. "pointmatch", "fee return", "")
  780. }
  781. }
  782. mi.lock.RUnlock()
  783. if mi.Prize > 0 && mi.Owner > 0 {
  784. cash.GiveMoney(mi.Owner, mi.Prize, common.LOGTYPE_POINTMATCH_CREATE_RETURN, "pointmatch", "create return", "")
  785. }
  786. isCancelled = true
  787. }
  788. mi.Status = matchbase.MatchStatus_Ended
  789. if !isCancelled {
  790. mi.postOnMatchEndToReceivers()
  791. } else {
  792. mi.postOnMatchCancelledToReceivers()
  793. }
  794. mi.lock.Lock()
  795. mi.UserList = nil
  796. mi.EliminateUsers = nil
  797. mi.lock.Unlock()
  798. }
  799. func (mi *matchinstance) resetSecToShrink() {
  800. if mi.Status == matchbase.MatchStatus_Playing {
  801. mi.SecToShrink = mi.ShrinkSec - int(time.Now().Unix()-mi.lastShrink)
  802. } else {
  803. mi.SecToShrink = 0
  804. }
  805. if mi.SecToShrink < 0 {
  806. mi.SecToShrink = 0
  807. }
  808. }