setsmatchinstance.go 22 KB

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