| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997 |
- package simplematch
- import (
- "bet24.com/log"
- "bet24.com/servers/common"
- game "bet24.com/servers/micros/game/proto"
- "bet24.com/servers/micros/matches/handler/matchbase"
- cash "bet24.com/servers/micros/money/proto"
- notification "bet24.com/servers/micros/notification/proto"
- privateroom "bet24.com/servers/micros/privateroom/proto"
- task "bet24.com/servers/micros/task/proto"
- robot "bet24.com/servers/micros/userservices/proto"
- "encoding/json"
- "fmt"
- "math/rand"
- "sort"
- "sync"
- "time"
- )
- type matchinstance struct {
- Owner int
- GameId int
- GameRule string
- TotalUser int
- Target int
- TableUser int
- PlayTimeout int
- Fee int
- Prize int
- MatchNo int
- CurrentRound int // 当前轮次
- StartTime string
- startTime int64
- Status int
- createTime int64
- UserList []*matchuser `json:",omitempty"`
- EliminateUsers []*matchuser `json:",omitempty"` // 已淘汰玩家
- promotedUsers []int // 本轮晋级玩家
- liveRooms []*matchroom // 目前正在进行的私人房间号
- lock *sync.RWMutex
- RoomHistory []matchbase.RoomHistory
- receivers []matchbase.MatchInstanceReceiver
- eleminateByScore bool
- config *matchconfig
- WinnerCount int
- lockRoomEnd *sync.RWMutex
- }
- func newMatchInstance(matchNo, userId int, gameId int,
- gameRule string, totalUserCount int, target int,
- tableUserCount int, enrollFee int, prize int, playTimeout int,
- config *matchconfig, eleminateByScore bool, winnerCount int) *matchinstance {
- mi := &matchinstance{
- MatchNo: matchNo,
- Owner: userId,
- GameId: gameId,
- GameRule: gameRule,
- TotalUser: totalUserCount,
- Target: target,
- TableUser: tableUserCount,
- Fee: enrollFee,
- Prize: prize,
- createTime: time.Now().Unix(),
- lock: &sync.RWMutex{},
- lockRoomEnd: &sync.RWMutex{},
- Status: matchbase.MatchStatus_Free,
- config: config,
- PlayTimeout: playTimeout,
- eleminateByScore: eleminateByScore,
- WinnerCount: winnerCount,
- }
- return mi
- }
- func (mi *matchinstance) isTimeout(timeoutFree, timeoutPlay, timeoutEnd int64) bool {
- if mi.Status == matchbase.MatchStatus_Playing {
- return time.Now().Unix()-mi.createTime >= timeoutPlay
- } else if mi.Status == matchbase.MatchStatus_Ended {
- return time.Now().Unix()-mi.createTime >= timeoutEnd
- }
- return time.Now().Unix()-mi.createTime >= timeoutFree
- }
- func (mi *matchinstance) dump() {
- log.Release(" MatchNo[%d] Owner[%d] Idled[%d] Rule[%s] TotalUser[%d] TableUser[%d] Fee[%d] Status[%d] Start[%s]",
- mi.MatchNo, mi.Owner, mi.getIdle(), mi.GameRule, mi.TotalUser, mi.TableUser, mi.Fee, mi.Status, mi.StartTime)
- //common.TimeStampToString(mi.StartTime))
- mi.lock.RLock()
- defer mi.lock.RUnlock()
- if len(mi.UserList) > 0 {
- log.Release(" UserList:")
- for _, v := range mi.UserList {
- log.Release(" UserId[%d],NickName[%s],Score[%d],Room[%d],Chair[%d],Team[%d]",
- v.UserId, v.NickName, v.Score, v.RoomNo, v.ChairId, v.teamId)
- }
- }
- if len(mi.EliminateUsers) > 0 {
- log.Release(" EliminateUsers:")
- for _, v := range mi.EliminateUsers {
- log.Release(" UserId[%d],NickName[%s],Score[%d],Room[%d],Chair[%d],Team[%d]",
- v.UserId, v.NickName, v.Score, v.RoomNo, v.ChairId, v.teamId)
- }
- }
- if len(mi.liveRooms) > 0 {
- log.Release(" liveRooms:")
- for _, v := range mi.liveRooms {
- v.dump()
- }
- }
- if len(mi.RoomHistory) > 0 {
- log.Release(" RoomHistory:")
- for _, v := range mi.RoomHistory {
- v.Dump()
- }
- }
- }
- func (mi *matchinstance) getIdle() int64 {
- return time.Now().Unix() - mi.createTime
- }
- func (mi *matchinstance) getCopy() matchinstance {
- var ret matchinstance
- d, _ := json.Marshal(mi)
- json.Unmarshal(d, &ret)
- return ret
- }
- func (mi *matchinstance) getUser(userId int) *matchuser {
- mi.lock.RLock()
- defer mi.lock.RUnlock()
- for _, v := range mi.UserList {
- if v.UserId == userId {
- return v
- }
- }
- return nil
- }
- func (mi *matchinstance) getUserScore(userId int) int {
- mu := mi.getUser(userId)
- if mu == nil {
- return 0
- }
- return mu.Score
- }
- func (mi *matchinstance) addUser(userId int, nickname string, faceId int, faceUrl string, score int) (ok bool, errMsg string) {
- ok = false
- errMsg = "ok"
- if mi.Status != matchbase.MatchStatus_Free {
- errMsg = "Match has Started"
- log.Release("matchinstance.addUser[%d] failed %s", userId, errMsg)
- return
- }
- // 已存在?
- mu := mi.getUser(userId)
- if mu != nil {
- ok = true
- return
- }
- if len(mi.UserList) >= mi.TotalUser {
- errMsg = "full of users"
- log.Release("matchinstance.addUser[%d] failed %s", userId, errMsg)
- return
- }
- // 扣钱
- if mi.Fee > 0 && !cash.ReduceMoney(userId, mi.Fee, common.LOGTYPE_SIMPLEMATCH_ENTER, "simplematch", "enter", "") {
- errMsg = fmt.Sprintf("not enough cash[%d] for play", mi.Fee)
- log.Release("matchinstance.addUser failed %s", errMsg)
- return
- }
- mi.lock.Lock()
- mi.UserList = append(mi.UserList, newMatchUser(userId, nickname, faceId, faceUrl, score, mi.config.BaseScore))
- mi.lock.Unlock()
- ok = true
- mi.checkAndStartRound()
- return
- }
- func (mi *matchinstance) removeUser(userId int) bool {
- if mi.Status == matchbase.MatchStatus_Playing {
- log.Release("matchinstance.removeUser[%d] failed match playing", userId)
- return false
- }
- idx := -1
- mi.lock.RLock()
- for i := 0; i < len(mi.UserList); i++ {
- if mi.UserList[i].UserId == userId {
- idx = i
- break
- }
- }
- mi.lock.RUnlock()
- if idx == -1 {
- log.Release("matchinstance.removeUser[%d] not found", userId)
- return false
- }
- if mi.Fee > 0 && mi.Status == matchbase.MatchStatus_Free {
-
- }
- mi.lock.Lock()
- mi.UserList = append(mi.UserList[:idx], mi.UserList[idx+1:]...)
- mi.lock.Unlock()
- return true
- }
- func (mi *matchinstance) closeByOwner(userId int) (bool, string) {
- if userId != mi.Owner {
- return false, "Not match owner"
- }
- if mi.Status >= matchbase.MatchStatus_Playing {
- return false, "Match has started"
- }
- mi.closeMatch("owner close")
- return true, "ok"
- }
- func (mi *matchinstance) closeMatch(reason string) {
- isCancelled := false
- // 如果有玩家,也退费
- if mi.Status < matchbase.MatchStatus_Playing {
- mi.lock.RLock()
- for _, v := range mi.UserList {
- if v == nil {
- continue
- }
- if mi.Fee > 0 {
- cash.GiveMoney(v.UserId, mi.Fee, common.LOGTYPE_SIMPLEMATCH_ENTER_RETURN,
- "simplematch", "fee return", "")
- }
- }
- mi.lock.RUnlock()
- if mi.Prize > 0 && mi.Owner > 0 {
- cash.GiveMoney(mi.Owner, mi.Prize, common.LOGTYPE_SIMPLEMATCH_CREATE_RETURN, "simplematch", "create return", "")
- }
- isCancelled = true
- }
- if mi.Status != matchbase.MatchStatus_Ended {
- mi.Status = matchbase.MatchStatus_Ended
- if !isCancelled {
- mi.postOnMatchEndToReceivers()
- } else {
- mi.postOnMatchCancelledToReceivers()
- }
- }
- mi.lock.Lock()
- mi.UserList = nil
- mi.EliminateUsers = nil
- mi.lock.Unlock()
- }
- func (mi *matchinstance) dismiss() {
- isCancelled := false
- if mi.Status < matchbase.MatchStatus_Ended {
- mi.lock.RLock()
- for _, v := range mi.UserList {
- if v == nil {
- continue
- }
- if mi.Fee > 0 {
- cash.GiveMoney(v.UserId, mi.Fee, common.LOGTYPE_SIMPLEMATCH_ENTER_RETURN,
- "simplematch", "fee return", "")
- }
- }
- mi.lock.RUnlock()
- if mi.Prize > 0 && mi.Owner > 0 {
- cash.GiveMoney(mi.Owner, mi.Prize, common.LOGTYPE_SIMPLEMATCH_CREATE_RETURN, "simplematch", "create return", "")
- }
- isCancelled = true
- }
- if mi.Status != matchbase.MatchStatus_Ended {
- mi.Status = matchbase.MatchStatus_Ended
- if !isCancelled {
- mi.postOnMatchEndToReceivers()
- } else {
- mi.postOnMatchCancelledToReceivers()
- }
- }
- mi.lock.Lock()
- mi.UserList = nil
- mi.EliminateUsers = nil
- mi.lock.Unlock()
- }
- func (mi *matchinstance) setUserRanks() []int {
- // 不是比分淘汰不排名
- if !mi.isEleminateByScore() {
- return []int{}
- }
- mi.lock.RLock()
- userlist := make([]*matchuser, len(mi.UserList))
- for i := 0; i < len(mi.UserList); i++ {
- userlist[i] = mi.UserList[i]
- }
- mi.lock.RUnlock()
- if len(userlist) == 0 {
- return []int{}
- }
- sort.Slice(userlist, func(i, j int) bool {
- return userlist[i].IsBetterThan(&userlist[j].MatchUser)
- })
- ret := make([]int, len(userlist))
- for i := 0; i < len(userlist); i++ {
- userlist[i].Rank = i + 1
- ret[i] = userlist[i].UserId
- }
- /*
- log.Debug("simplematch.matchinstance.setUserRanks")
- for i := 0; i < len(userlist); i++ {
- log.Debug(" Rank %d: %d score %d", userlist[i].Rank, userlist[i].UserId, userlist[i].Score)
- }*/
- return ret
- }
- // 检查比赛开始
- func (mi *matchinstance) checkAndStartRound() {
- mi.lock.RLock()
- userCount := len(mi.UserList)
- mi.lock.RUnlock()
- // 第一轮必须人满
- if userCount < mi.TotalUser && mi.CurrentRound == 0 {
- return
- }
- if userCount < mi.TableUser {
- log.Release("matchinstance.checkAndStartRound userCount[%d] < mi.TableUser[%d]", userCount, mi.TableUser)
- return
- }
- // 不是第一轮,所有房间都结束
- if mi.CurrentRound > 0 {
- for _, v := range mi.liveRooms {
- if v == nil {
- continue
- }
- if !v.isEnded() {
- return
- }
- }
- }
- // 需要几桌?
- tableCount := userCount / mi.TableUser
- if tableCount == 0 {
- log.Release("matchinstance.checkAndStartRound tableCount == 0")
- mi.dump()
- return
- }
- // 用户排名
- mi.setUserRanks()
- // 清理本轮晋级玩家
- mi.promotedUsers = []int{}
- // 先创建出来
- mi.liveRooms = make([]*matchroom, tableCount)
- var rooms []int
- for i := 0; i < tableCount; i++ {
- roomNo, err := privateroom.CreatePrivateRoomByUser(mi.Owner, mi.GameId, mi.GameRule, mi.Target, mi.TableUser,
- 0, 0, privateroom.RoomType_SimpleMatch, mi.PlayTimeout, false, "")
- if roomNo == 0 {
- log.Release("checkAndStartRound createRoom failed %s", err)
- mi.closeMatch("normal end")
- return
- }
- mi.liveRooms[i] = newMatchRoom(roomNo, mi)
- // 注册私人场事件
- //go privateroom.RegisterRoomStatus(mi, roomNo)
- rooms = append(rooms, roomNo)
- }
- log.Release("matchinstance.checkAndStartRound [%d] rooms%v have been created", mi.MatchNo, rooms)
- // 人满了,可以开始
- oldStatus := mi.Status
- mi.Status = matchbase.MatchStatus_Playing
- // 把报名费给Owner
- now := time.Now()
- mi.startTime = now.Unix()
- mi.StartTime = common.TimeStampToString(mi.startTime)
- if mi.Fee > 0 && mi.CurrentRound == 0 && mi.Owner > 0 {
- cash.GiveMoney(mi.Owner, mi.Fee*userCount, common.LOGTYPE_SIMPLEMATCH_OWNER_COLLECT, "simplematch", "owner", "")
- }
- if oldStatus != mi.Status {
- mi.postMatchStatusChangedNotificaiton(oldStatus, mi.Status)
- }
- if oldStatus == matchbase.MatchStatus_Free {
- mi.postOnMatchStartToReceivers()
- }
- // 把玩家随机分配到各个房间去
- userIdx := make([]int, userCount)
- // 是否需要组队?
- teamMatch := false
- if mi.config.TeamGame && mi.CurrentRound > 0 {
- for {
- teamCount := mi.TableUser / 2
- teamUsers := make(map[int][]int)
- for _, v := range mi.UserList {
- teamUsers[v.teamId] = append(teamUsers[v.teamId], v.UserId)
- }
- var teamIds []int
- for k, v := range teamUsers {
- teamIds = append(teamIds, k)
- if len(v) != teamCount {
- log.Release("matchinstance.checkAndStartRound teamIds[%d]:%v + teamCount=%d", k, v, teamCount)
- break
- }
- }
- if len(teamIds) != tableCount/teamCount {
- log.Release("matchinstance.checkAndStartRound teamIds%v tableCount=%d", teamIds, tableCount)
- break
- }
- // 随机打乱tameIds
- for i := len(teamIds) - 1; i > 1; i-- {
- pos := rand.Intn(i)
- teamIds[pos], teamIds[i] = teamIds[i], teamIds[pos]
- }
- for _, teamId := range teamIds {
- for _, uid := range teamUsers[teamId] {
- userIdx = append(userIdx, uid)
- }
- }
- teamMatch = true
- break
- }
- }
- if !teamMatch {
- for i := 0; i < len(mi.UserList); i++ {
- userIdx[i] = i
- }
- // 打乱
- for i := userCount - 1; i > 1; i-- {
- pos := rand.Intn(i)
- userIdx[pos], userIdx[i] = userIdx[i], userIdx[pos]
- }
- }
- // 玩家都分配好了,加入私人场
- mi.lock.RLock()
- for r := 0; r < len(mi.liveRooms); r++ {
- for u := 0; u < mi.TableUser; u++ {
- usr := mi.UserList[userIdx[r*mi.TableUser+u]]
- // 根据第一轮的情况组队
- if mi.config.TeamGame && mi.CurrentRound == 0 {
- usr.teamId = 1 + r*2 + u/2
- }
- mi.liveRooms[r].addUser(usr.UserId)
- toChairId := u
- if u == 1 {
- toChairId = 2
- } else if toChairId == 2 {
- toChairId = 1
- }
- go func(roomIndex int, chairId int) {
- var ret struct {
- ErrMsg string
- ServerAddr string
- TableId int
- ChairId int
- }
- retString := privateroom.UserRequestSit(mi.liveRooms[roomIndex].RoomNo,
- usr.UserId, usr.NickName, usr.FaceId, usr.FaceUrl, chairId, usr.Score, usr.BaseScore, usr.GameCount)
- if err := json.Unmarshal([]byte(retString), &ret); err != nil {
- log.Release("matchinstance.checkAndStartRound try enter privateroom unmarshal failed %v", err)
- return
- }
- if ret.ServerAddr == "" {
- log.Release("matchinstance.checkAndStartRound try enter privateroom failed %s", ret.ErrMsg)
- return
- }
- log.Debug("matchinstance.checkAndStartRound MatchId[%d] user[%d] enter room %d chair %d", mi.MatchNo, usr.UserId, mi.liveRooms[roomIndex].RoomNo, ret.ChairId)
- usr.arrangeRoom(mi.liveRooms[roomIndex].RoomNo, ret.ServerAddr, ret.TableId, ret.ChairId)
- go mi.postUserMatchRoomNotification(usr.UserId, ret.ServerAddr, ret.TableId, ret.ChairId)
- sec := 60
- if robot.IsRobot(usr.UserId) {
- sec = 5
- }
- privateroom.ForceUserEnter(usr.UserId, usr.RoomNo, ret.ChairId, sec)
- }(r, toChairId)
- }
- }
- mi.lock.RUnlock()
- }
- func (mi *matchinstance) getRoom(roomNo int) *matchroom {
- for _, v := range mi.liveRooms {
- if v == nil {
- log.Release("matchinstance[%d].getRoom [%d] v == nil", mi.MatchNo, roomNo)
- continue
- }
- if v.RoomNo == roomNo {
- return v
- }
- }
- // log.Release("matchinstance[%d].getRoom [%d] not found", mi.MatchNo, roomNo)
- return nil
- }
- // 比赛进程
- func (mi *matchinstance) OnRoomStart(roomNo int) {
- if mi == nil {
- log.Release("simplematch.matchinstance.OnRoomStart mi == nil")
- return
- }
- mr := mi.getRoom(roomNo)
- if mr == nil {
- return
- }
- log.Debug("simplematch.OnRoomStart %d ", roomNo)
- mr.Status = privateroom.PrivateRoomStatus_Playing
- }
- func (mi *matchinstance) onRoomEndEleminateByScore() {
- // 重置排名
- rankedUserIds := mi.setUserRanks()
- // 名次重排后,广播给所有人
- //if room != nil {
- mi.lock.RLock()
- for _, v := range mi.UserList {
- go func(userId, rank int) {
- ni := matchbase.Match_notificationInfo{Msg: matchbase.Match_noti_rank_changed, Rank: rank}
- d, _ := json.Marshal(ni)
- mi.sendNotification(userId, string(d))
- }(v.UserId, v.Rank)
- }
- mi.lock.RUnlock()
- //}
- // 看下是否所有房间都结束了
- for _, v := range mi.liveRooms {
- if !v.isEnded() {
- return
- }
- }
- // 一半的人淘汰
- lastRound := mi.isLastRound()
- winnerCount := len(rankedUserIds) / 2
- if lastRound && mi.WinnerCount != 0 {
- winnerCount = mi.WinnerCount
- }
- //for _, v := range winners {
- for i := 0; i < len(rankedUserIds); i++ {
- v := rankedUserIds[i]
- if lastRound {
- go task.DoTaskAction(v, task.TaskAction_matchfinal, 1, task.TaskScope{GameName: game.GetGameNameByGameId(mi.GameId)})
- }
- // 完成一局比赛
- go task.DoTaskAction(v, task.TaskAction_playmatch, 1, task.TaskScope{GameName: game.GetGameNameByGameId(mi.GameId)})
- if i < winnerCount {
- if lastRound {
- go task.DoTaskAction(v, task.TaskAction_matchchampion, 1, task.TaskScope{GameName: game.GetGameNameByGameId(mi.GameId)})
- }
- mi.addPromotedUser(v)
- mi.postUserRankNotification(v, i+1, 0)
- } else {
- rank := mi.addEleminatedUser(v, i+1)
- if lastRound {
- mi.postUserRankNotification(v, rank, 0)
- } else {
- mi.postUserEliminationNotification(v, rank)
- mi.postOnUserEliminatedToReceivers(v, rank)
- }
- }
- }
- // 继续下一轮
- mi.checkRoundEnd()
- }
- func (mi *matchinstance) OnRoomEnd(roomNo int, winners []int) {
- mr := mi.getRoom(roomNo)
- if mr == nil {
- return
- }
- log.Debug("simplematch.OnRoomEnd %d winners %v", roomNo, winners)
- if !mr.isValidUsers(winners) {
- log.Release("matchinstance[%d].onRoomEnd[%d] winners not exist", mi.MatchNo, roomNo)
- return
- }
- // 如果同时触发OnRoomEnd,则流程会异常
- mi.lockRoomEnd.Lock()
- defer mi.lockRoomEnd.Unlock()
- mr.Status = privateroom.PrivateRoomStatus_Ended
- mr.setWinners(winners)
- var rh matchbase.RoomHistory
- rh.RoomNo = roomNo
- rh.EndTime = time.Now().Unix()
- // 如果是积分淘汰制,则需要等所有人结束才能淘汰
- if mi.isEleminateByScore() {
- // 先加入历史记录
- for _, v := range mr.Users {
- mu := mi.getUser(v)
- if mu == nil {
- continue
- }
- if mi.isUserIn(v, winners) {
- mu.WinCount++
- }
- mu.clearRoomInfo()
- rh.Users = append(rh.Users, matchbase.RoomHistoryUser{UserId: v, Score: mi.getUserScore(v), IsPromote: false})
- }
- mi.RoomHistory = append(mi.RoomHistory, rh)
- mi.onRoomEndEleminateByScore()
- return
- }
- lastRound := mi.isLastRound()
- for _, v := range winners {
- if lastRound {
- go task.DoTaskAction(v, task.TaskAction_matchchampion, 1, task.TaskScope{GameName: game.GetGameNameByGameId(mi.GameId)})
- }
- mi.addPromotedUser(v)
- rh.Users = append(rh.Users, matchbase.RoomHistoryUser{UserId: v, Score: mi.getUserScore(v), IsPromote: true})
- }
- // 发淘汰信息
- for _, v := range mr.Users {
- if lastRound {
- go task.DoTaskAction(v, task.TaskAction_matchfinal, 1, task.TaskScope{GameName: game.GetGameNameByGameId(mi.GameId)})
- }
- // 完成一局比赛
- go task.DoTaskAction(v, task.TaskAction_playmatch, 1, task.TaskScope{GameName: game.GetGameNameByGameId(mi.GameId)})
- if !mi.isUserIn(v, winners) {
- rh.Users = append(rh.Users, matchbase.RoomHistoryUser{UserId: v, Score: mi.getUserScore(v), IsPromote: false})
- rank := mi.addEleminatedUser(v, 0)
- if lastRound {
- mi.postUserRankNotification(v, rank, 0)
- } else {
- mi.postUserEliminationNotification(v, rank)
- mi.postOnUserEliminatedToReceivers(v, rank)
- }
- }
- }
- mi.RoomHistory = append(mi.RoomHistory, rh)
- mi.checkRoundEnd()
- }
- func (mi *matchinstance) OnRoomUserScoreChanged(roomNo int, userId int, score int) {
- mr := mi.getRoom(roomNo)
- if mr == nil {
- //log.Release("matchinstance[%d].OnRoomUserScoreChanged[%d] room not exist", mi.MatchNo, roomNo)
- return
- }
- mu := mi.getUser(userId)
- if mu == nil {
- log.Release("matchinstance[%d].OnRoomUserScoreChanged[%d] user not exist", mi.MatchNo, userId)
- return
- }
- if mi.isEleminateByScore() {
- mu.Score += score
- } else {
- mu.Score = score
- }
- }
- func (mi *matchinstance) OnRoomStatusChanged(roomNo int, old, new int) {
- //log.Debug("matchinstance.OnRoomStatusChanged %d %d->%d", roomNo, old, new)
- }
- func (mi *matchinstance) isEleminateByScore() bool {
- return mi.eleminateByScore
- }
- func (mi *matchinstance) addPromotedUser(userId int) {
- mu := mi.getUser(userId)
- if mu == nil {
- return
- }
- go task.DoTaskAction(userId, task.TaskAction_matchpromote, 1, task.TaskScope{GameName: game.GetGameNameByGameId(mi.GameId)})
- mu.clearRoomInfo()
- mi.promotedUsers = append(mi.promotedUsers, userId)
- if len(mi.liveRooms) > 1 {
- mi.postUserPromotionNotification(userId)
- }
- }
- func (mi *matchinstance) addEleminatedUser(userId int, rank int) int {
- ret := 0
- mu := mi.getUser(userId)
- if mu == nil {
- return ret
- }
- mu.clearRoomInfo()
- mi.lock.Lock()
- //for _, v := range mi.UserList {
- for i := 0; i < len(mi.UserList); i++ {
- v := mi.UserList[i]
- if v.UserId == userId {
- mi.EliminateUsers = append(mi.EliminateUsers, v)
- //mi.roundElimiate = append(mi.roundElimiate, v)
- v.Round = mi.CurrentRound
- if rank <= 0 {
- rank = len(mi.UserList)
- }
- v.Rank = rank
- ret = v.Rank
- // delete
- mi.UserList = append(mi.UserList[:i], mi.UserList[i+1:]...)
- }
- }
- mi.lock.Unlock()
- return ret
- }
- func (mi *matchinstance) checkRoundEnd() {
- // 看下是否所有房间都结束了
- for _, v := range mi.liveRooms {
- if !v.isEnded() {
- return
- }
- }
- // 结束了,把非晋级玩家清理
- mi.lock.Lock()
- //for _, v := range mi.UserList {
- for i := 0; i < len(mi.UserList); {
- v := mi.UserList[i]
- if !mi.isUserIn(v.UserId, mi.promotedUsers) {
- mi.EliminateUsers = append(mi.EliminateUsers, v)
- v.Round = mi.CurrentRound
- v.Rank = len(mi.UserList)
- // delete
- mi.UserList = append(mi.UserList[:i], mi.UserList[i+1:]...)
- } else {
- i++
- }
- }
- leftUserCount := len(mi.UserList)
- mi.lock.Unlock()
- // 如果人数已经不足开桌,那么比赛就结束了
- if leftUserCount < mi.TableUser {
- // 剩下的玩家都为第一名
- mi.lock.Lock()
- for i := 0; i < len(mi.UserList); i++ {
- mi.UserList[i].Rank = 1
- }
- mi.lock.Unlock()
- mi.onMatchEnded(leftUserCount)
- return
- }
- mi.CurrentRound++
- // 延迟进行下一轮
- time.AfterFunc(time.Second*time.Duration(mi.config.getRoundTimeOff()), mi.checkAndStartRound)
- }
- func (mi *matchinstance) isUserIn(userId int, userIds []int) bool {
- for _, v := range userIds {
- if userId == v {
- return true
- }
- }
- return false
- }
- func (mi *matchinstance) onMatchEnded(winnerCount int) {
- mi.Status = matchbase.MatchStatus_Ended
- if winnerCount == 0 {
- log.Release("matchinstance.onMatchEnded winnerCount == 0")
- return
- }
- // 给最后的用户发奖金
- prize := mi.Prize / winnerCount
- tax := prize * getMatchManager().TaxRate / 100
- prize -= tax
- mi.lock.RLock()
- for _, v := range mi.UserList {
- if prize > 0 {
- cash.ModifyMoneyWithTax(v.UserId, prize, tax, common.LOGTYPE_SIMPLEMATCH_PRIZE, "simplematch", "prize", "")
- }
- // 发通知
- go mi.postUserRankNotification(v.UserId, 1, prize)
- }
- mi.lock.RUnlock()
- getHistoryManager().addHistory(*mi)
- mi.postOnMatchEndToReceivers()
- }
- func (mi *matchinstance) SendNotification(userId int, data string) {
- mi.sendNotification(userId, data)
- }
- func (mi *matchinstance) GetUserList() []int {
- var ret []int
- mi.lock.RLock()
- for _, v := range mi.UserList {
- ret = append(ret, v.UserId)
- }
- mi.lock.RUnlock()
- return ret
- }
- func (mi *matchinstance) sendNotification(userId int, data string) {
- if userId == -1 {
- // send all
- mi.lock.RLock()
- for _, v := range mi.UserList {
- notification.AddNotification(v.UserId, notification.Notification_Match, data)
- }
- mi.lock.RUnlock()
- return
- }
- notification.AddNotification(userId, notification.Notification_Match, data)
- }
- func (mi *matchinstance) setPrizeAndTax(userId int, prize, tax int) {
- mi.lock.Lock()
- defer mi.lock.Unlock()
- for _, v := range mi.UserList {
- if v == nil {
- continue
- }
- if v.UserId == userId {
- v.tax = tax
- v.prize = prize
- return
- }
- }
- }
- func (mi *matchinstance) getUsersDesc() string {
- type userDesc struct {
- UserId int
- Score int
- Prize int
- }
- var users []userDesc
- mi.lock.Lock()
- for _, v := range mi.UserList {
- if v == nil {
- continue
- }
- users = append(users, userDesc{UserId: v.UserId, Score: v.Score, Prize: v.prize})
- }
- mi.lock.Unlock()
- d, _ := json.Marshal(users)
- return string(d)
- }
- func (mi *matchinstance) getUsersDescForDB() string {
- var ret string
- mi.lock.Lock()
- for _, v := range mi.UserList {
- if v == nil {
- continue
- }
- ret = fmt.Sprintf("%s%d,%d,%d,%d;", ret, v.UserId, mi.Fee, v.tax, v.prize)
- }
- mi.lock.Unlock()
- return ret
- }
- func (mi *matchinstance) getTotalTax() int {
- ret := 0
- mi.lock.RLock()
- defer mi.lock.RUnlock()
- for _, v := range mi.UserList {
- if v == nil {
- continue
- }
- ret += v.tax
- }
- return ret
- }
- // MatchInstance
- func (mi *matchinstance) GetStatus() int {
- return mi.Status
- }
- func (mi *matchinstance) IsFull() bool {
- mi.lock.RLock()
- defer mi.lock.RUnlock()
- return len(mi.UserList) == mi.TotalUser
- }
- func (mi *matchinstance) IsUserEnrolled(userId int) bool {
- return mi.getUser(userId) != nil
- }
- func (mi *matchinstance) RegisterReceiver(receiver matchbase.MatchInstanceReceiver) {
- for _, v := range mi.receivers {
- if v == receiver {
- return
- }
- }
- mi.receivers = append(mi.receivers, receiver)
- }
- func (mi *matchinstance) GetWinners() []int {
- var ret []int
- if mi.Status == matchbase.MatchStatus_Ended {
- mi.lock.RLock()
- for _, v := range mi.UserList {
- if v == nil {
- continue
- }
- ret = append(ret, v.UserId)
- }
- mi.lock.RUnlock()
- }
- return ret
- }
- func (mi *matchinstance) postOnMatchCancelledToReceivers() {
- for _, v := range mi.receivers {
- v.OnMatchCancelled(mi.MatchNo)
- }
- }
- func (mi *matchinstance) postOnMatchEndToReceivers() {
- for _, v := range mi.receivers {
- v.OnMatchEnd(mi.MatchNo)
- }
- }
- func (mi *matchinstance) postOnMatchStartToReceivers() {
- for _, v := range mi.receivers {
- v.OnMatchStart(mi.MatchNo)
- }
- }
- func (mi *matchinstance) postOnUserEliminatedToReceivers(userId, rank int) {
- for _, v := range mi.receivers {
- v.OnUserEliminated(mi.MatchNo, userId, rank)
- }
- }
- func (mi *matchinstance) GetAllMatchUsers() []matchbase.MatchUser {
- var ret []matchbase.MatchUser
- mi.lock.RLock()
- for _, v := range mi.UserList {
- ret = append(ret, v.MatchUser)
- }
- for _, v := range mi.EliminateUsers {
- ret = append(ret, v.MatchUser)
- }
- mi.lock.RUnlock()
- return ret
- }
- func (mi *matchinstance) GetUser(userId int) *matchbase.MatchUser {
- ret := mi.getUser(userId)
- if ret == nil {
- return nil
- }
- return &ret.MatchUser
- }
- func (mi *matchinstance) isLastRound() bool {
- mi.lock.RLock()
- defer mi.lock.RUnlock()
- return len(mi.UserList) <= mi.TableUser
- }
|