matchinstance.go 25 KB

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